← pod_r4_v1

fastapi_13207

failed CONTEXT NO_PATCH UNSUBMITTED agent_error · 22 tool calls · 196 s · fastapi/fastapi

Task input

🐛 Fix OpenAPI schema support for computed fields when using `separate_input_output_schemas=False`

This demonstrates how the output schema differs when the FastAPI app runs with different values for `separate_input_output_schemas` - namely, the computed fields are omitted.

Initially reported here: https://github.com/fastapi/fastapi/discussions/10342

Tool calls (22)

#ToolArgumentsResult
1run_command
{
 "command": "grep -rn \"separate_input_output_schemas\" ."
}
{"status": "ok", "stdout": "./tests/test_openapi_separate_input_output_schemas.py:27:def get_app_client(separate_input_output_schemas: bool = True) -> TestClien
full
{"status": "ok", "stdout": "./tests/test_openapi_separate_input_output_schemas.py:27:def get_app_client(separate_input_output_schemas: bool = True) -> TestClient:\n./tests/test_openapi_separate_input_output_schemas.py:28:    app = FastAPI(separate_input_output_schemas=separate_input_output_schemas)\n./tests/test_openapi_separate_input_output_schemas.py:55:    client_no = get_app_client(separate_input_output_schemas=False)\n./tests/test_openapi_separate_input_output_schemas.py:68:    client_no = get_app_client(separate_input_output_schemas=False)\n./tests/test_openapi_separate_input_output_schemas.py:89:    client_no = get_app_client(separate_input_output_schemas=False)\n./tests/test_openapi_separate_input_output_schemas.py:116:    client_no = get_app_client(separate_input_output_schemas=False)\n./tests/test_openapi_separate_input_output_schemas.py:360:    client = get_app_client(separate_input_output_schemas=False)\n./docs/ru/docs/how-to/separate-openapi-schemas.md:86:\u0412 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043e\u0442\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u044d\u0442\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0432 FastAPI \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 `separate_input_output_schemas=False`.\n./docs/ru/docs/how-to/separate-openapi-schemas.md:90:\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 `separate_input_output_schemas` \u043f\u043e\u044f\u0432\u0438\u043b\u0430\u0441\u044c \u0432 FastAPI `0.102.0`. \ud83e\udd13\n./docs/pt/docs/how-to/separate-openapi-schemas.md:86:Nesse caso, voc\u00ea pode desativar esse recurso no **FastAPI**, com o par\u00e2metro `separate_input_output_schemas=False`.\n./docs/pt/docs/how-to/separate-openapi-schemas.md:90:O suporte para `separate_input_output_schemas` foi adicionado no FastAPI `0.102.0`. \ud83e\ud
2read_file
{
 "filepath": "fastapi/openapi/utils.py"
}
{"status": "ok", "filepath": "fastapi/openapi/utils.py", "content": "import http.client\nimport inspect\nimport warnings\nfrom typing import Any, Dict, List, Op
full
{"status": "ok", "filepath": "fastapi/openapi/utils.py", "content": "import http.client\nimport inspect\nimport warnings\nfrom typing import Any, Dict, List, Optional, Sequence, Set, Tuple, Type, Union, cast\n\nfrom fastapi import routing\nfrom fastapi._compat import (\n    JsonSchemaValue,\n    ModelField,\n    Undefined,\n    get_compat_model_name_map,\n    get_definitions,\n    get_schema_from_model_field,\n    lenient_issubclass,\n)\nfrom fastapi.datastructures import DefaultPlaceholder\nfrom fastapi.dependencies.models import Dependant\nfrom fastapi.dependencies.utils import (\n    _get_flat_fields_from_params,\n    get_flat_dependant,\n    get_flat_params,\n)\nfrom fastapi.encoders import jsonable_encoder\nfrom fastapi.openapi.constants import METHODS_WITH_BODY, REF_PREFIX\nfrom fastapi.openapi.models import OpenAPI\nfrom fastapi.params import Body, ParamTypes\nfrom fastapi.responses import Response\nfrom fastapi.types import ModelNameMap\nfrom fastapi.utils import (\n    deep_dict_update,\n    generate_operation_id_for_path,\n    is_body_allowed_for_status_code,\n)\nfrom pydantic import BaseModel\nfrom starlette.responses import JSONResponse\nfrom starlette.routing import BaseRoute\nfrom typing_extensions import Literal\n\nfrom .._compat import _is_model_field\n\nvalidation_error_definition = {\n    \"title\": \"ValidationError\",\n    \"type\": \"object\",\n    \"properties\": {\n        \"loc\": {\n            \"title\": \"Location\",\n            \"type\": \"array\",\n            \"items\": {\"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]},\n        },\n        \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n        \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n    },\n    \"required\": [\"loc\", \"msg\", \"type\"],\n}\n\nvalidation_error_response_definition = {\n    \"title\": \"HTTPValidationError\",\n    \"type\": \"object\",\n    \"properties\": {\n        \"detail\": {\n            \"title\": \"Detail\",\n       
3read_file
{
 "filepath": "fastapi/openapi/utils.py",
 "start_line": 151,
 "end_line": 558
}
{"status": "ok", "filepath": "fastapi/openapi/utils.py", "content": " \"required\": param.required,\n \"schema\": param_schema,\n }\n if field_info.description:
full
{"status": "ok", "filepath": "fastapi/openapi/utils.py", "content": "                \"required\": param.required,\n                \"schema\": param_schema,\n            }\n            if field_info.description:\n                parameter[\"description\"] = field_info.description\n            openapi_examples = getattr(field_info, \"openapi_examples\", None)\n            example = getattr(field_info, \"example\", None)\n            if openapi_examples:\n                parameter[\"examples\"] = jsonable_encoder(openapi_examples)\n            elif example != Undefined:\n                parameter[\"example\"] = jsonable_encoder(example)\n            if getattr(field_info, \"deprecated\", None):\n                parameter[\"deprecated\"] = True\n            parameters.append(parameter)\n    return parameters\n\n\ndef get_openapi_operation_request_body(\n    *,\n    body_field: Optional[ModelField],\n    model_name_map: ModelNameMap,\n    field_mapping: Dict[\n        Tuple[ModelField, Literal[\"validation\", \"serialization\"]], JsonSchemaValue\n    ],\n    separate_input_output_schemas: bool = True,\n) -> Optional[Dict[str, Any]]:\n    if not body_field:\n        return None\n    assert _is_model_field(body_field)\n    body_schema = get_schema_from_model_field(\n        field=body_field,\n        model_name_map=model_name_map,\n        field_mapping=field_mapping,\n        separate_input_output_schemas=separate_input_output_schemas,\n    )\n    field_info = cast(Body, body_field.field_info)\n    request_media_type = field_info.media_type\n    required = body_field.required\n    request_body_oai: Dict[str, Any] = {}\n    if required:\n        request_body_oai[\"required\"] = required\n    request_media_content: Dict[str, Any] = {\"schema\": body_schema}\n    if field_info.openapi_examples:\n        request_media_content[\"examples\"] = jsonable_encoder(\n            field_info.openapi_examples\n        )\n    elif field_info.example != Undefined:\n        request_medi
4read_file
{
 "end_line": 558,
 "filepath": "fastapi/openapi/utils.py",
 "start_line": 301
}
{"status": "ok", "filepath": "fastapi/openapi/utils.py", "content": " # over non-required definitions\n all_parameters.update(required_parameters)\n operation[\
full
{"status": "ok", "filepath": "fastapi/openapi/utils.py", "content": "                # over non-required definitions\n                all_parameters.update(required_parameters)\n                operation[\"parameters\"] = list(all_parameters.values())\n            if method in METHODS_WITH_BODY:\n                request_body_oai = get_openapi_operation_request_body(\n                    body_field=route.body_field,\n                    model_name_map=model_name_map,\n                    field_mapping=field_mapping,\n                    separate_input_output_schemas=separate_input_output_schemas,\n                )\n                if request_body_oai:\n                    operation[\"requestBody\"] = request_body_oai\n            if route.callbacks:\n                callbacks = {}\n                for callback in route.callbacks:\n                    if isinstance(callback, routing.APIRoute):\n                        (\n                            cb_path,\n                            cb_security_schemes,\n                            cb_definitions,\n                        ) = get_openapi_path(\n                            route=callback,\n                            operation_ids=operation_ids,\n                            model_name_map=model_name_map,\n                            field_mapping=field_mapping,\n                            separate_input_output_schemas=separate_input_output_schemas,\n                        )\n                        callbacks[callback.name] = {callback.path: cb_path}\n                operation[\"callbacks\"] = callbacks\n            if route.status_code is not None:\n                status_code = str(route.status_code)\n            else:\n                # It would probably make more sense for all response classes to have an\n                # explicit default status_code, and to extract it from them, instead of\n                # doing this inspection tricks, that would probably be in the future\n                # TODO: probably 
5run_command
{
 "command": "grep -rn \"get_schema_from_model_field\" ."
}
{"status": "ok", "stdout": "./fastapi/openapi/utils.py:13: get_schema_from_model_field,\n./fastapi/openapi/utils.py:129: param_schema = get_schema_from_model_fi
full
{"status": "ok", "stdout": "./fastapi/openapi/utils.py:13:    get_schema_from_model_field,\n./fastapi/openapi/utils.py:129:            param_schema = get_schema_from_model_field(\n./fastapi/openapi/utils.py:180:    body_schema = get_schema_from_model_field(\n./fastapi/openapi/utils.py:352:                        response_schema = get_schema_from_model_field(\n./fastapi/openapi/utils.py:385:                        additional_field_schema = get_schema_from_model_field(\n./fastapi/_compat/v1.py:236:def get_schema_from_model_field(\n./fastapi/_compat/__init__.py:23:from .main import get_schema_from_model_field as get_schema_from_model_field\n./fastapi/_compat/main.py:314:def get_schema_from_model_field(\n./fastapi/_compat/main.py:327:        return v1.get_schema_from_model_field(\n./fastapi/_compat/main.py:337:        return v2.get_schema_from_model_field(\n./fastapi/_compat/v2.py:174:def get_schema_from_model_field(\n", "stderr": "", "exit_code": 0}
6read_file
{
 "filepath": "fastapi/_compat/main.py"
}
{"status": "ok", "filepath": "fastapi/_compat/main.py", "content": "import sys\nfrom functools import lru_cache\nfrom typing import (\n Any,\n Dict,\n List,\n S
full
{"status": "ok", "filepath": "fastapi/_compat/main.py", "content": "import sys\nfrom functools import lru_cache\nfrom typing import (\n    Any,\n    Dict,\n    List,\n    Sequence,\n    Tuple,\n    Type,\n)\n\nfrom fastapi._compat import may_v1\nfrom fastapi._compat.shared import PYDANTIC_V2, lenient_issubclass\nfrom fastapi.types import ModelNameMap\nfrom pydantic import BaseModel\nfrom typing_extensions import Literal\n\nfrom .model_field import ModelField\n\nif PYDANTIC_V2:\n    from .v2 import BaseConfig as BaseConfig\n    from .v2 import FieldInfo as FieldInfo\n    from .v2 import PydanticSchemaGenerationError as PydanticSchemaGenerationError\n    from .v2 import RequiredParam as RequiredParam\n    from .v2 import Undefined as Undefined\n    from .v2 import UndefinedType as UndefinedType\n    from .v2 import Url as Url\n    from .v2 import Validator as Validator\n    from .v2 import evaluate_forwardref as evaluate_forwardref\n    from .v2 import get_missing_field_error as get_missing_field_error\n    from .v2 import (\n        with_info_plain_validator_function as with_info_plain_validator_function,\n    )\nelse:\n    from .v1 import BaseConfig as BaseConfig  # type: ignore[assignment]\n    from .v1 import FieldInfo as FieldInfo\n    from .v1 import (  # type: ignore[assignment]\n        PydanticSchemaGenerationError as PydanticSchemaGenerationError,\n    )\n    from .v1 import RequiredParam as RequiredParam\n    from .v1 import Undefined as Undefined\n    from .v1 import UndefinedType as UndefinedType\n    from .v1 import Url as Url  # type: ignore[assignment]\n    from .v1 import Validator as Validator\n    from .v1 import evaluate_forwardref as evaluate_forwardref\n    from .v1 import get_missing_field_error as get_missing_field_error\n    from .v1 import (  # type: ignore[assignment]\n        with_info_plain_validator_function as with_info_plain_validator_function,\n    )\n\n\n@lru_cache\ndef get_cached_model_fields(model: Type[BaseModel]) -> List[ModelFiel
7read_file
{
 "end_line": 362,
 "filepath": "fastapi/_compat/main.py",
 "start_line": 314
}
{"status": "ok", "filepath": "fastapi/_compat/main.py", "content": "def get_schema_from_model_field(\n *,\n field: ModelField,\n model_name_map: ModelNameMap,\n
full
{"status": "ok", "filepath": "fastapi/_compat/main.py", "content": "def get_schema_from_model_field(\n    *,\n    field: ModelField,\n    model_name_map: ModelNameMap,\n    field_mapping: Dict[\n        Tuple[ModelField, Literal[\"validation\", \"serialization\"]],\n        may_v1.JsonSchemaValue,\n    ],\n    separate_input_output_schemas: bool = True,\n) -> Dict[str, Any]:\n    if isinstance(field, may_v1.ModelField):\n        from fastapi._compat import v1\n\n        return v1.get_schema_from_model_field(\n            field=field,\n            model_name_map=model_name_map,\n            field_mapping=field_mapping,\n            separate_input_output_schemas=separate_input_output_schemas,\n        )\n    else:\n        assert PYDANTIC_V2\n        from . import v2\n\n        return v2.get_schema_from_model_field(\n            field=field,  # type: ignore[arg-type]\n            model_name_map=model_name_map,\n            field_mapping=field_mapping,  # type: ignore[arg-type]\n            separate_input_output_schemas=separate_input_output_schemas,\n        )\n\n\ndef _is_model_field(value: Any) -> bool:\n    if isinstance(value, may_v1.ModelField):\n        return True\n    elif PYDANTIC_V2:\n        from . import v2\n\n        return isinstance(value, v2.ModelField)\n    return False\n\n\ndef _is_model_class(value: Any) -> bool:\n    if lenient_issubclass(value, may_v1.BaseModel):\n        return True\n    elif PYDANTIC_V2:\n        from . import v2\n\n        return lenient_issubclass(value, v2.BaseModel)  # type: ignore[attr-defined]\n    return False", "start_line": 314, "end_line": 362, "total_lines": 362, "is_truncated": false}
8read_file
{
 "filepath": "fastapi/_compat/v2.py"
}
{"status": "ok", "filepath": "fastapi/_compat/v2.py", "content": "import re\nimport warnings\nfrom copy import copy, deepcopy\nfrom dataclasses import dataclass
full
{"status": "ok", "filepath": "fastapi/_compat/v2.py", "content": "import re\nimport warnings\nfrom copy import copy, deepcopy\nfrom dataclasses import dataclass\nfrom enum import Enum\nfrom typing import (\n    Any,\n    Dict,\n    List,\n    Sequence,\n    Set,\n    Tuple,\n    Type,\n    Union,\n    cast,\n)\n\nfrom fastapi._compat import may_v1, shared\nfrom fastapi.openapi.constants import REF_TEMPLATE\nfrom fastapi.types import IncEx, ModelNameMap\nfrom pydantic import BaseModel, TypeAdapter, create_model\nfrom pydantic import PydanticSchemaGenerationError as PydanticSchemaGenerationError\nfrom pydantic import PydanticUndefinedAnnotation as PydanticUndefinedAnnotation\nfrom pydantic import ValidationError as ValidationError\nfrom pydantic._internal._schema_generation_shared import (  # type: ignore[attr-defined]\n    GetJsonSchemaHandler as GetJsonSchemaHandler,\n)\nfrom pydantic._internal._typing_extra import eval_type_lenient\nfrom pydantic._internal._utils import lenient_issubclass as lenient_issubclass\nfrom pydantic.fields import FieldInfo as FieldInfo\nfrom pydantic.json_schema import GenerateJsonSchema as GenerateJsonSchema\nfrom pydantic.json_schema import JsonSchemaValue as JsonSchemaValue\nfrom pydantic_core import CoreSchema as CoreSchema\nfrom pydantic_core import PydanticUndefined, PydanticUndefinedType\nfrom pydantic_core import Url as Url\nfrom typing_extensions import Annotated, Literal, get_args, get_origin\n\ntry:\n    from pydantic_core.core_schema import (\n        with_info_plain_validator_function as with_info_plain_validator_function,\n    )\nexcept ImportError:  # pragma: no cover\n    from pydantic_core.core_schema import (\n        general_plain_validator_function as with_info_plain_validator_function,  # noqa: F401\n    )\n\nRequiredParam = PydanticUndefined\nUndefined = PydanticUndefined\nUndefinedType = PydanticUndefinedType\nevaluate_forwardref = eval_type_lenient\nValidator = Any\n\n\nclass BaseConfig:\n    pass\n\n\nclass ErrorWr
9read_file
{
 "end_line": 486,
 "filepath": "fastapi/_compat/v2.py",
 "start_line": 174
}
{"status": "ok", "filepath": "fastapi/_compat/v2.py", "content": "def get_schema_from_model_field(\n *,\n field: ModelField,\n model_name_map: ModelNameMap,\n f
full
{"status": "ok", "filepath": "fastapi/_compat/v2.py", "content": "def get_schema_from_model_field(\n    *,\n    field: ModelField,\n    model_name_map: ModelNameMap,\n    field_mapping: Dict[\n        Tuple[ModelField, Literal[\"validation\", \"serialization\"]], JsonSchemaValue\n    ],\n    separate_input_output_schemas: bool = True,\n) -> Dict[str, Any]:\n    override_mode: Union[Literal[\"validation\"], None] = (\n        None if separate_input_output_schemas else \"validation\"\n    )\n    # This expects that GenerateJsonSchema was already used to generate the definitions\n    json_schema = field_mapping[(field, override_mode or field.mode)]\n    if \"$ref\" not in json_schema:\n        # TODO remove when deprecating Pydantic v1\n        # Ref: https://github.com/pydantic/pydantic/blob/d61792cc42c80b13b23e3ffa74bc37ec7c77f7d1/pydantic/schema.py#L207\n        json_schema[\"title\"] = field.field_info.title or field.alias.title().replace(\n            \"_\", \" \"\n        )\n    return json_schema\n\n\ndef get_definitions(\n    *,\n    fields: Sequence[ModelField],\n    model_name_map: ModelNameMap,\n    separate_input_output_schemas: bool = True,\n) -> Tuple[\n    Dict[Tuple[ModelField, Literal[\"validation\", \"serialization\"]], JsonSchemaValue],\n    Dict[str, Dict[str, Any]],\n]:\n    schema_generator = GenerateJsonSchema(ref_template=REF_TEMPLATE)\n    override_mode: Union[Literal[\"validation\"], None] = (\n        None if separate_input_output_schemas else \"validation\"\n    )\n    validation_fields = [field for field in fields if field.mode == \"validation\"]\n    serialization_fields = [field for field in fields if field.mode == \"serialization\"]\n    flat_validation_models = get_flat_models_from_fields(\n        validation_fields, known_models=set()\n    )\n    flat_serialization_models = get_flat_models_from_fields(\n        serialization_fields, known_models=set()\n    )\n    flat_validation_model_fields = [\n        ModelField(\n            field_
10run_command
{
 "command": "cat <<EOF > /tmp/repro.py\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel, computed_field\nfrom fastapi.testclient import TestClient\nimport json\n\napp = FastAPI(separate_input_output_schemas=False)\n\nclass Item(BaseModel):\n    name: str\n    price: float\n\n    @computed_field\n    @property\n    def total(self) -> float:\n        return self.price * 1.2\n\n@app.get(\"/item\", response_model=Item)\ndef get_item():\n    return Item(name=\"Test\", price=10.0)\n\nclient = TestClient(app)\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    schema = response.json()\n    \n    # Find the Item schema\n    # Since separate_input_output_schemas=False, it should be just \"Item\"\n    # If it's True, it might be \"Item-Output\"\n    item_schema = schema[\"components\"][\"schemas\"].get(\"Item\")\n    if not item_schema:\n        print(\"Item schema not found!\")\n        return\n    \n    properties = item_schema.get(\"properties\", {})\n    print(f\"Properties: {list(properties.keys())}\")\n    \n    if \"total\" not in properties:\n        print(\"FAILED: 'total' (computed field) is missing from OpenAPI schema when separate_input_output_schemas=False\")\n    else:\n        print(\"PASSED: 'total' is present\")\n\nif __name__ == \"__main__\":\n    test_openapi_schema()\nEOF\npython3 /tmp/repro.py\n"
}
{"status": "ok", "stdout": "Properties: ['name', 'price']\nFAILED: 'total' (computed field) is missing from OpenAPI schema when separate_input_output_schemas=Fa
full
{"status": "ok", "stdout": "Properties: ['name', 'price']\nFAILED: 'total' (computed field) is missing from OpenAPI schema when separate_input_output_schemas=False\n", "stderr": "", "exit_code": 0}
11run_command
{
 "command": "cat <<EOF > /tmp/repro_true.py\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel, computed_field\nfrom fastapi.testclient import TestClient\nimport json\n\napp = FastAPI(separate_input_output_schemas=True)\n\nclass Item(BaseModel):\n    name: str\n    price: float\n\n    @computed_field\n    @property\n    def total(self) -> float:\n        return self.price * 1.2\n\n@app.get(\"/item\", response_model=Item)\ndef get_item():\n    return Item(name=\"Test\", price=10.0)\n\nclient = TestClient(app)\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    schema = response.json()\n    \n    # When separate_input_output_schemas=True, it should be \"Item-Output\" for response\n    item_schema = schema[\"components\"][\"schemas\"].get(\"Item-Output\")\n    if not item_schema:\n        print(\"Item-Output schema not found!\")\n        return\n    \n    properties = item_schema.get(\"properties\", {})\n    print(f\"Properties: {list(properties.keys())}\")\n    \n    if \"total\" not in properties:\n        print(\"FAILED: 'total' (computed field) is missing from OpenAPI schema when separate_input_output_schemas=True\")\n    else:\n        print(\"PASSED: 'total' is present\")\n\nif __name__ == \"__main__\":\n    test_openapi_schema()\nEOF\npython3 /tmp/repro_true.py\n"
}
{"status": "ok", "stdout": "Item-Output schema not found!\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "Item-Output schema not found!\n", "stderr": "", "exit_code": 0}
12run_command
{
 "command": "cat <<EOF > /tmp/repro_true.py\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel, computed_field\nfrom fastapi.testclient import TestClient\nimport json\n\napp = FastAPI(separate_input_output_schemas=True)\n\nclass Item(BaseModel):\n    name: str\n    price: float\n\n    @computed_field\n    @property\n    def total(self) -> float:\n        return self.price * 1.2\n\n@app.get(\"/item\", response_model=Item)\ndef get_item():\n    return Item(name=\"Test\", price=10.0)\n\nclient = TestClient(app)\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    schema = response.json()\n    \n    print(f\"Schemas: {list(schema['components']['schemas'].keys())}\")\n    \n    # Find any schema that looks like Item\n    item_schema = None\n    for name, schema_val in schema[\"components\"][\"schemas\"].items():\n        if \"Item\" in name:\n            item_schema = schema_val\n            print(f\"Found schema {name}\")\n            break\n            \n    if not item_schema:\n        print(\"Item schema not found!\")\n        return\n    \n    properties = item_schema.get(\"properties\", {})\n    print(f\"Properties: {list(properties.keys())}\")\n    \n    if \"total\" not in properties:\n        print(\"FAILED: 'total' (computed field) is missing\")\n    else:\n        print(\"PASSED: 'total' is present\")\n\nif __name__ == \"__main__\":\n    test_openapi_schema()\nEOF\npython3 /tmp/repro_true.py\n"
}
{"status": "ok", "stdout": "Schemas: ['Item']\nFound schema Item\nProperties: ['name', 'price', 'total']\nPASSED: 'total' is present\n", "stderr": "", "exit_cod
full
{"status": "ok", "stdout": "Schemas: ['Item']\nFound schema Item\nProperties: ['name', 'price', 'total']\nPASSED: 'total' is present\n", "stderr": "", "exit_code": 0}
13read_file
{
 "end_line": 250,
 "filepath": "fastapi/_compat/v2.py",
 "start_line": 174
}
{"status": "ok", "filepath": "fastapi/_compat/v2.py", "content": "def get_schema_from_model_field(\n *,\n field: ModelField,\n model_name_map: ModelNameMap,\n f
full
{"status": "ok", "filepath": "fastapi/_compat/v2.py", "content": "def get_schema_from_model_field(\n    *,\n    field: ModelField,\n    model_name_map: ModelNameMap,\n    field_mapping: Dict[\n        Tuple[ModelField, Literal[\"validation\", \"serialization\"]], JsonSchemaValue\n    ],\n    separate_input_output_schemas: bool = True,\n) -> Dict[str, Any]:\n    override_mode: Union[Literal[\"validation\"], None] = (\n        None if separate_input_output_schemas else \"validation\"\n    )\n    # This expects that GenerateJsonSchema was already used to generate the definitions\n    json_schema = field_mapping[(field, override_mode or field.mode)]\n    if \"$ref\" not in json_schema:\n        # TODO remove when deprecating Pydantic v1\n        # Ref: https://github.com/pydantic/pydantic/blob/d61792cc42c80b13b23e3ffa74bc37ec7c77f7d1/pydantic/schema.py#L207\n        json_schema[\"title\"] = field.field_info.title or field.alias.title().replace(\n            \"_\", \" \"\n        )\n    return json_schema\n\n\ndef get_definitions(\n    *,\n    fields: Sequence[ModelField],\n    model_name_map: ModelNameMap,\n    separate_input_output_schemas: bool = True,\n) -> Tuple[\n    Dict[Tuple[ModelField, Literal[\"validation\", \"serialization\"]], JsonSchemaValue],\n    Dict[str, Dict[str, Any]],\n]:\n    schema_generator = GenerateJsonSchema(ref_template=REF_TEMPLATE)\n    override_mode: Union[Literal[\"validation\"], None] = (\n        None if separate_input_output_schemas else \"validation\"\n    )\n    validation_fields = [field for field in fields if field.mode == \"validation\"]\n    serialization_fields = [field for field in fields if field.mode == \"serialization\"]\n    flat_validation_models = get_flat_models_from_fields(\n        validation_fields, known_models=set()\n    )\n    flat_serialization_models = get_flat_models_from_fields(\n        serialization_fields, known_models=set()\n    )\n    flat_validation_model_fields = [\n        ModelField(\n            field_
14run_command
{
 "command": "cat <<EOF > /tmp/repro.py\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel, computed_field\nfrom fastapi.testclient import TestClient\nimport json\n\napp = FastAPI(separate_input_output_schemas=False)\n\nclass Item(BaseModel):\n    name: str\n    price: float\n\n    @computed_field\n    @property\n    def total(self) -> float:\n        return self.price * 1.2\n\n@app.get(\"/item\", response_model=Item)\ndef get_item():\n    return Item(name=\"Test\", price=10.0)\n\nclient = TestClient(app)\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    schema = response.json()\n    \n    item_schema = schema[\"components\"][\"schemas\"].get(\"Item\")\n    if not item_schema:\n        print(f\"Item schema not found! Schemas: {list(schema['components']['schemas'].keys())}\")\n        return\n    \n    properties = item_schema.get(\"properties\", {})\n    print(f\"Properties: {list(properties.keys())}\")\n    \n    if \"total\" not in properties:\n        print(\"FAILED: 'total' (computed field) is missing from OpenAPI schema when separate_input_output_schemas=False\")\n    else:\n        print(\"PASSED: 'total' is present\")\n\nif __name__ == \"__main__\":\n    test_openapi_schema()\nEOF\npython3 /tmp/repro.py\n"
}
{"status": "ok", "stdout": "Properties: ['name', 'price']\nFAILED: 'total' (computed field) is missing from OpenAPI schema when separate_input_output_schemas=Fa
full
{"status": "ok", "stdout": "Properties: ['name', 'price']\nFAILED: 'total' (computed field) is missing from OpenAPI schema when separate_input_output_schemas=False\n", "stderr": "", "exit_code": 0}
15run_command
{
 "command": "cat <<EOF > /tmp/repro_true.py\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel, computed_field\nfrom fastapi.testclient import TestClient\nimport json\n\napp = FastAPI(separate_input_output_schemas=True)\n\nclass Item(BaseModel):\n    name: str\n    price: float\n\n    @computed_field\n    @property\n    def total(self) -> float:\n        return self.price * 1.2\n\n@app.get(\"/item\", response_model=Item)\ndef get_item():\n    return Item(name=\"Test\", price=10.0)\n\nclient = TestClient(app)\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    schema = response.json()\n    \n    print(f\"Schemas: {list(schema['components']['schemas'].keys())}\")\n    \n    item_schema = None\n    for name, schema_val in schema[\"components\"][\"schemas\"].items():\n        if \"Item\" in name:\n            item_schema = schema_val\n            print(f\"Found schema {name}\")\n            break\n            \n    if not item_schema:\n        print(\"Item schema not found!\")\n        return\n    \n    properties = item_schema.get(\"properties\", {})\n    print(f\"Properties: {list(properties.keys())}\")\n    \n    if \"total\" not in properties:\n        print(\"FAILED: 'total' (computed field) is missing\")\n    else:\n        print(\"PASSED: 'total' is present\")\n\nif __name__ == \"__main__\":\n    test_openapi_schema()\nEOF\npython3 /tmp/repro_true.py\n"
}
{"status": "ok", "stdout": "Schemas: ['Item']\nFound schema Item\nProperties: ['name', 'price', 'total']\nPASSED: 'total' is present\n", "stderr": "", "exit_cod
full
{"status": "ok", "stdout": "Schemas: ['Item']\nFound schema Item\nProperties: ['name', 'price', 'total']\nPASSED: 'total' is present\n", "stderr": "", "exit_code": 0}
16run_command
{
 "command": "cat <<EOF > /tmp/repro_mixed.py\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel, computed_field\nfrom fastapi.testclient import TestClient\nimport json\n\napp = FastAPI(separate_input_output_schemas=True)\n\nclass Item(BaseModel):\n    name: str\n    price: float\n\n    @computed_field\n    @property\n    def total(self) -> float:\n        return self.price * 1.2\n\n@app.post(\"/item\", response_model=Item)\ndef create_item(item: Item):\n    return item\n\nclient = TestClient(app)\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    schema = response.json()\n    \n    print(f\"Schemas: {list(schema['components']['schemas'].keys())}\")\n    \n    for name, schema_val in schema[\"components\"][\"schemas\"].items():\n        print(f\"Schema {name} properties: {list(schema_val.get('properties', {}).keys())}\")\n\nif __name__ == \"__main__\":\n    test_openapi_schema()\nEOF\npython3 /tmp/repro_mixed.py\n"
}
{"status": "ok", "stdout": "Schemas: ['HTTPValidationError', 'Item-Input', 'Item-Output', 'ValidationError']\nSchema HTTPValidationError properties: ['detail']\
full
{"status": "ok", "stdout": "Schemas: ['HTTPValidationError', 'Item-Input', 'Item-Output', 'ValidationError']\nSchema HTTPValidationError properties: ['detail']\nSchema Item-Input properties: ['name', 'price']\nSchema Item-Output properties: ['name', 'price', 'total']\nSchema ValidationError properties: ['loc', 'msg', 'type']\n", "stderr": "", "exit_code": 0}
17run_command
{
 "command": "cat <<EOF > /tmp/repro_mixed_false.py\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel, computed_field\nfrom fastapi.testclient import TestClient\nimport json\n\napp = FastAPI(separate_input_output_schemas=False)\n\nclass Item(BaseModel):\n    name: str\n    price: float\n\n    @computed_field\n    @property\n    def total(self) -> float:\n        return self.price * 1.2\n\n@app.post(\"/item\", response_model=Item)\ndef create_item(item: Item):\n    return item\n\nclient = TestClient(app)\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    schema = response.json()\n    \n    print(f\"Schemas: {list(schema['components']['schemas'].keys())}\")\n    \n    for name, schema_val in schema[\"components\"][\"schemas\"].items():\n        print(f\"Schema {name} properties: {list(schema_val.get('properties', {}).keys())}\")\n\nif __name__ == \"__main__\":\n    test_openapi_schema()\nEOF\npython3 /tmp/repro_mixed_false.py\n"
}
{"status": "ok", "stdout": "Schemas: ['HTTPValidationError', 'Item', 'ValidationError']\nSchema HTTPValidationError properties: ['detail']\nSchema Item properti
full
{"status": "ok", "stdout": "Schemas: ['HTTPValidationError', 'Item', 'ValidationError']\nSchema HTTPValidationError properties: ['detail']\nSchema Item properties: ['name', 'price']\nSchema ValidationError properties: ['loc', 'msg', 'type']\n", "stderr": "", "exit_code": 0}
18read_file
{
 "end_line": 220,
 "filepath": "fastapi/_compat/v2.py",
 "start_line": 174
}
{"status": "ok", "filepath": "fastapi/_compat/v2.py", "content": "def get_schema_from_model_field(\n *,\n field: ModelField,\n model_name_map: ModelNameMap,\n f
full
{"status": "ok", "filepath": "fastapi/_compat/v2.py", "content": "def get_schema_from_model_field(\n    *,\n    field: ModelField,\n    model_name_map: ModelNameMap,\n    field_mapping: Dict[\n        Tuple[ModelField, Literal[\"validation\", \"serialization\"]], JsonSchemaValue\n    ],\n    separate_input_output_schemas: bool = True,\n) -> Dict[str, Any]:\n    override_mode: Union[Literal[\"validation\"], None] = (\n        None if separate_input_output_schemas else \"validation\"\n    )\n    # This expects that GenerateJsonSchema was already used to generate the definitions\n    json_schema = field_mapping[(field, override_mode or field.mode)]\n    if \"$ref\" not in json_schema:\n        # TODO remove when deprecating Pydantic v1\n        # Ref: https://github.com/pydantic/pydantic/blob/d61792cc42c80b13b23e3ffa74bc37ec7c77f7d1/pydantic/schema.py#L207\n        json_schema[\"title\"] = field.field_info.title or field.alias.title().replace(\n            \"_\", \" \"\n        )\n    return json_schema\n\n\ndef get_definitions(\n    *,\n    fields: Sequence[ModelField],\n    model_name_map: ModelNameMap,\n    separate_input_output_schemas: bool = True,\n) -> Tuple[\n    Dict[Tuple[ModelField, Literal[\"validation\", \"serialization\"]], JsonSchemaValue],\n    Dict[str, Dict[str, Any]],\n]:\n    schema_generator = GenerateJsonSchema(ref_template=REF_TEMPLATE)\n    override_mode: Union[Literal[\"validation\"], None] = (\n        None if separate_input_output_schemas else \"validation\"\n    )\n    validation_fields = [field for field in fields if field.mode == \"validation\"]\n    serialization_fields = [field for field in fields if field.mode == \"serialization\"]\n    flat_validation_models = get_flat_models_from_fields(\n        validation_fields, known_models=set()\n    )\n    flat_serialization_models = get_flat_models_from_fields(\n        serialization_fields, known_models=set()\n    )\n    flat_validation_model_fields = [\n        ModelField(\n            field_
19run_command
{
 "command": "cat <<EOF > /tmp/repro_mixed_false.py\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel, computed_field\nfrom fastapi.testclient import TestClient\nimport json\n\napp = FastAPI(separate_input_output_schemas=False)\n\nclass Item(BaseModel):\n    name: str\n    price: float\n\n    @computed_field\n    @property\n    def total(self) -> float:\n        return self.price * 1.2\n\n@app.post(\"/item\", response_model=Item)\ndef create_item(item: Item):\n    return item\n\nclient = TestClient(app)\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    schema = response.json()\n    \n    print(f\"Schemas: {list(schema['components']['schemas'].keys())}\")\n    \n    for name, schema_val in schema[\"components\"][\"schemas\"].items():\n        print(f\"Schema {name} properties: {list(schema_val.get('properties', {}).keys())}\")\n\nif __name__ == \"__main__\":\n    test_openapi_schema()\nEOF\npython3 /tmp/repro_mixed_false.py\n"
}
{"status": "ok", "stdout": "Schemas: ['HTTPValidationError', 'Item', 'ValidationError']\nSchema HTTPValidationError properties: ['detail']\nSchema Item properti
full
{"status": "ok", "stdout": "Schemas: ['HTTPValidationError', 'Item', 'ValidationError']\nSchema HTTPValidationError properties: ['detail']\nSchema Item properties: ['name', 'price']\nSchema ValidationError properties: ['loc', 'msg', 'type']\n", "stderr": "", "exit_code": 0}
20run_command
{
 "command": "cat <<EOF > /tmp/repro_mixed_true.py\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel, computed_field\nfrom fastapi.testclient import TestClient\nimport json\n\napp = FastAPI(separate_input_output_schemas=True)\n\nclass Item(BaseModel):\n    name: str\n    price: float\n\n    @computed_field\n    @property\n    def total(self) -> float:\n        return self.price * 1.2\n\n@app.post(\"/item\", response_model=Item)\ndef create_item(item: Item):\n    return item\n\nclient = TestClient(app)\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    schema = response.json()\n    \n    print(f\"Schemas: {list(schema['components']['schemas'].keys())}\")\n    \n    for name, schema_val in schema[\"components\"][\"schemas\"].items():\n        print(f\"Schema {name} properties: {list(schema_val.get('properties', {}).keys())}\")\n\nif __name__ == \"__main__\":\n    test_openapi_schema()\nEOF\npython3 /tmp/repro_mixed_true.py\n"
}
{"status": "ok", "stdout": "Schemas: ['HTTPValidationError', 'Item-Input', 'Item-Output', 'ValidationError']\nSchema HTTPValidationError properties: ['detail']\
full
{"status": "ok", "stdout": "Schemas: ['HTTPValidationError', 'Item-Input', 'Item-Output', 'ValidationError']\nSchema HTTPValidationError properties: ['detail']\nSchema Item-Input properties: ['name', 'price']\nSchema Item-Output properties: ['name', 'price', 'total']\nSchema ValidationError properties: ['loc', 'msg', 'type']\n", "stderr": "", "exit_code": 0}
21run_command
{
 "command": "cat <<EOF > /tmp/repro_mixed_false.py\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel, computed_field\nfrom fastapi.testclient import TestClient\nimport json\n\napp = FastAPI(separate_input_output_schemas=False)\n\nclass Item(BaseModel):\n    name: str\n    price: float\n\n    @computed_field\n    @property\n    def total(self) -> float:\n        return self.price * 1.2\n\n@app.post(\"/item\", response_model=Item)\ndef create_item(item: Item):\n    return item\n\nclient = TestClient(app)\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    schema = response.json()\n    \n    print(f\"Schemas: {list(schema['components']['schemas'].keys())}\")\n    \n    for name, schema_val in schema[\"components\"][\"schemas\"].items():\n        print(f\"Schema {name} properties: {list(schema_val.get('properties', {}).keys())}\")\n\nif __name__ == \"__main__\":\n    test_openapi_schema()\nEOF\npython3 /tmp/repro_mixed_false.py\n"
}
{"status": "ok", "stdout": "Schemas: ['HTTPValidationError', 'Item', 'ValidationError']\nSchema HTTPValidationError properties: ['detail']\nSchema Item properti
full
{"status": "ok", "stdout": "Schemas: ['HTTPValidationError', 'Item', 'ValidationError']\nSchema HTTPValidationError properties: ['detail']\nSchema Item properties: ['name', 'price']\nSchema ValidationError properties: ['loc', 'msg', 'type']\n", "stderr": "", "exit_code": 0}
22run_command
{
 "command": "cat <<EOF > /tmp/repro_mixed_false.py\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel, computed_field\nfrom fastapi.testclient import TestClient\nimport json\n\napp = FastAPI(separate_input_output_schemas=False)\n\nclass Item(BaseModel):\n    name: str\n    price: float\n\n    @computed_field\n    @property\n    def total(self) -> float:\n        return self.price * 1.2\n\n@app.get(\"/item\", response_model=Item)\ndef get_item():\n    return Item(name=\"Test\", price=10.0)\n\nclient = TestClient(app)\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    schema = response.json()\n    \n    print(f\"Schemas: {list(schema['components']['schemas'].keys())}\")\n    \n    for name, schema_val in schema[\"components\"][\"schemas\"].items():\n        print(f\"Schema {name} properties: {list(schema_val.get('properties', {}).keys())}\")\n\nif __name__ == \"__main__\":\n    test_openapi_schema()\nEOF\npython3 /tmp/repro_mixed_false.py\n"
}
{"status": "ok", "stdout": "Schemas: ['Item']\nSchema Item properties: ['name', 'price']\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "Schemas: ['Item']\nSchema Item properties: ['name', 'price']\n", "stderr": "", "exit_code": 0}