Browse Source

Merge 375b767868 into 460f8d2cc8

pull/15519/merge
Md Mushfiqur Rahim 4 days ago
committed by GitHub
parent
commit
9c03ef07bb
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 23
      fastapi/dependencies/utils.py
  2. 1
      pyproject.toml
  3. 66
      tests/test_annotated_forward_ref.py

23
fastapi/dependencies/utils.py

@ -246,11 +246,32 @@ def get_typed_annotation(annotation: Any, globalns: dict[str, Any]) -> Any:
if isinstance(annotation, str):
annotation = ForwardRef(annotation)
annotation = evaluate_forwardref(annotation, globalns, globalns)
if annotation is type(None):
if isinstance(annotation, ForwardRef):
if "Annotated[" in annotation.__forward_arg__:
annotation = _resolve_forward_ref_lenient(annotation, globalns)
elif annotation is type(None):
return None
return annotation
def _resolve_forward_ref_lenient(
fwd_ref: ForwardRef,
globalns: dict[str, Any],
) -> Any:
class _LenientNamespace(dict[str, Any]):
def __missing__(self, key: str) -> Any:
return Any
localns = _LenientNamespace(globalns)
if sys.version_info >= (3, 13):
result = fwd_ref._evaluate(
globalns, localns, recursive_guard=frozenset(), type_params=()
)
else:
result = fwd_ref._evaluate(globalns, localns, recursive_guard=frozenset())
return result
def get_typed_return_annotation(call: Callable[..., Any]) -> Any:
signature = _get_signature(call)
unwrapped = inspect.unwrap(call)

1
pyproject.toml

@ -229,6 +229,7 @@ addopts = [
strict_xfail = true
filterwarnings = [
"error",
'ignore:The private ForwardRef._evaluate method is deprecated:DeprecationWarning',
]
timeout = "20"

66
tests/test_annotated_forward_ref.py

@ -0,0 +1,66 @@
from __future__ import annotations
from typing import Annotated
from fastapi import Depends, FastAPI
from inline_snapshot import snapshot
# Simulate the real-world bug: Potato is defined AFTER the route decorator
# under `from __future__ import annotations`.
app = FastAPI()
def get_potato():
return Potato(color="red", size=10)
@app.get("/")
async def read_root(potato: Annotated[Potato, Depends(get_potato)]):
return {"color": potato.color, "size": potato.size}
from dataclasses import dataclass # noqa: E402
@dataclass
class Potato:
color: str
size: int
def test_forward_ref_annotated_depends():
from fastapi.testclient import TestClient
client = TestClient(app)
resp = client.get("/")
assert resp.status_code == 200, resp.text
assert resp.json() == {"color": "red", "size": 10}
def test_forward_ref_annotated_depends_openapi():
from fastapi.testclient import TestClient
client = TestClient(app)
resp = client.get("/openapi.json")
assert resp.status_code == 200, resp.text
assert resp.json() == snapshot(
{
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/": {
"get": {
"summary": "Read Root",
"operationId": "read_root__get",
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
}
},
}
}
},
}
)
Loading…
Cancel
Save