Coverage for tests/test_dependency_contextmanager.py: 100%

271 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2025-01-13 13:38 +0000

1import json 1abcde

2from typing import Dict 1abcde

3 

4import pytest 1abcde

5from fastapi import BackgroundTasks, Depends, FastAPI 1abcde

6from fastapi.responses import StreamingResponse 1abcde

7from fastapi.testclient import TestClient 1abcde

8 

9app = FastAPI() 1abcde

10state = { 1abcde

11 "/async": "asyncgen not started", 

12 "/sync": "generator not started", 

13 "/async_raise": "asyncgen raise not started", 

14 "/sync_raise": "generator raise not started", 

15 "context_a": "not started a", 

16 "context_b": "not started b", 

17 "bg": "not set", 

18 "sync_bg": "not set", 

19} 

20 

21errors = [] 1abcde

22 

23 

24async def get_state(): 1abcde

25 return state 2: Z z { f p A | 0 B qbk q C ; 1 D } ~ 2 E rb= , 3 abg r F bb- 4 sbl s G ? . 5 cbdb/ 6 tb@ 7 H ebh t I fb8 J ubm u K [ 9 L gbhb! M vb] # N ibi v O jb$ P wbn w Q ^ % R kblb' S xb_ ( T mbj x U nb) V ybo y W ` * X obpb+ Y zb

26 

27 

28class AsyncDependencyError(Exception): 1abcde

29 pass 1abcde

30 

31 

32class SyncDependencyError(Exception): 1abcde

33 pass 1abcde

34 

35 

36class OtherDependencyError(Exception): 1abcde

37 pass 1abcde

38 

39 

40async def asyncgen_state(state: Dict[str, str] = Depends(get_state)): 1abcde

41 state["/async"] = "asyncgen started" 2{ qbabsbebubibwbmbyb

42 yield state["/async"] 2{ qbabsbebubibwbmbyb

43 state["/async"] = "asyncgen completed" 2{ qbabsbebubibwbmbyb

44 

45 

46def generator_state(state: Dict[str, str] = Depends(get_state)): 1abcde

47 state["/sync"] = "generator started" 2} rbcbtbgbvbkbxbobzb

48 yield state["/sync"] 2} rbcbtbgbvbkbxbobzb

49 state["/sync"] = "generator completed" 2} rbcbtbgbvbkbxbobzb

50 

51 

52async def asyncgen_state_try(state: Dict[str, str] = Depends(get_state)): 1abcde

53 state["/async_raise"] = "asyncgen raise started" 2: Z z | 0 B = , 3 bb- 4 @ 7 H fb8 J ] # N jb$ P _ ( T nb) V

54 try: 2: Z z | 0 B = , 3 bb- 4 @ 7 H fb8 J ] # N jb$ P _ ( T nb) V

55 yield state["/async_raise"] 2: Z z | 0 B = , 3 bb- 4 @ 7 H fb8 J ] # N jb$ P _ ( T nb) V

56 except AsyncDependencyError: 2: Z z | 0 B = , 3 bb- 4 @ 7 H fb8 J ] # N jb$ P _ ( T nb) V

57 errors.append("/async_raise") 1Zz0B,3-47H8J#N$P(T)V

58 raise 1Zz0B,3-47H8J#N$P(T)V

59 finally: 

60 state["/async_raise"] = "asyncgen raise finalized" 2: Z z | 0 B = bb@ 7 H fb8 J ] # N jb$ P _ ( T nb) V

61 

62 

63def generator_state_try(state: Dict[str, str] = Depends(get_state)): 1abcde

64 state["/sync_raise"] = "generator raise started" 2; 1 D ~ 2 E ? . 5 db/ 6 [ 9 L hb! M ^ % R lb' S ` * X pb+ Y

65 try: 2; 1 D ~ 2 E ? . 5 db/ 6 [ 9 L hb! M ^ % R lb' S ` * X pb+ Y

66 yield state["/sync_raise"] 2; 1 D ~ 2 E ? . 5 db/ 6 [ 9 L hb! M ^ % R lb' S ` * X pb+ Y

67 except SyncDependencyError: 2; 1 D ~ 2 E ? . 5 db/ 6 [ 9 L hb! M ^ % R lb' S ` * X pb+ Y

68 errors.append("/sync_raise") 11D2E.5/69L!M%R'S*X+Y

69 raise 11D2E.5/69L!M%R'S*X+Y

70 finally: 

71 state["/sync_raise"] = "generator raise finalized" 2; 1 D ~ 2 E ? db[ 9 L hb! M ^ % R lb' S ` * X pb+ Y

72 

73 

74async def context_a(state: dict = Depends(get_state)): 1abcde

75 state["context_a"] = "started a" 1fpAkqCgrFlsGhtImuKivOnwQjxUoyW

76 try: 1fpAkqCgrFlsGhtImuKivOnwQjxUoyW

77 yield state 1fpAkqCgrFlsGhtImuKivOnwQjxUoyW

78 finally: 

79 state["context_a"] = "finished a" 1fpAkqCgrFlsGhtImuKivOnwQjxUoyW

80 

81 

82async def context_b(state: dict = Depends(context_a)): 1abcde

83 state["context_b"] = "started b" 1fpAkqCgrFlsGhtImuKivOnwQjxUoyW

84 try: 1fpAkqCgrFlsGhtImuKivOnwQjxUoyW

85 yield state 1fpAkqCgrFlsGhtImuKivOnwQjxUoyW

86 finally: 

87 state["context_b"] = f"finished b with a: {state['context_a']}" 1fpAkqCgrFlsGhtImuKivOnwQjxUoyW

88 

89 

90@app.get("/async") 1abcde

91async def get_async(state: str = Depends(asyncgen_state)): 1abcde

92 return state 2{ abebibmb

93 

94 

95@app.get("/sync") 1abcde

96async def get_sync(state: str = Depends(generator_state)): 1abcde

97 return state 2} cbgbkbob

98 

99 

100@app.get("/async_raise") 1abcde

101async def get_async_raise(state: str = Depends(asyncgen_state_try)): 1abcde

102 assert state == "asyncgen raise started" 1Zz,37H#N(T

103 raise AsyncDependencyError() 1Zz,37H#N(T

104 

105 

106@app.get("/sync_raise") 1abcde

107async def get_sync_raise(state: str = Depends(generator_state_try)): 1abcde

108 assert state == "generator raise started" 11D.59L%R*X

109 raise SyncDependencyError() 11D.59L%R*X

110 

111 

112@app.get("/async_raise_other") 1abcde

113async def get_async_raise_other(state: str = Depends(asyncgen_state_try)): 1abcde

114 assert state == "asyncgen raise started" 1:=@]_

115 raise OtherDependencyError() 1:=@]_

116 

117 

118@app.get("/sync_raise_other") 1abcde

119async def get_sync_raise_other(state: str = Depends(generator_state_try)): 1abcde

120 assert state == "generator raise started" 1;?[^`

121 raise OtherDependencyError() 1;?[^`

122 

123 

124@app.get("/context_b") 1abcde

125async def get_context_b(state: dict = Depends(context_b)): 1abcde

126 return state 1prtvx

127 

128 

129@app.get("/context_b_raise") 1abcde

130async def get_context_b_raise(state: dict = Depends(context_b)): 1abcde

131 assert state["context_b"] == "started b" 1AFIOU

132 assert state["context_a"] == "started a" 1AFIOU

133 raise OtherDependencyError() 1AFIOU

134 

135 

136@app.get("/context_b_bg") 1abcde

137async def get_context_b_bg(tasks: BackgroundTasks, state: dict = Depends(context_b)): 1abcde

138 async def bg(state: dict): 1fghij

139 state["bg"] = f"bg set - b: {state['context_b']} - a: {state['context_a']}" 1fghij

140 

141 tasks.add_task(bg, state) 1fghij

142 return state 1fghij

143 

144 

145# Sync versions 

146 

147 

148@app.get("/sync_async") 1abcde

149def get_sync_async(state: str = Depends(asyncgen_state)): 1abcde

150 return state 2qbsbubwbyb

151 

152 

153@app.get("/sync_sync") 1abcde

154def get_sync_sync(state: str = Depends(generator_state)): 1abcde

155 return state 2rbtbvbxbzb

156 

157 

158@app.get("/sync_async_raise") 1abcde

159def get_sync_async_raise(state: str = Depends(asyncgen_state_try)): 1abcde

160 assert state == "asyncgen raise started" 10B-48J$P)V

161 raise AsyncDependencyError() 10B-48J$P)V

162 

163 

164@app.get("/sync_sync_raise") 1abcde

165def get_sync_sync_raise(state: str = Depends(generator_state_try)): 1abcde

166 assert state == "generator raise started" 12E/6!M'S+Y

167 raise SyncDependencyError() 12E/6!M'S+Y

168 

169 

170@app.get("/sync_async_raise_other") 1abcde

171def get_sync_async_raise_other(state: str = Depends(asyncgen_state_try)): 1abcde

172 assert state == "asyncgen raise started" 2| bbfbjbnb

173 raise OtherDependencyError() 2| bbfbjbnb

174 

175 

176@app.get("/sync_sync_raise_other") 1abcde

177def get_sync_sync_raise_other(state: str = Depends(generator_state_try)): 1abcde

178 assert state == "generator raise started" 2~ dbhblbpb

179 raise OtherDependencyError() 2~ dbhblbpb

180 

181 

182@app.get("/sync_context_b") 1abcde

183def get_sync_context_b(state: dict = Depends(context_b)): 1abcde

184 return state 1qsuwy

185 

186 

187@app.get("/sync_context_b_raise") 1abcde

188def get_sync_context_b_raise(state: dict = Depends(context_b)): 1abcde

189 assert state["context_b"] == "started b" 1CGKQW

190 assert state["context_a"] == "started a" 1CGKQW

191 raise OtherDependencyError() 1CGKQW

192 

193 

194@app.get("/sync_context_b_bg") 1abcde

195async def get_sync_context_b_bg( 1abcde

196 tasks: BackgroundTasks, state: dict = Depends(context_b) 

197): 

198 async def bg(state: dict): 1klmno

199 state["sync_bg"] = ( 1klmno

200 f"sync_bg set - b: {state['context_b']} - a: {state['context_a']}" 

201 ) 

202 

203 tasks.add_task(bg, state) 1klmno

204 return state 1klmno

205 

206 

207@app.middleware("http") 1abcde

208async def middleware(request, call_next): 1abcde

209 response: StreamingResponse = await call_next(request) 2: Z z { f p A | 0 B qbk q C ; 1 D } ~ 2 E rb= , 3 abg r F bb- 4 sbl s G ? . 5 cbdb/ 6 tb@ 7 H ebh t I fb8 J ubm u K [ 9 L gbhb! M vb] # N ibi v O jb$ P wbn w Q ^ % R kblb' S xb_ ( T mbj x U nb) V ybo y W ` * X obpb+ Y zb

210 response.headers["x-state"] = json.dumps(state.copy()) 2{ f p qbk q } rbabg r sbl s cbtbebh t ubm u gbvbibi v wbn w kbxbmbj x ybo y obzb

211 return response 2{ f p qbk q } rbabg r sbl s cbtbebh t ubm u gbvbibi v wbn w kbxbmbj x ybo y obzb

212 

213 

214client = TestClient(app) 1abcde

215 

216 

217def test_async_state(): 1abcde

218 assert state["/async"] == "asyncgen not started" 2{ abebibmb

219 response = client.get("/async") 2{ abebibmb

220 assert response.status_code == 200, response.text 2{ abebibmb

221 assert response.json() == "asyncgen started" 2{ abebibmb

222 assert state["/async"] == "asyncgen completed" 2{ abebibmb

223 

224 

225def test_sync_state(): 1abcde

226 assert state["/sync"] == "generator not started" 2} cbgbkbob

227 response = client.get("/sync") 2} cbgbkbob

228 assert response.status_code == 200, response.text 2} cbgbkbob

229 assert response.json() == "generator started" 2} cbgbkbob

230 assert state["/sync"] == "generator completed" 2} cbgbkbob

231 

232 

233def test_async_raise_other(): 1abcde

234 assert state["/async_raise"] == "asyncgen raise not started" 1:=@]_

235 with pytest.raises(OtherDependencyError): 1:=@]_

236 client.get("/async_raise_other") 1:=@]_

237 assert state["/async_raise"] == "asyncgen raise finalized" 1:=@]_

238 assert "/async_raise" not in errors 1:=@]_

239 

240 

241def test_sync_raise_other(): 1abcde

242 assert state["/sync_raise"] == "generator raise not started" 1;?[^`

243 with pytest.raises(OtherDependencyError): 1;?[^`

244 client.get("/sync_raise_other") 1;?[^`

245 assert state["/sync_raise"] == "generator raise finalized" 1;?[^`

246 assert "/sync_raise" not in errors 1;?[^`

247 

248 

249def test_async_raise_raises(): 1abcde

250 with pytest.raises(AsyncDependencyError): 1Z,7#(

251 client.get("/async_raise") 1Z,7#(

252 assert state["/async_raise"] == "asyncgen raise finalized" 1Z,7#(

253 assert "/async_raise" in errors 1Z,7#(

254 errors.clear() 1Z,7#(

255 

256 

257def test_async_raise_server_error(): 1abcde

258 client = TestClient(app, raise_server_exceptions=False) 1z3HNT

259 response = client.get("/async_raise") 1z3HNT

260 assert response.status_code == 500, response.text 1z3HNT

261 assert state["/async_raise"] == "asyncgen raise finalized" 1z3HNT

262 assert "/async_raise" in errors 1z3HNT

263 errors.clear() 1z3HNT

264 

265 

266def test_context_b(): 1abcde

267 response = client.get("/context_b") 1prtvx

268 data = response.json() 1prtvx

269 assert data["context_b"] == "started b" 1prtvx

270 assert data["context_a"] == "started a" 1prtvx

271 assert state["context_b"] == "finished b with a: started a" 1prtvx

272 assert state["context_a"] == "finished a" 1prtvx

273 

274 

275def test_context_b_raise(): 1abcde

276 with pytest.raises(OtherDependencyError): 1AFIOU

277 client.get("/context_b_raise") 1AFIOU

278 assert state["context_b"] == "finished b with a: started a" 1AFIOU

279 assert state["context_a"] == "finished a" 1AFIOU

280 

281 

282def test_background_tasks(): 1abcde

283 response = client.get("/context_b_bg") 1fghij

284 data = response.json() 1fghij

285 assert data["context_b"] == "started b" 1fghij

286 assert data["context_a"] == "started a" 1fghij

287 assert data["bg"] == "not set" 1fghij

288 middleware_state = json.loads(response.headers["x-state"]) 1fghij

289 assert middleware_state["context_b"] == "finished b with a: started a" 1fghij

290 assert middleware_state["context_a"] == "finished a" 1fghij

291 assert middleware_state["bg"] == "not set" 1fghij

292 assert state["context_b"] == "finished b with a: started a" 1fghij

293 assert state["context_a"] == "finished a" 1fghij

294 assert state["bg"] == "bg set - b: finished b with a: started a - a: finished a" 1fghij

295 

296 

297def test_sync_raise_raises(): 1abcde

298 with pytest.raises(SyncDependencyError): 11.9%*

299 client.get("/sync_raise") 11.9%*

300 assert state["/sync_raise"] == "generator raise finalized" 11.9%*

301 assert "/sync_raise" in errors 11.9%*

302 errors.clear() 11.9%*

303 

304 

305def test_sync_raise_server_error(): 1abcde

306 client = TestClient(app, raise_server_exceptions=False) 1D5LRX

307 response = client.get("/sync_raise") 1D5LRX

308 assert response.status_code == 500, response.text 1D5LRX

309 assert state["/sync_raise"] == "generator raise finalized" 1D5LRX

310 assert "/sync_raise" in errors 1D5LRX

311 errors.clear() 1D5LRX

312 

313 

314def test_sync_async_state(): 1abcde

315 response = client.get("/sync_async") 2qbsbubwbyb

316 assert response.status_code == 200, response.text 2qbsbubwbyb

317 assert response.json() == "asyncgen started" 2qbsbubwbyb

318 assert state["/async"] == "asyncgen completed" 2qbsbubwbyb

319 

320 

321def test_sync_sync_state(): 1abcde

322 response = client.get("/sync_sync") 2rbtbvbxbzb

323 assert response.status_code == 200, response.text 2rbtbvbxbzb

324 assert response.json() == "generator started" 2rbtbvbxbzb

325 assert state["/sync"] == "generator completed" 2rbtbvbxbzb

326 

327 

328def test_sync_async_raise_other(): 1abcde

329 with pytest.raises(OtherDependencyError): 2| bbfbjbnb

330 client.get("/sync_async_raise_other") 2| bbfbjbnb

331 assert state["/async_raise"] == "asyncgen raise finalized" 2| bbfbjbnb

332 assert "/async_raise" not in errors 2| bbfbjbnb

333 

334 

335def test_sync_sync_raise_other(): 1abcde

336 with pytest.raises(OtherDependencyError): 2~ dbhblbpb

337 client.get("/sync_sync_raise_other") 2~ dbhblbpb

338 assert state["/sync_raise"] == "generator raise finalized" 2~ dbhblbpb

339 assert "/sync_raise" not in errors 2~ dbhblbpb

340 

341 

342def test_sync_async_raise_raises(): 1abcde

343 with pytest.raises(AsyncDependencyError): 10-8$)

344 client.get("/sync_async_raise") 10-8$)

345 assert state["/async_raise"] == "asyncgen raise finalized" 10-8$)

346 assert "/async_raise" in errors 10-8$)

347 errors.clear() 10-8$)

348 

349 

350def test_sync_async_raise_server_error(): 1abcde

351 client = TestClient(app, raise_server_exceptions=False) 1B4JPV

352 response = client.get("/sync_async_raise") 1B4JPV

353 assert response.status_code == 500, response.text 1B4JPV

354 assert state["/async_raise"] == "asyncgen raise finalized" 1B4JPV

355 assert "/async_raise" in errors 1B4JPV

356 errors.clear() 1B4JPV

357 

358 

359def test_sync_sync_raise_raises(): 1abcde

360 with pytest.raises(SyncDependencyError): 12/!'+

361 client.get("/sync_sync_raise") 12/!'+

362 assert state["/sync_raise"] == "generator raise finalized" 12/!'+

363 assert "/sync_raise" in errors 12/!'+

364 errors.clear() 12/!'+

365 

366 

367def test_sync_sync_raise_server_error(): 1abcde

368 client = TestClient(app, raise_server_exceptions=False) 1E6MSY

369 response = client.get("/sync_sync_raise") 1E6MSY

370 assert response.status_code == 500, response.text 1E6MSY

371 assert state["/sync_raise"] == "generator raise finalized" 1E6MSY

372 assert "/sync_raise" in errors 1E6MSY

373 errors.clear() 1E6MSY

374 

375 

376def test_sync_context_b(): 1abcde

377 response = client.get("/sync_context_b") 1qsuwy

378 data = response.json() 1qsuwy

379 assert data["context_b"] == "started b" 1qsuwy

380 assert data["context_a"] == "started a" 1qsuwy

381 assert state["context_b"] == "finished b with a: started a" 1qsuwy

382 assert state["context_a"] == "finished a" 1qsuwy

383 

384 

385def test_sync_context_b_raise(): 1abcde

386 with pytest.raises(OtherDependencyError): 1CGKQW

387 client.get("/sync_context_b_raise") 1CGKQW

388 assert state["context_b"] == "finished b with a: started a" 1CGKQW

389 assert state["context_a"] == "finished a" 1CGKQW

390 

391 

392def test_sync_background_tasks(): 1abcde

393 response = client.get("/sync_context_b_bg") 1klmno

394 data = response.json() 1klmno

395 assert data["context_b"] == "started b" 1klmno

396 assert data["context_a"] == "started a" 1klmno

397 assert data["sync_bg"] == "not set" 1klmno

398 assert state["context_b"] == "finished b with a: started a" 1klmno

399 assert state["context_a"] == "finished a" 1klmno

400 assert ( 1klmno

401 state["sync_bg"] 

402 == "sync_bg set - b: finished b with a: started a - a: finished a" 

403 )