From aeb2d20ade4f577af8a431b5b2ee9b9868ddb104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 7 Feb 2026 09:28:43 +0100 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor=20and=20simplify?= =?UTF-8?q?=20function=20indirection=20through=20utils?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastapi/_compat/__init__.py | 12 ++++++++---- fastapi/_compat/v2.py | 16 ---------------- fastapi/dependencies/utils.py | 21 ++++++++++++--------- 3 files changed, 20 insertions(+), 29 deletions(-) diff --git a/fastapi/_compat/__init__.py b/fastapi/_compat/__init__.py index 62681696ed..4581c38c88 100644 --- a/fastapi/_compat/__init__.py +++ b/fastapi/_compat/__init__.py @@ -1,6 +1,14 @@ 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 +from .shared import ( + field_annotation_is_scalar_sequence as field_annotation_is_scalar_sequence, +) +from .shared import field_annotation_is_sequence as field_annotation_is_sequence +from .shared import ( + is_bytes_or_nonable_bytes_annotation as is_bytes_or_nonable_bytes_annotation, +) +from .shared import is_bytes_sequence_annotation as is_bytes_sequence_annotation from .shared import is_pydantic_v1_model_instance as is_pydantic_v1_model_instance from .shared import ( is_uploadfile_or_nonable_uploadfile_annotation as is_uploadfile_or_nonable_uploadfile_annotation, @@ -25,11 +33,7 @@ from .v2 import get_flat_models_from_fields as get_flat_models_from_fields from .v2 import get_missing_field_error as get_missing_field_error from .v2 import get_model_name_map as get_model_name_map from .v2 import get_schema_from_model_field as get_schema_from_model_field -from .v2 import is_bytes_field as is_bytes_field -from .v2 import is_bytes_sequence_field as is_bytes_sequence_field from .v2 import is_scalar_field as is_scalar_field -from .v2 import is_scalar_sequence_field as is_scalar_sequence_field -from .v2 import is_sequence_field as is_sequence_field from .v2 import serialize_sequence_value as serialize_sequence_value from .v2 import ( with_info_plain_validator_function as with_info_plain_validator_function, diff --git a/fastapi/_compat/v2.py b/fastapi/_compat/v2.py index cd0481eff4..87b9fb47fa 100644 --- a/fastapi/_compat/v2.py +++ b/fastapi/_compat/v2.py @@ -296,22 +296,6 @@ def is_scalar_field(field: ModelField) -> bool: ) and not isinstance(field.field_info, params.Body) -def is_sequence_field(field: ModelField) -> bool: - return shared.field_annotation_is_sequence(field.field_info.annotation) - - -def is_scalar_sequence_field(field: ModelField) -> bool: - return shared.field_annotation_is_scalar_sequence(field.field_info.annotation) - - -def is_bytes_field(field: ModelField) -> bool: - return shared.is_bytes_or_nonable_bytes_annotation(field.field_info.annotation) - - -def is_bytes_sequence_field(field: ModelField) -> bool: - return shared.is_bytes_sequence_annotation(field.field_info.annotation) - - def copy_field_info(*, field_info: FieldInfo, annotation: Any) -> FieldInfo: cls = type(field_info) merged_field_info = cls.from_annotation(annotation) diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py index b84bbf863d..80f9c76e90 100644 --- a/fastapi/dependencies/utils.py +++ b/fastapi/dependencies/utils.py @@ -25,13 +25,13 @@ from fastapi._compat import ( create_body_model, evaluate_forwardref, field_annotation_is_scalar, + field_annotation_is_scalar_sequence, + field_annotation_is_sequence, get_cached_model_fields, get_missing_field_error, - is_bytes_field, - is_bytes_sequence_field, + is_bytes_or_nonable_bytes_annotation, + is_bytes_sequence_annotation, is_scalar_field, - is_scalar_sequence_field, - is_sequence_field, is_uploadfile_or_nonable_uploadfile_annotation, is_uploadfile_sequence_annotation, lenient_issubclass, @@ -523,7 +523,7 @@ def analyze_param( elif isinstance(field_info, params.Query): assert ( is_scalar_field(field) - or is_scalar_sequence_field(field) + or field_annotation_is_scalar_sequence(field.field_info.annotation) or lenient_issubclass(field.field_info.annotation, BaseModel) ), f"Query parameter {param_name!r} must be one of the supported types" @@ -727,7 +727,7 @@ def _get_multidict_value( alias = alias or get_validation_alias(field) if ( (not _is_json_field(field)) - and is_sequence_field(field) + and field_annotation_is_sequence(field.field_info.annotation) and isinstance(values, (ImmutableMultiDict, Headers)) ): value = values.getlist(alias) @@ -740,7 +740,10 @@ def _get_multidict_value( and isinstance(value, str) # For type checks and value == "" ) - or (is_sequence_field(field) and len(value) == 0) + or ( + field_annotation_is_sequence(field.field_info.annotation) + and len(value) == 0 + ) ): if field.field_info.is_required(): return @@ -888,12 +891,12 @@ async def _extract_form_body( field_info = field.field_info if ( isinstance(field_info, params.File) - and is_bytes_field(field) + and is_bytes_or_nonable_bytes_annotation(field.field_info.annotation) and isinstance(value, UploadFile) ): value = await value.read() elif ( - is_bytes_sequence_field(field) + is_bytes_sequence_annotation(field.field_info.annotation) and isinstance(field_info, params.File) and value_is_sequence(value) ):