Skip to content

Commit

Permalink
Merge f6d7957 into 73a43e6
Browse files Browse the repository at this point in the history
  • Loading branch information
rmk135 authored Oct 7, 2021
2 parents 73a43e6 + f6d7957 commit e65e4eb
Show file tree
Hide file tree
Showing 8 changed files with 2,558 additions and 1,885 deletions.
31 changes: 30 additions & 1 deletion docs/containers/declarative.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,39 @@ Injections in the declarative container are done the usual way:
:language: python
:lines: 3-

You can override the container providers when you create the container instance:
You can override container providers while creating a container instance:

.. literalinclude:: ../../examples/containers/declarative_override_providers.py
:language: python
:lines: 3-
:emphasize-lines: 13

Alternatively, you can call ``container.override_providers()`` method when the container instance
already exists:

.. code-block:: python
:emphasize-lines: 3
container = Container()
container.override_providers(foo=mock.Mock(Foo), bar=mock.Mock(Bar))
assert isinstance(container.foo(), mock.Mock)
assert isinstance(container.bar(), mock.Mock)
You can also use ``container.override_providers()`` with a context manager to reset
provided overriding after the context is closed:

.. code-block:: python
:emphasize-lines: 3
container = Container()
with container.override_providers(foo=mock.Mock(Foo), bar=mock.Mock(Bar)):
assert isinstance(container.foo(), mock.Mock)
assert isinstance(container.bar(), mock.Mock)
assert isinstance(container.foo(), Foo)
assert isinstance(container.bar(), Bar)
.. disqus::
1 change: 1 addition & 0 deletions docs/main/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Develop
- Improve wiring with adding importing modules and packages from a string
``container.wire(modules=["yourapp.module1"])``.
- Add container wiring configuration ``wiring_config = containers.WiringConfiguration()``.
- Add support of ``with`` statement for ``container.override_providers()`` method.
- Update documentation and fix typos.

4.36.2
Expand Down
4,366 changes: 2,484 additions & 1,882 deletions src/dependency_injector/containers.c

Large diffs are not rendered by default.

8 changes: 7 additions & 1 deletion src/dependency_injector/containers.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class Container:
def set_providers(self, **providers: Provider): ...
def set_provider(self, name: str, provider: Provider) -> None: ...
def override(self, overriding: C_Base) -> None: ...
def override_providers(self, **overriding_providers: Union[Provider, Any]) -> None: ...
def override_providers(self, **overriding_providers: Union[Provider, Any]) -> ProvidersOverridingContext[C_Base]: ...
def reset_last_overriding(self) -> None: ...
def reset_override(self) -> None: ...
def is_auto_wiring_enabled(self) -> bool: ...
Expand Down Expand Up @@ -90,6 +90,12 @@ class DeclarativeContainer(Container):
def __init__(self, **overriding_providers: Union[Provider, Any]) -> None: ...


class ProvidersOverridingContext(Generic[T]):
def __init__(self, container: T, overridden_providers: Iterable[Union[Provider, Any]]) -> None: ...
def __enter__(self) -> T: ...
def __exit__(self, *_: Any) -> None: ...


class SingletonResetContext(Generic[T]):
def __init__(self, container: T): ...
def __enter__(self) -> T: ...
Expand Down
18 changes: 18 additions & 0 deletions src/dependency_injector/containers.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,12 @@ class DynamicContainer(Container):
:rtype: None
"""
overridden_providers = []
for name, overriding_provider in six.iteritems(overriding_providers):
container_provider = getattr(self, name)
container_provider.override(overriding_provider)
overridden_providers.append(container_provider)
return ProvidersOverridingContext(self, overridden_providers)

def reset_last_overriding(self):
"""Reset last overriding provider for each container providers.
Expand Down Expand Up @@ -784,6 +787,21 @@ class SingletonResetContext:
self._container.reset_singletons()



class ProvidersOverridingContext:

def __init__(self, container, overridden_providers):
self._container = container
self._overridden_providers = overridden_providers

def __enter__(self):
return self._container

def __exit__(self, *_):
for provider in self._overridden_providers:
provider.reset_last_overriding()


def override(object container):
""":py:class:`DeclarativeContainer` overriding decorator.
Expand Down
4 changes: 3 additions & 1 deletion tests/typing/declarative_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,11 @@ class Container6(containers.DeclarativeContainer):
container6: containers.Container = Container6()


# Test 7: to override()
# Test 7: to override_providers()
class Container7(containers.DeclarativeContainer):
provider = providers.Factory(str)

container7 = Container7()
container7.override_providers(provider="new_value")
with container7.override_providers(a=providers.Provider()):
...
2 changes: 2 additions & 0 deletions tests/typing/dynamic_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
# Test 3: to check override_providers()
container3 = containers.DynamicContainer()
container3.override_providers(a=providers.Provider())
with container3.override_providers(a=providers.Provider()):
...

# Test 4: to check set_providers()
container4 = containers.DynamicContainer()
Expand Down
13 changes: 13 additions & 0 deletions tests/unit/containers/test_dynamic_py2_py3.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,19 @@ def test_override_providers(self):
self.assertIs(container_a.p11.last_overriding, p1)
self.assertIs(container_a.p12.last_overriding, p2)

def test_override_providers_context_manager(self):
p1 = providers.Provider()
p2 = providers.Provider()
container_a = ContainerA()

with container_a.override_providers(p11=p1, p12=p2) as container:
self.assertIs(container, container_a)
self.assertIs(container_a.p11.last_overriding, p1)
self.assertIs(container_a.p12.last_overriding, p2)

self.assertIsNone(container_a.p11.last_overriding)
self.assertIsNone(container_a.p12.last_overriding)

def test_override_providers_with_unknown_provider(self):
container_a = ContainerA()

Expand Down

0 comments on commit e65e4eb

Please sign in to comment.