diff --git a/fastapi/_compat/shared.py b/fastapi/_compat/shared.py index 005ba67040..bfa5296dcb 100644 --- a/fastapi/_compat/shared.py +++ b/fastapi/_compat/shared.py @@ -21,7 +21,7 @@ from fastapi.types import UnionType from pydantic import BaseModel from pydantic.version import VERSION as PYDANTIC_VERSION from starlette.datastructures import UploadFile -from typing_extensions import get_args, get_origin +from typing_extensions import Annotated, get_args, get_origin # Copy from Pydantic v2, compatible with v1 if sys.version_info < (3, 10): @@ -103,6 +103,9 @@ def field_annotation_is_complex(annotation: Union[Type[Any], None]) -> bool: if origin is Union or origin is UnionType: return any(field_annotation_is_complex(arg) for arg in get_args(annotation)) + if origin is Annotated: + return field_annotation_is_complex(get_args(annotation)[0]) + return ( _annotation_is_complex(annotation) or _annotation_is_complex(origin) diff --git a/fastapi/_compat/v2.py b/fastapi/_compat/v2.py index eb5543fc99..8784d5afcd 100644 --- a/fastapi/_compat/v2.py +++ b/fastapi/_compat/v2.py @@ -1,4 +1,5 @@ import re +import warnings from copy import copy, deepcopy from dataclasses import dataclass from enum import Enum @@ -82,9 +83,20 @@ class ModelField: 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 shared.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():