From 2fe4c393a85c7a3ffb0e2fdfe28cb682cf0358f4 Mon Sep 17 00:00:00 2001 From: AndrianEquestrian Date: Sat, 31 May 2025 19:56:14 +0300 Subject: [PATCH 1/8] Add support for Fast Stream Depends --- src/dependency_injector/wiring.py | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/dependency_injector/wiring.py b/src/dependency_injector/wiring.py index b8534ee5..dd6635f4 100644 --- a/src/dependency_injector/wiring.py +++ b/src/dependency_injector/wiring.py @@ -66,6 +66,12 @@ except ImportError: werkzeug = None +try: + import fast_depends.dependencies +except ImportError: + fast_depends = None + + from . import providers __all__ = ( @@ -583,6 +589,8 @@ def _unpatch_attribute(patched: PatchedAttribute) -> None: def _extract_marker(parameter: inspect.Parameter) -> Optional["_Marker"]: + depends_available = False + if get_origin(parameter.annotation) is Annotated: args = get_args(parameter.annotation) if len(args) > 1: @@ -592,10 +600,13 @@ def _extract_marker(parameter: inspect.Parameter) -> Optional["_Marker"]: else: marker = parameter.default - if not isinstance(marker, _Marker) and not _is_fastapi_depends(marker): + if _is_fastapi_depends(marker) or _is_fast_stream_depends(marker): + depends_available = True + + if not isinstance(marker, _Marker) and not depends_available: return None - if _is_fastapi_depends(marker): + if depends_available: marker = marker.dependency if not isinstance(marker, _Marker): @@ -721,6 +732,14 @@ def _is_fastapi_depends(param: Any) -> bool: return fastapi and isinstance(param, fastapi.params.Depends) +if fast_depends: + def _is_fast_stream_depends(param: Any) -> bool: + return isinstance(param, fast_depends.dependencies.Depends) +else: + def _is_fast_stream_depends(param: Any) -> bool: + return False + + def _is_patched(fn) -> bool: return _patched_registry.has_callable(fn) From 575d0e46093c0e04a95d47257dd1765db3940199 Mon Sep 17 00:00:00 2001 From: AndrianEquestrian Date: Sat, 14 Jun 2025 14:19:45 +0300 Subject: [PATCH 2/8] fixup! Add support for Fast Stream Depends --- src/dependency_injector/wiring.py | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/dependency_injector/wiring.py b/src/dependency_injector/wiring.py index dd6635f4..e8503133 100644 --- a/src/dependency_injector/wiring.py +++ b/src/dependency_injector/wiring.py @@ -102,6 +102,23 @@ if TYPE_CHECKING: else: Container = Any +def _is_fastapi_depends(param: Any) -> bool: + return fastapi and isinstance(param, fastapi.params.Depends) + + +if fast_depends: + def _is_fast_stream_depends(param: Any) -> bool: + return isinstance(param, fast_depends.dependencies.Depends) +else: + def _is_fast_stream_depends(param: Any) -> bool: + return False + + +_DEPENDS_CHECKERS = ( + _is_fastapi_depends, + _is_fast_stream_depends, +) + class PatchedRegistry: @@ -600,7 +617,7 @@ def _extract_marker(parameter: inspect.Parameter) -> Optional["_Marker"]: else: marker = parameter.default - if _is_fastapi_depends(marker) or _is_fast_stream_depends(marker): + if any(depends_checker(marker) for depends_checker in _DEPENDS_CHECKERS): depends_available = True if not isinstance(marker, _Marker) and not depends_available: @@ -728,18 +745,6 @@ def _get_patched( return patched -def _is_fastapi_depends(param: Any) -> bool: - return fastapi and isinstance(param, fastapi.params.Depends) - - -if fast_depends: - def _is_fast_stream_depends(param: Any) -> bool: - return isinstance(param, fast_depends.dependencies.Depends) -else: - def _is_fast_stream_depends(param: Any) -> bool: - return False - - def _is_patched(fn) -> bool: return _patched_registry.has_callable(fn) From 1cb1d66d7c7403ef74ebf7b97bbddf841b9bf169 Mon Sep 17 00:00:00 2001 From: AndrianEquestrian Date: Sun, 15 Jun 2025 09:18:24 +0300 Subject: [PATCH 3/8] fixup! Add support for Fast Stream Depends --- src/dependency_injector/wiring.py | 55 +++++++++++++------------------ 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/src/dependency_injector/wiring.py b/src/dependency_injector/wiring.py index e8503133..ccb2cdc9 100644 --- a/src/dependency_injector/wiring.py +++ b/src/dependency_injector/wiring.py @@ -47,11 +47,19 @@ else: def get_origin(tp): return None +MARKER_EXTRACTORS = [] try: - import fastapi.params + from fastapi.params import Depends as FastApiDepends except ImportError: - fastapi = None + pass +else: + def extract_marker_from_fastapi(param: Any) -> Any: + if isinstance(param, FastApiDepends): + return param.dependency + return None + + MARKER_EXTRACTORS.append(extract_marker_from_fastapi) try: @@ -67,10 +75,16 @@ except ImportError: try: - import fast_depends.dependencies + from fast_depends.dependencies import Depends as FastDepends except ImportError: - fast_depends = None + pass +else: + def extract_marker_from_fast_depends(param: Any) -> Any: + if isinstance(param, FastDepends): + return param.dependency + return None + MARKER_EXTRACTORS.append(extract_marker_from_fast_depends) from . import providers @@ -102,23 +116,6 @@ if TYPE_CHECKING: else: Container = Any -def _is_fastapi_depends(param: Any) -> bool: - return fastapi and isinstance(param, fastapi.params.Depends) - - -if fast_depends: - def _is_fast_stream_depends(param: Any) -> bool: - return isinstance(param, fast_depends.dependencies.Depends) -else: - def _is_fast_stream_depends(param: Any) -> bool: - return False - - -_DEPENDS_CHECKERS = ( - _is_fastapi_depends, - _is_fast_stream_depends, -) - class PatchedRegistry: @@ -606,8 +603,6 @@ def _unpatch_attribute(patched: PatchedAttribute) -> None: def _extract_marker(parameter: inspect.Parameter) -> Optional["_Marker"]: - depends_available = False - if get_origin(parameter.annotation) is Annotated: args = get_args(parameter.annotation) if len(args) > 1: @@ -617,18 +612,14 @@ def _extract_marker(parameter: inspect.Parameter) -> Optional["_Marker"]: else: marker = parameter.default - if any(depends_checker(marker) for depends_checker in _DEPENDS_CHECKERS): - depends_available = True + for marker_extractor in MARKER_EXTRACTORS: + if _marker := marker_extractor(marker): + marker = _marker + break - if not isinstance(marker, _Marker) and not depends_available: + if not isinstance(marker, _Marker): return None - if depends_available: - marker = marker.dependency - - if not isinstance(marker, _Marker): - return None - return marker From 2e76b2b4a88f41f67d3a126dfcd3cef521519f5e Mon Sep 17 00:00:00 2001 From: AndrianEquestrian Date: Sun, 15 Jun 2025 13:00:05 +0300 Subject: [PATCH 4/8] fixup! Add support for Fast Stream Depends --- docs/examples/fastdepends.rst | 54 +++++++++++++++++++ requirements-dev.txt | 1 + .../unit/samples/wiringfastdepends/sample.py | 37 +++++++++++++ tests/unit/wiring/test_fastdepends.py | 30 +++++++++++ tox.ini | 2 + 5 files changed, 124 insertions(+) create mode 100644 docs/examples/fastdepends.rst create mode 100644 tests/unit/samples/wiringfastdepends/sample.py create mode 100644 tests/unit/wiring/test_fastdepends.py diff --git a/docs/examples/fastdepends.rst b/docs/examples/fastdepends.rst new file mode 100644 index 00000000..54e682f4 --- /dev/null +++ b/docs/examples/fastdepends.rst @@ -0,0 +1,54 @@ +.. _fastdepends-example: + +FastDepends example +=================== + +.. meta:: + :keywords: Python,Dependency Injection,FastDepends,Example + :description: This example demonstrates a usage of the FastDepends and Dependency Injector. + + +This example shows how to use ``Dependency Injector`` with `FastDepends `_. + +The example application is a REST API that searches for funny GIFs on the `Giphy `_. + +Example code is available on `Github `_. + +Quick sample +------------ + +Just use it within ``Depends`` + +.. code-block:: python + + import sys + + from dependency_injector import containers, providers + from dependency_injector.wiring import inject, Provide + from fast_depends import Depends + + + class CoefficientService: + @staticmethod + def get_coefficient() -> float: + return 1.2 + + + class Container(containers.DeclarativeContainer): + service = providers.Factory(CoefficientService) + + + @inject + def apply_coefficient( + a: int, + coefficient_provider: CoefficientService = Depends(Provide[Container.service]), + ) -> float: + return a * coefficient_provider.get_coefficient() + + + container = Container() + container.wire(modules=[sys.modules[__name__]]) + + assert apply_coefficient(100) == 120.0 + + diff --git a/requirements-dev.txt b/requirements-dev.txt index 47e3ca42..408b9bb6 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -20,5 +20,6 @@ scipy boto3 mypy_boto3_s3 typing_extensions +fast-depends -r requirements-ext.txt diff --git a/tests/unit/samples/wiringfastdepends/sample.py b/tests/unit/samples/wiringfastdepends/sample.py new file mode 100644 index 00000000..805345a6 --- /dev/null +++ b/tests/unit/samples/wiringfastdepends/sample.py @@ -0,0 +1,37 @@ +from dependency_injector.wiring import inject, Provide +from fast_depends import Depends + +# Runtime import to avoid syntax errors in samples on Python < 3.5 and reach top-dir +import os + +_SAMPLES_DIR = os.path.abspath( + os.path.sep.join( + ( + os.path.dirname(__file__), + "../samples/", + ) + ), +) +import sys + +sys.path.append(_SAMPLES_DIR) + + +from wiringfastdepends.sample import CoefficientService, Container + + + +@inject +def apply_coefficient( + a: int, + coefficient_provider: CoefficientService = Depends(Provide[Container.service]), +) -> float: + return a * coefficient_provider.get_coefficient() + + +container = Container() +container.wire(modules=[sys.modules[__name__]]) + + +def test_wire_positive() -> None: + assert apply_coefficient(100) == 120.0 \ No newline at end of file diff --git a/tests/unit/wiring/test_fastdepends.py b/tests/unit/wiring/test_fastdepends.py new file mode 100644 index 00000000..3457cf09 --- /dev/null +++ b/tests/unit/wiring/test_fastdepends.py @@ -0,0 +1,30 @@ + +import sys + +from dependency_injector import containers, providers +from dependency_injector.wiring import inject, Provide +from fast_depends import Depends + + +class CoefficientService: + @staticmethod + def get_coefficient() -> float: + return 1.2 + + +class Container(containers.DeclarativeContainer): + service = providers.Factory(CoefficientService) + + +@inject +def apply_coefficient( + a: int, + coefficient_provider: CoefficientService = Depends(Provide[Container.service]), +) -> float: + return a * coefficient_provider.get_coefficient() + + +container = Container() +container.wire(modules=[sys.modules[__name__]]) + +assert apply_coefficient(100) == 120.0 \ No newline at end of file diff --git a/tox.ini b/tox.ini index b2c5e79f..cadccd84 100644 --- a/tox.ini +++ b/tox.ini @@ -17,6 +17,7 @@ deps= mypy_boto3_s3 pydantic-settings werkzeug + fast-depends extras= yaml commands = pytest @@ -44,6 +45,7 @@ deps = boto3 mypy_boto3_s3 werkzeug + fast-depends commands = pytest -m pydantic [testenv:coveralls] From 977e7062500b29b07e0adc9b750862a910736282 Mon Sep 17 00:00:00 2001 From: AndrianEquestrian Date: Sun, 15 Jun 2025 13:53:51 +0300 Subject: [PATCH 5/8] fixup! Add support for Fast Stream Depends --- docs/examples/fastdepends.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/examples/fastdepends.rst b/docs/examples/fastdepends.rst index 54e682f4..d3ebcc81 100644 --- a/docs/examples/fastdepends.rst +++ b/docs/examples/fastdepends.rst @@ -10,8 +10,6 @@ FastDepends example This example shows how to use ``Dependency Injector`` with `FastDepends `_. -The example application is a REST API that searches for funny GIFs on the `Giphy `_. - Example code is available on `Github `_. Quick sample From be7078387c64835721a2940a60cf1fb86c8046d6 Mon Sep 17 00:00:00 2001 From: AndrianEquestrian Date: Sun, 15 Jun 2025 14:56:55 +0300 Subject: [PATCH 6/8] fixup! Add support for Fast Stream Depends --- docs/examples/fastdepends.rst | 2 +- .../unit/samples/wiringfastdepends/sample.py | 19 ++----------------- tests/unit/wiring/test_fastdepends.py | 3 ++- 3 files changed, 5 insertions(+), 19 deletions(-) diff --git a/docs/examples/fastdepends.rst b/docs/examples/fastdepends.rst index d3ebcc81..327ecfc7 100644 --- a/docs/examples/fastdepends.rst +++ b/docs/examples/fastdepends.rst @@ -47,6 +47,6 @@ Just use it within ``Depends`` container = Container() container.wire(modules=[sys.modules[__name__]]) - assert apply_coefficient(100) == 120.0 + apply_coefficient(100) == 120.0 diff --git a/tests/unit/samples/wiringfastdepends/sample.py b/tests/unit/samples/wiringfastdepends/sample.py index 805345a6..96fe2abf 100644 --- a/tests/unit/samples/wiringfastdepends/sample.py +++ b/tests/unit/samples/wiringfastdepends/sample.py @@ -1,22 +1,7 @@ -from dependency_injector.wiring import inject, Provide -from fast_depends import Depends - -# Runtime import to avoid syntax errors in samples on Python < 3.5 and reach top-dir -import os - -_SAMPLES_DIR = os.path.abspath( - os.path.sep.join( - ( - os.path.dirname(__file__), - "../samples/", - ) - ), -) import sys -sys.path.append(_SAMPLES_DIR) - - +from dependency_injector.wiring import inject, Provide +from fast_depends import Depends from wiringfastdepends.sample import CoefficientService, Container diff --git a/tests/unit/wiring/test_fastdepends.py b/tests/unit/wiring/test_fastdepends.py index 3457cf09..ee7f2374 100644 --- a/tests/unit/wiring/test_fastdepends.py +++ b/tests/unit/wiring/test_fastdepends.py @@ -27,4 +27,5 @@ def apply_coefficient( container = Container() container.wire(modules=[sys.modules[__name__]]) -assert apply_coefficient(100) == 120.0 \ No newline at end of file +def test_apply_coefficient(): + assert apply_coefficient(100) == 120.0 \ No newline at end of file From aaf98782665ba92fc60801f8d9e5dfafd9a7d3be Mon Sep 17 00:00:00 2001 From: AndrianEquestrian Date: Sun, 15 Jun 2025 17:50:41 +0300 Subject: [PATCH 7/8] fixup! Add support for Fast Stream Depends --- .../unit/samples/wiringfastdepends/sample.py | 17 +++++++---- tests/unit/wiring/test_fastdepends.py | 28 ++----------------- 2 files changed, 13 insertions(+), 32 deletions(-) diff --git a/tests/unit/samples/wiringfastdepends/sample.py b/tests/unit/samples/wiringfastdepends/sample.py index 96fe2abf..da58e8f2 100644 --- a/tests/unit/samples/wiringfastdepends/sample.py +++ b/tests/unit/samples/wiringfastdepends/sample.py @@ -1,10 +1,19 @@ import sys +from dependency_injector import containers, providers from dependency_injector.wiring import inject, Provide from fast_depends import Depends -from wiringfastdepends.sample import CoefficientService, Container +class CoefficientService: + @staticmethod + def get_coefficient() -> float: + return 1.2 + + +class Container(containers.DeclarativeContainer): + service = providers.Factory(CoefficientService) + @inject def apply_coefficient( @@ -15,8 +24,4 @@ def apply_coefficient( container = Container() -container.wire(modules=[sys.modules[__name__]]) - - -def test_wire_positive() -> None: - assert apply_coefficient(100) == 120.0 \ No newline at end of file +container.wire(modules=[sys.modules[__name__]]) \ No newline at end of file diff --git a/tests/unit/wiring/test_fastdepends.py b/tests/unit/wiring/test_fastdepends.py index ee7f2374..32118e59 100644 --- a/tests/unit/wiring/test_fastdepends.py +++ b/tests/unit/wiring/test_fastdepends.py @@ -1,31 +1,7 @@ - -import sys - -from dependency_injector import containers, providers from dependency_injector.wiring import inject, Provide -from fast_depends import Depends +from wiringfastdepends import sample -class CoefficientService: - @staticmethod - def get_coefficient() -> float: - return 1.2 - - -class Container(containers.DeclarativeContainer): - service = providers.Factory(CoefficientService) - - -@inject -def apply_coefficient( - a: int, - coefficient_provider: CoefficientService = Depends(Provide[Container.service]), -) -> float: - return a * coefficient_provider.get_coefficient() - - -container = Container() -container.wire(modules=[sys.modules[__name__]]) def test_apply_coefficient(): - assert apply_coefficient(100) == 120.0 \ No newline at end of file + assert sample.apply_coefficient(100) == 120.0 \ No newline at end of file From ea5830a929d7e161bbfae8b22aac8e2c73baf256 Mon Sep 17 00:00:00 2001 From: AndrianEquestrian Date: Sun, 15 Jun 2025 18:23:44 +0300 Subject: [PATCH 8/8] fixup! Add support for Fast Stream Depends --- tests/unit/samples/wiringfastdepends/sample.py | 9 +++++++++ tests/unit/wiring/test_fastdepends.py | 8 ++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/tests/unit/samples/wiringfastdepends/sample.py b/tests/unit/samples/wiringfastdepends/sample.py index da58e8f2..28310052 100644 --- a/tests/unit/samples/wiringfastdepends/sample.py +++ b/tests/unit/samples/wiringfastdepends/sample.py @@ -3,6 +3,7 @@ import sys from dependency_injector import containers, providers from dependency_injector.wiring import inject, Provide from fast_depends import Depends +from typing_extensions import Annotated class CoefficientService: @@ -23,5 +24,13 @@ def apply_coefficient( return a * coefficient_provider.get_coefficient() +@inject +def apply_coefficient_annotated( + a: int, + coefficient_provider: Annotated[CoefficientService, Depends(Provide[Container.service])], +) -> float: + return a * coefficient_provider.get_coefficient() + + container = Container() container.wire(modules=[sys.modules[__name__]]) \ No newline at end of file diff --git a/tests/unit/wiring/test_fastdepends.py b/tests/unit/wiring/test_fastdepends.py index 32118e59..2c326143 100644 --- a/tests/unit/wiring/test_fastdepends.py +++ b/tests/unit/wiring/test_fastdepends.py @@ -3,5 +3,9 @@ from dependency_injector.wiring import inject, Provide from wiringfastdepends import sample -def test_apply_coefficient(): - assert sample.apply_coefficient(100) == 120.0 \ No newline at end of file +def test_apply_coefficient() -> None: + assert sample.apply_coefficient(100) == 120.0 + + +def test_apply_coefficient_annotated() -> None: + assert sample.apply_coefficient_annotated(100) == 120.0 \ No newline at end of file