def test_mapping_with_top_level_merge(self): config = Config({'x': {'y': 1}}) data = {'z': 2} config.merge(data, mapping={ source: target.merge() }) compare(config.data, expected={'x': {'y': 1}, 'z': 2})
def test_mapping_with_top_level_merge(self): config = Config({'x': {'y': 1}}) data = {'z': 2} config.merge(data, mapping={ source: target.merge() }) compare(config.data, expected={'x': {'y': 1}, 'z': 2})
def test_override_type_mapping(self): config1 = Config([1, 2]) config2 = Config([3, 4]) def zipper(context, source, target): return zip(target, source) config1.merge(config2, mergers={list: zipper}) compare(config1.data, expected=[(1, 3), (2, 4)])
def test_other_to_dict(self): config1 = Config(1) config2 = Config(1) with ShouldRaise(type_error( "Cannot merge <class 'int'> with <class 'int'>" )): config1.merge(config2)
def test_list_to_dict(self): config1 = Config({'x': 1}) config2 = Config([1, 2]) with ShouldRaise(type_error( "Cannot merge <class 'list'> with <class 'dict'>" )): config1.merge(config2)
def test_override_type_mapping(self): config1 = Config([1, 2]) config2 = Config([3, 4]) def zipper(context, source, target): return zip(target, source) config1.merge(config2, mergers={list: zipper}) compare(config1.data, expected=[(1, 3), (2, 4)])
def test_mapping_dotted_strings(self): config = Config({'a': {'b': 'old'}}) data = {'c': {'d': 'new'}} config.merge(data, mapping={ 'c.d': 'a.b' }) compare(config.data, expected={'a': {'b': 'new'}})
def test_mapping_paths(self): config = Config({'x': 'old'}) data = {'foo': 'bar'} config.merge(data, mapping={ source['foo']: target['x'] }) compare(config.data, expected={'x': 'bar'})
def test_mapping_strings(self): config = Config({'x': 'old'}) data = {'foo': 'bar'} config.merge(data, mapping={ 'foo': 'x' }) compare(config.data, expected={'x': 'bar'})
def test_blank_type_mapping(self): config1 = Config({'foo': 'bar'}) config2 = Config({'baz': 'bob'}) with ShouldRaise(type_error( "Cannot merge <class 'dict'> with <class 'dict'>" )): config2.merge(config1, mergers={})
def test_supplement_type_mapping(self): config1 = Config({'x': (1, 2)}) config2 = Config({'x': (3, 4)}) def concat(context, source, target): return target + source config1.merge(config2, mergers=default_mergers+{tuple: concat}) compare(config1.data, expected={'x': (1, 2, 3, 4)})
def test_nested_working(self): config1 = Config(dict(x=1, y=[2, 3], z=dict(a=4, b=5))) config2 = Config(dict(w=6, y=[7], z=dict(b=8, c=9))) config1.merge(config2) compare(config1.data, expected=dict(x=1, w=6, y=[2, 3, 7], z=dict(a=4, b=8, c=9)))
def test_mapping_dotted_strings(self): config = Config({'a': {'b': 'old'}}) data = {'c': {'d': 'new'}} config.merge(data, mapping={ 'c.d': 'a.b' }) compare(config.data, expected={'a': {'b': 'new'}})
def test_other_to_dict(self): config1 = Config(1) config2 = Config(1) with ShouldRaise(type_error( "Cannot merge <class 'int'> with <class 'int'>" )): config1.merge(config2)
def test_nested_working(self): config1 = Config(dict(x=1, y=[2, 3], z=dict(a=4, b=5))) config2 = Config(dict(w=6, y=[7], z=dict(b=8, c=9))) config1.merge(config2) compare(config1.data, expected=dict(x=1, w=6, y=[2, 3, 7], z=dict(a=4, b=8, c=9)))
def test_blank_type_mapping(self): config1 = Config({'foo': 'bar'}) config2 = Config({'baz': 'bob'}) with ShouldRaise(type_error( "Cannot merge <class 'dict'> with <class 'dict'>" )): config2.merge(config1, mergers={})
def test_list_to_dict(self): config1 = Config({'x': 1}) config2 = Config([1, 2]) with ShouldRaise(type_error( "Cannot merge <class 'list'> with <class 'dict'>" )): config1.merge(config2)
def test_supplement_type_mapping(self): config1 = Config({'x': (1, 2)}) config2 = Config({'x': (3, 4)}) def concat(context, source, target): return target + source config1.merge(config2, mergers=default_mergers+{tuple: concat}) compare(config1.data, expected={'x': (1, 2, 3, 4)})
def test_mapping_paths(self): config = Config({'x': 'old'}) data = {'foo': 'bar'} config.merge(data, mapping={ source['foo']: target['x'] }) compare(config.data, expected={'x': 'bar'})
def test_mapping_strings(self): config = Config({'x': 'old'}) data = {'foo': 'bar'} config.merge(data, mapping={ 'foo': 'x' }) compare(config.data, expected={'x': 'bar'})
def test_mapping_type_conversion(self): config = Config({'x': 0}) data = {'y': '1'} config.merge(data, mapping={ convert(source['y'], int): target['x'] }) compare(config.data, expected={'x': 1})
def test_mapping_type_conversion(self): config = Config({'x': 0}) data = {'y': '1'} config.merge(data, mapping={ convert(source['y'], int): target['x'] }) compare(config.data, expected={'x': 1})
def test_type_returns_new_object(self): config1 = Config((1, 2)) config2 = Config((3, 4)) def concat(context, source, target): return target + source config1.merge(config2, mergers={tuple: concat}) compare(config1.data, expected=(1, 2, 3, 4))
def test_type_returns_new_object(self): config1 = Config((1, 2)) config2 = Config((3, 4)) def concat(context, source, target): return target + source config1.merge(config2, mergers={tuple: concat}) compare(config1.data, expected=(1, 2, 3, 4))
def test_defaults_and_env(self): config = Config({'present': 'dp', 'absent': 'da'}) environ = {'ENV_PRESENT': '1'} config.merge(environ, { convert('ENV_PRESENT', int): 'present', convert('ENV_ABSENT', int): 'absent', }) compare(config.present, expected=1) compare(config.absent, expected='da')
def test_mapping_extensive_conversation(self): config = Config({'a': 0}) data = {'x': 2, 'y': -1} def best(possible): return max(possible.values()) config.merge(data, mapping={ convert(source, best): target['a'] }) compare(config.data, expected={'a': 2})
def test_mapping_extensive_conversation(self): config = Config({'a': 0}) data = {'x': 2, 'y': -1} def best(possible): return max(possible.values()) config.merge(data, mapping={ convert(source, best): target['a'] }) compare(config.data, expected={'a': 2})
def test_defaults_and_env(self): config = Config({'present': 'dp', 'absent': 'da'}) environ = {'ENV_PRESENT': '1'} config.merge( environ, { convert('ENV_PRESENT', int): 'present', convert('ENV_ABSENT', int): 'absent', }) compare(config.present, expected=1) compare(config.absent, expected='da')
def test_layered(self, dir): # defaults config = Config({'database': {'user': '******'}, 'special': False}) # from system file: path = dir.write('etc/myapp.json', '{"special": true}') config.merge(Config.from_path(path)) # from user file: path = dir.write('home/user/myapp.json', '{"database": {"password": "******"}}') config.merge(Config.from_path(path)) # end result: compare(config.database.user, expected='foo') compare(config.database.password, expected='123') compare(config.special, expected=True)
def test_layered(self, dir): # defaults config = Config({ 'database': {'user': '******'}, 'special': False }) # from system file: path = dir.write('etc/myapp.json', '{"special": true}') config.merge(Config.from_path(path)) # from user file: path = dir.write('home/user/myapp.json', '{"database": {"password": "******"}}') config.merge(Config.from_path(path)) # end result: compare(config.database.user, expected='foo') compare(config.database.password, expected='123') compare(config.special, expected=True)
def load_config(): config = Config() cwd = Path.cwd() dirs = [cwd, *cwd.parents] for dir in reversed(dirs): paths = [ dir / '.config' / 'freezerbox' / 'conf.toml', dir / '.freezerboxrc', ] for path in paths: if path.exists(): subconf = Config.from_path(path, parser='toml') config.merge(subconf) dir = dir.parent return config.data
def test_defaults_and_argparse(self): parser = ArgumentParser() parser.add_argument('--first-url') parser.add_argument('--attempts', type=int, default=2) parser.add_argument('--bool-a', action='store_true') parser.add_argument('--bool-b', action='store_false') args = parser.parse_args(['--first-url', 'override_url', '--bool-a']) compare(args.bool_b, expected=True) config = Config({'urls': ['default_url'], 'bool_b': False}) config.merge(args, { 'first_url': target['urls'].insert(0), 'attempts': target['attempts'], 'bool_a': target['bool_a'], 'bool_b': target['bool_b'], }) compare(config.urls, expected=['override_url', 'default_url']) compare(config.attempts, expected=2) compare(config.bool_a, expected=True) compare(config.bool_b, expected=True)
def test_defaults_and_argparse(self): parser = ArgumentParser() parser.add_argument('--first-url') parser.add_argument('--attempts', type=int, default=2) parser.add_argument('--bool-a', action='store_true') parser.add_argument('--bool-b', action='store_false') args = parser.parse_args(['--first-url', 'override_url', '--bool-a']) compare(args.bool_b, expected=True) config = Config({'urls': ['default_url'], 'bool_b': False}) config.merge( args, { 'first_url': target['urls'].insert(0), 'attempts': target['attempts'], 'bool_a': target['bool_a'], 'bool_b': target['bool_b'], }) compare(config.urls, expected=['override_url', 'default_url']) compare(config.attempts, expected=2) compare(config.bool_a, expected=True) compare(config.bool_b, expected=True)
def test_explicit_extends(self): raise SkipTest('not yet') path1 = self.dir.write('base.yml', ''' base: 1 file: bad ''') path2 = self.dir.write('app.yml', ''' extends: {} file: 2 '''.format(path1)) config = Config(path2) config.validate(Schema({ 'extends': config.merge(), 'base': int, 'file': int, })) compare(config.base, expected=1) compare(config.file, expected=2)
def test_include_list(self): raise SkipTest('not yet') path1 = self.dir.write('other.yml', ''' - 2 - 3 ''') path2 = self.dir.write('app.yml', ''' root: - 1 - include: {} '''.format(path1)) config = Config(path2) config.validate(Schema({ 'include': config.merge(), 'base': int, 'file': int, })) compare(config.base, expected=1) compare(config.file, expected=2)
def test_dict_to_dict(self): config = Config() config.merge(Config(dict(x=1))) compare(config.x, expected=1)
def test_empty_config(self): config = Config() config.merge(Config()) compare(config.data, expected={})
def test_non_empty_config(self): config = Config({'foo': 'bar'}) config.merge(Config({'baz': 'bob'})) compare(config.data, {'foo': 'bar', 'baz': 'bob'})
def test_empty_config(self): config = Config() config.merge(Config()) compare(config.data, expected={})
def test_non_empty_config(self): config = Config({'foo': 'bar'}) config.merge(Config({'baz': 'bob'})) compare(config.data, {'foo': 'bar', 'baz': 'bob'})
def test_simple_type(self): config = Config() with ShouldRaise(type_error( "Cannot merge <class 'str'> with <class 'dict'>" )): config.merge('foo')
def test_dict_to_dict(self): config = Config({'x': 1}) config.merge({'y': 2}) compare(config.data, expected={'x': 1, 'y': 2})
def test_list_to_list(self): config = Config([1, 2]) config.merge([3, 4]) compare(config.data, expected=[1, 2, 3, 4])
def test_simple_type(self): config = Config() with ShouldRaise(type_error( "Cannot merge <class 'str'> with <class 'dict'>" )): config.merge('foo')
def test_list_to_list(self): config = Config([1, 2]) config.merge(Config([3, 4])) compare(config[0], expected=1) compare(config[2], expected=3) compare(list(config), expected=[1, 2, 3, 4])
def test_empty(self): config = Config() config.merge(Config()) # make sure empty dict is default: config.merge(Config({'x': 1})) compare(config.x, 1)
def test_non_config(self): config = Config() with ShouldRaise(TypeError("'foo' is not a Config instance")): config.merge('foo')
def test_list_to_list(self): config = Config([1, 2]) config.merge([3, 4]) compare(config.data, expected=[1, 2, 3, 4])
def test_dict_to_dict(self): config = Config({'x': 1}) config.merge({'y': 2}) compare(config.data, expected={'x': 1, 'y': 2})