Coverage for tests / test_request_params / test_file / test_required.py: 100%

122 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 fastapi import FastAPI, File, UploadFile 1abcd

5from fastapi.testclient import TestClient 1abcd

6 

7from .utils import get_body_model_name 1abcd

8 

9app = FastAPI() 1abcd

10 

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

12# Without aliases 

13 

14 

15@app.post("/required-bytes", operation_id="required_bytes") 1abcd

16async def read_required_bytes(p: Annotated[bytes, File()]): 1abcd

17 return {"file_size": len(p)} 1efg

18 

19 

20@app.post("/required-uploadfile", operation_id="required_uploadfile") 1abcd

21async def read_required_uploadfile(p: Annotated[UploadFile, File()]): 1abcd

22 return {"file_size": p.size} 1efg

23 

24 

25@pytest.mark.parametrize( 1abcd

26 "path", 

27 [ 

28 "/required-bytes", 

29 "/required-uploadfile", 

30 ], 

31) 

32def test_required_schema(path: str): 1abcd

33 openapi = app.openapi() 1OPQ

34 body_model_name = get_body_model_name(openapi, path) 1OPQ

35 

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

37 "properties": { 

38 "p": {"title": "P", "type": "string", "format": "binary"}, 

39 }, 

40 "required": ["p"], 

41 "title": body_model_name, 

42 "type": "object", 

43 } 

44 

45 

46@pytest.mark.parametrize( 1abcd

47 "path", 

48 [ 

49 "/required-bytes", 

50 "/required-uploadfile", 

51 ], 

52) 

53def test_required_missing(path: str): 1abcd

54 client = TestClient(app) 1qrs

55 response = client.post(path) 1qrs

56 assert response.status_code == 422 1qrs

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

58 "detail": [ 

59 { 

60 "type": "missing", 

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

62 "msg": "Field required", 

63 "input": None, 

64 } 

65 ] 

66 } 

67 

68 

69@pytest.mark.parametrize( 1abcd

70 "path", 

71 [ 

72 "/required-bytes", 

73 "/required-uploadfile", 

74 ], 

75) 

76def test_required(path: str): 1abcd

77 client = TestClient(app) 1efg

78 response = client.post(path, files=[("p", b"hello")]) 1efg

79 assert response.status_code == 200 1efg

80 assert response.json() == {"file_size": 5} 1efg

81 

82 

83# ===================================================================================== 

84# Alias 

85 

86 

87@app.post("/required-bytes-alias", operation_id="required_bytes_alias") 1abcd

88async def read_required_bytes_alias(p: Annotated[bytes, File(alias="p_alias")]): 1abcd

89 return {"file_size": len(p)} 1hij

90 

91 

92@app.post("/required-uploadfile-alias", operation_id="required_uploadfile_alias") 1abcd

93async def read_required_uploadfile_alias( 1abcd

94 p: Annotated[UploadFile, File(alias="p_alias")], 

95): 

96 return {"file_size": p.size} 1hij

97 

98 

99@pytest.mark.parametrize( 1abcd

100 "path", 

101 [ 

102 "/required-bytes-alias", 

103 "/required-uploadfile-alias", 

104 ], 

105) 

106def test_required_alias_schema(path: str): 1abcd

107 openapi = app.openapi() 1RST

108 body_model_name = get_body_model_name(openapi, path) 1RST

109 

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

111 "properties": { 

112 "p_alias": {"title": "P Alias", "type": "string", "format": "binary"}, 

113 }, 

114 "required": ["p_alias"], 

115 "title": body_model_name, 

116 "type": "object", 

117 } 

118 

119 

120@pytest.mark.parametrize( 1abcd

121 "path", 

122 [ 

123 "/required-bytes-alias", 

124 "/required-uploadfile-alias", 

125 ], 

126) 

127def test_required_alias_missing(path: str): 1abcd

128 client = TestClient(app) 1tuv

129 response = client.post(path) 1tuv

130 assert response.status_code == 422 1tuv

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

132 "detail": [ 

133 { 

134 "type": "missing", 

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

136 "msg": "Field required", 

137 "input": None, 

138 } 

139 ] 

140 } 

141 

142 

143@pytest.mark.parametrize( 1abcd

144 "path", 

145 [ 

146 "/required-bytes-alias", 

147 "/required-uploadfile-alias", 

148 ], 

149) 

150def test_required_alias_by_name(path: str): 1abcd

151 client = TestClient(app) 1wxy

152 response = client.post(path, files=[("p", b"hello")]) 1wxy

153 assert response.status_code == 422 1wxy

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

155 "detail": [ 

156 { 

157 "type": "missing", 

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

159 "msg": "Field required", 

160 "input": None, 

161 } 

162 ] 

163 } 

164 

165 

166@pytest.mark.parametrize( 1abcd

167 "path", 

168 [ 

169 "/required-bytes-alias", 

170 "/required-uploadfile-alias", 

171 ], 

172) 

173def test_required_alias_by_alias(path: str): 1abcd

174 client = TestClient(app) 1hij

175 response = client.post(path, files=[("p_alias", b"hello")]) 1hij

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

177 assert response.json() == {"file_size": 5} 1hij

178 

179 

180# ===================================================================================== 

181# Validation alias 

182 

183 

184@app.post( 1abcd

185 "/required-bytes-validation-alias", operation_id="required_bytes_validation_alias" 

186) 

187def read_required_bytes_validation_alias( 1abcd

188 p: Annotated[bytes, File(validation_alias="p_val_alias")], 

189): 

190 return {"file_size": len(p)} 1klm

191 

192 

193@app.post( 1abcd

194 "/required-uploadfile-validation-alias", 

195 operation_id="required_uploadfile_validation_alias", 

196) 

197def read_required_uploadfile_validation_alias( 1abcd

198 p: Annotated[UploadFile, File(validation_alias="p_val_alias")], 

199): 

200 return {"file_size": p.size} 1klm

201 

202 

203@pytest.mark.parametrize( 1abcd

204 "path", 

205 [ 

206 "/required-bytes-validation-alias", 

207 "/required-uploadfile-validation-alias", 

208 ], 

209) 

210def test_required_validation_alias_schema(path: str): 1abcd

211 openapi = app.openapi() 1UVW

212 body_model_name = get_body_model_name(openapi, path) 1UVW

213 

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

215 "properties": { 

216 "p_val_alias": { 

217 "title": "P Val Alias", 

218 "type": "string", 

219 "format": "binary", 

220 }, 

221 }, 

222 "required": ["p_val_alias"], 

223 "title": body_model_name, 

224 "type": "object", 

225 } 

226 

227 

228@pytest.mark.parametrize( 1abcd

229 "path", 

230 [ 

231 "/required-bytes-validation-alias", 

232 "/required-uploadfile-validation-alias", 

233 ], 

234) 

235def test_required_validation_alias_missing(path: str): 1abcd

236 client = TestClient(app) 1zAB

237 response = client.post(path) 1zAB

238 assert response.status_code == 422 1zAB

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

240 "detail": [ 

241 { 

242 "type": "missing", 

243 "loc": [ 

244 "body", 

245 "p_val_alias", 

246 ], 

247 "msg": "Field required", 

248 "input": None, 

249 } 

250 ] 

251 } 

252 

253 

254@pytest.mark.parametrize( 1abcd

255 "path", 

256 [ 

257 "/required-bytes-validation-alias", 

258 "/required-uploadfile-validation-alias", 

259 ], 

260) 

261def test_required_validation_alias_by_name(path: str): 1abcd

262 client = TestClient(app) 1CDE

263 response = client.post(path, files=[("p", b"hello")]) 1CDE

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

265 

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

267 "detail": [ 

268 { 

269 "type": "missing", 

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

271 "msg": "Field required", 

272 "input": None, 

273 } 

274 ] 

275 } 

276 

277 

278@pytest.mark.parametrize( 1abcd

279 "path", 

280 [ 

281 "/required-bytes-validation-alias", 

282 "/required-uploadfile-validation-alias", 

283 ], 

284) 

285def test_required_validation_alias_by_validation_alias(path: str): 1abcd

286 client = TestClient(app) 1klm

287 response = client.post(path, files=[("p_val_alias", b"hello")]) 1klm

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

289 assert response.json() == {"file_size": 5} 1klm

290 

291 

292# ===================================================================================== 

293# Alias and validation alias 

294 

295 

296@app.post( 1abcd

297 "/required-bytes-alias-and-validation-alias", 

298 operation_id="required_bytes_alias_and_validation_alias", 

299) 

300def read_required_bytes_alias_and_validation_alias( 1abcd

301 p: Annotated[bytes, File(alias="p_alias", validation_alias="p_val_alias")], 

302): 

303 return {"file_size": len(p)} 1nop

304 

305 

306@app.post( 1abcd

307 "/required-uploadfile-alias-and-validation-alias", 

308 operation_id="required_uploadfile_alias_and_validation_alias", 

309) 

310def read_required_uploadfile_alias_and_validation_alias( 1abcd

311 p: Annotated[UploadFile, File(alias="p_alias", validation_alias="p_val_alias")], 

312): 

313 return {"file_size": p.size} 1nop

314 

315 

316@pytest.mark.parametrize( 1abcd

317 "path", 

318 [ 

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

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

321 ], 

322) 

323def test_required_alias_and_validation_alias_schema(path: str): 1abcd

324 openapi = app.openapi() 1XYZ

325 body_model_name = get_body_model_name(openapi, path) 1XYZ

326 

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

328 "properties": { 

329 "p_val_alias": { 

330 "title": "P Val Alias", 

331 "type": "string", 

332 "format": "binary", 

333 }, 

334 }, 

335 "required": ["p_val_alias"], 

336 "title": body_model_name, 

337 "type": "object", 

338 } 

339 

340 

341@pytest.mark.parametrize( 1abcd

342 "path", 

343 [ 

344 "/required-bytes-alias-and-validation-alias", 

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

346 ], 

347) 

348def test_required_alias_and_validation_alias_missing(path: str): 1abcd

349 client = TestClient(app) 1FGH

350 response = client.post(path) 1FGH

351 assert response.status_code == 422 1FGH

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

353 "detail": [ 

354 { 

355 "type": "missing", 

356 "loc": [ 

357 "body", 

358 "p_val_alias", 

359 ], 

360 "msg": "Field required", 

361 "input": None, 

362 } 

363 ] 

364 } 

365 

366 

367@pytest.mark.parametrize( 1abcd

368 "path", 

369 [ 

370 "/required-bytes-alias-and-validation-alias", 

371 "/required-uploadfile-alias-and-validation-alias", 

372 ], 

373) 

374def test_required_alias_and_validation_alias_by_name(path: str): 1abcd

375 client = TestClient(app) 1IJK

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

377 assert response.status_code == 422 1IJK

378 

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

380 "detail": [ 

381 { 

382 "type": "missing", 

383 "loc": [ 

384 "body", 

385 "p_val_alias", 

386 ], 

387 "msg": "Field required", 

388 "input": None, 

389 } 

390 ] 

391 } 

392 

393 

394@pytest.mark.parametrize( 1abcd

395 "path", 

396 [ 

397 "/required-bytes-alias-and-validation-alias", 

398 "/required-uploadfile-alias-and-validation-alias", 

399 ], 

400) 

401def test_required_alias_and_validation_alias_by_alias(path: str): 1abcd

402 client = TestClient(app) 1LMN

403 response = client.post(path, files=[("p_alias", b"hello")]) 1LMN

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

405 

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

407 "detail": [ 

408 { 

409 "type": "missing", 

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

411 "msg": "Field required", 

412 "input": None, 

413 } 

414 ] 

415 } 

416 

417 

418@pytest.mark.parametrize( 1abcd

419 "path", 

420 [ 

421 "/required-bytes-alias-and-validation-alias", 

422 "/required-uploadfile-alias-and-validation-alias", 

423 ], 

424) 

425def test_required_alias_and_validation_alias_by_validation_alias(path: str): 1abcd

426 client = TestClient(app) 1nop

427 response = client.post(path, files=[("p_val_alias", b"hello")]) 1nop

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

429 assert response.json() == {"file_size": 5} 1nop