"""Implements a config object with dot-indexing syntax.""" import os from itertools import chain from operator import truth from envyaml import EnvYAML from funcy import first, juxt, butlast, last from pyinfra.locations import CONFIG_FILE def _get_item_and_maybe_make_dotindexable(container, item): ret = container[item] return DotIndexable(ret) if isinstance(ret, dict) else ret class DotIndexable: def __init__(self, x): self.x = x def __getattr__(self, item): return _get_item_and_maybe_make_dotindexable(self.x, item) def __repr__(self): return self.x.__repr__() def __getitem__(self, item): return self.__getattr__(item) def __setitem__(self, key, value): self.x[key] = value class Config: def __init__(self, config_path): self.__config = EnvYAML(config_path) def __getattr__(self, item): if item in self.__config: return _get_item_and_maybe_make_dotindexable(self.__config, item) def __getitem__(self, item): return self.__getattr__(item) def __setitem__(self, key, value): self.__config.key = value CONFIG = Config(CONFIG_FILE) def parse_disjunction_string(disjunction_string): def try_parse_env_var(disjunction_string): try: return os.environ[disjunction_string] except KeyError: return None options = disjunction_string.split("|") identifiers, fallback_value = juxt(butlast, last)(options) return first(chain(filter(truth, map(try_parse_env_var, identifiers)), [fallback_value]))