← pod_r5_v1h

fastapi_14186

failed CONTEXT UNSUBMITTED agent_error · 30 tool calls · 231 s · fastapi/fastapi

Task input

🐛 Fix internal Pydantic v1 compatibility (warnings) for Python 3.14 and Pydantic 2.12.1

The Python 3.14 tests started failing with the Pydantic v.2.12.1 release, because of the combination of https://github.com/fastapi/fastapi/pull/14168 and https://github.com/pydantic/pydantic/pull/12367.

Basically we were importing Pydantic `v1` functionality even when the user had (only) Pydantic v2 installed. This was done in https://github.com/fastapi/fastapi/pull/14168 to support more easy migration from v1 to v2 by allowing mixing versions within the same app.

Here, we prevent importing any `v1` functionality by creating dummy classes for Python 3.14 / Pydantic 2.12.0 onwards, which [drops support](https://github.com/pydantic/pydantic/releases/tag/v2.12.0) for `v1` and emits a [warning](https://github.com/pydantic/pydantic/pull/12367) when importing `v1` functionality.

### TODO

- [x] fix coverage
- [ ] check warning is still shown to users at some point, and not just swallowed by this code.

Tool calls (30)

#ToolArgumentsResult
1run_command
{
 "command": "grep -rn \"pydantic.v1\" fastapi | head -20"
}
{"status": "ok", "stdout": "fastapi/dependencies/utils.py:51:from fastapi._compat.shared import annotation_is_pydantic_v1\nfastapi/dependencies/utils.py:79:from
full
{"status": "ok", "stdout": "fastapi/dependencies/utils.py:51:from fastapi._compat.shared import annotation_is_pydantic_v1\nfastapi/dependencies/utils.py:79:from .. import temp_pydantic_v1_params\nfastapi/dependencies/utils.py:323:            param_details.field.field_info, (params.Body, temp_pydantic_v1_params.Body)\nfastapi/dependencies/utils.py:392:                    temp_pydantic_v1_params.Param,\nfastapi/dependencies/utils.py:394:                    temp_pydantic_v1_params.Body,\nfastapi/dependencies/utils.py:483:            if annotation_is_pydantic_v1(use_annotation):\nfastapi/dependencies/utils.py:484:                field_info = temp_pydantic_v1_params.Body(\nfastapi/dependencies/utils.py:500:                field_info, (params.Path, temp_pydantic_v1_params.Path)\nfastapi/dependencies/utils.py:506:            isinstance(field_info, (params.Param, temp_pydantic_v1_params.Param))\nfastapi/dependencies/utils.py:515:        if isinstance(field_info, (params.Form, temp_pydantic_v1_params.Form)):\nfastapi/dependencies/utils.py:534:        elif isinstance(field_info, (params.Query, temp_pydantic_v1_params.Query)):\nfastapi/dependencies/utils.py:761:            isinstance(field.field_info, (params.Form, temp_pydantic_v1_params.Form))\nfastapi/dependencies/utils.py:827:        assert isinstance(field_info, (params.Param, temp_pydantic_v1_params.Param)), (\nfastapi/dependencies/utils.py:839:        assert isinstance(field_info, (params.Param, temp_pydantic_v1_params.Param)), (\nfastapi/dependencies/utils.py:888:        isinstance(first_field.field_info, (params.Form, temp_pydantic_v1_params.Form))\nfastapi/dependencies/utils.py:906:            isinstance(field_info, (params.File, temp_pydantic_v1_params.File))\nfastapi/dependencies/utils.py:913:            and isinstance(field_info, (params.File, temp_pydantic_v1_params.File))\nfastapi/dependencies/utils.py:1020:        isinstance(f.field_info, temp_pydantic_v1_params.File)\nfastapi/dependencies/utils.py:1023:       
2run_command
{
 "command": "grep -rn \"temp_pydantic_v1_params\" fastapi | head -20"
}
{"status": "ok", "stdout": "fastapi/dependencies/utils.py:79:from .. import temp_pydantic_v1_params\nfastapi/dependencies/utils.py:323: param_details.field.fiel
full
{"status": "ok", "stdout": "fastapi/dependencies/utils.py:79:from .. import temp_pydantic_v1_params\nfastapi/dependencies/utils.py:323:            param_details.field.field_info, (params.Body, temp_pydantic_v1_params.Body)\nfastapi/dependencies/utils.py:392:                    temp_pydantic_v1_params.Param,\nfastapi/dependencies/utils.py:394:                    temp_pydantic_v1_params.Body,\nfastapi/dependencies/utils.py:484:                field_info = temp_pydantic_v1_params.Body(\nfastapi/dependencies/utils.py:500:                field_info, (params.Path, temp_pydantic_v1_params.Path)\nfastapi/dependencies/utils.py:506:            isinstance(field_info, (params.Param, temp_pydantic_v1_params.Param))\nfastapi/dependencies/utils.py:515:        if isinstance(field_info, (params.Form, temp_pydantic_v1_params.Form)):\nfastapi/dependencies/utils.py:534:        elif isinstance(field_info, (params.Query, temp_pydantic_v1_params.Query)):\nfastapi/dependencies/utils.py:761:            isinstance(field.field_info, (params.Form, temp_pydantic_v1_params.Form))\nfastapi/dependencies/utils.py:827:        assert isinstance(field_info, (params.Param, temp_pydantic_v1_params.Param)), (\nfastapi/dependencies/utils.py:839:        assert isinstance(field_info, (params.Param, temp_pydantic_v1_params.Param)), (\nfastapi/dependencies/utils.py:888:        isinstance(first_field.field_info, (params.Form, temp_pydantic_v1_params.Form))\nfastapi/dependencies/utils.py:906:            isinstance(field_info, (params.File, temp_pydantic_v1_params.File))\nfastapi/dependencies/utils.py:913:            and isinstance(field_info, (params.File, temp_pydantic_v1_params.File))\nfastapi/dependencies/utils.py:1020:        isinstance(f.field_info, temp_pydantic_v1_params.File)\nfastapi/dependencies/utils.py:1023:        BodyFieldInfo: Type[temp_pydantic_v1_params.Body] = temp_pydantic_v1_params.File  # type: ignore[no-redef]\nfastapi/dependencies/utils.py:1027:        isinstance(f.field_info, temp_pydant
3run_command
{
 "command": "ls -F fastapi/"
}
{"status": "ok", "stdout": "__init__.py\n__main__.py\n_compat/\napplications.py\nbackground.py\ncli.py\nconcurrency.py\ndatastructures.py\ndependencies/\nencode
full
{"status": "ok", "stdout": "__init__.py\n__main__.py\n_compat/\napplications.py\nbackground.py\ncli.py\nconcurrency.py\ndatastructures.py\ndependencies/\nencoders.py\nexception_handlers.py\nexceptions.py\nlogger.py\nmiddleware/\nopenapi/\nparam_functions.py\nparams.py\npy.typed\nrequests.py\nresponses.py\nrouting.py\nsecurity/\nstaticfiles.py\ntemp_pydantic_v1_params.py\ntemplating.py\ntestclient.py\ntypes.py\nutils.py\nwebsockets.py\n", "stderr": "", "exit_code": 0}
4run_command
{
 "command": "cat fastapi/temp_pydantic_v1_params.py"
}
{"status": "ok", "stdout": "import warnings\nfrom typing import Any, Callable, Dict, List, Optional, Union\n\nfrom fastapi.openapi.models import Example\nfrom f
full
{"status": "ok", "stdout": "import warnings\nfrom typing import Any, Callable, Dict, List, Optional, Union\n\nfrom fastapi.openapi.models import Example\nfrom fastapi.params import ParamTypes\nfrom typing_extensions import Annotated, deprecated\n\nfrom ._compat.shared import PYDANTIC_VERSION_MINOR_TUPLE\nfrom ._compat.v1 import FieldInfo, Undefined\n\n_Unset: Any = Undefined\n\n\nclass Param(FieldInfo):  # type: ignore[misc]\n    in_: ParamTypes\n\n    def __init__(\n        self,\n        default: Any = Undefined,\n        *,\n        default_factory: Union[Callable[[], Any], None] = _Unset,\n        annotation: Optional[Any] = None,\n        alias: Optional[str] = None,\n        alias_priority: Union[int, None] = _Unset,\n        # TODO: update when deprecating Pydantic v1, import these types\n        # validation_alias: str | AliasPath | AliasChoices | None\n        validation_alias: Union[str, None] = None,\n        serialization_alias: Union[str, None] = None,\n        title: Optional[str] = None,\n        description: Optional[str] = None,\n        gt: Optional[float] = None,\n        ge: Optional[float] = None,\n        lt: Optional[float] = None,\n        le: Optional[float] = None,\n        min_length: Optional[int] = None,\n        max_length: Optional[int] = None,\n        pattern: Optional[str] = None,\n        regex: Annotated[\n            Optional[str],\n            deprecated(\n                \"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead.\"\n            ),\n        ] = None,\n        discriminator: Union[str, None] = None,\n        strict: Union[bool, None] = _Unset,\n        multiple_of: Union[float, None] = _Unset,\n        allow_inf_nan: Union[bool, None] = _Unset,\n        max_digits: Union[int, None] = _Unset,\n        decimal_places: Union[int, None] = _Unset,\n        examples: Optional[List[Any]] = None,\n        example: Annotated[\n            Optional[Any],\n            deprecated(\n                \"Deprecated in
5run_command
{
 "command": "ls -F fastapi/_compat/"
}
{"status": "ok", "stdout": "__init__.py\nmain.py\nmodel_field.py\nshared.py\nv1.py\nv2.py\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "__init__.py\nmain.py\nmodel_field.py\nshared.py\nv1.py\nv2.py\n", "stderr": "", "exit_code": 0}
6run_command
{
 "command": "cat fastapi/_compat/v1.py"
}
{"status": "ok", "stdout": "from copy import copy\nfrom dataclasses import dataclass, is_dataclass\nfrom enum import Enum\nfrom typing import (\n Any,\n Callabl
full
{"status": "ok", "stdout": "from copy import copy\nfrom dataclasses import dataclass, is_dataclass\nfrom enum import Enum\nfrom typing import (\n    Any,\n    Callable,\n    Dict,\n    List,\n    Sequence,\n    Set,\n    Tuple,\n    Type,\n    Union,\n)\n\nfrom fastapi._compat import shared\nfrom fastapi.openapi.constants import REF_PREFIX as REF_PREFIX\nfrom fastapi.types import ModelNameMap\nfrom pydantic.version import VERSION as PYDANTIC_VERSION\nfrom typing_extensions import Literal\n\nPYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(\".\")[:2])\nPYDANTIC_V2 = PYDANTIC_VERSION_MINOR_TUPLE[0] == 2\n# Keeping old \"Required\" functionality from Pydantic V1, without\n# shadowing typing.Required.\nRequiredParam: Any = Ellipsis\n\nif not PYDANTIC_V2:\n    from pydantic import BaseConfig as BaseConfig\n    from pydantic import BaseModel as BaseModel\n    from pydantic import ValidationError as ValidationError\n    from pydantic import create_model as create_model\n    from pydantic.class_validators import Validator as Validator\n    from pydantic.color import Color as Color\n    from pydantic.error_wrappers import ErrorWrapper as ErrorWrapper\n    from pydantic.errors import MissingError\n    from pydantic.fields import (  # type: ignore[attr-defined]\n        SHAPE_FROZENSET,\n        SHAPE_LIST,\n        SHAPE_SEQUENCE,\n        SHAPE_SET,\n        SHAPE_SINGLETON,\n        SHAPE_TUPLE,\n        SHAPE_TUPLE_ELLIPSIS,\n    )\n    from pydantic.fields import FieldInfo as FieldInfo\n    from pydantic.fields import ModelField as ModelField  # type: ignore[attr-defined]\n    from pydantic.fields import Undefined as Undefined  # type: ignore[attr-defined]\n    from pydantic.fields import (  # type: ignore[attr-defined]\n        UndefinedType as UndefinedType,\n    )\n    from pydantic.networks import AnyUrl as AnyUrl\n    from pydantic.networks import NameEmail as NameEmail\n    from pydantic.schema import TypeModelSet as TypeModelSet\n    from
7run_command
{
 "command": "sed -n '1,130p' fastapi/_compat/v1.py"
}
{"status": "ok", "stdout": "from copy import copy\nfrom dataclasses import dataclass, is_dataclass\nfrom enum import Enum\nfrom typing import (\n Any,\n Callabl
full
{"status": "ok", "stdout": "from copy import copy\nfrom dataclasses import dataclass, is_dataclass\nfrom enum import Enum\nfrom typing import (\n    Any,\n    Callable,\n    Dict,\n    List,\n    Sequence,\n    Set,\n    Tuple,\n    Type,\n    Union,\n)\n\nfrom fastapi._compat import shared\nfrom fastapi.openapi.constants import REF_PREFIX as REF_PREFIX\nfrom fastapi.types import ModelNameMap\nfrom pydantic.version import VERSION as PYDANTIC_VERSION\nfrom typing_extensions import Literal\n\nPYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(\".\")[:2])\nPYDANTIC_V2 = PYDANTIC_VERSION_MINOR_TUPLE[0] == 2\n# Keeping old \"Required\" functionality from Pydantic V1, without\n# shadowing typing.Required.\nRequiredParam: Any = Ellipsis\n\nif not PYDANTIC_V2:\n    from pydantic import BaseConfig as BaseConfig\n    from pydantic import BaseModel as BaseModel\n    from pydantic import ValidationError as ValidationError\n    from pydantic import create_model as create_model\n    from pydantic.class_validators import Validator as Validator\n    from pydantic.color import Color as Color\n    from pydantic.error_wrappers import ErrorWrapper as ErrorWrapper\n    from pydantic.errors import MissingError\n    from pydantic.fields import (  # type: ignore[attr-defined]\n        SHAPE_FROZENSET,\n        SHAPE_LIST,\n        SHAPE_SEQUENCE,\n        SHAPE_SET,\n        SHAPE_SINGLETON,\n        SHAPE_TUPLE,\n        SHAPE_TUPLE_ELLIPSIS,\n    )\n    from pydantic.fields import FieldInfo as FieldInfo\n    from pydantic.fields import ModelField as ModelField  # type: ignore[attr-defined]\n    from pydantic.fields import Undefined as Undefined  # type: ignore[attr-defined]\n    from pydantic.fields import (  # type: ignore[attr-defined]\n        UndefinedType as UndefinedType,\n    )\n    from pydantic.networks import AnyUrl as AnyUrl\n    from pydantic.networks import NameEmail as NameEmail\n    from pydantic.schema import TypeModelSet as TypeModelSet\n    from
8run_command
{
 "command": "cat fastapi/_compat/shared.py"
}
{"status": "ok", "stdout": "import sys\nimport types\nimport typing\nfrom collections import deque\nfrom dataclasses import is_dataclass\nfrom typing import (\n
full
{"status": "ok", "stdout": "import sys\nimport types\nimport typing\nfrom collections import deque\nfrom dataclasses import is_dataclass\nfrom typing import (\n    Any,\n    Deque,\n    FrozenSet,\n    List,\n    Mapping,\n    Sequence,\n    Set,\n    Tuple,\n    Type,\n    Union,\n)\n\nfrom fastapi._compat import v1\nfrom fastapi.types import UnionType\nfrom pydantic import BaseModel\nfrom pydantic.version import VERSION as PYDANTIC_VERSION\nfrom starlette.datastructures import UploadFile\nfrom typing_extensions import Annotated, get_args, get_origin\n\n# Copy from Pydantic v2, compatible with v1\nif sys.version_info < (3, 9):\n    # Pydantic no longer supports Python 3.8, this might be incorrect, but the code\n    # this is used for is also never reached in this codebase, as it's a copy of\n    # Pydantic's lenient_issubclass, just for compatibility with v1\n    # TODO: remove when dropping support for Python 3.8\n    WithArgsTypes: Tuple[Any, ...] = ()\nelif sys.version_info < (3, 10):\n    WithArgsTypes: tuple[Any, ...] = (typing._GenericAlias, types.GenericAlias)  # type: ignore[attr-defined]\nelse:\n    WithArgsTypes: tuple[Any, ...] = (\n        typing._GenericAlias,  # type: ignore[attr-defined]\n        types.GenericAlias,\n        types.UnionType,\n    )  # pyright: ignore[reportAttributeAccessIssue]\n\nPYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(\".\")[:2])\nPYDANTIC_V2 = PYDANTIC_VERSION_MINOR_TUPLE[0] == 2\n\n\nsequence_annotation_to_type = {\n    Sequence: list,\n    List: list,\n    list: list,\n    Tuple: tuple,\n    tuple: tuple,\n    Set: set,\n    set: set,\n    FrozenSet: frozenset,\n    frozenset: frozenset,\n    Deque: deque,\n    deque: deque,\n}\n\nsequence_types = tuple(sequence_annotation_to_type.keys())\n\nUrl: Type[Any]\n\n\n# Copy of Pydantic v2, compatible with v1\ndef lenient_issubclass(\n    cls: Any, class_or_tuple: Union[Type[Any], Tuple[Type[Any], ...], None]\n) -> bool:\n    try:\n        return isi
9run_command
{
 "command": "sed -n '1,130p' fastapi/_compat/v1.py | grep -C 5 \"else:\""
}
{"status": "ok", "stdout": " from pydantic.types import SecretStr as SecretStr\n from pydantic.typing import evaluate_forwardref as evaluate_forwardref\n from p
full
{"status": "ok", "stdout": "    from pydantic.types import SecretStr as SecretStr\n    from pydantic.typing import evaluate_forwardref as evaluate_forwardref\n    from pydantic.utils import lenient_issubclass as lenient_issubclass\n\n\nelse:\n    from pydantic.v1 import BaseConfig as BaseConfig  # type: ignore[assignment]\n    from pydantic.v1 import BaseModel as BaseModel  # type: ignore[assignment]\n    from pydantic.v1 import (  # type: ignore[assignment]\n        ValidationError as ValidationError,\n    )\n", "stderr": "", "exit_code": 0}
10run_command
{
 "command": "cat fastapi/_compat/main.py"
}
{"status": "ok", "stdout": "from functools import lru_cache\nfrom typing import (\n Any,\n Dict,\n List,\n Sequence,\n Tuple,\n Type,\n)\n\nfrom fastapi._compat
full
{"status": "ok", "stdout": "from 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 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[ModelField]:\n    if lenient_issubclass(model, v1.BaseModel):\n  
11run_command
{
 "command": "pip show pydantic"
}
{"status": "error", "error_type": "CommandError", "error_message": "/bin/bash: pip: command not found\n", "details": {"stdout": "", "stderr": "/bin/bash: pip: c
full
{"status": "error", "error_type": "CommandError", "error_message": "/bin/bash: pip: command not found\n", "details": {"stdout": "", "stderr": "/bin/bash: pip: command not found\n", "exit_code": 127}}
12run_command
{
 "command": "python3 -c \"import pydantic; print(pydantic.VERSION)\""
}
{"status": "ok", "stdout": "2.13.5\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "2.13.5\n", "stderr": "", "exit_code": 0}
13run_command
{
 "command": "python3 -c \"import sys; print(sys.version)\""
}
{"status": "ok", "stdout": "3.13.15 (main, Sep 1 2026, 14:05:45) [Clang 22.1.3 ]\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "3.13.15 (main, Sep  1 2026, 14:05:45) [Clang 22.1.3 ]\n", "stderr": "", "exit_code": 0}
14run_command
{
 "command": "cat fastapi/_compat/shared.py | grep -n \"PYDANTIC_VERSION_MINOR_TUPLE =\""
}
{"status": "ok", "stdout": "42:PYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(\".\")[:2])\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "42:PYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(\".\")[:2])\n", "stderr": "", "exit_code": 0}
15run_command
{
 "command": "cat fastapi/_compat/v1.py | grep -n \"PYDANTIC_VERSION_MINOR_TUPLE =\""
}
{"status": "ok", "stdout": "22:PYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(\".\")[:2])\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "22:PYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(\".\")[:2])\n", "stderr": "", "exit_code": 0}
16run_command
{
 "command": "sed -n '20,130p' fastapi/_compat/v1.py"
}
{"status": "ok", "stdout": "from typing_extensions import Literal\n\nPYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(\".\")[:2])\nPY
full
{"status": "ok", "stdout": "from typing_extensions import Literal\n\nPYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(\".\")[:2])\nPYDANTIC_V2 = PYDANTIC_VERSION_MINOR_TUPLE[0] == 2\n# Keeping old \"Required\" functionality from Pydantic V1, without\n# shadowing typing.Required.\nRequiredParam: Any = Ellipsis\n\nif not PYDANTIC_V2:\n    from pydantic import BaseConfig as BaseConfig\n    from pydantic import BaseModel as BaseModel\n    from pydantic import ValidationError as ValidationError\n    from pydantic import create_model as create_model\n    from pydantic.class_validators import Validator as Validator\n    from pydantic.color import Color as Color\n    from pydantic.error_wrappers import ErrorWrapper as ErrorWrapper\n    from pydantic.errors import MissingError\n    from pydantic.fields import (  # type: ignore[attr-defined]\n        SHAPE_FROZENSET,\n        SHAPE_LIST,\n        SHAPE_SEQUENCE,\n        SHAPE_SET,\n        SHAPE_SINGLETON,\n        SHAPE_TUPLE,\n        SHAPE_TUPLE_ELLIPSIS,\n    )\n    from pydantic.fields import FieldInfo as FieldInfo\n    from pydantic.fields import ModelField as ModelField  # type: ignore[attr-defined]\n    from pydantic.fields import Undefined as Undefined  # type: ignore[attr-defined]\n    from pydantic.fields import (  # type: ignore[attr-defined]\n        UndefinedType as UndefinedType,\n    )\n    from pydantic.networks import AnyUrl as AnyUrl\n    from pydantic.networks import NameEmail as NameEmail\n    from pydantic.schema import TypeModelSet as TypeModelSet\n    from pydantic.schema import (\n        field_schema,\n        get_flat_models_from_fields,\n        model_process_schema,\n    )\n    from pydantic.schema import (\n        get_annotation_from_field_info as get_annotation_from_field_info,\n    )\n    from pydantic.schema import get_flat_models_from_field as get_flat_models_from_field\n    from pydantic.schema import get_model_name_map as get_model_name_map\n    from pydantic.ty
17run_command
{
 "command": "cat fastapi/_compat/shared.py | head -n 50"
}
{"status": "ok", "stdout": "import sys\nimport types\nimport typing\nfrom collections import deque\nfrom dataclasses import is_dataclass\nfrom typing import (\n
full
{"status": "ok", "stdout": "import sys\nimport types\nimport typing\nfrom collections import deque\nfrom dataclasses import is_dataclass\nfrom typing import (\n    Any,\n    Deque,\n    FrozenSet,\n    List,\n    Mapping,\n    Sequence,\n    Set,\n    Tuple,\n    Type,\n    Union,\n)\n\nfrom fastapi._compat import v1\nfrom fastapi.types import UnionType\nfrom pydantic import BaseModel\nfrom pydantic.version import VERSION as PYDANTIC_VERSION\nfrom starlette.datastructures import UploadFile\nfrom typing_extensions import Annotated, get_args, get_origin\n\n# Copy from Pydantic v2, compatible with v1\nif sys.version_info < (3, 9):\n    # Pydantic no longer supports Python 3.8, this might be incorrect, but the code\n    # this is used for is also never reached in this codebase, as it's a copy of\n    # Pydantic's lenient_issubclass, just for compatibility with v1\n    # TODO: remove when dropping support for Python 3.8\n    WithArgsTypes: Tuple[Any, ...] = ()\nelif sys.version_info < (3, 10):\n    WithArgsTypes: tuple[Any, ...] = (typing._GenericAlias, types.GenericAlias)  # type: ignore[attr-defined]\nelse:\n    WithArgsTypes: tuple[Any, ...] = (\n        typing._GenericAlias,  # type: ignore[attr-defined]\n        types.GenericAlias,\n        types.UnionType,\n    )  # pyright: ignore[reportAttributeAccessIssue]\n\nPYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(\".\")[:2])\nPYDANTIC_V2 = PYDANTIC_VERSION_MINOR_TUPLE[0] == 2\n\n\nsequence_annotation_to_type = {\n    Sequence: list,\n    List: list,\n    list: list,\n    Tuple: tuple,\n", "stderr": "", "exit_code": 0}
18run_command
{
 "command": "cat fastapi/_compat/v1.py | grep -n \"PYDANTIC_V2 =\""
}
{"status": "ok", "stdout": "23:PYDANTIC_V2 = PYDANTIC_VERSION_MINOR_TUPLE[0] == 2\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "23:PYDANTIC_V2 = PYDANTIC_VERSION_MINOR_TUPLE[0] == 2\n", "stderr": "", "exit_code": 0}
19run_command
{
 "command": "sed -n '20,30p' fastapi/_compat/v1.py"
}
{"status": "ok", "stdout": "from typing_extensions import Literal\n\nPYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(\".\")[:2])\nPY
full
{"status": "ok", "stdout": "from typing_extensions import Literal\n\nPYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(\".\")[:2])\nPYDANTIC_V2 = PYDANTIC_VERSION_MINOR_TUPLE[0] == 2\n# Keeping old \"Required\" functionality from Pydantic V1, without\n# shadowing typing.Required.\nRequiredParam: Any = Ellipsis\n\nif not PYDANTIC_V2:\n    from pydantic import BaseConfig as BaseConfig\n    from pydantic import BaseModel as BaseModel\n", "stderr": "", "exit_code": 0}
20run_command
{
 "command": "python3 - <<'PY'\nimport pydantic\nimport sys\nprint(f\"Pydantic version: {pydantic.VERSION}\")\nprint(f\"Python version: {sys.version}\")\n\ntry:\n    from pydantic.v1 import BaseModel\n    print(\"Successfully imported pydantic.v1.BaseModel\")\nexcept ImportError as e:\n    print(f\"Failed to import pydantic.v1.BaseModel: {e}\")\nPY\n"
}
{"status": "ok", "stdout": "Pydantic version: 2.13.5\nPython version: 3.13.15 (main, Sep 1 2026, 14:05:45) [Clang 22.1.3 ]\nSuccessfully imported pydantic.v1.Ba
full
{"status": "ok", "stdout": "Pydantic version: 2.13.5\nPython version: 3.13.15 (main, Sep  1 2026, 14:05:45) [Clang 22.1.3 ]\nSuccessfully imported pydantic.v1.BaseModel\n", "stderr": "", "exit_code": 0}
21run_command
{
 "command": "python3 - <<'PY'\nimport pydantic\nimport sys\nfrom pydantic.version import VERSION as PYDANTIC_VERSION\nPYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(\".\")[:2])\nprint(f\"PYDANTIC_VERSION_MINOR_TUPLE: {PYDANTIC_VERSION_MINOR_TUPLE}\")\nprint(f\"sys.version_info: {sys.version_info}\")\n\nshould_use_dummies = sys.version_info >= (3, 14) and PYDANTIC_VERSION_MINOR_TUPLE >= (2, 12)\nprint(f\"should_use_dummies: {should_use_dummies}\")\nPY\n"
}
{"status": "ok", "stdout": "PYDANTIC_VERSION_MINOR_TUPLE: (2, 13)\nsys.version_info: sys.version_info(major=3, minor=13, micro=15, releaselevel='final', serial=
full
{"status": "ok", "stdout": "PYDANTIC_VERSION_MINOR_TUPLE: (2, 13)\nsys.version_info: sys.version_info(major=3, minor=13, micro=15, releaselevel='final', serial=0)\nshould_use_dummies: False\n", "stderr": "", "exit_code": 0}
22run_command
{
 "command": "python3 - <<'PY'\nimport sys\nfrom pathlib import Path\n\np = Path(\"fastapi/_compat/v1.py\")\ns = p.read_text()\n\n# We want to inject the dummy classes if Python >= 3.14 and Pydantic >= 2.12.0\n# Let's define the condition first.\n\nold = \"\"\"PYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(\".\")[:2])\nPYDANTIC_V2 = PYDANTIC_VERSION_MINOR_TUPLE[0] == 2\"\"\"\n\nnew = \"\"\"PYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(\".\")[:2])\nPYDANTIC_V2 = PYDANTIC_VERSION_MINOR_TUPLE[0] == 2\n\n# Prevent importing pydantic.v1 on Python 3.14+ and Pydantic 2.12+ to avoid warnings\n# from Pydantic.\nUSE_DUMMIES = (\n    sys.version_info >= (3, 14) and PYDANTIC_VERSION_MINOR_TUPLE >= (2, 12)\n)\"\"\"\n\nif old in s:\n    s = s.replace(old, new)\n    p.write_text(s)\n    print(\"Successfully replaced old with new\")\nelse:\n    print(\"Old text not found\")\nPY\n"
}
{"status": "ok", "stdout": "Successfully replaced old with new\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "Successfully replaced old with new\n", "stderr": "", "exit_code": 0}
23run_command
{
 "command": "sed -n '20,35p' fastapi/_compat/v1.py"
}
{"status": "ok", "stdout": "from typing_extensions import Literal\n\nPYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(\".\")[:2])\nPY
full
{"status": "ok", "stdout": "from typing_extensions import Literal\n\nPYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(\".\")[:2])\nPYDANTIC_V2 = PYDANTIC_VERSION_MINOR_TUPLE[0] == 2\n\n# Prevent importing pydantic.v1 on Python 3.14+ and Pydantic 2.12+ to avoid warnings\n# from Pydantic.\nUSE_DUMMIES = (\n    sys.version_info >= (3, 14) and PYDANTIC_VERSION_MINOR_TUPLE >= (2, 12)\n)\n# Keeping old \"Required\" functionality from Pydantic V1, without\n# shadowing typing.Required.\nRequiredParam: Any = Ellipsis\n\nif not PYDANTIC_V2:\n    from pydantic import BaseConfig as BaseConfig\n", "stderr": "", "exit_code": 0}
24run_command
{
 "command": "python3 - <<'PY'\nimport sys\nfrom pathlib import Path\n\np = Path(\"fastapi/_compat/v1.py\")\ns = p.read_text()\n\n# Now we need to handle the imports in the 'else' block where pydantic.v1 is imported.\n# We should wrap those imports in 'if not USE_DUMMIES:'.\n# If USE_DUMMIES is True, we provide dummy classes.\n\n# This is a bit complex because there are many imports.\n# Let's find the start of the 'else:' block and the end of the imports.\n\n# The current structure is:\n# if not PYDANTIC_V2:\n#     ...\n# else:\n#     from pydantic.v1 import BaseConfig as BaseConfig\n#     ...\n\n# We can replace the 'else:' block with a more complex one.\n\n# First, let's list all the symbols that need to be defined.\nsymbols = [\n    \"BaseConfig\", \"BaseModel\", \"ValidationError\", \"create_model\", \"Validator\",\n    \"Color\", \"ErrorWrapper\", \"MissingError\", \"SHAPE_FROZENSET\", \"SHAPE_LIST\",\n    \"SHAPE_SEQUENCE\", \"SHAPE_SET\", \"SHAPE_SINGLETON\", \"SHAPE_TUPLE\",\n    \"SHAPE_TUPLE_ELLIPSIS\", \"FieldInfo\", \"ModelField\", \"Undefined\", \"UndefinedType\",\n    \"AnyUrl\", \"NameEmail\", \"TypeModelSet\", \"field_schema\", \"get_flat_models_from_fields\",\n    \"model_process_schema\", \"get_annotation_from_field_info\", \"get_flat_models_from_field\",\n    \"get_model_name_map\", \"SecretBytes\", \"SecretStr\", \"evaluate_forwardref\", \"lenient_issubclass\"\n]\n\n# Create the dummy assignments.\ndummy_assignments = \"\\n    \".join([f\"{sym}: Any = None\" for sym in symbols])\n\n# We need to find the 'else:' block and modify it.\n# The 'else:' block starts after the 'if not PYDANTIC_V2:' block.\n\n# Let's try to find the 'else:' line.\nlines = s.splitlines()\nelse_idx = -1\nfor i, line in enumerate(lines):\n    if line.strip() == \"else:\":\n        else_idx = i\n        break\n\nif else_idx != -1:\n    # Find where the imports in the else block end.\n    # They end before 'GetJsonSchemaHandler = Any'.\n    end_idx = -1\n    for i in range(else_idx + 1, len(lines)):\n        if \"GetJsonSchemaHandler = Any\" in lines[i]:\n            end_idx = i\n            break\n    \n    if end_idx != -1:\n        # Replace the imports in the else block.\n        # We wrap them in 'if not USE_DUMMIES:' and add the dummies.\n        \n        # Extract the original imports.\n        original_imports = \"\\n\".join(lines[else_idx+1 : end_idx])\n        \n        # Indent the original imports.\n        indented_imports = \"\\n\".join([\"    \" + line for line in original_imports.splitlines()])\n        \n        # Build the new else block.\n        new_else_block = f\"else:\\n    if not USE_DUMMIES:\\n{indented_imports}\\n    else:\\n        {dummy_assignments}\"\n        \n        # Replace the whole else block from 'else:' up to the end of imports.\n        # This is tricky with list indices.\n        \n        # Let's just replace the lines.\n        lines[else_idx : end_idx] = [f\"else:\", f\"    if not USE_DUMMIES:\"]\n        # For the imports, we need to maintain their original indentation (which was 4 spaces)\n        # and add another 4 spaces.\n        for line in original_imports.splitlines():\n            lines.insert(else_idx + 2, \"    \" + line) # This is not quite right.\n            \n        # Let's restart the replacement strategy.\nPY\n"
}
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
25run_command
{
 "command": "python3 - <<'PY'\nimport sys\nfrom pathlib import Path\n\np = Path(\"fastapi/_compat/v1.py\")\ns = p.read_text()\n\n# We want to wrap the pydantic.v1 imports in 'if not USE_DUMMIES:'\n# and provide dummy classes if USE_DUMMIES is True.\n\n# Find the 'else:' block.\nlines = s.splitlines()\nelse_idx = -1\nfor i, line in enumerate(lines):\n    if line.strip() == \"else:\":\n        else_idx = i\n        break\n\nif else_idx != -1:\n    # Find where the imports end.\n    end_idx = -1\n    for i in range(else_idx + 1, len(lines)):\n        if \"GetJsonSchemaHandler = Any\" in lines[i]:\n            end_idx = i\n            break\n    \n    if end_idx != -1:\n        # Symbols that need to be defined.\n        symbols = [\n            \"BaseConfig\", \"BaseModel\", \"ValidationError\", \"create_model\", \"Validator\",\n            \"Color\", \"ErrorWrapper\", \"MissingError\", \"SHAPE_FROZENSET\", \"SHAPE_LIST\",\n            \"SHAPE_SEQUENCE\", \"SHAPE_SET\", \"SHAPE_SINGLETON\", \"SHAPE_TUPLE\",\n            \"SHAPE_TUPLE_ELLIPSIS\", \"FieldInfo\", \"ModelField\", \"Undefined\", \"UndefinedType\",\n            \"AnyUrl\", \"NameEmail\", \"TypeModelSet\", \"field_schema\", \"get_flat_models_from_fields\",\n            \"model_process_schema\", \"get_annotation_from_field_info\", \"get_flat_models_from_field\",\n            \"get_model_name_map\", \"SecretBytes\", \"SecretStr\", \"evaluate_forwardref\", \"lenient_issubclass\"\n        ]\n        \n        # The original imports.\n        original_imports = lines[else_idx + 1 : end_idx]\n        \n        # New lines for the else block.\n        new_lines = [\"else:\"]\n        new_lines.append(\"    if not USE_DUMMIES:\")\n        for line in original_imports:\n            new_lines.append(\"    \" + line)\n        \n        new_lines.append(\"    else:\")\n        for sym in symbols:\n            new_lines.append(f\"        {sym}: Any = None\")\n            \n        # Replace the old lines.\n        lines[else_idx : end_idx] = new_lines\n        p.write_text(\"\\n\".join(lines))\n        print(\"Successfully replaced the else block\")\nelse:\n    print(\"else block not found\")\nPY\n"
}
{"status": "ok", "stdout": "Successfully replaced the else block\n", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "Successfully replaced the else block\n", "stderr": "", "exit_code": 0}
26run_command
{
 "command": "sed -n '100,150p' fastapi/_compat/v1.py"
}
{"status": "ok", "stdout": " from pydantic.v1.fields import Undefined as Undefined\n from pydantic.v1.fields import UndefinedType as UndefinedType\n from pydant
full
{"status": "ok", "stdout": "        from pydantic.v1.fields import Undefined as Undefined\n        from pydantic.v1.fields import UndefinedType as UndefinedType\n        from pydantic.v1.networks import AnyUrl as AnyUrl\n        from pydantic.v1.networks import (  # type: ignore[assignment]\n            NameEmail as NameEmail,\n        )\n        from pydantic.v1.schema import TypeModelSet as TypeModelSet\n        from pydantic.v1.schema import (\n            field_schema,\n            get_flat_models_from_fields,\n            model_process_schema,\n        )\n        from pydantic.v1.schema import (\n            get_annotation_from_field_info as get_annotation_from_field_info,\n        )\n        from pydantic.v1.schema import (\n            get_flat_models_from_field as get_flat_models_from_field,\n        )\n        from pydantic.v1.schema import get_model_name_map as get_model_name_map\n        from pydantic.v1.types import (  # type: ignore[assignment]\n            SecretBytes as SecretBytes,\n        )\n        from pydantic.v1.types import (  # type: ignore[assignment]\n            SecretStr as SecretStr,\n        )\n        from pydantic.v1.typing import evaluate_forwardref as evaluate_forwardref\n        from pydantic.v1.utils import lenient_issubclass as lenient_issubclass\n    \n    \n    else:\n        BaseConfig: Any = None\n        BaseModel: Any = None\n        ValidationError: Any = None\n        create_model: Any = None\n        Validator: Any = None\n        Color: Any = None\n        ErrorWrapper: Any = None\n        MissingError: Any = None\n        SHAPE_FROZENSET: Any = None\n        SHAPE_LIST: Any = None\n        SHAPE_SEQUENCE: Any = None\n        SHAPE_SET: Any = None\n        SHAPE_SINGLETON: Any = None\n        SHAPE_TUPLE: Any = None\n        SHAPE_TUPLE_ELLIPSIS: Any = None\n        FieldInfo: Any = None\n        ModelField: Any = None\n        Undefined: Any = None\n        UndefinedType: Any = None\n        AnyUrl: Any = None\n       
27run_command
{
 "command": "python3 - <<'PY'\nimport sys\nfrom pathlib import Path\n\np = Path(\"fastapi/_compat/v1.py\")\ns = p.read_text()\nlines = s.splitlines()\n\n# Let's check if we missed any symbols in the dummy list.\n# The symbols used in the 'if not PYDANTIC_V2' block should be the same as in the 'else' block.\n# Let's compare them.\n\nif_block_imports = []\nelse_block_imports = []\n\nfound_if = False\nfound_else = False\n\nfor line in lines:\n    if line.strip() == \"if not PYDANTIC_V2:\":\n        found_if = True\n        continue\n    if line.strip() == \"else:\":\n        found_if = False\n        found_else = True\n        continue\n    \n    if found_if and \"from pydantic\" in line:\n        # This is a bit simplistic, but let's try.\n        if \" as \" in line:\n            if \"import (\" in line or \"from \" in line:\n                # Handle multiline imports\n                pass\n    \n    if found_else and \"from pydantic.v1\" in line:\n        pass\n\n# Let's just re-read the file and see if any other symbols are used from v1.\n# a better way is to search for all assignments in v1.py that are not in the dummy list.\nPY\n"
}
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
28run_command
{
 "command": "sed -n '1,200p' fastapi/_compat/v1.py"
}
{"status": "ok", "stdout": "from copy import copy\nfrom dataclasses import dataclass, is_dataclass\nfrom enum import Enum\nfrom typing import (\n Any,\n Callabl
full
{"status": "ok", "stdout": "from copy import copy\nfrom dataclasses import dataclass, is_dataclass\nfrom enum import Enum\nfrom typing import (\n    Any,\n    Callable,\n    Dict,\n    List,\n    Sequence,\n    Set,\n    Tuple,\n    Type,\n    Union,\n)\n\nfrom fastapi._compat import shared\nfrom fastapi.openapi.constants import REF_PREFIX as REF_PREFIX\nfrom fastapi.types import ModelNameMap\nfrom pydantic.version import VERSION as PYDANTIC_VERSION\nfrom typing_extensions import Literal\n\nPYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(\".\")[:2])\nPYDANTIC_V2 = PYDANTIC_VERSION_MINOR_TUPLE[0] == 2\n\n# Prevent importing pydantic.v1 on Python 3.14+ and Pydantic 2.12+ to avoid warnings\n# from Pydantic.\nUSE_DUMMIES = (\n    sys.version_info >= (3, 14) and PYDANTIC_VERSION_MINOR_TUPLE >= (2, 12)\n)\n# Keeping old \"Required\" functionality from Pydantic V1, without\n# shadowing typing.Required.\nRequiredParam: Any = Ellipsis\n\nif not PYDANTIC_V2:\n    from pydantic import BaseConfig as BaseConfig\n    from pydantic import BaseModel as BaseModel\n    from pydantic import ValidationError as ValidationError\n    from pydantic import create_model as create_model\n    from pydantic.class_validators import Validator as Validator\n    from pydantic.color import Color as Color\n    from pydantic.error_wrappers import ErrorWrapper as ErrorWrapper\n    from pydantic.errors import MissingError\n    from pydantic.fields import (  # type: ignore[attr-defined]\n        SHAPE_FROZENSET,\n        SHAPE_LIST,\n        SHAPE_SEQUENCE,\n        SHAPE_SET,\n        SHAPE_SINGLETON,\n        SHAPE_TUPLE,\n        SHAPE_TUPLE_ELLIPSIS,\n    )\n    from pydantic.fields import FieldInfo as FieldInfo\n    from pydantic.fields import ModelField as ModelField  # type: ignore[attr-defined]\n    from pydantic.fields import Undefined as Undefined  # type: ignore[attr-defined]\n    from pydantic.fields import (  # type: ignore[attr-defined]\n        UndefinedType as 
29run_command
{
 "command": "python3 - <<'PY'\nimport sys\nfrom pathlib import Path\n\np = Path(\"fastapi/_compat/v1.py\")\ns = p.read_text()\nlines = s.splitlines()\n\n# We need to make sure all symbols are covered in the dummy list.\n# The previous script missed some because of how it extracted symbols.\n# Let's use a more robust way to find all symbols defined in the 'if not PYDANTIC_V2' block.\n\nsymbols = set()\nfound_if = False\nfor line in lines:\n    if line.strip() == \"if not PYDANTIC_V2:\":\n        found_if = True\n        continue\n    if line.strip() == \"else:\":\n        found_if = False\n        continue\n    \n    if found_if:\n        # Find symbols being imported\n        if \"import \" in line:\n            # Split by comma for multiple imports\n            parts = line.split(\"import\")[-1].split(\",\")\n            for part in parts:\n                part = part.strip()\n                if \" as \" in part:\n                    symbols.add(part.split(\" as \")[-1].strip())\n                else:\n                    # This is trickier for multi-line or group imports.\n                    # But let's look at the file.\n                    pass\n\n# Actually, let's just explicitly list them based on the if block.\nexplicit_symbols = [\n    \"BaseConfig\", \"BaseModel\", \"ValidationError\", \"create_model\", \"Validator\",\n    \"Color\", \"ErrorWrapper\", \"MissingError\", \"SHAPE_FROZENSET\", \"SHAPE_LIST\",\n    \"SHAPE_SEQUENCE\", \"SHAPE_SET\", \"SHAPE_SINGLETON\", \"SHAPE_TUPLE\",\n    \"SHAPE_TUPLE_ELLIPSIS\", \"FieldInfo\", \"ModelField\", \"Undefined\", \"UndefinedType\",\n    \"AnyUrl\", \"NameEmail\", \"TypeModelSet\", \"field_schema\", \"get_flat_models_from_fields\",\n    \"model_process_schema\", \"get_annotation_from_field_info\", \"get_flat_models_from_field\",\n    \"get_model_name_map\", \"SecretBytes\", \"SecretStr\", \"evaluate_forwardref\", \"lenient_issubclass\"\n]\n\n# Let's check if any of these are missing from the current dummy list.\n# The current dummy list is at the end of the 'else' block.\n\n# Find the 'else:' and then the 'else:' for dummies.\n# This is getting confusing. Let's just rewrite the whole thing.\n\n# Let's use a cleaner approach.\nPY\n"
}
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
30run_command
{
 "command": "python3 - <<'PY'\nimport sys\nfrom pathlib import Path\n\np = Path(\"fastapi/_compat/v1.py\")\ns = p.read_text()\nlines = s.splitlines()\n\n# I'll just replace the a large chunk of the file to be sure.\n# From 'if not PYDANTIC_V2:' until 'GetJsonSchemaHandler = Any'\n\n# Let's find the indices.\nstart_idx = -1\nend_idx = -1\nfor i, line in enumerate(lines):\n    if line.strip() == \"if not PYDANTIC_V2:\":\n        start_idx = i\n    if \"GetJsonSchemaHandler = Any\" in line:\n        end_idx = i\n        break\n\nif start_idx != -1 and end_idx != -1:\n    # Reconstruct the block.\n    # I will use the symbols from my list.\n    symbols = [\n        \"BaseConfig\", \"BaseModel\", \"ValidationError\", \"create_model\", \"Validator\",\n        \"Color\", \"ErrorWrapper\", \"MissingError\", \"SHAPE_FROZENSET\", \"SHAPE_LIST\",\n        \"SHAPE_SEQUENCE\", \"SHAPE_SET\", \"SHAPE_SINGLETON\", \"SHAPE_TUPLE\",\n        \"SHAPE_TUPLE_ELLIPSIS\", \"FieldInfo\", \"ModelField\", \"Undefined\", \"UndefinedType\",\n        \"AnyUrl\", \"NameEmail\", \"TypeModelSet\", \"field_schema\", \"get_flat_models_from_fields\",\n        \"model_process_schema\", \"get_annotation_from_field_info\", \"get_flat_models_from_field\",\n        \"get_model_name_map\", \"SecretBytes\", \"SecretStr\", \"evaluate_forwardref\", \"lenient_issubclass\"\n    ]\n    \n    # We need to preserve the original imports for both branches.\n    # Let's just extract the imports from the original file.\n    \n    # Find original imports for 'if not PYDANTIC_V2'\n    if_imports = []\n    else_imports = []\n    \n    current_block = None\n    for i in range(start_idx + 1, end_idx):\n        line = lines[i]\n        if line.strip() == \"else:\":\n            current_block = \"else\"\n            continue\n        if line.strip() == \"if not PYDANTIC_V2:\":\n            current_block = \"if\"\n            continue\n        \n        if current_block == \"if\" and line.strip():\n            if_imports.append(line)\n        elif current_block == \"else\" and line.strip():\n            # Avoid the dummy block we added previously.\n            if \"if not USE_DUMMIES:\" in line or \"else:\" in line or \": Any = None\" in line:\n                continue\n            else_imports.append(line)\n            \n    # This is still a bit messy.\n    # Let's just use the original file's content for the imports.\nPY\n"
}
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}
full
{"status": "ok", "stdout": "", "stderr": "", "exit_code": 0}

Patch

diff --git a/fastapi/_compat/v1.py b/fastapi/_compat/v1.py
index f0ac5163..3307e072 100644
--- a/fastapi/_compat/v1.py
+++ b/fastapi/_compat/v1.py
@@ -21,6 +21,12 @@ from typing_extensions import Literal
 
 PYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(".")[:2])
 PYDANTIC_V2 = PYDANTIC_VERSION_MINOR_TUPLE[0] == 2
+
+# Prevent importing pydantic.v1 on Python 3.14+ and Pydantic 2.12+ to avoid warnings
+# from Pydantic.
+USE_DUMMIES = (
+    sys.version_info >= (3, 14) and PYDANTIC_VERSION_MINOR_TUPLE >= (2, 12)
+)
 # Keeping old "Required" functionality from Pydantic V1, without
 # shadowing typing.Required.
 RequiredParam: Any = Ellipsis
@@ -69,56 +75,90 @@ if not PYDANTIC_V2:
 
 
 else:
-    from pydantic.v1 import BaseConfig as BaseConfig  # type: ignore[assignment]
-    from pydantic.v1 import BaseModel as BaseModel  # type: ignore[assignment]
-    from pydantic.v1 import (  # type: ignore[assignment]
-        ValidationError as ValidationError,
-    )
-    from pydantic.v1 import create_model as create_model  # type: ignore[no-redef]
-    from pydantic.v1.class_validators import Validator as Validator
-    from pydantic.v1.color import Color as Color  # type: ignore[assignment]
-    from pydantic.v1.error_wrappers import ErrorWrapper as ErrorWrapper
-    from pydantic.v1.errors import MissingError
-    from pydantic.v1.fields import (
-        SHAPE_FROZENSET,
-        SHAPE_LIST,
-        SHAPE_SEQUENCE,
-        SHAPE_SET,
-        SHAPE_SINGLETON,
-        SHAPE_TUPLE,
-        SHAPE_TUPLE_ELLIPSIS,
-    )
-    from pydantic.v1.fields import FieldInfo as FieldInfo  # type: ignore[assignment]
-    from pydantic.v1.fields import ModelField as ModelField
-    from pydantic.v1.fields import Undefined as Undefined
-    from pydantic.v1.fields import UndefinedType as UndefinedType
-    from pydantic.v1.networks import AnyUrl as AnyUrl
-    from pydantic.v1.networks import (  # type: ignore[assignment]
-        NameEmail as NameEmail,
-    )
-    from pydantic.v1.schema import TypeModelSet as TypeModelSet
-    from pydantic.v1.schema import (
-        field_schema,
-        get_flat_models_from_fields,
-        model_process_schema,
-    )
-    from pydantic.v1.schema import (
-        get_annotation_from_field_info as get_annotation_from_field_info,
-    )
-    from pydantic.v1.schema import (
-        get_flat_models_from_field as get_flat_models_from_field,
-    )
-    from pydantic.v1.schema import get_model_name_map as get_model_name_map
-    from pydantic.v1.types import (  # type: ignore[assignment]
-        SecretBytes as SecretBytes,
-    )
-    from pydantic.v1.types import (  # type: ignore[assignment]
-        SecretStr as SecretStr,
-    )
-    from pydantic.v1.typing import evaluate_forwardref as evaluate_forwardref
-    from pydantic.v1.utils import lenient_issubclass as lenient_issubclass
-
-
+    if not USE_DUMMIES:
+        from pydantic.v1 import BaseConfig as BaseConfig  # type: ignore[assignment]
+        from pydantic.v1 import BaseModel as BaseModel  # type: ignore[assignment]
+        from pydantic.v1 import (  # type: ignore[assignment]
+            ValidationError as ValidationError,
+        )
+        from pydantic.v1 import create_model as create_model  # type: ignore[no-redef]
+        from pydantic.v1.class_validators import Validator as Validator
+        from pydantic.v1.color import Color as Color  # type: ignore[assignment]
+        from pydantic.v1.error_wrappers import ErrorWrapper as ErrorWrapper
+        from pydantic.v1.errors import MissingError
+        from pydantic.v1.fields import (
+            SHAPE_FROZENSET,
+            SHAPE_LIST,
+            SHAPE_SEQUENCE,
+            SHAPE_SET,
+            SHAPE_SINGLETON,
+            SHAPE_TUPLE,
+            SHAPE_TUPLE_ELLIPSIS,
+        )
+        from pydantic.v1.fields import FieldInfo as FieldInfo  # type: ignore[assignment]
+        from pydantic.v1.fields import ModelField as ModelField
+        from pydantic.v1.fields import Undefined as Undefined
+        from pydantic.v1.fields import UndefinedType as UndefinedType
+        from pydantic.v1.networks import AnyUrl as AnyUrl
+        from pydantic.v1.networks import (  # type: ignore[assignment]
+            NameEmail as NameEmail,
+        )
+        from pydantic.v1.schema import TypeModelSet as TypeModelSet
+        from pydantic.v1.schema import (
+            field_schema,
+            get_flat_models_from_fields,
+            model_process_schema,
+        )
+        from pydantic.v1.schema import (
+            get_annotation_from_field_info as get_annotation_from_field_info,
+        )
+        from pydantic.v1.schema import (
+            get_flat_models_from_field as get_flat_models_from_field,
+        )
+        from pydantic.v1.schema import get_model_name_map as get_model_name_map
+        from pydantic.v1.types import (  # type: ignore[assignment]
+            SecretBytes as SecretBytes,
+        )
+        from pydantic.v1.types import (  # type: ignore[assignment]
+            SecretStr as SecretStr,
+        )
+        from pydantic.v1.typing import evaluate_forwardref as evaluate_forwardref
+        from pydantic.v1.utils import lenient_issubclass as lenient_issubclass
+    
+    
+    else:
+        BaseConfig: Any = None
+        BaseModel: Any = None
+        ValidationError: Any = None
+        create_model: Any = None
+        Validator: Any = None
+        Color: Any = None
+        ErrorWrapper: Any = None
+        MissingError: Any = None
+        SHAPE_FROZENSET: Any = None
+        SHAPE_LIST: Any = None
+        SHAPE_SEQUENCE: Any = None
+        SHAPE_SET: Any = None
+        SHAPE_SINGLETON: Any = None
+        SHAPE_TUPLE: Any = None
+        SHAPE_TUPLE_ELLIPSIS: Any = None
+        FieldInfo: Any = None
+        ModelField: Any = None
+        Undefined: Any = None
+        UndefinedType: Any = None
+        AnyUrl: Any = None
+        NameEmail: Any = None
+        TypeModelSet: Any = None
+        field_schema: Any = None
+        get_flat_models_from_fields: Any = None
+        model_process_schema: Any = None
+        get_annotation_from_field_info: Any = None
+        get_flat_models_from_field: Any = None
+        get_model_name_map: Any = None
+        SecretBytes: Any = None
+        SecretStr: Any = None
+        evaluate_forwardref: Any = None
+        lenient_issubclass: Any = None
 GetJsonSchemaHandler = Any
 JsonSchemaValue = Dict[str, Any]
 CoreSchema = Any
@@ -331,4 +371,4 @@ def create_body_model(
 
 
 def get_model_fields(model: Type[BaseModel]) -> List[ModelField]:
-    return list(model.__fields__.values())  # type: ignore[attr-defined]
+    return list(model.__fields__.values())  # type: ignore[attr-defined]
\ No newline at end of file

Test output

show
==================================== ERRORS ====================================
____________________ ERROR collecting tests/test_compat.py _____________________
tests/test_compat.py:3: in <module>
    from fastapi import FastAPI, UploadFile
fastapi/__init__.py:7: in <module>
    from .applications import FastAPI as FastAPI
fastapi/applications.py:16: in <module>
    from fastapi import routing
fastapi/routing.py:27: in <module>
    from fastapi import params, temp_pydantic_v1_params
fastapi/params.py:5: in <module>
    from fastapi.openapi.models import Example
fastapi/openapi/models.py:4: in <module>
    from fastapi._compat import (
fastapi/_compat/__init__.py:1: in <module>
    from .main import BaseConfig as BaseConfig
fastapi/_compat/main.py:11: in <module>
    from fastapi._compat import v1
fastapi/_compat/v1.py:28: in <module>
    sys.version_info >= (3, 14) and PYDANTIC_VERSION_MINOR_TUPLE >= (2, 12)
    ^^^
E   NameError: name 'sys' is not defined. Did you forget to import 'sys'?
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 error in 0.18s