Coverage for tests / test_request_params / test_query / test_list.py: 100%
124 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 1abcd
3import pytest 1abcd
4from dirty_equals import IsOneOf 1abcd
5from fastapi import FastAPI, Query 1abcd
6from fastapi.testclient import TestClient 1abcd
7from inline_snapshot import snapshot 1abcd
8from pydantic import BaseModel, Field 1abcd
10app = FastAPI() 1abcd
12# =====================================================================================
13# Without aliases
16@app.get("/required-list-str") 1abcd
17async def read_required_list_str(p: Annotated[list[str], Query()]): 1abcd
18 return {"p": p} 1efg
21class QueryModelRequiredListStr(BaseModel): 1abcd
22 p: list[str] 1abcd
25@app.get("/model-required-list-str") 1abcd
26def read_model_required_list_str(p: Annotated[QueryModelRequiredListStr, Query()]): 1abcd
27 return {"p": p.p} 1efg
30@pytest.mark.parametrize( 1abcd
31 "path",
32 ["/required-list-str", "/model-required-list-str"],
33)
34def test_required_list_str_schema(path: str): 1abcd
35 assert app.openapi()["paths"][path]["get"]["parameters"] == snapshot( 1OPQ
36 [
37 {
38 "required": True,
39 "schema": {
40 "title": "P",
41 "type": "array",
42 "items": {"type": "string"},
43 },
44 "name": "p",
45 "in": "query",
46 }
47 ]
48 )
51@pytest.mark.parametrize( 1abcd
52 "path",
53 ["/required-list-str", "/model-required-list-str"],
54)
55def test_required_list_str_missing(path: str): 1abcd
56 client = TestClient(app) 1qrs
57 response = client.get(path) 1qrs
58 assert response.status_code == 422 1qrs
59 assert response.json() == { 1qrs
60 "detail": [
61 {
62 "type": "missing",
63 "loc": ["query", "p"],
64 "msg": "Field required",
65 "input": IsOneOf(None, {}),
66 }
67 ]
68 }
71@pytest.mark.parametrize( 1abcd
72 "path",
73 ["/required-list-str", "/model-required-list-str"],
74)
75def test_required_list_str(path: str): 1abcd
76 client = TestClient(app) 1efg
77 response = client.get(f"{path}?p=hello&p=world") 1efg
78 assert response.status_code == 200 1efg
79 assert response.json() == {"p": ["hello", "world"]} 1efg
82# =====================================================================================
83# Alias
86@app.get("/required-list-alias") 1abcd
87async def read_required_list_alias(p: Annotated[list[str], Query(alias="p_alias")]): 1abcd
88 return {"p": p} 1hij
91class QueryModelRequiredListAlias(BaseModel): 1abcd
92 p: list[str] = Field(alias="p_alias") 1abcd
95@app.get("/model-required-list-alias") 1abcd
96async def read_model_required_list_alias( 1abcd
97 p: Annotated[QueryModelRequiredListAlias, Query()],
98):
99 return {"p": p.p} 1hij
102@pytest.mark.parametrize( 1abcd
103 "path",
104 ["/required-list-alias", "/model-required-list-alias"],
105)
106def test_required_list_str_alias_schema(path: str): 1abcd
107 assert app.openapi()["paths"][path]["get"]["parameters"] == snapshot( 1RST
108 [
109 {
110 "required": True,
111 "schema": {
112 "title": "P Alias",
113 "type": "array",
114 "items": {"type": "string"},
115 },
116 "name": "p_alias",
117 "in": "query",
118 }
119 ]
120 )
123@pytest.mark.parametrize( 1abcd
124 "path",
125 ["/required-list-alias", "/model-required-list-alias"],
126)
127def test_required_list_alias_missing(path: str): 1abcd
128 client = TestClient(app) 1tuv
129 response = client.get(path) 1tuv
130 assert response.status_code == 422 1tuv
131 assert response.json() == { 1tuv
132 "detail": [
133 {
134 "type": "missing",
135 "loc": ["query", "p_alias"],
136 "msg": "Field required",
137 "input": IsOneOf(None, {}),
138 }
139 ]
140 }
143@pytest.mark.parametrize( 1abcd
144 "path",
145 [
146 "/required-list-alias",
147 "/model-required-list-alias",
148 ],
149)
150def test_required_list_alias_by_name(path: str): 1abcd
151 client = TestClient(app) 1wxy
152 response = client.get(f"{path}?p=hello&p=world") 1wxy
153 assert response.status_code == 422 1wxy
154 assert response.json() == { 1wxy
155 "detail": [
156 {
157 "type": "missing",
158 "loc": ["query", "p_alias"],
159 "msg": "Field required",
160 "input": IsOneOf(None, {"p": ["hello", "world"]}),
161 }
162 ]
163 }
166@pytest.mark.parametrize( 1abcd
167 "path",
168 [
169 "/required-list-alias",
170 "/model-required-list-alias",
171 ],
172)
173def test_required_list_alias_by_alias(path: str): 1abcd
174 client = TestClient(app) 1hij
175 response = client.get(f"{path}?p_alias=hello&p_alias=world") 1hij
176 assert response.status_code == 200, response.text 1hij
177 assert response.json() == {"p": ["hello", "world"]} 1hij
180# =====================================================================================
181# Validation alias
184@app.get("/required-list-validation-alias") 1abcd
185def read_required_list_validation_alias( 1abcd
186 p: Annotated[list[str], Query(validation_alias="p_val_alias")],
187):
188 return {"p": p} 1klm
191class QueryModelRequiredListValidationAlias(BaseModel): 1abcd
192 p: list[str] = Field(validation_alias="p_val_alias") 1abcd
195@app.get("/model-required-list-validation-alias") 1abcd
196async def read_model_required_list_validation_alias( 1abcd
197 p: Annotated[QueryModelRequiredListValidationAlias, Query()],
198):
199 return {"p": p.p} 1klm
202@pytest.mark.parametrize( 1abcd
203 "path",
204 ["/required-list-validation-alias", "/model-required-list-validation-alias"],
205)
206def test_required_list_validation_alias_schema(path: str): 1abcd
207 assert app.openapi()["paths"][path]["get"]["parameters"] == snapshot( 1UVW
208 [
209 {
210 "required": True,
211 "schema": {
212 "title": "P Val Alias",
213 "type": "array",
214 "items": {"type": "string"},
215 },
216 "name": "p_val_alias",
217 "in": "query",
218 }
219 ]
220 )
223@pytest.mark.parametrize( 1abcd
224 "path",
225 [
226 "/required-list-validation-alias",
227 "/model-required-list-validation-alias",
228 ],
229)
230def test_required_list_validation_alias_missing(path: str): 1abcd
231 client = TestClient(app) 1zAB
232 response = client.get(path) 1zAB
233 assert response.status_code == 422 1zAB
234 assert response.json() == { 1zAB
235 "detail": [
236 {
237 "type": "missing",
238 "loc": [
239 "query",
240 "p_val_alias",
241 ],
242 "msg": "Field required",
243 "input": IsOneOf(None, {}),
244 }
245 ]
246 }
249@pytest.mark.parametrize( 1abcd
250 "path",
251 [
252 "/required-list-validation-alias",
253 "/model-required-list-validation-alias",
254 ],
255)
256def test_required_list_validation_alias_by_name(path: str): 1abcd
257 client = TestClient(app) 1CDE
258 response = client.get(f"{path}?p=hello&p=world") 1CDE
259 assert response.status_code == 422 1CDE
261 assert response.json() == { 1CDE
262 "detail": [
263 {
264 "type": "missing",
265 "loc": ["query", "p_val_alias"],
266 "msg": "Field required",
267 "input": IsOneOf(None, {"p": ["hello", "world"]}),
268 }
269 ]
270 }
273@pytest.mark.parametrize( 1abcd
274 "path",
275 ["/required-list-validation-alias", "/model-required-list-validation-alias"],
276)
277def test_required_list_validation_alias_by_validation_alias(path: str): 1abcd
278 client = TestClient(app) 1klm
279 response = client.get(f"{path}?p_val_alias=hello&p_val_alias=world") 1klm
280 assert response.status_code == 200, response.text 1klm
282 assert response.json() == {"p": ["hello", "world"]} 1klm
285# =====================================================================================
286# Alias and validation alias
289@app.get("/required-list-alias-and-validation-alias") 1abcd
290def read_required_list_alias_and_validation_alias( 1abcd
291 p: Annotated[list[str], Query(alias="p_alias", validation_alias="p_val_alias")],
292):
293 return {"p": p} 1nop
296class QueryModelRequiredListAliasAndValidationAlias(BaseModel): 1abcd
297 p: list[str] = Field(alias="p_alias", validation_alias="p_val_alias") 1abcd
300@app.get("/model-required-list-alias-and-validation-alias") 1abcd
301def read_model_required_list_alias_and_validation_alias( 1abcd
302 p: Annotated[QueryModelRequiredListAliasAndValidationAlias, Query()],
303):
304 return {"p": p.p} 1nop
307@pytest.mark.parametrize( 1abcd
308 "path",
309 [
310 "/required-list-alias-and-validation-alias",
311 "/model-required-list-alias-and-validation-alias",
312 ],
313)
314def test_required_list_alias_and_validation_alias_schema(path: str): 1abcd
315 assert app.openapi()["paths"][path]["get"]["parameters"] == snapshot( 1XYZ
316 [
317 {
318 "required": True,
319 "schema": {
320 "title": "P Val Alias",
321 "type": "array",
322 "items": {"type": "string"},
323 },
324 "name": "p_val_alias",
325 "in": "query",
326 }
327 ]
328 )
331@pytest.mark.parametrize( 1abcd
332 "path",
333 [
334 "/required-list-alias-and-validation-alias",
335 "/model-required-list-alias-and-validation-alias",
336 ],
337)
338def test_required_list_alias_and_validation_alias_missing(path: str): 1abcd
339 client = TestClient(app) 1FGH
340 response = client.get(path) 1FGH
341 assert response.status_code == 422 1FGH
342 assert response.json() == { 1FGH
343 "detail": [
344 {
345 "type": "missing",
346 "loc": [
347 "query",
348 "p_val_alias",
349 ],
350 "msg": "Field required",
351 "input": IsOneOf(None, {}),
352 }
353 ]
354 }
357@pytest.mark.parametrize( 1abcd
358 "path",
359 [
360 "/required-list-alias-and-validation-alias",
361 "/model-required-list-alias-and-validation-alias",
362 ],
363)
364def test_required_list_alias_and_validation_alias_by_name(path: str): 1abcd
365 client = TestClient(app) 1IJK
366 response = client.get(f"{path}?p=hello&p=world") 1IJK
367 assert response.status_code == 422 1IJK
368 assert response.json() == { 1IJK
369 "detail": [
370 {
371 "type": "missing",
372 "loc": [
373 "query",
374 "p_val_alias",
375 ],
376 "msg": "Field required",
377 "input": IsOneOf(
378 None,
379 {
380 "p": [
381 "hello",
382 "world",
383 ]
384 },
385 ),
386 }
387 ]
388 }
391@pytest.mark.parametrize( 1abcd
392 "path",
393 [
394 "/required-list-alias-and-validation-alias",
395 "/model-required-list-alias-and-validation-alias",
396 ],
397)
398def test_required_list_alias_and_validation_alias_by_alias(path: str): 1abcd
399 client = TestClient(app) 1LMN
400 response = client.get(f"{path}?p_alias=hello&p_alias=world") 1LMN
401 assert response.status_code == 422 1LMN
402 assert response.json() == { 1LMN
403 "detail": [
404 {
405 "type": "missing",
406 "loc": ["query", "p_val_alias"],
407 "msg": "Field required",
408 "input": IsOneOf(
409 None,
410 {"p_alias": ["hello", "world"]},
411 ),
412 }
413 ]
414 }
417@pytest.mark.parametrize( 1abcd
418 "path",
419 [
420 "/required-list-alias-and-validation-alias",
421 "/model-required-list-alias-and-validation-alias",
422 ],
423)
424def test_required_list_alias_and_validation_alias_by_validation_alias(path: str): 1abcd
425 client = TestClient(app) 1nop
426 response = client.get(f"{path}?p_val_alias=hello&p_val_alias=world") 1nop
427 assert response.status_code == 200, response.text 1nop
428 assert response.json() == {"p": ["hello", "world"]} 1nop