Coverage for fastapi/concurrency.py: 100%

18 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2025-09-29 03:37 +0000

1from contextlib import asynccontextmanager as asynccontextmanager 1abcdef

2from typing import AsyncGenerator, ContextManager, TypeVar 1abcdef

3 

4import anyio.to_thread 1abcdef

5from anyio import CapacityLimiter 1abcdef

6from starlette.concurrency import iterate_in_threadpool as iterate_in_threadpool # noqa 1abcdef

7from starlette.concurrency import run_in_threadpool as run_in_threadpool # noqa 1abcdef

8from starlette.concurrency import ( # noqa 1abcdef

9 run_until_first_complete as run_until_first_complete, 

10) 

11 

12_T = TypeVar("_T") 1abcdef

13 

14 

15@asynccontextmanager 1abcdef

16async def contextmanager_in_threadpool( 1abcdef

17 cm: ContextManager[_T], 

18) -> AsyncGenerator[_T, None]: 

19 # blocking __exit__ from running waiting on a free thread 

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

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

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

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

24 # works (1 is arbitrary) 

25 exit_limiter = CapacityLimiter(1) 23b4b5bTbs t u v 6b7b8b9bw !bx y z #bA B C $bD %bE UbFb'bF Gb(bG H I g h )b*b+bHbJ K L M ,b-b.b/bN :bO P Q ;bR S T =bU ?bV IbJb@bW Kb[bX Y Z i j ]b^b_bVb0 1 2 3 `b{b|b}b4 ~b5 6 7 ac8 9 ! bc# cc$ WbLbdc% Mbec' ( ) k l fcgchcXb* + , - icjckclc. mc/ : ; nc= ? @ oc[ pc] YbNbqc^ Obrc_ ` { m n sctcucZb| } ~ abvcwcxcycbbzccbdbebAcfbgbhbBcibCcjb0bPbDckbQbEclbmbnbo p FcGcHc1bobpbqbrbIcJcKcLcsbMctbubvbNcwbxbybOczbPcAb2bRbQcBbSbRcCbDbEbq r

26 try: 23b4b5bTbs t u v 6b7b8b9bw !bx y z #bA B C $bD %bE UbFb'bF Gb(bG H I g h )b*b+bHbJ K L M ,b-b.b/bN :bO P Q ;bR S T =bU ?bV IbJb@bW Kb[bX Y Z i j ]b^b_bVb0 1 2 3 `b{b|b}b4 ~b5 6 7 ac8 9 ! bc# cc$ WbLbdc% Mbec' ( ) k l fcgchcXb* + , - icjckclc. mc/ : ; nc= ? @ oc[ pc] YbNbqc^ Obrc_ ` { m n sctcucZb| } ~ abvcwcxcycbbzccbdbebAcfbgbhbBcibCcjb0bPbDckbQbEclbmbnbo p FcGcHc1bobpbqbrbIcJcKcLcsbMctbubvbNcwbxbybOczbPcAb2bRbQcBbSbRcCbDbEbq r

27 yield await run_in_threadpool(cm.__enter__) 23b4b5bTbs t u v 6b7b8b9bw !bx y z #bA B C $bD %bE UbFb'bF Gb(bG H I g h )b*b+bHbJ K L M ,b-b.b/bN :bO P Q ;bR S T =bU ?bV IbJb@bW Kb[bX Y Z i j ]b^b_bVb0 1 2 3 `b{b|b}b4 ~b5 6 7 ac8 9 ! bc# cc$ WbLbdc% Mbec' ( ) k l fcgchcXb* + , - icjckclc. mc/ : ; nc= ? @ oc[ pc] YbNbqc^ Obrc_ ` { m n sctcucZb| } ~ abvcwcxcycbbzccbdbebAcfbgbhbBcibCcjb0bPbDckbQbEclbmbnbo p FcGcHc1bobpbqbrbIcJcKcLcsbMctbubvbNcwbxbybOczbPcAb2bRbQcBbSbRcCbDbEbq r

28 except Exception as e: 2Tbs t u v w x y z A B C D E UbFbF GbG H I g h HbJ K L M N O P Q R S T U V IbJbW KbX Y Z i j Vb0 1 2 3 4 5 6 7 8 9 ! # $ WbLb% Mb' ( ) k l Xb* + , - . / : ; = ? @ [ ] YbNb^ Ob_ ` { m n Zb| } ~ abbbcbdbebfbgbhbibjb0bPbkbQblbmbnbo p 1bobpbqbrbsbtbubvbwbxbybzbAb2bRbBbSbCbDbEbq r

29 ok = bool( 2Tbs t u v w x y z A B C D E UbFbF GbG H I g h HbJ K L M N O P Q R S T U V IbJbW KbX Y Z i j Vb0 1 2 3 4 5 6 7 8 9 ! # $ WbLb% Mb' ( ) k l Xb* + , - . / : ; = ? @ [ ] YbNb^ Ob_ ` { m n Zb| } ~ abbbcbdbebfbgbhbibjb0bPbkbQblbmbnbo p 1bobpbqbrbsbtbubvbwbxbybzbAb2bRbBbSbCbDbEbq r

30 await anyio.to_thread.run_sync( 

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

32 ) 

33 ) 

34 if not ok: 2s t u v w x y z A B C D E FbF GbG H I g h J K L M N O P Q R S T U V JbW KbX Y Z i j 0 1 2 3 4 5 6 7 8 9 ! # $ Lb% Mb' ( ) k l * + , - . / : ; = ? @ [ ] Nb^ Ob_ ` { m n | } ~ abbbcbdbebfbgbhbibjbPbkbQblbmbnbo p obpbqbrbsbtbubvbwbxbybzbAbRbBbSbCbDbEbq r

35 raise e 2s t u v w x y z A B C D E F G H I g h HbJ K L M N O P Q R S T U V IbW X Y Z i j 0 1 2 3 4 5 6 7 8 9 ! # $ % ' ( ) k l * + , - . / : ; = ? @ [ ] ^ _ ` { m n | } ~ abbbcbdbebfbgbhbibjbkblbmbnbo p obpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbq r

36 else: 

37 await anyio.to_thread.run_sync( 23b4b5b6b7b8b9b!b#b$b%b'b(bg h )b*b+b,b-b.b/b:b;b=b?b@b[bi j ]b^b_b`b{b|b}b~bacbcccdceck l fcgchcicjckclcmcncocpcqcrcm n sctcucvcwcxcyczcAcBcCcDcEco p FcGcHcIcJcKcLcMcNcOcPcQcRcq r

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

39 )