1e31aef6aSopenharmony_cifrom functools import wraps
2e31aef6aSopenharmony_ci
3e31aef6aSopenharmony_cifrom . import filters
4e31aef6aSopenharmony_cifrom .asyncsupport import auto_aiter
5e31aef6aSopenharmony_cifrom .asyncsupport import auto_await
6e31aef6aSopenharmony_ci
7e31aef6aSopenharmony_ci
8e31aef6aSopenharmony_ciasync def auto_to_seq(value):
9e31aef6aSopenharmony_ci    seq = []
10e31aef6aSopenharmony_ci    if hasattr(value, "__aiter__"):
11e31aef6aSopenharmony_ci        async for item in value:
12e31aef6aSopenharmony_ci            seq.append(item)
13e31aef6aSopenharmony_ci    else:
14e31aef6aSopenharmony_ci        for item in value:
15e31aef6aSopenharmony_ci            seq.append(item)
16e31aef6aSopenharmony_ci    return seq
17e31aef6aSopenharmony_ci
18e31aef6aSopenharmony_ci
19e31aef6aSopenharmony_ciasync def async_select_or_reject(args, kwargs, modfunc, lookup_attr):
20e31aef6aSopenharmony_ci    seq, func = filters.prepare_select_or_reject(args, kwargs, modfunc, lookup_attr)
21e31aef6aSopenharmony_ci    if seq:
22e31aef6aSopenharmony_ci        async for item in auto_aiter(seq):
23e31aef6aSopenharmony_ci            if func(item):
24e31aef6aSopenharmony_ci                yield item
25e31aef6aSopenharmony_ci
26e31aef6aSopenharmony_ci
27e31aef6aSopenharmony_cidef dualfilter(normal_filter, async_filter):
28e31aef6aSopenharmony_ci    wrap_evalctx = False
29e31aef6aSopenharmony_ci    if getattr(normal_filter, "environmentfilter", False) is True:
30e31aef6aSopenharmony_ci
31e31aef6aSopenharmony_ci        def is_async(args):
32e31aef6aSopenharmony_ci            return args[0].is_async
33e31aef6aSopenharmony_ci
34e31aef6aSopenharmony_ci        wrap_evalctx = False
35e31aef6aSopenharmony_ci    else:
36e31aef6aSopenharmony_ci        has_evalctxfilter = getattr(normal_filter, "evalcontextfilter", False) is True
37e31aef6aSopenharmony_ci        has_ctxfilter = getattr(normal_filter, "contextfilter", False) is True
38e31aef6aSopenharmony_ci        wrap_evalctx = not has_evalctxfilter and not has_ctxfilter
39e31aef6aSopenharmony_ci
40e31aef6aSopenharmony_ci        def is_async(args):
41e31aef6aSopenharmony_ci            return args[0].environment.is_async
42e31aef6aSopenharmony_ci
43e31aef6aSopenharmony_ci    @wraps(normal_filter)
44e31aef6aSopenharmony_ci    def wrapper(*args, **kwargs):
45e31aef6aSopenharmony_ci        b = is_async(args)
46e31aef6aSopenharmony_ci        if wrap_evalctx:
47e31aef6aSopenharmony_ci            args = args[1:]
48e31aef6aSopenharmony_ci        if b:
49e31aef6aSopenharmony_ci            return async_filter(*args, **kwargs)
50e31aef6aSopenharmony_ci        return normal_filter(*args, **kwargs)
51e31aef6aSopenharmony_ci
52e31aef6aSopenharmony_ci    if wrap_evalctx:
53e31aef6aSopenharmony_ci        wrapper.evalcontextfilter = True
54e31aef6aSopenharmony_ci
55e31aef6aSopenharmony_ci    wrapper.asyncfiltervariant = True
56e31aef6aSopenharmony_ci
57e31aef6aSopenharmony_ci    return wrapper
58e31aef6aSopenharmony_ci
59e31aef6aSopenharmony_ci
60e31aef6aSopenharmony_cidef asyncfiltervariant(original):
61e31aef6aSopenharmony_ci    def decorator(f):
62e31aef6aSopenharmony_ci        return dualfilter(original, f)
63e31aef6aSopenharmony_ci
64e31aef6aSopenharmony_ci    return decorator
65e31aef6aSopenharmony_ci
66e31aef6aSopenharmony_ci
67e31aef6aSopenharmony_ci@asyncfiltervariant(filters.do_first)
68e31aef6aSopenharmony_ciasync def do_first(environment, seq):
69e31aef6aSopenharmony_ci    try:
70e31aef6aSopenharmony_ci        return await auto_aiter(seq).__anext__()
71e31aef6aSopenharmony_ci    except StopAsyncIteration:
72e31aef6aSopenharmony_ci        return environment.undefined("No first item, sequence was empty.")
73e31aef6aSopenharmony_ci
74e31aef6aSopenharmony_ci
75e31aef6aSopenharmony_ci@asyncfiltervariant(filters.do_groupby)
76e31aef6aSopenharmony_ciasync def do_groupby(environment, value, attribute):
77e31aef6aSopenharmony_ci    expr = filters.make_attrgetter(environment, attribute)
78e31aef6aSopenharmony_ci    return [
79e31aef6aSopenharmony_ci        filters._GroupTuple(key, await auto_to_seq(values))
80e31aef6aSopenharmony_ci        for key, values in filters.groupby(
81e31aef6aSopenharmony_ci            sorted(await auto_to_seq(value), key=expr), expr
82e31aef6aSopenharmony_ci        )
83e31aef6aSopenharmony_ci    ]
84e31aef6aSopenharmony_ci
85e31aef6aSopenharmony_ci
86e31aef6aSopenharmony_ci@asyncfiltervariant(filters.do_join)
87e31aef6aSopenharmony_ciasync def do_join(eval_ctx, value, d=u"", attribute=None):
88e31aef6aSopenharmony_ci    return filters.do_join(eval_ctx, await auto_to_seq(value), d, attribute)
89e31aef6aSopenharmony_ci
90e31aef6aSopenharmony_ci
91e31aef6aSopenharmony_ci@asyncfiltervariant(filters.do_list)
92e31aef6aSopenharmony_ciasync def do_list(value):
93e31aef6aSopenharmony_ci    return await auto_to_seq(value)
94e31aef6aSopenharmony_ci
95e31aef6aSopenharmony_ci
96e31aef6aSopenharmony_ci@asyncfiltervariant(filters.do_reject)
97e31aef6aSopenharmony_ciasync def do_reject(*args, **kwargs):
98e31aef6aSopenharmony_ci    return async_select_or_reject(args, kwargs, lambda x: not x, False)
99e31aef6aSopenharmony_ci
100e31aef6aSopenharmony_ci
101e31aef6aSopenharmony_ci@asyncfiltervariant(filters.do_rejectattr)
102e31aef6aSopenharmony_ciasync def do_rejectattr(*args, **kwargs):
103e31aef6aSopenharmony_ci    return async_select_or_reject(args, kwargs, lambda x: not x, True)
104e31aef6aSopenharmony_ci
105e31aef6aSopenharmony_ci
106e31aef6aSopenharmony_ci@asyncfiltervariant(filters.do_select)
107e31aef6aSopenharmony_ciasync def do_select(*args, **kwargs):
108e31aef6aSopenharmony_ci    return async_select_or_reject(args, kwargs, lambda x: x, False)
109e31aef6aSopenharmony_ci
110e31aef6aSopenharmony_ci
111e31aef6aSopenharmony_ci@asyncfiltervariant(filters.do_selectattr)
112e31aef6aSopenharmony_ciasync def do_selectattr(*args, **kwargs):
113e31aef6aSopenharmony_ci    return async_select_or_reject(args, kwargs, lambda x: x, True)
114e31aef6aSopenharmony_ci
115e31aef6aSopenharmony_ci
116e31aef6aSopenharmony_ci@asyncfiltervariant(filters.do_map)
117e31aef6aSopenharmony_ciasync def do_map(*args, **kwargs):
118e31aef6aSopenharmony_ci    seq, func = filters.prepare_map(args, kwargs)
119e31aef6aSopenharmony_ci    if seq:
120e31aef6aSopenharmony_ci        async for item in auto_aiter(seq):
121e31aef6aSopenharmony_ci            yield await auto_await(func(item))
122e31aef6aSopenharmony_ci
123e31aef6aSopenharmony_ci
124e31aef6aSopenharmony_ci@asyncfiltervariant(filters.do_sum)
125e31aef6aSopenharmony_ciasync def do_sum(environment, iterable, attribute=None, start=0):
126e31aef6aSopenharmony_ci    rv = start
127e31aef6aSopenharmony_ci    if attribute is not None:
128e31aef6aSopenharmony_ci        func = filters.make_attrgetter(environment, attribute)
129e31aef6aSopenharmony_ci    else:
130e31aef6aSopenharmony_ci
131e31aef6aSopenharmony_ci        def func(x):
132e31aef6aSopenharmony_ci            return x
133e31aef6aSopenharmony_ci
134e31aef6aSopenharmony_ci    async for item in auto_aiter(iterable):
135e31aef6aSopenharmony_ci        rv += func(item)
136e31aef6aSopenharmony_ci    return rv
137e31aef6aSopenharmony_ci
138e31aef6aSopenharmony_ci
139e31aef6aSopenharmony_ci@asyncfiltervariant(filters.do_slice)
140e31aef6aSopenharmony_ciasync def do_slice(value, slices, fill_with=None):
141e31aef6aSopenharmony_ci    return filters.do_slice(await auto_to_seq(value), slices, fill_with)
142e31aef6aSopenharmony_ci
143e31aef6aSopenharmony_ci
144e31aef6aSopenharmony_ciASYNC_FILTERS = {
145e31aef6aSopenharmony_ci    "first": do_first,
146e31aef6aSopenharmony_ci    "groupby": do_groupby,
147e31aef6aSopenharmony_ci    "join": do_join,
148e31aef6aSopenharmony_ci    "list": do_list,
149e31aef6aSopenharmony_ci    # we intentionally do not support do_last because that would be
150e31aef6aSopenharmony_ci    # ridiculous
151e31aef6aSopenharmony_ci    "reject": do_reject,
152e31aef6aSopenharmony_ci    "rejectattr": do_rejectattr,
153e31aef6aSopenharmony_ci    "map": do_map,
154e31aef6aSopenharmony_ci    "select": do_select,
155e31aef6aSopenharmony_ci    "selectattr": do_selectattr,
156e31aef6aSopenharmony_ci    "sum": do_sum,
157e31aef6aSopenharmony_ci    "slice": do_slice,
158e31aef6aSopenharmony_ci}
159