3 from functools
import WRAPPER_ASSIGNMENTS
4 from functools
import wraps
6 from .utils
import _PassArg
7 from .utils
import pass_eval_context
12 def async_variant(normal_func
): # type: ignore
13 def decorator(async_func
): # type: ignore
14 pass_arg
= _PassArg
.from_obj(normal_func
)
15 need_eval_context
= pass_arg
is None
17 if pass_arg
is _PassArg
.environment
:
19 def is_async(args
: t
.Any
) -> bool:
20 return t
.cast(bool, args
[0].is_async
)
24 def is_async(args
: t
.Any
) -> bool:
25 return t
.cast(bool, args
[0].environment
.is_async
)
27 # Take the doc and annotations from the sync function, but the
28 # name from the async function. Pallets-Sphinx-Themes
29 # build_function_directive expects __wrapped__ to point to the
31 async_func_attrs
= ("__module__", "__name__", "__qualname__")
32 normal_func_attrs
= tuple(set(WRAPPER_ASSIGNMENTS
).difference(async_func_attrs
))
34 @wraps(normal_func
, assigned
=normal_func_attrs
)
35 @wraps(async_func
, assigned
=async_func_attrs
, updated
=())
36 def wrapper(*args
, **kwargs
): # type: ignore
43 return async_func(*args
, **kwargs
)
45 return normal_func(*args
, **kwargs
)
48 wrapper
= pass_eval_context(wrapper
)
50 wrapper
.jinja_async_variant
= True
56 _common_primitives
= {int, float, bool, str, list, dict, tuple, type(None)}
59 async def auto_await(value
: t
.Union
[t
.Awaitable
["V"], "V"]) -> "V":
60 # Avoid a costly call to isawaitable
61 if type(value
) in _common_primitives
:
62 return t
.cast("V", value
)
64 if inspect
.isawaitable(value
):
65 return await t
.cast("t.Awaitable[V]", value
)
67 return t
.cast("V", value
)
71 iterable
: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
72 ) -> "t.AsyncIterator[V]":
73 if hasattr(iterable
, "__aiter__"):
74 async for item
in t
.cast("t.AsyncIterable[V]", iterable
):
77 for item
in t
.cast("t.Iterable[V]", iterable
):
81 async def auto_to_list(
82 value
: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
84 return [x
async for x
in auto_aiter(value
)]