feast.config — Feast 0.3.2 documentation

# Source code for feast.config

    #
    #  Copyright 2019 The Feast Authors
    #
    #  Licensed under the Apache License, Version 2.0 (the "License");
    #  you may not use this file except in compliance with the License.
    #  You may obtain a copy of the License at
    #
    #      https://www.apache.org/licenses/LICENSE-2.0
    #
    #  Unless required by applicable law or agreed to in writing, software
    #  distributed under the License is distributed on an "AS IS" BASIS,
    #  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    #  See the License for the specific language governing permissions and
    #  limitations under the License.
    #

    from os.path import expanduser, join
    import logging
    import os
    import sys
    from typing import Dict
    from urllib.parse import urlparse
    from urllib.parse import ParseResult

    import toml

    _logger = logging.getLogger(__name__)

    feast_configuration_properties = {"core_url": "URL", "serving_url": "URL"}

    CONFIGURATION_FILE_DIR = os.environ.get("FEAST_CONFIG", ".feast")
    CONFIGURATION_FILE_NAME = "config.toml"

    def _get_or_create_config() -> Dict:
        """Get user configuration file or create it and return"""

        user_config_file_dir, user_config_file_path = _get_config_file_locations()
        user_config_file_dir = user_config_file_dir.rstrip("/") + "/"
        if not os.path.exists(os.path.dirname(user_config_file_dir)):
            os.makedirs(os.path.dirname(user_config_file_dir))

        if not os.path.isfile(user_config_file_path):
            _save_config(user_config_file_path, _props_to_dict())

        try:
            return toml.load(user_config_file_path)
        except FileNotFoundError:
            _logger.error(
                "Could not find Feast configuration file " + user_config_file_path
            )
            sys.exit(1)
        except toml.decoder.TomlDecodeError:
            _logger.error(
                "Could not decode Feast configuration file " + user_config_file_path
            )
            sys.exit(1)
        except Exception as e:
            _logger.error(e)
            sys.exit(1)

    def set_property(prop: str, value: str):
        """
        Sets a single property in the Feast users local configuration file

        Args:
            prop: Feast property name
            value: Feast property value
        """
        if _is_valid_property(prop, value):
            active_feast_config = _get_or_create_config()
            active_feast_config[prop] = value
            _, user_config_file_path = _get_config_file_locations()
            _save_config(user_config_file_path, active_feast_config)
            print("Updated property [%s]" % prop)
        else:
            _logger.error("Invalid property selected")
            sys.exit(1)

    def get_config_property_or_fail(prop: str, force_config: Dict[str, str] = None) -> str:
        """
        Gets a single property in the users configuration

        Args:
            prop: Property to retrieve
            force_config: Configuration dictionary containing properties that should
                be overridden. This will take precedence over file based properties.

        Returns:
            Returns a string property
        """
        if (
            isinstance(force_config, dict)
            and prop in force_config
            and force_config[prop] is not None
        ):
            return force_config[prop]

        active_feast_config = _get_or_create_config()
        if _is_valid_property(prop, active_feast_config[prop]):
            return active_feast_config[prop]
        _logger.error("Could not load Feast property from configuration: %s" % prop)
        sys.exit(1)

    def _props_to_dict() -> Dict[str, str]:
        """Create empty dictionary of all Feast properties"""
        prop_dict = {}
        for prop in feast_configuration_properties:
            prop_dict[prop] = ""
        return prop_dict

    def _is_valid_property(prop: str, value: str) -> bool:
        """
        Validates both a Feast property as well as value

        Args:
            prop: Feast property name
            value: Feast property value

        Returns:
            Returns True if property and value are valid
        """
        if prop not in feast_configuration_properties:
            _logger.error("You are trying to set an invalid property")
            sys.exit(1)

        prop_type = feast_configuration_properties[prop]

        if prop_type == "URL":
            if "//" not in value:
                value = "%s%s" % ("grpc://", value)
            parsed_value = urlparse(value)  # type: ParseResult
            if parsed_value.netloc:
                return True

        _logger.error("The property you are trying to set could not be identified")
        sys.exit(1)

    def _save_config(user_config_file_path: str, config_string: Dict[str, str]):
        """
        Saves Feast configuration

        Args:
            user_config_file_path: Local file system path to save configuration
            config_string: Contents in dictionary format to save to path
        """
        try:
            with open(user_config_file_path, "w+") as f:
                toml.dump(config_string, f)
        except Exception as e:
            _logger.error("Could not update configuration file for Feast")
            print(e)
            sys.exit(1)

    def _get_config_file_locations() -> (str, str):
        """Gets the local user configuration directory and file path"""
        user_config_file_dir = join(expanduser("~"), CONFIGURATION_FILE_DIR)
        user_config_file_path = join(user_config_file_dir, CONFIGURATION_FILE_NAME)
        return user_config_file_dir, user_config_file_path