Coverage for tests / test_request_params / test_header / 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 AnyThing, IsOneOf, IsPartialDict 1abcd
5from fastapi import FastAPI, Header 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], Header()]): 1abcd
18 return {"p": p} 1efg
21class HeaderModelRequiredListStr(BaseModel): 1abcd
22 p: list[str] 1abcd
25@app.get("/model-required-list-str") 1abcd
26def read_model_required_list_str(p: Annotated[HeaderModelRequiredListStr, Header()]): 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": "header",
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": ["header", "p"],
64 "msg": "Field required",
65 "input": AnyThing,
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(path, headers=[("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], Header(alias="p_alias")]): 1abcd
88 return {"p": p} 1hij
91class HeaderModelRequiredListAlias(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[HeaderModelRequiredListAlias, Header()],
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": "header",
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": ["header", "p_alias"],
136 "msg": "Field required",
137 "input": AnyThing,
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(path, headers=[("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": ["header", "p_alias"],
159 "msg": "Field required",
160 "input": IsOneOf(None, IsPartialDict({"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(path, headers=[("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], Header(validation_alias="p_val_alias")],
187):
188 return {"p": p} 1klm
191class HeaderModelRequiredListValidationAlias(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[HeaderModelRequiredListValidationAlias, Header()],
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": "header",
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 "header",
240 "p_val_alias",
241 ],
242 "msg": "Field required",
243 "input": AnyThing,
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(path, headers=[("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": ["header", "p_val_alias"],
266 "msg": "Field required",
267 "input": IsOneOf(None, IsPartialDict({"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( 1klm
280 path, headers=[("p_val_alias", "hello"), ("p_val_alias", "world")]
281 )
282 assert response.status_code == 200, response.text 1klm
284 assert response.json() == {"p": ["hello", "world"]} 1klm
287# =====================================================================================
288# Alias and validation alias
291@app.get("/required-list-alias-and-validation-alias") 1abcd
292def read_required_list_alias_and_validation_alias( 1abcd
293 p: Annotated[list[str], Header(alias="p_alias", validation_alias="p_val_alias")],
294):
295 return {"p": p} 1nop
298class HeaderModelRequiredListAliasAndValidationAlias(BaseModel): 1abcd
299 p: list[str] = Field(alias="p_alias", validation_alias="p_val_alias") 1abcd
302@app.get("/model-required-list-alias-and-validation-alias") 1abcd
303def read_model_required_list_alias_and_validation_alias( 1abcd
304 p: Annotated[HeaderModelRequiredListAliasAndValidationAlias, Header()],
305):
306 return {"p": p.p} 1nop
309@pytest.mark.parametrize( 1abcd
310 "path",
311 [
312 "/required-list-alias-and-validation-alias",
313 "/model-required-list-alias-and-validation-alias",
314 ],
315)
316def test_required_list_alias_and_validation_alias_schema(path: str): 1abcd
317 assert app.openapi()["paths"][path]["get"]["parameters"] == snapshot( 1XYZ
318 [
319 {
320 "required": True,
321 "schema": {
322 "title": "P Val Alias",
323 "type": "array",
324 "items": {"type": "string"},
325 },
326 "name": "p_val_alias",
327 "in": "header",
328 }
329 ]
330 )
333@pytest.mark.parametrize( 1abcd
334 "path",
335 [
336 "/required-list-alias-and-validation-alias",
337 "/model-required-list-alias-and-validation-alias",
338 ],
339)
340def test_required_list_alias_and_validation_alias_missing(path: str): 1abcd
341 client = TestClient(app) 1FGH
342 response = client.get(path) 1FGH
343 assert response.status_code == 422 1FGH
344 assert response.json() == { 1FGH
345 "detail": [
346 {
347 "type": "missing",
348 "loc": [
349 "header",
350 "p_val_alias",
351 ],
352 "msg": "Field required",
353 "input": AnyThing,
354 }
355 ]
356 }
359@pytest.mark.parametrize( 1abcd
360 "path",
361 [
362 "/required-list-alias-and-validation-alias",
363 "/model-required-list-alias-and-validation-alias",
364 ],
365)
366def test_required_list_alias_and_validation_alias_by_name(path: str): 1abcd
367 client = TestClient(app) 1IJK
368 response = client.get(path, headers=[("p", "hello"), ("p", "world")]) 1IJK
369 assert response.status_code == 422 1IJK
370 assert response.json() == { 1IJK
371 "detail": [
372 {
373 "type": "missing",
374 "loc": [
375 "header",
376 "p_val_alias",
377 ],
378 "msg": "Field required",
379 "input": IsOneOf(
380 None,
381 IsPartialDict({"p": ["hello", "world"]}),
382 ),
383 }
384 ]
385 }
388@pytest.mark.parametrize( 1abcd
389 "path",
390 [
391 "/required-list-alias-and-validation-alias",
392 "/model-required-list-alias-and-validation-alias",
393 ],
394)
395def test_required_list_alias_and_validation_alias_by_alias(path: str): 1abcd
396 client = TestClient(app) 1LMN
397 response = client.get(path, headers=[("p_alias", "hello"), ("p_alias", "world")]) 1LMN
398 assert response.status_code == 422 1LMN
399 assert response.json() == { 1LMN
400 "detail": [
401 {
402 "type": "missing",
403 "loc": ["header", "p_val_alias"],
404 "msg": "Field required",
405 "input": IsOneOf(
406 None,
407 IsPartialDict({"p_alias": ["hello", "world"]}),
408 ),
409 }
410 ]
411 }
414@pytest.mark.parametrize( 1abcd
415 "path",
416 [
417 "/required-list-alias-and-validation-alias",
418 "/model-required-list-alias-and-validation-alias",
419 ],
420)
421def test_required_list_alias_and_validation_alias_by_validation_alias(path: str): 1abcd
422 client = TestClient(app) 1nop
423 response = client.get( 1nop
424 path, headers=[("p_val_alias", "hello"), ("p_val_alias", "world")]
425 )
426 assert response.status_code == 200, response.text 1nop
427 assert response.json() == {"p": ["hello", "world"]} 1nop