mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
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>
This commit is contained in:
parent
800bc01112
commit
8f60f3aef9
1 changed files with 153 additions and 59 deletions
|
@ -1,5 +1,5 @@
|
|||
# -*- 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)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
|
@ -12,22 +12,32 @@ DOCUMENTATION = '''
|
|||
version_added: 2.0.0
|
||||
author: Vladimir Botka (@vbotka)
|
||||
description:
|
||||
- Merge two or more lists by attribute O(index). Optional parameters O(recursive) and O(list_merge)
|
||||
control the merging of the lists in values. The function merge_hash from ansible.utils.vars
|
||||
is used. 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 "Combining
|
||||
hashes/dictionaries".
|
||||
- Merge two or more lists by attribute O(index). Optional
|
||||
parameters O(recursive) and O(list_merge) control the merging of
|
||||
the nested dictionaries and lists.
|
||||
- The function C(merge_hash) from C(ansible.utils.vars) is used.
|
||||
- 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
|
||||
options:
|
||||
_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
|
||||
elements: dictionary
|
||||
elements: raw
|
||||
required: true
|
||||
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
|
||||
elements: dictionary
|
||||
elements: raw
|
||||
index:
|
||||
description:
|
||||
- The dictionary key that must be present in every dictionary in every list that is used to
|
||||
|
@ -55,40 +65,134 @@ DOCUMENTATION = '''
|
|||
'''
|
||||
|
||||
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:
|
||||
msg: >-
|
||||
{{ list1 | community.general.lists_mergeby(
|
||||
list2,
|
||||
'index',
|
||||
recursive=True,
|
||||
list_merge='append'
|
||||
) }}"
|
||||
msg: |
|
||||
r1: {{ r1 }}
|
||||
r2: {{ r2 }}
|
||||
vars:
|
||||
list1:
|
||||
- index: a
|
||||
value: 123
|
||||
- index: b
|
||||
value: 42
|
||||
- {index: a, value: 123}
|
||||
- {index: b, value: 4}
|
||||
list2:
|
||||
- index: a
|
||||
foo: bar
|
||||
- index: c
|
||||
foo: baz
|
||||
# Produces the following list of dictionaries:
|
||||
# {
|
||||
# "index": "a",
|
||||
# "foo": "bar",
|
||||
# "value": 123
|
||||
# },
|
||||
# {
|
||||
# "index": "b",
|
||||
# "value": 42
|
||||
# },
|
||||
# {
|
||||
# "index": "c",
|
||||
# "foo": "baz"
|
||||
# }
|
||||
- {index: a, foo: bar}
|
||||
- {index: c, foo: baz}
|
||||
r1: "{{ list1 | community.general.lists_mergeby(list2, 'index') }}"
|
||||
r2: "{{ [list1, list2] | community.general.lists_mergeby('index') }}"
|
||||
|
||||
# r1:
|
||||
# - {index: a, foo: bar, value: 123}
|
||||
# - {index: b, value: 4}
|
||||
# - {index: c, foo: baz}
|
||||
# r2:
|
||||
# - {index: a, foo: bar, value: 123}
|
||||
# - {index: b, value: 4}
|
||||
# - {index: c, foo: baz}
|
||||
|
||||
- name: Example 2. Merge three lists
|
||||
ansible.builtin.debug:
|
||||
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 = '''
|
||||
|
@ -108,13 +212,14 @@ from operator import itemgetter
|
|||
|
||||
|
||||
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.
|
||||
This function is used by the function lists_mergeby.
|
||||
'''Merge 2 lists by attribute 'index'. The function 'merge_hash'
|
||||
from ansible.utils.vars is used. This function is used by the
|
||||
function lists_mergeby.
|
||||
'''
|
||||
|
||||
d = defaultdict(dict)
|
||||
for l in (x, y):
|
||||
for elem in l:
|
||||
for lst in (x, y):
|
||||
for elem in lst:
|
||||
if not isinstance(elem, Mapping):
|
||||
msg = "Elements of list arguments for lists_mergeby must be dictionaries. %s is %s"
|
||||
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):
|
||||
''' Merge 2 or more lists by attribute 'index'. Optional parameters 'recursive' and 'list_merge'
|
||||
control the merging of the lists in values. The function merge_hash from ansible.utils.vars
|
||||
is used. To learn details on how to use the parameters 'recursive' and 'list_merge' see
|
||||
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 }}"
|
||||
'''Merge 2 or more lists by attribute 'index'. To learn details
|
||||
on how to use the parameters 'recursive' and 'list_merge' see
|
||||
the filter ansible.builtin.combine.
|
||||
'''
|
||||
|
||||
recursive = kwargs.pop('recursive', False)
|
||||
|
@ -155,7 +249,7 @@ def lists_mergeby(*terms, **kwargs):
|
|||
"must be lists. %s is %s")
|
||||
raise AnsibleFilterError(msg % (sublist, type(sublist)))
|
||||
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:
|
||||
flat_list.append(item)
|
||||
else:
|
||||
|
|
Loading…
Reference in a new issue