]> git.ipfire.org Git - thirdparty/fastapi/fastapi.git/commitdiff
🐛 Fix support for `if TYPE_CHECKING`, non-evaluated stringified annotations (#14485)
authorSebastián Ramírez <tiangolo@gmail.com>
Wed, 10 Dec 2025 12:06:05 +0000 (04:06 -0800)
committerGitHub <noreply@github.com>
Wed, 10 Dec 2025 12:06:05 +0000 (13:06 +0100)
fastapi/dependencies/utils.py
tests/test_stringified_annotation_dependency.py [new file with mode: 0644]

index 23bca6f2a1a5e6698ade064cc2567ed2b06e976d..262dba6fdd667173861ae13aef9828b9b457a5d0 100644 (file)
@@ -209,11 +209,21 @@ def get_flat_params(dependant: Dependant) -> List[ModelField]:
     return path_params + query_params + header_params + cookie_params
 
 
-def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature:
+def _get_signature(call: Callable[..., Any]) -> inspect.Signature:
     if sys.version_info >= (3, 10):
-        signature = inspect.signature(call, eval_str=True)
+        try:
+            signature = inspect.signature(call, eval_str=True)
+        except NameError:
+            # Handle type annotations with if TYPE_CHECKING, not used by FastAPI
+            # e.g. dependency return types
+            signature = inspect.signature(call)
     else:
         signature = inspect.signature(call)
+    return signature
+
+
+def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature:
+    signature = _get_signature(call)
     unwrapped = inspect.unwrap(call)
     globalns = getattr(unwrapped, "__globals__", {})
     typed_params = [
@@ -239,10 +249,7 @@ def get_typed_annotation(annotation: Any, globalns: Dict[str, Any]) -> Any:
 
 
 def get_typed_return_annotation(call: Callable[..., Any]) -> Any:
-    if sys.version_info >= (3, 10):
-        signature = inspect.signature(call, eval_str=True)
-    else:
-        signature = inspect.signature(call)
+    signature = _get_signature(call)
     unwrapped = inspect.unwrap(call)
     annotation = signature.return_annotation
 
diff --git a/tests/test_stringified_annotation_dependency.py b/tests/test_stringified_annotation_dependency.py
new file mode 100644 (file)
index 0000000..89bb884
--- /dev/null
@@ -0,0 +1,80 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+import pytest
+from fastapi import Depends, FastAPI
+from fastapi.testclient import TestClient
+from inline_snapshot import snapshot
+from typing_extensions import Annotated
+
+if TYPE_CHECKING:  # pragma: no cover
+    from collections.abc import AsyncGenerator
+
+
+class DummyClient:
+    async def get_people(self) -> list:
+        return ["John Doe", "Jane Doe"]
+
+    async def close(self) -> None:
+        pass
+
+
+async def get_client() -> AsyncGenerator[DummyClient, None]:
+    client = DummyClient()
+    yield client
+    await client.close()
+
+
+Client = Annotated[DummyClient, Depends(get_client)]
+
+
+@pytest.fixture(name="client")
+def client_fixture() -> TestClient:
+    app = FastAPI()
+
+    @app.get("/")
+    async def get_people(client: Client) -> list:
+        return await client.get_people()
+
+    client = TestClient(app)
+    return client
+
+
+def test_get(client: TestClient):
+    response = client.get("/")
+    assert response.status_code == 200, response.text
+    assert response.json() == ["John Doe", "Jane Doe"]
+
+
+def test_openapi_schema(client: TestClient):
+    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": "Get People",
+                        "operationId": "get_people__get",
+                        "responses": {
+                            "200": {
+                                "description": "Successful Response",
+                                "content": {
+                                    "application/json": {
+                                        "schema": {
+                                            "items": {},
+                                            "type": "array",
+                                            "title": "Response Get People  Get",
+                                        }
+                                    }
+                                },
+                            }
+                        },
+                    }
+                }
+            },
+        }
+    )