Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
9f1f985
dummy edit
svlandeg Oct 14, 2025
eb43072
introduce may_v1 to introduce dummies for Python 3.14
svlandeg Oct 14, 2025
17084fe
🎨 [pre-commit.ci] Auto format from pre-commit.com hooks
pre-commit-ci[bot] Oct 14, 2025
90bd568
formatting
svlandeg Oct 14, 2025
2203a15
Merge branch 'fix/ci' of https://github.com/svlandeg/fastapi into fix/ci
svlandeg Oct 14, 2025
08bcb10
fix
svlandeg Oct 14, 2025
4e6a59b
add back definitions that got accidentally removed
svlandeg Oct 14, 2025
b8c0bac
remove unused ignore statement
svlandeg Oct 14, 2025
f324375
🎨 [pre-commit.ci] Auto format from pre-commit.com hooks
pre-commit-ci[bot] Oct 14, 2025
6afe57f
remove unused ignores
svlandeg Oct 14, 2025
9de6659
remove some more unused ignores
svlandeg Oct 14, 2025
4117120
🎨 [pre-commit.ci] Auto format from pre-commit.com hooks
pre-commit-ci[bot] Oct 14, 2025
ff0b26f
one more unused ignores
svlandeg Oct 14, 2025
2e0e997
Merge branch 'fix/ci' of https://github.com/svlandeg/fastapi into fix/ci
svlandeg Oct 14, 2025
b7d4d4c
🎨 [pre-commit.ci] Auto format from pre-commit.com hooks
pre-commit-ci[bot] Oct 14, 2025
1db6afc
fix definition of get_flat_models_from_fields in v1.py
svlandeg Oct 14, 2025
3474d3b
🎨 [pre-commit.ci] Auto format from pre-commit.com hooks
pre-commit-ci[bot] Oct 14, 2025
d6c6000
revert dummy edit
svlandeg Oct 14, 2025
8af2e34
Merge remote-tracking branch 'origin/fix/ci' into fix/ci
svlandeg Oct 14, 2025
bdbd90c
fix functions
svlandeg Oct 15, 2025
ed1728a
🎨 [pre-commit.ci] Auto format from pre-commit.com hooks
pre-commit-ci[bot] Oct 15, 2025
7cb78ce
fix ValidationError import
svlandeg Oct 15, 2025
d77cb57
add no cover statement
svlandeg Oct 15, 2025
4fbd78b
♻️ Tweak empty list check
tiangolo Oct 20, 2025
af21a3b
Merge branch 'master' into fix/ci
tiangolo Oct 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions fastapi/_compat/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
from .main import (
with_info_plain_validator_function as with_info_plain_validator_function,
)
from .may_v1 import CoreSchema as CoreSchema
from .may_v1 import GetJsonSchemaHandler as GetJsonSchemaHandler
from .may_v1 import JsonSchemaValue as JsonSchemaValue
from .may_v1 import _normalize_errors as _normalize_errors
from .model_field import ModelField as ModelField
from .shared import PYDANTIC_V2 as PYDANTIC_V2
from .shared import PYDANTIC_VERSION_MINOR_TUPLE as PYDANTIC_VERSION_MINOR_TUPLE
Expand All @@ -44,7 +48,3 @@
from .shared import lenient_issubclass as lenient_issubclass
from .shared import sequence_types as sequence_types
from .shared import value_is_sequence as value_is_sequence
from .v1 import CoreSchema as CoreSchema
from .v1 import GetJsonSchemaHandler as GetJsonSchemaHandler
from .v1 import JsonSchemaValue as JsonSchemaValue
from .v1 import _normalize_errors as _normalize_errors
127 changes: 92 additions & 35 deletions fastapi/_compat/main.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import sys
from functools import lru_cache
from typing import (
Any,
Expand All @@ -8,7 +9,7 @@
Type,
)

from fastapi._compat import v1
from fastapi._compat import may_v1
from fastapi._compat.shared import PYDANTIC_V2, lenient_issubclass
from fastapi.types import ModelNameMap
from pydantic import BaseModel
Expand Down Expand Up @@ -50,7 +51,9 @@

@lru_cache
def get_cached_model_fields(model: Type[BaseModel]) -> List[ModelField]:
if lenient_issubclass(model, v1.BaseModel):
if lenient_issubclass(model, may_v1.BaseModel):
from fastapi._compat import v1

return v1.get_model_fields(model)
else:
from . import v2
Expand All @@ -59,7 +62,7 @@ def get_cached_model_fields(model: Type[BaseModel]) -> List[ModelField]:


def _is_undefined(value: object) -> bool:
if isinstance(value, v1.UndefinedType):
if isinstance(value, may_v1.UndefinedType):
return True
elif PYDANTIC_V2:
from . import v2
Expand All @@ -69,7 +72,9 @@ def _is_undefined(value: object) -> bool:


def _get_model_config(model: BaseModel) -> Any:
if isinstance(model, v1.BaseModel):
if isinstance(model, may_v1.BaseModel):
from fastapi._compat import v1

return v1._get_model_config(model)
elif PYDANTIC_V2:
from . import v2
Expand All @@ -80,7 +85,9 @@ def _get_model_config(model: BaseModel) -> Any:
def _model_dump(
model: BaseModel, mode: Literal["json", "python"] = "json", **kwargs: Any
) -> Any:
if isinstance(model, v1.BaseModel):
if isinstance(model, may_v1.BaseModel):
from fastapi._compat import v1

return v1._model_dump(model, mode=mode, **kwargs)
elif PYDANTIC_V2:
from . import v2
Expand All @@ -89,7 +96,7 @@ def _model_dump(


def _is_error_wrapper(exc: Exception) -> bool:
if isinstance(exc, v1.ErrorWrapper):
if isinstance(exc, may_v1.ErrorWrapper):
return True
elif PYDANTIC_V2:
from . import v2
Expand All @@ -99,7 +106,9 @@ def _is_error_wrapper(exc: Exception) -> bool:


def copy_field_info(*, field_info: FieldInfo, annotation: Any) -> FieldInfo:
if isinstance(field_info, v1.FieldInfo):
if isinstance(field_info, may_v1.FieldInfo):
from fastapi._compat import v1

return v1.copy_field_info(field_info=field_info, annotation=annotation)
else:
assert PYDANTIC_V2
Expand All @@ -111,7 +120,9 @@ def copy_field_info(*, field_info: FieldInfo, annotation: Any) -> FieldInfo:
def create_body_model(
*, fields: Sequence[ModelField], model_name: str
) -> Type[BaseModel]:
if fields and isinstance(fields[0], v1.ModelField):
if fields and isinstance(fields[0], may_v1.ModelField):
from fastapi._compat import v1

return v1.create_body_model(fields=fields, model_name=model_name)
else:
assert PYDANTIC_V2
Expand All @@ -123,7 +134,9 @@ def create_body_model(
def get_annotation_from_field_info(
annotation: Any, field_info: FieldInfo, field_name: str
) -> Any:
if isinstance(field_info, v1.FieldInfo):
if isinstance(field_info, may_v1.FieldInfo):
from fastapi._compat import v1

return v1.get_annotation_from_field_info(
annotation=annotation, field_info=field_info, field_name=field_name
)
Expand All @@ -137,7 +150,9 @@ def get_annotation_from_field_info(


def is_bytes_field(field: ModelField) -> bool:
if isinstance(field, v1.ModelField):
if isinstance(field, may_v1.ModelField):
from fastapi._compat import v1

return v1.is_bytes_field(field)
else:
assert PYDANTIC_V2
Expand All @@ -147,7 +162,9 @@ def is_bytes_field(field: ModelField) -> bool:


def is_bytes_sequence_field(field: ModelField) -> bool:
if isinstance(field, v1.ModelField):
if isinstance(field, may_v1.ModelField):
from fastapi._compat import v1

return v1.is_bytes_sequence_field(field)
else:
assert PYDANTIC_V2
Expand All @@ -157,7 +174,9 @@ def is_bytes_sequence_field(field: ModelField) -> bool:


def is_scalar_field(field: ModelField) -> bool:
if isinstance(field, v1.ModelField):
if isinstance(field, may_v1.ModelField):
from fastapi._compat import v1

return v1.is_scalar_field(field)
else:
assert PYDANTIC_V2
Expand All @@ -167,7 +186,9 @@ def is_scalar_field(field: ModelField) -> bool:


def is_scalar_sequence_field(field: ModelField) -> bool:
if isinstance(field, v1.ModelField):
if isinstance(field, may_v1.ModelField):
from fastapi._compat import v1

return v1.is_scalar_sequence_field(field)
else:
assert PYDANTIC_V2
Expand All @@ -177,7 +198,9 @@ def is_scalar_sequence_field(field: ModelField) -> bool:


def is_sequence_field(field: ModelField) -> bool:
if isinstance(field, v1.ModelField):
if isinstance(field, may_v1.ModelField):
from fastapi._compat import v1

return v1.is_sequence_field(field)
else:
assert PYDANTIC_V2
Expand All @@ -187,7 +210,9 @@ def is_sequence_field(field: ModelField) -> bool:


def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]:
if isinstance(field, v1.ModelField):
if isinstance(field, may_v1.ModelField):
from fastapi._compat import v1

return v1.serialize_sequence_value(field=field, value=value)
else:
assert PYDANTIC_V2
Expand All @@ -197,7 +222,9 @@ def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]:


def _model_rebuild(model: Type[BaseModel]) -> None:
if lenient_issubclass(model, v1.BaseModel):
if lenient_issubclass(model, may_v1.BaseModel):
from fastapi._compat import v1

v1._model_rebuild(model)
elif PYDANTIC_V2:
from . import v2
Expand All @@ -206,9 +233,18 @@ def _model_rebuild(model: Type[BaseModel]) -> None:


def get_compat_model_name_map(fields: List[ModelField]) -> ModelNameMap:
v1_model_fields = [field for field in fields if isinstance(field, v1.ModelField)]
v1_flat_models = v1.get_flat_models_from_fields(v1_model_fields, known_models=set()) # type: ignore[attr-defined]
all_flat_models = v1_flat_models
v1_model_fields = [
field for field in fields if isinstance(field, may_v1.ModelField)
]
if v1_model_fields:
from fastapi._compat import v1

v1_flat_models = v1.get_flat_models_from_fields(
v1_model_fields, known_models=set()
)
all_flat_models = v1_flat_models
else:
all_flat_models = set()
if PYDANTIC_V2:
from . import v2

Expand All @@ -222,6 +258,8 @@ def get_compat_model_name_map(fields: List[ModelField]) -> ModelNameMap:

model_name_map = v2.get_model_name_map(all_flat_models)
return model_name_map
from fastapi._compat import v1

model_name_map = v1.get_model_name_map(all_flat_models)
return model_name_map

Expand All @@ -232,17 +270,35 @@ def get_definitions(
model_name_map: ModelNameMap,
separate_input_output_schemas: bool = True,
) -> Tuple[
Dict[Tuple[ModelField, Literal["validation", "serialization"]], v1.JsonSchemaValue],
Dict[
Tuple[ModelField, Literal["validation", "serialization"]],
may_v1.JsonSchemaValue,
],
Dict[str, Dict[str, Any]],
]:
v1_fields = [field for field in fields if isinstance(field, v1.ModelField)]
v1_field_maps, v1_definitions = v1.get_definitions(
fields=v1_fields,
model_name_map=model_name_map,
separate_input_output_schemas=separate_input_output_schemas,
)
if not PYDANTIC_V2:
return v1_field_maps, v1_definitions
if sys.version_info < (3, 14):
v1_fields = [field for field in fields if isinstance(field, may_v1.ModelField)]
v1_field_maps, v1_definitions = may_v1.get_definitions(
fields=v1_fields,
model_name_map=model_name_map,
separate_input_output_schemas=separate_input_output_schemas,
)
if not PYDANTIC_V2:
return v1_field_maps, v1_definitions
else:
from . import v2

v2_fields = [field for field in fields if isinstance(field, v2.ModelField)]
v2_field_maps, v2_definitions = v2.get_definitions(
fields=v2_fields,
model_name_map=model_name_map,
separate_input_output_schemas=separate_input_output_schemas,
)
all_definitions = {**v1_definitions, **v2_definitions}
all_field_maps = {**v1_field_maps, **v2_field_maps}
return all_field_maps, all_definitions

# Pydantic v1 is not supported since Python 3.14
else:
from . import v2

Expand All @@ -252,21 +308,22 @@ def get_definitions(
model_name_map=model_name_map,
separate_input_output_schemas=separate_input_output_schemas,
)
all_definitions = {**v1_definitions, **v2_definitions}
all_field_maps = {**v1_field_maps, **v2_field_maps}
return all_field_maps, all_definitions
return v2_field_maps, v2_definitions


def get_schema_from_model_field(
*,
field: ModelField,
model_name_map: ModelNameMap,
field_mapping: Dict[
Tuple[ModelField, Literal["validation", "serialization"]], v1.JsonSchemaValue
Tuple[ModelField, Literal["validation", "serialization"]],
may_v1.JsonSchemaValue,
],
separate_input_output_schemas: bool = True,
) -> Dict[str, Any]:
if isinstance(field, v1.ModelField):
if isinstance(field, may_v1.ModelField):
from fastapi._compat import v1

return v1.get_schema_from_model_field(
field=field,
model_name_map=model_name_map,
Expand All @@ -286,7 +343,7 @@ def get_schema_from_model_field(


def _is_model_field(value: Any) -> bool:
if isinstance(value, v1.ModelField):
if isinstance(value, may_v1.ModelField):
return True
elif PYDANTIC_V2:
from . import v2
Expand All @@ -296,7 +353,7 @@ def _is_model_field(value: Any) -> bool:


def _is_model_class(value: Any) -> bool:
if lenient_issubclass(value, v1.BaseModel):
if lenient_issubclass(value, may_v1.BaseModel):
return True
elif PYDANTIC_V2:
from . import v2
Expand Down
Loading