Coverage for tests / test_request_params / test_file / test_optional_list.py: 100%
122 statements
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-12 18:15 +0000
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-12 18:15 +0000
1from typing import Annotated, Optional 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("/optional-list-bytes") 1abcd
16async def read_optional_list_bytes(p: Annotated[Optional[list[bytes]], File()] = None): 1abcd
17 return {"file_size": [len(file) for file in p] if p else None} 1efghij
20@app.post("/optional-list-uploadfile") 1abcd
21async def read_optional_list_uploadfile( 1abcd
22 p: Annotated[Optional[list[UploadFile]], File()] = None,
23):
24 return {"file_size": [file.size for file in p] if p else None} 1efghij
27@pytest.mark.parametrize( 1abcd
28 "path",
29 [
30 "/optional-list-bytes",
31 "/optional-list-uploadfile",
32 ],
33)
34def test_optional_list_schema(path: str): 1abcd
35 openapi = app.openapi() 1OPQ
36 body_model_name = get_body_model_name(openapi, path) 1OPQ
38 assert app.openapi()["components"]["schemas"][body_model_name] == { 1OPQ
39 "properties": {
40 "p": {
41 "anyOf": [
42 {
43 "type": "array",
44 "items": {"type": "string", "format": "binary"},
45 },
46 {"type": "null"},
47 ],
48 "title": "P",
49 }
50 },
51 "title": body_model_name,
52 "type": "object",
53 }
56@pytest.mark.parametrize( 1abcd
57 "path",
58 [
59 "/optional-list-bytes",
60 "/optional-list-uploadfile",
61 ],
62)
63def test_optional_list_missing(path: str): 1abcd
64 client = TestClient(app) 1fhj
65 response = client.post(path) 1fhj
66 assert response.status_code == 200, response.text 1fhj
67 assert response.json() == {"file_size": None} 1fhj
70@pytest.mark.parametrize( 1abcd
71 "path",
72 [
73 "/optional-list-bytes",
74 "/optional-list-uploadfile",
75 ],
76)
77def test_optional_list(path: str): 1abcd
78 client = TestClient(app) 1egi
79 response = client.post(path, files=[("p", b"hello"), ("p", b"world")]) 1egi
80 assert response.status_code == 200 1egi
81 assert response.json() == {"file_size": [5, 5]} 1egi
84# =====================================================================================
85# Alias
88@app.post("/optional-list-bytes-alias") 1abcd
89async def read_optional_list_bytes_alias( 1abcd
90 p: Annotated[Optional[list[bytes]], File(alias="p_alias")] = None,
91):
92 return {"file_size": [len(file) for file in p] if p else None} 1klmnopqrs
95@app.post("/optional-list-uploadfile-alias") 1abcd
96async def read_optional_list_uploadfile_alias( 1abcd
97 p: Annotated[Optional[list[UploadFile]], File(alias="p_alias")] = None,
98):
99 return {"file_size": [file.size for file in p] if p else None} 1klmnopqrs
102@pytest.mark.parametrize( 1abcd
103 "path",
104 [
105 "/optional-list-bytes-alias",
106 "/optional-list-uploadfile-alias",
107 ],
108)
109def test_optional_list_alias_schema(path: str): 1abcd
110 openapi = app.openapi() 1RST
111 body_model_name = get_body_model_name(openapi, path) 1RST
113 assert app.openapi()["components"]["schemas"][body_model_name] == { 1RST
114 "properties": {
115 "p_alias": {
116 "anyOf": [
117 {
118 "type": "array",
119 "items": {"type": "string", "format": "binary"},
120 },
121 {"type": "null"},
122 ],
123 "title": "P Alias",
124 }
125 },
126 "title": body_model_name,
127 "type": "object",
128 }
131@pytest.mark.parametrize( 1abcd
132 "path",
133 [
134 "/optional-list-bytes-alias",
135 "/optional-list-uploadfile-alias",
136 ],
137)
138def test_optional_list_alias_missing(path: str): 1abcd
139 client = TestClient(app) 1mps
140 response = client.post(path) 1mps
141 assert response.status_code == 200 1mps
142 assert response.json() == {"file_size": None} 1mps
145@pytest.mark.parametrize( 1abcd
146 "path",
147 [
148 "/optional-list-bytes-alias",
149 "/optional-list-uploadfile-alias",
150 ],
151)
152def test_optional_list_alias_by_name(path: str): 1abcd
153 client = TestClient(app) 1lor
154 response = client.post(path, files=[("p", b"hello"), ("p", b"world")]) 1lor
155 assert response.status_code == 200, response.text 1lor
156 assert response.json() == {"file_size": None} 1lor
159@pytest.mark.parametrize( 1abcd
160 "path",
161 [
162 "/optional-list-bytes-alias",
163 "/optional-list-uploadfile-alias",
164 ],
165)
166def test_optional_list_alias_by_alias(path: str): 1abcd
167 client = TestClient(app) 1knq
168 response = client.post(path, files=[("p_alias", b"hello"), ("p_alias", b"world")]) 1knq
169 assert response.status_code == 200, response.text 1knq
170 assert response.json() == {"file_size": [5, 5]} 1knq
173# =====================================================================================
174# Validation alias
177@app.post("/optional-list-bytes-validation-alias") 1abcd
178def read_optional_list_bytes_validation_alias( 1abcd
179 p: Annotated[Optional[list[bytes]], File(validation_alias="p_val_alias")] = None,
180):
181 return {"file_size": [len(file) for file in p] if p else None} 1tuvwxyzAB
184@app.post("/optional-list-uploadfile-validation-alias") 1abcd
185def read_optional_list_uploadfile_validation_alias( 1abcd
186 p: Annotated[
187 Optional[list[UploadFile]], File(validation_alias="p_val_alias")
188 ] = None,
189):
190 return {"file_size": [file.size for file in p] if p else None} 1tuvwxyzAB
193@pytest.mark.parametrize( 1abcd
194 "path",
195 [
196 "/optional-list-bytes-validation-alias",
197 "/optional-list-uploadfile-validation-alias",
198 ],
199)
200def test_optional_validation_alias_schema(path: str): 1abcd
201 openapi = app.openapi() 1UVW
202 body_model_name = get_body_model_name(openapi, path) 1UVW
204 assert app.openapi()["components"]["schemas"][body_model_name] == { 1UVW
205 "properties": {
206 "p_val_alias": {
207 "anyOf": [
208 {
209 "type": "array",
210 "items": {"type": "string", "format": "binary"},
211 },
212 {"type": "null"},
213 ],
214 "title": "P Val Alias",
215 }
216 },
217 "title": body_model_name,
218 "type": "object",
219 }
222@pytest.mark.parametrize( 1abcd
223 "path",
224 [
225 "/optional-list-bytes-validation-alias",
226 "/optional-list-uploadfile-validation-alias",
227 ],
228)
229def test_optional_validation_alias_missing(path: str): 1abcd
230 client = TestClient(app) 1vyB
231 response = client.post(path) 1vyB
232 assert response.status_code == 200 1vyB
233 assert response.json() == {"file_size": None} 1vyB
236@pytest.mark.parametrize( 1abcd
237 "path",
238 [
239 "/optional-list-bytes-validation-alias",
240 "/optional-list-uploadfile-validation-alias",
241 ],
242)
243def test_optional_validation_alias_by_name(path: str): 1abcd
244 client = TestClient(app) 1twz
245 response = client.post(path, files=[("p", b"hello"), ("p", b"world")]) 1twz
246 assert response.status_code == 200, response.text 1twz
247 assert response.json() == {"file_size": None} 1twz
250@pytest.mark.parametrize( 1abcd
251 "path",
252 [
253 "/optional-list-bytes-validation-alias",
254 "/optional-list-uploadfile-validation-alias",
255 ],
256)
257def test_optional_validation_alias_by_validation_alias(path: str): 1abcd
258 client = TestClient(app) 1uxA
259 response = client.post( 1uxA
260 path, files=[("p_val_alias", b"hello"), ("p_val_alias", b"world")]
261 )
262 assert response.status_code == 200, response.text 1uxA
263 assert response.json() == {"file_size": [5, 5]} 1uxA
266# =====================================================================================
267# Alias and validation alias
270@app.post("/optional-list-bytes-alias-and-validation-alias") 1abcd
271def read_optional_list_bytes_alias_and_validation_alias( 1abcd
272 p: Annotated[
273 Optional[list[bytes]], File(alias="p_alias", validation_alias="p_val_alias")
274 ] = None,
275):
276 return {"file_size": [len(file) for file in p] if p else None} 1CDEFGHIJKLMN
279@app.post("/optional-list-uploadfile-alias-and-validation-alias") 1abcd
280def read_optional_list_uploadfile_alias_and_validation_alias( 1abcd
281 p: Annotated[
282 Optional[list[UploadFile]],
283 File(alias="p_alias", validation_alias="p_val_alias"),
284 ] = None,
285):
286 return {"file_size": [file.size for file in p] if p else None} 1CDEFGHIJKLMN
289@pytest.mark.parametrize( 1abcd
290 "path",
291 [
292 "/optional-list-bytes-alias-and-validation-alias",
293 "/optional-list-uploadfile-alias-and-validation-alias",
294 ],
295)
296def test_optional_list_alias_and_validation_alias_schema(path: str): 1abcd
297 openapi = app.openapi() 1XYZ
298 body_model_name = get_body_model_name(openapi, path) 1XYZ
300 assert app.openapi()["components"]["schemas"][body_model_name] == { 1XYZ
301 "properties": {
302 "p_val_alias": {
303 "anyOf": [
304 {
305 "type": "array",
306 "items": {"type": "string", "format": "binary"},
307 },
308 {"type": "null"},
309 ],
310 "title": "P Val Alias",
311 }
312 },
313 "title": body_model_name,
314 "type": "object",
315 }
318@pytest.mark.parametrize( 1abcd
319 "path",
320 [
321 "/optional-list-bytes-alias-and-validation-alias",
322 "/optional-list-uploadfile-alias-and-validation-alias",
323 ],
324)
325def test_optional_list_alias_and_validation_alias_missing(path: str): 1abcd
326 client = TestClient(app) 1FJN
327 response = client.post(path) 1FJN
328 assert response.status_code == 200 1FJN
329 assert response.json() == {"file_size": None} 1FJN
332@pytest.mark.parametrize( 1abcd
333 "path",
334 [
335 "/optional-list-bytes-alias-and-validation-alias",
336 "/optional-list-uploadfile-alias-and-validation-alias",
337 ],
338)
339def test_optional_list_alias_and_validation_alias_by_name(path: str): 1abcd
340 client = TestClient(app) 1DHL
341 response = client.post(path, files={"p": "hello"}) 1DHL
342 assert response.status_code == 200 1DHL
343 assert response.json() == {"file_size": None} 1DHL
346@pytest.mark.parametrize( 1abcd
347 "path",
348 [
349 "/optional-list-bytes-alias-and-validation-alias",
350 "/optional-list-uploadfile-alias-and-validation-alias",
351 ],
352)
353def test_optional_list_alias_and_validation_alias_by_alias(path: str): 1abcd
354 client = TestClient(app) 1CGK
355 response = client.post(path, files=[("p_alias", b"hello"), ("p_alias", b"world")]) 1CGK
356 assert response.status_code == 200, response.text 1CGK
357 assert response.json() == {"file_size": None} 1CGK
360@pytest.mark.parametrize( 1abcd
361 "path",
362 [
363 "/optional-list-bytes-alias-and-validation-alias",
364 "/optional-list-uploadfile-alias-and-validation-alias",
365 ],
366)
367def test_optional_list_alias_and_validation_alias_by_validation_alias(path: str): 1abcd
368 client = TestClient(app) 1EIM
369 response = client.post( 1EIM
370 path, files=[("p_val_alias", b"hello"), ("p_val_alias", b"world")]
371 )
372 assert response.status_code == 200, response.text 1EIM
373 assert response.json() == {"file_size": [5, 5]} 1EIM