Coverage for fastapi / concurrency.py: 100%

20 statements  

« prev     ^ index     » next       coverage.py v7.13.3, created at 2026-02-12 18:15 +0000

1from collections.abc import AsyncGenerator 1abcd

2from contextlib import AbstractContextManager 1abcd

3from contextlib import asynccontextmanager as asynccontextmanager 1abcd

4from typing import TypeVar 1abcd

5 

6import anyio.to_thread 1abcd

7from anyio import CapacityLimiter 1abcd

8from starlette.concurrency import iterate_in_threadpool as iterate_in_threadpool # noqa 1abcd

9from starlette.concurrency import run_in_threadpool as run_in_threadpool # noqa 1abcd

10from starlette.concurrency import ( # noqa 1abcd

11 run_until_first_complete as run_until_first_complete, 

12) 

13 

14_T = TypeVar("_T") 1abcd

15 

16 

17@asynccontextmanager 1abcd

18async def contextmanager_in_threadpool( 1abcd

19 cm: AbstractContextManager[_T], 

20) -> AsyncGenerator[_T, None]: 

21 # blocking __exit__ from running waiting on a free thread 

22 # can create race conditions/deadlocks if the context manager itself 

23 # has its own internal pool (e.g. a database connection pool) 

24 # to avoid this we let __exit__ run without a capacity limit 

25 # since we're creating a new limiter for each call, any non-zero limit 

26 # works (1 is arbitrary) 

27 exit_limiter = CapacityLimiter(1) 2. / : ( k l m n ; = ? @ o [ p q r ] s t u ^ _ ` { | } ~ abbbcbdbebfbgbhbv ibw ) 9 jbx ! kby z A lbe f mbnbob* B C D E pbqbrbsbF tbG H I ubJ K L vbwbxbybzbAbBbCbDbEbFbGbHbIbJbM KbN + # LbO $ MbP Q R Nbg h ObPbQb, S T U V RbSbTbUbW VbX Y Z Wb0 1 2 XbYbZb0b1b2b3b4b5b6b7b8b9b!b#b3 $b4 - % %b5 ' 'b6 7 8 (bi j

28 try: 2. / : ( k l m n ; = ? @ o [ p q r ] s t u ^ _ ` { | } ~ abbbcbdbebfbgbhbv ibw ) 9 jbx ! kby z A lbe f mbnbob* B C D E pbqbrbsbF tbG H I ubJ K L vbwbxbybzbAbBbCbDbEbFbGbHbIbJbM KbN + # LbO $ MbP Q R Nbg h ObPbQb, S T U V RbSbTbUbW VbX Y Z Wb0 1 2 XbYbZb0b1b2b3b4b5b6b7b8b9b!b#b3 $b4 - % %b5 ' 'b6 7 8 (bi j

29 yield await run_in_threadpool(cm.__enter__) 2. / : ( k l m n ; = ? @ o [ p q r ] s t u ^ _ ` { | } ~ abbbcbdbebfbgbhbv ibw ) 9 jbx ! kby z A lbe f mbnbob* B C D E pbqbrbsbF tbG H I ubJ K L vbwbxbybzbAbBbCbDbEbFbGbHbIbJbM KbN + # LbO $ MbP Q R Nbg h ObPbQb, S T U V RbSbTbUbW VbX Y Z Wb0 1 2 XbYbZb0b1b2b3b4b5b6b7b8b9b!b#b3 $b4 - % %b5 ' 'b6 7 8 (bi j

30 except Exception as e: 1(klmnopqrstuvw)9x!yzAef*BCDEFGHIJKLMN+#O$PQRgh,STUVWXYZ01234-%5'678ij

31 ok = bool( 1(klmnopqrstuvw)9x!yzAef*BCDEFGHIJKLMN+#O$PQRgh,STUVWXYZ01234-%5'678ij

32 await anyio.to_thread.run_sync( 

33 cm.__exit__, type(e), e, e.__traceback__, limiter=exit_limiter 

34 ) 

35 ) 

36 if not ok: 1klmnopqrstuvw9x!yzAefBCDEFGHIJKLMN#O$PQRghSTUVWXYZ01234%5'678ij

37 raise e 1klmnopqrstuvwxyzAefBCDEFGHIJKLMNOPQRghSTUVWXYZ012345678ij

38 else: 

39 await anyio.to_thread.run_sync( 2. / : ; = ? @ [ ] ^ _ ` { | } ~ abbbcbdbebfbgbhbibjbkblbe f mbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbg h ObPbQbRbSbTbUbVbWbXbYbZb0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(bi j

40 cm.__exit__, None, None, None, limiter=exit_limiter 

41 )