Skip to content

Commit 8eea9c4

Browse files
authored
Implement container.check_dependencies() (#396)
* Add implementation, typing stubs, and tests * Add docs and example * Update changelog
1 parent 2c5bb45 commit 8eea9c4

File tree

13 files changed

+7453
-6715
lines changed

13 files changed

+7453
-6715
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
.. _check-container-dependencies:
2+
3+
Check container dependencies
4+
----------------------------
5+
6+
To check container dependencies use method ``.check_dependencies()``.
7+
8+
.. literalinclude:: ../../examples/containers/check_dependencies.py
9+
:language: python
10+
:lines: 3-
11+
:emphasize-lines: 12
12+
13+
Method ``.check_dependencies()`` raises an error if container has any undefined dependencies.
14+
If all dependencies are provided or have defaults, no error is raised.
15+
16+
See also: :ref:`dependency-provider`.
17+
18+
.. disqus::

docs/containers/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,5 @@ Containers module API docs - :py:mod:`dependency_injector.containers`.
2424
specialization
2525
overriding
2626
reset_singletons
27+
check_dependencies
2728
traversal

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+
Development version
11+
-------------------
12+
- Add method ``container.check_dependencies()`` to check if all container dependencies
13+
are defined.
14+
See issue: `#383 <https://github.com/ets-labs/python-dependency-injector/issues/383>`_.
15+
Thanks to `@shaunc <https://github.com/shaunc>`_ for suggesting the feature.
16+
1017
4.21.0
1118
------
1219
- Improve ``Dependency`` provider error message: when dependency is undefined,

docs/providers/dependency.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
.. _dependency-provider:
2+
13
Dependency provider
24
===================
35

@@ -31,4 +33,6 @@ dependency provider will wrap it into the ``Object`` provider.
3133
:lines: 16-23
3234
:emphasize-lines: 3
3335

36+
See also: :ref:`check-container-dependencies`.
37+
3438
.. disqus::
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
"""Container dependencies check example."""
2+
3+
from dependency_injector import containers, providers
4+
5+
6+
class Container(containers.DeclarativeContainer):
7+
8+
service1 = providers.Dependency()
9+
service2 = providers.Dependency()
10+
11+
12+
if __name__ == '__main__':
13+
container = Container()
14+
container.check_dependencies() # <-- raises error:
15+
# Container has undefined dependencies: "Container.service1", "Container.service2"

src/dependency_injector/containers.c

Lines changed: 1729 additions & 1196 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: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class Container:
4545
def shutdown_resources(self) -> Optional[Awaitable]: ...
4646
def apply_container_providers_overridings(self) -> None: ...
4747
def reset_singletons(self) -> None: ...
48+
def check_dependencies(self) -> None: ...
4849
@overload
4950
def resolve_provider_name(self, provider: Provider) -> str: ...
5051
@classmethod

src/dependency_injector/containers.pyx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,30 @@ class DynamicContainer(Container):
305305
for provider in self.traverse(types=[providers.BaseSingleton]):
306306
provider.reset()
307307

308+
def check_dependencies(self):
309+
"""Check if container dependencies are defined.
310+
311+
If any dependency is undefined, raises an error.
312+
"""
313+
undefined = [
314+
dependency
315+
for dependency in self.traverse(types=[providers.Dependency])
316+
if not dependency.is_defined
317+
]
318+
319+
if not undefined:
320+
return
321+
322+
container_name = self.parent_name if self.parent_name else self.__class__.__name__
323+
undefined_names = [
324+
f'"{dependency.parent_name if dependency.parent_name else dependency}"'
325+
for dependency in undefined
326+
]
327+
raise errors.Error(
328+
f'Container "{container_name}" has undefined dependencies: '
329+
f'{", ".join(undefined_names)}',
330+
)
331+
308332
def resolve_provider_name(self, provider):
309333
"""Try to resolve provider name."""
310334
for provider_name, container_provider in self.providers.items():

0 commit comments

Comments
 (0)