diff --git a/.github/BOTMETA.yml b/.github/BOTMETA.yml index 9650fd0ef3..ec9b9b7ddc 100644 --- a/.github/BOTMETA.yml +++ b/.github/BOTMETA.yml @@ -135,6 +135,8 @@ files: $doc_fragments/xenserver.py: labels: xenserver maintainers: bvitnik + $filters/accumulate.py: + maintainers: VannTen $filters/counter.py: maintainers: keilr $filters/crc32.py: diff --git a/plugins/filter/accumulate.py b/plugins/filter/accumulate.py new file mode 100644 index 0000000000..9400936e1d --- /dev/null +++ b/plugins/filter/accumulate.py @@ -0,0 +1,62 @@ +# Copyright (c) Max Gautier +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +DOCUMENTATION = ''' + name: accumulate + short_description: Produce a list of accumulated sums of the input list contents + version_added: 10.1.0 + author: Max Gautier (@VannTen) + description: + - Passthrough to the L(Python itertools.accumulate function,https://docs.python.org/3/library/itertools.html#itertools.accumulate). + - Transforms an input list into the cumulative list of results from applying addition to the elements of the input list. + - Addition means the default Python implementation of C(+) for input list elements type. + options: + _input: + description: A list. + type: list + elements: any + required: true +''' + +RETURN = ''' + _value: + description: A list of cumulated sums of the elements of the input list. + type: list + elements: any +''' + +EXAMPLES = ''' +- name: Enumerate parent directories of some path + ansible.builtin.debug: + var: > + "/some/path/to/my/file" + | split('/') | map('split', '/') + | community.general.accumulate | map('join', '/') + # Produces: ['', '/some', '/some/path', '/some/path/to', '/some/path/to/my', '/some/path/to/my/file'] +- name: Growing string + ansible.builtin.debug: + var: "'abc' | community.general.accumulate" + # Produces ['a', 'ab', 'abc'] +''' + +from itertools import accumulate +from collections.abc import Sequence + +from ansible.errors import AnsibleFilterError + + +def list_accumulate(sequence): + if not isinstance(sequence, Sequence): + raise AnsibleFilterError('Invalid value type (%s) for accumulate (%r)' % + (type(sequence), sequence)) + + return accumulate(sequence) + + +class FilterModule(object): + + def filters(self): + return { + 'accumulate': list_accumulate, + } diff --git a/tests/integration/targets/filter_accumulate/aliases b/tests/integration/targets/filter_accumulate/aliases new file mode 100644 index 0000000000..343f119da8 --- /dev/null +++ b/tests/integration/targets/filter_accumulate/aliases @@ -0,0 +1,5 @@ +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +azp/posix/3 diff --git a/tests/integration/targets/filter_accumulate/tasks/main.yml b/tests/integration/targets/filter_accumulate/tasks/main.yml new file mode 100644 index 0000000000..8fe854228a --- /dev/null +++ b/tests/integration/targets/filter_accumulate/tasks/main.yml @@ -0,0 +1,35 @@ +--- +# Copyright (c), Max Gautier +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +- name: Filter | Accumulate | Test valid values + assert: + that: + - "'abc' | community.general.accumulate == ['a', 'ab', 'abc']" + - "['a', 'b'] | community.general.accumulate == ['a', 'ab']" + - "[1, 2, 3] | community.general.accumulate == [1, 3, 6]" + - "[['foo'],['bar'],['foobar']] | community.general.accumulate == [['foo'], ['foo', 'bar'], ['foo', 'bar', 'foobar']]" + - "'path/to/file' | split('/') | map('split', '/') | community.general.accumulate | map('join', '/') == ['path', 'path/to', 'path/to/file']" + - "[{'foo':1}, {'bar':2}] | map('dict2items') | community.general.accumulate | map('items2dict') == [{'foo':1}, {'foo':1, 'bar':2}]" + + +- name: Filter | Accumulate | Test invalid values | Integer + debug: + var: "1 | community.general.accumulate" + register: integer_result + ignore_errors: true + +- name: Filter | Accumulate | Test invalid values | Non uniform list + debug: + var: "['aa', 1] | community.general.accumulate" + register: non_uniform_list_result + ignore_errors: true + +- name: Filter | Accumulate | Test invalid values | Check errors + assert: + that: + - integer_result is failed + - integer_result.msg is match('Invalid value type.*') + - non_uniform_list_result is failed + - non_uniform_list_result.msg is match('Unexpected templating type error.*can only concatenate str.*')