Coverage for tests / test_request_params / test_form / test_optional_list.py: 100%
131 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, Form 1abcd
5from fastapi.testclient import TestClient 1abcd
6from pydantic import BaseModel, Field 1abcd
8from .utils import get_body_model_name 1abcd
10app = FastAPI() 1abcd
12# =====================================================================================
13# Without aliases
16@app.post("/optional-list-str", operation_id="optional_list_str") 1abcd
17async def read_optional_list_str( 1abcd
18 p: Annotated[Optional[list[str]], Form()] = None,
19):
20 return {"p": p} 1efghij
23class FormModelOptionalListStr(BaseModel): 1abcd
24 p: Optional[list[str]] = None 1abcd
27@app.post("/model-optional-list-str", operation_id="model_optional_list_str") 1abcd
28async def read_model_optional_list_str(p: Annotated[FormModelOptionalListStr, Form()]): 1abcd
29 return {"p": p.p} 1efghij
32@pytest.mark.parametrize( 1abcd
33 "path",
34 ["/optional-list-str", "/model-optional-list-str"],
35)
36def test_optional_list_str_schema(path: str): 1abcd
37 openapi = app.openapi() 1OPQ
38 body_model_name = get_body_model_name(openapi, path) 1OPQ
40 assert app.openapi()["components"]["schemas"][body_model_name] == { 1OPQ
41 "properties": {
42 "p": {
43 "anyOf": [
44 {"items": {"type": "string"}, "type": "array"},
45 {"type": "null"},
46 ],
47 "title": "P",
48 },
49 },
50 "title": body_model_name,
51 "type": "object",
52 }
55@pytest.mark.parametrize( 1abcd
56 "path",
57 ["/optional-list-str", "/model-optional-list-str"],
58)
59def test_optional_list_str_missing(path: str): 1abcd
60 client = TestClient(app) 1fhj
61 response = client.post(path) 1fhj
62 assert response.status_code == 200, response.text 1fhj
63 assert response.json() == {"p": None} 1fhj
66@pytest.mark.parametrize( 1abcd
67 "path",
68 ["/optional-list-str", "/model-optional-list-str"],
69)
70def test_optional_list_str(path: str): 1abcd
71 client = TestClient(app) 1egi
72 response = client.post(path, data={"p": ["hello", "world"]}) 1egi
73 assert response.status_code == 200 1egi
74 assert response.json() == {"p": ["hello", "world"]} 1egi
77# =====================================================================================
78# Alias
81@app.post("/optional-list-alias", operation_id="optional_list_alias") 1abcd
82async def read_optional_list_alias( 1abcd
83 p: Annotated[Optional[list[str]], Form(alias="p_alias")] = None,
84):
85 return {"p": p} 1klmnopqrs
88class FormModelOptionalListAlias(BaseModel): 1abcd
89 p: Optional[list[str]] = Field(None, alias="p_alias") 1abcd
92@app.post("/model-optional-list-alias", operation_id="model_optional_list_alias") 1abcd
93async def read_model_optional_list_alias( 1abcd
94 p: Annotated[FormModelOptionalListAlias, Form()],
95):
96 return {"p": p.p} 1klmnopqrs
99@pytest.mark.parametrize( 1abcd
100 "path",
101 [
102 "/optional-list-alias",
103 "/model-optional-list-alias",
104 ],
105)
106def test_optional_list_str_alias_schema(path: str): 1abcd
107 openapi = app.openapi() 1RST
108 body_model_name = get_body_model_name(openapi, path) 1RST
110 assert app.openapi()["components"]["schemas"][body_model_name] == { 1RST
111 "properties": {
112 "p_alias": {
113 "anyOf": [
114 {"items": {"type": "string"}, "type": "array"},
115 {"type": "null"},
116 ],
117 "title": "P Alias",
118 },
119 },
120 "title": body_model_name,
121 "type": "object",
122 }
125@pytest.mark.parametrize( 1abcd
126 "path",
127 ["/optional-list-alias", "/model-optional-list-alias"],
128)
129def test_optional_list_alias_missing(path: str): 1abcd
130 client = TestClient(app) 1mps
131 response = client.post(path) 1mps
132 assert response.status_code == 200 1mps
133 assert response.json() == {"p": None} 1mps
136@pytest.mark.parametrize( 1abcd
137 "path",
138 ["/optional-list-alias", "/model-optional-list-alias"],
139)
140def test_optional_list_alias_by_name(path: str): 1abcd
141 client = TestClient(app) 1lor
142 response = client.post(path, data={"p": ["hello", "world"]}) 1lor
143 assert response.status_code == 200 1lor
144 assert response.json() == {"p": None} 1lor
147@pytest.mark.parametrize( 1abcd
148 "path",
149 ["/optional-list-alias", "/model-optional-list-alias"],
150)
151def test_optional_list_alias_by_alias(path: str): 1abcd
152 client = TestClient(app) 1knq
153 response = client.post(path, data={"p_alias": ["hello", "world"]}) 1knq
154 assert response.status_code == 200 1knq
155 assert response.json() == {"p": ["hello", "world"]} 1knq
158# =====================================================================================
159# Validation alias
162@app.post( 1abcd
163 "/optional-list-validation-alias", operation_id="optional_list_validation_alias"
164)
165def read_optional_list_validation_alias( 1abcd
166 p: Annotated[Optional[list[str]], Form(validation_alias="p_val_alias")] = None,
167):
168 return {"p": p} 1tuvwxyzAB
171class FormModelOptionalListValidationAlias(BaseModel): 1abcd
172 p: Optional[list[str]] = Field(None, validation_alias="p_val_alias") 1abcd
175@app.post( 1abcd
176 "/model-optional-list-validation-alias",
177 operation_id="model_optional_list_validation_alias",
178)
179def read_model_optional_list_validation_alias( 1abcd
180 p: Annotated[FormModelOptionalListValidationAlias, Form()],
181):
182 return {"p": p.p} 1tuvwxyzAB
185@pytest.mark.parametrize( 1abcd
186 "path",
187 ["/optional-list-validation-alias", "/model-optional-list-validation-alias"],
188)
189def test_optional_list_validation_alias_schema(path: str): 1abcd
190 openapi = app.openapi() 1UVW
191 body_model_name = get_body_model_name(openapi, path) 1UVW
193 assert app.openapi()["components"]["schemas"][body_model_name] == { 1UVW
194 "properties": {
195 "p_val_alias": {
196 "anyOf": [
197 {"items": {"type": "string"}, "type": "array"},
198 {"type": "null"},
199 ],
200 "title": "P Val Alias",
201 },
202 },
203 "title": body_model_name,
204 "type": "object",
205 }
208@pytest.mark.parametrize( 1abcd
209 "path",
210 ["/optional-list-validation-alias", "/model-optional-list-validation-alias"],
211)
212def test_optional_list_validation_alias_missing(path: str): 1abcd
213 client = TestClient(app) 1vyB
214 response = client.post(path) 1vyB
215 assert response.status_code == 200 1vyB
216 assert response.json() == {"p": None} 1vyB
219@pytest.mark.parametrize( 1abcd
220 "path",
221 [
222 "/optional-list-validation-alias",
223 "/model-optional-list-validation-alias",
224 ],
225)
226def test_optional_list_validation_alias_by_name(path: str): 1abcd
227 client = TestClient(app) 1twz
228 response = client.post(path, data={"p": ["hello", "world"]}) 1twz
229 assert response.status_code == 200 1twz
230 assert response.json() == {"p": None} 1twz
233@pytest.mark.parametrize( 1abcd
234 "path",
235 ["/optional-list-validation-alias", "/model-optional-list-validation-alias"],
236)
237def test_optional_list_validation_alias_by_validation_alias(path: str): 1abcd
238 client = TestClient(app) 1uxA
239 response = client.post(path, data={"p_val_alias": ["hello", "world"]}) 1uxA
240 assert response.status_code == 200, response.text 1uxA
241 assert response.json() == {"p": ["hello", "world"]} 1uxA
244# =====================================================================================
245# Alias and validation alias
248@app.post( 1abcd
249 "/optional-list-alias-and-validation-alias",
250 operation_id="optional_list_alias_and_validation_alias",
251)
252def read_optional_list_alias_and_validation_alias( 1abcd
253 p: Annotated[
254 Optional[list[str]], Form(alias="p_alias", validation_alias="p_val_alias")
255 ] = None,
256):
257 return {"p": p} 1CDEFGHIJKLMN
260class FormModelOptionalListAliasAndValidationAlias(BaseModel): 1abcd
261 p: Optional[list[str]] = Field( 1abcd
262 None, alias="p_alias", validation_alias="p_val_alias"
263 )
266@app.post( 1abcd
267 "/model-optional-list-alias-and-validation-alias",
268 operation_id="model_optional_list_alias_and_validation_alias",
269)
270def read_model_optional_list_alias_and_validation_alias( 1abcd
271 p: Annotated[FormModelOptionalListAliasAndValidationAlias, Form()],
272):
273 return {"p": p.p} 1CDEFGHIJKLMN
276@pytest.mark.parametrize( 1abcd
277 "path",
278 [
279 "/optional-list-alias-and-validation-alias",
280 "/model-optional-list-alias-and-validation-alias",
281 ],
282)
283def test_optional_list_alias_and_validation_alias_schema(path: str): 1abcd
284 openapi = app.openapi() 1XYZ
285 body_model_name = get_body_model_name(openapi, path) 1XYZ
287 assert app.openapi()["components"]["schemas"][body_model_name] == { 1XYZ
288 "properties": {
289 "p_val_alias": {
290 "anyOf": [
291 {"items": {"type": "string"}, "type": "array"},
292 {"type": "null"},
293 ],
294 "title": "P Val Alias",
295 },
296 },
297 "title": body_model_name,
298 "type": "object",
299 }
302@pytest.mark.parametrize( 1abcd
303 "path",
304 [
305 "/optional-list-alias-and-validation-alias",
306 "/model-optional-list-alias-and-validation-alias",
307 ],
308)
309def test_optional_list_alias_and_validation_alias_missing(path: str): 1abcd
310 client = TestClient(app) 1FJN
311 response = client.post(path) 1FJN
312 assert response.status_code == 200 1FJN
313 assert response.json() == {"p": None} 1FJN
316@pytest.mark.parametrize( 1abcd
317 "path",
318 [
319 "/optional-list-alias-and-validation-alias",
320 "/model-optional-list-alias-and-validation-alias",
321 ],
322)
323def test_optional_list_alias_and_validation_alias_by_name(path: str): 1abcd
324 client = TestClient(app) 1DHL
325 response = client.post(path, data={"p": ["hello", "world"]}) 1DHL
326 assert response.status_code == 200 1DHL
327 assert response.json() == {"p": None} 1DHL
330@pytest.mark.parametrize( 1abcd
331 "path",
332 [
333 "/optional-list-alias-and-validation-alias",
334 "/model-optional-list-alias-and-validation-alias",
335 ],
336)
337def test_optional_list_alias_and_validation_alias_by_alias(path: str): 1abcd
338 client = TestClient(app) 1CGK
339 response = client.post(path, data={"p_alias": ["hello", "world"]}) 1CGK
340 assert response.status_code == 200 1CGK
341 assert response.json() == {"p": None} 1CGK
344@pytest.mark.parametrize( 1abcd
345 "path",
346 [
347 "/optional-list-alias-and-validation-alias",
348 "/model-optional-list-alias-and-validation-alias",
349 ],
350)
351def test_optional_list_alias_and_validation_alias_by_validation_alias(path: str): 1abcd
352 client = TestClient(app) 1EIM
353 response = client.post(path, data={"p_val_alias": ["hello", "world"]}) 1EIM
354 assert response.status_code == 200, response.text 1EIM
355 assert response.json() == { 1EIM
356 "p": [
357 "hello",
358 "world",
359 ]
360 }