From ae08c6a639b492ee5ad24048f40c8a5792eacdcb Mon Sep 17 00:00:00 2001 From: Martin Krizek Date: Mon, 23 Nov 2020 08:55:18 +0100 Subject: [PATCH] Ensure Ansible's unique filter preserves order (#67856) Fixes #63417 --- .../63417-unique-filter-preserve-order.yml | 2 ++ lib/ansible/plugins/filter/mathstuff.py | 18 ++++++------------ test/units/plugins/filter/test_mathstuff.py | 12 ++++++------ 3 files changed, 14 insertions(+), 18 deletions(-) create mode 100644 changelogs/fragments/63417-unique-filter-preserve-order.yml diff --git a/changelogs/fragments/63417-unique-filter-preserve-order.yml b/changelogs/fragments/63417-unique-filter-preserve-order.yml new file mode 100644 index 00000000000..da433fa2e09 --- /dev/null +++ b/changelogs/fragments/63417-unique-filter-preserve-order.yml @@ -0,0 +1,2 @@ +bugfixes: + - Ensure Ansible's unique filter preserves order (https://github.com/ansible/ansible/issues/63417) diff --git a/lib/ansible/plugins/filter/mathstuff.py b/lib/ansible/plugins/filter/mathstuff.py index 341f5b38216..77baa7ef006 100644 --- a/lib/ansible/plugins/filter/mathstuff.py +++ b/lib/ansible/plugins/filter/mathstuff.py @@ -62,11 +62,7 @@ def unique(environment, a, case_sensitive=False, attribute=None): error = e = None try: if HAS_UNIQUE: - c = do_unique(environment, a, case_sensitive=case_sensitive, attribute=attribute) - if isinstance(a, Hashable): - c = set(c) - else: - c = list(c) + c = list(do_unique(environment, a, case_sensitive=case_sensitive, attribute=attribute)) except TypeError as e: error = e _do_fail(e) @@ -82,13 +78,11 @@ def unique(environment, a, case_sensitive=False, attribute=None): raise AnsibleFilterError("Ansible's unique filter does not support case_sensitive nor attribute parameters, " "you need a newer version of Jinja2 that provides their version of the filter.") - if isinstance(a, Hashable): - c = set(a) - else: - c = [] - for x in a: - if x not in c: - c.append(x) + c = [] + for x in a: + if x not in c: + c.append(x) + return c diff --git a/test/units/plugins/filter/test_mathstuff.py b/test/units/plugins/filter/test_mathstuff.py index 78095e35593..d44a7146699 100644 --- a/test/units/plugins/filter/test_mathstuff.py +++ b/test/units/plugins/filter/test_mathstuff.py @@ -12,10 +12,10 @@ import ansible.plugins.filter.mathstuff as ms from ansible.errors import AnsibleFilterError, AnsibleFilterTypeError -UNIQUE_DATA = (([1, 3, 4, 2], sorted([1, 2, 3, 4])), - ([1, 3, 2, 4, 2, 3], sorted([1, 2, 3, 4])), - (['a', 'b', 'c', 'd'], sorted(['a', 'b', 'c', 'd'])), - (['a', 'a', 'd', 'b', 'a', 'd', 'c', 'b'], sorted(['a', 'b', 'c', 'd'])), +UNIQUE_DATA = (([1, 3, 4, 2], [1, 3, 4, 2]), + ([1, 3, 2, 4, 2, 3], [1, 3, 2, 4]), + (['a', 'b', 'c', 'd'], ['a', 'b', 'c', 'd']), + (['a', 'a', 'd', 'b', 'a', 'd', 'c', 'b'], ['a', 'd', 'b', 'c']), ) TWO_SETS_DATA = (([1, 2], [3, 4], ([], sorted([1, 2]), sorted([1, 2, 3, 4]), sorted([1, 2, 3, 4]))), @@ -29,10 +29,10 @@ env = Environment() @pytest.mark.parametrize('data, expected', UNIQUE_DATA) class TestUnique: def test_unhashable(self, data, expected): - assert sorted(ms.unique(env, list(data))) == expected + assert ms.unique(env, list(data)) == expected def test_hashable(self, data, expected): - assert sorted(ms.unique(env, tuple(data))) == expected + assert ms.unique(env, tuple(data)) == expected @pytest.mark.parametrize('dataset1, dataset2, expected', TWO_SETS_DATA)