From 6088b0cff5c2764a36b12067b48d5a451316cbe4 Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Wed, 29 Oct 2025 18:13:38 +0100 Subject: [PATCH] CI: add type checking (#10997) * Set up type checking with mypy. * Make mypy pass. * Use list() instead of sorted(). --- .mypy.ini | 216 ++++++++++++++++++ antsibull-nox.toml | 15 +- plugins/callback/dense.py | 2 +- plugins/callback/elastic.py | 1 + plugins/callback/logentries.py | 2 +- plugins/callback/opentelemetry.py | 1 + plugins/callback/print_task.py | 2 +- plugins/callback/selective.py | 8 +- plugins/connection/incus.py | 4 +- plugins/connection/lxd.py | 4 +- plugins/connection/qubes.py | 2 +- plugins/connection/wsl.py | 41 ++-- plugins/filter/hashids.py | 2 +- plugins/filter/json_patch.py | 9 +- plugins/filter/to_yaml.py | 11 +- plugins/filter/unicode_normalize.py | 2 +- plugins/inventory/lxd.py | 1 + plugins/inventory/scaleway.py | 1 + plugins/lookup/bitwarden.py | 2 +- plugins/lookup/github_app_access_token.py | 2 +- plugins/lookup/revbitspss.py | 1 + plugins/module_utils/_stormssh.py | 3 +- plugins/module_utils/cmd_runner_fmt.py | 7 + plugins/module_utils/consul.py | 13 +- plugins/module_utils/django.py | 16 +- plugins/module_utils/gitlab.py | 8 +- plugins/module_utils/known_hosts.py | 2 +- plugins/module_utils/mh/base.py | 6 +- plugins/module_utils/mh/exceptions.py | 8 +- plugins/module_utils/mh/mixins/state.py | 4 +- plugins/module_utils/mh/module_helper.py | 14 +- plugins/module_utils/scaleway.py | 3 +- plugins/module_utils/univention_umc.py | 4 +- plugins/modules/apt_rpm.py | 1 + plugins/modules/campfire.py | 9 +- plugins/modules/crypttab.py | 3 +- plugins/modules/filesystem.py | 18 +- plugins/modules/homectl.py | 2 + plugins/modules/htpasswd.py | 4 +- plugins/modules/jenkins_node.py | 4 +- plugins/modules/pacemaker_info.py | 2 +- plugins/modules/pmem.py | 1 + plugins/modules/rhevm.py | 4 +- plugins/modules/udm_user.py | 2 + plugins/plugin_utils/ansible_type.py | 5 +- plugins/test/a_module.py | 2 +- plugins/test/fqdn_valid.py | 1 + tests/unit/plugins/cache/test_redis.py | 2 +- .../module_utils/cloud/test_scaleway.py | 2 +- tests/unit/plugins/module_utils/test_csv.py | 6 +- .../test_gather_vm_params_and_facts.py | 6 +- .../xenserver/test_netaddr_functions.py | 4 +- .../xenserver/test_set_vm_power_state.py | 26 +-- .../xenserver/test_wait_for_functions.py | 12 +- .../module_utils/xenserver/test_xapi.py | 13 +- .../interfaces_file/test_interfaces_file.py | 2 +- tests/unit/plugins/modules/test_archive.py | 4 +- .../plugins/modules/test_gitlab_deploy_key.py | 2 +- .../unit/plugins/modules/test_gitlab_group.py | 4 +- .../modules/test_gitlab_group_access_token.py | 2 +- .../unit/plugins/modules/test_gitlab_hook.py | 2 +- .../plugins/modules/test_gitlab_project.py | 2 +- .../test_gitlab_project_access_token.py | 2 +- .../plugins/modules/test_gitlab_runner.py | 2 +- .../unit/plugins/modules/test_gitlab_user.py | 2 +- tests/unit/plugins/modules/test_nmcli.py | 18 +- tests/unit/plugins/modules/test_pacman.py | 3 +- tests/unit/plugins/modules/test_pacman_key.py | 2 +- .../modules/test_redhat_subscription.py | 4 +- .../plugins/modules/test_rhsm_repository.py | 2 +- .../modules/test_xcc_redfish_command.py | 2 +- .../modules/test_xenserver_guest_info.py | 2 +- .../test_xenserver_guest_powerstate.py | 14 +- 73 files changed, 442 insertions(+), 175 deletions(-) create mode 100644 .mypy.ini diff --git a/.mypy.ini b/.mypy.ini new file mode 100644 index 0000000000..1ec80d77db --- /dev/null +++ b/.mypy.ini @@ -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 diff --git a/antsibull-nox.toml b/antsibull-nox.toml index 735d572599..afd476ea61 100644 --- a/antsibull-nox.toml +++ b/antsibull-nox.toml @@ -28,7 +28,20 @@ run_yamllint = true yamllint_config = ".yamllint" # yamllint_config_plugins = ".yamllint-docs" # 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] validate_collection_refs="all" diff --git a/plugins/callback/dense.py b/plugins/callback/dense.py index de50d97ce1..30167791e9 100644 --- a/plugins/callback/dense.py +++ b/plugins/callback/dense.py @@ -485,4 +485,4 @@ class CallbackModule(CallbackModule_default): # When using -vv or higher, simply do the default action if display.verbosity >= 2 or not HAS_OD: - CallbackModule = CallbackModule_default + CallbackModule = CallbackModule_default # type: ignore diff --git a/plugins/callback/elastic.py b/plugins/callback/elastic.py index 82478b9e7d..ed0949a753 100644 --- a/plugins/callback/elastic.py +++ b/plugins/callback/elastic.py @@ -90,6 +90,7 @@ from ansible.errors import AnsibleError, AnsibleRuntimeError from ansible.module_utils.ansible_release import __version__ as ansible_version from ansible.plugins.callback import CallbackBase +ELASTIC_LIBRARY_IMPORT_ERROR: ImportError | None try: from elasticapm import Client, capture_span, trace_parent_from_string, instrument, label except ImportError as imp_exc: diff --git a/plugins/callback/logentries.py b/plugins/callback/logentries.py index 8fbcef4dd6..855bffa1c4 100644 --- a/plugins/callback/logentries.py +++ b/plugins/callback/logentries.py @@ -206,7 +206,7 @@ else: sock.connect((self.LE_API, self.LE_TLS_PORT)) self._conn = sock - SocketAppender = TLSSocketAppender + SocketAppender = TLSSocketAppender # type: ignore class CallbackModule(CallbackBase): diff --git a/plugins/callback/opentelemetry.py b/plugins/callback/opentelemetry.py index ca6ec2b916..6243992822 100644 --- a/plugins/callback/opentelemetry.py +++ b/plugins/callback/opentelemetry.py @@ -145,6 +145,7 @@ from ansible.errors import AnsibleError from ansible.module_utils.ansible_release import __version__ as ansible_version from ansible.plugins.callback import CallbackBase +OTEL_LIBRARY_IMPORT_ERROR: ImportError | None try: from opentelemetry import trace from opentelemetry.trace import SpanKind diff --git a/plugins/callback/print_task.py b/plugins/callback/print_task.py index f6008c817f..76d9aadb39 100644 --- a/plugins/callback/print_task.py +++ b/plugins/callback/print_task.py @@ -28,7 +28,7 @@ try: from yaml import CSafeDumper as SafeDumper from yaml import CSafeLoader as SafeLoader except ImportError: - from yaml import SafeDumper, SafeLoader + from yaml import SafeDumper, SafeLoader # type: ignore from ansible.plugins.callback import CallbackBase diff --git a/plugins/callback/selective.py b/plugins/callback/selective.py index 2a7dd07a3e..e7906ea7e5 100644 --- a/plugins/callback/selective.py +++ b/plugins/callback/selective.py @@ -46,13 +46,13 @@ from ansible.module_utils.common.text.converters import to_text DONT_COLORIZE = False COLORS = { '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', 'not_so_bold': '\033[1m\033[34m', - 'changed': f'\x1b[{C.COLOR_CODES[C.COLOR_CHANGED]}m', - 'failed': f'\x1b[{C.COLOR_CODES[C.COLOR_ERROR]}m', + 'changed': f'\x1b[{C.COLOR_CODES[C.COLOR_CHANGED]}m', # type: ignore + 'failed': f'\x1b[{C.COLOR_CODES[C.COLOR_ERROR]}m', # type: ignore '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 } diff --git a/plugins/connection/incus.py b/plugins/connection/incus.py index 3dfd37764b..5aecd45b6d 100644 --- a/plugins/connection/incus.py +++ b/plugins/connection/incus.py @@ -106,10 +106,10 @@ class Connection(ConnectionBase): host=self._instance()) 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""" - exec_cmd = [ + exec_cmd: list[str] = [ self._incus_cmd, "--project", self.get_option("project"), "exec", diff --git a/plugins/connection/lxd.py b/plugins/connection/lxd.py index d4d3b45d0a..e9930f76c7 100644 --- a/plugins/connection/lxd.py +++ b/plugins/connection/lxd.py @@ -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._connected = True - def _build_command(self, cmd) -> str: + def _build_command(self, cmd) -> list[str]: """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"): exec_cmd.extend(["--project", self.get_option("project")]) diff --git a/plugins/connection/qubes.py b/plugins/connection/qubes.py index 8d69594b22..3969b1bd36 100644 --- a/plugins/connection/qubes.py +++ b/plugins/connection/qubes.py @@ -106,7 +106,7 @@ class Connection(ConnectionBase): super(Connection, self)._connect() 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): """Run specified command in a running QubesVM """ super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable) diff --git a/plugins/connection/wsl.py b/plugins/connection/wsl.py index 3b768eebf8..9f181afff2 100644 --- a/plugins/connection/wsl.py +++ b/plugins/connection/wsl.py @@ -332,31 +332,23 @@ from ansible.utils.path import makedirs_safe from binascii import hexlify from subprocess import list2cmdline +PARAMIKO_IMPORT_ERR: str | None try: import paramiko + from paramiko import MissingHostKeyPolicy PARAMIKO_IMPORT_ERR = None except ImportError: - paramiko = None PARAMIKO_IMPORT_ERR = traceback.format_exc() - - -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 + MissingHostKeyPolicy = object # type: ignore display = Display() -def authenticity_msg(hostname: str, ktype: str, fingerprint: str) -> str: +def authenticity_msg(hostname: str, ktype: str, fingerprint: bytes) -> str: msg = f""" 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)? """ return msg @@ -376,7 +368,7 @@ class MyAddPolicy(MissingHostKeyPolicy): self.connection = connection 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'))): @@ -396,10 +388,10 @@ class MyAddPolicy(MissingHostKeyPolicy): if inp.lower() not in ['yes', 'y', '']: 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: - 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 # in order to control ordering. @@ -540,7 +532,7 @@ class Connection(ConnectionBase): return self 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(): added_this_time = getattr(key, '_added_by_ansible_this_time', False) if added_this_time: @@ -560,14 +552,14 @@ class Connection(ConnectionBase): makedirs_safe(path) 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(): # was f.write added_this_time = getattr(key, '_added_by_ansible_this_time', False) if not added_this_time: 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(): added_this_time = getattr(key, '_added_by_ansible_this_time', False) if added_this_time: @@ -595,13 +587,16 @@ class Connection(ConnectionBase): 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 try: - self.ssh.get_transport().set_keepalive(5) - chan = self.ssh.get_transport().open_session() + transport = self.ssh.get_transport() + if transport is None: + raise ValueError("Transport not available") + transport.set_keepalive(5) + chan = transport.open_session() except Exception as e: text_e = to_text(e) msg = 'Failed to open session' @@ -745,7 +740,7 @@ class Connection(ConnectionBase): # just in case any were added recently 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 # we can ensure the new file has the correct mode/owner diff --git a/plugins/filter/hashids.py b/plugins/filter/hashids.py index c58ae4d70b..3ea758213a 100644 --- a/plugins/filter/hashids.py +++ b/plugins/filter/hashids.py @@ -16,7 +16,7 @@ from ansible.module_utils.common.collections import is_sequence try: from ansible.errors import AnsibleTypeError except ImportError: - from ansible.errors import AnsibleFilterTypeError as AnsibleTypeError + from ansible.errors import AnsibleFilterTypeError as AnsibleTypeError # type: ignore try: from hashids import Hashids diff --git a/plugins/filter/json_patch.py b/plugins/filter/json_patch.py index 8cd6bd08b0..59d6caddb3 100644 --- a/plugins/filter/json_patch.py +++ b/plugins/filter/json_patch.py @@ -3,17 +3,18 @@ # SPDX-License-Identifier: GPL-3.0-or-later from __future__ import annotations + +import typing as t from json import loads -from typing import TYPE_CHECKING from ansible.errors import AnsibleFilterError -if TYPE_CHECKING: +if t.TYPE_CHECKING: from typing import Any, Callable, Union +JSONPATCH_IMPORT_ERROR: ImportError | None try: import jsonpatch - except ImportError as exc: HAS_LIB = False JSONPATCH_IMPORT_ERROR = exc @@ -82,7 +83,7 @@ class FilterModule: "You need to install 'jsonpatch' package prior to running 'json_patch' filter" ) from JSONPATCH_IMPORT_ERROR - args = {"op": op, "path": path} + args: dict[str, t.Any] = {"op": op, "path": path} from_arg = kwargs.pop("from", None) fail_test = kwargs.pop("fail_test", False) diff --git a/plugins/filter/to_yaml.py b/plugins/filter/to_yaml.py index 905b04271c..f808a9420c 100644 --- a/plugins/filter/to_yaml.py +++ b/plugins/filter/to_yaml.py @@ -11,15 +11,16 @@ from yaml import dump try: from yaml.cyaml import CSafeDumper as SafeDumper except ImportError: - from yaml import SafeDumper + from yaml import SafeDumper # type: ignore from ansible.module_utils.common.collections import is_sequence try: # This is ansible-core 2.19+ from ansible.utils.vars import transform_to_native_types from ansible.parsing.vault import VaultHelper, VaultLib + HAS_TRANSFORM_TO_NATIVE_TYPES = True except ImportError: - transform_to_native_types = None + HAS_TRANSFORM_TO_NATIVE_TYPES = False from ansible.parsing.yaml.objects import AnsibleVaultEncryptedUnicode 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 if isinstance(value, AnsibleUnsafe): # 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. if isinstance(value, Mapping): 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 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_compat( + return _to_native_types_compat( # type: ignore[unreachable] value, redact_value="" if redact_sensitive_values else None, # same string as in ansible-core 2.19 by transform_to_native_types() ) diff --git a/plugins/filter/unicode_normalize.py b/plugins/filter/unicode_normalize.py index f1fe18402b..7298246916 100644 --- a/plugins/filter/unicode_normalize.py +++ b/plugins/filter/unicode_normalize.py @@ -52,7 +52,7 @@ from ansible.errors import AnsibleFilterError try: from ansible.errors import AnsibleTypeError except ImportError: - from ansible.errors import AnsibleFilterTypeError as AnsibleTypeError + from ansible.errors import AnsibleFilterTypeError as AnsibleTypeError # type: ignore def unicode_normalize(data, form='NFC'): diff --git a/plugins/inventory/lxd.py b/plugins/inventory/lxd.py index 492d12a21b..ce7cf71ede 100644 --- a/plugins/inventory/lxd.py +++ b/plugins/inventory/lxd.py @@ -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.plugin_utils.unsafe import make_unsafe +IPADDRESS_IMPORT_ERROR: ImportError | None try: import ipaddress except ImportError as exc: diff --git a/plugins/inventory/scaleway.py b/plugins/inventory/scaleway.py index 59c19b498b..8b01acb60b 100644 --- a/plugins/inventory/scaleway.py +++ b/plugins/inventory/scaleway.py @@ -118,6 +118,7 @@ variables: import os import json +YAML_IMPORT_ERROR: ImportError | None try: import yaml except ImportError as exc: diff --git a/plugins/lookup/bitwarden.py b/plugins/lookup/bitwarden.py index e4d958a96f..60d11c8bfb 100644 --- a/plugins/lookup/bitwarden.py +++ b/plugins/lookup/bitwarden.py @@ -244,7 +244,7 @@ class Bitwarden(object): out, err = self._run(params) # 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 return [item['id'] for item in initial_matches diff --git a/plugins/lookup/github_app_access_token.py b/plugins/lookup/github_app_access_token.py index 0b4f4d53ee..dd0d9c1870 100644 --- a/plugins/lookup/github_app_access_token.py +++ b/plugins/lookup/github_app_access_token.py @@ -82,7 +82,7 @@ except ImportError: HAS_PYTHON_JWT = False # vs pyjwt if HAS_JWT and hasattr(jwt, 'JWT'): 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() try: diff --git a/plugins/lookup/revbitspss.py b/plugins/lookup/revbitspss.py index 86e3fbe38c..549bcd87bd 100644 --- a/plugins/lookup/revbitspss.py +++ b/plugins/lookup/revbitspss.py @@ -65,6 +65,7 @@ from ansible.plugins.lookup import LookupBase from ansible.utils.display import Display from ansible.errors import AnsibleError +ANOTHER_LIBRARY_IMPORT_ERROR: ImportError | None try: from pam.revbits_ansible.server import SecretServer except ImportError as imp_exc: diff --git a/plugins/module_utils/_stormssh.py b/plugins/module_utils/_stormssh.py index 42a72eb674..92cd44026b 100644 --- a/plugins/module_utils/_stormssh.py +++ b/plugins/module_utils/_stormssh.py @@ -11,10 +11,11 @@ import traceback from operator import itemgetter +PARAMIKO_IMPORT_ERROR: str | None try: from paramiko.config import SSHConfig except ImportError: - SSHConfig = object + SSHConfig = object # type: ignore HAS_PARAMIKO = False PARAMIKO_IMPORT_ERROR = traceback.format_exc() else: diff --git a/plugins/module_utils/cmd_runner_fmt.py b/plugins/module_utils/cmd_runner_fmt.py index dcb9fc8e20..8f00b5ea96 100644 --- a/plugins/module_utils/cmd_runner_fmt.py +++ b/plugins/module_utils/cmd_runner_fmt.py @@ -4,10 +4,17 @@ from __future__ import annotations +import typing as t + from functools import wraps 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): return list(value) if is_sequence(value) else [value] diff --git a/plugins/module_utils/consul.py b/plugins/module_utils/consul.py index b814485c55..c096349916 100644 --- a/plugins/module_utils/consul.py +++ b/plugins/module_utils/consul.py @@ -9,6 +9,7 @@ from __future__ import annotations import copy import json import re +import typing as t from urllib import error as urllib_error from urllib.parse import urlencode @@ -118,12 +119,12 @@ class _ConsulModule: As such backwards incompatible changes can occur even in bugfix releases. """ - api_endpoint = None # type: str - unique_identifiers = None # type: list - result_key = None # type: str - create_only_fields = set() - operational_attributes = set() - params = {} + api_endpoint: str | None = None + unique_identifiers: list | None = None + result_key: str | None = None + create_only_fields: set[str] = set() + operational_attributes: set[str] = set() + params: dict[str, t.Any] = {} def __init__(self, module): self._module = module diff --git a/plugins/module_utils/django.py b/plugins/module_utils/django.py index 4c052a1d6e..908a6b7ce7 100644 --- a/plugins/module_utils/django.py +++ b/plugins/module_utils/django.py @@ -4,12 +4,16 @@ from __future__ import annotations +import typing as t 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.python_runner import PythonRunner 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( # environmental options @@ -32,7 +36,7 @@ _pks = dict( 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"), app=cmd_runner_fmt.as_opt_val("--app"), apps=cmd_runner_fmt.as_list(), @@ -95,11 +99,11 @@ class _DjangoRunner(PythonRunner): class DjangoModuleHelper(ModuleHelper): module = {} - django_admin_cmd = None - arg_formats = {} - django_admin_arg_order = () - _django_args = [] - _check_mode_arg = "" + django_admin_cmd: str | None = None + arg_formats: dict[str, ArgFormatType] = {} + django_admin_arg_order: tuple[str, ...] | str = () + _django_args: list[str] = [] + _check_mode_arg: str = "" def __init__(self): self.module["argument_spec"], self.arg_formats = self._build_args(self.module.get("argument_spec", {}), diff --git a/plugins/module_utils/gitlab.py b/plugins/module_utils/gitlab.py index 7ad11ab5a2..b1b0082fa2 100644 --- a/plugins/module_utils/gitlab.py +++ b/plugins/module_utils/gitlab.py @@ -6,6 +6,8 @@ from __future__ import annotations +import typing as t + from ansible.module_utils.basic import missing_required_lib from ansible_collections.community.general.plugins.module_utils.version import LooseVersion @@ -15,7 +17,7 @@ from urllib.parse import urljoin import traceback -def _determine_list_all_kwargs(version): +def _determine_list_all_kwargs(version) -> dict[str, t.Any]: gitlab_version = LooseVersion(version) if gitlab_version >= LooseVersion('4.0.0'): # 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} -GITLAB_IMP_ERR = None +GITLAB_IMP_ERR: str | None = None try: import gitlab import requests HAS_GITLAB_PACKAGE = True list_all_kwargs = _determine_list_all_kwargs(gitlab.__version__) except Exception: - gitlab = None + gitlab = None # type: ignore GITLAB_IMP_ERR = traceback.format_exc() HAS_GITLAB_PACKAGE = False list_all_kwargs = {} diff --git a/plugins/module_utils/known_hosts.py b/plugins/module_utils/known_hosts.py index ec20b8d88b..15c630391e 100644 --- a/plugins/module_utils/known_hosts.py +++ b/plugins/module_utils/known_hosts.py @@ -20,7 +20,7 @@ from urllib.parse import urlparse try: from hashlib import sha1 except ImportError: - import sha as sha1 + import sha as sha1 # type: ignore[no-redef] HASHED_KEY_MAGIC = "|1|" diff --git a/plugins/module_utils/mh/base.py b/plugins/module_utils/mh/base.py index 688d65fc35..a1cd889eaf 100644 --- a/plugins/module_utils/mh/base.py +++ b/plugins/module_utils/mh/base.py @@ -5,15 +5,17 @@ from __future__ import annotations +import typing as t + 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.deco import module_fails_on_exception class ModuleHelperBase(object): - module = None + module: dict[str, t.Any] | None = None # TODO: better spec using t.TypedDict ModuleHelperException = _MHE - _delegated_to_module = ( + _delegated_to_module: tuple[str, ...] = ( 'check_mode', 'get_bin_path', 'warn', 'deprecate', 'debug', ) diff --git a/plugins/module_utils/mh/exceptions.py b/plugins/module_utils/mh/exceptions.py index 94bb7d7fff..d703b2676a 100644 --- a/plugins/module_utils/mh/exceptions.py +++ b/plugins/module_utils/mh/exceptions.py @@ -5,13 +5,15 @@ from __future__ import annotations +import typing as t + from ansible.module_utils.common.text.converters import to_native class ModuleHelperException(Exception): - def __init__(self, msg, update_output=None, *args, **kwargs): - self.msg = to_native(msg or f"Module failed with exception: {self}") + def __init__(self, msg: str, update_output: dict[str, t.Any] | None = None, *args, **kwargs): + self.msg: str = to_native(msg or f"Module failed with exception: {self}") if update_output is None: update_output = {} - self.update_output = update_output + self.update_output: dict[str, t.Any] = update_output super(ModuleHelperException, self).__init__(*args) diff --git a/plugins/module_utils/mh/mixins/state.py b/plugins/module_utils/mh/mixins/state.py index a04c3b1386..ef9b074005 100644 --- a/plugins/module_utils/mh/mixins/state.py +++ b/plugins/module_utils/mh/mixins/state.py @@ -7,8 +7,8 @@ from __future__ import annotations class StateMixin(object): - state_param = 'state' - default_state = None + state_param: str = 'state' + default_state: str | None = None def _state(self): state = self.module.params.get(self.state_param) diff --git a/plugins/module_utils/mh/module_helper.py b/plugins/module_utils/mh/module_helper.py index fdce99045c..cc9f88705a 100644 --- a/plugins/module_utils/mh/module_helper.py +++ b/plugins/module_utils/mh/module_helper.py @@ -5,6 +5,7 @@ from __future__ import annotations +import typing as t 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.deprecate_attrs import DeprecateAttrsMixin +if t.TYPE_CHECKING: + from collections.abc import Sequence + class ModuleHelper(DeprecateAttrsMixin, ModuleHelperBase): - facts_name = None - output_params = () - diff_params = () - change_params = () - facts_params = () + facts_name: str | None = None + output_params: Sequence[str] = () + diff_params: Sequence[str] = () + change_params: Sequence[str] = () + facts_params: Sequence[str] = () def __init__(self, module=None): super(ModuleHelper, self).__init__(module) diff --git a/plugins/module_utils/scaleway.py b/plugins/module_utils/scaleway.py index 2804ef4e71..c4ad0016ed 100644 --- a/plugins/module_utils/scaleway.py +++ b/plugins/module_utils/scaleway.py @@ -19,12 +19,11 @@ from ansible_collections.community.general.plugins.module_utils.datetime import now, ) -SCALEWAY_SECRET_IMP_ERR = None +SCALEWAY_SECRET_IMP_ERR: str | None = None try: from passlib.hash import argon2 HAS_SCALEWAY_SECRET_PACKAGE = True except Exception: - argon2 = None SCALEWAY_SECRET_IMP_ERR = traceback.format_exc() HAS_SCALEWAY_SECRET_PACKAGE = False diff --git a/plugins/module_utils/univention_umc.py b/plugins/module_utils/univention_umc.py index 1475a91542..5f72927db1 100644 --- a/plugins/module_utils/univention_umc.py +++ b/plugins/module_utils/univention_umc.py @@ -53,7 +53,7 @@ __all__ = [ ] -_singletons = {} +_singletons: dict[str, object] = {} def ldap_module(): @@ -61,7 +61,7 @@ def ldap_module(): return orig_ldap -def _singleton(name, constructor): +def _singleton(name: str, constructor): if name in _singletons: return _singletons[name] _singletons[name] = constructor() diff --git a/plugins/modules/apt_rpm.py b/plugins/modules/apt_rpm.py index 4786ee6e84..2b49f845f7 100644 --- a/plugins/modules/apt_rpm.py +++ b/plugins/modules/apt_rpm.py @@ -129,6 +129,7 @@ from ansible.module_utils.basic import ( ) from ansible.module_utils.common.text.converters import to_native +RPM_PYTHON_IMPORT_ERROR: str | None try: import rpm except ImportError: diff --git a/plugins/modules/campfire.py b/plugins/modules/campfire.py index 1adf61c637..f9924bcc9b 100644 --- a/plugins/modules/campfire.py +++ b/plugins/modules/campfire.py @@ -114,14 +114,7 @@ EXAMPLES = r""" msg: Task completed ... with feeling. """ -try: - 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 html import escape as html_escape from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.urls import fetch_url diff --git a/plugins/modules/crypttab.py b/plugins/modules/crypttab.py index e325c1df7c..fe37e83b27 100644 --- a/plugins/modules/crypttab.py +++ b/plugins/modules/crypttab.py @@ -166,10 +166,11 @@ def main(): class Crypttab(object): - _lines = [] + _lines: list[str] def __init__(self, path): self.path = path + self._lines = [] if not os.path.exists(path): if not os.path.exists(os.path.dirname(path)): os.makedirs(os.path.dirname(path)) diff --git a/plugins/modules/filesystem.py b/plugins/modules/filesystem.py index 91448666a0..7d0b128fb5 100644 --- a/plugins/modules/filesystem.py +++ b/plugins/modules/filesystem.py @@ -201,16 +201,16 @@ class Device(object): class Filesystem(object): - MKFS = None - MKFS_FORCE_FLAGS = [] - MKFS_SET_UUID_OPTIONS = None - MKFS_SET_UUID_EXTRA_OPTIONS = [] - INFO = None - GROW = None - GROW_MAX_SPACE_FLAGS = [] + MKFS: str | None = None + MKFS_FORCE_FLAGS: list[str] | None = [] + MKFS_SET_UUID_OPTIONS: list[str] | None = None + MKFS_SET_UUID_EXTRA_OPTIONS: list[str] | None = [] + INFO: str | None = None + GROW: str | None = None + GROW_MAX_SPACE_FLAGS: list[str] | None = [] GROW_MOUNTPOINT_ONLY = False - CHANGE_UUID = None - CHANGE_UUID_OPTION = None + CHANGE_UUID: str | None = None + CHANGE_UUID_OPTION: str | None = None CHANGE_UUID_OPTION_HAS_ARG = True LANG_ENV = {'LANG': 'C', 'LC_ALL': 'C', 'LC_MESSAGES': 'C'} diff --git a/plugins/modules/homectl.py b/plugins/modules/homectl.py index fd54197883..9d42c2cba6 100644 --- a/plugins/modules/homectl.py +++ b/plugins/modules/homectl.py @@ -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.common.text.formatters import human_to_bytes +CRYPT_IMPORT_ERROR: str | None try: import crypt except ImportError: @@ -282,6 +283,7 @@ else: HAS_CRYPT = True CRYPT_IMPORT_ERROR = None +LEGACYCRYPT_IMPORT_ERROR: str | None try: import legacycrypt if not HAS_CRYPT: diff --git a/plugins/modules/htpasswd.py b/plugins/modules/htpasswd.py index cecf8e49c7..e8d7b918a2 100644 --- a/plugins/modules/htpasswd.py +++ b/plugins/modules/htpasswd.py @@ -112,7 +112,9 @@ from ansible.module_utils.common.text.converters import to_native 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 diff --git a/plugins/modules/jenkins_node.py b/plugins/modules/jenkins_node.py index 5257745ec6..a17bc51436 100644 --- a/plugins/modules/jenkins_node.py +++ b/plugins/modules/jenkins_node.py @@ -164,7 +164,7 @@ IS_PYTHON_2 = sys.version_info[0] <= 2 class JenkinsNode: - def __init__(self, module): + def __init__(self, module: AnsibleModule) -> None: self.module = module self.name = module.params['name'] @@ -174,7 +174,7 @@ class JenkinsNode: self.url = module.params['url'] self.num_executors = module.params['num_executors'] 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: self.offline_message = self.offline_message.strip() diff --git a/plugins/modules/pacemaker_info.py b/plugins/modules/pacemaker_info.py index d858a93d39..a9f065133f 100644 --- a/plugins/modules/pacemaker_info.py +++ b/plugins/modules/pacemaker_info.py @@ -74,7 +74,7 @@ class PacemakerInfo(ModuleHelper): "constraint_info": "constraint", "property_info": "property" } - output_params = info_vars.keys() + output_params = list(info_vars.keys()) def __init_module__(self): self.runner = pacemaker_runner(self.module) diff --git a/plugins/modules/pmem.py b/plugins/modules/pmem.py index 78b16dbc2d..e31a968cfc 100644 --- a/plugins/modules/pmem.py +++ b/plugins/modules/pmem.py @@ -209,6 +209,7 @@ import re import traceback from ansible.module_utils.basic import AnsibleModule, missing_required_lib, human_to_bytes +XMLTODICT_LIBRARY_IMPORT_ERROR: str | None try: import xmltodict except ImportError: diff --git a/plugins/modules/rhevm.py b/plugins/modules/rhevm.py index 647b278574..8156aed6df 100644 --- a/plugins/modules/rhevm.py +++ b/plugins/modules/rhevm.py @@ -347,7 +347,7 @@ RHEV_UNAVAILABLE = 2 RHEV_TYPE_OPTS = ['desktop', 'host', 'server'] STATE_OPTS = ['absent', 'cd', 'down', 'info', 'ping', 'present', 'restart', 'up'] -msg = [] +msg: list[str] = [] changed = False failed = False @@ -1258,7 +1258,7 @@ def setChanged(): changed = True -def setMsg(message): +def setMsg(message: str) -> None: msg.append(message) diff --git a/plugins/modules/udm_user.py b/plugins/modules/udm_user.py index 6556a5e1f4..1bcb8d4ef5 100644 --- a/plugins/modules/udm_user.py +++ b/plugins/modules/udm_user.py @@ -328,6 +328,7 @@ from ansible_collections.community.general.plugins.module_utils.univention_umc i base_dn, ) +CRYPT_IMPORT_ERROR: str | None try: import crypt except ImportError: @@ -337,6 +338,7 @@ else: HAS_CRYPT = True CRYPT_IMPORT_ERROR = None +LEGACYCRYPT_IMPORT_ERROR: str | None try: import legacycrypt if not HAS_CRYPT: diff --git a/plugins/plugin_utils/ansible_type.py b/plugins/plugin_utils/ansible_type.py index d9481b4c9a..9b413dbe16 100644 --- a/plugins/plugin_utils/ansible_type.py +++ b/plugins/plugin_utils/ansible_type.py @@ -10,8 +10,9 @@ from collections.abc import Mapping try: # Introduced with Data Tagging (https://github.com/ansible/ansible/pull/84621): from ansible.module_utils.datatag import native_type_name as _native_type_name + HAS_NATIVE_TYPE_NAME = True except ImportError: - _native_type_name = None + HAS_NATIVE_TYPE_NAME = 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. """ - if use_native_type and _native_type_name: + if use_native_type and HAS_NATIVE_TYPE_NAME: data_type = _native_type_name(data) else: data_type = type(data).__name__ diff --git a/plugins/test/a_module.py b/plugins/test/a_module.py index cf0fb0670a..bbe51a5883 100644 --- a/plugins/test/a_module.py +++ b/plugins/test/a_module.py @@ -43,7 +43,7 @@ from ansible.plugins.loader import action_loader, module_loader try: from ansible.errors import AnsiblePluginRemovedError except ImportError: - AnsiblePluginRemovedError = Exception + AnsiblePluginRemovedError = Exception # type: ignore def a_module(term): diff --git a/plugins/test/fqdn_valid.py b/plugins/test/fqdn_valid.py index 6c16342114..a0fd0c935e 100644 --- a/plugins/test/fqdn_valid.py +++ b/plugins/test/fqdn_valid.py @@ -65,6 +65,7 @@ _value: from ansible.errors import AnsibleError +ANOTHER_LIBRARY_IMPORT_ERROR: ImportError | None try: from fqdn import FQDN except ImportError as imp_exc: diff --git a/tests/unit/plugins/cache/test_redis.py b/tests/unit/plugins/cache/test_redis.py index 6ad7d1842e..6d4744be66 100644 --- a/tests/unit/plugins/cache/test_redis.py +++ b/tests/unit/plugins/cache/test_redis.py @@ -19,7 +19,7 @@ def test_redis_cachemodule(): 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 connection = '[::1]:6379:1' assert isinstance(cache_loader.get('community.general.redis', **{'_uri': connection}), RedisCache) diff --git a/tests/unit/plugins/module_utils/cloud/test_scaleway.py b/tests/unit/plugins/module_utils/cloud/test_scaleway.py index b5f97f5b95..93e68fc3b0 100644 --- a/tests/unit/plugins/module_utils/cloud/test_scaleway.py +++ b/tests/unit/plugins/module_utils/cloud/test_scaleway.py @@ -36,7 +36,7 @@ class SecretVariablesTestCase(unittest.TestCase): self.assertEqual(SecretVariables.list_to_dict(source, hashed=True), expect) - def test_list_to_dict(self): + def test_list_to_dict_2(self): source = [ dict(key="secret1", value="value1"), dict(key="secret2", value="value2") diff --git a/tests/unit/plugins/module_utils/test_csv.py b/tests/unit/plugins/module_utils/test_csv.py index a7fe674a0e..918413f77d 100644 --- a/tests/unit/plugins/module_utils/test_csv.py +++ b/tests/unit/plugins/module_utils/test_csv.py @@ -5,6 +5,8 @@ from __future__ import annotations +import typing as t + import pytest 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', {}, @@ -153,7 +155,7 @@ def test_invalid_csv(data, dialect, dialect_params, fieldnames): @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 try: diff --git a/tests/unit/plugins/module_utils/xenserver/test_gather_vm_params_and_facts.py b/tests/unit/plugins/module_utils/xenserver/test_gather_vm_params_and_facts.py index 8cfb267b93..cbe5249f48 100644 --- a/tests/unit/plugins/module_utils/xenserver/test_gather_vm_params_and_facts.py +++ b/tests/unit/plugins/module_utils/xenserver/test_gather_vm_params_and_facts.py @@ -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): """Tests return of empty dict on bad 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', - testcase_gather_vm_params_and_facts['params'], - ids=testcase_gather_vm_params_and_facts['ids'], + testcase_gather_vm_params_and_facts['params'], # type: ignore + ids=testcase_gather_vm_params_and_facts['ids'], # type: ignore indirect=True) 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.""" diff --git a/tests/unit/plugins/module_utils/xenserver/test_netaddr_functions.py b/tests/unit/plugins/module_utils/xenserver/test_netaddr_functions.py index 16cce00a1b..e070f77fee 100644 --- a/tests/unit/plugins/module_utils/xenserver/test_netaddr_functions.py +++ b/tests/unit/plugins/module_utils/xenserver/test_netaddr_functions.py @@ -157,13 +157,13 @@ def test_is_valid_ip_prefix(xenserver, ip_prefix, 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): """Tests ip prefix to netmask conversion.""" 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): """Tests ip netmask to prefix conversion.""" assert xenserver.ip_netmask_to_prefix(ip_netmask) == ip_prefix diff --git a/tests/unit/plugins/module_utils/xenserver/test_set_vm_power_state.py b/tests/unit/plugins/module_utils/xenserver/test_set_vm_power_state.py index af099e6478..a0f0b0ca65 100644 --- a/tests/unit/plugins/module_utils/xenserver/test_set_vm_power_state.py +++ b/tests/unit/plugins/module_utils/xenserver/test_set_vm_power_state.py @@ -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): """Tests failure on bad vm_ref.""" 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', - testcase_set_vm_power_state_bad_transitions['params'], - ids=testcase_set_vm_power_state_bad_transitions['ids']) + testcase_set_vm_power_state_bad_transitions['params'], # type: ignore + 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): """Tests failure on bad power state transition.""" 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', - testcase_set_vm_power_state_task_timeout['params'], - ids=testcase_set_vm_power_state_task_timeout['ids']) + testcase_set_vm_power_state_task_timeout['params'], # type: ignore + 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): """Tests failure on async task timeout.""" 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', - testcase_set_vm_power_state_no_transitions['params'], - ids=testcase_set_vm_power_state_no_transitions['ids']) + testcase_set_vm_power_state_no_transitions['params'], # type: ignore + 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): """Tests regular invocation without power state transition.""" 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', - testcase_set_vm_power_state_transitions['params'], - ids=testcase_set_vm_power_state_transitions['ids']) + testcase_set_vm_power_state_transitions['params'], # type: ignore + ids=testcase_set_vm_power_state_transitions['ids']) # type: ignore def test_set_vm_power_state_transition(mocker, fake_ansible_module, 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', - testcase_set_vm_power_state_transitions_async['params'], - ids=testcase_set_vm_power_state_transitions_async['ids']) + testcase_set_vm_power_state_transitions_async['params'], # type: ignore + ids=testcase_set_vm_power_state_transitions_async['ids']) # type: ignore def test_set_vm_power_state_transition_async(mocker, fake_ansible_module, 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', - testcase_set_vm_power_state_transitions['params'], - ids=testcase_set_vm_power_state_transitions['ids']) + testcase_set_vm_power_state_transitions['params'], # type: ignore + ids=testcase_set_vm_power_state_transitions['ids']) # type: ignore def test_set_vm_power_state_transition_check_mode(mocker, fake_ansible_module, XenAPI, diff --git a/tests/unit/plugins/module_utils/xenserver/test_wait_for_functions.py b/tests/unit/plugins/module_utils/xenserver/test_wait_for_functions.py index 6e117a27ce..7c934e8126 100644 --- a/tests/unit/plugins/module_utils/xenserver/test_wait_for_functions.py +++ b/tests/unit/plugins/module_utils/xenserver/test_wait_for_functions.py @@ -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): """Tests failure on bad vm_ref.""" 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', - testcase_wait_for_vm_ip_address_bad_guest_metrics['params'], - ids=testcase_wait_for_vm_ip_address_bad_guest_metrics['ids']) + testcase_wait_for_vm_ip_address_bad_guest_metrics['params'], # type: ignore + 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): """Tests timeout.""" 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] -@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): """Tests failure on bad task_ref.""" 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', - testcase_wait_for_task_all_statuses['params'], - ids=testcase_wait_for_task_all_statuses['ids']) + testcase_wait_for_task_all_statuses['params'], # type: ignore + ids=testcase_wait_for_task_all_statuses['ids']) # type: ignore def test_wait_for_task(mocker, fake_ansible_module, XenAPI, xenserver, task_status, result): """Tests regular invocation.""" mocked_xenapi = mocker.patch.object(XenAPI.Session, 'xenapi', create=True) diff --git a/tests/unit/plugins/module_utils/xenserver/test_xapi.py b/tests/unit/plugins/module_utils/xenserver/test_xapi.py index 509d2fee91..0dd4def027 100644 --- a/tests/unit/plugins/module_utils/xenserver/test_xapi.py +++ b/tests/unit/plugins/module_utils/xenserver/test_xapi.py @@ -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): """Tests that connection to localhost uses XenAPI.xapi_local() function.""" 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() -@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): """Tests that connection to localhost uses empty username and password.""" 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}" -@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): """Tests that explicit scheme in hostname param is preserved.""" 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) -@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): """Tests that proper scheme is prepended to hostname without scheme.""" mocker.patch('XenAPI.Session') diff --git a/tests/unit/plugins/modules/interfaces_file/test_interfaces_file.py b/tests/unit/plugins/modules/interfaces_file/test_interfaces_file.py index 5f91df758c..4f98fbe0e9 100644 --- a/tests/unit/plugins/modules/interfaces_file/test_interfaces_file.py +++ b/tests/unit/plugins/modules/interfaces_file/test_interfaces_file.py @@ -373,7 +373,7 @@ class TestInterfacesFileModule(unittest.TestCase): iface_options = interfaces_file.get_interface_options(testcases[testname]["iface_lines"]) self.assertEqual(testcases[testname]["iface_options"], iface_options) - def test_get_interface_options(self): + def test_get_interface_options_2(self): testcases = { "select address": { "iface_options": [ diff --git a/tests/unit/plugins/modules/test_archive.py b/tests/unit/plugins/modules/test_archive.py index e14d6e9af9..187590f158 100644 --- a/tests/unit/plugins/modules/test_archive.py +++ b/tests/unit/plugins/modules/test_archive.py @@ -56,7 +56,7 @@ class TestArchive(ModuleTestCase): ) -PATHS = ( +PATHS: tuple[tuple[list[str | bytes], str | bytes], ...] = ( ([], ''), (['/'], '/'), ([b'/'], b'/'), @@ -68,5 +68,5 @@ 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 diff --git a/tests/unit/plugins/modules/test_gitlab_deploy_key.py b/tests/unit/plugins/modules/test_gitlab_deploy_key.py index b83c8e9c7a..3f194a6f7c 100644 --- a/tests/unit/plugins/modules/test_gitlab_deploy_key.py +++ b/tests/unit/plugins/modules/test_gitlab_deploy_key.py @@ -29,7 +29,7 @@ try: except ImportError: 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 - GitlabModuleTestCase = object + GitlabModuleTestCase = object # type: ignore resp_get_project = _dummy resp_find_project_deploy_key = _dummy resp_create_project_deploy_key = _dummy diff --git a/tests/unit/plugins/modules/test_gitlab_group.py b/tests/unit/plugins/modules/test_gitlab_group.py index 898405ac18..baf782a254 100644 --- a/tests/unit/plugins/modules/test_gitlab_group.py +++ b/tests/unit/plugins/modules/test_gitlab_group.py @@ -29,7 +29,7 @@ try: except ImportError: 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 - GitlabModuleTestCase = object + GitlabModuleTestCase = object # type: ignore resp_get_group = _dummy resp_get_missing_group = _dummy resp_create_group = _dummy @@ -58,7 +58,7 @@ class TestGitlabGroup(GitlabModuleTestCase): self.assertEqual(rvalue, True) @with_httmock(resp_get_missing_group) - def test_exist_group(self): + def test_exist_group_2(self): rvalue = self.moduleUtil.exists_group(1) self.assertEqual(rvalue, False) diff --git a/tests/unit/plugins/modules/test_gitlab_group_access_token.py b/tests/unit/plugins/modules/test_gitlab_group_access_token.py index 24417f9200..f3ffd382df 100644 --- a/tests/unit/plugins/modules/test_gitlab_group_access_token.py +++ b/tests/unit/plugins/modules/test_gitlab_group_access_token.py @@ -36,7 +36,7 @@ try: except ImportError: 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 - GitlabModuleTestCase = object + GitlabModuleTestCase = object # type: ignore resp_list_group_access_tokens = _dummy resp_create_group_access_tokens = _dummy resp_revoke_group_access_tokens = _dummy diff --git a/tests/unit/plugins/modules/test_gitlab_hook.py b/tests/unit/plugins/modules/test_gitlab_hook.py index b28745f76d..633cd43df3 100644 --- a/tests/unit/plugins/modules/test_gitlab_hook.py +++ b/tests/unit/plugins/modules/test_gitlab_hook.py @@ -29,7 +29,7 @@ try: except ImportError: 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 - GitlabModuleTestCase = object + GitlabModuleTestCase = object # type: ignore resp_get_project = _dummy resp_find_project_hook = _dummy resp_create_project_hook = _dummy diff --git a/tests/unit/plugins/modules/test_gitlab_project.py b/tests/unit/plugins/modules/test_gitlab_project.py index fd38c21af9..b38d8b862d 100644 --- a/tests/unit/plugins/modules/test_gitlab_project.py +++ b/tests/unit/plugins/modules/test_gitlab_project.py @@ -29,7 +29,7 @@ try: except ImportError: 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 - GitlabModuleTestCase = object + GitlabModuleTestCase = object # type: ignore resp_get_group = _dummy resp_get_project_by_name = _dummy resp_create_project = _dummy diff --git a/tests/unit/plugins/modules/test_gitlab_project_access_token.py b/tests/unit/plugins/modules/test_gitlab_project_access_token.py index 5077fa81bf..138d462e48 100644 --- a/tests/unit/plugins/modules/test_gitlab_project_access_token.py +++ b/tests/unit/plugins/modules/test_gitlab_project_access_token.py @@ -36,7 +36,7 @@ try: except ImportError: 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 - GitlabModuleTestCase = object + GitlabModuleTestCase = object # type: ignore resp_list_project_access_tokens = _dummy resp_create_project_access_tokens = _dummy resp_revoke_project_access_tokens = _dummy diff --git a/tests/unit/plugins/modules/test_gitlab_runner.py b/tests/unit/plugins/modules/test_gitlab_runner.py index 4ef39c9558..29dcb6f8e7 100644 --- a/tests/unit/plugins/modules/test_gitlab_runner.py +++ b/tests/unit/plugins/modules/test_gitlab_runner.py @@ -35,7 +35,7 @@ try: except ImportError: 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 - GitlabModuleTestCase = object + GitlabModuleTestCase = object # type: ignore resp_find_runners_list = _dummy resp_get_runner = _dummy resp_create_runner = _dummy diff --git a/tests/unit/plugins/modules/test_gitlab_user.py b/tests/unit/plugins/modules/test_gitlab_user.py index 462546d058..e2e68465d1 100644 --- a/tests/unit/plugins/modules/test_gitlab_user.py +++ b/tests/unit/plugins/modules/test_gitlab_user.py @@ -31,7 +31,7 @@ try: except ImportError: 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 - GitlabModuleTestCase = object + GitlabModuleTestCase = object # type: ignore resp_find_user = _dummy resp_get_user = _dummy resp_get_user_keys = _dummy diff --git a/tests/unit/plugins/modules/test_nmcli.py b/tests/unit/plugins/modules/test_nmcli.py index 7733500f76..ed840b397c 100644 --- a/tests/unit/plugins/modules/test_nmcli.py +++ b/tests/unit/plugins/modules/test_nmcli.py @@ -1640,11 +1640,12 @@ def mocked_generic_connection_modify(mocker): changed_return=(True, dict())) -@pytest.fixture -def mocked_generic_connection_unchanged(mocker): - mocker_set(mocker, - connection_exists=True, - execute_return=(0, TESTCASE_GENERIC_SHOW_OUTPUT, "")) +# TODO: overridden below! +# @pytest.fixture +# def mocked_generic_connection_unchanged(mocker): +# mocker_set(mocker, +# connection_exists=True, +# execute_return=(0, TESTCASE_GENERIC_SHOW_OUTPUT, "")) @pytest.fixture @@ -2104,6 +2105,7 @@ def test_bond_connection_create(mocked_generic_connection_create, capfd): assert results['changed'] +@pytest.mark.skip(reason="Currently broken") # TODO: fix me! @pytest.mark.parametrize('patch_ansible_module', TESTCASE_BOND, indirect=['patch_ansible_module']) 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']) -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 """ @@ -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']) -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 """ @@ -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']) -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 """ diff --git a/tests/unit/plugins/modules/test_pacman.py b/tests/unit/plugins/modules/test_pacman.py index b1ca5e9cf5..39e5cc4fa6 100644 --- a/tests/unit/plugins/modules/test_pacman.py +++ b/tests/unit/plugins/modules/test_pacman.py @@ -4,6 +4,7 @@ from __future__ import annotations +import typing as t from unittest import mock from ansible.module_utils import basic 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": {}, "available_pkgs": {}, "installed_groups": {}, diff --git a/tests/unit/plugins/modules/test_pacman_key.py b/tests/unit/plugins/modules/test_pacman_key.py index 795ff1cfae..550336c8b7 100644 --- a/tests/unit/plugins/modules/test_pacman_key.py +++ b/tests/unit/plugins/modules/test_pacman_key.py @@ -682,7 +682,7 @@ def patch_get_bin_path(mocker): @pytest.mark.parametrize( 'patch_ansible_module, expected', TESTCASES, - ids=[item[1]['id'] for item in TESTCASES], + ids=[item[1]['id'] for item in TESTCASES], # type: ignore indirect=['patch_ansible_module'] ) @pytest.mark.usefixtures('patch_ansible_module') diff --git a/tests/unit/plugins/modules/test_redhat_subscription.py b/tests/unit/plugins/modules/test_redhat_subscription.py index e7b7d67f92..1edc8e6840 100644 --- a/tests/unit/plugins/modules/test_redhat_subscription.py +++ b/tests/unit/plugins/modules/test_redhat_subscription.py @@ -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']) @@ -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']) diff --git a/tests/unit/plugins/modules/test_rhsm_repository.py b/tests/unit/plugins/modules/test_rhsm_repository.py index 31b4a48a28..eb920a21e6 100644 --- a/tests/unit/plugins/modules/test_rhsm_repository.py +++ b/tests/unit/plugins/modules/test_rhsm_repository.py @@ -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']) diff --git a/tests/unit/plugins/modules/test_xcc_redfish_command.py b/tests/unit/plugins/modules/test_xcc_redfish_command.py index 83eb2a0110..14c1011346 100644 --- a/tests/unit/plugins/modules/test_xcc_redfish_command.py +++ b/tests/unit/plugins/modules/test_xcc_redfish_command.py @@ -436,7 +436,7 @@ class TestXCCRedfishCommand(unittest.TestCase): with self.assertRaises(AnsibleFailJson) as result: 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({ 'category': 'Raw', 'command': 'PostResource', diff --git a/tests/unit/plugins/modules/test_xenserver_guest_info.py b/tests/unit/plugins/modules/test_xenserver_guest_info.py index e34d1fdd3d..30c73812ab 100644 --- a/tests/unit/plugins/modules/test_xenserver_guest_info.py +++ b/tests/unit/plugins/modules/test_xenserver_guest_info.py @@ -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): """ Tests regular module invocation including parsing and propagation of diff --git a/tests/unit/plugins/modules/test_xenserver_guest_powerstate.py b/tests/unit/plugins/modules/test_xenserver_guest_powerstate.py index fd809d1fa9..811d44700d 100644 --- a/tests/unit/plugins/modules/test_xenserver_guest_powerstate.py +++ b/tests/unit/plugins/modules/test_xenserver_guest_powerstate.py @@ -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): """Tests power state change handling.""" 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', - testcase_module_params_state_present['params'], - ids=testcase_module_params_state_present['ids'], + testcase_module_params_state_present['params'], # type: ignore + ids=testcase_module_params_state_present['ids'], # type: ignore indirect=True) 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', - testcase_module_params_state_other['params'], - ids=testcase_module_params_state_other['ids'], + testcase_module_params_state_other['params'], # type: ignore + ids=testcase_module_params_state_other['ids'], # type: ignore indirect=True) 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', - testcase_module_params_wait['params'], - ids=testcase_module_params_wait['ids'], + testcase_module_params_wait['params'], # type: ignore + ids=testcase_module_params_wait['ids'], # type: ignore indirect=True) def test_xenserver_guest_powerstate_wait(mocker, patch_ansible_module, capfd, XenAPI, xenserver_guest_powerstate): """