Skip to content

Commit 70e8d3a

Browse files
yizzyyizzy
authored andcommitted
refactor: separate UploadFile→bytes conversion from normalization
- Created dedicated _convert_uploadfile_to_bytes() function for type conversion - Removed conversion logic from _normalize_field_value() to preserve its original intent - Updated both call sites to chain normalize → convert → validate - Added explanatory comment for __all__ in params.py to document public API intent Addresses reviewer feedback about separation of concerns between normalization (structural changes) and conversion (type transformations/IO operations).
1 parent ae84ca5 commit 70e8d3a

File tree

2 files changed

+35
-15
lines changed

2 files changed

+35
-15
lines changed

aws_lambda_powertools/event_handler/middlewares/openapi_validation.py

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,12 @@ def _request_body_to_args(
552552
_handle_missing_field_value(field, values, errors, loc)
553553
continue
554554

555+
# Normalize the field value (e.g., convert lists to single values)
555556
value = _normalize_field_value(value=value, field_info=field.field_info)
557+
558+
# Convert UploadFile to bytes if needed before validation
559+
value = _convert_uploadfile_to_bytes(value=value, field_info=field.field_info)
560+
556561
values[field.name] = _validate_field(field=field, value=value, loc=loc, existing_errors=errors)
557562

558563
return values, errors
@@ -595,23 +600,34 @@ def _handle_missing_field_value(
595600
values[field.name] = field.get_default()
596601

597602

598-
def _normalize_field_value(value: Any, field_info: FieldInfo) -> Any:
599-
"""Normalize field value, converting lists to single values for non-sequence fields."""
600-
# Convert UploadFile to bytes if the expected type is bytes
601-
if isinstance(value, UploadFile):
602-
# Check if the annotation is bytes
603-
annotation = field_info.annotation
604-
# Handle Annotated types by unwrapping
605-
if hasattr(annotation, "__origin__"):
606-
from typing import get_args
603+
def _convert_uploadfile_to_bytes(value: Any, field_info: FieldInfo) -> Any:
604+
"""
605+
Convert UploadFile instances to bytes when the expected type is bytes.
606+
607+
This handles the conversion of uploaded files to bytes for validation,
608+
supporting both plain bytes annotations and Annotated[bytes, File()] patterns.
609+
"""
610+
if not isinstance(value, UploadFile):
611+
return value
607612

608-
args = get_args(annotation)
609-
if args:
610-
annotation = args[0]
613+
# Check if the annotation is bytes
614+
annotation = field_info.annotation
615+
# Handle Annotated types by unwrapping
616+
if hasattr(annotation, "__origin__"):
617+
from typing import get_args
611618

612-
if annotation is bytes:
613-
return value.file
619+
args = get_args(annotation)
620+
if args:
621+
annotation = args[0]
614622

623+
if annotation is bytes:
624+
return value.file
625+
626+
return value
627+
628+
629+
def _normalize_field_value(value: Any, field_info: FieldInfo) -> Any:
630+
"""Normalize field value, converting lists to single values for non-sequence fields."""
615631
if field_annotation_is_sequence(field_info.annotation):
616632
return value
617633
elif isinstance(value, list) and value:
@@ -705,7 +721,9 @@ def _process_model_param(input_dict: MutableMapping[str, Any], param: ModelField
705721
value = _get_param_value(input_dict, field_alias, field_name, model_class)
706722

707723
if value is not None:
708-
model_data[field_alias] = _normalize_field_value(value=value, field_info=field_info)
724+
value = _normalize_field_value(value=value, field_info=field_info)
725+
value = _convert_uploadfile_to_bytes(value=value, field_info=field_info)
726+
model_data[field_alias] = value
709727

710728
input_dict[param.alias] = model_data
711729

aws_lambda_powertools/event_handler/openapi/params.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
This turns the low-level function signature into typed, validated Pydantic models for consumption.
3131
"""
3232

33+
# Explicitly define public API for this module to support IDE autocomplete,
34+
# documentation generation, and controlled imports. Update when adding new parameter types.
3335
__all__ = ["Path", "Query", "Header", "Body", "Form", "File", "UploadFile"]
3436

3537

0 commit comments

Comments
 (0)