]> git.ipfire.org Git - thirdparty/fastapi/fastapi.git/commitdiff
👽️ Ensure compatibility with Pydantic 2.12.0 (#14036)
authorColin Watson <cjwatson@debian.org>
Wed, 8 Oct 2025 08:57:37 +0000 (09:57 +0100)
committerGitHub <noreply@github.com>
Wed, 8 Oct 2025 08:57:37 +0000 (10:57 +0200)
Co-authored-by: Sofie Van Landeghem <svlandeg@users.noreply.github.com>
Co-authored-by: Victorien <65306057+Viicos@users.noreply.github.com>
Co-authored-by: svlandeg <svlandeg@github.com>
Co-authored-by: Motov Yurii <109919500+YuriiMotov@users.noreply.github.com>
Co-authored-by: Patrick Arminio <patrick.arminio@gmail.com>
fastapi/_compat.py
fastapi/params.py
tests/test_multi_body_errors.py

index 26b6638c8d1c8849ff34e4838232f2f13b5bcf78..8ea5bf2535f88967b9c2347578f762323423e786 100644 (file)
@@ -1,3 +1,4 @@
+import warnings
 from collections import deque
 from copy import copy
 from dataclasses import dataclass, is_dataclass
@@ -109,9 +110,20 @@ if PYDANTIC_V2:
             return self.field_info.annotation
 
         def __post_init__(self) -> None:
-            self._type_adapter: TypeAdapter[Any] = TypeAdapter(
-                Annotated[self.field_info.annotation, self.field_info]
-            )
+            with warnings.catch_warnings():
+                # Pydantic >= 2.12.0 warns about field specific metadata that is unused
+                # (e.g. `TypeAdapter(Annotated[int, Field(alias='b')])`). In some cases, we
+                # end up building the type adapter from a model field annotation so we
+                # need to ignore the warning:
+                if PYDANTIC_VERSION_MINOR_TUPLE >= (2, 12):
+                    from pydantic.warnings import UnsupportedFieldAttributeWarning
+
+                    warnings.simplefilter(
+                        "ignore", category=UnsupportedFieldAttributeWarning
+                    )
+                self._type_adapter: TypeAdapter[Any] = TypeAdapter(
+                    Annotated[self.field_info.annotation, self.field_info]
+                )
 
         def get_default(self) -> Any:
             if self.field_info.is_required():
index 8f5601dd31e53804bb3c4de6e577d8612b79bcb1..e853750188f961f8d45fe57d026883b90ba5cff5 100644 (file)
@@ -22,7 +22,7 @@ class ParamTypes(Enum):
     cookie = "cookie"
 
 
-class Param(FieldInfo):
+class Param(FieldInfo):  # type: ignore[misc]
     in_: ParamTypes
 
     def __init__(
@@ -136,7 +136,7 @@ class Param(FieldInfo):
         return f"{self.__class__.__name__}({self.default})"
 
 
-class Path(Param):
+class Path(Param):  # type: ignore[misc]
     in_ = ParamTypes.path
 
     def __init__(
@@ -222,7 +222,7 @@ class Path(Param):
         )
 
 
-class Query(Param):
+class Query(Param):  # type: ignore[misc]
     in_ = ParamTypes.query
 
     def __init__(
@@ -306,7 +306,7 @@ class Query(Param):
         )
 
 
-class Header(Param):
+class Header(Param):  # type: ignore[misc]
     in_ = ParamTypes.header
 
     def __init__(
@@ -392,7 +392,7 @@ class Header(Param):
         )
 
 
-class Cookie(Param):
+class Cookie(Param):  # type: ignore[misc]
     in_ = ParamTypes.cookie
 
     def __init__(
@@ -476,7 +476,7 @@ class Cookie(Param):
         )
 
 
-class Body(FieldInfo):
+class Body(FieldInfo):  # type: ignore[misc]
     def __init__(
         self,
         default: Any = Undefined,
@@ -593,7 +593,7 @@ class Body(FieldInfo):
         return f"{self.__class__.__name__}({self.default})"
 
 
-class Form(Body):
+class Form(Body):  # type: ignore[misc]
     def __init__(
         self,
         default: Any = Undefined,
@@ -677,7 +677,7 @@ class Form(Body):
         )
 
 
-class File(Form):
+class File(Form):  # type: ignore[misc]
     def __init__(
         self,
         default: Any = Undefined,
index 0102f0f1a08452cd1c96c177f4c70a74524a710c..33304827a97f161b000ea78b6eb6c102862a4d4d 100644 (file)
@@ -185,7 +185,15 @@ def test_openapi_schema():
                                 "title": "Age",
                                 "anyOf": [
                                     {"exclusiveMinimum": 0.0, "type": "number"},
-                                    {"type": "string"},
+                                    IsOneOf(
+                                        # pydantic < 2.12.0
+                                        {"type": "string"},
+                                        # pydantic >= 2.12.0
+                                        {
+                                            "type": "string",
+                                            "pattern": r"^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$",
+                                        },
+                                    ),
                                 ],
                             }
                         )