|
|
|
|
@@ -11,38 +11,124 @@ import typing as t
|
|
|
|
|
|
|
|
|
|
from ansible.module_utils.basic import AnsibleModule
|
|
|
|
|
|
|
|
|
|
_T = t.TypeVar("_T")
|
|
|
|
|
if t.TYPE_CHECKING:
|
|
|
|
|
import datetime # pragma: no cover
|
|
|
|
|
from collections.abc import Callable, Mapping, Sequence # pragma: no cover
|
|
|
|
|
|
|
|
|
|
_T = t.TypeVar("_T") # pragma: no cover
|
|
|
|
|
|
|
|
|
|
def _ensure_list(value: list[_T] | tuple[_T] | None) -> list[_T]:
|
|
|
|
|
if value is None:
|
|
|
|
|
return []
|
|
|
|
|
return list(value)
|
|
|
|
|
ArgSpecType = t.Literal[ # pragma: no cover
|
|
|
|
|
"bits",
|
|
|
|
|
"bool",
|
|
|
|
|
"bytes",
|
|
|
|
|
"dict",
|
|
|
|
|
"float",
|
|
|
|
|
"int",
|
|
|
|
|
"json",
|
|
|
|
|
"jsonarg",
|
|
|
|
|
"list",
|
|
|
|
|
"path",
|
|
|
|
|
"raw",
|
|
|
|
|
"sid",
|
|
|
|
|
"str",
|
|
|
|
|
]
|
|
|
|
|
MutuallyExclusiveT = t.Union[ # pragma: no cover # noqa: UP007
|
|
|
|
|
Sequence[str], Sequence[Sequence[str]]
|
|
|
|
|
]
|
|
|
|
|
MutuallyExclusiveMutT = list[Sequence[str]] # pragma: no cover
|
|
|
|
|
RequiredTogetherT = Sequence[Sequence[str]] # pragma: no cover
|
|
|
|
|
RequiredTogetherMutT = list[Sequence[str]] # pragma: no cover
|
|
|
|
|
RequiredOneOfT = Sequence[Sequence[str]] # pragma: no cover
|
|
|
|
|
RequiredOneOfMutT = list[Sequence[str]] # pragma: no cover
|
|
|
|
|
RequiredIfT = Sequence[ # pragma: no cover
|
|
|
|
|
t.Union[ # noqa: UP007
|
|
|
|
|
list[object],
|
|
|
|
|
tuple[str, object, Sequence[str]],
|
|
|
|
|
tuple[str, object, Sequence[str], bool],
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
RequiredIfMutT = list[ # pragma: no cover
|
|
|
|
|
t.Union[ # noqa: UP007
|
|
|
|
|
list[object],
|
|
|
|
|
tuple[str, object, Sequence[str]],
|
|
|
|
|
tuple[str, object, Sequence[str], bool],
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
RequiredByT = Mapping[str, Sequence[str]] # pragma: no cover
|
|
|
|
|
RequiredByMutT = dict[str, Sequence[str]] # pragma: no cover
|
|
|
|
|
|
|
|
|
|
class DeprecatedAlias(t.TypedDict): # pragma: no cover
|
|
|
|
|
name: str
|
|
|
|
|
date: t.NotRequired[datetime.date | str]
|
|
|
|
|
version: t.NotRequired[str]
|
|
|
|
|
collection_name: str
|
|
|
|
|
|
|
|
|
|
class OneArgumentSpecT(t.TypedDict): # pragma: no cover
|
|
|
|
|
type: t.NotRequired[ArgSpecType | Callable[[object], object]]
|
|
|
|
|
elements: t.NotRequired[ArgSpecType]
|
|
|
|
|
default: t.NotRequired[object]
|
|
|
|
|
# For fallback elements, the first element of the sequence has to be a callable, the others sequences or dicts.
|
|
|
|
|
# Unfortunately there is no way to specify this in a generic way...
|
|
|
|
|
fallback: t.NotRequired[
|
|
|
|
|
Sequence[
|
|
|
|
|
Callable[[object], object] | Sequence[object] | Mapping[str, object]
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
choices: t.NotRequired[Sequence[object]]
|
|
|
|
|
context: t.NotRequired[Mapping[object, object]]
|
|
|
|
|
required: t.NotRequired[bool]
|
|
|
|
|
no_log: t.NotRequired[bool]
|
|
|
|
|
aliases: t.NotRequired[Sequence[str]]
|
|
|
|
|
apply_defaults: t.NotRequired[bool]
|
|
|
|
|
removed_in_version: t.NotRequired[str]
|
|
|
|
|
removed_at_date: t.NotRequired[datetime.date | str]
|
|
|
|
|
removed_from_collection: t.NotRequired[str]
|
|
|
|
|
options: t.NotRequired[Mapping[str, OneArgumentSpecT]] # recursive!
|
|
|
|
|
deprecated_aliases: t.NotRequired[Sequence[DeprecatedAlias]]
|
|
|
|
|
|
|
|
|
|
mutually_exclusive: t.NotRequired[MutuallyExclusiveT]
|
|
|
|
|
required_together: t.NotRequired[RequiredTogetherT]
|
|
|
|
|
required_one_of: t.NotRequired[RequiredOneOfT]
|
|
|
|
|
required_if: t.NotRequired[RequiredIfT]
|
|
|
|
|
required_by: t.NotRequired[RequiredByT]
|
|
|
|
|
|
|
|
|
|
ArgumentSpecT = Mapping[str, OneArgumentSpecT] # pragma: no cover
|
|
|
|
|
ArgumentSpecMutT = dict[str, OneArgumentSpecT] # pragma: no cover
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ArgumentSpec:
|
|
|
|
|
def __init__(
|
|
|
|
|
self,
|
|
|
|
|
argument_spec: dict[str, t.Any] | None = None,
|
|
|
|
|
argument_spec: ArgumentSpecT | None = None,
|
|
|
|
|
*,
|
|
|
|
|
mutually_exclusive: list[list[str] | tuple[str, ...]] | None = None,
|
|
|
|
|
required_together: list[list[str] | tuple[str, ...]] | None = None,
|
|
|
|
|
required_one_of: list[list[str] | tuple[str, ...]] | None = None,
|
|
|
|
|
required_if: (
|
|
|
|
|
list[
|
|
|
|
|
tuple[str, t.Any, list[str] | tuple[str, ...]]
|
|
|
|
|
| tuple[str, t.Any, list[str] | tuple[str, ...], bool]
|
|
|
|
|
]
|
|
|
|
|
| None
|
|
|
|
|
) = None,
|
|
|
|
|
required_by: dict[str, tuple[str, ...] | list[str]] | None = None,
|
|
|
|
|
required_together: RequiredTogetherT | None = None,
|
|
|
|
|
required_if: RequiredIfT | None = None,
|
|
|
|
|
required_one_of: RequiredOneOfT | None = None,
|
|
|
|
|
mutually_exclusive: MutuallyExclusiveT | None = None,
|
|
|
|
|
required_by: RequiredByT | None = None,
|
|
|
|
|
) -> None:
|
|
|
|
|
self.argument_spec = argument_spec or {}
|
|
|
|
|
self.mutually_exclusive = _ensure_list(mutually_exclusive)
|
|
|
|
|
self.required_together = _ensure_list(required_together)
|
|
|
|
|
self.required_one_of = _ensure_list(required_one_of)
|
|
|
|
|
self.required_if = _ensure_list(required_if)
|
|
|
|
|
self.required_by = required_by or {}
|
|
|
|
|
self.argument_spec: ArgumentSpecMutT = {}
|
|
|
|
|
self.required_together: RequiredTogetherMutT = []
|
|
|
|
|
self.required_if: RequiredIfMutT = []
|
|
|
|
|
self.required_one_of: RequiredOneOfMutT = []
|
|
|
|
|
self.mutually_exclusive: MutuallyExclusiveMutT = []
|
|
|
|
|
self.required_by: RequiredByMutT = {}
|
|
|
|
|
if argument_spec:
|
|
|
|
|
self.argument_spec.update(argument_spec)
|
|
|
|
|
if required_together:
|
|
|
|
|
self.required_together.extend(required_together)
|
|
|
|
|
if required_if:
|
|
|
|
|
self.required_if.extend(required_if)
|
|
|
|
|
if required_one_of:
|
|
|
|
|
self.required_one_of.extend(required_one_of)
|
|
|
|
|
if mutually_exclusive:
|
|
|
|
|
if all(isinstance(me, str) for me in mutually_exclusive):
|
|
|
|
|
# mutually_exclusive is a Sequence[str]
|
|
|
|
|
self.mutually_exclusive.append(mutually_exclusive) # type: ignore
|
|
|
|
|
else:
|
|
|
|
|
self.mutually_exclusive.extend(mutually_exclusive)
|
|
|
|
|
if required_by:
|
|
|
|
|
self.required_by.update(required_by)
|
|
|
|
|
|
|
|
|
|
def update_argspec(self, **kwargs: t.Any) -> t.Self:
|
|
|
|
|
self.argument_spec.update(kwargs)
|
|
|
|
|
@@ -51,17 +137,11 @@ class ArgumentSpec:
|
|
|
|
|
def update(
|
|
|
|
|
self,
|
|
|
|
|
*,
|
|
|
|
|
mutually_exclusive: list[list[str] | tuple[str, ...]] | None = None,
|
|
|
|
|
required_together: list[list[str] | tuple[str, ...]] | None = None,
|
|
|
|
|
required_one_of: list[list[str] | tuple[str, ...]] | None = None,
|
|
|
|
|
required_if: (
|
|
|
|
|
list[
|
|
|
|
|
tuple[str, t.Any, list[str] | tuple[str, ...]]
|
|
|
|
|
| tuple[str, t.Any, list[str] | tuple[str, ...], bool]
|
|
|
|
|
]
|
|
|
|
|
| None
|
|
|
|
|
) = None,
|
|
|
|
|
required_by: dict[str, tuple[str, ...] | list[str]] | None = None,
|
|
|
|
|
required_together: RequiredTogetherT | None = None,
|
|
|
|
|
required_if: RequiredIfT | None = None,
|
|
|
|
|
required_one_of: RequiredOneOfT | None = None,
|
|
|
|
|
mutually_exclusive: MutuallyExclusiveT | None = None,
|
|
|
|
|
required_by: RequiredByT | None = None,
|
|
|
|
|
) -> t.Self:
|
|
|
|
|
if mutually_exclusive:
|
|
|
|
|
self.mutually_exclusive.extend(mutually_exclusive)
|
|
|
|
|
|