]> git.ipfire.org Git - thirdparty/fastapi/fastapi.git/commitdiff
♻️ Refactor internals, cleanup unneeded Pydantic v1 specific logic (#14856)
authorSebastián Ramírez <tiangolo@gmail.com>
Fri, 6 Feb 2026 18:01:05 +0000 (10:01 -0800)
committerGitHub <noreply@github.com>
Fri, 6 Feb 2026 18:01:05 +0000 (19:01 +0100)
fastapi/_compat/__init__.py
fastapi/_compat/shared.py
fastapi/_compat/v2.py
fastapi/routing.py
fastapi/utils.py

index 3dfaf9b7121a086377cb29123ad7da8cbd1bc1a8..b7701bd1a1e2c22f18041b0cc18e73cad59a7542 100644 (file)
@@ -1,4 +1,3 @@
-from .shared import PYDANTIC_V2 as PYDANTIC_V2
 from .shared import PYDANTIC_VERSION_MINOR_TUPLE as PYDANTIC_VERSION_MINOR_TUPLE
 from .shared import annotation_is_pydantic_v1 as annotation_is_pydantic_v1
 from .shared import field_annotation_is_scalar as field_annotation_is_scalar
index 68b9bbdf1e954f8ff2fdead9bbc46264133a988a..fdda481b86fbd1a5b6b7c8fef3b5cf6c4645d4c6 100644 (file)
@@ -28,7 +28,6 @@ else:
     )  # pyright: ignore[reportAttributeAccessIssue]
 
 PYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(".")[:2])
-PYDANTIC_V2 = PYDANTIC_VERSION_MINOR_TUPLE[0] == 2
 
 
 sequence_annotation_to_type = {
index dae78a32e0ceb9c0bccdb3e288a8c783e34ab5cf..6c2eec58b52440ed7310173e06467eab9fa448e0 100644 (file)
@@ -500,14 +500,8 @@ def get_model_name_map(unique_models: TypeModelSet) -> dict[TypeModelOrEnum, str
 
 
 def get_compat_model_name_map(fields: list[ModelField]) -> ModelNameMap:
-    all_flat_models: TypeModelSet = set()
-
-    v2_model_fields = [field for field in fields if isinstance(field, ModelField)]
-    v2_flat_models = get_flat_models_from_fields(v2_model_fields, known_models=set())
-    all_flat_models = all_flat_models.union(v2_flat_models)
-
-    model_name_map = get_model_name_map(all_flat_models)
-    return model_name_map
+    flat_models = get_flat_models_from_fields(fields, known_models=set())
+    return get_model_name_map(flat_models)
 
 
 def get_flat_models_from_model(
index c95f624bdfea8d2d6ef3b8aa1ce09e429a1c0f3e..b8d1f76248b6f0026714a300af4e0dbb2cde1fb2 100644 (file)
@@ -59,7 +59,6 @@ from fastapi.exceptions import (
 )
 from fastapi.types import DecoratedCallable, IncEx
 from fastapi.utils import (
-    create_cloned_field,
     create_model_field,
     generate_unique_id,
     get_value_or_default,
@@ -652,20 +651,8 @@ class APIRoute(routing.Route):
                 type_=self.response_model,
                 mode="serialization",
             )
-            # Create a clone of the field, so that a Pydantic submodel is not returned
-            # as is just because it's an instance of a subclass of a more limited class
-            # e.g. UserInDB (containing hashed_password) could be a subclass of User
-            # that doesn't have the hashed_password. But because it's a subclass, it
-            # would pass the validation and be returned as is.
-            # By being a new field, no inheritance will be passed as is. A new model
-            # will always be created.
-            # TODO: remove when deprecating Pydantic v1
-            self.secure_cloned_response_field: Optional[ModelField] = (
-                create_cloned_field(self.response_field)
-            )
         else:
             self.response_field = None  # type: ignore
-            self.secure_cloned_response_field = None
         self.dependencies = list(dependencies or [])
         self.description = description or inspect.cleandoc(self.endpoint.__doc__ or "")
         # if a "form feed" character (page break) is found in the description text,
@@ -720,7 +707,7 @@ class APIRoute(routing.Route):
             body_field=self.body_field,
             status_code=self.status_code,
             response_class=self.response_class,
-            response_field=self.secure_cloned_response_field,
+            response_field=self.response_field,
             response_model_include=self.response_model_include,
             response_model_exclude=self.response_model_exclude,
             response_model_by_alias=self.response_model_by_alias,
index 1c3a0881f7d0e202828cf4b30d649e57de0ecdcb..da11fe2c77b8ca78a7ec086821bbdb5ea8a94a92 100644 (file)
@@ -1,13 +1,11 @@
 import re
 import warnings
-from collections.abc import MutableMapping
 from typing import (
     TYPE_CHECKING,
     Any,
     Optional,
     Union,
 )
-from weakref import WeakKeyDictionary
 
 import fastapi
 from fastapi._compat import (
@@ -21,7 +19,6 @@ from fastapi._compat import (
 )
 from fastapi.datastructures import DefaultPlaceholder, DefaultType
 from fastapi.exceptions import FastAPIDeprecationWarning, PydanticV1NotSupportedError
-from pydantic import BaseModel
 from pydantic.fields import FieldInfo
 from typing_extensions import Literal
 
@@ -30,11 +27,6 @@ from ._compat import v2
 if TYPE_CHECKING:  # pragma: nocover
     from .routing import APIRoute
 
-# Cache for `create_cloned_field`
-_CLONED_TYPES_CACHE: MutableMapping[type[BaseModel], type[BaseModel]] = (
-    WeakKeyDictionary()
-)
-
 
 def is_body_allowed_for_status_code(status_code: Union[int, str, None]) -> bool:
     if status_code is None:
@@ -97,14 +89,6 @@ def create_model_field(
         ) from None
 
 
-def create_cloned_field(
-    field: ModelField,
-    *,
-    cloned_types: Optional[MutableMapping[type[BaseModel], type[BaseModel]]] = None,
-) -> ModelField:
-    return field
-
-
 def generate_operation_id_for_path(
     *, name: str, path: str, method: str
 ) -> str:  # pragma: nocover