示例#1
0
def get_random_value(config: ConfigTree):
    """
    Executes function from https://docs.python.org/3/library/random.html
    :param config: Config that contains type "get_random_value" with 'func' and 'args'
    :return:
    """
    config_dict = config.as_plain_ordered_dict()
    if config_dict["type"] != "random":
        raise ValueError(
            "Config with type {0} is not valid for this function".format(
                config_dict["type"]))

    func_str = config_dict["func"]
    func_args = dict(config_dict["args"])

    return_first = False
    if func_str.endswith("[0]"):
        return_first = True
        func_str = func_str[:-3]

    allowed_funcs = {
        "random.randint": random.randint,
        "randint": random.randint,
        "random.uniform": random.uniform,
        "uniform": random.uniform,
        "random.randrange": random.randrange,
        "randrange": random.randrange,
        "random.shuffle": random.shuffle,
        "shuffle": random.shuffle,
        "random.choice": random.choice,
        "choice": random.choice,
        "random.choices": random.choices,
        "choices": random.choices,
    }

    if not func_str in allowed_funcs:
        raise ValueError(
            "Wrong function type {0}. The following types are allowed: {1}".
            format(func_str, ", ".join(sorted(allowed_funcs.keys()))))

    func = allowed_funcs[func_str]

    result_value = func(**func_args)
    if return_first:
        result_value = result_value[0]

    return result_value
示例#2
0
class Config(object):
    """
    Represents a server configuration.
    If watch=True, will watch configuration folders for changes and reload itself.
    NOTE: will not watch folders that were created after initialization.
    """

    # used in place of None in Config.get as default value because None is a valid value
    _MISSING = object()

    def __init__(self,
                 config_folder=None,
                 env=None,
                 verbose=True,
                 relative_to=None,
                 app=None,
                 is_server=False,
                 **_):
        self._app = app
        self._verbose = verbose
        self._folder_name = config_folder or DEFAULT_CONFIG_FOLDER
        self._roots = []
        self._config = ConfigTree()
        self._env = env or os.environ.get("TRAINS_ENV", Environment.default)
        self.config_paths = set()
        self.is_server = is_server

        if self._verbose:
            print("Config env:%s" % str(self._env))

        if not self._env:
            raise ValueError(
                "Missing environment in either init of environment variable")
        if self._env not in get_options(Environment):
            raise ValueError("Invalid environment %s" % env)
        if relative_to is not None:
            self.load_relative_to(relative_to)

    @property
    def root(self):
        return self.roots[0] if self.roots else None

    @property
    def roots(self):
        return self._roots

    @roots.setter
    def roots(self, value):
        self._roots = value

    @property
    def env(self):
        return self._env

    def logger(self, path=None):
        return logger(path)

    def load_relative_to(self, *module_paths):
        def normalize(p):
            return Path(os.path.abspath(str(p))).with_name(self._folder_name)

        self.roots = list(map(normalize, module_paths))
        self.reload()

    def _reload(self):
        env = self._env
        config = self._config.copy()

        if self.is_server:
            env_config_paths = ENV_CONFIG_PATHS
        else:
            env_config_paths = []

        env_config_path_override = os.environ.get(ENV_CONFIG_PATH_OVERRIDE_VAR)
        if env_config_path_override:
            env_config_paths = [expanduser(env_config_path_override)]

        # merge configuration from root and other environment config paths
        if self.roots or env_config_paths:
            config = functools.reduce(
                lambda cfg, path: ConfigTree.merge_configs(
                    cfg,
                    self._read_recursive_for_env(
                        path, env, verbose=self._verbose),
                    copy_trees=True,
                ),
                self.roots + env_config_paths,
                config,
            )

        # merge configuration from local configuration paths
        if LOCAL_CONFIG_PATHS:
            config = functools.reduce(
                lambda cfg, path: ConfigTree.merge_configs(
                    cfg,
                    self._read_recursive(path, verbose=self._verbose),
                    copy_trees=True),
                LOCAL_CONFIG_PATHS,
                config,
            )

        local_config_files = LOCAL_CONFIG_FILES
        local_config_override = os.environ.get(LOCAL_CONFIG_FILE_OVERRIDE_VAR)
        if local_config_override:
            local_config_files = [expanduser(local_config_override)]

        # merge configuration from local configuration files
        if local_config_files:
            config = functools.reduce(
                lambda cfg, file_path: ConfigTree.merge_configs(
                    cfg,
                    self._read_single_file(file_path, verbose=self._verbose),
                    copy_trees=True,
                ),
                local_config_files,
                config,
            )

        config["env"] = env
        return config

    def replace(self, config):
        self._config = config

    def reload(self):
        self.replace(self._reload())

    def initialize_logging(self):
        logging_config = self._config.get("logging", None)
        if not logging_config:
            return False

        # handle incomplete file handlers
        deleted = []
        handlers = logging_config.get("handlers", {})
        for name, handler in list(handlers.items()):
            cls = handler.get("class", None)
            is_file = cls and "FileHandler" in cls
            if cls is None or (is_file and "filename" not in handler):
                deleted.append(name)
                del handlers[name]
            elif is_file:
                file = Path(handler.get("filename"))
                if not file.is_file():
                    file.parent.mkdir(parents=True, exist_ok=True)
                    file.touch()

        # remove dependency in deleted handlers
        root_logger = logging_config.get("root", None)
        loggers = list(logging_config.get(
            "loggers", {}).values()) + ([root_logger] if root_logger else [])
        for logger in loggers:
            handlers = logger.get("handlers", None)
            if not handlers:
                continue
            logger["handlers"] = [h for h in handlers if h not in deleted]

        extra = None
        if self._app:
            extra = {"app": self._app}
        initialize_log(logging_config, extra=extra)
        return True

    def __getitem__(self, key):
        try:
            return self._config[key]
        except:
            return None

    def __getattr__(self, key):
        c = self.__getattribute__('_config')
        if key.split('.')[0] in c:
            try:
                return c[key]
            except Exception:
                return None
        return getattr(c, key)

    def get(self, key, default=_MISSING):
        value = self._config.get(key, default)
        if value is self._MISSING and not default:
            raise KeyError(
                "Unable to find value for key '{}' and default value was not provided."
                .format(key))
        return value

    def to_dict(self):
        return self._config.as_plain_ordered_dict()

    def as_json(self):
        return json.dumps(self.to_dict(), indent=2)

    def _read_recursive_for_env(self, root_path_str, env, verbose=True):
        root_path = Path(root_path_str)
        if root_path.exists():
            default_config = self._read_recursive(root_path /
                                                  Environment.default,
                                                  verbose=verbose)
            if (root_path / env) != (root_path / Environment.default):
                env_config = self._read_recursive(
                    root_path / env,
                    verbose=verbose)  # None is ok, will return empty config
                config = ConfigTree.merge_configs(default_config, env_config,
                                                  True)
            else:
                config = default_config
        else:
            config = ConfigTree()

        return config

    def _read_recursive(self, conf_root, verbose=True):
        conf = ConfigTree()
        if not conf_root:
            return conf
        conf_root = Path(conf_root)

        if not conf_root.exists():
            if verbose:
                print("No config in %s" % str(conf_root))
            return conf

        if verbose:
            print("Loading config from %s" % str(conf_root))
        for root, dirs, files in os.walk(str(conf_root)):

            rel_dir = str(Path(root).relative_to(conf_root))
            if rel_dir == ".":
                rel_dir = ""
            prefix = rel_dir.replace("/", ".")

            for filename in files:
                if not is_config_file(filename):
                    continue

                if prefix != "":
                    key = prefix + "." + Path(filename).stem
                else:
                    key = Path(filename).stem

                file_path = str(Path(root) / filename)

                conf.put(key, self._read_single_file(file_path,
                                                     verbose=verbose))

        return conf

    @staticmethod
    def _read_single_file(file_path, verbose=True):
        if not file_path or not Path(file_path).is_file():
            return ConfigTree()

        if verbose:
            print("Loading config from file %s" % file_path)

        try:
            return pyhocon.ConfigFactory.parse_file(file_path)
        except ParseSyntaxException as ex:
            msg = "Failed parsing {0} ({1.__class__.__name__}): (at char {1.loc}, line:{1.lineno}, col:{1.column})".format(
                file_path, ex)
            six.reraise(
                ConfigurationError,
                ConfigurationError(msg, file_path=file_path),
                sys.exc_info()[2],
            )
        except (ParseException, ParseFatalException,
                RecursiveGrammarException) as ex:
            msg = "Failed parsing {0} ({1.__class__.__name__}): {1}".format(
                file_path, ex)
            six.reraise(ConfigurationError, ConfigurationError(msg),
                        sys.exc_info()[2])
        except Exception as ex:
            print("Failed loading %s: %s" % (file_path, ex))
            raise
示例#3
0
def config_to_dict(config: pyhocon.ConfigTree) -> OrderedDict:
    return config.as_plain_ordered_dict()
示例#4
0
文件: config.py 项目: yaelsilb/trains
class Config(object):
    """
    Represents a server configuration.
    If watch=True, will watch configuration folders for changes and reload itself.
    NOTE: will not watch folders that were created after initialization.
    """

    # used in place of None in Config.get as default value because None is a valid value
    _MISSING = object()

    def __init__(self,
                 config_folder=None,
                 env=None,
                 verbose=True,
                 relative_to=None,
                 app=None,
                 watch=False,
                 is_server=False,
                 **_):
        self._app = app
        self._verbose = verbose
        self._folder_name = config_folder or DEFAULT_CONFIG_FOLDER
        self._roots = []
        self._config = ConfigTree()
        self._env = env or os.environ.get("TRAINS_ENV", Environment.default)
        self.config_paths = set()
        self.watch = watch
        self.is_server = is_server
        if watch:
            self.observer = Observer()
            self.observer.start()
            self.handler = ConfigReloader(self)

        if self._verbose:
            print("Config env:%s" % str(self._env))

        if not self._env:
            raise ValueError(
                "Missing environment in either init of environment variable")
        if self._env not in get_options(Environment):
            raise ValueError("Invalid environment %s" % env)
        if relative_to is not None:
            self.load_relative_to(relative_to)

    @property
    def root(self):
        return self.roots[0] if self.roots else None

    @property
    def roots(self):
        return self._roots

    @roots.setter
    def roots(self, value):
        self._roots = value

    @property
    def env(self):
        return self._env

    def logger(self, path=None):
        return logger(path)

    def load_relative_to(self, *module_paths):
        def normalize(p):
            return Path(os.path.abspath(str(p))).with_name(self._folder_name)

        self.roots = list(map(normalize, module_paths))
        self.reload()
        if self.watch:
            for path in self.config_paths:
                self.observer.schedule(self.handler, str(path), recursive=True)

    def _reload(self):
        env = self._env
        config = self._config.copy()

        if self.is_server:
            env_config_paths = ENV_CONFIG_PATHS
        else:
            env_config_paths = []

        env_config_path_override = os.environ.get(ENV_CONFIG_PATH_OVERRIDE_VAR)
        if env_config_path_override:
            env_config_paths = [expanduser(env_config_path_override)]

        # merge configuration from root and other environment config paths
        config = functools.reduce(
            lambda cfg, path: ConfigTree.merge_configs(
                cfg,
                self._read_recursive_for_env(path, env, verbose=self._verbose),
                copy_trees=True,
            ),
            self.roots + env_config_paths,
            config,
        )

        # merge configuration from local configuration paths
        config = functools.reduce(
            lambda cfg, path: ConfigTree.merge_configs(
                cfg,
                self._read_recursive(path, verbose=self._verbose),
                copy_trees=True),
            LOCAL_CONFIG_PATHS,
            config,
        )

        local_config_files = LOCAL_CONFIG_FILES
        local_config_override = os.environ.get(LOCAL_CONFIG_FILE_OVERRIDE_VAR)
        if local_config_override:
            local_config_files = [expanduser(local_config_override)]

        # merge configuration from local configuration files
        config = functools.reduce(
            lambda cfg, file_path: ConfigTree.merge_configs(
                cfg,
                self._read_single_file(file_path, verbose=self._verbose),
                copy_trees=True,
            ),
            local_config_files,
            config,
        )

        config["env"] = env
        return config

    def replace(self, config):
        self._config = config

    def reload(self):
        self.replace(self._reload())

    def initialize_logging(self):
        logging_config = self._config.get("logging", None)
        if not logging_config:
            return False

        # handle incomplete file handlers
        deleted = []
        handlers = logging_config.get("handlers", {})
        for name, handler in list(handlers.items()):
            cls = handler.get("class", None)
            is_file = cls and "FileHandler" in cls
            if cls is None or (is_file and "filename" not in handler):
                deleted.append(name)
                del handlers[name]
            elif is_file:
                file = Path(handler.get("filename"))
                if not file.is_file():
                    file.parent.mkdir(parents=True, exist_ok=True)
                    file.touch()

        # remove dependency in deleted handlers
        root_logger = logging_config.get("root", None)
        loggers = list(logging_config.get(
            "loggers", {}).values()) + ([root_logger] if root_logger else [])
        for logger in loggers:
            handlers = logger.get("handlers", None)
            if not handlers:
                continue
            logger["handlers"] = [h for h in handlers if h not in deleted]

        extra = None
        if self._app:
            extra = {"app": self._app}
        initialize_log(logging_config, extra=extra)
        return True

    def __getitem__(self, key):
        return self._config[key]

    def get(self, key, default=_MISSING):
        value = self._config.get(key, default)
        if value is self._MISSING and not default:
            raise KeyError(
                "Unable to find value for key '{}' and default value was not provided."
                .format(key))
        return value

    def to_dict(self):
        return self._config.as_plain_ordered_dict()

    def as_json(self):
        return json.dumps(self.to_dict(), indent=2)

    def _read_recursive_for_env(self, root_path_str, env, verbose=True):
        root_path = Path(root_path_str)
        if root_path.exists():
            default_config = self._read_recursive(root_path /
                                                  Environment.default,
                                                  verbose=verbose)
            env_config = self._read_recursive(
                root_path / env,
                verbose=verbose)  # None is ok, will return empty config
            config = ConfigTree.merge_configs(default_config, env_config, True)
        else:
            config = ConfigTree()

        return config

    def _read_recursive(self, conf_root, verbose=True):
        conf = ConfigTree()
        if not conf_root:
            return conf
        conf_root = Path(conf_root)

        if not conf_root.exists():
            if verbose:
                print("No config in %s" % str(conf_root))
            return conf

        if self.watch:
            self.config_paths.add(conf_root)

        if verbose:
            print("Loading config from %s" % str(conf_root))
        for root, dirs, files in os.walk(str(conf_root)):

            rel_dir = str(Path(root).relative_to(conf_root))
            if rel_dir == ".":
                rel_dir = ""
            prefix = rel_dir.replace("/", ".")

            for filename in files:
                if not is_config_file(filename):
                    continue

                if prefix != "":
                    key = prefix + "." + Path(filename).stem
                else:
                    key = Path(filename).stem

                file_path = str(Path(root) / filename)

                conf.put(key, self._read_single_file(file_path,
                                                     verbose=verbose))

        return conf

    @staticmethod
    def _read_single_file(file_path, verbose=True):
        if not file_path or not Path(file_path).is_file():
            return ConfigTree()

        if verbose:
            print("Loading config from file %s" % file_path)

        try:
            return pyhocon.ConfigFactory.parse_file(file_path)
        except ParseSyntaxException as ex:
            msg = "Failed parsing {0} ({1.__class__.__name__}): (at char {1.loc}, line:{1.lineno}, col:{1.column})".format(
                file_path, ex)
            six.reraise(
                ConfigurationError,
                ConfigurationError(msg, file_path=file_path),
                sys.exc_info()[2],
            )
        except (ParseException, ParseFatalException,
                RecursiveGrammarException) as ex:
            msg = "Failed parsing {0} ({1.__class__.__name__}): {1}".format(
                file_path, ex)
            six.reraise(ConfigurationError, ConfigurationError(msg),
                        sys.exc_info()[2])
        except Exception as ex:
            print("Failed loading %s: %s" % (file_path, ex))
            raise

    def get_config_for_bucket(self, base_url, extra_configurations=None):
        """
        Get the credentials for an AWS S3 bucket from the config
        :param base_url: URL of bucket
        :param extra_configurations:
        :return: bucket config
        :rtype: bucket config
        """

        warnings.warn(
            "Use backend_config.bucket_config.BucketList.get_config_for_uri",
            DeprecationWarning,
        )
        configs = S3BucketConfig.from_list(
            self.get("sdk.aws.s3.credentials", []))
        if extra_configurations:
            configs.extend(extra_configurations)

        def find_match(host=None, bucket=None):
            if not host and not bucket:
                raise ValueError("host or bucket required")
            try:
                if host:
                    res = {
                        config
                        for config in configs
                        if (config.host and fnmatch(host, config.host)) and (
                            not bucket or not config.bucket
                            or fnmatch(bucket.lower(), config.bucket.lower()))
                    }
                else:
                    res = {
                        config
                        for config in configs if config.bucket
                        and fnmatch(bucket.lower(), config.bucket.lower())
                    }
                return next(iter(res))
            except StopIteration:
                pass

        parsed = urlparse(base_url)
        parts = Path(parsed.path.strip("/")).parts
        if parsed.netloc:
            # We have a netloc (either an actual hostname or an AWS bucket name).
            # First, we'll try with the netloc as host, but if we don't find anything, we'll try without a host and
            # with the netloc as the bucket name
            match = None
            if parts:
                # try host/bucket only if path parts contain any element
                match = find_match(host=parsed.netloc, bucket=parts[0])
            if not match:
                # no path parts or no config found for host/bucket, try netloc as bucket
                match = find_match(bucket=parsed.netloc)
        else:
            # No netloc, so we'll simply search by bucket
            match = find_match(bucket=parts[0])

        if match:
            return match

        non_aws_s3_host_suffix = ":9000"
        if parsed.netloc.endswith(non_aws_s3_host_suffix):
            host = parsed.netloc
            bucket = parts[0] if parts else None
        else:
            host = None
            bucket = parsed.netloc

        return S3BucketConfig(
            key=self.get("sdk.aws.s3.key", None),
            secret=self.get("sdk.aws.s3.secret", None),
            region=self.get("sdk.aws.s3.region", None),
            multipart=True,
            bucket=bucket,
            host=host,
        )
示例#5
0
 def from_config_tree(cls, conf: pyhocon.ConfigTree):
     return cls(**conf.as_plain_ordered_dict())