mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-11-25 19:14:00 +03:00
Merge branch 'release/3.11.0' into master
This commit is contained in:
commit
0e50b1d379
|
@ -351,10 +351,10 @@ Next example demonstrates run of example application defined above:
|
|||
|
||||
if __name__ == '__main__':
|
||||
# Configure platform:
|
||||
Core.config.update({'database': {'dsn': ':memory:'},
|
||||
'aws': {'access_key_id': 'KEY',
|
||||
'secret_access_key': 'SECRET'},
|
||||
'auth': {'token_ttl': 3600}})
|
||||
Core.config.override({'database': {'dsn': ':memory:'},
|
||||
'aws': {'access_key_id': 'KEY',
|
||||
'secret_access_key': 'SECRET'},
|
||||
'auth': {'token_ttl': 3600}})
|
||||
Core.logger().addHandler(logging.StreamHandler(sys.stdout))
|
||||
|
||||
# Run application:
|
||||
|
|
|
@ -7,6 +7,13 @@ that were made in every particular version.
|
|||
From version 0.7.6 *Dependency Injector* framework strictly
|
||||
follows `Semantic versioning`_
|
||||
|
||||
3.11.0
|
||||
------
|
||||
- Improve ``Configuration`` provider overriding logic.
|
||||
- Refactor ``Configuration`` provider.
|
||||
- Improve ``DependenciesContainer`` provider overriding logic.
|
||||
- Update "services" example miniapp.
|
||||
- Update "bundles" example miniapp.
|
||||
|
||||
3.10.0
|
||||
------
|
||||
|
|
|
@ -23,8 +23,7 @@ class Core(containers.DeclarativeContainer):
|
|||
|
||||
if __name__ == '__main__':
|
||||
# Initializing containers
|
||||
core = Core()
|
||||
core.config.update({'database': {'dsn': ':memory:'},
|
||||
core = Core(config={'database': {'dsn': ':memory:'},
|
||||
'aws': {'access_key_id': 'KEY',
|
||||
'secret_access_key': 'SECRET'}})
|
||||
users = Users(database=core.sqlite)
|
||||
|
|
|
@ -8,10 +8,10 @@ from containers import Core, Application
|
|||
|
||||
if __name__ == '__main__':
|
||||
# Configure platform:
|
||||
Core.config.update({'database': {'dsn': ':memory:'},
|
||||
'aws': {'access_key_id': 'KEY',
|
||||
'secret_access_key': 'SECRET'},
|
||||
'auth': {'token_ttl': 3600}})
|
||||
Core.config.override({'database': {'dsn': ':memory:'},
|
||||
'aws': {'access_key_id': 'KEY',
|
||||
'secret_access_key': 'SECRET'},
|
||||
'auth': {'token_ttl': 3600}})
|
||||
Core.logger().addHandler(logging.StreamHandler(sys.stdout))
|
||||
|
||||
# Run application:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""Dependency injector top-level package."""
|
||||
|
||||
__version__ = '3.10.0'
|
||||
__version__ = '3.11.0'
|
||||
"""Version number that follows semantic versioning.
|
||||
|
||||
:type: str
|
||||
|
|
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
|
||||
cdef class Configuration(Provider):
|
||||
cdef class Configuration(Object):
|
||||
cdef str __name
|
||||
cdef object __value
|
||||
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
|
||||
cdef class Factory(Provider):
|
||||
|
|
|
@ -427,7 +427,6 @@ cdef class DependenciesContainer(Object):
|
|||
Dependencies container provider is used to implement late static binding
|
||||
for a set of providers of a particular container.
|
||||
|
||||
|
||||
Example code:
|
||||
|
||||
.. code-block:: python
|
||||
|
@ -520,6 +519,29 @@ cdef class DependenciesContainer(Object):
|
|||
self._override_providers(container=provider)
|
||||
return super(DependenciesContainer, self).override(provider)
|
||||
|
||||
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.__providers.values():
|
||||
try:
|
||||
child.reset_last_overriding()
|
||||
except Error:
|
||||
pass
|
||||
super(DependenciesContainer, self).reset_last_overriding()
|
||||
|
||||
def reset_override(self):
|
||||
"""Reset all overriding providers.
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
for child in self.__providers.values():
|
||||
child.reset_override()
|
||||
super(DependenciesContainer, self).reset_override()
|
||||
|
||||
cpdef object _override_providers(self, object container):
|
||||
"""Override providers with providers from provided container."""
|
||||
|
@ -823,7 +845,7 @@ cdef class CallableDelegate(Delegate):
|
|||
super(Delegate, self).__init__(callable)
|
||||
|
||||
|
||||
cdef class Configuration(Provider):
|
||||
cdef class Configuration(Object):
|
||||
"""Configuration provider.
|
||||
|
||||
Configuration provider helps with implementing late static binding of
|
||||
|
@ -836,8 +858,8 @@ cdef class Configuration(Provider):
|
|||
print(config.section1.option1()) # None
|
||||
print(config.section1.option2()) # None
|
||||
|
||||
config.update({'section1': {'option1': 1,
|
||||
'option2': 2}})
|
||||
config.override({'section1': {'option1': 1,
|
||||
'option2': 2}})
|
||||
|
||||
print(config.section1.option1()) # 1
|
||||
print(config.section1.option2()) # 2
|
||||
|
@ -852,12 +874,10 @@ cdef class Configuration(Provider):
|
|||
:param default: Default values of configuration unit.
|
||||
:type default: dict
|
||||
"""
|
||||
super(Configuration, self).__init__(default)
|
||||
|
||||
self.__name = name
|
||||
self.__value = None
|
||||
self.__children = dict()
|
||||
if default is not None:
|
||||
self.update(default)
|
||||
super(Configuration, self).__init__()
|
||||
self.__children = self._create_children(default)
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
"""Create and return full copy of provider."""
|
||||
|
@ -868,7 +888,7 @@ cdef class Configuration(Provider):
|
|||
return copied
|
||||
|
||||
copied = self.__class__(self.__name)
|
||||
copied.__value = deepcopy(self.__value, memo)
|
||||
copied.__provides = deepcopy(self.__provides, memo)
|
||||
copied.__children = deepcopy(self.__children, memo)
|
||||
|
||||
self._copy_overridings(copied)
|
||||
|
@ -884,9 +904,6 @@ cdef class Configuration(Provider):
|
|||
|
||||
def __getattr__(self, str name):
|
||||
"""Return child configuration provider."""
|
||||
cdef Configuration child_provider
|
||||
cdef object value
|
||||
|
||||
if name.startswith('__') and name.endswith('__'):
|
||||
raise AttributeError(
|
||||
'\'{cls}\' object has no attribute '
|
||||
|
@ -896,55 +913,103 @@ cdef class Configuration(Provider):
|
|||
child_provider = self.__children.get(name)
|
||||
|
||||
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):
|
||||
child_provider.update(self.__value.get(name))
|
||||
value = self.__call__()
|
||||
if isinstance(value, dict):
|
||||
child_value = value.get(name)
|
||||
child_provider.override(child_value)
|
||||
|
||||
self.__children[name] = child_provider
|
||||
|
||||
return child_provider
|
||||
|
||||
cpdef str get_name(self):
|
||||
def get_name(self):
|
||||
"""Name of configuration unit."""
|
||||
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.
|
||||
|
||||
.. deprecated:: 3.11
|
||||
|
||||
Use :py:meth:`Configuration.override` instead.
|
||||
|
||||
:param value: Value of configuration option.
|
||||
:type value: object | dict
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
cdef Configuration child_provider
|
||||
cdef object child_value
|
||||
self.override(value)
|
||||
|
||||
self.__value = value
|
||||
def _create_children(self, value):
|
||||
children = dict()
|
||||
|
||||
if not isinstance(self.__value, dict):
|
||||
return
|
||||
if not isinstance(value, dict):
|
||||
return children
|
||||
|
||||
for name in self.__value:
|
||||
child_provider = self.__children.get(name)
|
||||
for child_name, child_value in value.items():
|
||||
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:
|
||||
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
|
||||
return children
|
||||
|
||||
def _get_child_full_name(self, child_name):
|
||||
child_full_name = ''
|
||||
|
||||
if self.__name:
|
||||
child_full_name += self.__name + '.'
|
||||
|
||||
child_full_name += child_name
|
||||
|
||||
return child_full_name
|
||||
|
|
|
@ -341,6 +341,22 @@ class DependenciesContainerTests(unittest.TestCase):
|
|||
self.assertTrue(dependency.overridden)
|
||||
self.assertIs(dependency.last_overriding, self.container.dependency)
|
||||
|
||||
def test_reset_last_overriding(self):
|
||||
dependency = self.provider.dependency
|
||||
self.provider.override(self.container)
|
||||
self.provider.reset_last_overriding()
|
||||
|
||||
self.assertIsNone(dependency.last_overriding)
|
||||
self.assertIsNone(dependency.last_overriding)
|
||||
|
||||
def test_reset_override(self):
|
||||
dependency = self.provider.dependency
|
||||
self.provider.override(self.container)
|
||||
self.provider.reset_override()
|
||||
|
||||
self.assertFalse(dependency.overridden)
|
||||
self.assertFalse(dependency.overridden)
|
||||
|
||||
def test_init_with_container_and_providers(self):
|
||||
provider = providers.DependenciesContainer(
|
||||
self.container, dependency=providers.Dependency())
|
||||
|
|
|
@ -60,8 +60,33 @@ class ConfigTests(unittest.TestCase):
|
|||
self.assertEqual(abc(), 1)
|
||||
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(
|
||||
name='config', default={'a': {'b': {'c': 1, 'd': 2}}})
|
||||
|
||||
|
@ -75,6 +100,27 @@ class ConfigTests(unittest.TestCase):
|
|||
self.assertEqual(abc(), 1)
|
||||
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):
|
||||
self.assertIsNone(self.config.a())
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user