From 76af7110ead6083e75072f9e76242c9ce79b76ed Mon Sep 17 00:00:00 2001 From: Mehdi ABAAKOUK Date: Fri, 23 Dec 2022 09:46:29 +0100 Subject: [PATCH] make unique filter async-aware --- CHANGES.rst | 2 ++ src/jinja2/filters.py | 14 +++++++++++++- tests/test_async_filters.py | 7 +++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index 540d5cccb..e4bffbfb9 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -16,6 +16,8 @@ Unreleased :pr:`1960` - The runtime uses the correct ``concat`` function for the current environment when calling block references. :issue:`1701` +- Make ``|unique`` async-aware, allowing it to be used after another + async-aware filter. :issue:`1781` Version 3.1.4 diff --git a/src/jinja2/filters.py b/src/jinja2/filters.py index 4c949cbde..af9f6bc0e 100644 --- a/src/jinja2/filters.py +++ b/src/jinja2/filters.py @@ -438,7 +438,7 @@ def do_sort( @pass_environment -def do_unique( +def sync_do_unique( environment: "Environment", value: "t.Iterable[V]", case_sensitive: bool = False, @@ -470,6 +470,18 @@ def do_unique( yield item +@async_variant(sync_do_unique) # type: ignore +async def do_unique( + environment: "Environment", + value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", + case_sensitive: bool = False, + attribute: t.Optional[t.Union[str, int]] = None, +) -> "t.Iterator[V]": + return sync_do_unique( + environment, await auto_to_list(value), case_sensitive, attribute + ) + + def _min_or_max( environment: "Environment", value: "t.Iterable[V]", diff --git a/tests/test_async_filters.py b/tests/test_async_filters.py index e8cc350d5..e9892f1ed 100644 --- a/tests/test_async_filters.py +++ b/tests/test_async_filters.py @@ -277,6 +277,13 @@ def test_slice(env_async, items): ) +def test_unique_with_async_gen(env_async): + items = ["a", "b", "c", "c", "a", "d", "z"] + tmpl = env_async.from_string("{{ items|reject('==', 'z')|unique|list }}") + out = tmpl.render(items=items) + assert out == "['a', 'b', 'c', 'd']" + + def test_custom_async_filter(env_async, run_async_fn): async def customfilter(val): return str(val)