Skip to content

Commit 1c6160e

Browse files
authored
Feature/declarative container initialization (ets-labs#176)
* Add overriding functionality on declarative container initialization * Update changelog * Update bundles example
1 parent 1115e78 commit 1c6160e

File tree

10 files changed

+1787
-1221
lines changed

10 files changed

+1787
-1221
lines changed

docs/main/changelog.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ Development version
1212
- Rename ``ExternalDependency`` provider to ``Dependency``.
1313
- Add default value for ``instance_of`` argument of ``Dependency`` provider -
1414
``Dependency(instance_of=object)``.
15+
- Change initialization of declarative container, so it accepts overriding
16+
providers as keyword arguments -
17+
``DeclarativeContainer(**overriding_providers)``.
18+
- Add method to dynamic catalog for setting groups of providers -
19+
``DynamicContainer.set_providers(**providers)``.
20+
- Add method to dynamic catalog for overriding groups of providers -
21+
``DynamicContainer.set_providers(**overriding_providers)``.
1522

1623

1724
3.8.2

examples/miniapps/bundles/bundles/photos/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""Photos bundle."""
22

3-
from core import containers
3+
from dependency_injector import containers
44
from dependency_injector import providers
55

66
from . import entities

examples/miniapps/bundles/bundles/users/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""Users bundle."""
22

3-
from core import containers
3+
from dependency_injector import containers
44
from dependency_injector import providers
55

66
from . import entities

examples/miniapps/bundles/core/__init__.py

Whitespace-only changes.

examples/miniapps/bundles/core/containers.py

Lines changed: 0 additions & 43 deletions
This file was deleted.

examples/miniapps/bundles/run.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""Example application - Bundles."""
22

3-
from core import containers
3+
from dependency_injector import containers
44
from dependency_injector import providers
55

66
from bundles.users import Users

src/dependency_injector/containers.c

Lines changed: 1713 additions & 1169 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/dependency_injector/containers.pyx

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,18 @@ class DynamicContainer(object):
8888
del self.providers[name]
8989
super(DynamicContainer, self).__delattr__(name)
9090

91+
def set_providers(self, **providers):
92+
"""Set container providers.
93+
94+
:param providers: Dictionary of providers
95+
:type providers:
96+
dict[str, :py:class:`dependency_injector.providers.Provider`]
97+
98+
:rtype: None
99+
"""
100+
for name, provider in six.iteritems(providers):
101+
setattr(self, name, provider)
102+
91103
def override(self, object overriding):
92104
"""Override current container by overriding container.
93105
@@ -111,6 +123,19 @@ class DynamicContainer(object):
111123
except AttributeError:
112124
pass
113125

126+
def override_providers(self, **overriding_providers):
127+
"""Override container providers.
128+
129+
:param overriding_providers: Dictionary of providers
130+
:type overriding_providers:
131+
dict[str, :py:class:`dependency_injector.providers.Provider`]
132+
133+
:rtype: None
134+
"""
135+
for name, overriding_provider in six.iteritems(overriding_providers):
136+
container_provider = getattr(self, name)
137+
container_provider.override(overriding_provider)
138+
114139
def reset_last_overriding(self):
115140
"""Reset last overriding provider for each container providers.
116141
@@ -265,18 +290,16 @@ class DeclarativeContainer(object):
265290
:type: tuple[:py:class:`DeclarativeContainer`]
266291
"""
267292

268-
def __new__(cls, *args, **kwargs):
293+
def __new__(cls, **overriding_providers):
269294
"""Constructor.
270295
271296
:return: Dynamic container with copy of all providers.
272297
:rtype: :py:class:`DynamicContainer`
273298
"""
274-
container = cls.instance_type(*args, **kwargs)
299+
container = cls.instance_type()
275300
container.provider_type = cls.provider_type
276-
277-
for name, provider in six.iteritems(deepcopy(cls.providers)):
278-
setattr(container, name, provider)
279-
301+
container.set_providers(**deepcopy(cls.providers))
302+
container.override_providers(**overriding_providers)
280303
return container
281304

282305
@classmethod

tests/unit/containers/test_declarative.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,3 +265,12 @@ class Container2(containers.DeclarativeContainer):
265265
dict(Container1=Container.Container1,
266266
Container2=Container.Container2,
267267
Container3=Container.Container3))
268+
269+
def test_init_with_overriding_providers(self):
270+
p1 = providers.Provider()
271+
p2 = providers.Provider()
272+
273+
container = ContainerA(p11=p1, p12=p2)
274+
275+
self.assertIs(container.p11.last_overriding, p1)
276+
self.assertIs(container.p12.last_overriding, p2)

tests/unit/containers/test_dynamic.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,16 @@ def test_set_invalid_provider_type(self):
7575
self.assertIs(ContainerA.provider_type,
7676
containers.DeclarativeContainer.provider_type)
7777

78+
def test_set_providers(self):
79+
p13 = providers.Provider()
80+
p14 = providers.Provider()
81+
container_a = ContainerA()
82+
83+
container_a.set_providers(p13=p13, p14=p14)
84+
85+
self.assertIs(container_a.p13, p13)
86+
self.assertIs(container_a.p14, p14)
87+
7888
def test_override(self):
7989
class _Container(containers.DeclarativeContainer):
8090
p11 = providers.Provider()
@@ -108,6 +118,22 @@ def test_override_with_itself(self):
108118
with self.assertRaises(errors.Error):
109119
container.override(container)
110120

121+
def test_override_providers(self):
122+
p1 = providers.Provider()
123+
p2 = providers.Provider()
124+
container_a = ContainerA()
125+
126+
container_a.override_providers(p11=p1, p12=p2)
127+
128+
self.assertIs(container_a.p11.last_overriding, p1)
129+
self.assertIs(container_a.p12.last_overriding, p2)
130+
131+
def test_override_providers_with_unknown_provider(self):
132+
container_a = ContainerA()
133+
134+
with self.assertRaises(AttributeError):
135+
container_a.override_providers(unknown=providers.Provider())
136+
111137
def test_reset_last_overridding(self):
112138
class _Container(containers.DeclarativeContainer):
113139
p11 = providers.Provider()

0 commit comments

Comments
 (0)