Improve @containers.copy to replace subcontainer providers (#378)

* Improve @containers.copy to replace subcontainer providers

* Bump version to 4.11.1
This commit is contained in:
Roman Mogylatov 2021-01-27 09:21:45 -05:00 committed by GitHub
parent 78479c65e6
commit 92938b018d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 1007 additions and 497 deletions

View File

@ -7,6 +7,12 @@ that were made in every particular version.
From version 0.7.6 *Dependency Injector* framework strictly From version 0.7.6 *Dependency Injector* framework strictly
follows `Semantic versioning`_ follows `Semantic versioning`_
4.11.1
------
- Fix a bug in ``@containers.copy`` to improve replacing of subcontainer providers.
See issue `#378 <https://github.com/ets-labs/python-dependency-injector/issues/378>`_.
Many thanks to `Shaun Cutts <https://github.com/shaunc>`_ for reporting the issue.
4.11.0 4.11.0
------ ------
- Add ``loader`` argument to the configuration provider ``Configuration.from_yaml(..., loader=...)`` - Add ``loader`` argument to the configuration provider ``Configuration.from_yaml(..., loader=...)``

View File

@ -1,6 +1,6 @@
"""Top-level package.""" """Top-level package."""
__version__ = '4.11.0' __version__ = '4.11.1'
"""Version number. """Version number.
:type: str :type: str

File diff suppressed because it is too large Load Diff

View File

@ -541,16 +541,25 @@ def copy(object container):
:return: Declarative container's copying decorator. :return: Declarative container's copying decorator.
:rtype: callable(:py:class:`DeclarativeContainer`) :rtype: callable(:py:class:`DeclarativeContainer`)
""" """
def _decorator(copied_container): def _get_providers_memo(from_providers, source_providers):
cdef dict memo = dict() memo = dict()
for name, provider in six.iteritems(copied_container.cls_providers):
for name, provider in from_providers.items():
try: try:
source_provider = getattr(container, name) source_provider = source_providers[name]
except AttributeError: except KeyError:
pass ...
else: else:
memo[id(source_provider)] = provider memo[id(source_provider)] = provider
if hasattr(provider, 'providers') and hasattr(source_provider, 'providers'):
sub_memo = _get_providers_memo(provider.providers, source_provider.providers)
memo.update(sub_memo)
return memo
def _decorator(copied_container):
memo = _get_providers_memo(copied_container.cls_providers, container.providers)
providers_copy = deepcopy(container.providers, memo) providers_copy = deepcopy(container.providers, memo)
for name, provider in six.iteritems(providers_copy): for name, provider in six.iteritems(providers_copy):
setattr(copied_container, name, provider) setattr(copied_container, name, provider)

View File

@ -296,6 +296,26 @@ class DeclarativeContainerTests(unittest.TestCase):
self.assertEqual(_Container1.p13(), 11) self.assertEqual(_Container1.p13(), 11)
self.assertEqual(_Container2.p13(), 22) self.assertEqual(_Container2.p13(), 22)
def test_copy_with_replacing_subcontainer_providers(self):
# See: https://github.com/ets-labs/python-dependency-injector/issues/374
class X(containers.DeclarativeContainer):
foo = providers.Dependency(instance_of=str)
def build_x():
return X(foo='1')
class A(containers.DeclarativeContainer):
x = providers.DependenciesContainer(**X.providers)
y = x.foo
@containers.copy(A)
class B1(A):
x = providers.Container(build_x)
b1 = B1()
self.assertEqual(b1.y(), '1')
def test_containers_attribute(self): def test_containers_attribute(self):
class Container(containers.DeclarativeContainer): class Container(containers.DeclarativeContainer):
class Container1(containers.DeclarativeContainer): class Container1(containers.DeclarativeContainer):