]> git.ipfire.org Git - thirdparty/fastapi/fastapi.git/commitdiff
🐛 Fix OpenAPI schema support for computed fields when using `separate_input_output_sc...
authorVincent Grafé <vincent.grafe@gmail.com>
Tue, 2 Dec 2025 09:22:08 +0000 (01:22 -0800)
committerGitHub <noreply@github.com>
Tue, 2 Dec 2025 09:22:08 +0000 (09:22 +0000)
Co-authored-by: Sofie Van Landeghem <svlandeg@users.noreply.github.com>
Co-authored-by: svlandeg <svlandeg@github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: svlandeg <sofie.vanlandeghem@gmail.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
fastapi/_compat/v2.py
tests/test_computed_fields.py

index 3d91814c08730c0632a314437fd6da2de3253b03..543a42dda0c51e261733c12e7db0634dbf9b01f7 100644 (file)
@@ -180,8 +180,13 @@ def get_schema_from_model_field(
     ],
     separate_input_output_schemas: bool = True,
 ) -> Dict[str, Any]:
+    computed_fields = field._type_adapter.core_schema.get("schema", {}).get(
+        "computed_fields", []
+    )
     override_mode: Union[Literal["validation"], None] = (
-        None if separate_input_output_schemas else "validation"
+        None
+        if (separate_input_output_schemas or len(computed_fields) > 0)
+        else "validation"
     )
     # This expects that GenerateJsonSchema was already used to generate the definitions
     json_schema = field_mapping[(field, override_mode or field.mode)]
@@ -203,9 +208,14 @@ def get_definitions(
     Dict[Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue],
     Dict[str, Dict[str, Any]],
 ]:
+    has_computed_fields: bool = any(
+        field._type_adapter.core_schema.get("schema", {}).get("computed_fields", [])
+        for field in fields
+    )
+
     schema_generator = GenerateJsonSchema(ref_template=REF_TEMPLATE)
     override_mode: Union[Literal["validation"], None] = (
-        None if separate_input_output_schemas else "validation"
+        None if (separate_input_output_schemas or has_computed_fields) else "validation"
     )
     validation_fields = [field for field in fields if field.mode == "validation"]
     serialization_fields = [field for field in fields if field.mode == "serialization"]
index a1b4121688784dce8ffde8c1a5cd2b2b249dbc3e..f2e42999b35e71d43508fbed6b0955909a1e8d6b 100644 (file)
@@ -6,8 +6,9 @@ from .utils import needs_pydanticv2
 
 
 @pytest.fixture(name="client")
-def get_client():
-    app = FastAPI()
+def get_client(request):
+    separate_input_output_schemas = request.param
+    app = FastAPI(separate_input_output_schemas=separate_input_output_schemas)
 
     from pydantic import BaseModel, computed_field
 
@@ -32,6 +33,7 @@ def get_client():
     return client
 
 
+@pytest.mark.parametrize("client", [True, False], indirect=True)
 @pytest.mark.parametrize("path", ["/", "/responses"])
 @needs_pydanticv2
 def test_get(client: TestClient, path: str):
@@ -40,6 +42,7 @@ def test_get(client: TestClient, path: str):
     assert response.json() == {"width": 3, "length": 4, "area": 12}
 
 
+@pytest.mark.parametrize("client", [True, False], indirect=True)
 @needs_pydanticv2
 def test_openapi_schema(client: TestClient):
     response = client.get("/openapi.json")