From: Armin Ronacher Date: Wed, 28 Dec 2016 23:11:40 +0000 (+0100) Subject: Ported map and select X-Git-Tag: 2.9~49 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f7bb60af00e7c76243c7b4409c3acf1c19c510a7;p=thirdparty%2Fjinja.git Ported map and select --- diff --git a/jinja2/asyncfilters.py b/jinja2/asyncfilters.py index 78fafed8..2a6eb520 100644 --- a/jinja2/asyncfilters.py +++ b/jinja2/asyncfilters.py @@ -87,12 +87,33 @@ 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 seq: + yield func(item) + + ASYNC_FILTERS = { 'first': do_first, 'groupby': do_groupby, 'join': do_join, # we intentionally do not support do_last because that would be # ridiculous - 'reject': do_reject, - 'rejectattr': do_rejectattr, + 'reject': do_reject, + 'rejectattr': do_rejectattr, + 'map': do_map, + 'select': do_select, + 'selectattr': do_selectattr, } diff --git a/jinja2/filters.py b/jinja2/filters.py index b16e73ee..2d459732 100644 --- a/jinja2/filters.py +++ b/jinja2/filters.py @@ -821,24 +821,7 @@ def do_map(*args, **kwargs): .. versionadded:: 2.7 """ - context = args[0] - seq = args[1] - - if len(args) == 2 and 'attribute' in kwargs: - attribute = kwargs.pop('attribute') - if kwargs: - raise FilterArgumentError('Unexpected keyword argument %r' % - next(iter(kwargs))) - func = make_attrgetter(context.environment, attribute) - else: - try: - name = args[2] - args = args[3:] - except LookupError: - raise FilterArgumentError('map requires a filter argument') - func = lambda item: context.environment.call_filter( - name, item, args, kwargs, context=context) - + seq, func = prepare_map(args, kwargs) if seq: for item in seq: yield func(item) @@ -921,6 +904,28 @@ def do_rejectattr(*args, **kwargs): return select_or_reject(args, kwargs, lambda x: not x, True) +def prepare_map(args, kwargs): + context = args[0] + seq = args[1] + + if len(args) == 2 and 'attribute' in kwargs: + attribute = kwargs.pop('attribute') + if kwargs: + raise FilterArgumentError('Unexpected keyword argument %r' % + next(iter(kwargs))) + func = make_attrgetter(context.environment, attribute) + else: + try: + name = args[2] + args = args[3:] + except LookupError: + raise FilterArgumentError('map requires a filter argument') + func = lambda item: context.environment.call_filter( + name, item, args, kwargs, context=context) + + return seq, func + + def prepare_select_or_reject(args, kwargs, modfunc, lookup_attr): context = args[0] seq = args[1] diff --git a/tests/test_asyncfilters.py b/tests/test_asyncfilters.py index c5c55b7d..294a9b48 100644 --- a/tests/test_asyncfilters.py +++ b/tests/test_asyncfilters.py @@ -130,3 +130,32 @@ def test_bool_reject(env_async, items): '{{ items()|reject|join("|") }}' ) assert tmpl.render(items=items) == 'None|False|0' + + +def test_simple_select(env_async): + tmpl = env_async.from_string('{{ [1, 2, 3, 4, 5]|select("odd")|join("|") }}') + assert tmpl.render() == '1|3|5' + + +def test_bool_select(env_async): + tmpl = env_async.from_string( + '{{ [none, false, 0, 1, 2, 3, 4, 5]|select|join("|") }}' + ) + assert tmpl.render() == '1|2|3|4|5' + + +def test_simple_select_attr(env_async): + class User(object): + def __init__(self, name, is_active): + self.name = name + self.is_active = is_active + users = [ + User('john', True), + User('jane', True), + User('mike', False), + ] + tmpl = env_async.from_string( + '{{ users|selectattr("is_active")|' + 'map(attribute="name")|join("|") }}' + ) + assert tmpl.render(users=users) == 'john|jane'