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

Added filter plugin lists_mergeby. Fix #249 (#604)

This commit is contained in:
Vladimir Botka 2020-12-04 15:32:42 +01:00 committed by GitHub
parent b80854ff50
commit 0f88c71f59
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 100 additions and 0 deletions

View file

@ -0,0 +1,23 @@
---
minor_changes:
- |
A new filter ``lists_mergeby`` to merge two lists of dictionaries by an attribute.
For example:
.. code-block:: yaml
[{'n': 'n1', 'p1': 'A', 'p2': 'F'},
{'n': 'n2', 'p2': 'B'}] | community.general.lists_mergeby(
[{'n': 'n1', 'p1': 'C'},
{'n': 'n2', 'p2': 'D'},
{'n': 'n3', 'p3': 'E'}], 'n') | list
evaluates to
.. code-block:: yaml
[{'n': 'n1', 'p1': 'C', 'p2': 'F'},
{'n': 'n2', 'p2': 'D'},
{'n': 'n3', 'p3': 'E'}]
(https://github.com/ansible-collections/community.general/pull/604).

47
plugins/filter/list.py Normal file
View file

@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020, Vladimir Botka <vbotka@gmail.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from ansible.errors import AnsibleError, AnsibleFilterError
from ansible.module_utils.six import string_types
from ansible.module_utils.common._collections_compat import Mapping, Sequence
from collections import defaultdict
from operator import itemgetter
def lists_mergeby(l1, l2, index):
''' merge lists by attribute index. Example:
- debug: msg="{{ l1|community.general.lists_mergeby(l2, 'index')|list }}" '''
if not isinstance(l1, Sequence):
raise AnsibleFilterError('First argument for community.general.lists_mergeby must be list. %s is %s' %
(l1, type(l1)))
if not isinstance(l2, Sequence):
raise AnsibleFilterError('Second argument for community.general.lists_mergeby must be list. %s is %s' %
(l2, type(l2)))
if not isinstance(index, string_types):
raise AnsibleFilterError('Third argument for community.general.lists_mergeby must be string. %s is %s' %
(index, type(index)))
d = defaultdict(dict)
for l in (l1, l2):
for elem in l:
if not isinstance(elem, Mapping):
raise AnsibleFilterError('Elements of list arguments for lists_mergeby must be dictionaries. Found {0!r}.'.format(elem))
if index in elem.keys():
d[elem[index]].update(elem)
return sorted(d.values(), key=itemgetter(index))
class FilterModule(object):
''' Ansible list filters '''
def filters(self):
return {
'lists_mergeby': lists_mergeby,
}

View file

@ -0,0 +1,2 @@
shippable/posix/group2
skip/python2.6 # filters are controller only, and we no longer support Python 2.6 on the controller

View file

@ -0,0 +1,6 @@
---
- name: Test lists merged by attribute name
assert:
that:
- "(list1 | community.general.lists_mergeby(list2, 'name') | list |
difference(list3) | length) == 0"

View file

@ -0,0 +1,22 @@
list1:
- name: myname01
param01: myparam01
- name: myname02
param01: myparam02
list2:
- name: myname01
param01: myparam03
- name: myname02
param02: myparam04
- name: myname03
param03: myparam03
list3:
- name: myname01
param01: myparam03
- name: myname02
param01: myparam02
param02: myparam04
- name: myname03
param03: myparam03