Coverage for tests / test_file_and_form_order_issue_9116.py: 100%

39 statements  

« prev     ^ index     » next       coverage.py v7.13.3, created at 2026-04-06 01:24 +0000

1""" 

2Regression test, Error 422 if Form is declared before File 

3See https://github.com/tiangolo/fastapi/discussions/9116 

4""" 

5 

6from pathlib import Path 1abcd

7from typing import Annotated 1abcd

8 

9import pytest 1abcd

10from fastapi import FastAPI, File, Form 1abcd

11from fastapi.testclient import TestClient 1abcd

12 

13app = FastAPI() 1abcd

14 

15 

16@app.post("/file_before_form") 1abcd

17def file_before_form( 1abcd

18 file: bytes = File(), 

19 city: str = Form(), 

20): 

21 return {"file_content": file, "city": city} 1lmno

22 

23 

24@app.post("/file_after_form") 1abcd

25def file_after_form( 1abcd

26 city: str = Form(), 

27 file: bytes = File(), 

28): 

29 return {"file_content": file, "city": city} 1pGqr

30 

31 

32@app.post("/file_list_before_form") 1abcd

33def file_list_before_form( 1abcd

34 files: Annotated[list[bytes], File()], 

35 city: Annotated[str, Form()], 

36): 

37 return {"file_contents": files, "city": city} 1stuv

38 

39 

40@app.post("/file_list_after_form") 1abcd

41def file_list_after_form( 1abcd

42 city: Annotated[str, Form()], 

43 files: Annotated[list[bytes], File()], 

44): 

45 return {"file_contents": files, "city": city} 1wHxy

46 

47 

48client = TestClient(app) 1abcd

49 

50 

51@pytest.fixture 1abcd

52def tmp_file_1(tmp_path: Path) -> Path: 1abcd

53 f = tmp_path / "example1.txt" 1zAefBgCDhiEFjk

54 f.write_text("foo") 1zAefBgCDhiEFjk

55 return f 1zAefBgCDhiEFjk

56 

57 

58@pytest.fixture 1abcd

59def tmp_file_2(tmp_path: Path) -> Path: 1abcd

60 f = tmp_path / "example2.txt" 1efghijk

61 f.write_text("bar") 1efghijk

62 return f 1efghijk

63 

64 

65@pytest.mark.parametrize("endpoint_path", ("/file_before_form", "/file_after_form")) 1abcd

66def test_file_form_order(endpoint_path: str, tmp_file_1: Path): 1abcd

67 response = client.post( 1plmqnro

68 url=endpoint_path, 

69 data={"city": "Thimphou"}, 

70 files={"file": (tmp_file_1.name, tmp_file_1.read_bytes())}, 

71 ) 

72 assert response.status_code == 200, response.text 1plmqnro

73 assert response.json() == {"file_content": "foo", "city": "Thimphou"} 1plmqnro

74 

75 

76@pytest.mark.parametrize( 1abcd

77 "endpoint_path", ("/file_list_before_form", "/file_list_after_form") 

78) 

79def test_file_list_form_order(endpoint_path: str, tmp_file_1: Path, tmp_file_2: Path): 1abcd

80 response = client.post( 1wstxuyv

81 url=endpoint_path, 

82 data={"city": "Thimphou"}, 

83 files=( 

84 ("files", (tmp_file_1.name, tmp_file_1.read_bytes())), 

85 ("files", (tmp_file_2.name, tmp_file_2.read_bytes())), 

86 ), 

87 ) 

88 assert response.status_code == 200, response.text 1wstxuyv

89 assert response.json() == {"file_contents": ["foo", "bar"], "city": "Thimphou"} 1wstxuyv