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-04-06 01:24 +0000

1from typing import Annotated 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[list[str] | None, Header()] = None, 

18): 

19 return {"p": p} 1efghijkl

20 

21 

22class HeaderModelOptionalListStr(BaseModel): 1abcd

23 p: list[str] | None = 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} 1mnopqrst

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( 2kblbmbnbobpbqbrb

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) 1nfphrjtl

62 response = client.get(path) 1nfphrjtl

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

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

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) 1meogqisk

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

74 assert response.status_code == 200 1meogqisk

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

76 

77 

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

79# Alias 

80 

81 

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

83async def read_optional_list_alias( 1abcd

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

85): 

86 return {"p": p} 1uvwxyzABCDE

87 

88 

89class HeaderModelOptionalListAlias(BaseModel): 1abcd

90 p: list[str] | None = 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} 1FGHIJKLMNOP

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( 2sbtbubvbwbxbybzb

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) 1HwJyMBPE

129 response = client.get(path) 1HwJyMBPE

130 assert response.status_code == 200 1HwJyMBPE

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

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) 2G v abbbL A O D

140 response = client.get(path, headers=[("p", "hello"), ("p", "world")]) 2G v abbbL A O D

141 assert response.status_code == 200 2G v abbbL A O D

142 assert response.json() == {"p": None} 2G v abbbL A O D

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) 1FuIxKzNC

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

155 assert response.status_code == 200 1FuIxKzNC

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

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[list[str] | None, Header(validation_alias="p_val_alias")] = None, 

166): 

167 return {"p": p} 1QRSTUVWXYZ0

168 

169 

170class HeaderModelOptionalListValidationAlias(BaseModel): 1abcd

171 p: list[str] | None = 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} 21 2 3 Ab4 5 6 7 8 9 !

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( 2BbCbDbEbFbGbHbIb

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) 13S4U7X!0

210 response = client.get(path) 13S4U7X!0

211 assert response.status_code == 200 13S4U7X!0

212 assert response.json() == {"p": None} 13S4U7X!0

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) 21 Q cb5 V 8 Y

224 response = client.get(path, headers=[("p", "hello"), ("p", "world")]) 21 Q cb5 V 8 Y

225 assert response.status_code == 200 21 Q cb5 V 8 Y

226 assert response.json() == {"p": None} 21 Q cb5 V 8 Y

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) 22 R dbT 6 W 9 Z

235 response = client.get( 22 R dbT 6 W 9 Z

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

237 ) 

238 assert response.status_code == 200, response.text 22 R dbT 6 W 9 Z

239 assert response.json() == {"p": ["hello", "world"]} 22 R dbT 6 W 9 Z

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 list[str] | None, Header(alias="p_alias", validation_alias="p_val_alias") 

250 ] = None, 

251): 

252 return {"p": p} 1#$%'()*+,-./:

253 

254 

255class HeaderModelOptionalListAliasAndValidationAlias(BaseModel): 1abcd

256 p: list[str] | None = Field(None, alias="p_alias", validation_alias="p_val_alias") 1abcd

257 

258 

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

260def read_model_optional_list_alias_and_validation_alias( 1abcd

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

262): 

263 return {"p": p.p} 1;=?@[]^_`{|}~

264 

265 

266@pytest.mark.parametrize( 1abcd

267 "path", 

268 [ 

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

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

271 ], 

272) 

273def test_optional_list_alias_and_validation_alias_schema(path: str): 1abcd

274 assert app.openapi()["paths"][path]["get"]["parameters"] == snapshot( 2JbKbLbMbNbObPbQb

275 [ 

276 { 

277 "required": False, 

278 "schema": { 

279 "anyOf": [ 

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

281 {"type": "null"}, 

282 ], 

283 "title": "P Val Alias", 

284 }, 

285 "name": "p_val_alias", 

286 "in": "header", 

287 } 

288 ] 

289 ) 

290 

291 

292@pytest.mark.parametrize( 1abcd

293 "path", 

294 [ 

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

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

297 ], 

298) 

299def test_optional_list_alias_and_validation_alias_missing(path: str): 1abcd

300 client = TestClient(app) 1@'[(`,~:

301 response = client.get(path) 1@'[(`,~:

302 assert response.status_code == 200 1@'[(`,~:

303 assert response.json() == {"p": None} 1@'[(`,~:

304 

305 

306@pytest.mark.parametrize( 1abcd

307 "path", 

308 [ 

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

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

311 ], 

312) 

313def test_optional_list_alias_and_validation_alias_by_name(path: str): 1abcd

314 client = TestClient(app) 2= $ ebfb^ * | .

315 response = client.get(path, headers=[("p", "hello"), ("p", "world")]) 2= $ ebfb^ * | .

316 assert response.status_code == 200 2= $ ebfb^ * | .

317 assert response.json() == {"p": None} 2= $ ebfb^ * | .

318 

319 

320@pytest.mark.parametrize( 1abcd

321 "path", 

322 [ 

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

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

325 ], 

326) 

327def test_optional_list_alias_and_validation_alias_by_alias(path: str): 1abcd

328 client = TestClient(app) 2; # gbhb] ) { -

329 response = client.get(path, headers=[("p_alias", "hello"), ("p_alias", "world")]) 2; # gbhb] ) { -

330 assert response.status_code == 200 2; # gbhb] ) { -

331 assert response.json() == {"p": None} 2; # gbhb] ) { -

332 

333 

334@pytest.mark.parametrize( 1abcd

335 "path", 

336 [ 

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

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

339 ], 

340) 

341def test_optional_list_alias_and_validation_alias_by_validation_alias(path: str): 1abcd

342 client = TestClient(app) 2? % ibjb_ + } /

343 response = client.get( 2? % ibjb_ + } /

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

345 ) 

346 assert response.status_code == 200, response.text 2? % ibjb_ + } /

347 assert response.json() == { 2? % ibjb_ + } /

348 "p": [ 

349 "hello", 

350 "world", 

351 ] 

352 }