Fix `Container` provider to apply context overridings on root container initialization

This commit is contained in:
Roman Mogylatov 2021-01-13 17:07:41 -05:00
parent de6c3cda78
commit 1628cfaf28
6 changed files with 5918 additions and 5595 deletions

View File

@ -9,6 +9,9 @@ follows `Semantic versioning`_
Development version Development version
------------------- -------------------
- Fix ``Container`` provider to apply context overridings on root container initialization.
See issue `#354 <https://github.com/ets-labs/python-dependency-injector/issues/354>`_.
Many thanks to `Shaun Cutts <https://github.com/shaunc>`_ for submitting the issue.
- Hotfix for version ``4.8.0``: fix side effect in ``Container`` provider overriding. - Hotfix for version ``4.8.0``: fix side effect in ``Container`` provider overriding.
4.8.1 4.8.1

File diff suppressed because it is too large Load Diff

View File

@ -15,6 +15,7 @@ from .providers cimport (
Provider, Provider,
Object, Object,
Resource, Resource,
Container as ContainerProvider,
deepcopy, deepcopy,
) )
@ -252,6 +253,13 @@ class DynamicContainer(object):
if futures: if futures:
return asyncio.gather(*futures) return asyncio.gather(*futures)
def apply_container_providers_overridings(self):
"""Apply container providers' overridings."""
for provider in self.providers.values():
if not isinstance(provider, ContainerProvider):
continue
provider.apply_overridings()
class DeclarativeContainerMetaClass(type): class DeclarativeContainerMetaClass(type):
"""Declarative inversion of control container meta class.""" """Declarative inversion of control container meta class."""
@ -407,6 +415,7 @@ class DeclarativeContainer(object):
container.declarative_parent = cls container.declarative_parent = cls
container.set_providers(**deepcopy(cls.providers)) container.set_providers(**deepcopy(cls.providers))
container.override_providers(**overriding_providers) container.override_providers(**overriding_providers)
container.apply_container_providers_overridings()
return container return container
@classmethod @classmethod

File diff suppressed because it is too large Load Diff

View File

@ -765,10 +765,7 @@ cdef class DependenciesContainer(Object):
cpdef object _override_providers(self, object container): cpdef object _override_providers(self, object container):
"""Override providers with providers from provided container.""" """Override providers with providers from provided container."""
for name, dependency_provider in container.providers.items(): for name, dependency_provider in container.providers.items():
provider = self.__providers.get(name) provider = getattr(self, name)
if not provider:
continue
if provider.last_overriding is dependency_provider: if provider.last_overriding is dependency_provider:
continue continue
@ -3041,7 +3038,6 @@ cdef class Container(Provider):
if container is None: if container is None:
container = container_cls() container = container_cls()
container.override_providers(**overriding_providers)
self.__container = container self.__container = container
super(Container, self).__init__() super(Container, self).__init__()
@ -3085,6 +3081,13 @@ cdef class Container(Provider):
self.__container.override_providers(**provider.providers) self.__container.override_providers(**provider.providers)
super().override(provider) super().override(provider)
def apply_overridings(self):
"""Apply container overriding.
This method should not be called directly. It is called on
declarative container initialization."""
self.__container.override_providers(**self.__overriding_providers)
cpdef object _provide(self, tuple args, dict kwargs): cpdef object _provide(self, tuple args, dict kwargs):
"""Return single instance.""" """Return single instance."""
return self.__container return self.__container

View File

@ -76,3 +76,21 @@ class ContainerTests(unittest.TestCase):
with self.assertRaises(errors.Error): with self.assertRaises(errors.Error):
provider.override(providers.Object('foo')) provider.override(providers.Object('foo'))
def test_lazy_overriding(self):
class D(containers.DeclarativeContainer):
foo = providers.Object("foo")
class A(containers.DeclarativeContainer):
d = providers.DependenciesContainer()
bar = providers.Callable(lambda f: f + "++", d.foo.provided)
class B(containers.DeclarativeContainer):
d = providers.DependenciesContainer()
a = providers.Container(A, d=d)
b = B(d=D())
result = b.a().bar()
self.assertEqual(result, 'foo++')
# See: https://github.com/ets-labs/python-dependency-injector/issues/354