Coverage for tests / test_request_params / test_file / test_required.py: 100%
122 statements
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-21 17:29 +0000
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-21 17:29 +0000
1from typing import Annotated 1abcd
3import pytest 1abcd
4from fastapi import FastAPI, File, UploadFile 1abcd
5from fastapi.testclient import TestClient 1abcd
7from .utils import get_body_model_name 1abcd
9app = FastAPI() 1abcd
11# =====================================================================================
12# Without aliases
15@app.post("/required-bytes", operation_id="required_bytes") 1abcd
16async def read_required_bytes(p: Annotated[bytes, File()]): 1abcd
17 return {"file_size": len(p)} 1efg
20@app.post("/required-uploadfile", operation_id="required_uploadfile") 1abcd
21async def read_required_uploadfile(p: Annotated[UploadFile, File()]): 1abcd
22 return {"file_size": p.size} 1efg
25@pytest.mark.parametrize( 1abcd
26 "path",
27 [
28 "/required-bytes",
29 "/required-uploadfile",
30 ],
31)
32def test_required_schema(path: str): 1abcd
33 openapi = app.openapi() 1OPQ
34 body_model_name = get_body_model_name(openapi, path) 1OPQ
36 assert app.openapi()["components"]["schemas"][body_model_name] == { 1OPQ
37 "properties": {
38 "p": {
39 "title": "P",
40 "type": "string",
41 "contentMediaType": "application/octet-stream",
42 },
43 },
44 "required": ["p"],
45 "title": body_model_name,
46 "type": "object",
47 }
50@pytest.mark.parametrize( 1abcd
51 "path",
52 [
53 "/required-bytes",
54 "/required-uploadfile",
55 ],
56)
57def test_required_missing(path: str): 1abcd
58 client = TestClient(app) 1qrs
59 response = client.post(path) 1qrs
60 assert response.status_code == 422 1qrs
61 assert response.json() == { 1qrs
62 "detail": [
63 {
64 "type": "missing",
65 "loc": ["body", "p"],
66 "msg": "Field required",
67 "input": None,
68 }
69 ]
70 }
73@pytest.mark.parametrize( 1abcd
74 "path",
75 [
76 "/required-bytes",
77 "/required-uploadfile",
78 ],
79)
80def test_required(path: str): 1abcd
81 client = TestClient(app) 1efg
82 response = client.post(path, files=[("p", b"hello")]) 1efg
83 assert response.status_code == 200 1efg
84 assert response.json() == {"file_size": 5} 1efg
87# =====================================================================================
88# Alias
91@app.post("/required-bytes-alias", operation_id="required_bytes_alias") 1abcd
92async def read_required_bytes_alias(p: Annotated[bytes, File(alias="p_alias")]): 1abcd
93 return {"file_size": len(p)} 1hij
96@app.post("/required-uploadfile-alias", operation_id="required_uploadfile_alias") 1abcd
97async def read_required_uploadfile_alias( 1abcd
98 p: Annotated[UploadFile, File(alias="p_alias")],
99):
100 return {"file_size": p.size} 1hij
103@pytest.mark.parametrize( 1abcd
104 "path",
105 [
106 "/required-bytes-alias",
107 "/required-uploadfile-alias",
108 ],
109)
110def test_required_alias_schema(path: str): 1abcd
111 openapi = app.openapi() 1RST
112 body_model_name = get_body_model_name(openapi, path) 1RST
114 assert app.openapi()["components"]["schemas"][body_model_name] == { 1RST
115 "properties": {
116 "p_alias": {
117 "title": "P Alias",
118 "type": "string",
119 "contentMediaType": "application/octet-stream",
120 },
121 },
122 "required": ["p_alias"],
123 "title": body_model_name,
124 "type": "object",
125 }
128@pytest.mark.parametrize( 1abcd
129 "path",
130 [
131 "/required-bytes-alias",
132 "/required-uploadfile-alias",
133 ],
134)
135def test_required_alias_missing(path: str): 1abcd
136 client = TestClient(app) 1tuv
137 response = client.post(path) 1tuv
138 assert response.status_code == 422 1tuv
139 assert response.json() == { 1tuv
140 "detail": [
141 {
142 "type": "missing",
143 "loc": ["body", "p_alias"],
144 "msg": "Field required",
145 "input": None,
146 }
147 ]
148 }
151@pytest.mark.parametrize( 1abcd
152 "path",
153 [
154 "/required-bytes-alias",
155 "/required-uploadfile-alias",
156 ],
157)
158def test_required_alias_by_name(path: str): 1abcd
159 client = TestClient(app) 1wxy
160 response = client.post(path, files=[("p", b"hello")]) 1wxy
161 assert response.status_code == 422 1wxy
162 assert response.json() == { 1wxy
163 "detail": [
164 {
165 "type": "missing",
166 "loc": ["body", "p_alias"],
167 "msg": "Field required",
168 "input": None,
169 }
170 ]
171 }
174@pytest.mark.parametrize( 1abcd
175 "path",
176 [
177 "/required-bytes-alias",
178 "/required-uploadfile-alias",
179 ],
180)
181def test_required_alias_by_alias(path: str): 1abcd
182 client = TestClient(app) 1hij
183 response = client.post(path, files=[("p_alias", b"hello")]) 1hij
184 assert response.status_code == 200, response.text 1hij
185 assert response.json() == {"file_size": 5} 1hij
188# =====================================================================================
189# Validation alias
192@app.post( 1abcd
193 "/required-bytes-validation-alias", operation_id="required_bytes_validation_alias"
194)
195def read_required_bytes_validation_alias( 1abcd
196 p: Annotated[bytes, File(validation_alias="p_val_alias")],
197):
198 return {"file_size": len(p)} 1klm
201@app.post( 1abcd
202 "/required-uploadfile-validation-alias",
203 operation_id="required_uploadfile_validation_alias",
204)
205def read_required_uploadfile_validation_alias( 1abcd
206 p: Annotated[UploadFile, File(validation_alias="p_val_alias")],
207):
208 return {"file_size": p.size} 1klm
211@pytest.mark.parametrize( 1abcd
212 "path",
213 [
214 "/required-bytes-validation-alias",
215 "/required-uploadfile-validation-alias",
216 ],
217)
218def test_required_validation_alias_schema(path: str): 1abcd
219 openapi = app.openapi() 1UVW
220 body_model_name = get_body_model_name(openapi, path) 1UVW
222 assert app.openapi()["components"]["schemas"][body_model_name] == { 1UVW
223 "properties": {
224 "p_val_alias": {
225 "title": "P Val Alias",
226 "type": "string",
227 "contentMediaType": "application/octet-stream",
228 },
229 },
230 "required": ["p_val_alias"],
231 "title": body_model_name,
232 "type": "object",
233 }
236@pytest.mark.parametrize( 1abcd
237 "path",
238 [
239 "/required-bytes-validation-alias",
240 "/required-uploadfile-validation-alias",
241 ],
242)
243def test_required_validation_alias_missing(path: str): 1abcd
244 client = TestClient(app) 1zAB
245 response = client.post(path) 1zAB
246 assert response.status_code == 422 1zAB
247 assert response.json() == { 1zAB
248 "detail": [
249 {
250 "type": "missing",
251 "loc": [
252 "body",
253 "p_val_alias",
254 ],
255 "msg": "Field required",
256 "input": None,
257 }
258 ]
259 }
262@pytest.mark.parametrize( 1abcd
263 "path",
264 [
265 "/required-bytes-validation-alias",
266 "/required-uploadfile-validation-alias",
267 ],
268)
269def test_required_validation_alias_by_name(path: str): 1abcd
270 client = TestClient(app) 1CDE
271 response = client.post(path, files=[("p", b"hello")]) 1CDE
272 assert response.status_code == 422, response.text 1CDE
274 assert response.json() == { 1CDE
275 "detail": [
276 {
277 "type": "missing",
278 "loc": ["body", "p_val_alias"],
279 "msg": "Field required",
280 "input": None,
281 }
282 ]
283 }
286@pytest.mark.parametrize( 1abcd
287 "path",
288 [
289 "/required-bytes-validation-alias",
290 "/required-uploadfile-validation-alias",
291 ],
292)
293def test_required_validation_alias_by_validation_alias(path: str): 1abcd
294 client = TestClient(app) 1klm
295 response = client.post(path, files=[("p_val_alias", b"hello")]) 1klm
296 assert response.status_code == 200, response.text 1klm
297 assert response.json() == {"file_size": 5} 1klm
300# =====================================================================================
301# Alias and validation alias
304@app.post( 1abcd
305 "/required-bytes-alias-and-validation-alias",
306 operation_id="required_bytes_alias_and_validation_alias",
307)
308def read_required_bytes_alias_and_validation_alias( 1abcd
309 p: Annotated[bytes, File(alias="p_alias", validation_alias="p_val_alias")],
310):
311 return {"file_size": len(p)} 1nop
314@app.post( 1abcd
315 "/required-uploadfile-alias-and-validation-alias",
316 operation_id="required_uploadfile_alias_and_validation_alias",
317)
318def read_required_uploadfile_alias_and_validation_alias( 1abcd
319 p: Annotated[UploadFile, File(alias="p_alias", validation_alias="p_val_alias")],
320):
321 return {"file_size": p.size} 1nop
324@pytest.mark.parametrize( 1abcd
325 "path",
326 [
327 "/required-bytes-alias-and-validation-alias",
328 "/required-uploadfile-alias-and-validation-alias",
329 ],
330)
331def test_required_alias_and_validation_alias_schema(path: str): 1abcd
332 openapi = app.openapi() 1XYZ
333 body_model_name = get_body_model_name(openapi, path) 1XYZ
335 assert app.openapi()["components"]["schemas"][body_model_name] == { 1XYZ
336 "properties": {
337 "p_val_alias": {
338 "title": "P Val Alias",
339 "type": "string",
340 "contentMediaType": "application/octet-stream",
341 },
342 },
343 "required": ["p_val_alias"],
344 "title": body_model_name,
345 "type": "object",
346 }
349@pytest.mark.parametrize( 1abcd
350 "path",
351 [
352 "/required-bytes-alias-and-validation-alias",
353 "/required-uploadfile-alias-and-validation-alias",
354 ],
355)
356def test_required_alias_and_validation_alias_missing(path: str): 1abcd
357 client = TestClient(app) 1FGH
358 response = client.post(path) 1FGH
359 assert response.status_code == 422 1FGH
360 assert response.json() == { 1FGH
361 "detail": [
362 {
363 "type": "missing",
364 "loc": [
365 "body",
366 "p_val_alias",
367 ],
368 "msg": "Field required",
369 "input": None,
370 }
371 ]
372 }
375@pytest.mark.parametrize( 1abcd
376 "path",
377 [
378 "/required-bytes-alias-and-validation-alias",
379 "/required-uploadfile-alias-and-validation-alias",
380 ],
381)
382def test_required_alias_and_validation_alias_by_name(path: str): 1abcd
383 client = TestClient(app) 1IJK
384 response = client.post(path, files={"p": "hello"}) 1IJK
385 assert response.status_code == 422 1IJK
387 assert response.json() == { 1IJK
388 "detail": [
389 {
390 "type": "missing",
391 "loc": [
392 "body",
393 "p_val_alias",
394 ],
395 "msg": "Field required",
396 "input": None,
397 }
398 ]
399 }
402@pytest.mark.parametrize( 1abcd
403 "path",
404 [
405 "/required-bytes-alias-and-validation-alias",
406 "/required-uploadfile-alias-and-validation-alias",
407 ],
408)
409def test_required_alias_and_validation_alias_by_alias(path: str): 1abcd
410 client = TestClient(app) 1LMN
411 response = client.post(path, files=[("p_alias", b"hello")]) 1LMN
412 assert response.status_code == 422, response.text 1LMN
414 assert response.json() == { 1LMN
415 "detail": [
416 {
417 "type": "missing",
418 "loc": ["body", "p_val_alias"],
419 "msg": "Field required",
420 "input": None,
421 }
422 ]
423 }
426@pytest.mark.parametrize( 1abcd
427 "path",
428 [
429 "/required-bytes-alias-and-validation-alias",
430 "/required-uploadfile-alias-and-validation-alias",
431 ],
432)
433def test_required_alias_and_validation_alias_by_validation_alias(path: str): 1abcd
434 client = TestClient(app) 1nop
435 response = client.post(path, files=[("p_val_alias", b"hello")]) 1nop
436 assert response.status_code == 200, response.text 1nop
437 assert response.json() == {"file_size": 5} 1nop