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

122 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, 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("/optional-list-bytes") 1abcd

16async def read_optional_list_bytes(p: Annotated[list[bytes] | None, File()] = None): 1abcd

17 return {"file_size": [len(file) for file in p] if p else None} 1efghijkl

18 

19 

20@app.post("/optional-list-uploadfile") 1abcd

21async def read_optional_list_uploadfile( 1abcd

22 p: Annotated[list[UploadFile] | None, File()] = None, 

23): 

24 return {"file_size": [file.size for file in p] if p else None} 1mnopqrst

25 

26 

27@pytest.mark.parametrize( 1abcd

28 "path", 

29 [ 

30 "/optional-list-bytes", 

31 "/optional-list-uploadfile", 

32 ], 

33) 

34def test_optional_list_schema(path: str): 1abcd

35 openapi = app.openapi() 2kblbmbnbobpbqbrb

36 body_model_name = get_body_model_name(openapi, path) 2kblbmbnbobpbqbrb

37 

38 assert app.openapi()["components"]["schemas"][body_model_name] == { 2kblbmbnbobpbqbrb

39 "properties": { 

40 "p": { 

41 "anyOf": [ 

42 { 

43 "type": "array", 

44 "items": { 

45 "type": "string", 

46 "contentMediaType": "application/octet-stream", 

47 }, 

48 }, 

49 {"type": "null"}, 

50 ], 

51 "title": "P", 

52 } 

53 }, 

54 "title": body_model_name, 

55 "type": "object", 

56 } 

57 

58 

59@pytest.mark.parametrize( 1abcd

60 "path", 

61 [ 

62 "/optional-list-bytes", 

63 "/optional-list-uploadfile", 

64 ], 

65) 

66def test_optional_list_missing(path: str): 1abcd

67 client = TestClient(app) 1fnhpjrlt

68 response = client.post(path) 1fnhpjrlt

69 assert response.status_code == 200, response.text 1fnhpjrlt

70 assert response.json() == {"file_size": None} 1fnhpjrlt

71 

72 

73@pytest.mark.parametrize( 1abcd

74 "path", 

75 [ 

76 "/optional-list-bytes", 

77 "/optional-list-uploadfile", 

78 ], 

79) 

80def test_optional_list(path: str): 1abcd

81 client = TestClient(app) 1emgoiqks

82 response = client.post(path, files=[("p", b"hello"), ("p", b"world")]) 1emgoiqks

83 assert response.status_code == 200 1emgoiqks

84 assert response.json() == {"file_size": [5, 5]} 1emgoiqks

85 

86 

87# ===================================================================================== 

88# Alias 

89 

90 

91@app.post("/optional-list-bytes-alias") 1abcd

92async def read_optional_list_bytes_alias( 1abcd

93 p: Annotated[list[bytes] | None, File(alias="p_alias")] = None, 

94): 

95 return {"file_size": [len(file) for file in p] if p else None} 1uvwxyzABCDE

96 

97 

98@app.post("/optional-list-uploadfile-alias") 1abcd

99async def read_optional_list_uploadfile_alias( 1abcd

100 p: Annotated[list[UploadFile] | None, File(alias="p_alias")] = None, 

101): 

102 return {"file_size": [file.size for file in p] if p else None} 1FGHIJKLMNOP

103 

104 

105@pytest.mark.parametrize( 1abcd

106 "path", 

107 [ 

108 "/optional-list-bytes-alias", 

109 "/optional-list-uploadfile-alias", 

110 ], 

111) 

112def test_optional_list_alias_schema(path: str): 1abcd

113 openapi = app.openapi() 2sbtbubvbwbxbybzb

114 body_model_name = get_body_model_name(openapi, path) 2sbtbubvbwbxbybzb

115 

116 assert app.openapi()["components"]["schemas"][body_model_name] == { 2sbtbubvbwbxbybzb

117 "properties": { 

118 "p_alias": { 

119 "anyOf": [ 

120 { 

121 "type": "array", 

122 "items": { 

123 "type": "string", 

124 "contentMediaType": "application/octet-stream", 

125 }, 

126 }, 

127 {"type": "null"}, 

128 ], 

129 "title": "P Alias", 

130 } 

131 }, 

132 "title": body_model_name, 

133 "type": "object", 

134 } 

135 

136 

137@pytest.mark.parametrize( 1abcd

138 "path", 

139 [ 

140 "/optional-list-bytes-alias", 

141 "/optional-list-uploadfile-alias", 

142 ], 

143) 

144def test_optional_list_alias_missing(path: str): 1abcd

145 client = TestClient(app) 1wHyJBMEP

146 response = client.post(path) 1wHyJBMEP

147 assert response.status_code == 200 1wHyJBMEP

148 assert response.json() == {"file_size": None} 1wHyJBMEP

149 

150 

151@pytest.mark.parametrize( 1abcd

152 "path", 

153 [ 

154 "/optional-list-bytes-alias", 

155 "/optional-list-uploadfile-alias", 

156 ], 

157) 

158def test_optional_list_alias_by_name(path: str): 1abcd

159 client = TestClient(app) 1vGxIALDO

160 response = client.post(path, files=[("p", b"hello"), ("p", b"world")]) 1vGxIALDO

161 assert response.status_code == 200, response.text 1vGxIALDO

162 assert response.json() == {"file_size": None} 1vGxIALDO

163 

164 

165@pytest.mark.parametrize( 1abcd

166 "path", 

167 [ 

168 "/optional-list-bytes-alias", 

169 "/optional-list-uploadfile-alias", 

170 ], 

171) 

172def test_optional_list_alias_by_alias(path: str): 1abcd

173 client = TestClient(app) 2u F abbbz K C N

174 response = client.post(path, files=[("p_alias", b"hello"), ("p_alias", b"world")]) 2u F abbbz K C N

175 assert response.status_code == 200, response.text 2u F abbbz K C N

176 assert response.json() == {"file_size": [5, 5]} 2u F abbbz K C N

177 

178 

179# ===================================================================================== 

180# Validation alias 

181 

182 

183@app.post("/optional-list-bytes-validation-alias") 1abcd

184def read_optional_list_bytes_validation_alias( 1abcd

185 p: Annotated[list[bytes] | None, File(validation_alias="p_val_alias")] = None, 

186): 

187 return {"file_size": [len(file) for file in p] if p else None} 1QRSTUVWXYZ

188 

189 

190@app.post("/optional-list-uploadfile-validation-alias") 1abcd

191def read_optional_list_uploadfile_validation_alias( 1abcd

192 p: Annotated[list[UploadFile] | None, File(validation_alias="p_val_alias")] = None, 

193): 

194 return {"file_size": [file.size for file in p] if p else None} 10123456789

195 

196 

197@pytest.mark.parametrize( 1abcd

198 "path", 

199 [ 

200 "/optional-list-bytes-validation-alias", 

201 "/optional-list-uploadfile-validation-alias", 

202 ], 

203) 

204def test_optional_validation_alias_schema(path: str): 1abcd

205 openapi = app.openapi() 2AbBbCbDbEbFbGbHb

206 body_model_name = get_body_model_name(openapi, path) 2AbBbCbDbEbFbGbHb

207 

208 assert app.openapi()["components"]["schemas"][body_model_name] == { 2AbBbCbDbEbFbGbHb

209 "properties": { 

210 "p_val_alias": { 

211 "anyOf": [ 

212 { 

213 "type": "array", 

214 "items": { 

215 "type": "string", 

216 "contentMediaType": "application/octet-stream", 

217 }, 

218 }, 

219 {"type": "null"}, 

220 ], 

221 "title": "P Val Alias", 

222 } 

223 }, 

224 "title": body_model_name, 

225 "type": "object", 

226 } 

227 

228 

229@pytest.mark.parametrize( 1abcd

230 "path", 

231 [ 

232 "/optional-list-bytes-validation-alias", 

233 "/optional-list-uploadfile-validation-alias", 

234 ], 

235) 

236def test_optional_validation_alias_missing(path: str): 1abcd

237 client = TestClient(app) 1S2T3W6Z9

238 response = client.post(path) 1S2T3W6Z9

239 assert response.status_code == 200 1S2T3W6Z9

240 assert response.json() == {"file_size": None} 1S2T3W6Z9

241 

242 

243@pytest.mark.parametrize( 1abcd

244 "path", 

245 [ 

246 "/optional-list-bytes-validation-alias", 

247 "/optional-list-uploadfile-validation-alias", 

248 ], 

249) 

250def test_optional_validation_alias_by_name(path: str): 1abcd

251 client = TestClient(app) 2Q 0 cbdbU 4 X 7

252 response = client.post(path, files=[("p", b"hello"), ("p", b"world")]) 2Q 0 cbdbU 4 X 7

253 assert response.status_code == 200, response.text 2Q 0 cbdbU 4 X 7

254 assert response.json() == {"file_size": None} 2Q 0 cbdbU 4 X 7

255 

256 

257@pytest.mark.parametrize( 1abcd

258 "path", 

259 [ 

260 "/optional-list-bytes-validation-alias", 

261 "/optional-list-uploadfile-validation-alias", 

262 ], 

263) 

264def test_optional_validation_alias_by_validation_alias(path: str): 1abcd

265 client = TestClient(app) 2R 1 ebfbV 5 Y 8

266 response = client.post( 2R 1 ebfbV 5 Y 8

267 path, files=[("p_val_alias", b"hello"), ("p_val_alias", b"world")] 

268 ) 

269 assert response.status_code == 200, response.text 2R 1 ebfbV 5 Y 8

270 assert response.json() == {"file_size": [5, 5]} 2R 1 ebfbV 5 Y 8

271 

272 

273# ===================================================================================== 

274# Alias and validation alias 

275 

276 

277@app.post("/optional-list-bytes-alias-and-validation-alias") 1abcd

278def read_optional_list_bytes_alias_and_validation_alias( 1abcd

279 p: Annotated[ 

280 list[bytes] | None, File(alias="p_alias", validation_alias="p_val_alias") 

281 ] = None, 

282): 

283 return {"file_size": [len(file) for file in p] if p else None} 1!#$%'()*+,-./:

284 

285 

286@app.post("/optional-list-uploadfile-alias-and-validation-alias") 1abcd

287def read_optional_list_uploadfile_alias_and_validation_alias( 1abcd

288 p: Annotated[ 

289 list[UploadFile] | None, 

290 File(alias="p_alias", validation_alias="p_val_alias"), 

291 ] = None, 

292): 

293 return {"file_size": [file.size for file in p] if p else None} 2; = ? @ Qb[ ] ^ _ ` { | } ~

294 

295 

296@pytest.mark.parametrize( 1abcd

297 "path", 

298 [ 

299 "/optional-list-bytes-alias-and-validation-alias", 

300 "/optional-list-uploadfile-alias-and-validation-alias", 

301 ], 

302) 

303def test_optional_list_alias_and_validation_alias_schema(path: str): 1abcd

304 openapi = app.openapi() 2IbJbKbLbMbNbObPb

305 body_model_name = get_body_model_name(openapi, path) 2IbJbKbLbMbNbObPb

306 

307 assert app.openapi()["components"]["schemas"][body_model_name] == { 2IbJbKbLbMbNbObPb

308 "properties": { 

309 "p_val_alias": { 

310 "anyOf": [ 

311 { 

312 "type": "array", 

313 "items": { 

314 "type": "string", 

315 "contentMediaType": "application/octet-stream", 

316 }, 

317 }, 

318 {"type": "null"}, 

319 ], 

320 "title": "P Val Alias", 

321 } 

322 }, 

323 "title": body_model_name, 

324 "type": "object", 

325 } 

326 

327 

328@pytest.mark.parametrize( 1abcd

329 "path", 

330 [ 

331 "/optional-list-bytes-alias-and-validation-alias", 

332 "/optional-list-uploadfile-alias-and-validation-alias", 

333 ], 

334) 

335def test_optional_list_alias_and_validation_alias_missing(path: str): 1abcd

336 client = TestClient(app) 1%@([,`:~

337 response = client.post(path) 1%@([,`:~

338 assert response.status_code == 200 1%@([,`:~

339 assert response.json() == {"file_size": None} 1%@([,`:~

340 

341 

342@pytest.mark.parametrize( 1abcd

343 "path", 

344 [ 

345 "/optional-list-bytes-alias-and-validation-alias", 

346 "/optional-list-uploadfile-alias-and-validation-alias", 

347 ], 

348) 

349def test_optional_list_alias_and_validation_alias_by_name(path: str): 1abcd

350 client = TestClient(app) 2# = gbhb* ^ . |

351 response = client.post(path, files={"p": "hello"}) 2# = gbhb* ^ . |

352 assert response.status_code == 200 2# = gbhb* ^ . |

353 assert response.json() == {"file_size": None} 2# = gbhb* ^ . |

354 

355 

356@pytest.mark.parametrize( 1abcd

357 "path", 

358 [ 

359 "/optional-list-bytes-alias-and-validation-alias", 

360 "/optional-list-uploadfile-alias-and-validation-alias", 

361 ], 

362) 

363def test_optional_list_alias_and_validation_alias_by_alias(path: str): 1abcd

364 client = TestClient(app) 2! ; ib) ] - {

365 response = client.post(path, files=[("p_alias", b"hello"), ("p_alias", b"world")]) 2! ; ib) ] - {

366 assert response.status_code == 200, response.text 2! ; ib) ] - {

367 assert response.json() == {"file_size": None} 2! ; ib) ] - {

368 

369 

370@pytest.mark.parametrize( 1abcd

371 "path", 

372 [ 

373 "/optional-list-bytes-alias-and-validation-alias", 

374 "/optional-list-uploadfile-alias-and-validation-alias", 

375 ], 

376) 

377def test_optional_list_alias_and_validation_alias_by_validation_alias(path: str): 1abcd

378 client = TestClient(app) 2$ ? ' jb+ _ / }

379 response = client.post( 2$ ? ' jb+ _ / }

380 path, files=[("p_val_alias", b"hello"), ("p_val_alias", b"world")] 

381 ) 

382 assert response.status_code == 200, response.text 2$ ? ' jb+ _ / }

383 assert response.json() == {"file_size": [5, 5]} 2$ ? ' jb+ _ / }