8000 Container.reset_singletons() (#390) · kiq7/python-dependency-injector@c964253 · GitHub
[go: up one dir, main page]

Skip to content

Commit c964253

Browse files
authored
Container.reset_singletons() (ets-labs#390)
* Rename container tests * Add implementation + tests * Update changelog * Add examples and docs
1 parent c4892af commit c964253

File tree

9 files changed

+1056
-725
lines changed

9 files changed

+1056
-725
lines changed

docs/containers/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@ Containers module API docs - :py:mod:`dependency_injector.containers`.
2323
dynamic
2424
specialization
2525
overriding
26+
reset_singletons
2627
traversal

docs/containers/reset_singletons.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Reset container singletons
2+
--------------------------
3+
4+
To reset all container singletons use method ``.reset_singletons()``.
5+
6+
.. literalinclude:: ../../examples/containers/reset_singletons.py
7+
:language: python
8+
:lines: 3-
9+
:emphasize-lines: 16
10+
11+
Method ``.reset_singletons()`` also resets singletons in sub-containers: ``providers.Container`` and
12+
``providers.DependenciesContainer.``
13+
14+
.. literalinclude:: ../../examples/containers/reset_singletons_subcontainers.py
15+
:language: python
16+
:lines: 3-
17+
:emphasize-lines: 21
18+
19+
.. disqus::

docs/main/changelog.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ follows `Semantic versioning`_
99

1010
Development version
1111
-------------------
12+
- Add ``container.reset_singleton()`` method to reset container singletons.
1213
- Refactor ``container.apply_container_providers_overridings()`` to use ``container.traverse()``.
1314
This enables deep lazy initialization of ``Container`` providers.
1415
- Add tests for ``Selector`` provider.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
"""Container reset singletons example."""
2+
3+
from dependency_injector import containers, providers
4+
5+
6+
class Container(containers.DeclarativeContainer):
7+
8+
service1 = providers.Singleton(object)
9+
service2 = providers.Singleton(object)
10+
11+
12+
if __name__ == '__main__':
13+
container = Container()
14+
15+
service1 = container.service1()
16+
service2 = container.service2()
17+
18+
container.reset_singletons()
19+
20+
assert service1 is not container.service1()
21+
assert service2 is not container.service2()
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""Container reset singletons in subcontainer example."""
2+
3+
from dependency_injector import containers, providers
4+
5+
6+
class SubContainer(containers.DeclarativeContainer):
7+
8+
service = providers.Singleton(object)
9+
10+
11+
class Container(containers.DeclarativeContainer):
12+
13+
service = providers.Singleton(object)
14+
sub = providers.Container(SubContainer)
15+
16+
17+
if __name__ == '__main__':
18+
container = Container()
19+
20+
service1 = container.service()
21+
service2 = container.sub().service()
22+
23+
container.reset_singletons()
24+
25+
assert service1 is not container.service()
26+
assert service2 is not container.sub().service()

src/dependency_injector/containers.c

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

src/dependency_injector/containers.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ class Container:
4343
def unwire(self) -> None: ...
4444
def init_resources(self) -> Optional[Awaitable]: ...
4545
def shutdown_resources(self) -> Optional[Awaitable]: ...
46+
def apply_container_providers_overridings(self) -> None: ...
47+
def reset_singletons(self) -> None: ...
4648
@overload
4749
def traverse(self, types: Optional[Sequence[Type]] = None) -> Iterator[Provider]: ...
4850
@classmethod

src/dependency_injector/containers.pyx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,11 @@ class DynamicContainer(Container):
271271
for provider in self.traverse(types=[providers.Container]):
272272
provider.apply_overridings()
273273

274+
def reset_singletons(self):
275+
"""Reset all container singletons."""
276+
for provider in self.traverse(types=[providers.Singleton]):
277+
provider.reset()
278+
274279

275280
class DeclarativeContainerMetaClass(type):
276281
"""Declarative inversion of control container meta class."""

tests/unit/containers/test_dynamic_py2_py3.py

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ def test_override_providers_with_unknown_provider(self):
140140
with self.assertRaises(AttributeError):
141141
container_a.override_providers(unknown=providers.Provider())
142142

143-
def test_reset_last_overridding(self):
143+
def test_reset_last_overriding(self):
144144
class _Container(containers.DeclarativeContainer):
145145
p11 = providers.Provider()
146146

@@ -164,7 +164,7 @@ class _OverridingContainer2(containers.DeclarativeContainer):
164164
self.assertEqual(container.p11.overridden,
165165
(overriding_container1.p11,))
166166

167-
def test_reset_last_overridding_when_not_overridden(self):
167+
def test_reset_last_overriding_when_not_overridden(self):
168168
container = ContainerA()
169169

170170
with self.assertRaises(errors.Error):
@@ -287,3 +287,51 @@ class Container(containers.DeclarativeContainer):
287287
self.assertEqual(_init1.shutdown_counter, 2)
288288
self.assertEqual(_init2.init_counter, 2)
289289
self.assertEqual(_init2.shutdown_counter, 2)
290+
291+
def reset_singletons(self):
292+
class SubSubContainer(containers.DeclarativeContainer):
293+
singleton = providers.Singleton(object)
294+
295+
class SubContainer(containers.DeclarativeContainer):
296+
singleton = providers.Singleton(object)
297+
sub_sub_container = providers.Container(SubSubContainer)
298+
299+
class Container(containers.DeclarativeContainer):
300+
singleton = providers.Singleton(object)
301+
sub_container = providers.Container(SubContainer)
302+
303+
container = Container()
304+
305+
obj11 = container.singleton()
306+
obj12 = container.sub_container().singleton()
307+
obj13 = container.sub_container().sub_sub_container().singleton()
308+
309+
obj21 = container.singleton()
310+
obj22 = container.sub_container().singleton()
311+
obj23 = container.sub_container().sub_sub_container().singleton()
312+
313+
self.assertIs(obj11, obj21)
314+
self.assertIs(obj12, obj22)
315+
self.assertIs(obj13, obj23)
316+
317+
container.reset_singletons()
318+
319+
obj31 = container.singleton()
320+
obj32 = container.sub_container().singleton()
321+
obj33 = container.sub_container().sub_sub_container().singleton()
322+
323+
obj41 = container.singleton()
324+
obj42 = container.sub_container().singleton()
325+
obj43 = container.sub_container().sub_sub_container().singleton()
326+
327+
self.assertIsNot(obj11, obj31)
328+
self.assertIsNot(obj12, obj32)
329+
self.assertIsNot(obj13, obj33)
330+
331+
self.assertIsNot(obj21, obj31)
332+
self.assertIsNot(obj22, obj32)
333+
self.assertIsNot(obj23, obj33)
334+
335+
self.assertIs(obj31, obj41)
336+
self.assertIs(obj32, obj42)
337+
self.assertIs(obj33, obj43)

0 commit comments

Comments
 (0)
0