8000 [FS-2169] Error on faststream.Context instead of faststream.[broker].fastapi.Context by NelsonNotes · Pull Request #2181 · ag2ai/faststream · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

[FS-2169] Error on faststream.Context instead of faststream.[broker].fastapi.Context #2181

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
merged 9 commits into from
Apr 16, 2025
2 changes: 1 addition & 1 deletion docs/docs/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ search:
- get_dependant
- [get_fastapi_dependant](api/faststream/broker/fastapi/get_dependant/get_fastapi_dependant.md)
- [get_fastapi_native_dependant](api/faststream/broker/fastapi/get_dependant/get_fastapi_native_dependant.md)
- [has_faststream_depends](api/faststream/broker/fastapi/get_dependant/has_faststream_depends.md)
- [has_signature_param](api/faststream/broker/fastapi/get_dependant/has_signature_param.md)
- [is_faststream_decorated](api/faststream/broker/fastapi/get_dependant/is_faststream_decorated.md)
- [mark_faststream_decorated](api/faststream/broker/fastapi/get_dependant/mark_faststream_decorated.md)
- route
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ search:
boost: 0.5
---

::: faststream.broker.fastapi.get_dependant.has_faststream_depends
::: faststream.broker.fastapi.get_dependant.has_signature_param
9 changes: 4 additions & 5 deletions faststream/broker/fastapi/get_dependant.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import inspect
from typing import TYPE_CHECKING, Any, Callable, Iterable, cast

from fast_depends.dependencies import model
from fast_depends.utils import get_typed_annotation
from fastapi.dependencies.utils import (
get_dependant,
Expand Down Expand Up @@ -140,18 +139,18 @@ def _patch_fastapi_dependent(dependant: "Dependant") -> "Dependant":
return dependant


def has_faststream_depends(orig_call: Callable[..., Any]) -> bool:
"""Check if faststream.Depends is used in the handler."""
def has_signature_param(orig_call: Callable[..., Any], param_type: type) -> bool:
"""Check if any param of param_type is presented as default or `Annotated` within the call signature."""
endpoint_signature = get_typed_signature(orig_call)
signature_params = endpoint_signature.parameters
for param in signature_params.values():
ann = param.annotation
if ann is not inspect.Signature.empty and get_origin(ann) is Annotated:
annotated_args = get_args(ann)
for arg in annotated_args:
if isinstance(arg, model.Depends):
if isinstance(arg, param_type):
return True
if isinstance(param.default, model.Depends):
if isinstance(param.default, param_type):
return True
return False

Expand Down
12 changes: 9 additions & 3 deletions faststream/broker/fastapi/route.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,20 @@
Union,
)

from fast_depends.dependencies import model
from fastapi.routing import run_endpoint_function, serialize_response
from starlette.requests import Request

from faststream.broker.fastapi.get_dependant import (
get_fastapi_native_dependant,
has_faststream_depends,
has_signature_param,
is_faststream_decorated,
mark_faststream_decorated,
)
from faststream.broker.response import Response, ensure_response
from faststream.broker.types import P_HandlerParams, T_HandlerReturn
from faststream.exceptions import SetupError
from faststream.utils.context.types import Context as FSContext

from ._compat import (
FASTAPI_V106,
Expand Down Expand Up @@ -82,8 +84,12 @@ def wrap_callable_to_fastapi_compatible(
response_model_exclude_defaults: bool,
response_model_exclude_none: bool,
) -> Callable[["NativeMessage[Any]"], Awaitable[Any]]:
if has_faststream_depends(user_callable):
msg = f"Incorrect `faststream.Depends` usage at `{user_callable.__name__}`. For FastAPI integration use `fastapi.Depends`"
if has_signature_param(user_callable, model.Depends):
msg = f"Incorrect `faststream.Depends` usage at `{user_callable.__name__}`. For FastAPI integration use `fastapi.Depends`."
raise SetupError(msg)

if has_signature_param(user_callable, FSContext):
msg = f"Incorrect `faststream.Context` usage at `{user_callable.__name__}`. For FastAPI integration use `faststream.[broker].fastapi.Context`."
raise SetupError(msg)

if is_faststream_decorated(user_callable):
Expand Down
68 changes: 68 additions & 0 deletions tests/brokers/base/fastapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from fastapi.testclient import TestClient
from typing_extensions import Annotated, Any, TypeVar

from faststream import Context as FSContext
from faststream import Depends as FSDepends
from faststream import Response, context
from faststream.broker.core.usecase import BrokerUsecase
Expand Down Expand Up @@ -102,6 +103,73 @@ async def hello(msg=Context(context_key)):
assert event.is_set()
mock.assert_called_with(True)

async def test_context_annotated(
self, mock: Mock, queue: str, event: asyncio.Event
):
router = self.router_class()

context_key = "message.headers"

args, kwargs = self.get_subscriber_params(queue)

@router.subscriber(*args, **kwargs)
async def hello(msg: Annotated[Any, Context(context_key)]):
event.set()
return mock(msg == context.resolve(context_key))

async with router.broker:
await router.broker.start()
await asyncio.wait(
(
asyncio.create_task(router.broker.publish("", queue)),
asyncio.create_task(event.wait()),
),
timeout=self.timeout,
)

assert event.is_set()
mock.assert_called_with(True)

async def test_faststream_context(
self, mock: Mock, queue: str, event: asyncio.Event
):
router = self.router_class()

context_key = "message.headers"

args, kwargs = self.get_subscriber_params(queue)

@router.subscriber(*args, **kwargs)
async def hello(msg=FSContext(context_key)):
event.set()
return mock(msg == context.resolve(context_key))

app = FastAPI()
app.include_router(router)

with pytest.raises(SetupError), TestClient(app):
...

async def test_faststream_context_annotated(
self, mock: Mock, queue: str, event: asyncio.Event
):
router = self.router_class()

context_key = "message.headers"

args, kwargs = self.get_subscriber_params(queue)

@router.subscriber(*args, **kwargs)
async def hello(msg: Annotated[Any, FSContext(context_key)]):
event.set()
return mock(msg == context.resolve(context_key))

app = FastAPI()
app.include_router(router)

with pytest.raises(SetupError), TestClient(app):
...

async def test_initial_context(self, queue: str, event: asyncio.Event):
router = self.router_class()

Expand Down
Loading
0