You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
159 lines
4.2 KiB
159 lines
4.2 KiB
4 years ago
|
from functools import wraps
|
||
|
|
||
|
from . import filters
|
||
|
from .asyncsupport import auto_aiter
|
||
|
from .asyncsupport import auto_await
|
||
|
|
||
|
|
||
|
async def auto_to_seq(value):
|
||
|
seq = []
|
||
|
if hasattr(value, "__aiter__"):
|
||
|
async for item in value:
|
||
|
seq.append(item)
|
||
|
else:
|
||
|
for item in value:
|
||
|
seq.append(item)
|
||
|
return seq
|
||
|
|
||
|
|
||
|
async def async_select_or_reject(args, kwargs, modfunc, lookup_attr):
|
||
|
seq, func = filters.prepare_select_or_reject(args, kwargs, modfunc, lookup_attr)
|
||
|
if seq:
|
||
|
async for item in auto_aiter(seq):
|
||
|
if func(item):
|
||
|
yield item
|
||
|
|
||
|
|
||
|
def dualfilter(normal_filter, async_filter):
|
||
|
wrap_evalctx = False
|
||
|
if getattr(normal_filter, "environmentfilter", False) is True:
|
||
|
|
||
|
def is_async(args):
|
||
|
return args[0].is_async
|
||
|
|
||
|
wrap_evalctx = False
|
||
|
else:
|
||
|
has_evalctxfilter = getattr(normal_filter, "evalcontextfilter", False) is True
|
||
|
has_ctxfilter = getattr(normal_filter, "contextfilter", False) is True
|
||
|
wrap_evalctx = not has_evalctxfilter and not has_ctxfilter
|
||
|
|
||
|
def is_async(args):
|
||
|
return args[0].environment.is_async
|
||
|
|
||
|
@wraps(normal_filter)
|
||
|
def wrapper(*args, **kwargs):
|
||
|
b = is_async(args)
|
||
|
if wrap_evalctx:
|
||
|
args = args[1:]
|
||
|
if b:
|
||
|
return async_filter(*args, **kwargs)
|
||
|
return normal_filter(*args, **kwargs)
|
||
|
|
||
|
if wrap_evalctx:
|
||
|
wrapper.evalcontextfilter = True
|
||
|
|
||
|
wrapper.asyncfiltervariant = True
|
||
|
|
||
|
return wrapper
|
||
|
|
||
|
|
||
|
def asyncfiltervariant(original):
|
||
|
def decorator(f):
|
||
|
return dualfilter(original, f)
|
||
|
|
||
|
return decorator
|
||
|
|
||
|
|
||
|
@asyncfiltervariant(filters.do_first)
|
||
|
async def do_first(environment, seq):
|
||
|
try:
|
||
|
return await auto_aiter(seq).__anext__()
|
||
|
except StopAsyncIteration:
|
||
|
return environment.undefined("No first item, sequence was empty.")
|
||
|
|
||
|
|
||
|
@asyncfiltervariant(filters.do_groupby)
|
||
|
async def do_groupby(environment, value, attribute):
|
||
|
expr = filters.make_attrgetter(environment, attribute)
|
||
|
return [
|
||
|
filters._GroupTuple(key, await auto_to_seq(values))
|
||
|
for key, values in filters.groupby(
|
||
|
sorted(await auto_to_seq(value), key=expr), expr
|
||
|
)
|
||
|
]
|
||
|
|
||
|
|
||
|
@asyncfiltervariant(filters.do_join)
|
||
|
async def do_join(eval_ctx, value, d=u"", attribute=None):
|
||
|
return filters.do_join(eval_ctx, await auto_to_seq(value), d, attribute)
|
||
|
|
||
|
|
||
|
@asyncfiltervariant(filters.do_list)
|
||
|
async def do_list(value):
|
||
|
return await auto_to_seq(value)
|
||
|
|
||
|
|
||
|
@asyncfiltervariant(filters.do_reject)
|
||
|
async def do_reject(*args, **kwargs):
|
||
|
return async_select_or_reject(args, kwargs, lambda x: not x, False)
|
||
|
|
||
|
|
||
|
@asyncfiltervariant(filters.do_rejectattr)
|
||
|
async def do_rejectattr(*args, **kwargs):
|
||
|
return async_select_or_reject(args, kwargs, lambda x: not x, True)
|
||
|
|
||
|
|
||
|
@asyncfiltervariant(filters.do_select)
|
||
|
async def do_select(*args, **kwargs):
|
||
|
return async_select_or_reject(args, kwargs, lambda x: x, False)
|
||
|
|
||
|
|
||
|
@asyncfiltervariant(filters.do_selectattr)
|
||
|
async def do_selectattr(*args, **kwargs):
|
||
|
return async_select_or_reject(args, kwargs, lambda x: x, True)
|
||
|
|
||
|
|
||
|
@asyncfiltervariant(filters.do_map)
|
||
|
async def do_map(*args, **kwargs):
|
||
|
seq, func = filters.prepare_map(args, kwargs)
|
||
|
if seq:
|
||
|
async for item in auto_aiter(seq):
|
||
|
yield await auto_await(func(item))
|
||
|
|
||
|
|
||
|
@asyncfiltervariant(filters.do_sum)
|
||
|
async def do_sum(environment, iterable, attribute=None, start=0):
|
||
|
rv = start
|
||
|
if attribute is not None:
|
||
|
func = filters.make_attrgetter(environment, attribute)
|
||
|
else:
|
||
|
|
||
|
def func(x):
|
||
|
return x
|
||
|
|
||
|
async for item in auto_aiter(iterable):
|
||
|
rv += func(item)
|
||
|
return rv
|
||
|
|
||
|
|
||
|
@asyncfiltervariant(filters.do_slice)
|
||
|
async def do_slice(value, slices, fill_with=None):
|
||
|
return filters.do_slice(await auto_to_seq(value), slices, fill_with)
|
||
|
|
||
|
|
||
|
ASYNC_FILTERS = {
|
||
|
"first": do_first,
|
||
|
"groupby": do_groupby,
|
||
|
"join": do_join,
|
||
|
"list": do_list,
|
||
|
# we intentionally do not support do_last because that would be
|
||
|
# ridiculous
|
||
|
"reject": do_reject,
|
||
|
"rejectattr": do_rejectattr,
|
||
|
"map": do_map,
|
||
|
"select": do_select,
|
||
|
"selectattr": do_selectattr,
|
||
|
"sum": do_sum,
|
||
|
"slice": do_slice,
|
||
|
}
|