Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
* Implement ansible-collections#8594

* Fix lint and BOTMETA entries.

* Fix BOTMETA

* Consolidate argument check, code simplification, and formatting. Remove test vars.

* Fix lint.

* retrigger checks

* Update plugins/plugin_utils/ansible_type.py

Co-authored-by: Felix Fontein <[email protected]>

* Update plugins/test/ansible_type.py

Co-authored-by: Felix Fontein <[email protected]>

---------

Co-authored-by: Felix Fontein <[email protected]>
  • Loading branch information
vbotka and felixfontein authored Jul 13, 2024
1 parent ca8ecb1 commit 8990f97
Show file tree
Hide file tree
Showing 10 changed files with 847 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .github/BOTMETA.yml
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ files:
maintainers: vbotka
$filters/replace_keys.py:
maintainers: vbotka
$filters/reveal_ansible_type.py:
maintainers: vbotka
$filters/time.py:
maintainers: resmo
$filters/to_days.yml:
Expand Down Expand Up @@ -1425,12 +1427,16 @@ files:
ignore: matze
labels: zypper
maintainers: $team_suse
$plugin_utils/ansible_type.py:
maintainers: vbotka
$plugin_utils/keys_filter.py:
maintainers: vbotka
$plugin_utils/unsafe.py:
maintainers: felixfontein
$tests/a_module.py:
maintainers: felixfontein
$tests/ansible_type.py:
maintainers: vbotka
$tests/fqdn_valid.py:
maintainers: vbotka
#########################
Expand Down
134 changes: 134 additions & 0 deletions plugins/filter/reveal_ansible_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2024 Vladimir Botka <[email protected]>
# 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

from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

DOCUMENTATION = '''
name: reveal_ansible_type
short_description: Return input type
version_added: "9.2.0"
author: Vladimir Botka (@vbotka)
description: This filter returns input type.
options:
_input:
description: Input data.
type: raw
required: true
alias:
description: Data type aliases.
default: {}
type: dictionary
'''

EXAMPLES = '''
# Substitution converts str to AnsibleUnicode
# -------------------------------------------
# String. AnsibleUnicode.
data: "abc"
result: '{{ data | community.general.reveal_ansible_type }}'
# result => AnsibleUnicode
# String. AnsibleUnicode alias str.
alias: {"AnsibleUnicode": "str"}
data: "abc"
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
# result => str
# List. All items are AnsibleUnicode.
data: ["a", "b", "c"]
result: '{{ data | community.general.reveal_ansible_type }}'
# result => list[AnsibleUnicode]
# Dictionary. All keys are AnsibleUnicode. All values are AnsibleUnicode.
data: {"a": "foo", "b": "bar", "c": "baz"}
result: '{{ data | community.general.reveal_ansible_type }}'
# result => dict[AnsibleUnicode, AnsibleUnicode]
# No substitution and no alias. Type of strings is str
# ----------------------------------------------------
# String
result: '{{ "abc" | community.general.reveal_ansible_type }}'
# result => str
# Integer
result: '{{ 123 | community.general.reveal_ansible_type }}'
# result => int
# Float
result: '{{ 123.45 | community.general.reveal_ansible_type }}'
# result => float
# Boolean
result: '{{ true | community.general.reveal_ansible_type }}'
# result => bool
# List. All items are strings.
result: '{{ ["a", "b", "c"] | community.general.reveal_ansible_type }}'
# result => list[str]
# List of dictionaries.
result: '{{ [{"a": 1}, {"b": 2}] | community.general.reveal_ansible_type }}'
# result => list[dict]
# Dictionary. All keys are strings. All values are integers.
result: '{{ {"a": 1} | community.general.reveal_ansible_type }}'
# result => dict[str, int]
# Dictionary. All keys are strings. All values are integers.
result: '{{ {"a": 1, "b": 2} | community.general.reveal_ansible_type }}'
# result => dict[str, int]
# Type of strings is AnsibleUnicode or str
# ----------------------------------------
# Dictionary. The keys are integers or strings. All values are strings.
alias: {"AnsibleUnicode": "str"}
data: {1: 'a', 'b': 'b'}
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
# result => dict[int|str, str]
# Dictionary. All keys are integers. All values are keys.
alias: {"AnsibleUnicode": "str"}
data: {1: 'a', 2: 'b'}
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
# result => dict[int, str]
# Dictionary. All keys are strings. Multiple types values.
alias: {"AnsibleUnicode": "str"}
data: {'a': 1, 'b': 1.1, 'c': 'abc', 'd': True, 'e': ['x', 'y', 'z'], 'f': {'x': 1, 'y': 2}}
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
# result => dict[str, bool|dict|float|int|list|str]
# List. Multiple types items.
alias: {"AnsibleUnicode": "str"}
data: [1, 2, 1.1, 'abc', True, ['x', 'y', 'z'], {'x': 1, 'y': 2}]
result: '{{ data | community.general.reveal_ansible_type(alias) }}'
# result => list[bool|dict|float|int|list|str]
'''

RETURN = '''
_value:
description: Type of the data.
type: str
'''

from ansible_collections.community.general.plugins.plugin_utils.ansible_type import _ansible_type


def reveal_ansible_type(data, alias=None):
"""Returns data type"""

return _ansible_type(data, alias)


class FilterModule(object):

def filters(self):
return {
'reveal_ansible_type': reveal_ansible_type
}
47 changes: 47 additions & 0 deletions plugins/plugin_utils/ansible_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Copyright (c) 2024 Vladimir Botka <[email protected]>
# 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

from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

from ansible.errors import AnsibleFilterError
from ansible.module_utils.common._collections_compat import Mapping


def _atype(data, alias):
"""
Returns the name of the type class.
"""

data_type = type(data).__name__
return alias.get(data_type, data_type)


def _ansible_type(data, alias):
"""
Returns the Ansible data type.
"""

if alias is None:
alias = {}

if not isinstance(alias, Mapping):
msg = "The argument alias must be a dictionary. %s is %s"
raise AnsibleFilterError(msg % (alias, type(alias)))

data_type = _atype(data, alias)

if data_type == 'list' and len(data) > 0:
items = [_atype(i, alias) for i in data]
items_type = '|'.join(sorted(set(items)))
return ''.join((data_type, '[', items_type, ']'))

if data_type == 'dict' and len(data) > 0:
keys = [_atype(i, alias) for i in data.keys()]
vals = [_atype(i, alias) for i in data.values()]
keys_type = '|'.join(sorted(set(keys)))
vals_type = '|'.join(sorted(set(vals)))
return ''.join((data_type, '[', keys_type, ', ', vals_type, ']'))

return data_type
Loading

0 comments on commit 8990f97

Please sign in to comment.