Skip to content

Commit b411807

Browse files
Add support for Fast Stream Depends (#898)
1 parent f2da51e commit b411807

File tree

8 files changed

+133
-15
lines changed

8 files changed

+133
-15
lines changed

docs/examples/fastdepends.rst

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
.. _fastdepends-example:
2+
3+
FastDepends example
4+
===================
5+
6+
.. meta::
7+
:keywords: Python,Dependency Injection,FastDepends,Example
8+
:description: This example demonstrates a usage of the FastDepends and Dependency Injector.
9+
10+
11+
This example demonstrates how to use ``Dependency Injector`` with `FastDepends <https://github.com/Lancetnik/FastDepends>`_, a lightweight dependency injection framework inspired by FastAPI's dependency system, but without the web framework components.
12+
13+
Basic Usage
14+
-----------
15+
16+
The integration between FastDepends and Dependency Injector is straightforward. Simply use Dependency Injector's ``Provide`` marker within FastDepends' ``Depends`` function:
17+
18+
.. code-block:: python
19+
20+
import sys
21+
22+
from dependency_injector import containers, providers
23+
from dependency_injector.wiring import inject, Provide
24+
from fast_depends import Depends
25+
26+
27+
class CoefficientService:
28+
@staticmethod
29+
def get_coefficient() -> float:
30+
return 1.2
31+
32+
33+
class Container(containers.DeclarativeContainer):
34+
service = providers.Factory(CoefficientService)
35+
36+
37+
@inject
38+
def apply_coefficient(
39+
a: int,
40+
coefficient_provider: CoefficientService = Depends(Provide[Container.service]),
41+
) -> float:
42+
return a * coefficient_provider.get_coefficient()
43+
44+
45+
container = Container()
46+
container.wire(modules=[sys.modules[__name__]])
47+
48+
apply_coefficient(100) == 120.0

docs/examples/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@ Explore the examples to see the ``Dependency Injector`` in action.
2222
fastapi
2323
fastapi-redis
2424
fastapi-sqlalchemy
25+
fastdepends
2526

2627
.. disqus::

docs/wiring.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,5 +693,6 @@ Take a look at other application examples:
693693
- :ref:`fastapi-example`
694694
- :ref:`fastapi-redis-example`
695695
- :ref:`fastapi-sqlalchemy-example`
696+
- :ref:`fastdepends-example`
696697

697698
.. disqus::

requirements-dev.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,6 @@ scipy
2020
boto3
2121
mypy_boto3_s3
2222
typing_extensions
23+
fast-depends
2324

2425
-r requirements-ext.txt

src/dependency_injector/wiring.py

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,33 @@ def get_origin(tp):
5959
return None
6060

6161

62+
MARKER_EXTRACTORS = []
63+
6264
try:
63-
import fastapi.params
65+
from fastapi.params import Depends as FastAPIDepends
6466
except ImportError:
65-
fastapi = None
67+
pass
68+
else:
69+
70+
def extract_marker_from_fastapi(param: Any) -> Any:
71+
if isinstance(param, FastAPIDepends):
72+
return param.dependency
73+
return None
74+
75+
MARKER_EXTRACTORS.append(extract_marker_from_fastapi)
76+
77+
try:
78+
from fast_depends.dependencies import Depends as FastDepends
79+
except ImportError:
80+
pass
81+
else:
82+
83+
def extract_marker_from_fast_depends(param: Any) -> Any:
84+
if isinstance(param, FastDepends):
85+
return param.dependency
86+
return None
87+
88+
MARKER_EXTRACTORS.append(extract_marker_from_fast_depends)
6689

6790

6891
try:
@@ -76,8 +99,7 @@ def get_origin(tp):
7699
except ImportError:
77100
werkzeug = None
78101

79-
80-
from . import providers
102+
from . import providers # noqa: E402
81103

82104
__all__ = (
83105
"wire",
@@ -607,14 +629,13 @@ def _extract_marker(parameter: inspect.Parameter) -> Optional["_Marker"]:
607629
else:
608630
marker = parameter.default
609631

610-
if not isinstance(marker, _Marker) and not _is_fastapi_depends(marker):
611-
return None
612-
613-
if _is_fastapi_depends(marker):
614-
marker = marker.dependency
632+
for marker_extractor in MARKER_EXTRACTORS:
633+
if _marker := marker_extractor(marker):
634+
marker = _marker
635+
break
615636

616-
if not isinstance(marker, _Marker):
617-
return None
637+
if not isinstance(marker, _Marker):
638+
return None
618639

619640
return marker
620641

@@ -735,10 +756,6 @@ def _get_patched(
735756
return patched
736757

737758

738-
def _is_fastapi_depends(param: Any) -> bool:
739-
return fastapi and isinstance(param, fastapi.params.Depends)
740-
741-
742759
def _is_patched(fn) -> bool:
743760
return _patched_registry.has_callable(fn)
744761

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import sys
2+
3+
from fast_depends import Depends
4+
from typing_extensions import Annotated
5+
6+
from dependency_injector import containers, providers
7+
from dependency_injector.wiring import Provide, inject
8+
9+
10+
class CoefficientService:
11+
@staticmethod
12+
def get_coefficient() -> float:
13+
return 1.2
14+
15+
16+
class Container(containers.DeclarativeContainer):
17+
service = providers.Factory(CoefficientService)
18+
19+
20+
@inject
21+
def apply_coefficient(
22+
a: int,
23+
coefficient_provider: CoefficientService = Depends(Provide[Container.service]),
24+
) -> float:
25+
return a * coefficient_provider.get_coefficient()
26+
27+
28+
@inject
29+
def apply_coefficient_annotated(
30+
a: int,
31+
coefficient_provider: Annotated[
32+
CoefficientService, Depends(Provide[Container.service])
33+
],
34+
) -> float:
35+
return a * coefficient_provider.get_coefficient()
36+
37+
38+
container = Container()
39+
container.wire(modules=[sys.modules[__name__]])

tests/unit/wiring/test_fastdepends.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from wiringfastdepends import sample
2+
3+
4+
def test_apply_coefficient() -> None:
5+
assert sample.apply_coefficient(100) == 120.0
6+
7+
8+
def test_apply_coefficient_annotated() -> None:
9+
assert sample.apply_coefficient_annotated(100) == 120.0

tox.ini

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ deps=
1717
mypy_boto3_s3
1818
pydantic-settings
1919
werkzeug
20+
fast-depends
2021
extras=
2122
yaml
2223
commands = pytest
@@ -44,6 +45,7 @@ deps =
4445
boto3
4546
mypy_boto3_s3
4647
werkzeug
48+
fast-depends
4749
commands = pytest -m pydantic
4850

4951
[testenv:coveralls]

0 commit comments

Comments
 (0)