diff --git a/objects/providers.py b/objects/providers.py index fdf9b880..78491f1f 100644 --- a/objects/providers.py +++ b/objects/providers.py @@ -303,23 +303,27 @@ class Config(Provider): def __getattr__(self, item): """Return instance of deferred config.""" - return _DeferredConfig(parents=(item,), - root_config=self) + return _ChildConfig(parents=(item,), root_config=self) def __call__(self, paths=None): """Return provided instance.""" value = self.value if paths: for path in paths: - value = value[path] - return value + try: + value = value[path] + except KeyError: + raise Error('Config key ' + '"{}" is undefined'.format('.'.join(paths))) + return value -class _DeferredConfig(Provider): +class _ChildConfig(Provider): - """Deferred config provider. + """Child config provider. - Deferred config providers provide an value from the root config object. + Child config provide an value from the root config object according to + the current path in the config tree. """ __slots__ = ('parents', 'root_config') @@ -328,12 +332,12 @@ class _DeferredConfig(Provider): """Initializer.""" self.parents = parents self.root_config = root_config - super(_DeferredConfig, self).__init__() + super(_ChildConfig, self).__init__() def __getattr__(self, item): """Return instance of deferred config.""" - return _DeferredConfig(parents=self.parents + (item,), - root_config=self.root_config) + return _ChildConfig(parents=self.parents + (item,), + root_config=self.root_config) def __call__(self, *args, **kwargs): """Return provided instance.""" diff --git a/tests/test_providers.py b/tests/test_providers.py index d74f2170..987739d1 100644 --- a/tests/test_providers.py +++ b/tests/test_providers.py @@ -480,7 +480,7 @@ class CallableTests(unittest.TestCase): def test_is_provider(self): """Test `is_provider` check.""" - self.assertTrue(is_provider(Callable(map))) + self.assertTrue(is_provider(self.provider)) def test_call(self): """Test provider call.""" @@ -517,4 +517,59 @@ class ConfigTests(unittest.TestCase): def setUp(self): """Set test cases environment up.""" + self.initial_data = dict(key='value', + category=dict(setting='setting_value')) + self.provider = Config(self.initial_data) + + def test_is_provider(self): + """Test `is_provider` check.""" + self.assertTrue(is_provider(self.provider)) + + def test_init_without_initial_value(self): + """Test provider's creation with no initial value.""" + self.assertEqual(Config()(), dict()) + + def test_call(self): + """Test returning of config value.""" + self.assertEqual(self.provider(), self.initial_data) + + def test_update_from(self): + """Test update of config value.""" + self.assertEqual(self.provider(), self.initial_data) + + self.initial_data['key'] = 'other_value' + self.provider.update_from(self.initial_data) + self.assertEqual(self.provider(), self.initial_data) + + def test_call_child(self): + """Test returning of child config values.""" + category = self.provider.category + category_setting = self.provider.category.setting + + self.assertTrue(is_provider(category)) + self.assertTrue(is_provider(category_setting)) + + self.assertEqual(category(), self.initial_data['category']) + self.assertEqual(category_setting(), + self.initial_data['category']['setting']) + + def test_call_deferred_child_and_update_from(self): + """Test returning of deferred child config values.""" self.provider = Config() + category = self.provider.category + category_setting = self.provider.category.setting + + self.assertTrue(is_provider(category)) + self.assertTrue(is_provider(category_setting)) + + self.provider.update_from(self.initial_data) + + self.assertEqual(category(), self.initial_data['category']) + self.assertEqual(category_setting(), + self.initial_data['category']['setting']) + + def test_call_deferred_child_with_empty_value(self): + """Test returning of deferred child config values.""" + self.provider = Config() + category_setting = self.provider.category.setting + self.assertRaises(Error, category_setting)