Skip to content

Commit 74a058e

Browse files
committed
Merge branch 'release/3.8.0' into master
2 parents 73ce30e + 83a792b commit 74a058e

File tree

8 files changed

+1276
-717
lines changed

8 files changed

+1276
-717
lines changed

docs/main/changelog.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ that were made in every particular version.
77
From version 0.7.6 *Dependency Injector* framework strictly
88
follows `Semantic versioning`_
99

10+
3.8.0
11+
-----
12+
- Add ``DeclarativeContainer.containers`` attribute that stores dictionary of
13+
nested containers.
14+
- Fix bug related to double-overridden providers (provider1 -> provider2 ->
15+
provider3).
16+
1017
3.7.1
1118
-----
1219
- Add support of six 1.11.0.

src/dependency_injector/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""Dependency injector top-level package."""
22

3-
__version__ = '3.7.1'
3+
__version__ = '3.8.0'
44
"""Version number that follows semantic versioning.
55
66
:type: str

src/dependency_injector/containers.c

Lines changed: 1171 additions & 671 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: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,12 @@ class DeclarativeContainerMetaClass(type):
144144
cdef tuple inherited_providers
145145
cdef type cls
146146

147+
containers = tuple((name, container)
148+
for name, container in six.iteritems(attributes)
149+
if is_container(container))
150+
151+
attributes['containers'] = dict(containers)
152+
147153
cls_providers = tuple((name, provider)
148154
for name, provider in six.iteritems(attributes)
149155
if isinstance(provider, Provider))
@@ -229,6 +235,12 @@ class DeclarativeContainer(object):
229235
:type: type
230236
"""
231237

238+
containers = dict()
239+
"""Read-only dictionary of all nested containers.
240+
241+
:type: dict[str, :py:class:`DeclarativeContainer`]
242+
"""
243+
232244
providers = dict()
233245
"""Read-only dictionary of all providers.
234246

src/dependency_injector/providers.c

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

src/dependency_injector/providers.pyx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ cdef class Provider(object):
9696
Callable interface implementation.
9797
"""
9898
if self.__last_overriding is not None:
99-
return self.__last_overriding._provide(args, kwargs)
99+
return self.__last_overriding(*args, **kwargs)
100100
return self._provide(args, kwargs)
101101

102102
def __deepcopy__(self, memo):
@@ -353,7 +353,7 @@ cdef class ExternalDependency(Provider):
353353
if self.__last_overriding is None:
354354
raise Error('Dependency is not defined')
355355

356-
instance = self.__last_overriding._provide(args, kwargs)
356+
instance = self.__last_overriding(*args, **kwargs)
357357

358358
if not isinstance(instance, self.instance_of):
359359
raise Error('{0} is not an '.format(instance) +
@@ -634,7 +634,7 @@ cdef class AbstractCallable(Callable):
634634
"""
635635
if self.__last_overriding is None:
636636
raise Error('{0} must be overridden before calling'.format(self))
637-
return self.__last_overriding._provide(args, kwargs)
637+
return self.__last_overriding(*args, **kwargs)
638638

639639
def override(self, provider):
640640
"""Override provider with another provider.
@@ -1076,7 +1076,7 @@ cdef class AbstractFactory(Factory):
10761076
"""
10771077
if self.__last_overriding is None:
10781078
raise Error('{0} must be overridden before calling'.format(self))
1079-
return self.__last_overriding._provide(args, kwargs)
1079+
return self.__last_overriding(*args, **kwargs)
10801080

10811081
def override(self, provider):
10821082
"""Override provider with another provider.
@@ -1606,7 +1606,7 @@ cdef class AbstractSingleton(BaseSingleton):
16061606
"""
16071607
if self.__last_overriding is None:
16081608
raise Error('{0} must be overridden before calling'.format(self))
1609-
return self.__last_overriding._provide(args, kwargs)
1609+
return self.__last_overriding(*args, **kwargs)
16101610

16111611
def override(self, provider):
16121612
"""Override provider with another provider.

tests/unit/containers/test_declarative.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,3 +250,18 @@ class _Container2(_Container):
250250

251251
self.assertEqual(_Container1.p13(), 11)
252252
self.assertEqual(_Container2.p13(), 22)
253+
254+
def test_containers_attribute(self):
255+
class Container(containers.DeclarativeContainer):
256+
class Container1(containers.DeclarativeContainer):
257+
pass
258+
259+
class Container2(containers.DeclarativeContainer):
260+
pass
261+
262+
Container3 = containers.DynamicContainer()
263+
264+
self.assertEqual(Container.containers,
265+
dict(Container1=Container.Container1,
266+
Container2=Container.Container2,
267+
Container3=Container.Container3))

tests/unit/providers/test_base.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,15 @@ def test_override(self):
5151
self.assertTrue(self.provider.overridden)
5252
self.assertIs(self.provider.last_overriding, overriding_provider)
5353

54+
def test_double_override(self):
55+
overriding_provider1 = providers.Object(1)
56+
overriding_provider2 = providers.Object(2)
57+
58+
self.provider.override(overriding_provider1)
59+
overriding_provider1.override(overriding_provider2)
60+
61+
self.assertEqual(self.provider(), overriding_provider2())
62+
5463
def test_overriding_context(self):
5564
overriding_provider = providers.Provider()
5665
with self.provider.override(overriding_provider):

0 commit comments

Comments
 (0)