def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]:
origin_type = get_origin(field.field_info.annotation) or field.field_info.annotation
+ if origin_type is Union: # Handle optional sequences
+ union_args = get_args(field.field_info.annotation)
+ for union_arg in union_args:
+ if union_arg is type(None):
+ continue
+ origin_type = get_origin(union_arg) or union_arg
+ break
assert issubclass(origin_type, shared.sequence_types) # type: ignore[arg-type]
return shared.sequence_annotation_to_type[origin_type](value) # type: ignore[no-any-return]
assert is_uploadfile_sequence_annotation(Union[List[str], List[UploadFile]])
+@needs_pydanticv2
+def test_serialize_sequence_value_with_optional_list():
+ """Test that serialize_sequence_value handles optional lists correctly."""
+ from fastapi._compat import v2
+
+ field_info = FieldInfo(annotation=Union[List[str], None])
+ field = v2.ModelField(name="items", field_info=field_info)
+ result = v2.serialize_sequence_value(field=field, value=["a", "b", "c"])
+ assert result == ["a", "b", "c"]
+ assert isinstance(result, list)
+
+
+@needs_pydanticv2
+def test_serialize_sequence_value_with_none_first_in_union():
+ """Test that serialize_sequence_value handles Union[None, List[...]] correctly."""
+ from fastapi._compat import v2
+
+ field_info = FieldInfo(annotation=Union[None, List[str]])
+ field = v2.ModelField(name="items", field_info=field_info)
+ result = v2.serialize_sequence_value(field=field, value=["x", "y"])
+ assert result == ["x", "y"]
+ assert isinstance(result, list)
+
+
@needs_py_lt_314
def test_is_pv1_scalar_field():
from fastapi._compat import v1
--- /dev/null
+from typing import List, Optional
+
+from fastapi import FastAPI, File
+from fastapi.testclient import TestClient
+
+app = FastAPI()
+
+
+@app.post("/files")
+async def upload_files(files: Optional[List[bytes]] = File(None)):
+ if files is None:
+ return {"files_count": 0}
+ return {"files_count": len(files), "sizes": [len(f) for f in files]}
+
+
+def test_optional_bytes_list():
+ client = TestClient(app)
+ response = client.post(
+ "/files",
+ files=[("files", b"content1"), ("files", b"content2")],
+ )
+ assert response.status_code == 200
+ assert response.json() == {"files_count": 2, "sizes": [8, 8]}
+
+
+def test_optional_bytes_list_no_files():
+ client = TestClient(app)
+ response = client.post("/files")
+ assert response.status_code == 200
+ assert response.json() == {"files_count": 0}