Coverage for tests/test_file_and_form_order_issue_9116.py: 100%
40 statements
« prev ^ index » next coverage.py v7.6.1, created at 2025-09-22 00:03 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2025-09-22 00:03 +0000
1"""
2Regression test, Error 422 if Form is declared before File
3See https://github.com/tiangolo/fastapi/discussions/9116
4"""
6from pathlib import Path 1abcdef
7from typing import List 1abcdef
9import pytest 1abcdef
10from fastapi import FastAPI, File, Form 1abcdef
11from fastapi.testclient import TestClient 1abcdef
12from typing_extensions import Annotated 1abcdef
14app = FastAPI() 1abcdef
17@app.post("/file_before_form") 1abcdef
18def file_before_form( 1abcdef
19 file: bytes = File(),
20 city: str = Form(),
21):
22 return {"file_content": file, "city": city} 1ghijkl
25@app.post("/file_after_form") 1abcdef
26def file_after_form( 1abcdef
27 city: str = Form(),
28 file: bytes = File(),
29):
30 return {"file_content": file, "city": city} 1ghijkl
33@app.post("/file_list_before_form") 1abcdef
34def file_list_before_form( 1abcdef
35 files: Annotated[List[bytes], File()],
36 city: Annotated[str, Form()],
37):
38 return {"file_contents": files, "city": city} 1mnopqr
41@app.post("/file_list_after_form") 1abcdef
42def file_list_after_form( 1abcdef
43 city: Annotated[str, Form()],
44 files: Annotated[List[bytes], File()],
45):
46 return {"file_contents": files, "city": city} 1mnopqr
49client = TestClient(app) 1abcdef
52@pytest.fixture 1abcdef
53def tmp_file_1(tmp_path: Path) -> Path: 1abcdef
54 f = tmp_path / "example1.txt" 1abcdef
55 f.write_text("foo") 1abcdef
56 return f 1abcdef
59@pytest.fixture 1abcdef
60def tmp_file_2(tmp_path: Path) -> Path: 1abcdef
61 f = tmp_path / "example2.txt" 1abcdef
62 f.write_text("bar") 1abcdef
63 return f 1abcdef
66@pytest.mark.parametrize("endpoint_path", ("/file_before_form", "/file_after_form")) 1abcdef
67def test_file_form_order(endpoint_path: str, tmp_file_1: Path): 1abcdef
68 response = client.post( 1ghijkl
69 url=endpoint_path,
70 data={"city": "Thimphou"},
71 files={"file": (tmp_file_1.name, tmp_file_1.read_bytes())},
72 )
73 assert response.status_code == 200, response.text 1ghijkl
74 assert response.json() == {"file_content": "foo", "city": "Thimphou"} 1ghijkl
77@pytest.mark.parametrize( 1abcdef
78 "endpoint_path", ("/file_list_before_form", "/file_list_after_form")
79)
80def test_file_list_form_order(endpoint_path: str, tmp_file_1: Path, tmp_file_2: Path): 1abcdef
81 response = client.post( 1mnopqr
82 url=endpoint_path,
83 data={"city": "Thimphou"},
84 files=(
85 ("files", (tmp_file_1.name, tmp_file_1.read_bytes())),
86 ("files", (tmp_file_2.name, tmp_file_2.read_bytes())),
87 ),
88 )
89 assert response.status_code == 200, response.text 1mnopqr
90 assert response.json() == {"file_contents": ["foo", "bar"], "city": "Thimphou"} 1mnopqr