diff --git a/docs/docsite/rst/playbooks_filters.rst b/docs/docsite/rst/playbooks_filters.rst index c7d3b38ce4..4b8eddc0df 100644 --- a/docs/docsite/rst/playbooks_filters.rst +++ b/docs/docsite/rst/playbooks_filters.rst @@ -116,6 +116,19 @@ To get the maximum value from a list of numbers:: {{ [3, 4, 2] | max }} +.. versionadded:: 2.5 + +Flatten a list (same thing the `flatten` lookup does):: + + {{ [3, [4, 2] ]|flatten }} + +Flatten only the first level of a list (akin to the `items` lookup):: + + {{ [3, [4, [2]] ]|flatten(level=1) }} + + +To get the minimum value from list of numbers:: + .. _set_theory_filters: Set Theory Filters diff --git a/lib/ansible/plugins/filter/core.py b/lib/ansible/plugins/filter/core.py index 47811fcc22..ce01cfefb2 100644 --- a/lib/ansible/plugins/filter/core.py +++ b/lib/ansible/plugins/filter/core.py @@ -465,6 +465,27 @@ def b64decode(string): return to_text(base64.b64decode(to_bytes(string, errors='surrogate_or_strict'))) +def flatten(mylist, levels=None): + + ret = [] + for element in mylist: + if element in (None, 'None', 'null'): + # ignore undefined items + break + elif isinstance(element, MutableSequence): + if levels is None: + ret.extend(flatten(element)) + elif levels >= 1: + levels = int(levels) - 1 + ret.extend(flatten(element, levels=levels)) + else: + ret.append(element) + else: + ret.append(element) + + return ret + + class FilterModule(object): ''' Ansible core jinja2 filters ''' @@ -472,6 +493,7 @@ class FilterModule(object): return { # jinja2 overrides 'groupby': do_groupby, + 'flatten': flatten, # base 64 'b64decode': b64decode, diff --git a/test/integration/targets/filters/tasks/main.yml b/test/integration/targets/filters/tasks/main.yml index 4daabde476..28821bd258 100644 --- a/test/integration/targets/filters/tasks/main.yml +++ b/test/integration/targets/filters/tasks/main.yml @@ -168,3 +168,20 @@ that: - _bad_urlsplit_filter is failed - "'unknown URL component' in _bad_urlsplit_filter.msg" + +- name: Flatten tests + block: + - name: use flatten + set_fact: + flat_full: '{{orig_list|flatten}}' + flat_one: '{{orig_list|flatten(levels=1)}}' + flat_two: '{{orig_list|flatten(levels=2)}}' + + - name: Verify flatten filter works as expected + assert: + that: + - flat_full == [1, 2, 3, 4, 5, 6, 7] + - flat_one == [1, 2, 3, [4, [5]], 6, 7] + - flat_two == [1, 2, 3, 4, [5], 6, 7] + vars: + orig_list: [1, 2, [3, [4, [5]], 6], 7]