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-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, 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[list[str] | None, Form()] = None,
19):
20 return {"p": p} 1efghij
23class FormModelOptionalListStr(BaseModel): 1abcd
24 p: list[str] | None = 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[list[str] | None, Form(alias="p_alias")] = None,
84):
85 return {"p": p} 1klmnopqrs
88class FormModelOptionalListAlias(BaseModel): 1abcd
89 p: list[str] | None = 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[list[str] | None, Form(validation_alias="p_val_alias")] = None,
167):
168 return {"p": p} 1tuvwxyzAB
171class FormModelOptionalListValidationAlias(BaseModel): 1abcd
172 p: list[str] | None = 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 list[str] | None, Form(alias="p_alias", validation_alias="p_val_alias")
255 ] = None,
256):
257 return {"p": p} 1CDEFGHIJKLMN
260class FormModelOptionalListAliasAndValidationAlias(BaseModel): 1abcd
261 p: list[str] | None = Field(None, alias="p_alias", validation_alias="p_val_alias") 1abcd
264@app.post( 1abcd
265 "/model-optional-list-alias-and-validation-alias",
266 operation_id="model_optional_list_alias_and_validation_alias",
267)
268def read_model_optional_list_alias_and_validation_alias( 1abcd
269 p: Annotated[FormModelOptionalListAliasAndValidationAlias, Form()],
270):
271 return {"p": p.p} 1CDEFGHIJKLMN
274@pytest.mark.parametrize( 1abcd
275 "path",
276 [
277 "/optional-list-alias-and-validation-alias",
278 "/model-optional-list-alias-and-validation-alias",
279 ],
280)
281def test_optional_list_alias_and_validation_alias_schema(path: str): 1abcd
282 openapi = app.openapi() 1XYZ
283 body_model_name = get_body_model_name(openapi, path) 1XYZ
285 assert app.openapi()["components"]["schemas"][body_model_name] == { 1XYZ
286 "properties": {
287 "p_val_alias": {
288 "anyOf": [
289 {"items": {"type": "string"}, "type": "array"},
290 {"type": "null"},
291 ],
292 "title": "P Val Alias",
293 },
294 },
295 "title": body_model_name,
296 "type": "object",
297 }
300@pytest.mark.parametrize( 1abcd
301 "path",
302 [
303 "/optional-list-alias-and-validation-alias",
304 "/model-optional-list-alias-and-validation-alias",
305 ],
306)
307def test_optional_list_alias_and_validation_alias_missing(path: str): 1abcd
308 client = TestClient(app) 1FJN
309 response = client.post(path) 1FJN
310 assert response.status_code == 200 1FJN
311 assert response.json() == {"p": None} 1FJN
314@pytest.mark.parametrize( 1abcd
315 "path",
316 [
317 "/optional-list-alias-and-validation-alias",
318 "/model-optional-list-alias-and-validation-alias",
319 ],
320)
321def test_optional_list_alias_and_validation_alias_by_name(path: str): 1abcd
322 client = TestClient(app) 1DHL
323 response = client.post(path, data={"p": ["hello", "world"]}) 1DHL
324 assert response.status_code == 200 1DHL
325 assert response.json() == {"p": None} 1DHL
328@pytest.mark.parametrize( 1abcd
329 "path",
330 [
331 "/optional-list-alias-and-validation-alias",
332 "/model-optional-list-alias-and-validation-alias",
333 ],
334)
335def test_optional_list_alias_and_validation_alias_by_alias(path: str): 1abcd
336 client = TestClient(app) 1CGK
337 response = client.post(path, data={"p_alias": ["hello", "world"]}) 1CGK
338 assert response.status_code == 200 1CGK
339 assert response.json() == {"p": None} 1CGK
342@pytest.mark.parametrize( 1abcd
343 "path",
344 [
345 "/optional-list-alias-and-validation-alias",
346 "/model-optional-list-alias-and-validation-alias",
347 ],
348)
349def test_optional_list_alias_and_validation_alias_by_validation_alias(path: str): 1abcd
350 client = TestClient(app) 1EIM
351 response = client.post(path, data={"p_val_alias": ["hello", "world"]}) 1EIM
352 assert response.status_code == 200, response.text 1EIM
353 assert response.json() == { 1EIM
354 "p": [
355 "hello",
356 "world",
357 ]
358 }