52 lines
1.7 KiB
Python
52 lines
1.7 KiB
Python
|
from typing import Any, Callable
|
||
|
|
||
|
from starlette.concurrency import iterate_in_threadpool as iterate_in_threadpool # noqa
|
||
|
from starlette.concurrency import run_in_threadpool as run_in_threadpool # noqa
|
||
|
from starlette.concurrency import ( # noqa
|
||
|
run_until_first_complete as run_until_first_complete,
|
||
|
)
|
||
|
|
||
|
asynccontextmanager_error_message = """
|
||
|
FastAPI's contextmanager_in_threadpool require Python 3.7 or above,
|
||
|
or the backport for Python 3.6, installed with:
|
||
|
pip install async-generator
|
||
|
"""
|
||
|
|
||
|
|
||
|
def _fake_asynccontextmanager(func: Callable[..., Any]) -> Callable[..., Any]:
|
||
|
def raiser(*args: Any, **kwargs: Any) -> Any:
|
||
|
raise RuntimeError(asynccontextmanager_error_message)
|
||
|
|
||
|
return raiser
|
||
|
|
||
|
|
||
|
try:
|
||
|
from contextlib import asynccontextmanager as asynccontextmanager # type: ignore
|
||
|
except ImportError:
|
||
|
try:
|
||
|
from async_generator import ( # type: ignore # isort: skip
|
||
|
asynccontextmanager as asynccontextmanager,
|
||
|
)
|
||
|
except ImportError: # pragma: no cover
|
||
|
asynccontextmanager = _fake_asynccontextmanager
|
||
|
|
||
|
try:
|
||
|
from contextlib import AsyncExitStack as AsyncExitStack # type: ignore
|
||
|
except ImportError:
|
||
|
try:
|
||
|
from async_exit_stack import AsyncExitStack as AsyncExitStack # type: ignore
|
||
|
except ImportError: # pragma: no cover
|
||
|
AsyncExitStack = None # type: ignore
|
||
|
|
||
|
|
||
|
@asynccontextmanager # type: ignore
|
||
|
async def contextmanager_in_threadpool(cm: Any) -> Any:
|
||
|
try:
|
||
|
yield await run_in_threadpool(cm.__enter__)
|
||
|
except Exception as e:
|
||
|
ok = await run_in_threadpool(cm.__exit__, type(e), e, None)
|
||
|
if not ok:
|
||
|
raise e
|
||
|
else:
|
||
|
await run_in_threadpool(cm.__exit__, None, None, None)
|