Browse Source

Fix Annotated ForwardRef dependencies with future annotations

pull/15234/head
giria660 4 months ago
parent
commit
2703df6fdf
No known key found for this signature in database GPG Key ID: 3D8290B3CD372BA4
  1. 14
      fastapi/dependencies/utils.py
  2. 59
      tests/test_stringified_annotation_forwardref_dependency.py

14
fastapi/dependencies/utils.py

@ -1,6 +1,7 @@
import dataclasses
import inspect
import sys
from builtins import __dict__ as builtins_dict
from collections.abc import (
AsyncGenerator,
AsyncIterable,
@ -242,10 +243,21 @@ def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature:
return typed_signature
class _LenientTypeResolutionDict(dict[str, Any]):
def __missing__(self, key: str) -> Any:
value = builtins_dict.get(key, ForwardRef(key))
self[key] = value
return value
def get_typed_annotation(annotation: Any, globalns: dict[str, Any]) -> Any:
if isinstance(annotation, str):
annotation = ForwardRef(annotation)
annotation = evaluate_forwardref(annotation, globalns, globalns) # ty: ignore[deprecated]
if isinstance(annotation, ForwardRef):
lenient_globalns = _LenientTypeResolutionDict(globalns)
annotation = evaluate_forwardref( # ty: ignore[deprecated]
annotation, lenient_globalns, lenient_globalns
)
if annotation is type(None):
return None
return annotation

59
tests/test_stringified_annotation_forwardref_dependency.py

@ -0,0 +1,59 @@
from __future__ import annotations
from dataclasses import dataclass
from typing import Annotated
from fastapi import Depends, FastAPI
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
app = FastAPI()
def get_potato() -> 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}
@dataclass
class Potato:
color: str
size: int
client = TestClient(app)
def test_stringified_annotated_forwardref_dependency():
response = client.get("/")
assert response.status_code == 200, response.text
assert response.json() == {"color": "red", "size": 10}
def test_stringified_annotated_forwardref_dependency_openapi():
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.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