mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-11-22 09:36:48 +03:00
Refactor configuration provider
This commit is contained in:
parent
86a8efa294
commit
e877b33fd1
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -71,16 +71,10 @@ cdef class CallableDelegate(Delegate):
|
||||||
|
|
||||||
|
|
||||||
# Configuration providers
|
# Configuration providers
|
||||||
cdef class Configuration(Provider):
|
cdef class Configuration(Object):
|
||||||
cdef str __name
|
cdef str __name
|
||||||
cdef object __value
|
|
||||||
cdef dict __children
|
cdef dict __children
|
||||||
|
|
||||||
cpdef str get_name(self)
|
|
||||||
cpdef object update(self, object value)
|
|
||||||
cpdef object _provide(self, tuple args, dict kwargs)
|
|
||||||
cpdef str _get_child_name(self, str child_name)
|
|
||||||
|
|
||||||
|
|
||||||
# Factory providers
|
# Factory providers
|
||||||
cdef class Factory(Provider):
|
cdef class Factory(Provider):
|
||||||
|
|
|
@ -823,7 +823,7 @@ cdef class CallableDelegate(Delegate):
|
||||||
super(Delegate, self).__init__(callable)
|
super(Delegate, self).__init__(callable)
|
||||||
|
|
||||||
|
|
||||||
cdef class Configuration(Provider):
|
cdef class Configuration(Object):
|
||||||
"""Configuration provider.
|
"""Configuration provider.
|
||||||
|
|
||||||
Configuration provider helps with implementing late static binding of
|
Configuration provider helps with implementing late static binding of
|
||||||
|
@ -836,7 +836,7 @@ cdef class Configuration(Provider):
|
||||||
print(config.section1.option1()) # None
|
print(config.section1.option1()) # None
|
||||||
print(config.section1.option2()) # None
|
print(config.section1.option2()) # None
|
||||||
|
|
||||||
config.update({'section1': {'option1': 1,
|
config.override({'section1': {'option1': 1,
|
||||||
'option2': 2}})
|
'option2': 2}})
|
||||||
|
|
||||||
print(config.section1.option1()) # 1
|
print(config.section1.option1()) # 1
|
||||||
|
@ -852,12 +852,10 @@ cdef class Configuration(Provider):
|
||||||
:param default: Default values of configuration unit.
|
:param default: Default values of configuration unit.
|
||||||
:type default: dict
|
:type default: dict
|
||||||
"""
|
"""
|
||||||
|
super(Configuration, self).__init__(default)
|
||||||
|
|
||||||
self.__name = name
|
self.__name = name
|
||||||
self.__value = None
|
self.__children = self._create_children(default)
|
||||||
self.__children = dict()
|
|
||||||
if default is not None:
|
|
||||||
self.update(default)
|
|
||||||
super(Configuration, self).__init__()
|
|
||||||
|
|
||||||
def __deepcopy__(self, memo):
|
def __deepcopy__(self, memo):
|
||||||
"""Create and return full copy of provider."""
|
"""Create and return full copy of provider."""
|
||||||
|
@ -868,7 +866,7 @@ cdef class Configuration(Provider):
|
||||||
return copied
|
return copied
|
||||||
|
|
||||||
copied = self.__class__(self.__name)
|
copied = self.__class__(self.__name)
|
||||||
copied.__value = deepcopy(self.__value, memo)
|
copied.__provides = deepcopy(self.__provides, memo)
|
||||||
copied.__children = deepcopy(self.__children, memo)
|
copied.__children = deepcopy(self.__children, memo)
|
||||||
|
|
||||||
self._copy_overridings(copied)
|
self._copy_overridings(copied)
|
||||||
|
@ -884,9 +882,6 @@ cdef class Configuration(Provider):
|
||||||
|
|
||||||
def __getattr__(self, str name):
|
def __getattr__(self, str name):
|
||||||
"""Return child configuration provider."""
|
"""Return child configuration provider."""
|
||||||
cdef Configuration child_provider
|
|
||||||
cdef object value
|
|
||||||
|
|
||||||
if name.startswith('__') and name.endswith('__'):
|
if name.startswith('__') and name.endswith('__'):
|
||||||
raise AttributeError(
|
raise AttributeError(
|
||||||
'\'{cls}\' object has no attribute '
|
'\'{cls}\' object has no attribute '
|
||||||
|
@ -896,55 +891,103 @@ cdef class Configuration(Provider):
|
||||||
child_provider = self.__children.get(name)
|
child_provider = self.__children.get(name)
|
||||||
|
|
||||||
if child_provider is None:
|
if child_provider is None:
|
||||||
child_provider = self.__class__(self._get_child_name(name))
|
child_name = self._get_child_full_name(name)
|
||||||
|
child_provider = self.__class__(child_name)
|
||||||
|
|
||||||
if isinstance(self.__value, dict):
|
value = self.__call__()
|
||||||
child_provider.update(self.__value.get(name))
|
if isinstance(value, dict):
|
||||||
|
child_value = value.get(name)
|
||||||
|
child_provider.override(child_value)
|
||||||
|
|
||||||
self.__children[name] = child_provider
|
self.__children[name] = child_provider
|
||||||
|
|
||||||
return child_provider
|
return child_provider
|
||||||
|
|
||||||
cpdef str get_name(self):
|
def get_name(self):
|
||||||
"""Name of configuration unit."""
|
"""Name of configuration unit."""
|
||||||
return self.__name
|
return self.__name
|
||||||
|
|
||||||
cpdef object update(self, value):
|
def override(self, provider):
|
||||||
|
"""Override provider with another provider.
|
||||||
|
|
||||||
|
:param provider: Overriding provider.
|
||||||
|
:type provider: :py:class:`Provider`
|
||||||
|
|
||||||
|
:raise: :py:exc:`dependency_injector.errors.Error`
|
||||||
|
|
||||||
|
:return: Overriding context.
|
||||||
|
:rtype: :py:class:`OverridingContext`
|
||||||
|
"""
|
||||||
|
overriding_context = super(Configuration, self).override(provider)
|
||||||
|
|
||||||
|
value = self.__call__()
|
||||||
|
if not isinstance(value, dict):
|
||||||
|
return
|
||||||
|
|
||||||
|
for name in value:
|
||||||
|
child_provider = self.__children.get(name)
|
||||||
|
if child_provider is None:
|
||||||
|
continue
|
||||||
|
child_provider.override(value.get(name))
|
||||||
|
|
||||||
|
return overriding_context
|
||||||
|
|
||||||
|
def reset_last_overriding(self):
|
||||||
|
"""Reset last overriding provider.
|
||||||
|
|
||||||
|
:raise: :py:exc:`dependency_injector.errors.Error` if provider is not
|
||||||
|
overridden.
|
||||||
|
|
||||||
|
:rtype: None
|
||||||
|
"""
|
||||||
|
for child in self.__children.values():
|
||||||
|
try:
|
||||||
|
child.reset_last_overriding()
|
||||||
|
except Error:
|
||||||
|
pass
|
||||||
|
super(Configuration, self).reset_last_overriding()
|
||||||
|
|
||||||
|
def reset_override(self):
|
||||||
|
"""Reset all overriding providers.
|
||||||
|
|
||||||
|
:rtype: None
|
||||||
|
"""
|
||||||
|
for child in self.__children.values():
|
||||||
|
child.reset_override()
|
||||||
|
super(Configuration, self).reset_override()
|
||||||
|
|
||||||
|
def update(self, value):
|
||||||
"""Set configuration options.
|
"""Set configuration options.
|
||||||
|
|
||||||
|
.. deprecated:: 3.11
|
||||||
|
|
||||||
|
Use :py:meth:`Configuration.override` instead.
|
||||||
|
|
||||||
:param value: Value of configuration option.
|
:param value: Value of configuration option.
|
||||||
:type value: object | dict
|
:type value: object | dict
|
||||||
|
|
||||||
:rtype: None
|
:rtype: None
|
||||||
"""
|
"""
|
||||||
cdef Configuration child_provider
|
self.override(value)
|
||||||
cdef object child_value
|
|
||||||
|
|
||||||
self.__value = value
|
def _create_children(self, value):
|
||||||
|
children = dict()
|
||||||
|
|
||||||
if not isinstance(self.__value, dict):
|
if not isinstance(value, dict):
|
||||||
return
|
return children
|
||||||
|
|
||||||
for name in self.__value:
|
for child_name, child_value in value.items():
|
||||||
child_provider = self.__children.get(name)
|
child_full_name = self._get_child_full_name(child_name)
|
||||||
|
child_provider = self.__class__(child_full_name, child_value)
|
||||||
|
children[child_name] = child_provider
|
||||||
|
|
||||||
if child_provider is None:
|
return children
|
||||||
continue
|
|
||||||
|
|
||||||
child_provider.update(self.__value.get(name))
|
|
||||||
|
|
||||||
cpdef object _provide(self, tuple args, dict kwargs):
|
|
||||||
"""Return result of provided callable's call."""
|
|
||||||
return self.__value
|
|
||||||
|
|
||||||
cpdef str _get_child_name(self, str child_name):
|
|
||||||
cdef str child_full_name
|
|
||||||
|
|
||||||
|
def _get_child_full_name(self, child_name):
|
||||||
child_full_name = ''
|
child_full_name = ''
|
||||||
|
|
||||||
if self.__name:
|
if self.__name:
|
||||||
child_full_name += self.__name + '.'
|
child_full_name += self.__name + '.'
|
||||||
|
|
||||||
child_full_name += child_name
|
child_full_name += child_name
|
||||||
|
|
||||||
return child_full_name
|
return child_full_name
|
||||||
|
|
|
@ -60,8 +60,33 @@ class ConfigTests(unittest.TestCase):
|
||||||
self.assertEqual(abc(), 1)
|
self.assertEqual(abc(), 1)
|
||||||
self.assertEqual(abd(), 2)
|
self.assertEqual(abd(), 2)
|
||||||
|
|
||||||
def test_providers_with_default_value(self):
|
def test_providers_value_override(self):
|
||||||
|
a = self.config.a
|
||||||
|
ab = self.config.a.b
|
||||||
|
abc = self.config.a.b.c
|
||||||
|
abd = self.config.a.b.d
|
||||||
|
|
||||||
|
self.config.override({'a': {'b': {'c': 1, 'd': 2}}})
|
||||||
|
|
||||||
|
self.assertEqual(a(), {'b': {'c': 1, 'd': 2}})
|
||||||
|
self.assertEqual(ab(), {'c': 1, 'd': 2})
|
||||||
|
self.assertEqual(abc(), 1)
|
||||||
|
self.assertEqual(abd(), 2)
|
||||||
|
|
||||||
|
def test_providers_with_already_overridden_value(self):
|
||||||
|
self.config.override({'a': {'b': {'c': 1, 'd': 2}}})
|
||||||
|
|
||||||
|
a = self.config.a
|
||||||
|
ab = self.config.a.b
|
||||||
|
abc = self.config.a.b.c
|
||||||
|
abd = self.config.a.b.d
|
||||||
|
|
||||||
|
self.assertEqual(a(), {'b': {'c': 1, 'd': 2}})
|
||||||
|
self.assertEqual(ab(), {'c': 1, 'd': 2})
|
||||||
|
self.assertEqual(abc(), 1)
|
||||||
|
self.assertEqual(abd(), 2)
|
||||||
|
|
||||||
|
def test_providers_with_default_value(self):
|
||||||
self.config = providers.Configuration(
|
self.config = providers.Configuration(
|
||||||
name='config', default={'a': {'b': {'c': 1, 'd': 2}}})
|
name='config', default={'a': {'b': {'c': 1, 'd': 2}}})
|
||||||
|
|
||||||
|
@ -75,6 +100,27 @@ class ConfigTests(unittest.TestCase):
|
||||||
self.assertEqual(abc(), 1)
|
self.assertEqual(abc(), 1)
|
||||||
self.assertEqual(abd(), 2)
|
self.assertEqual(abd(), 2)
|
||||||
|
|
||||||
|
def test_providers_with_default_value_overriding(self):
|
||||||
|
self.config = providers.Configuration(
|
||||||
|
name='config', default={'a': {'b': {'c': 1, 'd': 2}}})
|
||||||
|
|
||||||
|
self.assertEqual(self.config.a(), {'b': {'c': 1, 'd': 2}})
|
||||||
|
self.assertEqual(self.config.a.b(), {'c': 1, 'd': 2})
|
||||||
|
self.assertEqual(self.config.a.b.c(), 1)
|
||||||
|
self.assertEqual(self.config.a.b.d(), 2)
|
||||||
|
|
||||||
|
self.config.override({'a': {'b': {'c': 3, 'd': 4}}})
|
||||||
|
self.assertEqual(self.config.a(), {'b': {'c': 3, 'd': 4}})
|
||||||
|
self.assertEqual(self.config.a.b(), {'c': 3, 'd': 4})
|
||||||
|
self.assertEqual(self.config.a.b.c(), 3)
|
||||||
|
self.assertEqual(self.config.a.b.d(), 4)
|
||||||
|
|
||||||
|
self.config.reset_override()
|
||||||
|
self.assertEqual(self.config.a(), {'b': {'c': 1, 'd': 2}})
|
||||||
|
self.assertEqual(self.config.a.b(), {'c': 1, 'd': 2})
|
||||||
|
self.assertEqual(self.config.a.b.c(), 1)
|
||||||
|
self.assertEqual(self.config.a.b.d(), 2)
|
||||||
|
|
||||||
def test_value_of_undefined_option(self):
|
def test_value_of_undefined_option(self):
|
||||||
self.assertIsNone(self.config.a())
|
self.assertIsNone(self.config.a())
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user