1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

[PR #8475/8f60f3ae backport][stable-8] Update docs lists_mergeby (#8494)

Update docs lists_mergeby (#8475)

* Fix #8474. Complete examples and documentation of lists_mergeby

* Fix docs syntax O(_input)

* Update docs.

* Update plugins/filter/lists_mergeby.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update plugins/filter/lists_mergeby.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update plugins/filter/lists_mergeby.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update plugins/filter/lists_mergeby.py

Co-authored-by: Felix Fontein <felix@fontein.de>

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 8f60f3aef9)

Co-authored-by: Vladimir Botka <vbotka@gmail.com>
This commit is contained in:
patchback[bot] 2024-06-13 07:47:59 +02:00 committed by GitHub
parent b756728718
commit 4f37a931a0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (c) 2020-2022, Vladimir Botka <vbotka@gmail.com> # Copyright (c) 2020-2024, Vladimir Botka <vbotka@gmail.com>
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # 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 # SPDX-License-Identifier: GPL-3.0-or-later
@ -12,22 +12,32 @@ DOCUMENTATION = '''
version_added: 2.0.0 version_added: 2.0.0
author: Vladimir Botka (@vbotka) author: Vladimir Botka (@vbotka)
description: description:
- Merge two or more lists by attribute O(index). Optional parameters O(recursive) and O(list_merge) - Merge two or more lists by attribute O(index). Optional
control the merging of the lists in values. The function merge_hash from ansible.utils.vars parameters O(recursive) and O(list_merge) control the merging of
is used. To learn details on how to use the parameters O(recursive) and O(list_merge) see the nested dictionaries and lists.
Ansible User's Guide chapter "Using filters to manipulate data" section "Combining - The function C(merge_hash) from C(ansible.utils.vars) is used.
hashes/dictionaries". - To learn details on how to use the parameters O(recursive) and
O(list_merge) see Ansible User's Guide chapter "Using filters to
manipulate data" section R(Combining hashes/dictionaries, combine_filter) or the
filter P(ansible.builtin.combine#filter).
positional: another_list, index positional: another_list, index
options: options:
_input: _input:
description: A list of dictionaries. description:
- A list of dictionaries, or a list of lists of dictionaries.
- The required type of the C(elements) is set to C(raw)
because all elements of O(_input) can be either dictionaries
or lists.
type: list type: list
elements: dictionary elements: raw
required: true required: true
another_list: another_list:
description: Another list of dictionaries. This parameter can be specified multiple times. description:
- Another list of dictionaries, or a list of lists of dictionaries.
- This parameter can be specified multiple times.
type: list type: list
elements: dictionary elements: raw
index: index:
description: description:
- The dictionary key that must be present in every dictionary in every list that is used to - The dictionary key that must be present in every dictionary in every list that is used to
@ -55,40 +65,134 @@ DOCUMENTATION = '''
''' '''
EXAMPLES = ''' EXAMPLES = '''
- name: Merge two lists # Some results below are manually formatted for better readability. The
# dictionaries' keys will be sorted alphabetically in real output.
- name: Example 1. Merge two lists. The results r1 and r2 are the same.
ansible.builtin.debug: ansible.builtin.debug:
msg: >- msg: |
{{ list1 | community.general.lists_mergeby( r1: {{ r1 }}
list2, r2: {{ r2 }}
'index',
recursive=True,
list_merge='append'
) }}"
vars: vars:
list1: list1:
- index: a - {index: a, value: 123}
value: 123 - {index: b, value: 4}
- index: b
value: 42
list2: list2:
- index: a - {index: a, foo: bar}
foo: bar - {index: c, foo: baz}
- index: c r1: "{{ list1 | community.general.lists_mergeby(list2, 'index') }}"
foo: baz r2: "{{ [list1, list2] | community.general.lists_mergeby('index') }}"
# Produces the following list of dictionaries:
# { # r1:
# "index": "a", # - {index: a, foo: bar, value: 123}
# "foo": "bar", # - {index: b, value: 4}
# "value": 123 # - {index: c, foo: baz}
# }, # r2:
# { # - {index: a, foo: bar, value: 123}
# "index": "b", # - {index: b, value: 4}
# "value": 42 # - {index: c, foo: baz}
# },
# { - name: Example 2. Merge three lists
# "index": "c", ansible.builtin.debug:
# "foo": "baz" var: r
# } vars:
list1:
- {index: a, value: 123}
- {index: b, value: 4}
list2:
- {index: a, foo: bar}
- {index: c, foo: baz}
list3:
- {index: d, foo: qux}
r: "{{ [list1, list2, list3] | community.general.lists_mergeby('index') }}"
# r:
# - {index: a, foo: bar, value: 123}
# - {index: b, value: 4}
# - {index: c, foo: baz}
# - {index: d, foo: qux}
- name: Example 3. Merge single list. The result is the same as 2.
ansible.builtin.debug:
var: r
vars:
list1:
- {index: a, value: 123}
- {index: b, value: 4}
- {index: a, foo: bar}
- {index: c, foo: baz}
- {index: d, foo: qux}
r: "{{ [list1, []] | community.general.lists_mergeby('index') }}"
# r:
# - {index: a, foo: bar, value: 123}
# - {index: b, value: 4}
# - {index: c, foo: baz}
# - {index: d, foo: qux}
- name: Example 4. Merge two lists. By default, replace nested lists.
ansible.builtin.debug:
var: r
vars:
list1:
- {index: a, foo: [X1, X2]}
- {index: b, foo: [X1, X2]}
list2:
- {index: a, foo: [Y1, Y2]}
- {index: b, foo: [Y1, Y2]}
r: "{{ [list1, list2] | community.general.lists_mergeby('index') }}"
# r:
# - {index: a, foo: [Y1, Y2]}
# - {index: b, foo: [Y1, Y2]}
- name: Example 5. Merge two lists. Append nested lists.
ansible.builtin.debug:
var: r
vars:
list1:
- {index: a, foo: [X1, X2]}
- {index: b, foo: [X1, X2]}
list2:
- {index: a, foo: [Y1, Y2]}
- {index: b, foo: [Y1, Y2]}
r: "{{ [list1, list2] | community.general.lists_mergeby('index', list_merge='append') }}"
# r:
# - {index: a, foo: [X1, X2, Y1, Y2]}
# - {index: b, foo: [X1, X2, Y1, Y2]}
- name: Example 6. Merge two lists. By default, do not merge nested dictionaries.
ansible.builtin.debug:
var: r
vars:
list1:
- {index: a, foo: {x: 1, y: 2}}
- {index: b, foo: [X1, X2]}
list2:
- {index: a, foo: {y: 3, z: 4}}
- {index: b, foo: [Y1, Y2]}
r: "{{ [list1, list2] | community.general.lists_mergeby('index') }}"
# r:
# - {index: a, foo: {y: 3, z: 4}}
# - {index: b, foo: [Y1, Y2]}
- name: Example 7. Merge two lists. Merge nested dictionaries too.
ansible.builtin.debug:
var: r
vars:
list1:
- {index: a, foo: {x: 1, y: 2}}
- {index: b, foo: [X1, X2]}
list2:
- {index: a, foo: {y: 3, z: 4}}
- {index: b, foo: [Y1, Y2]}
r: "{{ [list1, list2] | community.general.lists_mergeby('index', recursive=true) }}"
# r:
# - {index: a, foo: {x:1, y: 3, z: 4}}
# - {index: b, foo: [Y1, Y2]}
''' '''
RETURN = ''' RETURN = '''
@ -108,13 +212,14 @@ from operator import itemgetter
def list_mergeby(x, y, index, recursive=False, list_merge='replace'): def list_mergeby(x, y, index, recursive=False, list_merge='replace'):
''' Merge 2 lists by attribute 'index'. The function merge_hash from ansible.utils.vars is used. '''Merge 2 lists by attribute 'index'. The function 'merge_hash'
This function is used by the function lists_mergeby. from ansible.utils.vars is used. This function is used by the
function lists_mergeby.
''' '''
d = defaultdict(dict) d = defaultdict(dict)
for l in (x, y): for lst in (x, y):
for elem in l: for elem in lst:
if not isinstance(elem, Mapping): if not isinstance(elem, Mapping):
msg = "Elements of list arguments for lists_mergeby must be dictionaries. %s is %s" msg = "Elements of list arguments for lists_mergeby must be dictionaries. %s is %s"
raise AnsibleFilterError(msg % (elem, type(elem))) raise AnsibleFilterError(msg % (elem, type(elem)))
@ -124,20 +229,9 @@ def list_mergeby(x, y, index, recursive=False, list_merge='replace'):
def lists_mergeby(*terms, **kwargs): def lists_mergeby(*terms, **kwargs):
''' Merge 2 or more lists by attribute 'index'. Optional parameters 'recursive' and 'list_merge' '''Merge 2 or more lists by attribute 'index'. To learn details
control the merging of the lists in values. The function merge_hash from ansible.utils.vars on how to use the parameters 'recursive' and 'list_merge' see
is used. To learn details on how to use the parameters 'recursive' and 'list_merge' see the filter ansible.builtin.combine.
Ansible User's Guide chapter "Using filters to manipulate data" section "Combining
hashes/dictionaries".
Example:
- debug:
msg: "{{ list1|
community.general.lists_mergeby(list2,
'index',
recursive=True,
list_merge='append')|
list }}"
''' '''
recursive = kwargs.pop('recursive', False) recursive = kwargs.pop('recursive', False)
@ -155,7 +249,7 @@ def lists_mergeby(*terms, **kwargs):
"must be lists. %s is %s") "must be lists. %s is %s")
raise AnsibleFilterError(msg % (sublist, type(sublist))) raise AnsibleFilterError(msg % (sublist, type(sublist)))
if len(sublist) > 0: if len(sublist) > 0:
if all(isinstance(l, Sequence) for l in sublist): if all(isinstance(lst, Sequence) for lst in sublist):
for item in sublist: for item in sublist:
flat_list.append(item) flat_list.append(item)
else: else: