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-04-06 01:24 +0000
« prev ^ index » next coverage.py v7.13.3, created at 2026-04-06 01:24 +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} 1efghijkl
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} 1mnopqrst
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() 2lbmbnbobpbqbrbsb
38 body_model_name = get_body_model_name(openapi, path) 2lbmbnbobpbqbrbsb
40 assert app.openapi()["components"]["schemas"][body_model_name] == { 2lbmbnbobpbqbrbsb
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) 1nfphrjtl
61 response = client.post(path) 1nfphrjtl
62 assert response.status_code == 200, response.text 1nfphrjtl
63 assert response.json() == {"p": None} 1nfphrjtl
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) 1meogqisk
72 response = client.post(path, data={"p": ["hello", "world"]}) 1meogqisk
73 assert response.status_code == 200 1meogqisk
74 assert response.json() == {"p": ["hello", "world"]} 1meogqisk
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} 1uvwxyzABCDE
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} 1FGHIJKLMNOP
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() 2tbubvbwbxbybzbAb
108 body_model_name = get_body_model_name(openapi, path) 2tbubvbwbxbybzbAb
110 assert app.openapi()["components"]["schemas"][body_model_name] == { 2tbubvbwbxbybzbAb
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) 1HwJyMBPE
131 response = client.post(path) 1HwJyMBPE
132 assert response.status_code == 200 1HwJyMBPE
133 assert response.json() == {"p": None} 1HwJyMBPE
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) 1GvIxLAOD
142 response = client.post(path, data={"p": ["hello", "world"]}) 1GvIxLAOD
143 assert response.status_code == 200 1GvIxLAOD
144 assert response.json() == {"p": None} 1GvIxLAOD
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) 2F u bbcbK z N C
153 response = client.post(path, data={"p_alias": ["hello", "world"]}) 2F u bbcbK z N C
154 assert response.status_code == 200 2F u bbcbK z N C
155 assert response.json() == {"p": ["hello", "world"]} 2F u bbcbK z N C
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} 1QRSTUVWXYZ
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} 10123456789
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() 2BbCbDbEbFbGbHbIb
191 body_model_name = get_body_model_name(openapi, path) 2BbCbDbEbFbGbHbIb
193 assert app.openapi()["components"]["schemas"][body_model_name] == { 2BbCbDbEbFbGbHbIb
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) 12S3T6W9Z
214 response = client.post(path) 12S3T6W9Z
215 assert response.status_code == 200 12S3T6W9Z
216 assert response.json() == {"p": None} 12S3T6W9Z
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) 20 Q dbeb4 U 7 X
228 response = client.post(path, data={"p": ["hello", "world"]}) 20 Q dbeb4 U 7 X
229 assert response.status_code == 200 20 Q dbeb4 U 7 X
230 assert response.json() == {"p": None} 20 Q dbeb4 U 7 X
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) 21 R fbgb5 V 8 Y
239 response = client.post(path, data={"p_val_alias": ["hello", "world"]}) 21 R fbgb5 V 8 Y
240 assert response.status_code == 200, response.text 21 R fbgb5 V 8 Y
241 assert response.json() == {"p": ["hello", "world"]} 21 R fbgb5 V 8 Y
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} 1!#$%'()*+,-./:
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} 2; = ? @ [ ] ^ _ ` { | } ~ ab
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() 2JbKbLbMbNbObPb
283 body_model_name = get_body_model_name(openapi, path) 2JbKbLbMbNbObPb
285 assert app.openapi()["components"]["schemas"][body_model_name] == { 2JbKbLbMbNbObPb
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) 2@ % ] ( { , ab:
309 response = client.post(path) 2@ % ] ( { , ab:
310 assert response.status_code == 200 2@ % ] ( { , ab:
311 assert response.json() == {"p": None} 2@ % ] ( { , ab:
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) 2= # hbib_ * } .
323 response = client.post(path, data={"p": ["hello", "world"]}) 2= # hbib_ * } .
324 assert response.status_code == 200 2= # hbib_ * } .
325 assert response.json() == {"p": None} 2= # hbib_ * } .
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) 1;!['^)|-
337 response = client.post(path, data={"p_alias": ["hello", "world"]}) 1;!['^)|-
338 assert response.status_code == 200 1;!['^)|-
339 assert response.json() == {"p": None} 1;!['^)|-
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) 2? $ jbkb` + ~ /
351 response = client.post(path, data={"p_val_alias": ["hello", "world"]}) 2? $ jbkb` + ~ /
352 assert response.status_code == 200, response.text 2? $ jbkb` + ~ /
353 assert response.json() == { 2? $ jbkb` + ~ /
354 "p": [
355 "hello",
356 "world",
357 ]
358 }