mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-04-14 16:05:04 +00:00
Reformat everything.
This commit is contained in:
parent
3f2213791a
commit
340ff8586d
1008 changed files with 61301 additions and 58309 deletions
|
|
@ -49,14 +49,13 @@ from ansible.errors import AnsibleFilterError
|
|||
|
||||
def list_accumulate(sequence):
|
||||
if not isinstance(sequence, Sequence):
|
||||
raise AnsibleFilterError(f'Invalid value type ({type(sequence)}) for accumulate ({sequence!r})')
|
||||
raise AnsibleFilterError(f"Invalid value type ({type(sequence)}) for accumulate ({sequence!r})")
|
||||
|
||||
return accumulate(sequence)
|
||||
|
||||
|
||||
class FilterModule:
|
||||
|
||||
def filters(self):
|
||||
return {
|
||||
'accumulate': list_accumulate,
|
||||
"accumulate": list_accumulate,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,9 +40,11 @@ from collections import Counter
|
|||
|
||||
|
||||
def counter(sequence):
|
||||
''' Count elements in a sequence. Returns dict with count result. '''
|
||||
"""Count elements in a sequence. Returns dict with count result."""
|
||||
if not isinstance(sequence, Sequence):
|
||||
raise AnsibleFilterError(f'Argument for community.general.counter must be a sequence (string or list). {sequence} is {type(sequence)}')
|
||||
raise AnsibleFilterError(
|
||||
f"Argument for community.general.counter must be a sequence (string or list). {sequence} is {type(sequence)}"
|
||||
)
|
||||
|
||||
try:
|
||||
result = dict(Counter(sequence))
|
||||
|
|
@ -54,11 +56,11 @@ def counter(sequence):
|
|||
|
||||
|
||||
class FilterModule:
|
||||
''' Ansible counter jinja2 filters '''
|
||||
"""Ansible counter jinja2 filters"""
|
||||
|
||||
def filters(self):
|
||||
filters = {
|
||||
'counter': counter,
|
||||
"counter": counter,
|
||||
}
|
||||
|
||||
return filters
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ from ansible.module_utils.common.collections import is_string
|
|||
|
||||
try:
|
||||
from zlib import crc32
|
||||
|
||||
HAS_ZLIB = True
|
||||
except ImportError:
|
||||
HAS_ZLIB = False
|
||||
|
|
@ -45,17 +46,17 @@ _value:
|
|||
|
||||
def crc32s(value):
|
||||
if not is_string(value):
|
||||
raise AnsibleFilterError(f'Invalid value type ({type(value)}) for crc32 ({value!r})')
|
||||
raise AnsibleFilterError(f"Invalid value type ({type(value)}) for crc32 ({value!r})")
|
||||
|
||||
if not HAS_ZLIB:
|
||||
raise AnsibleFilterError('Failed to import zlib module')
|
||||
raise AnsibleFilterError("Failed to import zlib module")
|
||||
|
||||
data = to_bytes(value, errors='surrogate_or_strict')
|
||||
return f"{crc32(data) & 0xffffffff:x}"
|
||||
data = to_bytes(value, errors="surrogate_or_strict")
|
||||
return f"{crc32(data) & 0xFFFFFFFF:x}"
|
||||
|
||||
|
||||
class FilterModule:
|
||||
def filters(self):
|
||||
return {
|
||||
'crc32': crc32s,
|
||||
"crc32": crc32s,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
# Copyright (c) 2021, Felix Fontein <felix@fontein.de>
|
||||
# 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
|
||||
|
|
@ -61,17 +60,17 @@ _value:
|
|||
|
||||
|
||||
def dict_filter(sequence):
|
||||
'''Convert a list of tuples to a dictionary.
|
||||
"""Convert a list of tuples to a dictionary.
|
||||
|
||||
Example: ``[[1, 2], ['a', 'b']] | community.general.dict`` results in ``{1: 2, 'a': 'b'}``
|
||||
'''
|
||||
"""
|
||||
return dict(sequence)
|
||||
|
||||
|
||||
class FilterModule:
|
||||
'''Ansible jinja2 filters'''
|
||||
"""Ansible jinja2 filters"""
|
||||
|
||||
def filters(self):
|
||||
return {
|
||||
'dict': dict_filter,
|
||||
"dict": dict_filter,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ _value:
|
|||
|
||||
|
||||
def dict_kv(value, key):
|
||||
'''Return a dictionary with a single key-value pair
|
||||
"""Return a dictionary with a single key-value pair
|
||||
|
||||
Example:
|
||||
|
||||
|
|
@ -89,14 +89,12 @@ def dict_kv(value, key):
|
|||
}
|
||||
]
|
||||
}
|
||||
'''
|
||||
"""
|
||||
return {key: value}
|
||||
|
||||
|
||||
class FilterModule:
|
||||
''' Query filter '''
|
||||
"""Query filter"""
|
||||
|
||||
def filters(self):
|
||||
return {
|
||||
'dict_kv': dict_kv
|
||||
}
|
||||
return {"dict_kv": dict_kv}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
# Copyright (c) 2021, Andrew Pantuso (@ajpantuso) <ajpantuso@gmail.com>
|
||||
# Copyright (c) 2018, Dag Wieers (@dagwieers) <dag@wieers.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)
|
||||
|
|
@ -80,13 +79,16 @@ _value:
|
|||
|
||||
from ansible.errors import AnsibleFilterError
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.csv import (initialize_dialect, read_csv, CSVError,
|
||||
DialectNotAvailableError,
|
||||
CustomDialectFailureError)
|
||||
from ansible_collections.community.general.plugins.module_utils.csv import (
|
||||
initialize_dialect,
|
||||
read_csv,
|
||||
CSVError,
|
||||
DialectNotAvailableError,
|
||||
CustomDialectFailureError,
|
||||
)
|
||||
|
||||
|
||||
def from_csv(data, dialect='excel', fieldnames=None, delimiter=None, skipinitialspace=None, strict=None):
|
||||
|
||||
def from_csv(data, dialect="excel", fieldnames=None, delimiter=None, skipinitialspace=None, strict=None):
|
||||
dialect_params = {
|
||||
"delimiter": delimiter,
|
||||
"skipinitialspace": skipinitialspace,
|
||||
|
|
@ -112,8 +114,5 @@ def from_csv(data, dialect='excel', fieldnames=None, delimiter=None, skipinitial
|
|||
|
||||
|
||||
class FilterModule:
|
||||
|
||||
def filters(self):
|
||||
return {
|
||||
'from_csv': from_csv
|
||||
}
|
||||
return {"from_csv": from_csv}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
# Copyright (c) 2023, Steffen Scheib <steffen@scheib.me>
|
||||
# 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
|
||||
|
|
@ -51,7 +50,7 @@ from ansible.errors import AnsibleFilterError
|
|||
|
||||
|
||||
class IniParser(ConfigParser):
|
||||
''' Implements a configparser which is able to return a dict '''
|
||||
"""Implements a configparser which is able to return a dict"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(interpolation=None)
|
||||
|
|
@ -61,35 +60,32 @@ class IniParser(ConfigParser):
|
|||
d = dict(self._sections)
|
||||
for k in d:
|
||||
d[k] = dict(self._defaults, **d[k])
|
||||
d[k].pop('__name__', None)
|
||||
d[k].pop("__name__", None)
|
||||
|
||||
if self._defaults:
|
||||
d['DEFAULT'] = dict(self._defaults)
|
||||
d["DEFAULT"] = dict(self._defaults)
|
||||
|
||||
return d
|
||||
|
||||
|
||||
def from_ini(obj):
|
||||
''' Read the given string as INI file and return a dict '''
|
||||
"""Read the given string as INI file and return a dict"""
|
||||
|
||||
if not isinstance(obj, str):
|
||||
raise AnsibleFilterError(f'from_ini requires a str, got {type(obj)}')
|
||||
raise AnsibleFilterError(f"from_ini requires a str, got {type(obj)}")
|
||||
|
||||
parser = IniParser()
|
||||
|
||||
try:
|
||||
parser.read_file(StringIO(obj))
|
||||
except Exception as ex:
|
||||
raise AnsibleFilterError(f'from_ini failed to parse given string: {ex}', orig_exc=ex)
|
||||
raise AnsibleFilterError(f"from_ini failed to parse given string: {ex}", orig_exc=ex)
|
||||
|
||||
return parser.as_dict()
|
||||
|
||||
|
||||
class FilterModule:
|
||||
''' Query filter '''
|
||||
"""Query filter"""
|
||||
|
||||
def filters(self):
|
||||
|
||||
return {
|
||||
'from_ini': from_ini
|
||||
}
|
||||
return {"from_ini": from_ini}
|
||||
|
|
|
|||
|
|
@ -57,33 +57,33 @@ from collections.abc import Mapping, Sequence
|
|||
|
||||
|
||||
def groupby_as_dict(sequence, attribute):
|
||||
'''
|
||||
"""
|
||||
Given a sequence of dictionaries and an attribute name, returns a dictionary mapping
|
||||
the value of this attribute to the dictionary.
|
||||
|
||||
If multiple dictionaries in the sequence have the same value for this attribute,
|
||||
the filter will fail.
|
||||
'''
|
||||
"""
|
||||
if not isinstance(sequence, Sequence):
|
||||
raise AnsibleFilterError('Input is not a sequence')
|
||||
raise AnsibleFilterError("Input is not a sequence")
|
||||
|
||||
result = dict()
|
||||
for list_index, element in enumerate(sequence):
|
||||
if not isinstance(element, Mapping):
|
||||
raise AnsibleFilterError(f'Sequence element #{list_index} is not a mapping')
|
||||
raise AnsibleFilterError(f"Sequence element #{list_index} is not a mapping")
|
||||
if attribute not in element:
|
||||
raise AnsibleFilterError(f'Attribute not contained in element #{list_index} of sequence')
|
||||
raise AnsibleFilterError(f"Attribute not contained in element #{list_index} of sequence")
|
||||
result_index = element[attribute]
|
||||
if result_index in result:
|
||||
raise AnsibleFilterError(f'Multiple sequence entries have attribute value {result_index!r}')
|
||||
raise AnsibleFilterError(f"Multiple sequence entries have attribute value {result_index!r}")
|
||||
result[result_index] = element
|
||||
return result
|
||||
|
||||
|
||||
class FilterModule:
|
||||
''' Ansible list filters '''
|
||||
"""Ansible list filters"""
|
||||
|
||||
def filters(self):
|
||||
return {
|
||||
'groupby_as_dict': groupby_as_dict,
|
||||
"groupby_as_dict": groupby_as_dict,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
# Copyright (c) 2021, Andrew Pantuso (@ajpantuso) <ajpantuso@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
|
||||
|
|
@ -20,6 +19,7 @@ except ImportError:
|
|||
|
||||
try:
|
||||
from hashids import Hashids
|
||||
|
||||
HAS_HASHIDS = True
|
||||
except ImportError:
|
||||
HAS_HASHIDS = False
|
||||
|
|
@ -35,27 +35,21 @@ def initialize_hashids(**kwargs):
|
|||
return Hashids(**params)
|
||||
except TypeError as e:
|
||||
raise AnsibleFilterError(
|
||||
"The provided parameters %s are invalid: %s" % (
|
||||
', '.join(["%s=%s" % (k, v) for k, v in params.items()]),
|
||||
to_native(e)
|
||||
)
|
||||
"The provided parameters %s are invalid: %s"
|
||||
% (", ".join(["%s=%s" % (k, v) for k, v in params.items()]), to_native(e))
|
||||
)
|
||||
|
||||
|
||||
def hashids_encode(nums, salt=None, alphabet=None, min_length=None):
|
||||
"""Generates a YouTube-like hash from a sequence of ints
|
||||
|
||||
:nums: Sequence of one or more ints to hash
|
||||
:salt: String to use as salt when hashing
|
||||
:alphabet: String of 16 or more unique characters to produce a hash
|
||||
:min_length: Minimum length of hash produced
|
||||
:nums: Sequence of one or more ints to hash
|
||||
:salt: String to use as salt when hashing
|
||||
:alphabet: String of 16 or more unique characters to produce a hash
|
||||
:min_length: Minimum length of hash produced
|
||||
"""
|
||||
|
||||
hashids = initialize_hashids(
|
||||
salt=salt,
|
||||
alphabet=alphabet,
|
||||
min_length=min_length
|
||||
)
|
||||
hashids = initialize_hashids(salt=salt, alphabet=alphabet, min_length=min_length)
|
||||
|
||||
# Handles the case where a single int is not encapsulated in a list or tuple.
|
||||
# User convenience seems preferable to strict typing in this case
|
||||
|
|
@ -74,25 +68,20 @@ def hashids_encode(nums, salt=None, alphabet=None, min_length=None):
|
|||
def hashids_decode(hashid, salt=None, alphabet=None, min_length=None):
|
||||
"""Decodes a YouTube-like hash to a sequence of ints
|
||||
|
||||
:hashid: Hash string to decode
|
||||
:salt: String to use as salt when hashing
|
||||
:alphabet: String of 16 or more unique characters to produce a hash
|
||||
:min_length: Minimum length of hash produced
|
||||
:hashid: Hash string to decode
|
||||
:salt: String to use as salt when hashing
|
||||
:alphabet: String of 16 or more unique characters to produce a hash
|
||||
:min_length: Minimum length of hash produced
|
||||
"""
|
||||
|
||||
hashids = initialize_hashids(
|
||||
salt=salt,
|
||||
alphabet=alphabet,
|
||||
min_length=min_length
|
||||
)
|
||||
hashids = initialize_hashids(salt=salt, alphabet=alphabet, min_length=min_length)
|
||||
nums = hashids.decode(hashid)
|
||||
return list(nums)
|
||||
|
||||
|
||||
class FilterModule:
|
||||
|
||||
def filters(self):
|
||||
return {
|
||||
'hashids_encode': hashids_encode,
|
||||
'hashids_decode': hashids_decode,
|
||||
"hashids_encode": hashids_encode,
|
||||
"hashids_decode": hashids_decode,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ import importlib
|
|||
|
||||
try:
|
||||
import jc
|
||||
|
||||
HAS_LIB = True
|
||||
except ImportError:
|
||||
HAS_LIB = False
|
||||
|
|
@ -133,26 +134,28 @@ def jc_filter(data, parser, quiet=True, raw=False):
|
|||
"""
|
||||
|
||||
if not HAS_LIB:
|
||||
raise AnsibleError('You need to install "jc" as a Python library on the Ansible controller prior to running jc filter')
|
||||
raise AnsibleError(
|
||||
'You need to install "jc" as a Python library on the Ansible controller prior to running jc filter'
|
||||
)
|
||||
|
||||
try:
|
||||
# new API (jc v1.18.0 and higher) allows use of plugin parsers
|
||||
if hasattr(jc, 'parse'):
|
||||
if hasattr(jc, "parse"):
|
||||
return jc.parse(parser, data, quiet=quiet, raw=raw)
|
||||
|
||||
# old API (jc v1.17.7 and lower)
|
||||
else:
|
||||
jc_parser = importlib.import_module(f'jc.parsers.{parser}')
|
||||
jc_parser = importlib.import_module(f"jc.parsers.{parser}")
|
||||
return jc_parser.parse(data, quiet=quiet, raw=raw)
|
||||
|
||||
except Exception as e:
|
||||
raise AnsibleFilterError(f'Error in jc filter plugin: {e}')
|
||||
raise AnsibleFilterError(f"Error in jc filter plugin: {e}")
|
||||
|
||||
|
||||
class FilterModule:
|
||||
''' Query filter '''
|
||||
"""Query filter"""
|
||||
|
||||
def filters(self):
|
||||
return {
|
||||
'jc': jc_filter,
|
||||
"jc": jc_filter,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,39 +35,28 @@ class FilterModule:
|
|||
try:
|
||||
return loads(inp)
|
||||
except Exception as e:
|
||||
raise AnsibleFilterError(
|
||||
f"{filter_name}: could not decode JSON from {object_name}: {e}"
|
||||
) from e
|
||||
raise AnsibleFilterError(f"{filter_name}: could not decode JSON from {object_name}: {e}") from e
|
||||
|
||||
if not isinstance(inp, (list, dict)):
|
||||
raise AnsibleFilterError(
|
||||
f"{filter_name}: {object_name} is not dictionary, list or string"
|
||||
)
|
||||
raise AnsibleFilterError(f"{filter_name}: {object_name} is not dictionary, list or string")
|
||||
|
||||
return inp
|
||||
|
||||
def check_patch_arguments(self, filter_name: str, args: dict):
|
||||
|
||||
if "op" not in args or not isinstance(args["op"], str):
|
||||
raise AnsibleFilterError(f"{filter_name}: 'op' argument is not a string")
|
||||
|
||||
if args["op"] not in OPERATIONS_AVAILABLE:
|
||||
raise AnsibleFilterError(
|
||||
f"{filter_name}: unsupported 'op' argument: {args['op']}"
|
||||
)
|
||||
raise AnsibleFilterError(f"{filter_name}: unsupported 'op' argument: {args['op']}")
|
||||
|
||||
if "path" not in args or not isinstance(args["path"], str):
|
||||
raise AnsibleFilterError(f"{filter_name}: 'path' argument is not a string")
|
||||
|
||||
if args["op"] in OPERATIONS_NEEDING_FROM:
|
||||
if "from" not in args:
|
||||
raise AnsibleFilterError(
|
||||
f"{filter_name}: 'from' argument missing for '{args['op']}' operation"
|
||||
)
|
||||
raise AnsibleFilterError(f"{filter_name}: 'from' argument missing for '{args['op']}' operation")
|
||||
if not isinstance(args["from"], str):
|
||||
raise AnsibleFilterError(
|
||||
f"{filter_name}: 'from' argument is not a string"
|
||||
)
|
||||
raise AnsibleFilterError(f"{filter_name}: 'from' argument is not a string")
|
||||
|
||||
def json_patch(
|
||||
self,
|
||||
|
|
@ -77,7 +66,6 @@ class FilterModule:
|
|||
value: Any = None,
|
||||
**kwargs: dict,
|
||||
) -> Any:
|
||||
|
||||
if not HAS_LIB:
|
||||
raise AnsibleFilterError(
|
||||
"You need to install 'jsonpatch' package prior to running 'json_patch' filter"
|
||||
|
|
@ -88,9 +76,7 @@ class FilterModule:
|
|||
fail_test = kwargs.pop("fail_test", False)
|
||||
|
||||
if kwargs:
|
||||
raise AnsibleFilterError(
|
||||
f"json_patch: unexpected keywords arguments: {', '.join(sorted(kwargs))}"
|
||||
)
|
||||
raise AnsibleFilterError(f"json_patch: unexpected keywords arguments: {', '.join(sorted(kwargs))}")
|
||||
|
||||
if not isinstance(fail_test, bool):
|
||||
raise AnsibleFilterError("json_patch: 'fail_test' argument is not a bool")
|
||||
|
|
@ -109,9 +95,7 @@ class FilterModule:
|
|||
result = jsonpatch.apply_patch(inp, [args])
|
||||
except jsonpatch.JsonPatchTestFailed as e:
|
||||
if fail_test:
|
||||
raise AnsibleFilterError(
|
||||
f"json_patch: test operation failed: {e}"
|
||||
) from e
|
||||
raise AnsibleFilterError(f"json_patch: test operation failed: {e}") from e
|
||||
else:
|
||||
pass
|
||||
except Exception as e:
|
||||
|
|
@ -126,16 +110,13 @@ class FilterModule:
|
|||
/,
|
||||
fail_test: bool = False,
|
||||
) -> Any:
|
||||
|
||||
if not HAS_LIB:
|
||||
raise AnsibleFilterError(
|
||||
"You need to install 'jsonpatch' package prior to running 'json_patch_recipe' filter"
|
||||
) from JSONPATCH_IMPORT_ERROR
|
||||
|
||||
if not isinstance(operations, list):
|
||||
raise AnsibleFilterError(
|
||||
"json_patch_recipe: 'operations' needs to be a list"
|
||||
)
|
||||
raise AnsibleFilterError("json_patch_recipe: 'operations' needs to be a list")
|
||||
|
||||
if not isinstance(fail_test, bool):
|
||||
raise AnsibleFilterError("json_patch: 'fail_test' argument is not a bool")
|
||||
|
|
@ -150,9 +131,7 @@ class FilterModule:
|
|||
result = jsonpatch.apply_patch(inp, operations)
|
||||
except jsonpatch.JsonPatchTestFailed as e:
|
||||
if fail_test:
|
||||
raise AnsibleFilterError(
|
||||
f"json_patch_recipe: test operation failed: {e}"
|
||||
) from e
|
||||
raise AnsibleFilterError(f"json_patch_recipe: test operation failed: {e}") from e
|
||||
else:
|
||||
pass
|
||||
except Exception as e:
|
||||
|
|
@ -165,7 +144,6 @@ class FilterModule:
|
|||
inp: Union[str, list, dict, bytes, bytearray],
|
||||
target: Union[str, list, dict, bytes, bytearray],
|
||||
) -> list:
|
||||
|
||||
if not HAS_LIB:
|
||||
raise AnsibleFilterError(
|
||||
"You need to install 'jsonpatch' package prior to running 'json_diff' filter"
|
||||
|
|
|
|||
|
|
@ -109,44 +109,46 @@ from ansible.errors import AnsibleError, AnsibleFilterError
|
|||
|
||||
try:
|
||||
import jmespath
|
||||
|
||||
HAS_LIB = True
|
||||
except ImportError:
|
||||
HAS_LIB = False
|
||||
|
||||
|
||||
def json_query(data, expr):
|
||||
'''Query data using jmespath query language ( http://jmespath.org ). Example:
|
||||
"""Query data using jmespath query language ( http://jmespath.org ). Example:
|
||||
- ansible.builtin.debug: msg="{{ instance | json_query(tagged_instances[*].block_device_mapping.*.volume_id') }}"
|
||||
'''
|
||||
"""
|
||||
if not HAS_LIB:
|
||||
raise AnsibleError('You need to install "jmespath" prior to running '
|
||||
'json_query filter')
|
||||
raise AnsibleError('You need to install "jmespath" prior to running json_query filter')
|
||||
|
||||
# Hack to handle Ansible Unsafe text, AnsibleMapping and AnsibleSequence
|
||||
# See issues https://github.com/ansible-collections/community.general/issues/320
|
||||
# and https://github.com/ansible/ansible/issues/85600.
|
||||
jmespath.functions.REVERSE_TYPES_MAP['string'] = jmespath.functions.REVERSE_TYPES_MAP['string'] + (
|
||||
'AnsibleUnicode', 'AnsibleUnsafeText', '_AnsibleTaggedStr',
|
||||
jmespath.functions.REVERSE_TYPES_MAP["string"] = jmespath.functions.REVERSE_TYPES_MAP["string"] + (
|
||||
"AnsibleUnicode",
|
||||
"AnsibleUnsafeText",
|
||||
"_AnsibleTaggedStr",
|
||||
)
|
||||
jmespath.functions.REVERSE_TYPES_MAP['array'] = jmespath.functions.REVERSE_TYPES_MAP['array'] + (
|
||||
'AnsibleSequence', '_AnsibleLazyTemplateList',
|
||||
jmespath.functions.REVERSE_TYPES_MAP["array"] = jmespath.functions.REVERSE_TYPES_MAP["array"] + (
|
||||
"AnsibleSequence",
|
||||
"_AnsibleLazyTemplateList",
|
||||
)
|
||||
jmespath.functions.REVERSE_TYPES_MAP['object'] = jmespath.functions.REVERSE_TYPES_MAP['object'] + (
|
||||
'AnsibleMapping', '_AnsibleLazyTemplateDict',
|
||||
jmespath.functions.REVERSE_TYPES_MAP["object"] = jmespath.functions.REVERSE_TYPES_MAP["object"] + (
|
||||
"AnsibleMapping",
|
||||
"_AnsibleLazyTemplateDict",
|
||||
)
|
||||
try:
|
||||
return jmespath.search(expr, data)
|
||||
except jmespath.exceptions.JMESPathError as e:
|
||||
raise AnsibleFilterError(f'JMESPathError in json_query filter plugin:\n{e}')
|
||||
raise AnsibleFilterError(f"JMESPathError in json_query filter plugin:\n{e}")
|
||||
except Exception as e:
|
||||
# For older jmespath, we can get ValueError and TypeError without much info.
|
||||
raise AnsibleFilterError(f'Error in jmespath.search in json_query filter plugin:\n{e}')
|
||||
raise AnsibleFilterError(f"Error in jmespath.search in json_query filter plugin:\n{e}")
|
||||
|
||||
|
||||
class FilterModule:
|
||||
''' Query filter '''
|
||||
"""Query filter"""
|
||||
|
||||
def filters(self):
|
||||
return {
|
||||
'json_query': json_query
|
||||
}
|
||||
return {"json_query": json_query}
|
||||
|
|
|
|||
|
|
@ -101,10 +101,11 @@ _value:
|
|||
|
||||
from ansible_collections.community.general.plugins.plugin_utils.keys_filter import (
|
||||
_keys_filter_params,
|
||||
_keys_filter_target_str)
|
||||
_keys_filter_target_str,
|
||||
)
|
||||
|
||||
|
||||
def keep_keys(data, target=None, matching_parameter='equal'):
|
||||
def keep_keys(data, target=None, matching_parameter="equal"):
|
||||
"""keep specific keys from dictionaries in a list"""
|
||||
|
||||
# test parameters
|
||||
|
|
@ -112,16 +113,20 @@ def keep_keys(data, target=None, matching_parameter='equal'):
|
|||
# test and transform target
|
||||
tt = _keys_filter_target_str(target, matching_parameter)
|
||||
|
||||
if matching_parameter == 'equal':
|
||||
if matching_parameter == "equal":
|
||||
|
||||
def keep_key(key):
|
||||
return key in tt
|
||||
elif matching_parameter == 'starts_with':
|
||||
elif matching_parameter == "starts_with":
|
||||
|
||||
def keep_key(key):
|
||||
return key.startswith(tt)
|
||||
elif matching_parameter == 'ends_with':
|
||||
elif matching_parameter == "ends_with":
|
||||
|
||||
def keep_key(key):
|
||||
return key.endswith(tt)
|
||||
elif matching_parameter == 'regex':
|
||||
elif matching_parameter == "regex":
|
||||
|
||||
def keep_key(key):
|
||||
return tt.match(key) is not None
|
||||
|
||||
|
|
@ -129,8 +134,7 @@ def keep_keys(data, target=None, matching_parameter='equal'):
|
|||
|
||||
|
||||
class FilterModule:
|
||||
|
||||
def filters(self):
|
||||
return {
|
||||
'keep_keys': keep_keys,
|
||||
"keep_keys": keep_keys,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ def flatten_list(lst):
|
|||
result = []
|
||||
for sublist in lst:
|
||||
if not is_sequence(sublist):
|
||||
msg = ("All arguments must be lists. %s is %s")
|
||||
msg = "All arguments must be lists. %s is %s"
|
||||
raise AnsibleFilterError(msg % (sublist, type(sublist)))
|
||||
if len(sublist) > 0:
|
||||
if all(is_sequence(sub) for sub in sublist):
|
||||
|
|
@ -45,13 +45,11 @@ def flatten_list(lst):
|
|||
|
||||
def lists_union(*args, **kwargs):
|
||||
lists = args
|
||||
flatten = kwargs.pop('flatten', False)
|
||||
flatten = kwargs.pop("flatten", False)
|
||||
|
||||
if kwargs:
|
||||
# Some unused kwargs remain
|
||||
raise AnsibleFilterError(
|
||||
f"lists_union() got unexpected keywords arguments: {', '.join(kwargs.keys())}"
|
||||
)
|
||||
raise AnsibleFilterError(f"lists_union() got unexpected keywords arguments: {', '.join(kwargs.keys())}")
|
||||
|
||||
if flatten:
|
||||
lists = flatten_list(args)
|
||||
|
|
@ -74,13 +72,11 @@ def do_union(a, b):
|
|||
|
||||
def lists_intersect(*args, **kwargs):
|
||||
lists = args
|
||||
flatten = kwargs.pop('flatten', False)
|
||||
flatten = kwargs.pop("flatten", False)
|
||||
|
||||
if kwargs:
|
||||
# Some unused kwargs remain
|
||||
raise AnsibleFilterError(
|
||||
f"lists_intersect() got unexpected keywords arguments: {', '.join(kwargs.keys())}"
|
||||
)
|
||||
raise AnsibleFilterError(f"lists_intersect() got unexpected keywords arguments: {', '.join(kwargs.keys())}")
|
||||
|
||||
if flatten:
|
||||
lists = flatten_list(args)
|
||||
|
|
@ -112,13 +108,11 @@ def do_intersect(a, b):
|
|||
|
||||
def lists_difference(*args, **kwargs):
|
||||
lists = args
|
||||
flatten = kwargs.pop('flatten', False)
|
||||
flatten = kwargs.pop("flatten", False)
|
||||
|
||||
if kwargs:
|
||||
# Some unused kwargs remain
|
||||
raise AnsibleFilterError(
|
||||
f"lists_difference() got unexpected keywords arguments: {', '.join(kwargs.keys())}"
|
||||
)
|
||||
raise AnsibleFilterError(f"lists_difference() got unexpected keywords arguments: {', '.join(kwargs.keys())}")
|
||||
|
||||
if flatten:
|
||||
lists = flatten_list(args)
|
||||
|
|
@ -150,13 +144,11 @@ def do_difference(a, b):
|
|||
|
||||
def lists_symmetric_difference(*args, **kwargs):
|
||||
lists = args
|
||||
flatten = kwargs.pop('flatten', False)
|
||||
flatten = kwargs.pop("flatten", False)
|
||||
|
||||
if kwargs:
|
||||
# Some unused kwargs remain
|
||||
raise AnsibleFilterError(
|
||||
f"lists_difference() got unexpected keywords arguments: {', '.join(kwargs.keys())}"
|
||||
)
|
||||
raise AnsibleFilterError(f"lists_difference() got unexpected keywords arguments: {', '.join(kwargs.keys())}")
|
||||
|
||||
if flatten:
|
||||
lists = flatten_list(args)
|
||||
|
|
@ -189,12 +181,12 @@ def do_symmetric_difference(a, b):
|
|||
|
||||
|
||||
class FilterModule:
|
||||
''' Ansible lists jinja2 filters '''
|
||||
"""Ansible lists jinja2 filters"""
|
||||
|
||||
def filters(self):
|
||||
return {
|
||||
'lists_union': lists_union,
|
||||
'lists_intersect': lists_intersect,
|
||||
'lists_difference': lists_difference,
|
||||
'lists_symmetric_difference': lists_symmetric_difference,
|
||||
"lists_union": lists_union,
|
||||
"lists_intersect": lists_intersect,
|
||||
"lists_difference": lists_difference,
|
||||
"lists_symmetric_difference": lists_symmetric_difference,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -202,11 +202,11 @@ from collections import defaultdict
|
|||
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.
|
||||
'''
|
||||
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.
|
||||
"""
|
||||
|
||||
d = defaultdict(dict)
|
||||
for lst in (x, y):
|
||||
|
|
@ -220,13 +220,13 @@ def list_mergeby(x, y, index, recursive=False, list_merge='replace'):
|
|||
|
||||
|
||||
def lists_mergeby(*terms, **kwargs):
|
||||
'''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.
|
||||
'''
|
||||
"""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)
|
||||
list_merge = kwargs.pop('list_merge', 'replace')
|
||||
recursive = kwargs.pop("recursive", False)
|
||||
list_merge = kwargs.pop("list_merge", "replace")
|
||||
if kwargs:
|
||||
raise AnsibleFilterError("'recursive' and 'list_merge' are the only valid keyword arguments.")
|
||||
if len(terms) < 2:
|
||||
|
|
@ -236,8 +236,7 @@ def lists_mergeby(*terms, **kwargs):
|
|||
flat_list = []
|
||||
for sublist in terms[:-1]:
|
||||
if not isinstance(sublist, Sequence):
|
||||
msg = ("All arguments before the argument index for community.general.lists_mergeby "
|
||||
"must be lists. %s is %s")
|
||||
msg = "All arguments before the argument index for community.general.lists_mergeby must be lists. %s is %s"
|
||||
raise AnsibleFilterError(msg % (sublist, type(sublist)))
|
||||
if len(sublist) > 0:
|
||||
if all(isinstance(lst, Sequence) for lst in sublist):
|
||||
|
|
@ -256,8 +255,7 @@ def lists_mergeby(*terms, **kwargs):
|
|||
index = terms[-1]
|
||||
|
||||
if not isinstance(index, str):
|
||||
msg = ("First argument after the lists for community.general.lists_mergeby must be string. "
|
||||
"%s is %s")
|
||||
msg = "First argument after the lists for community.general.lists_mergeby must be string. %s is %s"
|
||||
raise AnsibleFilterError(msg % (index, type(index)))
|
||||
|
||||
high_to_low_prio_list_iterator = reversed(lists)
|
||||
|
|
@ -269,9 +267,9 @@ def lists_mergeby(*terms, **kwargs):
|
|||
|
||||
|
||||
class FilterModule:
|
||||
''' Ansible list filters '''
|
||||
"""Ansible list filters"""
|
||||
|
||||
def filters(self):
|
||||
return {
|
||||
'lists_mergeby': lists_mergeby,
|
||||
"lists_mergeby": lists_mergeby,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,29 +47,29 @@ from ansible.errors import AnsibleFilterError
|
|||
|
||||
|
||||
def random_mac(value, seed=None):
|
||||
''' takes string prefix, and return it completed with random bytes
|
||||
to get a complete 6 bytes MAC address '''
|
||||
"""takes string prefix, and return it completed with random bytes
|
||||
to get a complete 6 bytes MAC address"""
|
||||
|
||||
if not isinstance(value, str):
|
||||
raise AnsibleFilterError(f'Invalid value type ({type(value)}) for random_mac ({value})')
|
||||
raise AnsibleFilterError(f"Invalid value type ({type(value)}) for random_mac ({value})")
|
||||
|
||||
value = value.lower()
|
||||
mac_items = value.split(':')
|
||||
mac_items = value.split(":")
|
||||
|
||||
if len(mac_items) > 5:
|
||||
raise AnsibleFilterError(f'Invalid value ({value}) for random_mac: 5 colon(:) separated items max')
|
||||
raise AnsibleFilterError(f"Invalid value ({value}) for random_mac: 5 colon(:) separated items max")
|
||||
|
||||
err = ""
|
||||
for mac in mac_items:
|
||||
if not mac:
|
||||
err += ",empty item"
|
||||
continue
|
||||
if not re.match('[a-f0-9]{2}', mac):
|
||||
if not re.match("[a-f0-9]{2}", mac):
|
||||
err += f",{mac} not hexa byte"
|
||||
err = err.strip(',')
|
||||
err = err.strip(",")
|
||||
|
||||
if err:
|
||||
raise AnsibleFilterError(f'Invalid value ({value}) for random_mac: {err}')
|
||||
raise AnsibleFilterError(f"Invalid value ({value}) for random_mac: {err}")
|
||||
|
||||
if seed is None:
|
||||
r = SystemRandom()
|
||||
|
|
@ -79,13 +79,14 @@ def random_mac(value, seed=None):
|
|||
v = r.randint(68719476736, 1099511627775)
|
||||
# Select first n chars to complement input prefix
|
||||
remain = 2 * (6 - len(mac_items))
|
||||
rnd = f'{v:x}'[:remain]
|
||||
return value + re.sub(r'(..)', r':\1', rnd)
|
||||
rnd = f"{v:x}"[:remain]
|
||||
return value + re.sub(r"(..)", r":\1", rnd)
|
||||
|
||||
|
||||
class FilterModule:
|
||||
''' Ansible jinja2 filters '''
|
||||
"""Ansible jinja2 filters"""
|
||||
|
||||
def filters(self):
|
||||
return {
|
||||
'random_mac': random_mac,
|
||||
"random_mac": random_mac,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,10 +101,11 @@ _value:
|
|||
|
||||
from ansible_collections.community.general.plugins.plugin_utils.keys_filter import (
|
||||
_keys_filter_params,
|
||||
_keys_filter_target_str)
|
||||
_keys_filter_target_str,
|
||||
)
|
||||
|
||||
|
||||
def remove_keys(data, target=None, matching_parameter='equal'):
|
||||
def remove_keys(data, target=None, matching_parameter="equal"):
|
||||
"""remove specific keys from dictionaries in a list"""
|
||||
|
||||
# test parameters
|
||||
|
|
@ -112,16 +113,20 @@ def remove_keys(data, target=None, matching_parameter='equal'):
|
|||
# test and transform target
|
||||
tt = _keys_filter_target_str(target, matching_parameter)
|
||||
|
||||
if matching_parameter == 'equal':
|
||||
if matching_parameter == "equal":
|
||||
|
||||
def keep_key(key):
|
||||
return key not in tt
|
||||
elif matching_parameter == 'starts_with':
|
||||
elif matching_parameter == "starts_with":
|
||||
|
||||
def keep_key(key):
|
||||
return not key.startswith(tt)
|
||||
elif matching_parameter == 'ends_with':
|
||||
elif matching_parameter == "ends_with":
|
||||
|
||||
def keep_key(key):
|
||||
return not key.endswith(tt)
|
||||
elif matching_parameter == 'regex':
|
||||
elif matching_parameter == "regex":
|
||||
|
||||
def keep_key(key):
|
||||
return tt.match(key) is None
|
||||
|
||||
|
|
@ -129,8 +134,7 @@ def remove_keys(data, target=None, matching_parameter='equal'):
|
|||
|
||||
|
||||
class FilterModule:
|
||||
|
||||
def filters(self):
|
||||
return {
|
||||
'remove_keys': remove_keys,
|
||||
"remove_keys": remove_keys,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,10 +131,11 @@ _value:
|
|||
|
||||
from ansible_collections.community.general.plugins.plugin_utils.keys_filter import (
|
||||
_keys_filter_params,
|
||||
_keys_filter_target_dict)
|
||||
_keys_filter_target_dict,
|
||||
)
|
||||
|
||||
|
||||
def replace_keys(data, target=None, matching_parameter='equal'):
|
||||
def replace_keys(data, target=None, matching_parameter="equal"):
|
||||
"""replace specific keys in a list of dictionaries"""
|
||||
|
||||
# test parameters
|
||||
|
|
@ -142,25 +143,29 @@ def replace_keys(data, target=None, matching_parameter='equal'):
|
|||
# test and transform target
|
||||
tz = _keys_filter_target_dict(target, matching_parameter)
|
||||
|
||||
if matching_parameter == 'equal':
|
||||
if matching_parameter == "equal":
|
||||
|
||||
def replace_key(key):
|
||||
for b, a in tz:
|
||||
if key == b:
|
||||
return a
|
||||
return key
|
||||
elif matching_parameter == 'starts_with':
|
||||
elif matching_parameter == "starts_with":
|
||||
|
||||
def replace_key(key):
|
||||
for b, a in tz:
|
||||
if key.startswith(b):
|
||||
return a
|
||||
return key
|
||||
elif matching_parameter == 'ends_with':
|
||||
elif matching_parameter == "ends_with":
|
||||
|
||||
def replace_key(key):
|
||||
for b, a in tz:
|
||||
if key.endswith(b):
|
||||
return a
|
||||
return key
|
||||
elif matching_parameter == 'regex':
|
||||
elif matching_parameter == "regex":
|
||||
|
||||
def replace_key(key):
|
||||
for b, a in tz:
|
||||
if b.match(key):
|
||||
|
|
@ -171,8 +176,7 @@ def replace_keys(data, target=None, matching_parameter='equal'):
|
|||
|
||||
|
||||
class FilterModule:
|
||||
|
||||
def filters(self):
|
||||
return {
|
||||
'replace_keys': replace_keys,
|
||||
"replace_keys": replace_keys,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -140,8 +140,5 @@ def reveal_ansible_type(data, alias=None):
|
|||
|
||||
|
||||
class FilterModule:
|
||||
|
||||
def filters(self):
|
||||
return {
|
||||
'reveal_ansible_type': reveal_ansible_type
|
||||
}
|
||||
return {"reveal_ansible_type": reveal_ansible_type}
|
||||
|
|
|
|||
|
|
@ -9,30 +9,30 @@ from ansible.errors import AnsibleFilterError
|
|||
|
||||
|
||||
UNIT_FACTORS = {
|
||||
'ms': [],
|
||||
's': [1000],
|
||||
'm': [1000, 60],
|
||||
'h': [1000, 60, 60],
|
||||
'd': [1000, 60, 60, 24],
|
||||
'w': [1000, 60, 60, 24, 7],
|
||||
'mo': [1000, 60, 60, 24, 30],
|
||||
'y': [1000, 60, 60, 24, 365],
|
||||
"ms": [],
|
||||
"s": [1000],
|
||||
"m": [1000, 60],
|
||||
"h": [1000, 60, 60],
|
||||
"d": [1000, 60, 60, 24],
|
||||
"w": [1000, 60, 60, 24, 7],
|
||||
"mo": [1000, 60, 60, 24, 30],
|
||||
"y": [1000, 60, 60, 24, 365],
|
||||
}
|
||||
|
||||
|
||||
UNIT_TO_SHORT_FORM = {
|
||||
'millisecond': 'ms',
|
||||
'msec': 'ms',
|
||||
'msecond': 'ms',
|
||||
'sec': 's',
|
||||
'second': 's',
|
||||
'hour': 'h',
|
||||
'min': 'm',
|
||||
'minute': 'm',
|
||||
'day': 'd',
|
||||
'week': 'w',
|
||||
'month': 'mo',
|
||||
'year': 'y',
|
||||
"millisecond": "ms",
|
||||
"msec": "ms",
|
||||
"msecond": "ms",
|
||||
"sec": "s",
|
||||
"second": "s",
|
||||
"hour": "h",
|
||||
"min": "m",
|
||||
"minute": "m",
|
||||
"day": "d",
|
||||
"week": "w",
|
||||
"month": "mo",
|
||||
"year": "y",
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -43,8 +43,8 @@ def multiply(factors):
|
|||
return result
|
||||
|
||||
|
||||
def to_time_unit(human_time, unit='ms', **kwargs):
|
||||
''' Return a time unit from a human readable string '''
|
||||
def to_time_unit(human_time, unit="ms", **kwargs):
|
||||
"""Return a time unit from a human readable string"""
|
||||
|
||||
# No need to handle 0
|
||||
if human_time == "0":
|
||||
|
|
@ -53,35 +53,35 @@ def to_time_unit(human_time, unit='ms', **kwargs):
|
|||
unit_to_short_form = UNIT_TO_SHORT_FORM
|
||||
unit_factors = UNIT_FACTORS
|
||||
|
||||
unit = unit_to_short_form.get(unit.rstrip('s'), unit)
|
||||
unit = unit_to_short_form.get(unit.rstrip("s"), unit)
|
||||
if unit not in unit_factors:
|
||||
raise AnsibleFilterError((
|
||||
f"to_time_unit() can not convert to the following unit: {unit}. Available units (singular or plural):"
|
||||
f"{', '.join(unit_to_short_form.keys())}. Available short units: {', '.join(unit_factors.keys())}"
|
||||
))
|
||||
raise AnsibleFilterError(
|
||||
(
|
||||
f"to_time_unit() can not convert to the following unit: {unit}. Available units (singular or plural):"
|
||||
f"{', '.join(unit_to_short_form.keys())}. Available short units: {', '.join(unit_factors.keys())}"
|
||||
)
|
||||
)
|
||||
|
||||
if 'year' in kwargs:
|
||||
unit_factors['y'] = unit_factors['y'][:-1] + [kwargs.pop('year')]
|
||||
if 'month' in kwargs:
|
||||
unit_factors['mo'] = unit_factors['mo'][:-1] + [kwargs.pop('month')]
|
||||
if "year" in kwargs:
|
||||
unit_factors["y"] = unit_factors["y"][:-1] + [kwargs.pop("year")]
|
||||
if "month" in kwargs:
|
||||
unit_factors["mo"] = unit_factors["mo"][:-1] + [kwargs.pop("month")]
|
||||
|
||||
if kwargs:
|
||||
raise AnsibleFilterError(f"to_time_unit() got unknown keyword arguments: {', '.join(kwargs.keys())}")
|
||||
|
||||
result = 0
|
||||
for h_time_string in human_time.split():
|
||||
res = re.match(r'(-?\d+)(\w+)', h_time_string)
|
||||
res = re.match(r"(-?\d+)(\w+)", h_time_string)
|
||||
if not res:
|
||||
raise AnsibleFilterError(
|
||||
f"to_time_unit() can not interpret following string: {human_time}")
|
||||
raise AnsibleFilterError(f"to_time_unit() can not interpret following string: {human_time}")
|
||||
|
||||
h_time_int = int(res.group(1))
|
||||
h_time_unit = res.group(2)
|
||||
|
||||
h_time_unit = unit_to_short_form.get(h_time_unit.rstrip('s'), h_time_unit)
|
||||
h_time_unit = unit_to_short_form.get(h_time_unit.rstrip("s"), h_time_unit)
|
||||
if h_time_unit not in unit_factors:
|
||||
raise AnsibleFilterError(
|
||||
f"to_time_unit() can not interpret following string: {human_time}")
|
||||
raise AnsibleFilterError(f"to_time_unit() can not interpret following string: {human_time}")
|
||||
|
||||
time_in_milliseconds = h_time_int * multiply(unit_factors[h_time_unit])
|
||||
result += time_in_milliseconds
|
||||
|
|
@ -89,59 +89,59 @@ def to_time_unit(human_time, unit='ms', **kwargs):
|
|||
|
||||
|
||||
def to_milliseconds(human_time, **kwargs):
|
||||
''' Return milli seconds from a human readable string '''
|
||||
return to_time_unit(human_time, 'ms', **kwargs)
|
||||
"""Return milli seconds from a human readable string"""
|
||||
return to_time_unit(human_time, "ms", **kwargs)
|
||||
|
||||
|
||||
def to_seconds(human_time, **kwargs):
|
||||
''' Return seconds from a human readable string '''
|
||||
return to_time_unit(human_time, 's', **kwargs)
|
||||
"""Return seconds from a human readable string"""
|
||||
return to_time_unit(human_time, "s", **kwargs)
|
||||
|
||||
|
||||
def to_minutes(human_time, **kwargs):
|
||||
''' Return minutes from a human readable string '''
|
||||
return to_time_unit(human_time, 'm', **kwargs)
|
||||
"""Return minutes from a human readable string"""
|
||||
return to_time_unit(human_time, "m", **kwargs)
|
||||
|
||||
|
||||
def to_hours(human_time, **kwargs):
|
||||
''' Return hours from a human readable string '''
|
||||
return to_time_unit(human_time, 'h', **kwargs)
|
||||
"""Return hours from a human readable string"""
|
||||
return to_time_unit(human_time, "h", **kwargs)
|
||||
|
||||
|
||||
def to_days(human_time, **kwargs):
|
||||
''' Return days from a human readable string '''
|
||||
return to_time_unit(human_time, 'd', **kwargs)
|
||||
"""Return days from a human readable string"""
|
||||
return to_time_unit(human_time, "d", **kwargs)
|
||||
|
||||
|
||||
def to_weeks(human_time, **kwargs):
|
||||
''' Return weeks from a human readable string '''
|
||||
return to_time_unit(human_time, 'w', **kwargs)
|
||||
"""Return weeks from a human readable string"""
|
||||
return to_time_unit(human_time, "w", **kwargs)
|
||||
|
||||
|
||||
def to_months(human_time, **kwargs):
|
||||
''' Return months from a human readable string '''
|
||||
return to_time_unit(human_time, 'mo', **kwargs)
|
||||
"""Return months from a human readable string"""
|
||||
return to_time_unit(human_time, "mo", **kwargs)
|
||||
|
||||
|
||||
def to_years(human_time, **kwargs):
|
||||
''' Return years from a human readable string '''
|
||||
return to_time_unit(human_time, 'y', **kwargs)
|
||||
"""Return years from a human readable string"""
|
||||
return to_time_unit(human_time, "y", **kwargs)
|
||||
|
||||
|
||||
class FilterModule:
|
||||
''' Ansible time jinja2 filters '''
|
||||
"""Ansible time jinja2 filters"""
|
||||
|
||||
def filters(self):
|
||||
filters = {
|
||||
'to_time_unit': to_time_unit,
|
||||
'to_milliseconds': to_milliseconds,
|
||||
'to_seconds': to_seconds,
|
||||
'to_minutes': to_minutes,
|
||||
'to_hours': to_hours,
|
||||
'to_days': to_days,
|
||||
'to_weeks': to_weeks,
|
||||
'to_months': to_months,
|
||||
'to_years': to_years,
|
||||
"to_time_unit": to_time_unit,
|
||||
"to_milliseconds": to_milliseconds,
|
||||
"to_seconds": to_seconds,
|
||||
"to_minutes": to_minutes,
|
||||
"to_hours": to_hours,
|
||||
"to_days": to_days,
|
||||
"to_weeks": to_weeks,
|
||||
"to_months": to_months,
|
||||
"to_years": to_years,
|
||||
}
|
||||
|
||||
return filters
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
# Copyright (c) 2023, Steffen Scheib <steffen@scheib.me>
|
||||
# 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
|
||||
|
|
@ -55,7 +54,7 @@ from ansible.errors import AnsibleFilterError
|
|||
|
||||
|
||||
class IniParser(ConfigParser):
|
||||
''' Implements a configparser which sets the correct optionxform '''
|
||||
"""Implements a configparser which sets the correct optionxform"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(interpolation=None)
|
||||
|
|
@ -63,23 +62,21 @@ class IniParser(ConfigParser):
|
|||
|
||||
|
||||
def to_ini(obj):
|
||||
''' Read the given dict and return an INI formatted string '''
|
||||
"""Read the given dict and return an INI formatted string"""
|
||||
|
||||
if not isinstance(obj, Mapping):
|
||||
raise AnsibleFilterError(f'to_ini requires a dict, got {type(obj)}')
|
||||
raise AnsibleFilterError(f"to_ini requires a dict, got {type(obj)}")
|
||||
|
||||
ini_parser = IniParser()
|
||||
|
||||
try:
|
||||
ini_parser.read_dict(obj)
|
||||
except Exception as ex:
|
||||
raise AnsibleFilterError('to_ini failed to parse given dict:'
|
||||
f'{ex}', orig_exc=ex)
|
||||
raise AnsibleFilterError(f"to_ini failed to parse given dict:{ex}", orig_exc=ex)
|
||||
|
||||
# catching empty dicts
|
||||
if obj == dict():
|
||||
raise AnsibleFilterError('to_ini received an empty dict. '
|
||||
'An empty dict cannot be converted.')
|
||||
raise AnsibleFilterError("to_ini received an empty dict. An empty dict cannot be converted.")
|
||||
|
||||
config = StringIO()
|
||||
ini_parser.write(config)
|
||||
|
|
@ -87,14 +84,11 @@ def to_ini(obj):
|
|||
# config.getvalue() returns two \n at the end
|
||||
# with the below insanity, we remove the very last character of
|
||||
# the resulting string
|
||||
return ''.join(config.getvalue().rsplit(config.getvalue()[-1], 1))
|
||||
return "".join(config.getvalue().rsplit(config.getvalue()[-1], 1))
|
||||
|
||||
|
||||
class FilterModule:
|
||||
''' Query filter '''
|
||||
"""Query filter"""
|
||||
|
||||
def filters(self):
|
||||
|
||||
return {
|
||||
'to_ini': to_ini
|
||||
}
|
||||
return {"to_ini": to_ini}
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@ _value:
|
|||
|
||||
try:
|
||||
import prettytable
|
||||
|
||||
HAS_PRETTYTABLE = True
|
||||
except ImportError:
|
||||
HAS_PRETTYTABLE = False
|
||||
|
|
@ -125,6 +126,7 @@ class TypeValidationError(AnsibleFilterError):
|
|||
obj: The object with incorrect type
|
||||
expected: Description of expected type
|
||||
"""
|
||||
|
||||
def __init__(self, obj, expected):
|
||||
type_name = "string" if isinstance(obj, str) else type(obj).__name__
|
||||
super().__init__(f"Expected {expected}, got a {type_name}")
|
||||
|
|
@ -142,10 +144,7 @@ def _validate_list_param(param, param_name, ensure_strings=True):
|
|||
AnsibleFilterError: If validation fails
|
||||
"""
|
||||
# Map parameter names to their original error message format
|
||||
error_messages = {
|
||||
"column_order": "a list of column names",
|
||||
"header_names": "a list of header names"
|
||||
}
|
||||
error_messages = {"column_order": "a list of column names", "header_names": "a list of header names"}
|
||||
|
||||
# Use the specific error message if available, otherwise use a generic one
|
||||
error_msg = error_messages.get(param_name, f"a list for {param_name}")
|
||||
|
|
@ -182,9 +181,9 @@ def _match_key(item_dict, lookup_key):
|
|||
|
||||
# Try boolean conversion for 'true'/'false' strings
|
||||
if isinstance(lookup_key, str):
|
||||
if lookup_key.lower() == 'true' and True in item_dict:
|
||||
if lookup_key.lower() == "true" and True in item_dict:
|
||||
return True
|
||||
if lookup_key.lower() == 'false' and False in item_dict:
|
||||
if lookup_key.lower() == "false" and False in item_dict:
|
||||
return False
|
||||
|
||||
# Try numeric conversion for string numbers
|
||||
|
|
@ -258,9 +257,7 @@ def to_prettytable(data, *args, **kwargs):
|
|||
String containing the ASCII table
|
||||
"""
|
||||
if not HAS_PRETTYTABLE:
|
||||
raise AnsibleFilterError(
|
||||
'You need to install "prettytable" Python module to use this filter'
|
||||
)
|
||||
raise AnsibleFilterError('You need to install "prettytable" Python module to use this filter')
|
||||
|
||||
# === Input validation ===
|
||||
# Validate list type
|
||||
|
|
@ -278,7 +275,7 @@ def to_prettytable(data, *args, **kwargs):
|
|||
|
||||
# === Process column order ===
|
||||
# Handle both positional and keyword column_order
|
||||
column_order = kwargs.pop('column_order', None)
|
||||
column_order = kwargs.pop("column_order", None)
|
||||
|
||||
# Check for conflict between args and column_order
|
||||
if args and column_order is not None:
|
||||
|
|
@ -295,7 +292,8 @@ def to_prettytable(data, *args, **kwargs):
|
|||
# Validate column_order doesn't exceed the number of fields (skip if data is empty)
|
||||
if data and len(column_order) > max_fields:
|
||||
raise AnsibleFilterError(
|
||||
f"'column_order' has more elements ({len(column_order)}) than available fields in data ({max_fields})")
|
||||
f"'column_order' has more elements ({len(column_order)}) than available fields in data ({max_fields})"
|
||||
)
|
||||
|
||||
# === Process headers ===
|
||||
# Determine field names and ensure they are strings
|
||||
|
|
@ -306,24 +304,26 @@ def to_prettytable(data, *args, **kwargs):
|
|||
field_names = [to_text(k) for k in sample_dict]
|
||||
|
||||
# Process custom headers
|
||||
header_names = kwargs.pop('header_names', None)
|
||||
header_names = kwargs.pop("header_names", None)
|
||||
if header_names is not None:
|
||||
_validate_list_param(header_names, "header_names")
|
||||
|
||||
# Validate header_names doesn't exceed the number of fields (skip if data is empty)
|
||||
if data and len(header_names) > max_fields:
|
||||
raise AnsibleFilterError(
|
||||
f"'header_names' has more elements ({len(header_names)}) than available fields in data ({max_fields})")
|
||||
f"'header_names' has more elements ({len(header_names)}) than available fields in data ({max_fields})"
|
||||
)
|
||||
|
||||
# Validate that column_order and header_names have the same size if both provided
|
||||
if column_order is not None and len(column_order) != len(header_names):
|
||||
raise AnsibleFilterError(
|
||||
f"'column_order' and 'header_names' must have the same number of elements. "
|
||||
f"Got {len(column_order)} columns and {len(header_names)} headers.")
|
||||
f"Got {len(column_order)} columns and {len(header_names)} headers."
|
||||
)
|
||||
|
||||
# === Process alignments ===
|
||||
# Get column alignments and validate
|
||||
column_alignments = kwargs.pop('column_alignments', {})
|
||||
column_alignments = kwargs.pop("column_alignments", {})
|
||||
valid_alignments = {"left", "center", "right", "l", "c", "r"}
|
||||
|
||||
# Validate column_alignments is a dictionary
|
||||
|
|
@ -344,12 +344,14 @@ def to_prettytable(data, *args, **kwargs):
|
|||
if value.lower() not in valid_alignments:
|
||||
raise AnsibleFilterError(
|
||||
f"Invalid alignment '{value}' in 'column_alignments'. "
|
||||
f"Valid alignments are: {', '.join(sorted(valid_alignments))}")
|
||||
f"Valid alignments are: {', '.join(sorted(valid_alignments))}"
|
||||
)
|
||||
|
||||
# Validate column_alignments doesn't have more keys than fields (skip if data is empty)
|
||||
if data and len(column_alignments) > max_fields:
|
||||
raise AnsibleFilterError(
|
||||
f"'column_alignments' has more elements ({len(column_alignments)}) than available fields in data ({max_fields})")
|
||||
f"'column_alignments' has more elements ({len(column_alignments)}) than available fields in data ({max_fields})"
|
||||
)
|
||||
|
||||
# Check for unknown parameters
|
||||
if kwargs:
|
||||
|
|
@ -404,6 +406,4 @@ class FilterModule:
|
|||
"""Ansible core jinja2 filters."""
|
||||
|
||||
def filters(self):
|
||||
return {
|
||||
'to_prettytable': to_prettytable
|
||||
}
|
||||
return {"to_prettytable": to_prettytable}
|
||||
|
|
|
|||
|
|
@ -8,16 +8,19 @@ import typing as t
|
|||
from collections.abc import Mapping, Set
|
||||
|
||||
from yaml import dump
|
||||
|
||||
try:
|
||||
from yaml.cyaml import CSafeDumper as SafeDumper
|
||||
except ImportError:
|
||||
from yaml import SafeDumper # type: ignore
|
||||
|
||||
from ansible.module_utils.common.collections import is_sequence
|
||||
|
||||
try:
|
||||
# This is ansible-core 2.19+
|
||||
from ansible.utils.vars import transform_to_native_types
|
||||
from ansible.parsing.vault import VaultHelper, VaultLib
|
||||
|
||||
HAS_TRANSFORM_TO_NATIVE_TYPES = True
|
||||
except ImportError:
|
||||
HAS_TRANSFORM_TO_NATIVE_TYPES = False
|
||||
|
|
@ -36,7 +39,9 @@ def _to_native_types_compat(value: t.Any, *, redact_value: str | None) -> t.Any:
|
|||
# But that's fine, since this code path isn't taken on ansible-core 2.19+ anyway.
|
||||
if isinstance(value, Mapping):
|
||||
return {
|
||||
_to_native_types_compat(key, redact_value=redact_value): _to_native_types_compat(val, redact_value=redact_value)
|
||||
_to_native_types_compat(key, redact_value=redact_value): _to_native_types_compat(
|
||||
val, redact_value=redact_value
|
||||
)
|
||||
for key, val in value.items()
|
||||
}
|
||||
if isinstance(value, Set):
|
||||
|
|
@ -80,11 +85,15 @@ def remove_all_tags(value: t.Any, *, redact_sensitive_values: bool = False) -> t
|
|||
|
||||
return _to_native_types_compat( # type: ignore[unreachable]
|
||||
value,
|
||||
redact_value="<redacted>" if redact_sensitive_values else None, # same string as in ansible-core 2.19 by transform_to_native_types()
|
||||
redact_value="<redacted>"
|
||||
if redact_sensitive_values
|
||||
else None, # same string as in ansible-core 2.19 by transform_to_native_types()
|
||||
)
|
||||
|
||||
|
||||
def to_yaml(value: t.Any, *, redact_sensitive_values: bool = False, default_flow_style: bool | None = None, **kwargs) -> str:
|
||||
def to_yaml(
|
||||
value: t.Any, *, redact_sensitive_values: bool = False, default_flow_style: bool | None = None, **kwargs
|
||||
) -> str:
|
||||
"""Serialize input as terse flow-style YAML."""
|
||||
return dump(
|
||||
remove_all_tags(value, redact_sensitive_values=redact_sensitive_values),
|
||||
|
|
@ -95,7 +104,9 @@ def to_yaml(value: t.Any, *, redact_sensitive_values: bool = False, default_flow
|
|||
)
|
||||
|
||||
|
||||
def to_nice_yaml(value: t.Any, *, redact_sensitive_values: bool = False, indent: int = 2, default_flow_style: bool = False, **kwargs) -> str:
|
||||
def to_nice_yaml(
|
||||
value: t.Any, *, redact_sensitive_values: bool = False, indent: int = 2, default_flow_style: bool = False, **kwargs
|
||||
) -> str:
|
||||
"""Serialize input as verbose multi-line YAML."""
|
||||
return to_yaml(
|
||||
value,
|
||||
|
|
@ -109,6 +120,6 @@ def to_nice_yaml(value: t.Any, *, redact_sensitive_values: bool = False, indent:
|
|||
class FilterModule:
|
||||
def filters(self):
|
||||
return {
|
||||
'to_yaml': to_yaml,
|
||||
'to_nice_yaml': to_nice_yaml,
|
||||
"to_yaml": to_yaml,
|
||||
"to_nice_yaml": to_nice_yaml,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
# Copyright (c) 2021, Andrew Pantuso (@ajpantuso) <ajpantuso@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
|
||||
|
|
@ -55,7 +54,7 @@ except ImportError:
|
|||
from ansible.errors import AnsibleFilterTypeError as AnsibleTypeError # type: ignore
|
||||
|
||||
|
||||
def unicode_normalize(data, form='NFC'):
|
||||
def unicode_normalize(data, form="NFC"):
|
||||
"""Applies normalization to 'unicode' strings.
|
||||
|
||||
Args:
|
||||
|
|
@ -70,7 +69,7 @@ def unicode_normalize(data, form='NFC'):
|
|||
if not isinstance(data, str):
|
||||
raise AnsibleTypeError(f"{type(data)} is not a valid input type")
|
||||
|
||||
if form not in ('NFC', 'NFD', 'NFKC', 'NFKD'):
|
||||
if form not in ("NFC", "NFD", "NFKC", "NFKD"):
|
||||
raise AnsibleFilterError(f"{form!r} is not a valid form")
|
||||
|
||||
return normalize(form, data)
|
||||
|
|
@ -79,5 +78,5 @@ def unicode_normalize(data, form='NFC'):
|
|||
class FilterModule:
|
||||
def filters(self):
|
||||
return {
|
||||
'unicode_normalize': unicode_normalize,
|
||||
"unicode_normalize": unicode_normalize,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,14 +37,12 @@ from ansible_collections.community.general.plugins.module_utils.version import L
|
|||
|
||||
|
||||
def version_sort(value, reverse=False):
|
||||
'''Sort a list according to loose versions so that e.g. 2.9 is smaller than 2.10'''
|
||||
"""Sort a list according to loose versions so that e.g. 2.9 is smaller than 2.10"""
|
||||
return sorted(value, key=LooseVersion, reverse=reverse)
|
||||
|
||||
|
||||
class FilterModule:
|
||||
''' Version sort filter '''
|
||||
"""Version sort filter"""
|
||||
|
||||
def filters(self):
|
||||
return {
|
||||
'version_sort': version_sort
|
||||
}
|
||||
return {"version_sort": version_sort}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue