Coverage for fastapi / concurrency.py: 100%
20 statements
« prev ^ index » next coverage.py v7.13.3, created at 2026-04-06 01:24 +0000
« prev ^ index » next coverage.py v7.13.3, created at 2026-04-06 01:24 +0000
1from collections.abc import AsyncGenerator 1abcd
2from contextlib import AbstractContextManager 1abcd
3from contextlib import asynccontextmanager as asynccontextmanager 1abcd
4from typing import TypeVar 1abcd
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)
14_T = TypeVar("_T") 1abcd
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) 2pbqbrbfbq r s t sbtbubu vbwbxbv w x yby z A zbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbB SbTbC D gbhb^ _ UbVbE F ` { WbXbG H I J K L YbZbe f g h 0bib1b2b3bjbM N O P 4b5b6bQ 7b8b9bR S T !bU V W #b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]bX ^b_bY Z kblb| } `b{b0 1 ~ ab|b}b2 3 4 5 6 7 ~baci j k l bcccdcmb8 9 ! # ecfcgc$ hcicjc% ' ( kc) * + lcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDc, EcFc- . nbobbbcbGcHc/ : dbebIcJc; = ? @ [ ] KcLcm n o p
28 try: 2pbqbrbfbq r s t sbtbubu vbwbxbv w x yby z A zbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbB SbTbC D gbhb^ _ UbVbE F ` { WbXbG H I J K L YbZbe f g h 0bib1b2b3bjbM N O P 4b5b6bQ 7b8b9bR S T !bU V W #b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]bX ^b_bY Z kblb| } `b{b0 1 ~ ab|b}b2 3 4 5 6 7 ~baci j k l bcccdcmb8 9 ! # ecfcgc$ hcicjc% ' ( kc) * + lcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDc, EcFc- . nbobbbcbGcHc/ : dbebIcJc; = ? @ [ ] KcLcm n o p
29 yield await run_in_threadpool(cm.__enter__) 2pbqbrbfbq r s t sbtbubu vbwbxbv w x yby z A zbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbB SbTbC D gbhb^ _ UbVbE F ` { WbXbG H I J K L YbZbe f g h 0bibOc1b2b3bjbM N O P 4b5b6bQ 7b8b9bR S T !bU V W #b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]bX ^b_bY Z kblb| } `b{b0 1 ~ ab|b}b2 3 4 5 6 7 ~baci j k l bcccdcmb8 9 ! # ecfcgc$ hcicjc% ' ( kc) * + lcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDc, EcFc- . nbobbbcbGcHc/ : dbebIcJc; = ? @ [ ] KcLcm n o p
30 except Exception as e: 2fbq r s t u v w x y z A B C D gbhb^ _ E F ` { G H I J K L e f g h ibMcjbM N O P Q R S T U V W X Y Z kblb| } 0 1 ~ ab2 3 4 5 6 7 i j k l mb8 9 ! # $ % ' ( ) * + , - . nbobbbcb/ : dbeb; = ? @ [ ] m n o p
31 ok = bool( 2fbq r s t u v w x y z A B C D gbhb^ _ E F ` { G H I J K L e f g h ibMcNcjbM N O P Q R S T U V W X Y Z kblb| } 0 1 ~ ab2 3 4 5 6 7 i j k l mb8 9 ! # $ % ' ( ) * + , - . nbobbbcb/ : dbeb; = ? @ [ ] m n o p
32 await anyio.to_thread.run_sync(
33 cm.__exit__, type(e), e, e.__traceback__, limiter=exit_limiter
34 )
35 )
36 if not ok: 2q r s t u v w x y z A B C D ^ _ E F ` { G H I J K L e f g h McNcM N O P Q R S T U V W X Y Z | } 0 1 ~ ab2 3 4 5 6 7 i j k l 8 9 ! # $ % ' ( ) * + , - . bbcb/ : dbeb; = ? @ [ ] m n o p
37 raise e 2q r s t u v w x y z A B C D E F G H I J K L e f g h McNcM N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 i j k l 8 9 ! # $ % ' ( ) * + , - . / : ; = ? @ [ ] m n o p
38 else:
39 await anyio.to_thread.run_sync( 2pbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZbe f g h Pc0b1b2b3b4b5b6b7b8b9b!b#b$b%b'b(b)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~baci j k l bcccdcecfcgchcicjckclcmcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcm n o p
40 cm.__exit__, None, None, None, limiter=exit_limiter
41 )