Skip to content

Add support for Fast Stream Depends #898

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions docs/examples/fastdepends.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
.. _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 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.

Basic Usage
-----------

The integration between FastDepends and Dependency Injector is straightforward. Simply use Dependency Injector's ``Provide`` marker within FastDepends' ``Depends`` function:

.. 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__]])
apply_coefficient(100) == 120.0
1 change: 1 addition & 0 deletions docs/examples/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ Explore the examples to see the ``Dependency Injector`` in action.
fastapi
fastapi-redis
fastapi-sqlalchemy
fastdepends

.. disqus::
1 change: 1 addition & 0 deletions docs/wiring.rst
Original file line number Diff line number Diff line change
Expand Up @@ -662,5 +662,6 @@ Take a look at other application examples:
- :ref:`fastapi-example`
- :ref:`fastapi-redis-example`
- :ref:`fastapi-sqlalchemy-example`
- :ref:`fastdepends-example`

.. disqus::
1 change: 1 addition & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ scipy
boto3
mypy_boto3_s3
typing_extensions
fast-depends

-r requirements-ext.txt
47 changes: 32 additions & 15 deletions src/dependency_injector/wiring.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,33 @@ 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:
from fast_depends.dependencies import Depends as FastDepends
except ImportError:
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)


try:
Expand All @@ -65,8 +88,7 @@ def get_origin(tp):
except ImportError:
werkzeug = None


from . import providers
from . import providers # noqa: E402

__all__ = (
"wire",
Expand Down Expand Up @@ -592,14 +614,13 @@ def _extract_marker(parameter: inspect.Parameter) -> Optional["_Marker"]:
else:
marker = parameter.default

if not isinstance(marker, _Marker) and not _is_fastapi_depends(marker):
return None

if _is_fastapi_depends(marker):
marker = marker.dependency
for marker_extractor in MARKER_EXTRACTORS:
if _marker := marker_extractor(marker):
marker = _marker
break

if not isinstance(marker, _Marker):
return None
if not isinstance(marker, _Marker):
return None

return marker

Expand Down Expand Up @@ -717,10 +738,6 @@ def _get_patched(
return patched


def _is_fastapi_depends(param: Any) -> bool:
return fastapi and isinstance(param, fastapi.params.Depends)


def _is_patched(fn) -> bool:
return _patched_registry.has_callable(fn)

Expand Down
39 changes: 39 additions & 0 deletions tests/unit/samples/wiringfastdepends/sample.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import sys

from fast_depends import Depends
from typing_extensions import Annotated

from dependency_injector import containers, providers
from dependency_injector.wiring import Provide, inject


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()


@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__]])
9 changes: 9 additions & 0 deletions tests/unit/wiring/test_fastdepends.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from wiringfastdepends import sample


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
2 changes: 2 additions & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ deps=
mypy_boto3_s3
pydantic-settings
werkzeug
fast-depends
extras=
yaml
commands = pytest
Expand Down Expand Up @@ -44,6 +45,7 @@ deps =
boto3
mypy_boto3_s3
werkzeug
fast-depends
commands = pytest -m pydantic

[testenv:coveralls]
Expand Down