1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2026-02-04 07:51:50 +00:00

CI: add type checking (#10997)

* Set up type checking with mypy.

* Make mypy pass.

* Use list() instead of sorted().
This commit is contained in:
Felix Fontein 2025-10-29 18:13:38 +01:00 committed by GitHub
parent 831787619a
commit 6088b0cff5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
73 changed files with 442 additions and 175 deletions

216
.mypy.ini Normal file
View file

@ -0,0 +1,216 @@
# Copyright (c) Ansible Project
# 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
[mypy]
# check_untyped_defs = True
# disallow_untyped_defs = True
# strict = True -- only try to enable once everything (including dependencies!) is typed
strict_equality = True
strict_bytes = True
warn_redundant_casts = True
# warn_return_any = True
warn_unreachable = True
[mypy-ansible.*]
# ansible-core has partial typing information
follow_untyped_imports = True
# The following imports are Python packages that:
# 1. We do not install (we can't install everything!);
# 2. That have type stubs, but we don't install them (again, we can't install everything!); or
# 3. That have no types and type stubs.
[mypy-aerospike.*]
ignore_missing_imports = True
[mypy-boto3.*]
ignore_missing_imports = True
[mypy-bs4.*]
ignore_missing_imports = True
[mypy-cgi.*]
ignore_missing_imports = True
[mypy-chef.*]
ignore_missing_imports = True
[mypy-consul.*]
ignore_missing_imports = True
[mypy-credstash.*]
ignore_missing_imports = True
[mypy-crypt.*]
ignore_missing_imports = True
[mypy-datadog.*]
ignore_missing_imports = True
[mypy-dbus.*]
ignore_missing_imports = True
[mypy-delinea.*]
ignore_missing_imports = True
[mypy-dnf.*]
ignore_missing_imports = True
[mypy-dnsimple.*]
ignore_missing_imports = True
[mypy-etcd3.*]
ignore_missing_imports = True
[mypy-flatdict.*]
ignore_missing_imports = True
[mypy-footmark.*]
ignore_missing_imports = True
[mypy-fqdn.*]
ignore_missing_imports = True
[mypy-func.*]
ignore_missing_imports = True
[mypy-gi.*]
ignore_missing_imports = True
[mypy-github3.*]
ignore_missing_imports = True
[mypy-hashids.*]
ignore_missing_imports = True
[mypy-heroku3.*]
ignore_missing_imports = True
[mypy-hpe3parclient.*]
ignore_missing_imports = True
[mypy-hpe3par_sdk.*]
ignore_missing_imports = True
[mypy-hpilo.*]
ignore_missing_imports = True
[mypy-hpOneView.*]
ignore_missing_imports = True
[mypy-httmock.*] # TODO!
ignore_missing_imports = True
[mypy-influxdb.*]
ignore_missing_imports = True
[mypy-jc.*]
ignore_missing_imports = True
[mypy-jenkins.*]
ignore_missing_imports = True
[mypy-jmespath.*]
ignore_missing_imports = True
[mypy-jsonpatch.*]
ignore_missing_imports = True
[mypy-kazoo.*]
ignore_missing_imports = True
[mypy-keyring.*]
ignore_missing_imports = True
[mypy-keystoneauth1.*]
ignore_missing_imports = True
[mypy-layman.*]
ignore_missing_imports = True
[mypy-ldap.*]
ignore_missing_imports = True
[mypy-legacycrypt.*]
ignore_missing_imports = True
[mypy-libcloud.*]
ignore_missing_imports = True
[mypy-linode.*]
ignore_missing_imports = True
[mypy-linode_api4.*]
ignore_missing_imports = True
[mypy-lmdb.*]
ignore_missing_imports = True
[mypy-logdna.*]
ignore_missing_imports = True
[mypy-logstash.*]
ignore_missing_imports = True
[mypy-lxc.*]
ignore_missing_imports = True
[mypy-manageiq_client.*]
ignore_missing_imports = True
[mypy-matrix_client.*]
ignore_missing_imports = True
[mypy-memcache.*]
ignore_missing_imports = True
[mypy-nc_dnsapi.*]
ignore_missing_imports = True
[mypy-nomad.*]
ignore_missing_imports = True
[mypy-oci.*]
ignore_missing_imports = True
[mypy-oneandone.*]
ignore_missing_imports = True
[mypy-opentelemetry.*]
ignore_missing_imports = True
[mypy-ovh.*]
ignore_missing_imports = True
[mypy-ovirtsdk.*]
ignore_missing_imports = True
[mypy-packet.*]
ignore_missing_imports = True
[mypy-paho.*]
ignore_missing_imports = True
[mypy-pam.*]
ignore_missing_imports = True
[mypy-pdpyras.*]
ignore_missing_imports = True
[mypy-petname.*]
ignore_missing_imports = True
[mypy-pingdom.*]
ignore_missing_imports = True
[mypy-portage.*]
ignore_missing_imports = True
[mypy-potatoes_that_will_never_be_there.*]
ignore_missing_imports = True
[mypy-prettytable.*]
ignore_missing_imports = True
[mypy-pubnub_blocks_client.*]
ignore_missing_imports = True
[mypy-pushbullet.*]
ignore_missing_imports = True
[mypy-pycdlib.*]
ignore_missing_imports = True
[mypy-pyghmi.*]
ignore_missing_imports = True
[mypy-pylxca.*]
ignore_missing_imports = True
[mypy-pymssql.*]
ignore_missing_imports = True
[mypy-pyodbc.*]
ignore_missing_imports = True
[mypy-pyone.*]
ignore_missing_imports = True
[mypy-pypureomapi.*]
ignore_missing_imports = True
[mypy-pysnmp.*]
ignore_missing_imports = True
[mypy-pyxcli.*]
ignore_missing_imports = True
[mypy-rpm.*]
ignore_missing_imports = True
[mypy-salt.*]
ignore_missing_imports = True
[mypy-selinux.*]
ignore_missing_imports = True
[mypy-semantic_version.*]
ignore_missing_imports = True
[mypy-sendgrid.*]
ignore_missing_imports = True
[mypy-seobject.*]
ignore_missing_imports = True
[mypy-sha.*]
ignore_missing_imports = True
[mypy-SoftLayer.*]
ignore_missing_imports = True
[mypy-spotinst_sdk.*]
ignore_missing_imports = True
[mypy-statsd.*]
ignore_missing_imports = True
[mypy-storops.*]
ignore_missing_imports = True
[mypy-taiga.*]
ignore_missing_imports = True
[mypy-thycotic.*]
ignore_missing_imports = True
[mypy-univention.*]
ignore_missing_imports = True
[mypy-vexatapi.*]
ignore_missing_imports = True
[mypy-websocket.*]
ignore_missing_imports = True
[mypy-XenAPI.*]
ignore_missing_imports = True
[mypy-xkcdpass.*]
ignore_missing_imports = True
[mypy-xmljson.*]
ignore_missing_imports = True
[mypy-xmltodict.*]
ignore_missing_imports = True
[mypy-xmpp.*]
ignore_missing_imports = True

View file

@ -28,7 +28,20 @@ run_yamllint = true
yamllint_config = ".yamllint" yamllint_config = ".yamllint"
# yamllint_config_plugins = ".yamllint-docs" # yamllint_config_plugins = ".yamllint-docs"
# yamllint_config_plugins_examples = ".yamllint-examples" # yamllint_config_plugins_examples = ".yamllint-examples"
run_mypy = false run_mypy = true
mypy_ansible_core_package = "ansible-core>=2.19.0"
mypy_config = ".mypy.ini"
mypy_extra_deps = [
"cryptography",
"dnspython",
"lxml-stubs",
"types-mock",
"types-paramiko",
"types-passlib",
"types-psutil",
"types-PyYAML",
"types-requests",
]
[sessions.docs_check] [sessions.docs_check]
validate_collection_refs="all" validate_collection_refs="all"

View file

@ -485,4 +485,4 @@ class CallbackModule(CallbackModule_default):
# When using -vv or higher, simply do the default action # When using -vv or higher, simply do the default action
if display.verbosity >= 2 or not HAS_OD: if display.verbosity >= 2 or not HAS_OD:
CallbackModule = CallbackModule_default CallbackModule = CallbackModule_default # type: ignore

View file

@ -90,6 +90,7 @@ from ansible.errors import AnsibleError, AnsibleRuntimeError
from ansible.module_utils.ansible_release import __version__ as ansible_version from ansible.module_utils.ansible_release import __version__ as ansible_version
from ansible.plugins.callback import CallbackBase from ansible.plugins.callback import CallbackBase
ELASTIC_LIBRARY_IMPORT_ERROR: ImportError | None
try: try:
from elasticapm import Client, capture_span, trace_parent_from_string, instrument, label from elasticapm import Client, capture_span, trace_parent_from_string, instrument, label
except ImportError as imp_exc: except ImportError as imp_exc:

View file

@ -206,7 +206,7 @@ else:
sock.connect((self.LE_API, self.LE_TLS_PORT)) sock.connect((self.LE_API, self.LE_TLS_PORT))
self._conn = sock self._conn = sock
SocketAppender = TLSSocketAppender SocketAppender = TLSSocketAppender # type: ignore
class CallbackModule(CallbackBase): class CallbackModule(CallbackBase):

View file

@ -145,6 +145,7 @@ from ansible.errors import AnsibleError
from ansible.module_utils.ansible_release import __version__ as ansible_version from ansible.module_utils.ansible_release import __version__ as ansible_version
from ansible.plugins.callback import CallbackBase from ansible.plugins.callback import CallbackBase
OTEL_LIBRARY_IMPORT_ERROR: ImportError | None
try: try:
from opentelemetry import trace from opentelemetry import trace
from opentelemetry.trace import SpanKind from opentelemetry.trace import SpanKind

View file

@ -28,7 +28,7 @@ try:
from yaml import CSafeDumper as SafeDumper from yaml import CSafeDumper as SafeDumper
from yaml import CSafeLoader as SafeLoader from yaml import CSafeLoader as SafeLoader
except ImportError: except ImportError:
from yaml import SafeDumper, SafeLoader from yaml import SafeDumper, SafeLoader # type: ignore
from ansible.plugins.callback import CallbackBase from ansible.plugins.callback import CallbackBase

View file

@ -46,13 +46,13 @@ from ansible.module_utils.common.text.converters import to_text
DONT_COLORIZE = False DONT_COLORIZE = False
COLORS = { COLORS = {
'normal': '\033[0m', 'normal': '\033[0m',
'ok': f'\x1b[{C.COLOR_CODES[C.COLOR_OK]}m', 'ok': f'\x1b[{C.COLOR_CODES[C.COLOR_OK]}m', # type: ignore
'bold': '\033[1m', 'bold': '\033[1m',
'not_so_bold': '\033[1m\033[34m', 'not_so_bold': '\033[1m\033[34m',
'changed': f'\x1b[{C.COLOR_CODES[C.COLOR_CHANGED]}m', 'changed': f'\x1b[{C.COLOR_CODES[C.COLOR_CHANGED]}m', # type: ignore
'failed': f'\x1b[{C.COLOR_CODES[C.COLOR_ERROR]}m', 'failed': f'\x1b[{C.COLOR_CODES[C.COLOR_ERROR]}m', # type: ignore
'endc': '\033[0m', 'endc': '\033[0m',
'skipped': f'\x1b[{C.COLOR_CODES[C.COLOR_SKIP]}m', 'skipped': f'\x1b[{C.COLOR_CODES[C.COLOR_SKIP]}m', # type: ignore
} }

View file

@ -106,10 +106,10 @@ class Connection(ConnectionBase):
host=self._instance()) host=self._instance())
self._connected = True self._connected = True
def _build_command(self, cmd) -> str: def _build_command(self, cmd) -> list[str]:
"""build the command to execute on the incus host""" """build the command to execute on the incus host"""
exec_cmd = [ exec_cmd: list[str] = [
self._incus_cmd, self._incus_cmd,
"--project", self.get_option("project"), "--project", self.get_option("project"),
"exec", "exec",

View file

@ -108,10 +108,10 @@ class Connection(ConnectionBase):
self._display.vvv(f"ESTABLISH LXD CONNECTION FOR USER: {self.get_option('remote_user')}", host=self._host()) self._display.vvv(f"ESTABLISH LXD CONNECTION FOR USER: {self.get_option('remote_user')}", host=self._host())
self._connected = True self._connected = True
def _build_command(self, cmd) -> str: def _build_command(self, cmd) -> list[str]:
"""build the command to execute on the lxd host""" """build the command to execute on the lxd host"""
exec_cmd = [self._lxc_cmd] exec_cmd: list[str] = [self._lxc_cmd]
if self.get_option("project"): if self.get_option("project"):
exec_cmd.extend(["--project", self.get_option("project")]) exec_cmd.extend(["--project", self.get_option("project")])

View file

@ -106,7 +106,7 @@ class Connection(ConnectionBase):
super(Connection, self)._connect() super(Connection, self)._connect()
self._connected = True self._connected = True
@ensure_connect @ensure_connect # type: ignore # TODO: for some reason, the type infos for ensure_connect suck...
def exec_command(self, cmd, in_data=None, sudoable=False): def exec_command(self, cmd, in_data=None, sudoable=False):
"""Run specified command in a running QubesVM """ """Run specified command in a running QubesVM """
super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable) super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable)

View file

@ -332,31 +332,23 @@ from ansible.utils.path import makedirs_safe
from binascii import hexlify from binascii import hexlify
from subprocess import list2cmdline from subprocess import list2cmdline
PARAMIKO_IMPORT_ERR: str | None
try: try:
import paramiko import paramiko
from paramiko import MissingHostKeyPolicy
PARAMIKO_IMPORT_ERR = None PARAMIKO_IMPORT_ERR = None
except ImportError: except ImportError:
paramiko = None
PARAMIKO_IMPORT_ERR = traceback.format_exc() PARAMIKO_IMPORT_ERR = traceback.format_exc()
MissingHostKeyPolicy = object # type: ignore
if t.TYPE_CHECKING and PARAMIKO_IMPORT_ERR is None:
from paramiko import MissingHostKeyPolicy
from paramiko.client import SSHClient
from paramiko.pkey import PKey
else:
MissingHostKeyPolicy: type = object
SSHClient: type = object
PKey: type = object
display = Display() display = Display()
def authenticity_msg(hostname: str, ktype: str, fingerprint: str) -> str: def authenticity_msg(hostname: str, ktype: str, fingerprint: bytes) -> str:
msg = f""" msg = f"""
paramiko: The authenticity of host '{hostname}' can't be established. paramiko: The authenticity of host '{hostname}' can't be established.
The {ktype} key fingerprint is {fingerprint}. The {ktype} key fingerprint is {to_text(fingerprint)}.
Are you sure you want to continue connecting (yes/no)? Are you sure you want to continue connecting (yes/no)?
""" """
return msg return msg
@ -376,7 +368,7 @@ class MyAddPolicy(MissingHostKeyPolicy):
self.connection = connection self.connection = connection
self._options = connection._options self._options = connection._options
def missing_host_key(self, client: SSHClient, hostname: str, key: PKey) -> None: def missing_host_key(self, client: paramiko.SSHClient, hostname: str, key: paramiko.PKey) -> None:
if all((self.connection.get_option('host_key_checking'), not self.connection.get_option('host_key_auto_add'))): if all((self.connection.get_option('host_key_checking'), not self.connection.get_option('host_key_auto_add'))):
@ -396,10 +388,10 @@ class MyAddPolicy(MissingHostKeyPolicy):
if inp.lower() not in ['yes', 'y', '']: if inp.lower() not in ['yes', 'y', '']:
raise AnsibleError('host connection rejected by user') raise AnsibleError('host connection rejected by user')
key._added_by_ansible_this_time = True key._added_by_ansible_this_time = True # type: ignore
# existing implementation below: # existing implementation below:
client._host_keys.add(hostname, key.get_name(), key) client._host_keys.add(hostname, key.get_name(), key) # type: ignore[attr-defined] # TODO: figure out what _host_keys is!
# host keys are actually saved in close() function below # host keys are actually saved in close() function below
# in order to control ordering. # in order to control ordering.
@ -540,7 +532,7 @@ class Connection(ConnectionBase):
return self return self
def _any_keys_added(self) -> bool: def _any_keys_added(self) -> bool:
for hostname, keys in self.ssh._host_keys.items(): for hostname, keys in self.ssh._host_keys.items(): # type: ignore[attr-defined] # TODO: figure out what _host_keys is!
for keytype, key in keys.items(): for keytype, key in keys.items():
added_this_time = getattr(key, '_added_by_ansible_this_time', False) added_this_time = getattr(key, '_added_by_ansible_this_time', False)
if added_this_time: if added_this_time:
@ -560,14 +552,14 @@ class Connection(ConnectionBase):
makedirs_safe(path) makedirs_safe(path)
with open(filename, 'w') as f: with open(filename, 'w') as f:
for hostname, keys in self.ssh._host_keys.items(): for hostname, keys in self.ssh._host_keys.items(): # type: ignore[attr-defined] # TODO: figure out what _host_keys is!
for keytype, key in keys.items(): for keytype, key in keys.items():
# was f.write # was f.write
added_this_time = getattr(key, '_added_by_ansible_this_time', False) added_this_time = getattr(key, '_added_by_ansible_this_time', False)
if not added_this_time: if not added_this_time:
f.write(f'{hostname} {keytype} {key.get_base64()}\n') f.write(f'{hostname} {keytype} {key.get_base64()}\n')
for hostname, keys in self.ssh._host_keys.items(): for hostname, keys in self.ssh._host_keys.items(): # type: ignore[attr-defined] # TODO: figure out what _host_keys is!
for keytype, key in keys.items(): for keytype, key in keys.items():
added_this_time = getattr(key, '_added_by_ansible_this_time', False) added_this_time = getattr(key, '_added_by_ansible_this_time', False)
if added_this_time: if added_this_time:
@ -595,13 +587,16 @@ class Connection(ConnectionBase):
cmd = self._build_wsl_command(cmd) cmd = self._build_wsl_command(cmd)
super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable) super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable) # type: ignore[safe-super]
bufsize = 4096 bufsize = 4096
try: try:
self.ssh.get_transport().set_keepalive(5) transport = self.ssh.get_transport()
chan = self.ssh.get_transport().open_session() if transport is None:
raise ValueError("Transport not available")
transport.set_keepalive(5)
chan = transport.open_session()
except Exception as e: except Exception as e:
text_e = to_text(e) text_e = to_text(e)
msg = 'Failed to open session' msg = 'Failed to open session'
@ -745,7 +740,7 @@ class Connection(ConnectionBase):
# just in case any were added recently # just in case any were added recently
self.ssh.load_system_host_keys() self.ssh.load_system_host_keys()
self.ssh._host_keys.update(self.ssh._system_host_keys) self.ssh._host_keys.update(self.ssh._system_host_keys) # type: ignore[attr-defined] # TODO this is a HACK!
# gather information about the current key file, so # gather information about the current key file, so
# we can ensure the new file has the correct mode/owner # we can ensure the new file has the correct mode/owner

View file

@ -16,7 +16,7 @@ from ansible.module_utils.common.collections import is_sequence
try: try:
from ansible.errors import AnsibleTypeError from ansible.errors import AnsibleTypeError
except ImportError: except ImportError:
from ansible.errors import AnsibleFilterTypeError as AnsibleTypeError from ansible.errors import AnsibleFilterTypeError as AnsibleTypeError # type: ignore
try: try:
from hashids import Hashids from hashids import Hashids

View file

@ -3,17 +3,18 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
from __future__ import annotations from __future__ import annotations
import typing as t
from json import loads from json import loads
from typing import TYPE_CHECKING
from ansible.errors import AnsibleFilterError from ansible.errors import AnsibleFilterError
if TYPE_CHECKING: if t.TYPE_CHECKING:
from typing import Any, Callable, Union from typing import Any, Callable, Union
JSONPATCH_IMPORT_ERROR: ImportError | None
try: try:
import jsonpatch import jsonpatch
except ImportError as exc: except ImportError as exc:
HAS_LIB = False HAS_LIB = False
JSONPATCH_IMPORT_ERROR = exc JSONPATCH_IMPORT_ERROR = exc
@ -82,7 +83,7 @@ class FilterModule:
"You need to install 'jsonpatch' package prior to running 'json_patch' filter" "You need to install 'jsonpatch' package prior to running 'json_patch' filter"
) from JSONPATCH_IMPORT_ERROR ) from JSONPATCH_IMPORT_ERROR
args = {"op": op, "path": path} args: dict[str, t.Any] = {"op": op, "path": path}
from_arg = kwargs.pop("from", None) from_arg = kwargs.pop("from", None)
fail_test = kwargs.pop("fail_test", False) fail_test = kwargs.pop("fail_test", False)

View file

@ -11,15 +11,16 @@ from yaml import dump
try: try:
from yaml.cyaml import CSafeDumper as SafeDumper from yaml.cyaml import CSafeDumper as SafeDumper
except ImportError: except ImportError:
from yaml import SafeDumper from yaml import SafeDumper # type: ignore
from ansible.module_utils.common.collections import is_sequence from ansible.module_utils.common.collections import is_sequence
try: try:
# This is ansible-core 2.19+ # This is ansible-core 2.19+
from ansible.utils.vars import transform_to_native_types from ansible.utils.vars import transform_to_native_types
from ansible.parsing.vault import VaultHelper, VaultLib from ansible.parsing.vault import VaultHelper, VaultLib
HAS_TRANSFORM_TO_NATIVE_TYPES = True
except ImportError: except ImportError:
transform_to_native_types = None HAS_TRANSFORM_TO_NATIVE_TYPES = False
from ansible.parsing.yaml.objects import AnsibleVaultEncryptedUnicode from ansible.parsing.yaml.objects import AnsibleVaultEncryptedUnicode
from ansible.utils.unsafe_proxy import AnsibleUnsafe from ansible.utils.unsafe_proxy import AnsibleUnsafe
@ -31,7 +32,7 @@ def _to_native_types_compat(value: t.Any, *, redact_value: str | None) -> t.Any:
return value return value
if isinstance(value, AnsibleUnsafe): if isinstance(value, AnsibleUnsafe):
# This only works up to ansible-core 2.18: # This only works up to ansible-core 2.18:
return _to_native_types_compat(value._strip_unsafe(), redact_value=redact_value) return _to_native_types_compat(value._strip_unsafe(), redact_value=redact_value) # type: ignore
# But that's fine, since this code path isn't taken on ansible-core 2.19+ anyway. # But that's fine, since this code path isn't taken on ansible-core 2.19+ anyway.
if isinstance(value, Mapping): if isinstance(value, Mapping):
return { return {
@ -74,10 +75,10 @@ def remove_all_tags(value: t.Any, *, redact_sensitive_values: bool = False) -> t
If ``redact_sensitive_values`` is ``True``, all sensitive values will be redacted. If ``redact_sensitive_values`` is ``True``, all sensitive values will be redacted.
""" """
if transform_to_native_types is not None: if HAS_TRANSFORM_TO_NATIVE_TYPES:
return _to_native_types(value, redact=redact_sensitive_values) return _to_native_types(value, redact=redact_sensitive_values)
return _to_native_types_compat( return _to_native_types_compat( # type: ignore[unreachable]
value, 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()
) )

View file

@ -52,7 +52,7 @@ from ansible.errors import AnsibleFilterError
try: try:
from ansible.errors import AnsibleTypeError from ansible.errors import AnsibleTypeError
except ImportError: except ImportError:
from ansible.errors import AnsibleFilterTypeError as AnsibleTypeError from ansible.errors import AnsibleFilterTypeError as AnsibleTypeError # type: ignore
def unicode_normalize(data, form='NFC'): def unicode_normalize(data, form='NFC'):

View file

@ -179,6 +179,7 @@ from ansible.errors import AnsibleError, AnsibleParserError
from ansible_collections.community.general.plugins.module_utils.lxd import LXDClient, LXDClientException from ansible_collections.community.general.plugins.module_utils.lxd import LXDClient, LXDClientException
from ansible_collections.community.general.plugins.plugin_utils.unsafe import make_unsafe from ansible_collections.community.general.plugins.plugin_utils.unsafe import make_unsafe
IPADDRESS_IMPORT_ERROR: ImportError | None
try: try:
import ipaddress import ipaddress
except ImportError as exc: except ImportError as exc:

View file

@ -118,6 +118,7 @@ variables:
import os import os
import json import json
YAML_IMPORT_ERROR: ImportError | None
try: try:
import yaml import yaml
except ImportError as exc: except ImportError as exc:

View file

@ -244,7 +244,7 @@ class Bitwarden(object):
out, err = self._run(params) out, err = self._run(params)
# This includes things that matched in different fields. # This includes things that matched in different fields.
initial_matches = AnsibleJSONDecoder().raw_decode(out)[0] initial_matches = AnsibleJSONDecoder().raw_decode(out)[0] # type: ignore[operator]
# Filter to only return the ID of a collections with exactly matching name # Filter to only return the ID of a collections with exactly matching name
return [item['id'] for item in initial_matches return [item['id'] for item in initial_matches

View file

@ -82,7 +82,7 @@ except ImportError:
HAS_PYTHON_JWT = False # vs pyjwt HAS_PYTHON_JWT = False # vs pyjwt
if HAS_JWT and hasattr(jwt, 'JWT'): if HAS_JWT and hasattr(jwt, 'JWT'):
HAS_PYTHON_JWT = True HAS_PYTHON_JWT = True
from jwt import jwk_from_pem, JWT from jwt import jwk_from_pem, JWT # type: ignore[attr-defined]
jwt_instance = JWT() jwt_instance = JWT()
try: try:

View file

@ -65,6 +65,7 @@ from ansible.plugins.lookup import LookupBase
from ansible.utils.display import Display from ansible.utils.display import Display
from ansible.errors import AnsibleError from ansible.errors import AnsibleError
ANOTHER_LIBRARY_IMPORT_ERROR: ImportError | None
try: try:
from pam.revbits_ansible.server import SecretServer from pam.revbits_ansible.server import SecretServer
except ImportError as imp_exc: except ImportError as imp_exc:

View file

@ -11,10 +11,11 @@ import traceback
from operator import itemgetter from operator import itemgetter
PARAMIKO_IMPORT_ERROR: str | None
try: try:
from paramiko.config import SSHConfig from paramiko.config import SSHConfig
except ImportError: except ImportError:
SSHConfig = object SSHConfig = object # type: ignore
HAS_PARAMIKO = False HAS_PARAMIKO = False
PARAMIKO_IMPORT_ERROR = traceback.format_exc() PARAMIKO_IMPORT_ERROR = traceback.format_exc()
else: else:

View file

@ -4,10 +4,17 @@
from __future__ import annotations from __future__ import annotations
import typing as t
from functools import wraps from functools import wraps
from ansible.module_utils.common.collections import is_sequence from ansible.module_utils.common.collections import is_sequence
if t.TYPE_CHECKING:
from collections.abc import Callable
ArgFormatType = Callable[[t.Any], list[str]]
def _ensure_list(value): def _ensure_list(value):
return list(value) if is_sequence(value) else [value] return list(value) if is_sequence(value) else [value]

View file

@ -9,6 +9,7 @@ from __future__ import annotations
import copy import copy
import json import json
import re import re
import typing as t
from urllib import error as urllib_error from urllib import error as urllib_error
from urllib.parse import urlencode from urllib.parse import urlencode
@ -118,12 +119,12 @@ class _ConsulModule:
As such backwards incompatible changes can occur even in bugfix releases. As such backwards incompatible changes can occur even in bugfix releases.
""" """
api_endpoint = None # type: str api_endpoint: str | None = None
unique_identifiers = None # type: list unique_identifiers: list | None = None
result_key = None # type: str result_key: str | None = None
create_only_fields = set() create_only_fields: set[str] = set()
operational_attributes = set() operational_attributes: set[str] = set()
params = {} params: dict[str, t.Any] = {}
def __init__(self, module): def __init__(self, module):
self._module = module self._module = module

View file

@ -4,12 +4,16 @@
from __future__ import annotations from __future__ import annotations
import typing as t
from ansible.module_utils.common.dict_transformations import dict_merge from ansible.module_utils.common.dict_transformations import dict_merge
from ansible_collections.community.general.plugins.module_utils import cmd_runner_fmt from ansible_collections.community.general.plugins.module_utils import cmd_runner_fmt
from ansible_collections.community.general.plugins.module_utils.python_runner import PythonRunner from ansible_collections.community.general.plugins.module_utils.python_runner import PythonRunner
from ansible_collections.community.general.plugins.module_utils.module_helper import ModuleHelper from ansible_collections.community.general.plugins.module_utils.module_helper import ModuleHelper
if t.TYPE_CHECKING:
from .cmd_runner_fmt import ArgFormatType
django_std_args = dict( django_std_args = dict(
# environmental options # environmental options
@ -32,7 +36,7 @@ _pks = dict(
primary_keys=dict(type="list", elements="str"), primary_keys=dict(type="list", elements="str"),
) )
_django_std_arg_fmts = dict( _django_std_arg_fmts: dict[str, ArgFormatType] = dict(
all=cmd_runner_fmt.as_bool("--all"), all=cmd_runner_fmt.as_bool("--all"),
app=cmd_runner_fmt.as_opt_val("--app"), app=cmd_runner_fmt.as_opt_val("--app"),
apps=cmd_runner_fmt.as_list(), apps=cmd_runner_fmt.as_list(),
@ -95,11 +99,11 @@ class _DjangoRunner(PythonRunner):
class DjangoModuleHelper(ModuleHelper): class DjangoModuleHelper(ModuleHelper):
module = {} module = {}
django_admin_cmd = None django_admin_cmd: str | None = None
arg_formats = {} arg_formats: dict[str, ArgFormatType] = {}
django_admin_arg_order = () django_admin_arg_order: tuple[str, ...] | str = ()
_django_args = [] _django_args: list[str] = []
_check_mode_arg = "" _check_mode_arg: str = ""
def __init__(self): def __init__(self):
self.module["argument_spec"], self.arg_formats = self._build_args(self.module.get("argument_spec", {}), self.module["argument_spec"], self.arg_formats = self._build_args(self.module.get("argument_spec", {}),

View file

@ -6,6 +6,8 @@
from __future__ import annotations from __future__ import annotations
import typing as t
from ansible.module_utils.basic import missing_required_lib from ansible.module_utils.basic import missing_required_lib
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
@ -15,7 +17,7 @@ from urllib.parse import urljoin
import traceback import traceback
def _determine_list_all_kwargs(version): def _determine_list_all_kwargs(version) -> dict[str, t.Any]:
gitlab_version = LooseVersion(version) gitlab_version = LooseVersion(version)
if gitlab_version >= LooseVersion('4.0.0'): if gitlab_version >= LooseVersion('4.0.0'):
# 4.0.0 removed 'as_list' # 4.0.0 removed 'as_list'
@ -27,14 +29,14 @@ def _determine_list_all_kwargs(version):
return {'as_list': False, 'all': True, 'per_page': 100} return {'as_list': False, 'all': True, 'per_page': 100}
GITLAB_IMP_ERR = None GITLAB_IMP_ERR: str | None = None
try: try:
import gitlab import gitlab
import requests import requests
HAS_GITLAB_PACKAGE = True HAS_GITLAB_PACKAGE = True
list_all_kwargs = _determine_list_all_kwargs(gitlab.__version__) list_all_kwargs = _determine_list_all_kwargs(gitlab.__version__)
except Exception: except Exception:
gitlab = None gitlab = None # type: ignore
GITLAB_IMP_ERR = traceback.format_exc() GITLAB_IMP_ERR = traceback.format_exc()
HAS_GITLAB_PACKAGE = False HAS_GITLAB_PACKAGE = False
list_all_kwargs = {} list_all_kwargs = {}

View file

@ -20,7 +20,7 @@ from urllib.parse import urlparse
try: try:
from hashlib import sha1 from hashlib import sha1
except ImportError: except ImportError:
import sha as sha1 import sha as sha1 # type: ignore[no-redef]
HASHED_KEY_MAGIC = "|1|" HASHED_KEY_MAGIC = "|1|"

View file

@ -5,15 +5,17 @@
from __future__ import annotations from __future__ import annotations
import typing as t
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils.mh.exceptions import ModuleHelperException as _MHE from ansible_collections.community.general.plugins.module_utils.mh.exceptions import ModuleHelperException as _MHE
from ansible_collections.community.general.plugins.module_utils.mh.deco import module_fails_on_exception from ansible_collections.community.general.plugins.module_utils.mh.deco import module_fails_on_exception
class ModuleHelperBase(object): class ModuleHelperBase(object):
module = None module: dict[str, t.Any] | None = None # TODO: better spec using t.TypedDict
ModuleHelperException = _MHE ModuleHelperException = _MHE
_delegated_to_module = ( _delegated_to_module: tuple[str, ...] = (
'check_mode', 'get_bin_path', 'warn', 'deprecate', 'debug', 'check_mode', 'get_bin_path', 'warn', 'deprecate', 'debug',
) )

View file

@ -5,13 +5,15 @@
from __future__ import annotations from __future__ import annotations
import typing as t
from ansible.module_utils.common.text.converters import to_native from ansible.module_utils.common.text.converters import to_native
class ModuleHelperException(Exception): class ModuleHelperException(Exception):
def __init__(self, msg, update_output=None, *args, **kwargs): def __init__(self, msg: str, update_output: dict[str, t.Any] | None = None, *args, **kwargs):
self.msg = to_native(msg or f"Module failed with exception: {self}") self.msg: str = to_native(msg or f"Module failed with exception: {self}")
if update_output is None: if update_output is None:
update_output = {} update_output = {}
self.update_output = update_output self.update_output: dict[str, t.Any] = update_output
super(ModuleHelperException, self).__init__(*args) super(ModuleHelperException, self).__init__(*args)

View file

@ -7,8 +7,8 @@ from __future__ import annotations
class StateMixin(object): class StateMixin(object):
state_param = 'state' state_param: str = 'state'
default_state = None default_state: str | None = None
def _state(self): def _state(self):
state = self.module.params.get(self.state_param) state = self.module.params.get(self.state_param)

View file

@ -5,6 +5,7 @@
from __future__ import annotations from __future__ import annotations
import typing as t
from ansible.module_utils.common.dict_transformations import dict_merge from ansible.module_utils.common.dict_transformations import dict_merge
@ -13,13 +14,16 @@ from ansible_collections.community.general.plugins.module_utils.mh.base import M
from ansible_collections.community.general.plugins.module_utils.mh.mixins.state import StateMixin from ansible_collections.community.general.plugins.module_utils.mh.mixins.state import StateMixin
from ansible_collections.community.general.plugins.module_utils.mh.mixins.deprecate_attrs import DeprecateAttrsMixin from ansible_collections.community.general.plugins.module_utils.mh.mixins.deprecate_attrs import DeprecateAttrsMixin
if t.TYPE_CHECKING:
from collections.abc import Sequence
class ModuleHelper(DeprecateAttrsMixin, ModuleHelperBase): class ModuleHelper(DeprecateAttrsMixin, ModuleHelperBase):
facts_name = None facts_name: str | None = None
output_params = () output_params: Sequence[str] = ()
diff_params = () diff_params: Sequence[str] = ()
change_params = () change_params: Sequence[str] = ()
facts_params = () facts_params: Sequence[str] = ()
def __init__(self, module=None): def __init__(self, module=None):
super(ModuleHelper, self).__init__(module) super(ModuleHelper, self).__init__(module)

View file

@ -19,12 +19,11 @@ from ansible_collections.community.general.plugins.module_utils.datetime import
now, now,
) )
SCALEWAY_SECRET_IMP_ERR = None SCALEWAY_SECRET_IMP_ERR: str | None = None
try: try:
from passlib.hash import argon2 from passlib.hash import argon2
HAS_SCALEWAY_SECRET_PACKAGE = True HAS_SCALEWAY_SECRET_PACKAGE = True
except Exception: except Exception:
argon2 = None
SCALEWAY_SECRET_IMP_ERR = traceback.format_exc() SCALEWAY_SECRET_IMP_ERR = traceback.format_exc()
HAS_SCALEWAY_SECRET_PACKAGE = False HAS_SCALEWAY_SECRET_PACKAGE = False

View file

@ -53,7 +53,7 @@ __all__ = [
] ]
_singletons = {} _singletons: dict[str, object] = {}
def ldap_module(): def ldap_module():
@ -61,7 +61,7 @@ def ldap_module():
return orig_ldap return orig_ldap
def _singleton(name, constructor): def _singleton(name: str, constructor):
if name in _singletons: if name in _singletons:
return _singletons[name] return _singletons[name]
_singletons[name] = constructor() _singletons[name] = constructor()

View file

@ -129,6 +129,7 @@ from ansible.module_utils.basic import (
) )
from ansible.module_utils.common.text.converters import to_native from ansible.module_utils.common.text.converters import to_native
RPM_PYTHON_IMPORT_ERROR: str | None
try: try:
import rpm import rpm
except ImportError: except ImportError:

View file

@ -114,14 +114,7 @@ EXAMPLES = r"""
msg: Task completed ... with feeling. msg: Task completed ... with feeling.
""" """
try: from html import escape as html_escape
from html import escape as html_escape
except ImportError:
# Python-3.2 or later
import cgi
def html_escape(text, quote=True):
return cgi.escape(text, quote)
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.urls import fetch_url from ansible.module_utils.urls import fetch_url

View file

@ -166,10 +166,11 @@ def main():
class Crypttab(object): class Crypttab(object):
_lines = [] _lines: list[str]
def __init__(self, path): def __init__(self, path):
self.path = path self.path = path
self._lines = []
if not os.path.exists(path): if not os.path.exists(path):
if not os.path.exists(os.path.dirname(path)): if not os.path.exists(os.path.dirname(path)):
os.makedirs(os.path.dirname(path)) os.makedirs(os.path.dirname(path))

View file

@ -201,16 +201,16 @@ class Device(object):
class Filesystem(object): class Filesystem(object):
MKFS = None MKFS: str | None = None
MKFS_FORCE_FLAGS = [] MKFS_FORCE_FLAGS: list[str] | None = []
MKFS_SET_UUID_OPTIONS = None MKFS_SET_UUID_OPTIONS: list[str] | None = None
MKFS_SET_UUID_EXTRA_OPTIONS = [] MKFS_SET_UUID_EXTRA_OPTIONS: list[str] | None = []
INFO = None INFO: str | None = None
GROW = None GROW: str | None = None
GROW_MAX_SPACE_FLAGS = [] GROW_MAX_SPACE_FLAGS: list[str] | None = []
GROW_MOUNTPOINT_ONLY = False GROW_MOUNTPOINT_ONLY = False
CHANGE_UUID = None CHANGE_UUID: str | None = None
CHANGE_UUID_OPTION = None CHANGE_UUID_OPTION: str | None = None
CHANGE_UUID_OPTION_HAS_ARG = True CHANGE_UUID_OPTION_HAS_ARG = True
LANG_ENV = {'LANG': 'C', 'LC_ALL': 'C', 'LC_MESSAGES': 'C'} LANG_ENV = {'LANG': 'C', 'LC_ALL': 'C', 'LC_MESSAGES': 'C'}

View file

@ -273,6 +273,7 @@ from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.basic import jsonify from ansible.module_utils.basic import jsonify
from ansible.module_utils.common.text.formatters import human_to_bytes from ansible.module_utils.common.text.formatters import human_to_bytes
CRYPT_IMPORT_ERROR: str | None
try: try:
import crypt import crypt
except ImportError: except ImportError:
@ -282,6 +283,7 @@ else:
HAS_CRYPT = True HAS_CRYPT = True
CRYPT_IMPORT_ERROR = None CRYPT_IMPORT_ERROR = None
LEGACYCRYPT_IMPORT_ERROR: str | None
try: try:
import legacycrypt import legacycrypt
if not HAS_CRYPT: if not HAS_CRYPT:

View file

@ -112,7 +112,9 @@ from ansible.module_utils.common.text.converters import to_native
with deps.declare("passlib"): with deps.declare("passlib"):
from passlib.apache import HtpasswdFile, htpasswd_context # Apparently the type infos don't know htpasswd_context, which *does* exist
# (but isn't mentioned in the documentation for some reason)
from passlib.apache import HtpasswdFile, htpasswd_context # type: ignore[attr-defined]
from passlib.context import CryptContext from passlib.context import CryptContext

View file

@ -164,7 +164,7 @@ IS_PYTHON_2 = sys.version_info[0] <= 2
class JenkinsNode: class JenkinsNode:
def __init__(self, module): def __init__(self, module: AnsibleModule) -> None:
self.module = module self.module = module
self.name = module.params['name'] self.name = module.params['name']
@ -174,7 +174,7 @@ class JenkinsNode:
self.url = module.params['url'] self.url = module.params['url']
self.num_executors = module.params['num_executors'] self.num_executors = module.params['num_executors']
self.labels = module.params['labels'] self.labels = module.params['labels']
self.offline_message = module.params['offline_message'] # type: str | None self.offline_message: str | None = module.params['offline_message']
if self.offline_message is not None: if self.offline_message is not None:
self.offline_message = self.offline_message.strip() self.offline_message = self.offline_message.strip()

View file

@ -74,7 +74,7 @@ class PacemakerInfo(ModuleHelper):
"constraint_info": "constraint", "constraint_info": "constraint",
"property_info": "property" "property_info": "property"
} }
output_params = info_vars.keys() output_params = list(info_vars.keys())
def __init_module__(self): def __init_module__(self):
self.runner = pacemaker_runner(self.module) self.runner = pacemaker_runner(self.module)

View file

@ -209,6 +209,7 @@ import re
import traceback import traceback
from ansible.module_utils.basic import AnsibleModule, missing_required_lib, human_to_bytes from ansible.module_utils.basic import AnsibleModule, missing_required_lib, human_to_bytes
XMLTODICT_LIBRARY_IMPORT_ERROR: str | None
try: try:
import xmltodict import xmltodict
except ImportError: except ImportError:

View file

@ -347,7 +347,7 @@ RHEV_UNAVAILABLE = 2
RHEV_TYPE_OPTS = ['desktop', 'host', 'server'] RHEV_TYPE_OPTS = ['desktop', 'host', 'server']
STATE_OPTS = ['absent', 'cd', 'down', 'info', 'ping', 'present', 'restart', 'up'] STATE_OPTS = ['absent', 'cd', 'down', 'info', 'ping', 'present', 'restart', 'up']
msg = [] msg: list[str] = []
changed = False changed = False
failed = False failed = False
@ -1258,7 +1258,7 @@ def setChanged():
changed = True changed = True
def setMsg(message): def setMsg(message: str) -> None:
msg.append(message) msg.append(message)

View file

@ -328,6 +328,7 @@ from ansible_collections.community.general.plugins.module_utils.univention_umc i
base_dn, base_dn,
) )
CRYPT_IMPORT_ERROR: str | None
try: try:
import crypt import crypt
except ImportError: except ImportError:
@ -337,6 +338,7 @@ else:
HAS_CRYPT = True HAS_CRYPT = True
CRYPT_IMPORT_ERROR = None CRYPT_IMPORT_ERROR = None
LEGACYCRYPT_IMPORT_ERROR: str | None
try: try:
import legacycrypt import legacycrypt
if not HAS_CRYPT: if not HAS_CRYPT:

View file

@ -10,8 +10,9 @@ from collections.abc import Mapping
try: try:
# Introduced with Data Tagging (https://github.com/ansible/ansible/pull/84621): # Introduced with Data Tagging (https://github.com/ansible/ansible/pull/84621):
from ansible.module_utils.datatag import native_type_name as _native_type_name from ansible.module_utils.datatag import native_type_name as _native_type_name
HAS_NATIVE_TYPE_NAME = True
except ImportError: except ImportError:
_native_type_name = None HAS_NATIVE_TYPE_NAME = False
def _atype(data, alias, *, use_native_type: bool = False): def _atype(data, alias, *, use_native_type: bool = False):
@ -19,7 +20,7 @@ def _atype(data, alias, *, use_native_type: bool = False):
Returns the name of the type class. Returns the name of the type class.
""" """
if use_native_type and _native_type_name: if use_native_type and HAS_NATIVE_TYPE_NAME:
data_type = _native_type_name(data) data_type = _native_type_name(data)
else: else:
data_type = type(data).__name__ data_type = type(data).__name__

View file

@ -43,7 +43,7 @@ from ansible.plugins.loader import action_loader, module_loader
try: try:
from ansible.errors import AnsiblePluginRemovedError from ansible.errors import AnsiblePluginRemovedError
except ImportError: except ImportError:
AnsiblePluginRemovedError = Exception AnsiblePluginRemovedError = Exception # type: ignore
def a_module(term): def a_module(term):

View file

@ -65,6 +65,7 @@ _value:
from ansible.errors import AnsibleError from ansible.errors import AnsibleError
ANOTHER_LIBRARY_IMPORT_ERROR: ImportError | None
try: try:
from fqdn import FQDN from fqdn import FQDN
except ImportError as imp_exc: except ImportError as imp_exc:

View file

@ -19,7 +19,7 @@ def test_redis_cachemodule():
assert isinstance(cache_loader.get('community.general.redis', **{'_uri': connection}), RedisCache) assert isinstance(cache_loader.get('community.general.redis', **{'_uri': connection}), RedisCache)
def test_redis_cachemodule(): def test_redis_cachemodule_2():
# The _uri option is required for the redis plugin # The _uri option is required for the redis plugin
connection = '[::1]:6379:1' connection = '[::1]:6379:1'
assert isinstance(cache_loader.get('community.general.redis', **{'_uri': connection}), RedisCache) assert isinstance(cache_loader.get('community.general.redis', **{'_uri': connection}), RedisCache)

View file

@ -36,7 +36,7 @@ class SecretVariablesTestCase(unittest.TestCase):
self.assertEqual(SecretVariables.list_to_dict(source, hashed=True), expect) self.assertEqual(SecretVariables.list_to_dict(source, hashed=True), expect)
def test_list_to_dict(self): def test_list_to_dict_2(self):
source = [ source = [
dict(key="secret1", value="value1"), dict(key="secret1", value="value1"),
dict(key="secret2", value="value2") dict(key="secret2", value="value2")

View file

@ -5,6 +5,8 @@
from __future__ import annotations from __future__ import annotations
import typing as t
import pytest import pytest
from ansible_collections.community.general.plugins.module_utils import csv from ansible_collections.community.general.plugins.module_utils import csv
@ -112,7 +114,7 @@ INVALID_CSV = [
), ),
] ]
INVALID_DIALECT = [ INVALID_DIALECT: list[tuple[str, t.Any, t.Any, str]] = [
( (
'invalid', 'invalid',
{}, {},
@ -153,7 +155,7 @@ def test_invalid_csv(data, dialect, dialect_params, fieldnames):
@pytest.mark.parametrize("dialect,dialect_params,fieldnames,data", INVALID_DIALECT) @pytest.mark.parametrize("dialect,dialect_params,fieldnames,data", INVALID_DIALECT)
def test_invalid_dialect(data, dialect, dialect_params, fieldnames): def test_invalid_dialect(data: str, dialect: t.Any, dialect_params: t.Any, fieldnames: str) -> None:
result = False result = False
try: try:

View file

@ -25,7 +25,7 @@ testcase_gather_vm_params_and_facts = {
} }
@pytest.mark.parametrize('vm_ref', testcase_bad_xenapi_refs['params'], ids=testcase_bad_xenapi_refs['ids']) @pytest.mark.parametrize('vm_ref', testcase_bad_xenapi_refs['params'], ids=testcase_bad_xenapi_refs['ids']) # type: ignore
def test_gather_vm_params_bad_vm_ref(fake_ansible_module, xenserver, vm_ref): def test_gather_vm_params_bad_vm_ref(fake_ansible_module, xenserver, vm_ref):
"""Tests return of empty dict on bad vm_ref.""" """Tests return of empty dict on bad vm_ref."""
assert xenserver.gather_vm_params(fake_ansible_module, vm_ref) == {} assert xenserver.gather_vm_params(fake_ansible_module, vm_ref) == {}
@ -38,8 +38,8 @@ def test_gather_vm_facts_no_vm_params(fake_ansible_module, xenserver):
@pytest.mark.parametrize('fixture_data_from_file', @pytest.mark.parametrize('fixture_data_from_file',
testcase_gather_vm_params_and_facts['params'], testcase_gather_vm_params_and_facts['params'], # type: ignore
ids=testcase_gather_vm_params_and_facts['ids'], ids=testcase_gather_vm_params_and_facts['ids'], # type: ignore
indirect=True) indirect=True)
def test_gather_vm_params_and_facts(mocker, fake_ansible_module, XenAPI, xenserver, fixture_data_from_file): def test_gather_vm_params_and_facts(mocker, fake_ansible_module, XenAPI, xenserver, fixture_data_from_file):
"""Tests proper parsing of VM parameters and facts.""" """Tests proper parsing of VM parameters and facts."""

View file

@ -157,13 +157,13 @@ def test_is_valid_ip_prefix(xenserver, ip_prefix, result):
assert xenserver.is_valid_ip_prefix(ip_prefix) is result assert xenserver.is_valid_ip_prefix(ip_prefix) is result
@pytest.mark.parametrize('ip_prefix, ip_netmask', testcase_ip_prefix_to_netmask['params'], ids=testcase_ip_prefix_to_netmask['ids']) @pytest.mark.parametrize('ip_prefix, ip_netmask', testcase_ip_prefix_to_netmask['params'], ids=testcase_ip_prefix_to_netmask['ids']) # type: ignore
def test_ip_prefix_to_netmask(xenserver, ip_prefix, ip_netmask): def test_ip_prefix_to_netmask(xenserver, ip_prefix, ip_netmask):
"""Tests ip prefix to netmask conversion.""" """Tests ip prefix to netmask conversion."""
assert xenserver.ip_prefix_to_netmask(ip_prefix) == ip_netmask assert xenserver.ip_prefix_to_netmask(ip_prefix) == ip_netmask
@pytest.mark.parametrize('ip_netmask, ip_prefix', testcase_ip_netmask_to_prefix['params'], ids=testcase_ip_netmask_to_prefix['ids']) @pytest.mark.parametrize('ip_netmask, ip_prefix', testcase_ip_netmask_to_prefix['params'], ids=testcase_ip_netmask_to_prefix['ids']) # type: ignore
def test_ip_netmask_to_prefix(xenserver, ip_netmask, ip_prefix): def test_ip_netmask_to_prefix(xenserver, ip_netmask, ip_prefix):
"""Tests ip netmask to prefix conversion.""" """Tests ip netmask to prefix conversion."""
assert xenserver.ip_netmask_to_prefix(ip_netmask) == ip_prefix assert xenserver.ip_netmask_to_prefix(ip_netmask) == ip_prefix

View file

@ -184,7 +184,7 @@ testcase_set_vm_power_state_transitions_async = {
} }
@pytest.mark.parametrize('vm_ref', testcase_bad_xenapi_refs['params'], ids=testcase_bad_xenapi_refs['ids']) @pytest.mark.parametrize('vm_ref', testcase_bad_xenapi_refs['params'], ids=testcase_bad_xenapi_refs['ids']) # type: ignore
def test_set_vm_power_state_bad_vm_ref(fake_ansible_module, xenserver, vm_ref): def test_set_vm_power_state_bad_vm_ref(fake_ansible_module, xenserver, vm_ref):
"""Tests failure on bad vm_ref.""" """Tests failure on bad vm_ref."""
with pytest.raises(FailJsonException) as exc_info: with pytest.raises(FailJsonException) as exc_info:
@ -222,8 +222,8 @@ def test_set_vm_power_state_bad_power_state(mocker, fake_ansible_module, XenAPI,
@pytest.mark.parametrize('power_state_desired, power_state_current, error_msg', @pytest.mark.parametrize('power_state_desired, power_state_current, error_msg',
testcase_set_vm_power_state_bad_transitions['params'], testcase_set_vm_power_state_bad_transitions['params'], # type: ignore
ids=testcase_set_vm_power_state_bad_transitions['ids']) ids=testcase_set_vm_power_state_bad_transitions['ids']) # type: ignore
def test_set_vm_power_state_bad_transition(mocker, fake_ansible_module, XenAPI, xenserver, power_state_desired, power_state_current, error_msg): def test_set_vm_power_state_bad_transition(mocker, fake_ansible_module, XenAPI, xenserver, power_state_desired, power_state_current, error_msg):
"""Tests failure on bad power state transition.""" """Tests failure on bad power state transition."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True) mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
@ -245,8 +245,8 @@ def test_set_vm_power_state_bad_transition(mocker, fake_ansible_module, XenAPI,
@pytest.mark.parametrize('power_state, error_msg', @pytest.mark.parametrize('power_state, error_msg',
testcase_set_vm_power_state_task_timeout['params'], testcase_set_vm_power_state_task_timeout['params'], # type: ignore
ids=testcase_set_vm_power_state_task_timeout['ids']) ids=testcase_set_vm_power_state_task_timeout['ids']) # type: ignore
def test_set_vm_power_state_task_timeout(mocker, fake_ansible_module, XenAPI, xenserver, power_state, error_msg): def test_set_vm_power_state_task_timeout(mocker, fake_ansible_module, XenAPI, xenserver, power_state, error_msg):
"""Tests failure on async task timeout.""" """Tests failure on async task timeout."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True) mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
@ -272,8 +272,8 @@ def test_set_vm_power_state_task_timeout(mocker, fake_ansible_module, XenAPI, xe
@pytest.mark.parametrize('power_state_desired, power_state_current', @pytest.mark.parametrize('power_state_desired, power_state_current',
testcase_set_vm_power_state_no_transitions['params'], testcase_set_vm_power_state_no_transitions['params'], # type: ignore
ids=testcase_set_vm_power_state_no_transitions['ids']) ids=testcase_set_vm_power_state_no_transitions['ids']) # type: ignore
def test_set_vm_power_state_no_transition(mocker, fake_ansible_module, XenAPI, xenserver, power_state_desired, power_state_current): def test_set_vm_power_state_no_transition(mocker, fake_ansible_module, XenAPI, xenserver, power_state_desired, power_state_current):
"""Tests regular invocation without power state transition.""" """Tests regular invocation without power state transition."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True) mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
@ -295,8 +295,8 @@ def test_set_vm_power_state_no_transition(mocker, fake_ansible_module, XenAPI, x
@pytest.mark.parametrize('power_state_desired, power_state_current, power_state_resulting, activated_xenapi_method', @pytest.mark.parametrize('power_state_desired, power_state_current, power_state_resulting, activated_xenapi_method',
testcase_set_vm_power_state_transitions['params'], testcase_set_vm_power_state_transitions['params'], # type: ignore
ids=testcase_set_vm_power_state_transitions['ids']) ids=testcase_set_vm_power_state_transitions['ids']) # type: ignore
def test_set_vm_power_state_transition(mocker, def test_set_vm_power_state_transition(mocker,
fake_ansible_module, fake_ansible_module,
XenAPI, XenAPI,
@ -332,8 +332,8 @@ def test_set_vm_power_state_transition(mocker,
@pytest.mark.parametrize('power_state_desired, power_state_current, power_state_resulting, activated_xenapi_method', @pytest.mark.parametrize('power_state_desired, power_state_current, power_state_resulting, activated_xenapi_method',
testcase_set_vm_power_state_transitions_async['params'], testcase_set_vm_power_state_transitions_async['params'], # type: ignore
ids=testcase_set_vm_power_state_transitions_async['ids']) ids=testcase_set_vm_power_state_transitions_async['ids']) # type: ignore
def test_set_vm_power_state_transition_async(mocker, def test_set_vm_power_state_transition_async(mocker,
fake_ansible_module, fake_ansible_module,
XenAPI, XenAPI,
@ -375,8 +375,8 @@ def test_set_vm_power_state_transition_async(mocker,
@pytest.mark.parametrize('power_state_desired, power_state_current, power_state_resulting, activated_xenapi_method', @pytest.mark.parametrize('power_state_desired, power_state_current, power_state_resulting, activated_xenapi_method',
testcase_set_vm_power_state_transitions['params'], testcase_set_vm_power_state_transitions['params'], # type: ignore
ids=testcase_set_vm_power_state_transitions['ids']) ids=testcase_set_vm_power_state_transitions['ids']) # type: ignore
def test_set_vm_power_state_transition_check_mode(mocker, def test_set_vm_power_state_transition_check_mode(mocker,
fake_ansible_module, fake_ansible_module,
XenAPI, XenAPI,

View file

@ -56,7 +56,7 @@ testcase_wait_for_task_all_statuses = {
} }
@pytest.mark.parametrize('vm_ref', testcase_bad_xenapi_refs['params'], ids=testcase_bad_xenapi_refs['ids']) @pytest.mark.parametrize('vm_ref', testcase_bad_xenapi_refs['params'], ids=testcase_bad_xenapi_refs['ids']) # type: ignore
def test_wait_for_vm_ip_address_bad_vm_ref(fake_ansible_module, xenserver, vm_ref): def test_wait_for_vm_ip_address_bad_vm_ref(fake_ansible_module, xenserver, vm_ref):
"""Tests failure on bad vm_ref.""" """Tests failure on bad vm_ref."""
with pytest.raises(FailJsonException) as exc_info: with pytest.raises(FailJsonException) as exc_info:
@ -94,8 +94,8 @@ def test_wait_for_vm_ip_address_bad_power_state(mocker, fake_ansible_module, Xen
@pytest.mark.parametrize('bad_guest_metrics_ref, bad_guest_metrics', @pytest.mark.parametrize('bad_guest_metrics_ref, bad_guest_metrics',
testcase_wait_for_vm_ip_address_bad_guest_metrics['params'], testcase_wait_for_vm_ip_address_bad_guest_metrics['params'], # type: ignore
ids=testcase_wait_for_vm_ip_address_bad_guest_metrics['ids']) ids=testcase_wait_for_vm_ip_address_bad_guest_metrics['ids']) # type: ignore
def test_wait_for_vm_ip_address_timeout(mocker, fake_ansible_module, XenAPI, xenserver, bad_guest_metrics_ref, bad_guest_metrics): def test_wait_for_vm_ip_address_timeout(mocker, fake_ansible_module, XenAPI, xenserver, bad_guest_metrics_ref, bad_guest_metrics):
"""Tests timeout.""" """Tests timeout."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True) mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)
@ -156,7 +156,7 @@ def test_wait_for_vm_ip_address(mocker, fake_ansible_module, XenAPI, xenserver):
assert fake_guest_metrics == mocked_returns['VM_guest_metrics.get_record.side_effect'][1] assert fake_guest_metrics == mocked_returns['VM_guest_metrics.get_record.side_effect'][1]
@pytest.mark.parametrize('task_ref', testcase_bad_xenapi_refs['params'], ids=testcase_bad_xenapi_refs['ids']) @pytest.mark.parametrize('task_ref', testcase_bad_xenapi_refs['params'], ids=testcase_bad_xenapi_refs['ids']) # type: ignore
def test_wait_for_task_bad_task_ref(fake_ansible_module, xenserver, task_ref): def test_wait_for_task_bad_task_ref(fake_ansible_module, xenserver, task_ref):
"""Tests failure on bad task_ref.""" """Tests failure on bad task_ref."""
with pytest.raises(FailJsonException) as exc_info: with pytest.raises(FailJsonException) as exc_info:
@ -193,8 +193,8 @@ def test_wait_for_task_timeout(mocker, fake_ansible_module, XenAPI, xenserver):
@pytest.mark.parametrize('task_status, result', @pytest.mark.parametrize('task_status, result',
testcase_wait_for_task_all_statuses['params'], testcase_wait_for_task_all_statuses['params'], # type: ignore
ids=testcase_wait_for_task_all_statuses['ids']) ids=testcase_wait_for_task_all_statuses['ids']) # type: ignore
def test_wait_for_task(mocker, fake_ansible_module, XenAPI, xenserver, task_status, result): def test_wait_for_task(mocker, fake_ansible_module, XenAPI, xenserver, task_status, result):
"""Tests regular invocation.""" """Tests regular invocation."""
mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True) mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True)

View file

@ -63,7 +63,7 @@ testcase_module_remote_conn_scheme = {
} }
@pytest.mark.parametrize('fake_ansible_module', testcase_module_local_conn['params'], ids=testcase_module_local_conn['ids'], indirect=True) @pytest.mark.parametrize('fake_ansible_module', testcase_module_local_conn['params'], ids=testcase_module_local_conn['ids'], indirect=True) # type: ignore
def test_xapi_connect_local_session(mocker, fake_ansible_module, XenAPI, xenserver): def test_xapi_connect_local_session(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests that connection to localhost uses XenAPI.xapi_local() function.""" """Tests that connection to localhost uses XenAPI.xapi_local() function."""
mocker.patch('XenAPI.xapi_local') mocker.patch('XenAPI.xapi_local')
@ -73,7 +73,7 @@ def test_xapi_connect_local_session(mocker, fake_ansible_module, XenAPI, xenserv
XenAPI.xapi_local.assert_called_once() XenAPI.xapi_local.assert_called_once()
@pytest.mark.parametrize('fake_ansible_module', testcase_module_local_conn['params'], ids=testcase_module_local_conn['ids'], indirect=True) @pytest.mark.parametrize('fake_ansible_module', testcase_module_local_conn['params'], ids=testcase_module_local_conn['ids'], indirect=True) # type: ignore
def test_xapi_connect_local_login(mocker, fake_ansible_module, XenAPI, xenserver): def test_xapi_connect_local_login(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests that connection to localhost uses empty username and password.""" """Tests that connection to localhost uses empty username and password."""
mocker.patch.object(XenAPI.Session, 'login_with_password', create=True) mocker.patch.object(XenAPI.Session, 'login_with_password', create=True)
@ -114,7 +114,12 @@ def test_xapi_connect_login_failure(mocker, fake_ansible_module, XenAPI, xenserv
assert exc_info.value.kwargs['msg'] == f"Unable to log on to XenServer at http://{hostname} as {username}: {fake_error_msg}" assert exc_info.value.kwargs['msg'] == f"Unable to log on to XenServer at http://{hostname} as {username}: {fake_error_msg}"
@pytest.mark.parametrize('fake_ansible_module', testcase_module_remote_conn_scheme['params'], ids=testcase_module_remote_conn_scheme['ids'], indirect=True) @pytest.mark.parametrize(
'fake_ansible_module',
testcase_module_remote_conn_scheme['params'], # type: ignore
ids=testcase_module_remote_conn_scheme['ids'], # type: ignore
indirect=True,
)
def test_xapi_connect_remote_scheme(mocker, fake_ansible_module, XenAPI, xenserver): def test_xapi_connect_remote_scheme(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests that explicit scheme in hostname param is preserved.""" """Tests that explicit scheme in hostname param is preserved."""
mocker.patch('XenAPI.Session') mocker.patch('XenAPI.Session')
@ -127,7 +132,7 @@ def test_xapi_connect_remote_scheme(mocker, fake_ansible_module, XenAPI, xenserv
XenAPI.Session.assert_called_once_with(hostname, ignore_ssl=ignore_ssl) XenAPI.Session.assert_called_once_with(hostname, ignore_ssl=ignore_ssl)
@pytest.mark.parametrize('fake_ansible_module', testcase_module_remote_conn['params'], ids=testcase_module_remote_conn['ids'], indirect=True) @pytest.mark.parametrize('fake_ansible_module', testcase_module_remote_conn['params'], ids=testcase_module_remote_conn['ids'], indirect=True) # type: ignore
def test_xapi_connect_remote_no_scheme(mocker, fake_ansible_module, XenAPI, xenserver): def test_xapi_connect_remote_no_scheme(mocker, fake_ansible_module, XenAPI, xenserver):
"""Tests that proper scheme is prepended to hostname without scheme.""" """Tests that proper scheme is prepended to hostname without scheme."""
mocker.patch('XenAPI.Session') mocker.patch('XenAPI.Session')

View file

@ -373,7 +373,7 @@ class TestInterfacesFileModule(unittest.TestCase):
iface_options = interfaces_file.get_interface_options(testcases[testname]["iface_lines"]) iface_options = interfaces_file.get_interface_options(testcases[testname]["iface_lines"])
self.assertEqual(testcases[testname]["iface_options"], iface_options) self.assertEqual(testcases[testname]["iface_options"], iface_options)
def test_get_interface_options(self): def test_get_interface_options_2(self):
testcases = { testcases = {
"select address": { "select address": {
"iface_options": [ "iface_options": [

View file

@ -56,7 +56,7 @@ class TestArchive(ModuleTestCase):
) )
PATHS = ( PATHS: tuple[tuple[list[str | bytes], str | bytes], ...] = (
([], ''), ([], ''),
(['/'], '/'), (['/'], '/'),
([b'/'], b'/'), ([b'/'], b'/'),
@ -68,5 +68,5 @@ PATHS = (
@pytest.mark.parametrize("paths,root", PATHS) @pytest.mark.parametrize("paths,root", PATHS)
def test_common_path(paths, root): def test_common_path(paths: list[str | bytes], root: str | bytes) -> None:
assert common_path(paths) == root assert common_path(paths) == root

View file

@ -29,7 +29,7 @@ try:
except ImportError: except ImportError:
pytestmark.append(pytest.mark.skip("Could not load gitlab module required for testing")) pytestmark.append(pytest.mark.skip("Could not load gitlab module required for testing"))
# Need to set these to something so that we don't fail when parsing # Need to set these to something so that we don't fail when parsing
GitlabModuleTestCase = object GitlabModuleTestCase = object # type: ignore
resp_get_project = _dummy resp_get_project = _dummy
resp_find_project_deploy_key = _dummy resp_find_project_deploy_key = _dummy
resp_create_project_deploy_key = _dummy resp_create_project_deploy_key = _dummy

View file

@ -29,7 +29,7 @@ try:
except ImportError: except ImportError:
pytestmark.append(pytest.mark.skip("Could not load gitlab module required for testing")) pytestmark.append(pytest.mark.skip("Could not load gitlab module required for testing"))
# Need to set these to something so that we don't fail when parsing # Need to set these to something so that we don't fail when parsing
GitlabModuleTestCase = object GitlabModuleTestCase = object # type: ignore
resp_get_group = _dummy resp_get_group = _dummy
resp_get_missing_group = _dummy resp_get_missing_group = _dummy
resp_create_group = _dummy resp_create_group = _dummy
@ -58,7 +58,7 @@ class TestGitlabGroup(GitlabModuleTestCase):
self.assertEqual(rvalue, True) self.assertEqual(rvalue, True)
@with_httmock(resp_get_missing_group) @with_httmock(resp_get_missing_group)
def test_exist_group(self): def test_exist_group_2(self):
rvalue = self.moduleUtil.exists_group(1) rvalue = self.moduleUtil.exists_group(1)
self.assertEqual(rvalue, False) self.assertEqual(rvalue, False)

View file

@ -36,7 +36,7 @@ try:
except ImportError: except ImportError:
pytestmark.append(pytest.mark.skip("Could not load gitlab module required for testing")) pytestmark.append(pytest.mark.skip("Could not load gitlab module required for testing"))
# Need to set these to something so that we don't fail when parsing # Need to set these to something so that we don't fail when parsing
GitlabModuleTestCase = object GitlabModuleTestCase = object # type: ignore
resp_list_group_access_tokens = _dummy resp_list_group_access_tokens = _dummy
resp_create_group_access_tokens = _dummy resp_create_group_access_tokens = _dummy
resp_revoke_group_access_tokens = _dummy resp_revoke_group_access_tokens = _dummy

View file

@ -29,7 +29,7 @@ try:
except ImportError: except ImportError:
pytestmark.append(pytest.mark.skip("Could not load gitlab module required for testing")) pytestmark.append(pytest.mark.skip("Could not load gitlab module required for testing"))
# Need to set these to something so that we don't fail when parsing # Need to set these to something so that we don't fail when parsing
GitlabModuleTestCase = object GitlabModuleTestCase = object # type: ignore
resp_get_project = _dummy resp_get_project = _dummy
resp_find_project_hook = _dummy resp_find_project_hook = _dummy
resp_create_project_hook = _dummy resp_create_project_hook = _dummy

View file

@ -29,7 +29,7 @@ try:
except ImportError: except ImportError:
pytestmark.append(pytest.mark.skip("Could not load gitlab module required for testing")) pytestmark.append(pytest.mark.skip("Could not load gitlab module required for testing"))
# Need to set these to something so that we don't fail when parsing # Need to set these to something so that we don't fail when parsing
GitlabModuleTestCase = object GitlabModuleTestCase = object # type: ignore
resp_get_group = _dummy resp_get_group = _dummy
resp_get_project_by_name = _dummy resp_get_project_by_name = _dummy
resp_create_project = _dummy resp_create_project = _dummy

View file

@ -36,7 +36,7 @@ try:
except ImportError: except ImportError:
pytestmark.append(pytest.mark.skip("Could not load gitlab module required for testing")) pytestmark.append(pytest.mark.skip("Could not load gitlab module required for testing"))
# Need to set these to something so that we don't fail when parsing # Need to set these to something so that we don't fail when parsing
GitlabModuleTestCase = object GitlabModuleTestCase = object # type: ignore
resp_list_project_access_tokens = _dummy resp_list_project_access_tokens = _dummy
resp_create_project_access_tokens = _dummy resp_create_project_access_tokens = _dummy
resp_revoke_project_access_tokens = _dummy resp_revoke_project_access_tokens = _dummy

View file

@ -35,7 +35,7 @@ try:
except ImportError: except ImportError:
pytestmark.append(pytest.mark.skip("Could not load gitlab module required for testing")) pytestmark.append(pytest.mark.skip("Could not load gitlab module required for testing"))
# Need to set these to something so that we don't fail when parsing # Need to set these to something so that we don't fail when parsing
GitlabModuleTestCase = object GitlabModuleTestCase = object # type: ignore
resp_find_runners_list = _dummy resp_find_runners_list = _dummy
resp_get_runner = _dummy resp_get_runner = _dummy
resp_create_runner = _dummy resp_create_runner = _dummy

View file

@ -31,7 +31,7 @@ try:
except ImportError: except ImportError:
pytestmark.append(pytest.mark.skip("Could not load gitlab module required for testing")) pytestmark.append(pytest.mark.skip("Could not load gitlab module required for testing"))
# Need to set these to something so that we don't fail when parsing # Need to set these to something so that we don't fail when parsing
GitlabModuleTestCase = object GitlabModuleTestCase = object # type: ignore
resp_find_user = _dummy resp_find_user = _dummy
resp_get_user = _dummy resp_get_user = _dummy
resp_get_user_keys = _dummy resp_get_user_keys = _dummy

View file

@ -1640,11 +1640,12 @@ def mocked_generic_connection_modify(mocker):
changed_return=(True, dict())) changed_return=(True, dict()))
@pytest.fixture # TODO: overridden below!
def mocked_generic_connection_unchanged(mocker): # @pytest.fixture
mocker_set(mocker, # def mocked_generic_connection_unchanged(mocker):
connection_exists=True, # mocker_set(mocker,
execute_return=(0, TESTCASE_GENERIC_SHOW_OUTPUT, "")) # connection_exists=True,
# execute_return=(0, TESTCASE_GENERIC_SHOW_OUTPUT, ""))
@pytest.fixture @pytest.fixture
@ -2104,6 +2105,7 @@ def test_bond_connection_create(mocked_generic_connection_create, capfd):
assert results['changed'] assert results['changed']
@pytest.mark.skip(reason="Currently broken") # TODO: fix me!
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_BOND, indirect=['patch_ansible_module']) @pytest.mark.parametrize('patch_ansible_module', TESTCASE_BOND, indirect=['patch_ansible_module'])
def test_bond_connection_unchanged(mocked_bond_connection_unchanged, capfd): def test_bond_connection_unchanged(mocked_bond_connection_unchanged, capfd):
""" """
@ -3450,7 +3452,7 @@ def test_ethernet_connection_static_ipv6_address_static_route_with_metric_create
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_ETHERNET_ADD_IPV6_INT_WITH_MULTIPLE_ROUTES_AND_METRIC, indirect=['patch_ansible_module']) @pytest.mark.parametrize('patch_ansible_module', TESTCASE_ETHERNET_ADD_IPV6_INT_WITH_MULTIPLE_ROUTES_AND_METRIC, indirect=['patch_ansible_module'])
def test_ethernet_connection_static_ipv6_address_static_route_create(mocked_ethernet_connection_with_ipv6_static_address_static_route_create, capfd): def test_ethernet_connection_static_ipv6_address_static_route_create_2(mocked_ethernet_connection_with_ipv6_static_address_static_route_create, capfd):
""" """
Test : Create ethernet connection with static IPv6 address and multiple static routes with metric Test : Create ethernet connection with static IPv6 address and multiple static routes with metric
""" """
@ -4097,7 +4099,7 @@ def test_create_ethernet_addr_gen_mode_and_ip6_privacy_static(mocked_generic_con
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_ETHERNET_STATIC_IP6_PRIVACY_AND_ADDR_GEN_MODE, indirect=['patch_ansible_module']) @pytest.mark.parametrize('patch_ansible_module', TESTCASE_ETHERNET_STATIC_IP6_PRIVACY_AND_ADDR_GEN_MODE, indirect=['patch_ansible_module'])
def test_ethernet_connection_static_with_multiple_ip4_addresses_unchanged(mocked_ethernet_connection_static_ip6_privacy_and_addr_gen_mode_unchange, capfd): def test_ethernet_connection_static_with_multiple_ip4_addresses_unchanged_2(mocked_ethernet_connection_static_ip6_privacy_and_addr_gen_mode_unchange, capfd):
""" """
Test : Ethernet connection with static IP configuration unchanged Test : Ethernet connection with static IP configuration unchanged
""" """
@ -4340,7 +4342,7 @@ def test_infiniband_connection_static_transport_mode_connected(
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_GENERIC_DIFF_CHECK, indirect=['patch_ansible_module']) @pytest.mark.parametrize('patch_ansible_module', TESTCASE_GENERIC_DIFF_CHECK, indirect=['patch_ansible_module'])
def test_bond_connection_unchanged(mocked_generic_connection_diff_check, capfd): def test_bond_connection_unchanged_2(mocked_generic_connection_diff_check, capfd):
""" """
Test : Bond connection unchanged Test : Bond connection unchanged
""" """

View file

@ -4,6 +4,7 @@
from __future__ import annotations from __future__ import annotations
import typing as t
from unittest import mock from unittest import mock
from ansible.module_utils import basic from ansible.module_utils import basic
from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import ( from ansible_collections.community.internal_test_tools.tests.unit.plugins.modules.utils import (
@ -110,7 +111,7 @@ valid_inventory = {
}, },
} }
empty_inventory = { empty_inventory: dict[str, dict[str, t.Any]] = {
"installed_pkgs": {}, "installed_pkgs": {},
"available_pkgs": {}, "available_pkgs": {},
"installed_groups": {}, "installed_groups": {},

View file

@ -682,7 +682,7 @@ def patch_get_bin_path(mocker):
@pytest.mark.parametrize( @pytest.mark.parametrize(
'patch_ansible_module, expected', 'patch_ansible_module, expected',
TESTCASES, TESTCASES,
ids=[item[1]['id'] for item in TESTCASES], ids=[item[1]['id'] for item in TESTCASES], # type: ignore
indirect=['patch_ansible_module'] indirect=['patch_ansible_module']
) )
@pytest.mark.usefixtures('patch_ansible_module') @pytest.mark.usefixtures('patch_ansible_module')

View file

@ -856,7 +856,7 @@ Entitlement Type: Physical
] ]
TEST_CASES_IDS = [item[1]['id'] for item in TEST_CASES] TEST_CASES_IDS: list[str] = [item[1]['id'] for item in TEST_CASES] # type: ignore
@pytest.mark.parametrize('patch_ansible_module, testcase', TEST_CASES, ids=TEST_CASES_IDS, indirect=['patch_ansible_module']) @pytest.mark.parametrize('patch_ansible_module, testcase', TEST_CASES, ids=TEST_CASES_IDS, indirect=['patch_ansible_module'])
@ -1212,7 +1212,7 @@ System Purpose Status: Matched
] ]
SYSPURPOSE_TEST_CASES_IDS = [item[1]['id'] for item in SYSPURPOSE_TEST_CASES] SYSPURPOSE_TEST_CASES_IDS: list[str] = [item[1]['id'] for item in SYSPURPOSE_TEST_CASES] # type: ignore
@pytest.mark.parametrize('patch_ansible_module, testcase', SYSPURPOSE_TEST_CASES, ids=SYSPURPOSE_TEST_CASES_IDS, indirect=['patch_ansible_module']) @pytest.mark.parametrize('patch_ansible_module, testcase', SYSPURPOSE_TEST_CASES, ids=SYSPURPOSE_TEST_CASES_IDS, indirect=['patch_ansible_module'])

View file

@ -759,7 +759,7 @@ TEST_CASES = [
] ]
TEST_CASES_IDS = [item[1]['id'] for item in TEST_CASES] TEST_CASES_IDS: list[str] = [item[1]['id'] for item in TEST_CASES] # type: ignore
@pytest.mark.parametrize('patch_ansible_module, testcase', TEST_CASES, ids=TEST_CASES_IDS, indirect=['patch_ansible_module']) @pytest.mark.parametrize('patch_ansible_module, testcase', TEST_CASES, ids=TEST_CASES_IDS, indirect=['patch_ansible_module'])

View file

@ -436,7 +436,7 @@ class TestXCCRedfishCommand(unittest.TestCase):
with self.assertRaises(AnsibleFailJson) as result: with self.assertRaises(AnsibleFailJson) as result:
module.main() module.main()
def test_module_command_PostResource_fail_when_no_requestbody(self): def test_module_command_PostResource_fail_when_no_requestbody_2(self):
with set_module_args({ with set_module_args({
'category': 'Raw', 'category': 'Raw',
'command': 'PostResource', 'command': 'PostResource',

View file

@ -45,7 +45,7 @@ testcase_module_params = {
} }
@pytest.mark.parametrize('patch_ansible_module', testcase_module_params['params'], ids=testcase_module_params['ids'], indirect=True) @pytest.mark.parametrize('patch_ansible_module', testcase_module_params['params'], ids=testcase_module_params['ids'], indirect=True) # type: ignore
def test_xenserver_guest_info(mocker, capfd, XenAPI, xenserver_guest_info): def test_xenserver_guest_info(mocker, capfd, XenAPI, xenserver_guest_info):
""" """
Tests regular module invocation including parsing and propagation of Tests regular module invocation including parsing and propagation of

View file

@ -126,7 +126,7 @@ testcase_module_params_wait = {
} }
@pytest.mark.parametrize('power_state', testcase_set_powerstate['params'], ids=testcase_set_powerstate['ids']) @pytest.mark.parametrize('power_state', testcase_set_powerstate['params'], ids=testcase_set_powerstate['ids']) # type: ignore
def test_xenserver_guest_powerstate_set_power_state(mocker, fake_ansible_module, XenAPI, xenserver_guest_powerstate, power_state): def test_xenserver_guest_powerstate_set_power_state(mocker, fake_ansible_module, XenAPI, xenserver_guest_powerstate, power_state):
"""Tests power state change handling.""" """Tests power state change handling."""
mocker.patch('ansible_collections.community.general.plugins.modules.xenserver_guest_powerstate.get_object_ref', mocker.patch('ansible_collections.community.general.plugins.modules.xenserver_guest_powerstate.get_object_ref',
@ -163,8 +163,8 @@ def test_xenserver_guest_powerstate_set_power_state(mocker, fake_ansible_module,
@pytest.mark.parametrize('patch_ansible_module', @pytest.mark.parametrize('patch_ansible_module',
testcase_module_params_state_present['params'], testcase_module_params_state_present['params'], # type: ignore
ids=testcase_module_params_state_present['ids'], ids=testcase_module_params_state_present['ids'], # type: ignore
indirect=True) indirect=True)
def test_xenserver_guest_powerstate_present(mocker, patch_ansible_module, capfd, XenAPI, xenserver_guest_powerstate): def test_xenserver_guest_powerstate_present(mocker, patch_ansible_module, capfd, XenAPI, xenserver_guest_powerstate):
""" """
@ -209,8 +209,8 @@ def test_xenserver_guest_powerstate_present(mocker, patch_ansible_module, capfd,
@pytest.mark.parametrize('patch_ansible_module', @pytest.mark.parametrize('patch_ansible_module',
testcase_module_params_state_other['params'], testcase_module_params_state_other['params'], # type: ignore
ids=testcase_module_params_state_other['ids'], ids=testcase_module_params_state_other['ids'], # type: ignore
indirect=True) indirect=True)
def test_xenserver_guest_powerstate_other(mocker, patch_ansible_module, capfd, XenAPI, xenserver_guest_powerstate): def test_xenserver_guest_powerstate_other(mocker, patch_ansible_module, capfd, XenAPI, xenserver_guest_powerstate):
""" """
@ -255,8 +255,8 @@ def test_xenserver_guest_powerstate_other(mocker, patch_ansible_module, capfd, X
@pytest.mark.parametrize('patch_ansible_module', @pytest.mark.parametrize('patch_ansible_module',
testcase_module_params_wait['params'], testcase_module_params_wait['params'], # type: ignore
ids=testcase_module_params_wait['ids'], ids=testcase_module_params_wait['ids'], # type: ignore
indirect=True) indirect=True)
def test_xenserver_guest_powerstate_wait(mocker, patch_ansible_module, capfd, XenAPI, xenserver_guest_powerstate): def test_xenserver_guest_powerstate_wait(mocker, patch_ansible_module, capfd, XenAPI, xenserver_guest_powerstate):
""" """