def test_config_with_circular_import(self):
        with tempfile.TemporaryDirectory() as temp:
            with open(os.path.join(temp, 'foo.json'), mode='w') as f:
                json.dump({'import': 'bar.json'}, f)
            with open(os.path.join(temp, 'bar.json'), mode='w') as f:
                json.dump([{'import': './foo.json'}], f)

            with self.assertRaises(RuntimeError):
                Config.load_path(os.path.join(temp, 'foo.json'))
    def test_config_with_circular_import(self):
        with tempfile.TemporaryDirectory() as temp:
            with open(os.path.join(temp, 'foo.json'), mode='w') as f:
                json.dump({'a': {'import': 'bar.json'}}, f)
            with open(os.path.join(temp, 'bar.json'), mode='w') as f:
                json.dump([{'import': './foo.json'}], f)

            with self.assertRaises(RuntimeError) as cm:
                Config.load_path(os.path.join(temp, 'foo.json'))

        self.assertEqual(
            cm.exception.args,
            ('Circular import', '!/ of {foo} -> !/a of {foo} -> !/ of {bar}'
             ' -> !/0 of {bar} -> !/ of {foo}'.format(
                 foo=os.path.join(temp, 'foo.json'),
                 bar=os.path.join(temp, 'bar.json'))))
Example #3
0
def parse_config(configs: Dict[str, Any],
                 custom_types: Optional[Dict[str, Any]] = None) -> Config:
    _types = {k: v for k, v in types.items()}
    if custom_types is not None:
        for k, v in custom_types.items():
            _types[k] = v
    _types["with_file_cache"] = \
        lambda path, config: with_file_cache(path, config, _types)

    def convert(d: Any, rename: bool) -> Any:
        if not isinstance(d, dict):
            return d
        if rename:
            if "type" in d:
                t = d.pop("type")
                d = {key: convert(value, True) for key, value in d.items()}
                d["_type"] = t
            else:
                d = {key: convert(value, True) for key, value in d.items()}
        else:
            if "type" in d and d["type"] == "with_file_cache":
                config = d.pop("config")
                d = {key: convert(value, False) for key, value in d.items()}
                d["config"] = convert(config, True)
            else:
                d = {key: convert(value, False) for key, value in d.items()}
        return d

    return Config(convert(configs, False), _types)
    def test_config_with_invalid_type(self):
        config = Config({'foo': [{'type': 'foo', 'a': 0, 'b': 1}]})
        with self.assertRaises(KeyError) as cm:
            config['/']

        self.assertEqual(cm.exception.args[-2:],
                         ('foo not in types', '/ -> /foo -> /foo/0'))
    def test_config_with_config_key_invalid_index(self):
        config = Config([['a'], [['b', ['c', 'd']]]])
        with self.assertRaises(IndexError) as cm:
            config['/1/2/3']

        self.assertEqual(cm.exception.args[-2:],
                         ('2 not in !/1', '/1/2/3 -> !/1/2/3 -> !/1/2'))
    def test_config_with_config_key_invalid_key(self):
        config = Config({'foo': {'bar': {'baz': None}}})
        with self.assertRaises(KeyError) as cm:
            config['/foo/Bar/baz']

        self.assertEqual(
            cm.exception.args[-2:],
            ('Bar not in !/foo', '/foo/Bar/baz -> !/foo/Bar/baz -> !/foo/Bar'))
    def test_config_with_attr_key_invalid_type(self):
        config = Config({'foo': [['b', {'baz': None}]]})
        with self.assertRaises(TypeError) as cm:
            config['/.foo.bar.baz']

        self.assertEqual(cm.exception.args[-2:],
                         ('bar not in /.foo ([[\'b\', {\'baz\': None}]])',
                          '/.foo.bar.baz -> /.foo.bar'))
    def test_config_with_attr_key_invalid_key(self):
        config = Config({'foo': {'bar': {'baz': None}}})
        with self.assertRaises(KeyError) as cm:
            config['/.foo.Bar.baz']

        self.assertEqual(cm.exception.args[-2:],
                         ('Bar not in /.foo ({\'bar\': {\'baz\': None}})',
                          '/.foo.Bar.baz -> /.foo.Bar'))
    def test_config_with_attr_key_invalid_index(self):
        config = Config([['a'], [['b', ['c', 'd']]]])
        with self.assertRaises(IndexError) as cm:
            config['/.1.2.3']

        self.assertEqual(
            cm.exception.args[-2:],
            ('2 not in /.1 ([[\'b\', [\'c\', \'d\']]])', '/.1.2.3 -> /.1.2'))
    def test_config_with_config_key_invalid_type(self):
        config = Config({'foo': [['b', {'baz': None}]]})
        with self.assertRaises(TypeError) as cm:
            config['/foo/bar/baz']

        self.assertEqual(
            cm.exception.args[-2:],
            ('bar not in !/foo', '/foo/bar/baz -> !/foo/bar/baz -> !/foo/bar'))
    def test_config_with_circular_dependency(self):
        config = Config({'foo': '@/bar', 'bar': '@foo.d'})
        with self.assertRaises(RuntimeError) as cm:
            config['/']

        self.assertIn(
            cm.exception.args, {
                ('Circular dependency', '/ -> /foo -> /bar -> /foo.d -> /foo'),
                ('Circular dependency', '/ -> /bar -> /foo.d -> /foo -> /bar'),
            })
    def test_config_with_invalid_call(self):
        def foo():
            raise RuntimeError('foo')

        config = Config({'foo': [{
            'type': 'foo',
            'a': 0,
            'b': 1
        }]},
                        types={'foo': foo})
        with self.assertRaises(TypeError) as cm:
            config['/']

        self.assertEqual(cm.exception.args[-1:], ('/ -> /foo -> /foo/0', ))
    def test_config_escape(self):
        pre_eval_config = {
            'foo': {
                'v0': {
                    'type': 'func_0',
                    'a': 1,
                    'b': 2
                },
            },
            'bar': {
                'type': 'func_2'
            },
        }
        config = Config(pre_eval_config, self.types)

        self.assertEqual(config['!/foo'], {
            'v0': {
                'type': 'func_0',
                'a': 1,
                'b': 2
            },
        })
        self.assertEqual(json.loads(config['/bar']), pre_eval_config)
    def test_config(self):
        config = Config(
            {
                'foo': {
                    'v0': {
                        'type': 'func_0',
                        'a': 1,
                        'b': 2
                    },
                    'v1': {
                        'type': 'func_0',
                        'a': 1,
                        'b': 2,
                        'c': 3
                    },
                    'v2': {
                        'type': 'func_1',
                        'a': 1,
                        'b': 2
                    },
                    'v3': {
                        'type': 'func_1',
                        'a': 1,
                        'b': 2,
                        'c': 3
                    },
                },
                'bar': [
                    {
                        'type': 'cls_0',
                        'a': 1,
                        'b': 2
                    },
                    {
                        'type': 'cls_0',
                        'a': 1,
                        'b': 2,
                        'c': 3
                    },
                    {
                        'type': 'cls_1',
                        'a': 1,
                        'b': 2
                    },
                    {
                        'type': 'cls_1',
                        'a': 1,
                        'b': 2,
                        'c': 3
                    },
                ],
                'baz': {
                    'v0': '@/foo/v2.d',
                    'v1': '@../bar/1/c',
                    'v2': '@/bar/3.d',
                    'v3': '@../foo/v3',
                }
            }, self.types)

        self.assertEqual(
            config['/'], {
                'foo': {
                    'v0': 13,
                    'v1': 6,
                    'v2': {
                        'd': 2,
                        'e': 13
                    },
                    'v3': {
                        'd': 2,
                        'e': 3
                    },
                },
                'bar': [
                    Cls0(1, 2, 10),
                    Cls0(1, 2, 3),
                    Cls1(1, 2, 13),
                    Cls1(1, 2, 3),
                ],
                'baz': {
                    'v0': 2,
                    'v1': 3,
                    'v2': 2,
                    'v3': {
                        'd': 2,
                        'e': 3
                    },
                },
            })
 def test_config_with_circular_dependency(self):
     config = Config({'foo': '@/bar', 'bar': '@foo.d'})
     with self.assertRaises(RuntimeError):
         config['/']
    def test_config_load_path(self):
        with tempfile.TemporaryDirectory() as temp0, \
             tempfile.TemporaryDirectory() as temp1:
            with open(os.path.join(temp0, 'foo.json'), mode='w') as f:
                json.dump(
                    {
                        'foo': {
                            'v0': {
                                'type': 'func_0',
                                'a': 1,
                                'b': 2
                            }
                        },
                        'bar': {
                            'import': os.path.join(temp1, 'bar.json')
                        },
                        'baz': {
                            'import': 'baz.json',
                            '0/b': 3,
                            '1/d': [1, 2],
                        },
                    }, f)
            with open(os.path.join(temp1, 'bar.json'), mode='w') as f:
                json.dump({'type': 'func_0', 'a': 3, 'b': 4}, f)
            with open(os.path.join(temp0, 'baz.json'), mode='w') as f:
                json.dump([
                    {
                        'type': 'func_1',
                        'a': 1,
                        'b': 2
                    },
                    {
                        'd': 3,
                        'e': 4
                    },
                ], f)

            config = Config.load_path(os.path.join(temp0, 'foo.json'),
                                      types=self.types)

        self.assertEqual(config['!/foo'],
                         {'v0': {
                             'type': 'func_0',
                             'a': 1,
                             'b': 2
                         }})
        self.assertEqual(config['/foo'], {'v0': 13})
        self.assertEqual(config['!/bar'], {'type': 'func_0', 'a': 3, 'b': 4})
        self.assertEqual(config['/bar'], 17)
        self.assertEqual(config['!/baz'], [
            {
                'type': 'func_1',
                'a': 1,
                'b': 3
            },
            {
                'd': [1, 2],
                'e': 4
            },
        ])
        self.assertEqual(config['/baz'], [
            {
                'd': 3,
                'e': 13
            },
            {
                'd': [1, 2],
                'e': 4
            },
        ])
Example #17
0
 def f():
     return Config(restore(config), types)["/"]