Coverage for tests / test_request_params / test_header / test_optional_list.py: 100%

123 statements  

« prev     ^ index     » next       coverage.py v7.13.3, created at 2026-02-12 18:15 +0000

1from typing import Annotated, Optional 1abcd

2 

3import pytest 1abcd

4from fastapi import FastAPI, Header 1abcd

5from fastapi.testclient import TestClient 1abcd

6from inline_snapshot import snapshot 1abcd

7from pydantic import BaseModel, Field 1abcd

8 

9app = FastAPI() 1abcd

10 

11# ===================================================================================== 

12# Without aliases 

13 

14 

15@app.get("/optional-list-str") 1abcd

16async def read_optional_list_str( 1abcd

17 p: Annotated[Optional[list[str]], Header()] = None, 

18): 

19 return {"p": p} 1efghij

20 

21 

22class HeaderModelOptionalListStr(BaseModel): 1abcd

23 p: Optional[list[str]] = None 1abcd

24 

25 

26@app.get("/model-optional-list-str") 1abcd

27async def read_model_optional_list_str( 1abcd

28 p: Annotated[HeaderModelOptionalListStr, Header()], 

29): 

30 return {"p": p.p} 1efghij

31 

32 

33@pytest.mark.parametrize( 1abcd

34 "path", 

35 ["/optional-list-str", "/model-optional-list-str"], 

36) 

37def test_optional_list_str_schema(path: str): 1abcd

38 assert app.openapi()["paths"][path]["get"]["parameters"] == snapshot( 1OPQ

39 [ 

40 { 

41 "required": False, 

42 "schema": { 

43 "anyOf": [ 

44 {"items": {"type": "string"}, "type": "array"}, 

45 {"type": "null"}, 

46 ], 

47 "title": "P", 

48 }, 

49 "name": "p", 

50 "in": "header", 

51 } 

52 ] 

53 ) 

54 

55 

56@pytest.mark.parametrize( 1abcd

57 "path", 

58 ["/optional-list-str", "/model-optional-list-str"], 

59) 

60def test_optional_list_str_missing(path: str): 1abcd

61 client = TestClient(app) 1fhj

62 response = client.get(path) 1fhj

63 assert response.status_code == 200, response.text 1fhj

64 assert response.json() == {"p": None} 1fhj

65 

66 

67@pytest.mark.parametrize( 1abcd

68 "path", 

69 ["/optional-list-str", "/model-optional-list-str"], 

70) 

71def test_optional_list_str(path: str): 1abcd

72 client = TestClient(app) 1egi

73 response = client.get(path, headers=[("p", "hello"), ("p", "world")]) 1egi

74 assert response.status_code == 200 1egi

75 assert response.json() == {"p": ["hello", "world"]} 1egi

76 

77 

78# ===================================================================================== 

79# Alias 

80 

81 

82@app.get("/optional-list-alias") 1abcd

83async def read_optional_list_alias( 1abcd

84 p: Annotated[Optional[list[str]], Header(alias="p_alias")] = None, 

85): 

86 return {"p": p} 1klmnopqrs

87 

88 

89class HeaderModelOptionalListAlias(BaseModel): 1abcd

90 p: Optional[list[str]] = Field(None, alias="p_alias") 1abcd

91 

92 

93@app.get("/model-optional-list-alias") 1abcd

94async def read_model_optional_list_alias( 1abcd

95 p: Annotated[HeaderModelOptionalListAlias, Header()], 

96): 

97 return {"p": p.p} 1klmnopqrs

98 

99 

100@pytest.mark.parametrize( 1abcd

101 "path", 

102 ["/optional-list-alias", "/model-optional-list-alias"], 

103) 

104def test_optional_list_str_alias_schema(path: str): 1abcd

105 assert app.openapi()["paths"][path]["get"]["parameters"] == snapshot( 1RST

106 [ 

107 { 

108 "required": False, 

109 "schema": { 

110 "anyOf": [ 

111 {"items": {"type": "string"}, "type": "array"}, 

112 {"type": "null"}, 

113 ], 

114 "title": "P Alias", 

115 }, 

116 "name": "p_alias", 

117 "in": "header", 

118 } 

119 ] 

120 ) 

121 

122 

123@pytest.mark.parametrize( 1abcd

124 "path", 

125 ["/optional-list-alias", "/model-optional-list-alias"], 

126) 

127def test_optional_list_alias_missing(path: str): 1abcd

128 client = TestClient(app) 1mps

129 response = client.get(path) 1mps

130 assert response.status_code == 200 1mps

131 assert response.json() == {"p": None} 1mps

132 

133 

134@pytest.mark.parametrize( 1abcd

135 "path", 

136 ["/optional-list-alias", "/model-optional-list-alias"], 

137) 

138def test_optional_list_alias_by_name(path: str): 1abcd

139 client = TestClient(app) 1lor

140 response = client.get(path, headers=[("p", "hello"), ("p", "world")]) 1lor

141 assert response.status_code == 200 1lor

142 assert response.json() == {"p": None} 1lor

143 

144 

145@pytest.mark.parametrize( 1abcd

146 "path", 

147 [ 

148 "/optional-list-alias", 

149 "/model-optional-list-alias", 

150 ], 

151) 

152def test_optional_list_alias_by_alias(path: str): 1abcd

153 client = TestClient(app) 1knq

154 response = client.get(path, headers=[("p_alias", "hello"), ("p_alias", "world")]) 1knq

155 assert response.status_code == 200 1knq

156 assert response.json() == {"p": ["hello", "world"]} 1knq

157 

158 

159# ===================================================================================== 

160# Validation alias 

161 

162 

163@app.get("/optional-list-validation-alias") 1abcd

164def read_optional_list_validation_alias( 1abcd

165 p: Annotated[Optional[list[str]], Header(validation_alias="p_val_alias")] = None, 

166): 

167 return {"p": p} 1tuvwxyzAB

168 

169 

170class HeaderModelOptionalListValidationAlias(BaseModel): 1abcd

171 p: Optional[list[str]] = Field(None, validation_alias="p_val_alias") 1abcd

172 

173 

174@app.get("/model-optional-list-validation-alias") 1abcd

175def read_model_optional_list_validation_alias( 1abcd

176 p: Annotated[HeaderModelOptionalListValidationAlias, Header()], 

177): 

178 return {"p": p.p} 1tuvwxyzAB

179 

180 

181@pytest.mark.parametrize( 1abcd

182 "path", 

183 ["/optional-list-validation-alias", "/model-optional-list-validation-alias"], 

184) 

185def test_optional_list_validation_alias_schema(path: str): 1abcd

186 assert app.openapi()["paths"][path]["get"]["parameters"] == snapshot( 1UVW

187 [ 

188 { 

189 "required": False, 

190 "schema": { 

191 "anyOf": [ 

192 {"items": {"type": "string"}, "type": "array"}, 

193 {"type": "null"}, 

194 ], 

195 "title": "P Val Alias", 

196 }, 

197 "name": "p_val_alias", 

198 "in": "header", 

199 } 

200 ] 

201 ) 

202 

203 

204@pytest.mark.parametrize( 1abcd

205 "path", 

206 ["/optional-list-validation-alias", "/model-optional-list-validation-alias"], 

207) 

208def test_optional_list_validation_alias_missing(path: str): 1abcd

209 client = TestClient(app) 1vyB

210 response = client.get(path) 1vyB

211 assert response.status_code == 200 1vyB

212 assert response.json() == {"p": None} 1vyB

213 

214 

215@pytest.mark.parametrize( 1abcd

216 "path", 

217 [ 

218 "/optional-list-validation-alias", 

219 "/model-optional-list-validation-alias", 

220 ], 

221) 

222def test_optional_list_validation_alias_by_name(path: str): 1abcd

223 client = TestClient(app) 1twz

224 response = client.get(path, headers=[("p", "hello"), ("p", "world")]) 1twz

225 assert response.status_code == 200 1twz

226 assert response.json() == {"p": None} 1twz

227 

228 

229@pytest.mark.parametrize( 1abcd

230 "path", 

231 ["/optional-list-validation-alias", "/model-optional-list-validation-alias"], 

232) 

233def test_optional_list_validation_alias_by_validation_alias(path: str): 1abcd

234 client = TestClient(app) 1uxA

235 response = client.get( 1uxA

236 path, headers=[("p_val_alias", "hello"), ("p_val_alias", "world")] 

237 ) 

238 assert response.status_code == 200, response.text 1uxA

239 assert response.json() == {"p": ["hello", "world"]} 1uxA

240 

241 

242# ===================================================================================== 

243# Alias and validation alias 

244 

245 

246@app.get("/optional-list-alias-and-validation-alias") 1abcd

247def read_optional_list_alias_and_validation_alias( 1abcd

248 p: Annotated[ 

249 Optional[list[str]], Header(alias="p_alias", validation_alias="p_val_alias") 

250 ] = None, 

251): 

252 return {"p": p} 1CDEFGHIJKLMN

253 

254 

255class HeaderModelOptionalListAliasAndValidationAlias(BaseModel): 1abcd

256 p: Optional[list[str]] = Field( 1abcd

257 None, alias="p_alias", validation_alias="p_val_alias" 

258 ) 

259 

260 

261@app.get("/model-optional-list-alias-and-validation-alias") 1abcd

262def read_model_optional_list_alias_and_validation_alias( 1abcd

263 p: Annotated[HeaderModelOptionalListAliasAndValidationAlias, Header()], 

264): 

265 return {"p": p.p} 1CDEFGHIJKLMN

266 

267 

268@pytest.mark.parametrize( 1abcd

269 "path", 

270 [ 

271 "/optional-list-alias-and-validation-alias", 

272 "/model-optional-list-alias-and-validation-alias", 

273 ], 

274) 

275def test_optional_list_alias_and_validation_alias_schema(path: str): 1abcd

276 assert app.openapi()["paths"][path]["get"]["parameters"] == snapshot( 1XYZ

277 [ 

278 { 

279 "required": False, 

280 "schema": { 

281 "anyOf": [ 

282 {"items": {"type": "string"}, "type": "array"}, 

283 {"type": "null"}, 

284 ], 

285 "title": "P Val Alias", 

286 }, 

287 "name": "p_val_alias", 

288 "in": "header", 

289 } 

290 ] 

291 ) 

292 

293 

294@pytest.mark.parametrize( 1abcd

295 "path", 

296 [ 

297 "/optional-list-alias-and-validation-alias", 

298 "/model-optional-list-alias-and-validation-alias", 

299 ], 

300) 

301def test_optional_list_alias_and_validation_alias_missing(path: str): 1abcd

302 client = TestClient(app) 1FJN

303 response = client.get(path) 1FJN

304 assert response.status_code == 200 1FJN

305 assert response.json() == {"p": None} 1FJN

306 

307 

308@pytest.mark.parametrize( 1abcd

309 "path", 

310 [ 

311 "/optional-list-alias-and-validation-alias", 

312 "/model-optional-list-alias-and-validation-alias", 

313 ], 

314) 

315def test_optional_list_alias_and_validation_alias_by_name(path: str): 1abcd

316 client = TestClient(app) 1DHL

317 response = client.get(path, headers=[("p", "hello"), ("p", "world")]) 1DHL

318 assert response.status_code == 200 1DHL

319 assert response.json() == {"p": None} 1DHL

320 

321 

322@pytest.mark.parametrize( 1abcd

323 "path", 

324 [ 

325 "/optional-list-alias-and-validation-alias", 

326 "/model-optional-list-alias-and-validation-alias", 

327 ], 

328) 

329def test_optional_list_alias_and_validation_alias_by_alias(path: str): 1abcd

330 client = TestClient(app) 1CGK

331 response = client.get(path, headers=[("p_alias", "hello"), ("p_alias", "world")]) 1CGK

332 assert response.status_code == 200 1CGK

333 assert response.json() == {"p": None} 1CGK

334 

335 

336@pytest.mark.parametrize( 1abcd

337 "path", 

338 [ 

339 "/optional-list-alias-and-validation-alias", 

340 "/model-optional-list-alias-and-validation-alias", 

341 ], 

342) 

343def test_optional_list_alias_and_validation_alias_by_validation_alias(path: str): 1abcd

344 client = TestClient(app) 1EIM

345 response = client.get( 1EIM

346 path, headers=[("p_val_alias", "hello"), ("p_val_alias", "world")] 

347 ) 

348 assert response.status_code == 200, response.text 1EIM

349 assert response.json() == { 1EIM

350 "p": [ 

351 "hello", 

352 "world", 

353 ] 

354 }