Source code for fuzzy_types.configuration

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# @Author: José Sánchez-Gallego (gallegoj@uw.edu)
# @Date: 2019-05-08
# @Filename: configuration.py
# @License: BSD 3-clause (http://www.opensource.org/licenses/BSD-3-Clause)

import inspect
import os
import pathlib
import yaml
from typing import Union


__all__ = ['read_yaml_file', 'merge_config', 'get_config']


[docs]def read_yaml_file(path: Union[str, pathlib.Path]) -> dict: """Read a YAML file and returns a dictionary.""" if isinstance(path, (str, pathlib.Path)): with open(path, 'r') as fp: config = yaml.safe_load(fp) else: # Assume it's an stream config = yaml.safe_load(path) return config
[docs]def merge_config(user: dict, default: dict) -> dict: """Merges a user configuration with the default one.""" if isinstance(user, dict) and isinstance(default, dict): for kk, vv in default.items(): if kk not in user: user[kk] = vv else: user[kk] = merge_config(user[kk], vv) return user
[docs]def get_config(name: str, config_file: str = None, allow_user: bool = True, user_path: str = None, config_envvar: str = None, merge_mode: str = 'update') -> dict: """Returns a configuration dictionary. The configuration dictionary is created by merging the default configuration file that is part of the library (normally in ``etc/<name>.yml``) with a user configuration file. The path to the user configuration file can be defined as an environment variable to be passed to this function in ``config_envvar`` or as a path in ``user_path``. The environment variable, if exists, always takes precedence. Parameters ---------- name : str The name of the package. config_file : str The path to the configuration file. If `None`, defaults to ``etc/<name>.yml`` relative to the file that called `.get_config`. allow_user : bool If `True`, looks for an user configuration file and merges is to the default configuration. Otherwise it returns just the default configuration. user_path : str The path to the user configuration file. Defaults to ``~/.config/<name>/<name>.yml``. Ignored if the file does not exist. config_envvar : str The environment variable that contains the path to the user configuration file. Defaults to ``<name>_CONFIG_PATH``. If the environment variable exists, the ``user_path`` is ignored. merge_mode : str Defines how the default and user dictionaries will be merged. If ``update``, the user dictionary will be used to update the default configuration. If ``replace``, only the user configuration will be returned. Returns ------- config : dict A dictionary containing the configuration. """ assert merge_mode in ['update', 'replace'], 'invalid merge mode.' if not config_file: frame = inspect.stack()[1] module = inspect.getmodule(frame[0]) dirname = os.path.dirname(module.__file__) config_file = os.path.join(dirname, f'etc/{name}.yml') if os.path.exists(config_file): config = read_yaml_file(config_file) else: config = {} if allow_user is False: return config config_envvar = config_envvar or '{}_CONFIG_PATH'.format(name.upper()) if user_path is not None: user_path = os.path.expanduser(os.path.expandvars(user_path)) else: user_path = os.path.expanduser('~/.fuzzy/{0}.yml'.format(name)) if config_envvar in os.environ: custom_config_fn = os.environ[config_envvar] elif os.path.exists(user_path): custom_config_fn = user_path else: return config user_config = read_yaml_file(custom_config_fn) or {} if merge_mode == 'update': return merge_config(user_config, config) else: return user_config