def test_config_logging(self): import logging.config config_tree = ConfigTree() config_tree.put('version', 1) config_tree.put('root.level', logging.INFO) assert dict(config_tree)['version'] == 1 logging.config.dictConfig(config_tree)
def _fixup_self_references(cls, config, accept_unresolved=False): if isinstance(config, ConfigTree) and config.root: for key in config: # Traverse history of element history = config.history[key] previous_item = history[0] for current_item in history[1:]: for substitution in cls._find_substitutions(current_item): prop_path = ConfigTree.parse_key(substitution.variable) if len(prop_path) > 1 and config.get(substitution.variable, None) is not None: continue # If value is present in latest version, don't do anything if prop_path[0] == key: if isinstance(previous_item, ConfigValues) and not accept_unresolved: # We hit a dead end, we cannot evaluate raise ConfigSubstitutionException( "Property {variable} cannot be substituted. Check for cycles.".format( variable=substitution.variable ) ) else: value = previous_item if len(prop_path) == 1 else previous_item.get(".".join(prop_path[1:])) _, _, current_item = cls._do_substitute(substitution, value) previous_item = current_item if len(history) == 1: # special case, when self optional referencing without existing for substitution in cls._find_substitutions(previous_item): prop_path = ConfigTree.parse_key(substitution.variable) if len(prop_path) > 1 and config.get(substitution.variable, None) is not None: continue # If value is present in latest version, don't do anything if prop_path[0] == key and substitution.optional: cls._do_substitute(substitution, None)
def test_contains_with_quoted_keys(self): config_tree = ConfigTree() config_tree.put('a.b."c.d"', 5) assert 'a' in config_tree assert 'a.b' in config_tree assert 'a.c' not in config_tree assert 'a.b."c.d"' in config_tree assert 'a.b.c.d' not in config_tree
def test_contains(self): config_tree = ConfigTree() config_tree.put('a.b', 5) config_tree.put('a.c', None) assert 'a' in config_tree assert 'a.b' in config_tree assert 'a.c' in config_tree assert 'a.b.c' not in config_tree
def create_tree(value): if isinstance(value, dict): res = ConfigTree(root=root) for key, child_value in value.items(): res.put(key, create_tree(child_value)) return res if isinstance(value, list): return [create_tree(v) for v in value] else: return value
def test_config_list(self): config_tree = ConfigTree() config_tree.put("a.b.c", [4, 5]) assert config_tree.get("a.b.c") == [4, 5] config_tree.put("a.b.c", [6, 7]) assert config_tree.get("a.b.c") == [6, 7] config_tree.put("a.b.c", [8, 9], True) assert config_tree.get("a.b.c") == [6, 7, 8, 9]
def test_config_tree_special_characters(self): special_characters = '$}[]:=+#`^?!@*&.' for char in special_characters: config_tree = ConfigTree() escaped_key = "\"test{char}key\"".format(char=char) key = "a.b.{escaped_key}".format(escaped_key=escaped_key) config_tree.put(key, "value") hocon_tree = HOCONConverter.to_hocon(config_tree) assert escaped_key in hocon_tree parsed_tree = ConfigFactory.parse_string(hocon_tree) assert parsed_tree.get(key) == "value"
def test_plain_ordered_dict(self): config_tree = ConfigTree() config_tree.put('"a.b"', 5) config_tree.put('a."b.c"', [ConfigTree(), 2]) config_tree.get('a."b.c"')[0].put('"c.d"', 1) d = OrderedDict() d['a.b'] = 5 d['a'] = OrderedDict() d['a']['b.c'] = [OrderedDict(), 2] d['a']['b.c'][0]['c.d'] = 1 assert config_tree.as_plain_ordered_dict() == d
def test_config_tree_quoted_string(self): config_tree = ConfigTree() config_tree.put("a.b.c", "value") assert config_tree.get("a.b.c") == "value" with pytest.raises(ConfigMissingException): assert config_tree.get("a.b.d") with pytest.raises(ConfigMissingException): config_tree.get("a.d.e") with pytest.raises(ConfigWrongTypeException): config_tree.get("a.b.c.e")
def test_numerically_index_objects_to_arrays(self): config_tree = ConfigTree() config_tree.put("list.2", "b") config_tree.put("list.0", "a") assert config_tree.get_list("list") == ["a", "b"] config_tree.put("invalid-list.a", "c") config_tree.put("invalid-list.b", "d") with pytest.raises(ConfigException): config_tree.get_list("invalid-list")
def postParse(self, instring, loc, token_list): """Create ConfigTree from tokens :param instring: :param loc: :param token_list: :return: """ config_tree = ConfigTree() for element in token_list: expanded_tokens = element.tokens if isinstance( element, ConfigInclude) else [element] for tokens in expanded_tokens: # key, value1 (optional), ... key = tokens[0].strip() values = tokens[1:] # empty string if len(values) == 0: config_tree.put(key, '') else: value = values[0] if isinstance(value, list): config_tree.put(key, value, False) else: # Merge dict if isinstance(value, ConfigValues): conf_value = value value.parent = config_tree value.key = key else: conf_value = value config_tree.put(key, conf_value) return config_tree
def test_getter_type_conversion_number_to_string(self): config_tree = ConfigTree() config_tree.put("int", 5) assert config_tree.get_string("int") == "5" config_tree.put("float", 2.345) assert config_tree.get_string("float") == "2.345"
def test_getter_type_conversion_bool_to_string(self): config_tree = ConfigTree() config_tree.put("bool-true", True) assert config_tree.get_string("bool-true") == "true" config_tree.put("bool-false", False) assert config_tree.get_string("bool-false") == "false"
def test_durations(self): one_sec = ("1s", "1 s", "1seconds", "1 seconds", " 1s ", " 1 s ", "1second", "1000", "1000ms", "1000 ms", "1000 milliseconds", " 1000 milliseconds ", "1000millisecond", "1000000us", "1000000 us", "1000000 microseconds", "1000000microsecond", "1000000000ns", "1000000000 ns", "1000000000 nanoseconds", "1000000000nanosecond", "0.01666666666666666666666m", "0.01666666666666666666666 minutes", "0.01666666666666666666666 minute", "0.00027777777777777777777h", "0.00027777777777777777777 hours", "0.00027777777777777777777hour", "1.1574074074074073e-05d", "1.1574074074074073e-05 days", "1.1574074074074073e-05day") config_tree = ConfigTree() nanos_in_one_sec = 1000**3 millis_in_one_sec = 1000 for repr in one_sec: config_tree.put("one_sec", repr) assert config_tree.get_nanoseconds() == nanos_in_one_sec assert config_tree.get_milliseconds() == millis_in_one_sec
def postParse(self, instring, loc, token_list): """Create ConfigTree from tokens :param instring: :param loc: :param token_list: :return: """ config_tree = ConfigTree() for element in token_list: expanded_tokens = element.tokens if isinstance(element, ConfigInclude) else [element] for tokens in expanded_tokens: # key, value1 (optional), ... key = tokens[0].strip() values = tokens[1:] # empty string if len(values) == 0: config_tree.put(key, "") else: value = values[0] if isinstance(value, list): config_tree.put(key, value, False) else: # Merge dict if isinstance(value, ConfigValues): conf_value = value value.parent = config_tree value.key = key else: conf_value = value config_tree.put(key, conf_value) return config_tree
def test_configmissing_raised(self): config_tree = ConfigTree() for getter in [ config_tree.get, config_tree.get_bool, config_tree.get_config, config_tree.get_float, config_tree.get_int, config_tree.get_list, config_tree.get_string ]: with pytest.raises(ConfigMissingException): assert getter('missing_key')
def _merge(a, b): if a is None or b is None: return a or b elif isinstance(a, ConfigTree) and isinstance(b, ConfigTree): return ConfigTree.merge_configs(a, b) elif isinstance(a, list) and isinstance(b, list): return a + b else: raise ConfigException('Unable to make such include (merging unexpected types: {a} and {b}', a=type(a), b=type(b))
def postParse(self, instring, loc, token_list): """Create ConfigTree from tokens :param instring: :param loc: :param token_list: :return: """ config_tree = ConfigTree() for element in token_list: # from include then merge items expanded_tokens = element.items() if isinstance( element, ConfigTree) else [element] for tokens in expanded_tokens: # key, value1, value2, ... key = tokens[0].strip() values = tokens[1:] # empty string if len(values) == 0: config_tree.put(key, '') else: if isinstance(values[0], list): # Merge arrays config_tree.put(key, values[0], False) for value in values[1:]: config_tree.put(key, value, True) else: # Merge dict for value in values: if isinstance(value, ConfigList): conf_value = list(value) elif isinstance(value, ConfigValues): conf_value = value value.parent = config_tree value.key = key else: conf_value = value config_tree.put(key, conf_value) return config_tree
def __init__(self, routers=None, **kwargs): self.extensions = {} self.kwargs = kwargs default_config_file = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), 'application.conf') config_file = self.kwargs.pop('config', default_config_file) if os.path.exists(config_file): self.config = ConfigFactory.parse_file(config_file) else: self.config = ConfigTree() if routers is None: routers = [] self.routers = routers self.filters = []
def __generate(value: object, path): if is_dataclass(value): tree = { k: __generate(v, f"{path}.{k}") for k, v in asdict(value).items() } return ConfigTree(tree) if isinstance(value, dict): tree = {k: __generate(v, f"{path}.{k}") for k, v in value.items()} return ConfigTree(tree) if isinstance(value, list): tree = [__generate(e, f"{path}[]") for e in value] return ConfigList(tree) # needs a better impl. # if isinstance(value, timedelta): # if isinstance(value, relativedelta): return value
def postParse(self, instring, loc, token_list): """Create ConfigTree from tokens :param instring: :param loc: :param token_list: :return: """ config_tree = ConfigTree() for element in token_list: # from include then merge items expanded_tokens = element.items() if isinstance(element, ConfigTree) else [element] for tokens in expanded_tokens: # key, value1, value2, ... key = tokens[0].strip() values = tokens[1:] # empty string if len(values) == 0: config_tree.put(key, '') else: if isinstance(values[0], list): # Merge arrays config_tree.put(key, values[0], False) for value in values[1:]: config_tree.put(key, value, True) else: # Merge dict for value in values: if isinstance(value, ConfigList): conf_value = list(value) elif isinstance(value, ConfigValues): conf_value = value value.parent = config_tree value.key = key else: conf_value = value config_tree.put(key, conf_value) return config_tree
def postParse(self, instring, loc, token_list): """Create ConfigTree from tokens :param instring: :param loc: :param token_list: :return: """ config_tree = ConfigTree(root=self.root) for element in token_list: expanded_tokens = element.tokens if isinstance(element, ConfigInclude) else [element] for tokens in expanded_tokens: # key, value1 (optional), ... key = tokens[0].strip() operator = '=' if len(tokens) == 3 and tokens[1].strip() in [':', '=', '+=']: operator = tokens[1].strip() values = tokens[2:] elif len(tokens) == 2: values = tokens[1:] else: raise ParseSyntaxException("Unknown tokens {tokens} received".format(tokens=tokens)) # empty string if len(values) == 0: config_tree.put(key, '') else: value = values[0] if isinstance(value, list) and operator == "+=": value = ConfigValues([ConfigSubstitution(key, True, '', False, loc), value], False, loc) config_tree.put(key, value, False) elif isinstance(value, unicode) and operator == "+=": value = ConfigValues([ConfigSubstitution(key, True, '', True, loc), ' ' + value], True, loc) config_tree.put(key, value, False) elif isinstance(value, list): config_tree.put(key, value, False) else: existing_value = config_tree.get(key, None) if isinstance(value, ConfigTree) and not isinstance(existing_value, list): # Only Tree has to be merged with tree config_tree.put(key, value, True) elif isinstance(value, ConfigValues): conf_value = value value.parent = config_tree value.key = key if isinstance(existing_value, list) or isinstance(existing_value, ConfigTree): config_tree.put(key, conf_value, True) else: config_tree.put(key, conf_value, False) else: config_tree.put(key, value, False) return config_tree
def test_configtree_pop(self): config_tree = ConfigTree() config_tree.put("string", "string") assert config_tree.pop("string", "default") == "string" assert config_tree.pop("string-new", "default") == "default" assert config_tree == ConfigTree() with pytest.raises(ConfigMissingException): assert config_tree.pop("string-new") config_tree.put("list", [1, 2, 3]) assert config_tree.pop("list", [4]) == [1, 2, 3] assert config_tree.pop("list-new", [4]) == [4] assert config_tree == ConfigTree() config_tree.put("config", {'a': 5}) assert config_tree.pop("config", {'b': 1}) == {'a': 5} assert config_tree.pop("config-new", {'b': 1}) == {'b': 1} assert config_tree == ConfigTree() config_tree = ConfigTree() config_tree.put('key', 'value') assert config_tree.pop('key', 'value') == 'value' assert 'key' not in config_tree config_tree = ConfigTree() config_tree.put('a.b.c.one', 1) config_tree.put('a.b.c.two', 2) config_tree.put('"f.k".g.three', 3) exp = OrderedDict() exp['a'] = OrderedDict() exp['a']['b'] = OrderedDict() exp['a']['b']['c'] = OrderedDict() exp['a']['b']['c']['one'] = 1 exp['a']['b']['c']['two'] = 2 exp['f.k'] = OrderedDict() exp['f.k']['g'] = OrderedDict() exp['f.k']['g']['three'] = 3 assert config_tree.pop('a.b.c').as_plain_ordered_dict() == exp['a']['b']['c'] assert config_tree.pop('a.b.c', None) is None with pytest.raises(ConfigMissingException): assert config_tree.pop('a.b.c') with pytest.raises(ConfigMissingException): assert config_tree['a']['b'].pop('c') assert config_tree.pop('a').as_plain_ordered_dict() == OrderedDict(b=OrderedDict()) assert config_tree.pop('"f.k"').as_plain_ordered_dict() == OrderedDict(g=OrderedDict(three=3)) assert config_tree.as_plain_ordered_dict() == OrderedDict()
def test_config_tree_iterator(self): config_tree = ConfigTree() config_tree.put("a.b.c", 5) for k in config_tree: assert k == "a" assert config_tree[k]["b.c"] == 5
def test_config_tree_null(self): config_tree = ConfigTree() config_tree.put("a.b.c", None) assert config_tree.get("a.b.c") is None
def test_getter_type_conversion_string_to_bool(self): config_tree = ConfigTree() config_tree.put("bool-string-true", "true") assert config_tree.get_bool("bool-string-true") is True config_tree.put("bool-string-false", "false") assert config_tree.get_bool("bool-string-false") is False config_tree.put("bool-string-yes", "yes") assert config_tree.get_bool("bool-string-yes") is True config_tree.put("bool-string-no", "no") assert config_tree.get_bool("bool-string-no") is False config_tree.put("bool-string-on", "on") assert config_tree.get_bool("bool-string-on") is True config_tree.put("bool-string-off", "off") assert config_tree.get_bool("bool-string-off") is False config_tree.put("invalid-bool-string", "invalid") with pytest.raises(ConfigException): config_tree.get_bool("invalid-bool-string")
def test_config_tree_number(self): config_tree = ConfigTree() config_tree.put("a.b.c", 5) assert config_tree.get("a.b.c") == 5
def test_configtree_pop(self): config_tree = ConfigTree() config_tree.put("string", "string") assert config_tree.pop("string", "default") == "string" assert config_tree.pop("string-new", "default") == "default" assert config_tree == ConfigTree() with pytest.raises(ConfigMissingException): assert config_tree.pop("string-new") config_tree.put("list", [1, 2, 3]) assert config_tree.pop("list", [4]) == [1, 2, 3] assert config_tree.pop("list-new", [4]) == [4] assert config_tree == ConfigTree() config_tree.put("config", {'a': 5}) assert config_tree.pop("config", {'b': 1}) == {'a': 5} assert config_tree.pop("config-new", {'b': 1}) == {'b': 1} assert config_tree == ConfigTree() config_tree = ConfigTree() config_tree.put('key', 'value') assert config_tree.pop('key', 'value') == 'value' assert 'key' not in config_tree config_tree = ConfigTree() config_tree.put('a.b.c.one', 1) config_tree.put('a.b.c.two', 2) config_tree.put('"f.k".g.three', 3) exp = OrderedDict() exp['a'] = OrderedDict() exp['a']['b'] = OrderedDict() exp['a']['b']['c'] = OrderedDict() exp['a']['b']['c']['one'] = 1 exp['a']['b']['c']['two'] = 2 exp['f.k'] = OrderedDict() exp['f.k']['g'] = OrderedDict() exp['f.k']['g']['three'] = 3 assert config_tree.pop( 'a.b.c').as_plain_ordered_dict() == exp['a']['b']['c'] assert config_tree.pop('a.b.c', None) is None with pytest.raises(ConfigMissingException): assert config_tree.pop('a.b.c') with pytest.raises(ConfigMissingException): assert config_tree['a']['b'].pop('c') assert config_tree.pop('a').as_plain_ordered_dict() == OrderedDict( b=OrderedDict()) assert config_tree.pop('"f.k"').as_plain_ordered_dict() == OrderedDict( g=OrderedDict(three=3)) assert config_tree.as_plain_ordered_dict() == OrderedDict()
def test_config_tree_null_items(self): config_tree = ConfigTree() config_tree.put("a", NoneValue()) assert list(config_tree.items()) == [("a", None)]
def test_keyerror_raised(self): config_tree = ConfigTree() config_tree.put("a", {'b': 5}) with pytest.raises(KeyError): assert config_tree['c']
def test_getters_with_default(self): config_tree = ConfigTree() config_tree.put("int", 5) assert config_tree.get("int-new", 1) == 1 assert config_tree.get_int("int", 1) == 5 assert config_tree.get_int("int-new", 1) == 1 assert config_tree.get_int("int-new.test", 1) == 1 config_tree.put("float", 4.5) assert config_tree.get("float", 1.0) == 4.5 assert config_tree.get("float-new", 1.0) == 1.0 assert config_tree.get_float("float", 1.0) == 4.5 assert config_tree.get_float("float-new", 1.0) == 1.0 assert config_tree.get_float("float-new.test", 1.0) == 1.0 config_tree.put("string", "string") assert config_tree.get("string", "default") == "string" assert config_tree.get("string-new", "default") == "default" assert config_tree.get_string("string", "default") == "string" assert config_tree.get_string("string-new", "default") == "default" assert config_tree.get_string("string-new.test", "default") == "default" config_tree.put("list", [1, 2, 3]) assert config_tree.get("list", [4]) == [1, 2, 3] assert config_tree.get("list-new", [4]) == [4] assert config_tree.get_list("list", [4]) == [1, 2, 3] assert config_tree.get_list("list-new", [4]) == [4] config_tree.put("bool", True) assert config_tree.get("bool", False) is True assert config_tree.get("bool-new", False) is False assert config_tree.get_bool("bool", False) is True assert config_tree.get_bool("bool-new", False) is False config_tree.put("config", {'a': 5}) assert config_tree.get("config", {'b': 1}) == {'a': 5} assert config_tree.get("config-new", {'b': 1}) == {'b': 1} assert config_tree.get_config("config", {'b': 1}) == {'a': 5} assert config_tree.get_config("config-new", {'b': 1}) == {'b': 1}
def test_getter_type_conversion_string_to_bool(self): config_tree = ConfigTree() config_tree.put("bool-string-true", "true") assert config_tree.get_bool("bool-string-true") is True config_tree.put("bool-string-true", "True") assert config_tree.get_bool("bool-string-true") is True config_tree.put("bool-string-false", "false") assert config_tree.get_bool("bool-string-false") is False config_tree.put("bool-string-false", "False") assert config_tree.get_bool("bool-string-false") is False config_tree.put("bool-string-yes", "yes") assert config_tree.get_bool("bool-string-yes") is True config_tree.put("bool-string-no", "no") assert config_tree.get_bool("bool-string-no") is False config_tree.put("bool-string-on", "on") assert config_tree.get_bool("bool-string-on") is True config_tree.put("bool-string-off", "off") assert config_tree.get_bool("bool-string-off") is False config_tree.put("invalid-bool-string", "invalid") with pytest.raises(ConfigException): config_tree.get_bool("invalid-bool-string")
def test_config_tree_number(self): config_tree = ConfigTree() config_tree.put("a.b.c", 5) config_tree.put("a.b.e", 4.5) assert config_tree.get("a.b.c") == 5 assert config_tree.get("a.b.e") == 4.5
def test_getters(self): config_tree = ConfigTree() config_tree.put("int", 5) assert config_tree["int"] == 5 assert config_tree.get("int") == 5 assert config_tree.get_int("int") == 5 config_tree.put("float", 4.5) assert config_tree["float"] == 4.5 assert config_tree.get("float") == 4.5 assert config_tree.get_float("float") == 4.5 config_tree.put("string", "string") assert config_tree["string"] == "string" assert config_tree.get("string") == "string" assert config_tree.get_string("string") == "string" config_tree.put("list", [1, 2, 3]) assert config_tree["list"] == [1, 2, 3] assert config_tree.get("list") == [1, 2, 3] assert config_tree.get_list("list") == [1, 2, 3] config_tree.put("bool", True) assert config_tree["bool"] is True assert config_tree.get("bool") is True assert config_tree.get_bool("bool") is True config_tree.put("config", {'a': 5}) assert config_tree["config"] == {'a': 5} assert config_tree.get("config") == {'a': 5} assert config_tree.get_config("config") == {'a': 5}
def test_config_logging(self): import logging.config config_tree = ConfigTree() config_tree.put('version', 1) config_tree.put('root.level', logging.INFO) assert dict(config_tree)['version'] == 1
def test_overrides_int_with_config_append(self): config_tree = ConfigTree() config_tree.put("int", 5, True) config_tree.put("int.config", 1, True) assert config_tree == {'int': {'config': 1}}
def postParse(self, instring, loc, token_list): """Create ConfigTree from tokens :param instring: :param loc: :param token_list: :return: """ config_tree = ConfigTree(root=self.root) for element in token_list: expanded_tokens = element.tokens if isinstance( element, ConfigInclude) else [element] for tokens in expanded_tokens: # key, value1 (optional), ... key = tokens[0].strip() operator = '=' if len(tokens) == 3 and tokens[1].strip() in [':', '=', '+=']: operator = tokens[1].strip() values = tokens[2:] elif len(tokens) == 2: values = tokens[1:] else: raise ParseSyntaxException( "Unknown tokens {tokens} received".format( tokens=tokens)) # empty string if len(values) == 0: config_tree.put(key, '') else: value = values[0] if isinstance(value, list) and operator == "+=": value = ConfigValues([ ConfigSubstitution(key, True, '', False, loc), value ], False, loc) config_tree.put(key, value, False) elif isinstance(value, unicode) and operator == "+=": value = ConfigValues([ ConfigSubstitution(key, True, '', True, loc), ' ' + value ], True, loc) config_tree.put(key, value, False) elif isinstance(value, list): config_tree.put(key, value, False) else: existing_value = config_tree.get(key, None) if isinstance(value, ConfigTree) and not isinstance( existing_value, list): # Only Tree has to be merged with tree config_tree.put(key, value, True) elif isinstance(value, ConfigValues): conf_value = value value.parent = config_tree value.key = key if isinstance(existing_value, list) or isinstance( existing_value, ConfigTree): config_tree.put(key, conf_value, True) else: config_tree.put(key, conf_value, False) else: config_tree.put(key, value, False) return config_tree