Skip to content

Commit 6f859e4

Browse files
authored
(#454) (#597) Fix @Inject + @wraps, refactor patched callables registry and injections storage principles (#610)
* Refactor patched callables registry and injections storage principles * Rename properties of PatchedRegistry * Add typing improvements in wiring module * Add __slots__ for PatchedAttribute * Minor code style fixes * Add test * Rename test * Update typing in test * Make minor style fixes to test * Update changelog * Add documentation on the @Inject decorator
1 parent 0668295 commit 6f859e4

File tree

6 files changed

+543
-278
lines changed

6 files changed

+543
-278
lines changed

docs/main/changelog.rst

+6
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,13 @@ follows `Semantic versioning`_
1111
Development
1212
-----------
1313
- Add ``Configuration.from_json()`` method to load configuration from a json file.
14+
- Fix bug with wiring not working properly with functions double wrapped by ``@functools.wraps`` decorator.
15+
See issue: `#454 <https://github.com/ets-labs/python-dependency-injector/issues/454>`_.
16+
Many thanks to: `@platipo <https://github.com/platipo>`_, `@MatthieuMoreau0 <https://github.com/MatthieuMoreau0>`_,
17+
`@fabiocerqueira <https://github.com/fabiocerqueira>`_, `@Jitesh-Khuttan <https://github.com/Jitesh-Khuttan>`_.
18+
- Refactor wiring module to store all patched callable data in the ``PatchedRegistry``.
1419
- Improve wording on the "Dependency injection and inversion of control in Python" docs page.
20+
- Add documentation on the ``@inject`` decorator.
1521
- Update typing in the main example and cohesion/coupling correlation definition in
1622
"Dependency injection and inversion of control in Python".
1723
Thanks to `@illia-v (Illia Volochii) <https://github.com/illia-v>`_ for the

docs/wiring.rst

+76
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,82 @@ To use wiring you need:
2222
:local:
2323
:backlinks: none
2424

25+
Decorator @inject
26+
-----------------
27+
28+
Decorator ``@inject`` injects the dependencies. Use it to decorate all functions and methods
29+
with the injections.
30+
31+
.. code-block:: python
32+
33+
from dependency_injector.wiring import inject, Provide
34+
35+
36+
@inject
37+
def foo(bar: Bar = Provide[Container.bar]):
38+
...
39+
40+
Decorator ``@inject`` must be specified as a very first decorator of a function to ensure that
41+
the wiring works appropriately. This will also contribute to the performance of the wiring process.
42+
43+
.. code-block:: python
44+
45+
from dependency_injector.wiring import inject, Provide
46+
47+
48+
@decorator_etc
49+
@decorator_2
50+
@decorator_1
51+
@inject
52+
def foo(bar: Bar = Provide[Container.bar]):
53+
...
54+
55+
Specifying the ``@inject`` as a first decorator is also crucial for FastAPI, other frameworks
56+
using decorators similarly, for closures, and for any types of custom decorators with the injections.
57+
58+
FastAPI example:
59+
60+
.. code-block:: python
61+
62+
app = FastAPI()
63+
64+
65+
@app.api_route("/")
66+
@inject
67+
async def index(service: Service = Depends(Provide[Container.service])):
68+
value = await service.process()
69+
return {"result": value}
70+
71+
Decorators example:
72+
73+
.. code-block:: python
74+
75+
def decorator1(func):
76+
@functools.wraps(func)
77+
@inject
78+
def wrapper(value1: int = Provide[Container.config.value1]):
79+
result = func()
80+
return result + value1
81+
return wrapper
82+
83+
84+
def decorator2(func):
85+
@functools.wraps(func)
86+
@inject
87+
def wrapper(value2: int = Provide[Container.config.value2]):
88+
result = func()
89+
return result + value2
90+
return wrapper
91+
92+
@decorator1
93+
@decorator2
94+
def sample():
95+
...
96+
97+
.. seealso::
98+
`Issue #404 <https://github.com/ets-labs/python-dependency-injector/issues/404#issuecomment-785216978>`_
99+
explains ``@inject`` decorator in a few more details.
100+
25101
Markers
26102
-------
27103

0 commit comments

Comments
 (0)