mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-04-17 01:11:28 +00:00
[PR #11167/19757b3a backport][stable-12] Add type hints to action and test plugins and to plugin utils; fix some bugs, and improve input validation (#11191)
Add type hints to action and test plugins and to plugin utils; fix some bugs, and improve input validation (#11167)
* Add type hints to action and test plugins and to plugin utils. Also fix some bugs and add proper input validation.
* Combine lines.
* Extend changelog fragment.
* Move task_vars initialization up.
---------
(cherry picked from commit 19757b3a4c)
Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
This commit is contained in:
parent
dbcd0dc497
commit
9cdeb5a9b9
11 changed files with 194 additions and 96 deletions
|
|
@ -38,7 +38,11 @@ _value:
|
|||
type: boolean
|
||||
"""
|
||||
|
||||
import typing as t
|
||||
from collections.abc import Callable
|
||||
|
||||
from ansible.plugins.loader import action_loader, module_loader
|
||||
from ansible.errors import AnsibleFilterError
|
||||
|
||||
try:
|
||||
from ansible.errors import AnsiblePluginRemovedError
|
||||
|
|
@ -46,12 +50,14 @@ except ImportError:
|
|||
AnsiblePluginRemovedError = Exception # type: ignore
|
||||
|
||||
|
||||
def a_module(term):
|
||||
def a_module(term: t.Any) -> bool:
|
||||
"""
|
||||
Example:
|
||||
- 'community.general.ufw' is community.general.a_module
|
||||
- 'community.general.does_not_exist' is not community.general.a_module
|
||||
"""
|
||||
if not isinstance(term, str):
|
||||
raise AnsibleFilterError(f"Parameter must be a string, got {term!r} of type {type(term)}")
|
||||
try:
|
||||
for loader in (action_loader, module_loader):
|
||||
data = loader.find_plugin(term)
|
||||
|
|
@ -65,7 +71,7 @@ def a_module(term):
|
|||
class TestModule:
|
||||
"""Ansible jinja2 tests"""
|
||||
|
||||
def tests(self):
|
||||
def tests(self) -> dict[str, Callable]:
|
||||
return {
|
||||
"a_module": a_module,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -222,19 +222,21 @@ _value:
|
|||
type: bool
|
||||
"""
|
||||
|
||||
from collections.abc import Sequence
|
||||
import typing as t
|
||||
from collections.abc import Callable, Sequence
|
||||
|
||||
from ansible.errors import AnsibleFilterError
|
||||
from ansible_collections.community.general.plugins.plugin_utils.ansible_type import _ansible_type
|
||||
|
||||
|
||||
def ansible_type(data, dtype, alias=None):
|
||||
def ansible_type(data: t.Any, dtype: t.Any, alias: t.Any = None) -> bool:
|
||||
"""Validates data type"""
|
||||
|
||||
if not isinstance(dtype, Sequence):
|
||||
msg = "The argument dtype must be a string or a list. dtype is %s."
|
||||
raise AnsibleFilterError(msg % (dtype, type(dtype)))
|
||||
msg = f"The argument dtype must be a string or a list. dtype is {dtype!r} of type {type(dtype)}."
|
||||
raise AnsibleFilterError(msg)
|
||||
|
||||
data_types: Sequence
|
||||
if isinstance(dtype, str):
|
||||
data_types = [dtype]
|
||||
else:
|
||||
|
|
@ -245,5 +247,5 @@ def ansible_type(data, dtype, alias=None):
|
|||
|
||||
|
||||
class TestModule:
|
||||
def tests(self):
|
||||
def tests(self) -> dict[str, Callable]:
|
||||
return {"ansible_type": ansible_type}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,10 @@ _value:
|
|||
type: bool
|
||||
"""
|
||||
|
||||
from ansible.errors import AnsibleError
|
||||
import typing as t
|
||||
from collections.abc import Callable
|
||||
|
||||
from ansible.errors import AnsibleFilterError
|
||||
|
||||
ANOTHER_LIBRARY_IMPORT_ERROR: ImportError | None
|
||||
try:
|
||||
|
|
@ -74,7 +77,7 @@ else:
|
|||
ANOTHER_LIBRARY_IMPORT_ERROR = None
|
||||
|
||||
|
||||
def fqdn_valid(name, min_labels=1, allow_underscores=False):
|
||||
def fqdn_valid(name: t.Any, min_labels: t.Any = 1, allow_underscores: t.Any = False) -> bool:
|
||||
"""
|
||||
Example:
|
||||
- 'srv.example.com' is community.general.fqdn_valid
|
||||
|
|
@ -82,7 +85,22 @@ def fqdn_valid(name, min_labels=1, allow_underscores=False):
|
|||
"""
|
||||
|
||||
if ANOTHER_LIBRARY_IMPORT_ERROR:
|
||||
raise AnsibleError("Python package fqdn must be installed to use this test.") from ANOTHER_LIBRARY_IMPORT_ERROR
|
||||
raise AnsibleFilterError(
|
||||
"Python package fqdn must be installed to use this test."
|
||||
) from ANOTHER_LIBRARY_IMPORT_ERROR
|
||||
|
||||
if not isinstance(name, str):
|
||||
raise AnsibleFilterError(f"The name parameter must be a string, got {name!r} of type {type(name)}")
|
||||
|
||||
if not isinstance(min_labels, int):
|
||||
raise AnsibleFilterError(
|
||||
f"The min_labels parameter must be an integer, got {min_labels!r} of type {type(min_labels)}"
|
||||
)
|
||||
|
||||
if not isinstance(allow_underscores, bool):
|
||||
raise AnsibleFilterError(
|
||||
f"The allow_underscores parameter must be a boolean, got {allow_underscores!r} of type {type(allow_underscores)}"
|
||||
)
|
||||
|
||||
fobj = FQDN(name, min_labels=min_labels, allow_underscores=allow_underscores)
|
||||
return fobj.is_valid
|
||||
|
|
@ -93,7 +111,7 @@ class TestModule:
|
|||
https://pypi.org/project/fqdn/
|
||||
"""
|
||||
|
||||
def tests(self):
|
||||
def tests(self) -> dict[str, Callable]:
|
||||
return {
|
||||
"fqdn_valid": fqdn_valid,
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue