Coverage for tests / test_request_params / test_form / test_list.py: 100%

132 statements  

« prev     ^ index     » next       coverage.py v7.13.3, created at 2026-04-06 01:24 +0000

1from typing import Annotated 1adbc

2 

3import pytest 1adbc

4from dirty_equals import IsOneOf, IsPartialDict 1adbc

5from fastapi import FastAPI, Form 1adbc

6from fastapi.testclient import TestClient 1adbc

7from pydantic import BaseModel, Field 1adbc

8 

9from .utils import get_body_model_name 1adbc

10 

11app = FastAPI() 1adbc

12 

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

14# Without aliases 

15 

16 

17@app.post("/required-list-str", operation_id="required_list_str") 1adbc

18async def read_required_list_str(p: Annotated[list[str], Form()]): 1adbc

19 return {"p": p} 1efgh

20 

21 

22class FormModelRequiredListStr(BaseModel): 1adbc

23 p: list[str] 1abc

24 

25 

26@app.post("/model-required-list-str", operation_id="model_required_list_str") 1adbc

27def read_model_required_list_str(p: Annotated[FormModelRequiredListStr, Form()]): 1adbc

28 return {"p": p.p} 2i Mbj k

29 

30 

31@pytest.mark.parametrize( 1adbc

32 "path", 

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

34) 

35def test_required_list_str_schema(path: str): 1adbc

36 openapi = app.openapi() 2ibjbkblbmbnbob

37 body_model_name = get_body_model_name(openapi, path) 2ibjbkblbmbnbob

38 

39 assert app.openapi()["components"]["schemas"][body_model_name] == { 2ibjbkblbmbnbob

40 "properties": { 

41 "p": { 

42 "items": {"type": "string"}, 

43 "title": "P", 

44 "type": "array", 

45 }, 

46 }, 

47 "required": ["p"], 

48 "title": body_model_name, 

49 "type": "object", 

50 } 

51 

52 

53@pytest.mark.parametrize( 1adbc

54 "path", 

55 ["/required-list-str", "/model-required-list-str"], 

56) 

57def test_required_list_str_missing(path: str): 1adbc

58 client = TestClient(app) 1JKLMNOPQ

59 response = client.post(path) 1JKLMNOPQ

60 assert response.status_code == 422 1JKLMNOPQ

61 assert response.json() == { 1JKLMNOPQ

62 "detail": [ 

63 { 

64 "type": "missing", 

65 "loc": ["body", "p"], 

66 "msg": "Field required", 

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

68 } 

69 ] 

70 } 

71 

72 

73@pytest.mark.parametrize( 1adbc

74 "path", 

75 ["/required-list-str", "/model-required-list-str"], 

76) 

77def test_required_list_str(path: str): 1adbc

78 client = TestClient(app) 1iefjgkh

79 response = client.post(path, data={"p": ["hello", "world"]}) 1iefjgkh

80 assert response.status_code == 200 1iefjgkh

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

82 

83 

84# ===================================================================================== 

85# Alias 

86 

87 

88@app.post("/required-list-alias", operation_id="required_list_alias") 1adbc

89async def read_required_list_alias(p: Annotated[list[str], Form(alias="p_alias")]): 1adbc

90 return {"p": p} 1lmno

91 

92 

93class FormModelRequiredListAlias(BaseModel): 1adbc

94 p: list[str] = Field(alias="p_alias") 1adbc

95 

96 

97@app.post("/model-required-list-alias", operation_id="model_required_list_alias") 1adbc

98async def read_model_required_list_alias( 1adbc

99 p: Annotated[FormModelRequiredListAlias, Form()], 

100): 

101 return {"p": p.p} 1pqrs

102 

103 

104@pytest.mark.parametrize( 1adbc

105 "path", 

106 [ 

107 "/required-list-alias", 

108 "/model-required-list-alias", 

109 ], 

110) 

111def test_required_list_str_alias_schema(path: str): 1adbc

112 openapi = app.openapi() 2pbqbrbsbtbubvbwb

113 body_model_name = get_body_model_name(openapi, path) 2pbqbrbsbtbubvbwb

114 

115 assert app.openapi()["components"]["schemas"][body_model_name] == { 2pbqbrbsbtbubvbwb

116 "properties": { 

117 "p_alias": { 

118 "items": {"type": "string"}, 

119 "title": "P Alias", 

120 "type": "array", 

121 }, 

122 }, 

123 "required": ["p_alias"], 

124 "title": body_model_name, 

125 "type": "object", 

126 } 

127 

128 

129@pytest.mark.parametrize( 1adbc

130 "path", 

131 ["/required-list-alias", "/model-required-list-alias"], 

132) 

133def test_required_list_alias_missing(path: str): 1adbc

134 client = TestClient(app) 1RSTUVWXY

135 response = client.post(path) 1RSTUVWXY

136 assert response.status_code == 422 1RSTUVWXY

137 assert response.json() == { 1RSTUVWXY

138 "detail": [ 

139 { 

140 "type": "missing", 

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

142 "msg": "Field required", 

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

144 } 

145 ] 

146 } 

147 

148 

149@pytest.mark.parametrize( 1adbc

150 "path", 

151 [ 

152 "/required-list-alias", 

153 "/model-required-list-alias", 

154 ], 

155) 

156def test_required_list_alias_by_name(path: str): 1adbc

157 client = TestClient(app) 1Z012345

158 response = client.post(path, data={"p": ["hello", "world"]}) 1Z012345

159 assert response.status_code == 422 1Z012345

160 assert response.json() == { 1Z012345

161 "detail": [ 

162 { 

163 "type": "missing", 

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

165 "msg": "Field required", 

166 "input": IsOneOf(None, {"p": ["hello", "world"]}), 

167 } 

168 ] 

169 } 

170 

171 

172@pytest.mark.parametrize( 1adbc

173 "path", 

174 ["/required-list-alias", "/model-required-list-alias"], 

175) 

176def test_required_list_alias_by_alias(path: str): 1adbc

177 client = TestClient(app) 1plqmrnso

178 response = client.post(path, data={"p_alias": ["hello", "world"]}) 1plqmrnso

179 assert response.status_code == 200, response.text 1plqmrnso

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

181 

182 

183# ===================================================================================== 

184# Validation alias 

185 

186 

187@app.post( 1adbc

188 "/required-list-validation-alias", operation_id="required_list_validation_alias" 

189) 

190def read_required_list_validation_alias( 1adbc

191 p: Annotated[list[str], Form(validation_alias="p_val_alias")], 

192): 

193 return {"p": p} 1tuvw

194 

195 

196class FormModelRequiredListValidationAlias(BaseModel): 1adbc

197 p: list[str] = Field(validation_alias="p_val_alias") 1adbc

198 

199 

200@app.post( 1adbc

201 "/model-required-list-validation-alias", 

202 operation_id="model_required_list_validation_alias", 

203) 

204async def read_model_required_list_validation_alias( 1adbc

205 p: Annotated[FormModelRequiredListValidationAlias, Form()], 

206): 

207 return {"p": p.p} 1xyzA

208 

209 

210@pytest.mark.parametrize( 1adbc

211 "path", 

212 ["/required-list-validation-alias", "/model-required-list-validation-alias"], 

213) 

214def test_required_list_validation_alias_schema(path: str): 1adbc

215 openapi = app.openapi() 2xbybzbAbBbCbDb

216 body_model_name = get_body_model_name(openapi, path) 2xbybzbAbBbCbDb

217 

218 assert app.openapi()["components"]["schemas"][body_model_name] == { 2xbybzbAbBbCbDb

219 "properties": { 

220 "p_val_alias": { 

221 "items": {"type": "string"}, 

222 "title": "P Val Alias", 

223 "type": "array", 

224 }, 

225 }, 

226 "required": ["p_val_alias"], 

227 "title": body_model_name, 

228 "type": "object", 

229 } 

230 

231 

232@pytest.mark.parametrize( 1adbc

233 "path", 

234 [ 

235 "/required-list-validation-alias", 

236 "/model-required-list-validation-alias", 

237 ], 

238) 

239def test_required_list_validation_alias_missing(path: str): 1adbc

240 client = TestClient(app) 16789!#$%

241 response = client.post(path) 16789!#$%

242 assert response.status_code == 422 16789!#$%

243 assert response.json() == { 16789!#$%

244 "detail": [ 

245 { 

246 "type": "missing", 

247 "loc": [ 

248 "body", 

249 "p_val_alias", 

250 ], 

251 "msg": "Field required", 

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

253 } 

254 ] 

255 } 

256 

257 

258@pytest.mark.parametrize( 1adbc

259 "path", 

260 [ 

261 "/required-list-validation-alias", 

262 "/model-required-list-validation-alias", 

263 ], 

264) 

265def test_required_list_validation_alias_by_name(path: str): 1adbc

266 client = TestClient(app) 1'()*+,-.

267 response = client.post(path, data={"p": ["hello", "world"]}) 1'()*+,-.

268 assert response.status_code == 422, response.text 1'()*+,-.

269 

270 assert response.json() == { 1'()*+,-.

271 "detail": [ 

272 { 

273 "type": "missing", 

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

275 "msg": "Field required", 

276 "input": IsOneOf(None, IsPartialDict({"p": ["hello", "world"]})), 

277 } 

278 ] 

279 } 

280 

281 

282@pytest.mark.parametrize( 1adbc

283 "path", 

284 ["/required-list-validation-alias", "/model-required-list-validation-alias"], 

285) 

286def test_required_list_validation_alias_by_validation_alias(path: str): 1adbc

287 client = TestClient(app) 1xtyuzvAw

288 response = client.post(path, data={"p_val_alias": ["hello", "world"]}) 1xtyuzvAw

289 assert response.status_code == 200, response.text 1xtyuzvAw

290 

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

292 

293 

294# ===================================================================================== 

295# Alias and validation alias 

296 

297 

298@app.post( 1adbc

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

300 operation_id="required_list_alias_and_validation_alias", 

301) 

302def read_required_list_alias_and_validation_alias( 1adbc

303 p: Annotated[list[str], Form(alias="p_alias", validation_alias="p_val_alias")], 

304): 

305 return {"p": p} 1BCDE

306 

307 

308class FormModelRequiredListAliasAndValidationAlias(BaseModel): 1adbc

309 p: list[str] = Field(alias="p_alias", validation_alias="p_val_alias") 1adbc

310 

311 

312@app.post( 1adbc

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

314 operation_id="model_required_list_alias_and_validation_alias", 

315) 

316def read_model_required_list_alias_and_validation_alias( 1adbc

317 p: Annotated[FormModelRequiredListAliasAndValidationAlias, Form()], 

318): 

319 return {"p": p.p} 1FGHI

320 

321 

322@pytest.mark.parametrize( 1adbc

323 "path", 

324 [ 

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

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

327 ], 

328) 

329def test_required_list_alias_and_validation_alias_schema(path: str): 1adbc

330 openapi = app.openapi() 2EbFbGbHbIbJbKbLb

331 body_model_name = get_body_model_name(openapi, path) 2EbFbGbHbIbJbKbLb

332 

333 assert app.openapi()["components"]["schemas"][body_model_name] == { 2EbFbGbHbIbJbKbLb

334 "properties": { 

335 "p_val_alias": { 

336 "items": {"type": "string"}, 

337 "title": "P Val Alias", 

338 "type": "array", 

339 }, 

340 }, 

341 "required": ["p_val_alias"], 

342 "title": body_model_name, 

343 "type": "object", 

344 } 

345 

346 

347@pytest.mark.parametrize( 1adbc

348 "path", 

349 [ 

350 "/required-list-alias-and-validation-alias", 

351 "/model-required-list-alias-and-validation-alias", 

352 ], 

353) 

354def test_required_list_alias_and_validation_alias_missing(path: str): 1adbc

355 client = TestClient(app) 1/:;=?@[]

356 response = client.post(path) 1/:;=?@[]

357 assert response.status_code == 422 1/:;=?@[]

358 assert response.json() == { 1/:;=?@[]

359 "detail": [ 

360 { 

361 "type": "missing", 

362 "loc": [ 

363 "body", 

364 "p_val_alias", 

365 ], 

366 "msg": "Field required", 

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

368 } 

369 ] 

370 } 

371 

372 

373@pytest.mark.parametrize( 1adbc

374 "path", 

375 [ 

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

377 "/model-required-list-alias-and-validation-alias", 

378 ], 

379) 

380def test_required_list_alias_and_validation_alias_by_name(path: str): 1adbc

381 client = TestClient(app) 2^ _ ` { | } ~ ab

382 response = client.post(path, data={"p": ["hello", "world"]}) 2^ _ ` { | } ~ ab

383 assert response.status_code == 422 2^ _ ` { | } ~ ab

384 assert response.json() == { 2^ _ ` { | } ~ ab

385 "detail": [ 

386 { 

387 "type": "missing", 

388 "loc": [ 

389 "body", 

390 "p_val_alias", 

391 ], 

392 "msg": "Field required", 

393 "input": IsOneOf( 

394 None, 

395 {"p": ["hello", "world"]}, 

396 ), 

397 } 

398 ] 

399 } 

400 

401 

402@pytest.mark.parametrize( 1adbc

403 "path", 

404 [ 

405 "/required-list-alias-and-validation-alias", 

406 "/model-required-list-alias-and-validation-alias", 

407 ], 

408) 

409def test_required_list_alias_and_validation_alias_by_alias(path: str): 1adbc

410 client = TestClient(app) 2bbcbdbebfbgbhb

411 response = client.post(path, data={"p_alias": ["hello", "world"]}) 2bbcbdbebfbgbhb

412 assert response.status_code == 422 2bbcbdbebfbgbhb

413 assert response.json() == { 2bbcbdbebfbgbhb

414 "detail": [ 

415 { 

416 "type": "missing", 

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

418 "msg": "Field required", 

419 "input": IsOneOf(None, {"p_alias": ["hello", "world"]}), 

420 } 

421 ] 

422 } 

423 

424 

425@pytest.mark.parametrize( 1adbc

426 "path", 

427 [ 

428 "/required-list-alias-and-validation-alias", 

429 "/model-required-list-alias-and-validation-alias", 

430 ], 

431) 

432def test_required_list_alias_and_validation_alias_by_validation_alias(path: str): 1adbc

433 client = TestClient(app) 1FBGCHDIE

434 response = client.post(path, data={"p_val_alias": ["hello", "world"]}) 1FBGCHDIE

435 assert response.status_code == 200, response.text 1FBGCHDIE

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