Skip to content

Commit 3857cc3

Browse files
[FS-2158] Explicit error in case of mixed up fastapi.Depends and faststream.Depends (#2160)
* tests(fastapi): added test for incorrect Depends * Update fastapi.py * feat(depends): added wrong depends exception * docs: generate API References * fix(fastapi_tests): fixed 3.8 compatibility * docs: generate API References --------- Co-authored-by: Pastukhov Nikita <[email protected]>
1 parent 12ceeef commit 3857cc3

File tree

5 files changed

+78
-2
lines changed

5 files changed

+78
-2
lines changed

docs/docs/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,7 @@ search:
374374
- get_dependant
375375
- [get_fastapi_dependant](api/faststream/broker/fastapi/get_dependant/get_fastapi_dependant.md)
376376
- [get_fastapi_native_dependant](api/faststream/broker/fastapi/get_dependant/get_fastapi_native_dependant.md)
377+
- [has_faststream_depends](api/faststream/broker/fastapi/get_dependant/has_faststream_depends.md)
377378
- [is_faststream_decorated](api/faststream/broker/fastapi/get_dependant/is_faststream_decorated.md)
378379
- [mark_faststream_decorated](api/faststream/broker/fastapi/get_dependant/mark_faststream_decorated.md)
379380
- route
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
# 0.5 - API
3+
# 2 - Release
4+
# 3 - Contributing
5+
# 5 - Template Page
6+
# 10 - Default
7+
search:
8+
boost: 0.5
9+
---
10+
11+
::: faststream.broker.fastapi.get_dependant.has_faststream_depends

faststream/broker/fastapi/get_dependant.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1+
import inspect
12
from typing import TYPE_CHECKING, Any, Callable, Iterable, cast
23

4+
from fast_depends.dependencies import model
35
from fast_depends.utils import get_typed_annotation
4-
from fastapi.dependencies.utils import get_dependant, get_parameterless_sub_dependant
6+
from fastapi.dependencies.utils import (
7+
get_dependant,
8+
get_parameterless_sub_dependant,
9+
get_typed_signature,
10+
)
11+
from typing_extensions import Annotated, get_args, get_origin
512

613
from faststream._compat import PYDANTIC_V2
714

@@ -133,6 +140,22 @@ def _patch_fastapi_dependent(dependant: "Dependant") -> "Dependant":
133140
return dependant
134141

135142

143+
def has_faststream_depends(orig_call: Callable[..., Any]) -> bool:
144+
"""Check if faststream.Depends is used in the handler."""
145+
endpoint_signature = get_typed_signature(orig_call)
146+
signature_params = endpoint_signature.parameters
147+
for param in signature_params.values():
148+
ann = param.annotation
149+
if ann is not inspect.Signature.empty and get_origin(ann) is Annotated:
150+
annotated_args = get_args(ann)
151+
for arg in annotated_args:
152+
if isinstance(arg, model.Depends):
153+
return True
154+
if isinstance(param.default, model.Depends):
155+
return True
156+
return False
157+
158+
136159
FASTSTREAM_FASTAPI_PLUGIN_DECORATOR_MARKER = "__faststream_consumer__"
137160

138161

faststream/broker/fastapi/route.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@
1919

2020
from faststream.broker.fastapi.get_dependant import (
2121
get_fastapi_native_dependant,
22+
has_faststream_depends,
2223
is_faststream_decorated,
2324
mark_faststream_decorated,
2425
)
2526
from faststream.broker.response import Response, ensure_response
2627
from faststream.broker.types import P_HandlerParams, T_HandlerReturn
28+
from faststream.exceptions import SetupError
2729

2830
from ._compat import (
2931
FASTAPI_V106,
@@ -80,6 +82,10 @@ def wrap_callable_to_fastapi_compatible(
8082
response_model_exclude_defaults: bool,
8183
response_model_exclude_none: bool,
8284
) -> Callable[["NativeMessage[Any]"], Awaitable[Any]]:
85+
if has_faststream_depends(user_callable):
86+
msg = f"Incorrect `faststream.Depends` usage at `{user_callable.__name__}`. For FastAPI integration use `fastapi.Depends`"
87+
raise SetupError(msg)
88+
8389
if is_faststream_decorated(user_callable):
8490
return user_callable # type: ignore[return-value]
8591

tests/brokers/base/fastapi.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
import asyncio
22
from contextlib import asynccontextmanager
3-
from typing import Any, Callable, Type, TypeVar
3+
from typing import Callable, Type
44
from unittest.mock import Mock
55

66
import pytest
77
from fastapi import BackgroundTasks, Depends, FastAPI, Header
88
from fastapi.exceptions import RequestValidationError
99
from fastapi.testclient import TestClient
10+
from typing_extensions import Annotated, Any, TypeVar
1011

12+
from faststream import Depends as FSDepends
1113
from faststream import Response, context
1214
from faststream.broker.core.usecase import BrokerUsecase
1315
from faststream.broker.fastapi.context import Context
1416
from faststream.broker.fastapi.router import StreamRouter
1517
from faststream.broker.router import BrokerRouter
18+
from faststream.exceptions import SetupError
1619
from faststream.types import AnyCallable
1720

1821
from .basic import BaseTestcaseConfig
@@ -333,6 +336,38 @@ async def hello(a, w=Depends(dep)):
333336

334337
mock.assert_called_once_with("hi")
335338

339+
async def test_depends_from_fastdepends_default(self, queue: str):
340+
router = self.router_class()
341+
342+
args, kwargs = self.get_subscriber_params(queue)
343+
344+
subscriber = router.subscriber(*args, **kwargs)
345+
346+
@subscriber
347+
def sub(d: Any = FSDepends(lambda: 1)) -> None: ...
348+
349+
app = FastAPI()
350+
app.include_router(router)
351+
352+
with pytest.raises(SetupError), TestClient(app):
353+
...
354+
355+
async def test_depends_from_fastdepends_annotated(self, queue: str):
356+
router = self.router_class()
357+
358+
args, kwargs = self.get_subscriber_params(queue)
359+
360+
subscriber = router.subscriber(*args, **kwargs)
361+
362+
@subscriber
363+
def sub(d: Annotated[Any, FSDepends(lambda: 1)]) -> None: ...
364+
365+
app = FastAPI()
366+
app.include_router(router)
367+
368+
with pytest.raises(SetupError), TestClient(app):
369+
...
370+
336371
async def test_yield_depends(self, mock: Mock, queue: str):
337372
router = self.router_class()
338373

0 commit comments

Comments
 (0)