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

124 statements  

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

1from typing import Annotated 1abcd

2 

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

9 

10app = FastAPI() 1abcd

11 

12# ===================================================================================== 

13# Without aliases 

14 

15 

16@app.get("/required-str") 1abcd

17async def read_required_str(p: Annotated[str, Header()]): 1abcd

18 return {"p": p} 1efg

19 

20 

21class HeaderModelRequiredStr(BaseModel): 1abcd

22 p: str 1abcd

23 

24 

25@app.get("/model-required-str") 1abcd

26async def read_model_required_str(p: Annotated[HeaderModelRequiredStr, Header()]): 1abcd

27 return {"p": p.p} 1efg

28 

29 

30@pytest.mark.parametrize( 1abcd

31 "path", 

32 ["/required-str", "/model-required-str"], 

33) 

34def test_required_str_schema(path: str): 1abcd

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

36 [ 

37 { 

38 "required": True, 

39 "schema": {"title": "P", "type": "string"}, 

40 "name": "p", 

41 "in": "header", 

42 } 

43 ] 

44 ) 

45 

46 

47@pytest.mark.parametrize( 1abcd

48 "path", 

49 ["/required-str", "/model-required-str"], 

50) 

51def test_required_str_missing(path: str): 1abcd

52 client = TestClient(app) 1qrs

53 response = client.get(path) 1qrs

54 assert response.status_code == 422 1qrs

55 assert response.json() == { 1qrs

56 "detail": [ 

57 { 

58 "type": "missing", 

59 "loc": ["header", "p"], 

60 "msg": "Field required", 

61 "input": AnyThing, 

62 } 

63 ] 

64 } 

65 

66 

67@pytest.mark.parametrize( 1abcd

68 "path", 

69 ["/required-str", "/model-required-str"], 

70) 

71def test_required_str(path: str): 1abcd

72 client = TestClient(app) 1efg

73 response = client.get(path, headers={"p": "hello"}) 1efg

74 assert response.status_code == 200 1efg

75 assert response.json() == {"p": "hello"} 1efg

76 

77 

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

79# Alias 

80 

81 

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

83async def read_required_alias(p: Annotated[str, Header(alias="p_alias")]): 1abcd

84 return {"p": p} 1hij

85 

86 

87class HeaderModelRequiredAlias(BaseModel): 1abcd

88 p: str = Field(alias="p_alias") 1abcd

89 

90 

91@app.get("/model-required-alias") 1abcd

92async def read_model_required_alias(p: Annotated[HeaderModelRequiredAlias, Header()]): 1abcd

93 return {"p": p.p} 1hij

94 

95 

96@pytest.mark.parametrize( 1abcd

97 "path", 

98 ["/required-alias", "/model-required-alias"], 

99) 

100def test_required_str_alias_schema(path: str): 1abcd

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

102 [ 

103 { 

104 "required": True, 

105 "schema": {"title": "P Alias", "type": "string"}, 

106 "name": "p_alias", 

107 "in": "header", 

108 } 

109 ] 

110 ) 

111 

112 

113@pytest.mark.parametrize( 1abcd

114 "path", 

115 ["/required-alias", "/model-required-alias"], 

116) 

117def test_required_alias_missing(path: str): 1abcd

118 client = TestClient(app) 1tuv

119 response = client.get(path) 1tuv

120 assert response.status_code == 422 1tuv

121 assert response.json() == { 1tuv

122 "detail": [ 

123 { 

124 "type": "missing", 

125 "loc": ["header", "p_alias"], 

126 "msg": "Field required", 

127 "input": AnyThing, 

128 } 

129 ] 

130 } 

131 

132 

133@pytest.mark.parametrize( 1abcd

134 "path", 

135 [ 

136 "/required-alias", 

137 "/model-required-alias", 

138 ], 

139) 

140def test_required_alias_by_name(path: str): 1abcd

141 client = TestClient(app) 1wxy

142 response = client.get(path, headers={"p": "hello"}) 1wxy

143 assert response.status_code == 422 1wxy

144 assert response.json() == { 1wxy

145 "detail": [ 

146 { 

147 "type": "missing", 

148 "loc": ["header", "p_alias"], 

149 "msg": "Field required", 

150 "input": IsOneOf(None, IsPartialDict({"p": "hello"})), 

151 } 

152 ] 

153 } 

154 

155 

156@pytest.mark.parametrize( 1abcd

157 "path", 

158 [ 

159 "/required-alias", 

160 "/model-required-alias", 

161 ], 

162) 

163def test_required_alias_by_alias(path: str): 1abcd

164 client = TestClient(app) 1hij

165 response = client.get(path, headers={"p_alias": "hello"}) 1hij

166 assert response.status_code == 200, response.text 1hij

167 assert response.json() == {"p": "hello"} 1hij

168 

169 

170# ===================================================================================== 

171# Validation alias 

172 

173 

174@app.get("/required-validation-alias") 1abcd

175def read_required_validation_alias( 1abcd

176 p: Annotated[str, Header(validation_alias="p_val_alias")], 

177): 

178 return {"p": p} 1klm

179 

180 

181class HeaderModelRequiredValidationAlias(BaseModel): 1abcd

182 p: str = Field(validation_alias="p_val_alias") 1abcd

183 

184 

185@app.get("/model-required-validation-alias") 1abcd

186def read_model_required_validation_alias( 1abcd

187 p: Annotated[HeaderModelRequiredValidationAlias, Header()], 

188): 

189 return {"p": p.p} 1klm

190 

191 

192@pytest.mark.parametrize( 1abcd

193 "path", 

194 ["/required-validation-alias", "/model-required-validation-alias"], 

195) 

196def test_required_validation_alias_schema(path: str): 1abcd

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

198 [ 

199 { 

200 "required": True, 

201 "schema": {"title": "P Val Alias", "type": "string"}, 

202 "name": "p_val_alias", 

203 "in": "header", 

204 } 

205 ] 

206 ) 

207 

208 

209@pytest.mark.parametrize( 1abcd

210 "path", 

211 [ 

212 "/required-validation-alias", 

213 "/model-required-validation-alias", 

214 ], 

215) 

216def test_required_validation_alias_missing(path: str): 1abcd

217 client = TestClient(app) 1zAB

218 response = client.get(path) 1zAB

219 assert response.status_code == 422 1zAB

220 assert response.json() == { 1zAB

221 "detail": [ 

222 { 

223 "type": "missing", 

224 "loc": [ 

225 "header", 

226 "p_val_alias", 

227 ], 

228 "msg": "Field required", 

229 "input": AnyThing, 

230 } 

231 ] 

232 } 

233 

234 

235@pytest.mark.parametrize( 1abcd

236 "path", 

237 [ 

238 "/required-validation-alias", 

239 "/model-required-validation-alias", 

240 ], 

241) 

242def test_required_validation_alias_by_name(path: str): 1abcd

243 client = TestClient(app) 1CDE

244 response = client.get(path, headers={"p": "hello"}) 1CDE

245 assert response.status_code == 422, response.text 1CDE

246 

247 assert response.json() == { 1CDE

248 "detail": [ 

249 { 

250 "type": "missing", 

251 "loc": ["header", "p_val_alias"], 

252 "msg": "Field required", 

253 "input": IsOneOf(None, IsPartialDict({"p": "hello"})), 

254 } 

255 ] 

256 } 

257 

258 

259@pytest.mark.parametrize( 1abcd

260 "path", 

261 [ 

262 "/required-validation-alias", 

263 "/model-required-validation-alias", 

264 ], 

265) 

266def test_required_validation_alias_by_validation_alias(path: str): 1abcd

267 client = TestClient(app) 1klm

268 response = client.get(path, headers={"p_val_alias": "hello"}) 1klm

269 assert response.status_code == 200, response.text 1klm

270 

271 assert response.json() == {"p": "hello"} 1klm

272 

273 

274# ===================================================================================== 

275# Alias and validation alias 

276 

277 

278@app.get("/required-alias-and-validation-alias") 1abcd

279def read_required_alias_and_validation_alias( 1abcd

280 p: Annotated[str, Header(alias="p_alias", validation_alias="p_val_alias")], 

281): 

282 return {"p": p} 1nop

283 

284 

285class HeaderModelRequiredAliasAndValidationAlias(BaseModel): 1abcd

286 p: str = Field(alias="p_alias", validation_alias="p_val_alias") 1abcd

287 

288 

289@app.get("/model-required-alias-and-validation-alias") 1abcd

290def read_model_required_alias_and_validation_alias( 1abcd

291 p: Annotated[HeaderModelRequiredAliasAndValidationAlias, Header()], 

292): 

293 return {"p": p.p} 1nop

294 

295 

296@pytest.mark.parametrize( 1abcd

297 "path", 

298 [ 

299 "/required-alias-and-validation-alias", 

300 "/model-required-alias-and-validation-alias", 

301 ], 

302) 

303def test_required_alias_and_validation_alias_schema(path: str): 1abcd

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

305 [ 

306 { 

307 "required": True, 

308 "schema": {"title": "P Val Alias", "type": "string"}, 

309 "name": "p_val_alias", 

310 "in": "header", 

311 } 

312 ] 

313 ) 

314 

315 

316@pytest.mark.parametrize( 1abcd

317 "path", 

318 [ 

319 "/required-alias-and-validation-alias", 

320 "/model-required-alias-and-validation-alias", 

321 ], 

322) 

323def test_required_alias_and_validation_alias_missing(path: str): 1abcd

324 client = TestClient(app) 1FGH

325 response = client.get(path) 1FGH

326 assert response.status_code == 422 1FGH

327 assert response.json() == { 1FGH

328 "detail": [ 

329 { 

330 "type": "missing", 

331 "loc": [ 

332 "header", 

333 "p_val_alias", 

334 ], 

335 "msg": "Field required", 

336 "input": AnyThing, 

337 } 

338 ] 

339 } 

340 

341 

342@pytest.mark.parametrize( 1abcd

343 "path", 

344 [ 

345 "/required-alias-and-validation-alias", 

346 "/model-required-alias-and-validation-alias", 

347 ], 

348) 

349def test_required_alias_and_validation_alias_by_name(path: str): 1abcd

350 client = TestClient(app) 1IJK

351 response = client.get(path, headers={"p": "hello"}) 1IJK

352 assert response.status_code == 422 1IJK

353 

354 assert response.json() == { 1IJK

355 "detail": [ 

356 { 

357 "type": "missing", 

358 "loc": [ 

359 "header", 

360 "p_val_alias", 

361 ], 

362 "msg": "Field required", 

363 "input": IsOneOf( 

364 None, 

365 IsPartialDict({"p": "hello"}), 

366 ), 

367 } 

368 ] 

369 } 

370 

371 

372@pytest.mark.parametrize( 1abcd

373 "path", 

374 [ 

375 "/required-alias-and-validation-alias", 

376 "/model-required-alias-and-validation-alias", 

377 ], 

378) 

379def test_required_alias_and_validation_alias_by_alias(path: str): 1abcd

380 client = TestClient(app) 1LMN

381 response = client.get(path, headers={"p_alias": "hello"}) 1LMN

382 assert response.status_code == 422 1LMN

383 

384 assert response.json() == { 1LMN

385 "detail": [ 

386 { 

387 "type": "missing", 

388 "loc": ["header", "p_val_alias"], 

389 "msg": "Field required", 

390 "input": IsOneOf( 

391 None, 

392 IsPartialDict({"p_alias": "hello"}), 

393 ), 

394 } 

395 ] 

396 } 

397 

398 

399@pytest.mark.parametrize( 1abcd

400 "path", 

401 [ 

402 "/required-alias-and-validation-alias", 

403 "/model-required-alias-and-validation-alias", 

404 ], 

405) 

406def test_required_alias_and_validation_alias_by_validation_alias(path: str): 1abcd

407 client = TestClient(app) 1nop

408 response = client.get(path, headers={"p_val_alias": "hello"}) 1nop

409 assert response.status_code == 200, response.text 1nop

410 

411 assert response.json() == {"p": "hello"} 1nop