From a36c655c4393fd43b755f66f98d7c32ec5d3c896 Mon Sep 17 00:00:00 2001 From: adhoc Date: Tue, 25 Mar 2025 14:50:20 +0100 Subject: [PATCH 1/4] fix none default --- fastapi/dependencies/utils.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py index d205d17fa..43e74452b 100644 --- a/fastapi/dependencies/utils.py +++ b/fastapi/dependencies/utils.py @@ -837,6 +837,7 @@ async def _extract_form_body( values = {} first_field = body_fields[0] first_field_info = first_field.field_info + processed_keys = set() for field in body_fields: value = _get_multidict_value(field, received_body) @@ -865,10 +866,11 @@ async def _extract_form_body( for sub_value in value: tg.start_soon(process_fn, sub_value.read) value = serialize_sequence_value(field=field, value=results) + processed_keys.add(field.alias) if value is not None: values[field.alias] = value for key, value in received_body.items(): - if key not in values: + if key not in processed_keys: values[key] = value return values From 5e501bb4c00ca0032da0a42fa40f5bafeb6c4c6a Mon Sep 17 00:00:00 2001 From: adhoc Date: Tue, 25 Mar 2025 15:38:04 +0100 Subject: [PATCH 2/4] add tests --- tests/test_form_default.py | 46 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 tests/test_form_default.py diff --git a/tests/test_form_default.py b/tests/test_form_default.py new file mode 100644 index 000000000..1c42bb401 --- /dev/null +++ b/tests/test_form_default.py @@ -0,0 +1,46 @@ +from typing import Annotated, Optional + +from fastapi import FastAPI, File, Form +from starlette.testclient import TestClient + +app = FastAPI() +client = TestClient(app) + + +@app.post("/urlencoded") +async def post_url_encoded(age: Annotated[Optional[int], Form()] = None): + return age + + +def test_form_default_url_encoded(): + response = client.post("/urlencoded", data={"age": ""}) + assert response.status_code == 200 + assert response.text == "null" + + +@app.post("/multipart") +async def post_multi_part( + age: Annotated[Optional[int], Form()] = None, + file: Annotated[Optional[bytes], File()] = None, +): + assert file is None + assert age is None + + +def test_form_default_multi_part(): + response = client.post("/multipart", data={"age": ""}) + assert response.status_code == 200 + + +@app.post("/multipart-file-first") +async def post_multi_part_file_first( + file: Annotated[Optional[bytes], File()] = None, + age: Annotated[Optional[int], Form()] = None, +): + assert file is None + assert age is None + + +def test_form_default_multi_part_file_first(): + response = client.post("/multipart-file-first", data={"age": ""}) + assert response.status_code == 200 From f2648fe45c9ca137fcee008dc3ddc0c521fcbf92 Mon Sep 17 00:00:00 2001 From: adhoc Date: Tue, 25 Mar 2025 16:17:47 +0100 Subject: [PATCH 3/4] fix import --- tests/test_form_default.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_form_default.py b/tests/test_form_default.py index 1c42bb401..f31c92ecf 100644 --- a/tests/test_form_default.py +++ b/tests/test_form_default.py @@ -1,4 +1,4 @@ -from typing import Annotated, Optional +from typing_extensions import Annotated, Optional from fastapi import FastAPI, File, Form from starlette.testclient import TestClient From da43c9c91ac9badc425d780697a771b5b8a9a0eb Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 25 Mar 2025 15:18:01 +0000 Subject: [PATCH 4/4] =?UTF-8?q?=F0=9F=8E=A8=20[pre-commit.ci]=20Auto=20for?= =?UTF-8?q?mat=20from=20pre-commit.com=20hooks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_form_default.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_form_default.py b/tests/test_form_default.py index f31c92ecf..97ff47463 100644 --- a/tests/test_form_default.py +++ b/tests/test_form_default.py @@ -1,7 +1,8 @@ -from typing_extensions import Annotated, Optional +from typing import Optional from fastapi import FastAPI, File, Form from starlette.testclient import TestClient +from typing_extensions import Annotated app = FastAPI() client = TestClient(app)