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

136 statements  

« prev     ^ index     » next       coverage.py v7.13.3, created at 2026-02-21 17:29 +0000

1from typing import Annotated, Any 1abcd

2 

3import pytest 1abcd

4from dirty_equals import IsOneOf 1abcd

5from fastapi import Body, FastAPI 1abcd

6from fastapi.testclient import TestClient 1abcd

7from pydantic import BaseModel, Field 1abcd

8 

9from .utils import get_body_model_name 1abcd

10 

11app = FastAPI() 1abcd

12 

13# ===================================================================================== 

14# Without aliases 

15 

16 

17@app.post("/required-str", operation_id="required_str") 1abcd

18async def read_required_str(p: Annotated[str, Body(embed=True)]): 1abcd

19 return {"p": p} 1efg

20 

21 

22class BodyModelRequiredStr(BaseModel): 1abcd

23 p: str 1abcd

24 

25 

26@app.post("/model-required-str", operation_id="model_required_str") 1abcd

27async def read_model_required_str(p: BodyModelRequiredStr): 1abcd

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

29 

30 

31@pytest.mark.parametrize( 1abcd

32 "path", 

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

34) 

35def test_required_str_schema(path: str): 1abcd

36 openapi = app.openapi() 1OPQ

37 body_model_name = get_body_model_name(openapi, path) 1OPQ

38 

39 assert app.openapi()["components"]["schemas"][body_model_name] == { 1OPQ

40 "properties": { 

41 "p": {"title": "P", "type": "string"}, 

42 }, 

43 "required": ["p"], 

44 "title": body_model_name, 

45 "type": "object", 

46 } 

47 

48 

49@pytest.mark.parametrize("json", [None, {}]) 1abcd

50@pytest.mark.parametrize( 1abcd

51 "path", 

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

53) 

54def test_required_str_missing(path: str, json: dict[str, Any] | None): 1abcd

55 client = TestClient(app) 1qrs

56 response = client.post(path, json=json) 1qrs

57 assert response.status_code == 422 1qrs

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

59 "detail": [ 

60 { 

61 "type": "missing", 

62 "loc": IsOneOf(["body"], ["body", "p"]), 

63 "msg": "Field required", 

64 "input": IsOneOf(None, {}), 

65 } 

66 ] 

67 } 

68 

69 

70@pytest.mark.parametrize( 1abcd

71 "path", 

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

73) 

74def test_required_str(path: str): 1abcd

75 client = TestClient(app) 1efg

76 response = client.post(path, json={"p": "hello"}) 1efg

77 assert response.status_code == 200 1efg

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

79 

80 

81# ===================================================================================== 

82# Alias 

83 

84 

85@app.post("/required-alias", operation_id="required_alias") 1abcd

86async def read_required_alias( 1abcd

87 p: Annotated[str, Body(embed=True, alias="p_alias")], 

88): 

89 return {"p": p} 1hij

90 

91 

92class BodyModelRequiredAlias(BaseModel): 1abcd

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

94 

95 

96@app.post("/model-required-alias", operation_id="model_required_alias") 1abcd

97async def read_model_required_alias(p: BodyModelRequiredAlias): 1abcd

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

99 

100 

101@pytest.mark.parametrize( 1abcd

102 "path", 

103 [ 

104 "/required-alias", 

105 "/model-required-alias", 

106 ], 

107) 

108def test_required_str_alias_schema(path: str): 1abcd

109 openapi = app.openapi() 1RST

110 body_model_name = get_body_model_name(openapi, path) 1RST

111 

112 assert app.openapi()["components"]["schemas"][body_model_name] == { 1RST

113 "properties": { 

114 "p_alias": {"title": "P Alias", "type": "string"}, 

115 }, 

116 "required": ["p_alias"], 

117 "title": body_model_name, 

118 "type": "object", 

119 } 

120 

121 

122@pytest.mark.parametrize("json", [None, {}]) 1abcd

123@pytest.mark.parametrize( 1abcd

124 "path", 

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

126) 

127def test_required_alias_missing(path: str, json: dict[str, Any] | None): 1abcd

128 client = TestClient(app) 1tuv

129 response = client.post(path, json=json) 1tuv

130 assert response.status_code == 422 1tuv

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

132 "detail": [ 

133 { 

134 "type": "missing", 

135 "loc": IsOneOf(["body", "p_alias"], ["body"]), 

136 "msg": "Field required", 

137 "input": IsOneOf(None, {}), 

138 } 

139 ] 

140 } 

141 

142 

143@pytest.mark.parametrize( 1abcd

144 "path", 

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

146) 

147def test_required_alias_by_name(path: str): 1abcd

148 client = TestClient(app) 1wxy

149 response = client.post(path, json={"p": "hello"}) 1wxy

150 assert response.status_code == 422 1wxy

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

152 "detail": [ 

153 { 

154 "type": "missing", 

155 "loc": ["body", "p_alias"], 

156 "msg": "Field required", 

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

158 } 

159 ] 

160 } 

161 

162 

163@pytest.mark.parametrize( 1abcd

164 "path", 

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

166) 

167def test_required_alias_by_alias(path: str): 1abcd

168 client = TestClient(app) 1hij

169 response = client.post(path, json={"p_alias": "hello"}) 1hij

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

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

172 

173 

174# ===================================================================================== 

175# Validation alias 

176 

177 

178@app.post("/required-validation-alias", operation_id="required_validation_alias") 1abcd

179def read_required_validation_alias( 1abcd

180 p: Annotated[str, Body(embed=True, validation_alias="p_val_alias")], 

181): 

182 return {"p": p} 1klm

183 

184 

185class BodyModelRequiredValidationAlias(BaseModel): 1abcd

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

187 

188 

189@app.post( 1abcd

190 "/model-required-validation-alias", operation_id="model_required_validation_alias" 

191) 

192def read_model_required_validation_alias( 1abcd

193 p: BodyModelRequiredValidationAlias, 

194): 

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

196 

197 

198@pytest.mark.parametrize( 1abcd

199 "path", 

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

201) 

202def test_required_validation_alias_schema(path: str): 1abcd

203 openapi = app.openapi() 1UVW

204 body_model_name = get_body_model_name(openapi, path) 1UVW

205 

206 assert app.openapi()["components"]["schemas"][body_model_name] == { 1UVW

207 "properties": { 

208 "p_val_alias": {"title": "P Val Alias", "type": "string"}, 

209 }, 

210 "required": ["p_val_alias"], 

211 "title": body_model_name, 

212 "type": "object", 

213 } 

214 

215 

216@pytest.mark.parametrize("json", [None, {}]) 1abcd

217@pytest.mark.parametrize( 1abcd

218 "path", 

219 [ 

220 "/required-validation-alias", 

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

222 ], 

223) 

224def test_required_validation_alias_missing(path: str, json: dict[str, Any] | None): 1abcd

225 client = TestClient(app) 1zAB

226 response = client.post(path, json=json) 1zAB

227 assert response.status_code == 422 1zAB

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

229 "detail": [ 

230 { 

231 "type": "missing", 

232 "loc": IsOneOf(["body", "p_val_alias"], ["body"]), 

233 "msg": "Field required", 

234 "input": IsOneOf(None, {}), 

235 } 

236 ] 

237 } 

238 

239 

240@pytest.mark.parametrize( 1abcd

241 "path", 

242 [ 

243 "/required-validation-alias", 

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

245 ], 

246) 

247def test_required_validation_alias_by_name(path: str): 1abcd

248 client = TestClient(app) 1CDE

249 response = client.post(path, json={"p": "hello"}) 1CDE

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

251 

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

253 "detail": [ 

254 { 

255 "type": "missing", 

256 "loc": ["body", "p_val_alias"], 

257 "msg": "Field required", 

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

259 } 

260 ] 

261 } 

262 

263 

264@pytest.mark.parametrize( 1abcd

265 "path", 

266 [ 

267 "/required-validation-alias", 

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

269 ], 

270) 

271def test_required_validation_alias_by_validation_alias(path: str): 1abcd

272 client = TestClient(app) 1klm

273 response = client.post(path, json={"p_val_alias": "hello"}) 1klm

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

275 

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

277 

278 

279# ===================================================================================== 

280# Alias and validation alias 

281 

282 

283@app.post( 1abcd

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

285 operation_id="required_alias_and_validation_alias", 

286) 

287def read_required_alias_and_validation_alias( 1abcd

288 p: Annotated[ 

289 str, Body(embed=True, alias="p_alias", validation_alias="p_val_alias") 

290 ], 

291): 

292 return {"p": p} 1nop

293 

294 

295class BodyModelRequiredAliasAndValidationAlias(BaseModel): 1abcd

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

297 

298 

299@app.post( 1abcd

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

301 operation_id="model_required_alias_and_validation_alias", 

302) 

303def read_model_required_alias_and_validation_alias( 1abcd

304 p: BodyModelRequiredAliasAndValidationAlias, 

305): 

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

307 

308 

309@pytest.mark.parametrize( 1abcd

310 "path", 

311 [ 

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

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

314 ], 

315) 

316def test_required_alias_and_validation_alias_schema(path: str): 1abcd

317 openapi = app.openapi() 1XYZ

318 body_model_name = get_body_model_name(openapi, path) 1XYZ

319 

320 assert app.openapi()["components"]["schemas"][body_model_name] == { 1XYZ

321 "properties": { 

322 "p_val_alias": {"title": "P Val Alias", "type": "string"}, 

323 }, 

324 "required": ["p_val_alias"], 

325 "title": body_model_name, 

326 "type": "object", 

327 } 

328 

329 

330@pytest.mark.parametrize("json", [None, {}]) 1abcd

331@pytest.mark.parametrize( 1abcd

332 "path", 

333 [ 

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

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

336 ], 

337) 

338def test_required_alias_and_validation_alias_missing( 1abcd

339 path: str, json: dict[str, Any] | None 

340): 

341 client = TestClient(app) 1FGH

342 response = client.post(path, json=json) 1FGH

343 assert response.status_code == 422 1FGH

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

345 "detail": [ 

346 { 

347 "type": "missing", 

348 "loc": IsOneOf(["body"], ["body", "p_val_alias"]), 

349 "msg": "Field required", 

350 "input": IsOneOf(None, {}), 

351 } 

352 ] 

353 } 

354 

355 

356@pytest.mark.parametrize( 1abcd

357 "path", 

358 [ 

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

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

361 ], 

362) 

363def test_required_alias_and_validation_alias_by_name(path: str): 1abcd

364 client = TestClient(app) 1IJK

365 response = client.post(path, json={"p": "hello"}) 1IJK

366 assert response.status_code == 422 1IJK

367 

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

369 "detail": [ 

370 { 

371 "type": "missing", 

372 "loc": [ 

373 "body", 

374 "p_val_alias", 

375 ], 

376 "msg": "Field required", 

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

378 } 

379 ] 

380 } 

381 

382 

383@pytest.mark.parametrize( 1abcd

384 "path", 

385 [ 

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

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

388 ], 

389) 

390def test_required_alias_and_validation_alias_by_alias(path: str): 1abcd

391 client = TestClient(app) 1LMN

392 response = client.post(path, json={"p_alias": "hello"}) 1LMN

393 assert response.status_code == 422, response.text 1LMN

394 

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

396 "detail": [ 

397 { 

398 "type": "missing", 

399 "loc": ["body", "p_val_alias"], 

400 "msg": "Field required", 

401 "input": IsOneOf(None, {"p_alias": "hello"}), 

402 } 

403 ] 

404 } 

405 

406 

407@pytest.mark.parametrize( 1abcd

408 "path", 

409 [ 

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

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

412 ], 

413) 

414def test_required_alias_and_validation_alias_by_validation_alias(path: str): 1abcd

415 client = TestClient(app) 1nop

416 response = client.post(path, json={"p_val_alias": "hello"}) 1nop

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

418 

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