diff --git a/.pylintrc b/.pylintrc index 8f3dceb3..5d2837de 100644 --- a/.pylintrc +++ b/.pylintrc @@ -379,18 +379,12 @@ disable=raw-checker-failed, wrong-import-order, wrong-import-position, # To clean up: - arguments-differ, - consider-using-with, fixme, import-error, # TODO figure out why pylint cannot find the module - no-member, no-name-in-module, # TODO figure out why pylint cannot find the module - not-an-iterable, # TODO: needs better typing info protected-access, - redefined-outer-name, # needed for test fixtures subprocess-popen-preexec-fn, unexpected-keyword-arg, - unsupported-assignment-operation, # TODO: needs better typing info unused-argument, # Cannot remove yet due to inadequacy of rules inconsistent-return-statements, # doesn't notice that fail_json() does not return diff --git a/plugins/action/docker_container_copy_into.py b/plugins/action/docker_container_copy_into.py index ca11d553..25306d43 100644 --- a/plugins/action/docker_container_copy_into.py +++ b/plugins/action/docker_container_copy_into.py @@ -29,6 +29,7 @@ class ActionModule(ActionBase): result = super().run(tmp, task_vars) del tmp # tmp no longer has any effect + # pylint: disable-next=no-member max_file_size_for_diff: int = C.MAX_FILE_SIZE_FOR_DIFF # type: ignore self._task.args["_max_file_size_for_diff"] = max_file_size_for_diff diff --git a/plugins/connection/docker.py b/plugins/connection/docker.py index fe66e653..cc0cf461 100644 --- a/plugins/connection/docker.py +++ b/plugins/connection/docker.py @@ -123,7 +123,7 @@ from shlex import quote from ansible.errors import AnsibleConnectionFailure, AnsibleError, AnsibleFileNotFound from ansible.module_utils.common.process import get_bin_path -from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text +from ansible.module_utils.common.text.converters import to_bytes, to_text from ansible.plugins.connection import BUFSIZE, ConnectionBase from ansible.utils.display import Display @@ -188,7 +188,7 @@ class Connection(ConnectionBase): ) as p: cmd_output, err = p.communicate() - return old_docker_cmd, to_native(cmd_output), err, p.returncode + return old_docker_cmd, to_text(cmd_output), err, p.returncode def _new_docker_version(self) -> tuple[list[str], str, bytes, int]: # no result yet, must be newer Docker version @@ -201,7 +201,7 @@ class Connection(ConnectionBase): new_docker_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) as p: cmd_output, err = p.communicate() - return new_docker_cmd, to_native(cmd_output), err, p.returncode + return new_docker_cmd, to_text(cmd_output), err, p.returncode def _get_docker_version(self) -> str: cmd, cmd_output, err, returncode = self._old_docker_version() @@ -213,7 +213,7 @@ class Connection(ConnectionBase): cmd, cmd_output, err, returncode = self._new_docker_version() if returncode: raise AnsibleError( - f"Docker version check ({to_native(cmd)}) failed: {to_native(err)}" + f"Docker version check ({to_text(cmd)}) failed: {to_text(err)}" ) return self._sanitize_version(to_text(cmd_output, errors="surrogate_or_strict")) @@ -427,7 +427,7 @@ class Connection(ConnectionBase): stdout, stderr = p.communicate() raise AnsibleError( "timeout waiting for privilege escalation password prompt:\n" - + to_native(become_output) + + to_text(become_output) ) chunks = b"" @@ -445,7 +445,7 @@ class Connection(ConnectionBase): stdout, stderr = p.communicate() raise AnsibleError( "privilege output closed while waiting for password prompt:\n" - + to_native(become_output) + + to_text(become_output) ) become_output += chunks finally: @@ -503,7 +503,7 @@ class Connection(ConnectionBase): out_path = self._prefix_login_path(out_path) if not os.path.exists(to_bytes(in_path, errors="surrogate_or_strict")): raise AnsibleFileNotFound( - f"file or module does not exist: {to_native(in_path)}" + f"file or module does not exist: {to_text(in_path)}" ) out_path = quote(out_path) @@ -525,6 +525,7 @@ class Connection(ConnectionBase): ) args = [to_bytes(i, errors="surrogate_or_strict") for i in args] try: + # pylint: disable-next=consider-using-with p = subprocess.Popen( args, stdin=in_file, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) @@ -536,7 +537,7 @@ class Connection(ConnectionBase): if p.returncode != 0: raise AnsibleError( - f"failed to transfer file {to_native(in_path)} to {to_native(out_path)}:\n{to_native(stdout)}\n{to_native(stderr)}" + f"failed to transfer file {to_text(in_path)} to {to_text(out_path)}:\n{to_text(stdout)}\n{to_text(stderr)}" ) def fetch_file(self, in_path: str, out_path: str) -> None: @@ -587,6 +588,7 @@ class Connection(ConnectionBase): to_bytes(actual_out_path, errors="surrogate_or_strict"), "wb" ) as out_file: try: + # pylint: disable-next=consider-using-with pp = subprocess.Popen( args, stdin=subprocess.PIPE, diff --git a/plugins/connection/docker_api.py b/plugins/connection/docker_api.py index bce216ab..3fd1f3e4 100644 --- a/plugins/connection/docker_api.py +++ b/plugins/connection/docker_api.py @@ -110,7 +110,7 @@ import os.path import typing as t from ansible.errors import AnsibleConnectionFailure, AnsibleFileNotFound -from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text +from ansible.module_utils.common.text.converters import to_bytes, to_text from ansible.plugins.connection import ConnectionBase from ansible.utils.display import Display @@ -335,13 +335,13 @@ class Connection(ConnectionBase): stdout, stderr = exec_socket_handler.consume() raise AnsibleConnectionFailure( "timeout waiting for privilege escalation password prompt:\n" - + to_native(become_output[0]) + + to_text(become_output[0]) ) if exec_socket_handler.is_eof(): raise AnsibleConnectionFailure( "privilege output closed while waiting for password prompt:\n" - + to_native(become_output[0]) + + to_text(become_output[0]) ) if not self.become.check_success(become_output[0]): @@ -437,9 +437,9 @@ class Connection(ConnectionBase): not_found_can_be_resource=True, ) except DockerFileNotFound as exc: - raise AnsibleFileNotFound(to_native(exc)) from exc + raise AnsibleFileNotFound(to_text(exc)) from exc except DockerFileCopyError as exc: - raise AnsibleConnectionFailure(to_native(exc)) from exc + raise AnsibleConnectionFailure(to_text(exc)) from exc def fetch_file(self, in_path: str, out_path: str) -> None: """Fetch a file from container to local.""" @@ -468,9 +468,9 @@ class Connection(ConnectionBase): not_found_can_be_resource=True, ) except DockerFileNotFound as exc: - raise AnsibleFileNotFound(to_native(exc)) from exc + raise AnsibleFileNotFound(to_text(exc)) from exc except DockerFileCopyError as exc: - raise AnsibleConnectionFailure(to_native(exc)) from exc + raise AnsibleConnectionFailure(to_text(exc)) from exc def close(self) -> None: """Terminate the connection. Nothing to do for Docker""" diff --git a/plugins/connection/nsenter.py b/plugins/connection/nsenter.py index 57b39c3a..41833649 100644 --- a/plugins/connection/nsenter.py +++ b/plugins/connection/nsenter.py @@ -50,7 +50,7 @@ import typing as t import ansible.constants as C from ansible.errors import AnsibleError -from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text +from ansible.module_utils.common.text.converters import to_bytes, to_text from ansible.plugins.connection import ConnectionBase from ansible.utils.display import Display from ansible.utils.path import unfrackpath @@ -92,6 +92,7 @@ class Connection(ConnectionBase): display.debug("in nsenter.exec_command()") + # pylint: disable-next=no-member def_executable: str | None = C.DEFAULT_EXECUTABLE # type: ignore[attr-defined] executable = def_executable.split()[0] if def_executable else None @@ -178,7 +179,7 @@ class Connection(ConnectionBase): stdout, stderr = p.communicate() raise AnsibleError( "timeout waiting for privilege escalation password prompt:\n" - + to_native(become_output) + + to_text(become_output) ) chunks = b"" @@ -196,7 +197,7 @@ class Connection(ConnectionBase): stdout, stderr = p.communicate() raise AnsibleError( "privilege output closed while waiting for password prompt:\n" - + to_native(become_output) + + to_text(become_output) ) become_output += chunks finally: @@ -279,7 +280,7 @@ class Connection(ConnectionBase): out_file.write(out) except IOError as e: raise AnsibleError( - f"failed to transfer file to {to_native(out_path)}: {e}" + f"failed to transfer file to {to_text(out_path)}: {e}" ) from e def close(self) -> None: diff --git a/plugins/inventory/docker_machine.py b/plugins/inventory/docker_machine.py index e9ccca1b..f3e539c0 100644 --- a/plugins/inventory/docker_machine.py +++ b/plugins/inventory/docker_machine.py @@ -105,7 +105,7 @@ import typing as t from ansible.errors import AnsibleError from ansible.module_utils.common.process import get_bin_path -from ansible.module_utils.common.text.converters import to_native, to_text +from ansible.module_utils.common.text.converters import to_text from ansible.plugins.inventory import BaseInventoryPlugin, Cacheable, Constructable from ansible.utils.display import Display from ansible_collections.community.library_inventory_filtering_v1.plugins.plugin_utils.inventory_filter import ( @@ -142,7 +142,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable): try: self.docker_machine_path = get_bin_path("docker-machine") except ValueError as e: - raise AnsibleError(to_native(e)) from e + raise AnsibleError(to_text(e)) from e command = [self.docker_machine_path] command.extend(args) diff --git a/plugins/module_utils/_api/api/client.py b/plugins/module_utils/_api/api/client.py index 622b4539..2457dfea 100644 --- a/plugins/module_utils/_api/api/client.py +++ b/plugins/module_utils/_api/api/client.py @@ -652,6 +652,8 @@ class APIClient(_Session): def get_adapter(self, url: str) -> BaseAdapter: try: + # pylint finds our Session stub instead of requests.Session: + # pylint: disable-next=no-member return super().get_adapter(url) except _InvalidSchema as e: if self._custom_adapter: diff --git a/plugins/module_utils/_api/errors.py b/plugins/module_utils/_api/errors.py index cd62ba5e..ad09531a 100644 --- a/plugins/module_utils/_api/errors.py +++ b/plugins/module_utils/_api/errors.py @@ -13,7 +13,7 @@ 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_text from ._import_helper import HTTPError as _HTTPError @@ -39,7 +39,7 @@ def create_api_error_from_http_exception(e: _HTTPError) -> t.NoReturn: try: explanation = response.json()["message"] except ValueError: - explanation = to_native((response.content or "").strip()) + explanation = to_text((response.content or "").strip()) cls = APIError if response.status_code == 404: if explanation and ( diff --git a/plugins/module_utils/_api/transport/basehttpadapter.py b/plugins/module_utils/_api/transport/basehttpadapter.py index 90239199..53dc5e3e 100644 --- a/plugins/module_utils/_api/transport/basehttpadapter.py +++ b/plugins/module_utils/_api/transport/basehttpadapter.py @@ -16,6 +16,8 @@ from .._import_helper import HTTPAdapter as _HTTPAdapter class BaseHTTPAdapter(_HTTPAdapter): def close(self) -> None: + # pylint finds our HTTPAdapter stub instead of requests.adapters.HTTPAdapter: + # pylint: disable-next=no-member super().close() if hasattr(self, "pools"): self.pools.clear() diff --git a/plugins/module_utils/_api/transport/ssladapter.py b/plugins/module_utils/_api/transport/ssladapter.py index 3d1d674e..8c6c728a 100644 --- a/plugins/module_utils/_api/transport/ssladapter.py +++ b/plugins/module_utils/_api/transport/ssladapter.py @@ -58,7 +58,11 @@ class SSLHTTPAdapter(BaseHTTPAdapter): We already take care of a normal poolmanager via init_poolmanager But we still need to take care of when there is a proxy poolmanager + + Note that this method is no longer called for newer requests versions. """ + # pylint finds our HTTPAdapter stub instead of requests.adapters.HTTPAdapter: + # pylint: disable-next=no-member conn = super().get_connection(*args, **kwargs) if ( self.assert_hostname is not None diff --git a/plugins/module_utils/_api/utils/build.py b/plugins/module_utils/_api/utils/build.py index f87204c1..b46cc32a 100644 --- a/plugins/module_utils/_api/utils/build.py +++ b/plugins/module_utils/_api/utils/build.py @@ -97,49 +97,50 @@ def create_archive( ) -> t.IO[bytes]: extra_files = extra_files or [] if not fileobj: + # pylint: disable-next=consider-using-with fileobj = tempfile.NamedTemporaryFile() - t = tarfile.open(mode="w:gz" if gzip else "w", fileobj=fileobj) - if files is None: - files = build_file_list(root) - extra_names = set(e[0] for e in extra_files) - for path in files: - if path in extra_names: - # Extra files override context files with the same name - continue - full_path = os.path.join(root, path) - i = t.gettarinfo(full_path, arcname=path) - if i is None: - # This happens when we encounter a socket file. We can safely - # ignore it and proceed. - continue # type: ignore + with tarfile.open(mode="w:gz" if gzip else "w", fileobj=fileobj) as tarf: + if files is None: + files = build_file_list(root) + extra_names = set(e[0] for e in extra_files) + for path in files: + if path in extra_names: + # Extra files override context files with the same name + continue + full_path = os.path.join(root, path) - # Workaround https://bugs.python.org/issue32713 - if i.mtime < 0 or i.mtime > 8**11 - 1: - i.mtime = int(i.mtime) + i = tarf.gettarinfo(full_path, arcname=path) + if i is None: + # This happens when we encounter a socket file. We can safely + # ignore it and proceed. + continue # type: ignore - if IS_WINDOWS_PLATFORM: - # Windows does not keep track of the execute bit, so we make files - # and directories executable by default. - i.mode = i.mode & 0o755 | 0o111 + # Workaround https://bugs.python.org/issue32713 + if i.mtime < 0 or i.mtime > 8**11 - 1: + i.mtime = int(i.mtime) - if i.isfile(): - try: - with open(full_path, "rb") as f: - t.addfile(i, f) - except IOError as exc: - raise IOError(f"Can not read file in context: {full_path}") from exc - else: - # Directories, FIFOs, symlinks... do not need to be read. - t.addfile(i, None) + if IS_WINDOWS_PLATFORM: + # Windows does not keep track of the execute bit, so we make files + # and directories executable by default. + i.mode = i.mode & 0o755 | 0o111 - for name, contents in extra_files: - info = tarfile.TarInfo(name) - contents_encoded = contents.encode("utf-8") - info.size = len(contents_encoded) - t.addfile(info, io.BytesIO(contents_encoded)) + if i.isfile(): + try: + with open(full_path, "rb") as f: + tarf.addfile(i, f) + except IOError as exc: + raise IOError(f"Can not read file in context: {full_path}") from exc + else: + # Directories, FIFOs, symlinks... do not need to be read. + tarf.addfile(i, None) + + for name, contents in extra_files: + info = tarfile.TarInfo(name) + contents_encoded = contents.encode("utf-8") + info.size = len(contents_encoded) + tarf.addfile(info, io.BytesIO(contents_encoded)) - t.close() fileobj.seek(0) return fileobj @@ -147,7 +148,7 @@ def create_archive( def mkbuildcontext(dockerfile: io.BytesIO | t.IO[bytes]) -> t.IO[bytes]: f = tempfile.NamedTemporaryFile() # pylint: disable=consider-using-with try: - with tarfile.open(mode="w", fileobj=f) as t: + with tarfile.open(mode="w", fileobj=f) as tarf: if isinstance(dockerfile, io.StringIO): # type: ignore raise TypeError("Please use io.BytesIO to create in-memory Dockerfiles") if isinstance(dockerfile, io.BytesIO): @@ -155,8 +156,8 @@ def mkbuildcontext(dockerfile: io.BytesIO | t.IO[bytes]) -> t.IO[bytes]: dfinfo.size = len(dockerfile.getvalue()) dockerfile.seek(0) else: - dfinfo = t.gettarinfo(fileobj=dockerfile, arcname="Dockerfile") - t.addfile(dfinfo, dockerfile) + dfinfo = tarf.gettarinfo(fileobj=dockerfile, arcname="Dockerfile") + tarf.addfile(dfinfo, dockerfile) f.seek(0) except Exception: # noqa: E722 f.close() diff --git a/plugins/module_utils/_common_cli.py b/plugins/module_utils/_common_cli.py index 26bd3a70..36484880 100644 --- a/plugins/module_utils/_common_cli.py +++ b/plugins/module_utils/_common_cli.py @@ -14,7 +14,7 @@ import typing as t from ansible.module_utils.basic import AnsibleModule, env_fallback from ansible.module_utils.common.process import get_bin_path -from ansible.module_utils.common.text.converters import to_native +from ansible.module_utils.common.text.converters import to_text from ansible_collections.community.docker.plugins.module_utils._api.auth import ( resolve_repository_name, @@ -132,9 +132,7 @@ class AnsibleDockerClientBase: self.fail( "Cannot determine Docker Daemon information. Are you maybe using podman instead of docker?" ) - self.docker_api_version_str = to_native( - self._version["Server"]["ApiVersion"] - ) + self.docker_api_version_str = to_text(self._version["Server"]["ApiVersion"]) self.docker_api_version = LooseVersion(self.docker_api_version_str) min_docker_api_version = min_docker_api_version or "1.25" if self.docker_api_version < LooseVersion(min_docker_api_version): @@ -191,12 +189,12 @@ class AnsibleDockerClientBase: *args, check_rc=check_rc, data=data, cwd=cwd, environ_update=environ_update ) if warn_on_stderr and stderr: - self.warn(to_native(stderr)) + self.warn(to_text(stderr)) try: data = json.loads(stdout) except Exception as exc: # pylint: disable=broad-exception-caught self.fail( - f"Error while parsing JSON output of {self._compose_cmd_str(args)}: {exc}\nJSON output: {to_native(stdout)}" + f"Error while parsing JSON output of {self._compose_cmd_str(args)}: {exc}\nJSON output: {to_text(stdout)}" ) return rc, data, stderr @@ -213,7 +211,7 @@ class AnsibleDockerClientBase: *args, check_rc=check_rc, data=data, cwd=cwd, environ_update=environ_update ) if warn_on_stderr and stderr: - self.warn(to_native(stderr)) + self.warn(to_text(stderr)) result = [] try: for line in stdout.splitlines(): @@ -222,7 +220,7 @@ class AnsibleDockerClientBase: result.append(json.loads(line)) except Exception as exc: # pylint: disable=broad-exception-caught self.fail( - f"Error while parsing JSON output of {self._compose_cmd_str(args)}: {exc}\nJSON output: {to_native(stdout)}" + f"Error while parsing JSON output of {self._compose_cmd_str(args)}: {exc}\nJSON output: {to_text(stdout)}" ) return rc, result, stderr @@ -338,7 +336,7 @@ class AnsibleDockerClientBase: self.log(f"Image {name}:{tag} not found.") return None if rc != 0: - self.fail(f"Error inspecting image {name}:{tag} - {to_native(stderr)}") + self.fail(f"Error inspecting image {name}:{tag} - {to_text(stderr)}") return image[0] self.log(f"Image {name}:{tag} not found.") @@ -367,11 +365,11 @@ class AnsibleDockerClientBase: rc, image, stderr = self.call_cli_json("image", "inspect", image_id) if not image: if not accept_missing_image: - self.fail(f"Error inspecting image ID {image_id} - {to_native(stderr)}") + self.fail(f"Error inspecting image ID {image_id} - {to_text(stderr)}") self.log(f"Image {image_id} not found.") return None if rc != 0: - self.fail(f"Error inspecting image ID {image_id} - {to_native(stderr)}") + self.fail(f"Error inspecting image ID {image_id} - {to_text(stderr)}") return image[0] diff --git a/plugins/module_utils/_compose_v2.py b/plugins/module_utils/_compose_v2.py index 4fdb1014..d3564629 100644 --- a/plugins/module_utils/_compose_v2.py +++ b/plugins/module_utils/_compose_v2.py @@ -19,7 +19,7 @@ from collections import namedtuple from shlex import quote from ansible.module_utils.basic import missing_required_lib -from ansible.module_utils.common.text.converters import to_native +from ansible.module_utils.common.text.converters import to_text from ansible_collections.community.docker.plugins.module_utils._logfmt import ( InvalidLogFmt as _InvalidLogFmt, @@ -418,7 +418,7 @@ def parse_json_events( ResourceType.UNKNOWN, None, "Warning", - to_native(line[len(b"Warning: ") :]), + to_text(line[len(b"Warning: ") :]), ) events.append(event) continue @@ -557,7 +557,7 @@ def parse_events( if stderr_lines and stderr_lines[-1] == b"": del stderr_lines[-1] for index, line in enumerate(stderr_lines): - line = to_native(line.strip()) + line = to_text(line.strip()) if not line: continue warn_missing_dry_run_prefix = False @@ -731,8 +731,8 @@ def update_failed( result["failed"] = True result["msg"] = "\n".join(errors) result["cmd"] = " ".join(quote(arg) for arg in [cli] + args) - result["stdout"] = to_native(stdout) - result["stderr"] = to_native(stderr) + result["stdout"] = to_text(stdout) + result["stderr"] = to_text(stderr) result["rc"] = rc return True @@ -978,8 +978,8 @@ class BaseComposeManager(DockerBaseClass): ignore_build_events=ignore_build_events, ) result["actions"] = result.get("actions", []) + extract_actions(events) - result["stdout"] = combine_text_output(result.get("stdout"), to_native(stdout)) - result["stderr"] = combine_text_output(result.get("stderr"), to_native(stderr)) + result["stdout"] = combine_text_output(result.get("stdout"), to_text(stdout)) + result["stderr"] = combine_text_output(result.get("stderr"), to_text(stderr)) def update_failed( self, diff --git a/plugins/module_utils/_copy.py b/plugins/module_utils/_copy.py index 2e3ee6ab..8f520885 100644 --- a/plugins/module_utils/_copy.py +++ b/plugins/module_utils/_copy.py @@ -18,7 +18,7 @@ import stat import tarfile import typing as t -from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text +from ansible.module_utils.common.text.converters import to_bytes, to_text from ansible_collections.community.docker.plugins.module_utils._api.errors import ( APIError, @@ -223,7 +223,7 @@ def put_file( ) -> None: """Transfer a file from local to Docker container.""" if not os.path.exists(to_bytes(in_path, errors="surrogate_or_strict")): - raise DockerFileNotFound(f"file or module does not exist: {to_native(in_path)}") + raise DockerFileNotFound(f"file or module does not exist: {to_text(in_path)}") b_in_path = to_bytes(in_path, errors="surrogate_or_strict") diff --git a/plugins/module_utils/_module_container/base.py b/plugins/module_utils/_module_container/base.py index 82842789..e527b377 100644 --- a/plugins/module_utils/_module_container/base.py +++ b/plugins/module_utils/_module_container/base.py @@ -790,17 +790,17 @@ def _preprocess_mounts( ) -> dict[str, t.Any]: last: dict[str, str] = {} - def check_collision(t: str, name: str) -> None: - if t in last: - if name == last[t]: + def check_collision(target: str, name: str) -> None: + if target in last: + if name == last[target]: module.fail_json( - msg=f'The mount point "{t}" appears twice in the {name} option' + msg=f'The mount point "{target}" appears twice in the {name} option' ) else: module.fail_json( - msg=f'The mount point "{t}" appears both in the {name} and {last[t]} option' + msg=f'The mount point "{target}" appears both in the {name} and {last[target]} option' ) - last[t] = name + last[target] = name if "mounts" in values: mounts = [] diff --git a/plugins/module_utils/_scramble.py b/plugins/module_utils/_scramble.py index fa4b6dc2..db05ecf8 100644 --- a/plugins/module_utils/_scramble.py +++ b/plugins/module_utils/_scramble.py @@ -10,7 +10,7 @@ from __future__ import annotations import base64 import random -from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text +from ansible.module_utils.common.text.converters import to_bytes, to_text def generate_insecure_key() -> bytes: @@ -31,7 +31,7 @@ def scramble(value: str, key: bytes) -> str: b_value = to_bytes(value) k = key[0] b_value = bytes([k ^ b for b in b_value]) - return f"=S={to_native(base64.b64encode(b_value))}" + return f"=S={to_text(base64.b64encode(b_value))}" def unscramble(value: str, key: bytes) -> str: diff --git a/plugins/modules/docker_container_copy_into.py b/plugins/modules/docker_container_copy_into.py index f52bf098..caa0b5c2 100644 --- a/plugins/modules/docker_container_copy_into.py +++ b/plugins/modules/docker_container_copy_into.py @@ -171,7 +171,7 @@ import stat import traceback import typing as t -from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text +from ansible.module_utils.common.text.converters import to_bytes, to_text from ansible.module_utils.common.validation import check_type_int from ansible_collections.community.docker.plugins.module_utils._api.errors import ( @@ -1041,7 +1041,7 @@ def copy_content_into_container( def parse_modern(mode: str | int) -> int: if isinstance(mode, str): - return int(to_native(mode), 8) + return int(to_text(mode), 8) if isinstance(mode, int): return mode raise TypeError(f"must be an octal string or an integer, got {mode!r}") @@ -1049,7 +1049,7 @@ def parse_modern(mode: str | int) -> int: def parse_octal_string_only(mode: str) -> int: if isinstance(mode, str): - return int(to_native(mode), 8) + return int(to_text(mode), 8) raise TypeError(f"must be an octal string, got {mode!r}") @@ -1185,7 +1185,7 @@ def main() -> None: except DockerUnexpectedError as exc: client.fail(f"Unexpected error: {exc}", exception=traceback.format_exc()) except DockerFileCopyError as exc: - client.fail(to_native(exc)) + client.fail(to_text(exc)) except OSError as exc: client.fail(f"Unexpected error: {exc}", exception=traceback.format_exc()) diff --git a/plugins/modules/docker_image.py b/plugins/modules/docker_image.py index d2f42d6a..2fc3f344 100644 --- a/plugins/modules/docker_image.py +++ b/plugins/modules/docker_image.py @@ -369,7 +369,7 @@ import os import traceback import typing as t -from ansible.module_utils.common.text.converters import to_native +from ansible.module_utils.common.text.converters import to_text from ansible.module_utils.common.text.formatters import human_to_bytes from ansible_collections.community.docker.plugins.module_utils._api.auth import ( @@ -899,7 +899,7 @@ class ImageManager(DockerBaseClass): buildargs = {} if self.buildargs: for key, value in self.buildargs.items(): - buildargs[key] = to_native(value) + buildargs[key] = to_text(value) container_limits = self.container_limits or {} for key in container_limits.keys(): diff --git a/plugins/modules/docker_image_build.py b/plugins/modules/docker_image_build.py index ee1f64c1..b13185c1 100644 --- a/plugins/modules/docker_image_build.py +++ b/plugins/modules/docker_image_build.py @@ -284,7 +284,7 @@ import os import traceback import typing as t -from ansible.module_utils.common.text.converters import to_native +from ansible.module_utils.common.text.converters import to_text from ansible.module_utils.common.text.formatters import human_to_bytes from ansible_collections.community.docker.plugins.module_utils._api.utils.utils import ( @@ -545,12 +545,12 @@ class ImageBuilder(DockerBaseClass): if rc != 0: self.fail( f"Building {self.name}:{self.tag} failed", - stdout=to_native(stdout), - stderr=to_native(stderr), + stdout=to_text(stdout), + stderr=to_text(stderr), command=args, ) - results["stdout"] = to_native(stdout) - results["stderr"] = to_native(stderr) + results["stdout"] = to_text(stdout) + results["stderr"] = to_text(stderr) results["image"] = self.client.find_image(self.name, self.tag) or {} results["command"] = args diff --git a/plugins/modules/docker_network.py b/plugins/modules/docker_network.py index 4df3ef66..d73e0ddd 100644 --- a/plugins/modules/docker_network.py +++ b/plugins/modules/docker_network.py @@ -286,7 +286,7 @@ import time import traceback import typing as t -from ansible.module_utils.common.text.converters import to_native +from ansible.module_utils.common.text.converters import to_text from ansible_collections.community.docker.plugins.module_utils._api.errors import ( DockerException, @@ -412,7 +412,7 @@ class DockerNetworkManager: for ipam_config in self.parameters.ipam_config: validate_cidr(ipam_config["subnet"]) except ValueError as e: - self.client.fail(to_native(e)) + self.client.fail(to_text(e)) if self.parameters.driver_options: self.parameters.driver_options = clean_dict_booleans_for_docker_api( diff --git a/plugins/modules/docker_node.py b/plugins/modules/docker_node.py index 524c240e..a2b25fb3 100644 --- a/plugins/modules/docker_node.py +++ b/plugins/modules/docker_node.py @@ -143,7 +143,7 @@ except ImportError: # missing Docker SDK for Python handled in ansible.module_utils.docker.common pass -from ansible.module_utils.common.text.converters import to_native +from ansible.module_utils.common.text.converters import to_text from ansible_collections.community.docker.plugins.module_utils._common import ( RequestException, @@ -237,11 +237,12 @@ class SwarmNodeManager(DockerBaseClass): node_spec["Labels"] = self.parameters.labels changed = True elif self.parameters.labels_state == "merge": - node_spec["Labels"] = dict(node_info["Spec"]["Labels"] or {}) + labels: dict[str, str] = dict(node_info["Spec"]["Labels"] or {}) + node_spec["Labels"] = labels if self.parameters.labels is not None: for key, value in self.parameters.labels.items(): - if node_spec["Labels"].get(key) != value: - node_spec["Labels"][key] = value + if labels.get(key) != value: + labels[key] = value changed = True if self.parameters.labels_to_remove is not None: @@ -253,7 +254,7 @@ class SwarmNodeManager(DockerBaseClass): changed = True else: self.client.module.warn( - f"Label '{to_native(key)}' listed both in 'labels' and 'labels_to_remove'. " + f"Label '{to_text(key)}' listed both in 'labels' and 'labels_to_remove'. " "Keeping the assigned label value." ) else: diff --git a/plugins/modules/docker_plugin.py b/plugins/modules/docker_plugin.py index e480845c..f69f8bfc 100644 --- a/plugins/modules/docker_plugin.py +++ b/plugins/modules/docker_plugin.py @@ -131,7 +131,7 @@ actions: import traceback import typing as t -from ansible.module_utils.common.text.converters import to_native +from ansible.module_utils.common.text.converters import to_text from ansible_collections.community.docker.plugins.module_utils._api import auth from ansible_collections.community.docker.plugins.module_utils._api.errors import ( @@ -215,7 +215,7 @@ class DockerPluginManager: except NotFound: return None except APIError as e: - self.client.fail(to_native(e)) + self.client.fail(to_text(e)) def has_different_config(self) -> DifferenceTracker: """ @@ -293,7 +293,7 @@ class DockerPluginManager: "/plugins/{0}/set", self.preferred_name, data=data ) except APIError as e: - self.client.fail(to_native(e)) + self.client.fail(to_text(e)) self.actions.append(f"Installed plugin {self.preferred_name}") self.changed = True @@ -307,7 +307,7 @@ class DockerPluginManager: "/plugins/{0}", self.preferred_name, params={"force": force} ) except APIError as e: - self.client.fail(to_native(e)) + self.client.fail(to_text(e)) self.actions.append(f"Removed plugin {self.preferred_name}") self.changed = True @@ -323,7 +323,7 @@ class DockerPluginManager: "/plugins/{0}/set", self.preferred_name, data=data ) except APIError as e: - self.client.fail(to_native(e)) + self.client.fail(to_text(e)) self.actions.append(f"Updated plugin {self.preferred_name} settings") self.changed = True else: @@ -361,7 +361,7 @@ class DockerPluginManager: params={"timeout": timeout}, ) except APIError as e: - self.client.fail(to_native(e)) + self.client.fail(to_text(e)) self.actions.append(f"Enabled plugin {self.preferred_name}") self.changed = True else: @@ -374,7 +374,7 @@ class DockerPluginManager: params={"timeout": timeout}, ) except APIError as e: - self.client.fail(to_native(e)) + self.client.fail(to_text(e)) self.actions.append(f"Enabled plugin {self.preferred_name}") self.changed = True @@ -387,7 +387,7 @@ class DockerPluginManager: "/plugins/{0}/disable", self.preferred_name ) except APIError as e: - self.client.fail(to_native(e)) + self.client.fail(to_text(e)) self.actions.append(f"Disable plugin {self.preferred_name}") self.changed = True else: diff --git a/plugins/modules/docker_stack.py b/plugins/modules/docker_stack.py index 413f155d..01fe18b5 100644 --- a/plugins/modules/docker_stack.py +++ b/plugins/modules/docker_stack.py @@ -161,7 +161,7 @@ import traceback import typing as t from time import sleep -from ansible.module_utils.common.text.converters import to_native +from ansible.module_utils.common.text.converters import to_text from ansible_collections.community.docker.plugins.module_utils._common_cli import ( AnsibleModuleDockerClient, @@ -190,9 +190,9 @@ def docker_stack_services( dummy_rc, out, err = client.call_cli( "stack", "services", stack_name, "--format", "{{.Name}}" ) - if to_native(err) == f"Nothing found in stack: {stack_name}\n": + if to_text(err) == f"Nothing found in stack: {stack_name}\n": return [] - return to_native(out).strip().split("\n") + return to_text(out).strip().split("\n") def docker_service_inspect( @@ -221,7 +221,7 @@ def docker_stack_deploy( command += ["--compose-file", compose_file] command += [stack_name] rc, out, err = client.call_cli(*command) - return rc, to_native(out), to_native(err) + return rc, to_text(out), to_text(err) def docker_stack_inspect( @@ -244,11 +244,11 @@ def docker_stack_rm( command += ["--detach=false"] rc, out, err = client.call_cli(*command) - while to_native(err) != f"Nothing found in stack: {stack_name}\n" and retries > 0: + while to_text(err) != f"Nothing found in stack: {stack_name}\n" and retries > 0: sleep(interval) retries = retries - 1 rc, out, err = client.call_cli(*command) - return rc, to_native(out), to_native(err) + return rc, to_text(out), to_text(err) def main() -> None: diff --git a/plugins/modules/docker_stack_info.py b/plugins/modules/docker_stack_info.py index c9117a3d..58e69b96 100644 --- a/plugins/modules/docker_stack_info.py +++ b/plugins/modules/docker_stack_info.py @@ -77,7 +77,7 @@ EXAMPLES = r""" import json import traceback -from ansible.module_utils.common.text.converters import to_native +from ansible.module_utils.common.text.converters import to_text from ansible_collections.community.docker.plugins.module_utils._common_cli import ( AnsibleModuleDockerClient, @@ -99,7 +99,7 @@ def main() -> None: changed=False, rc=rc, stdout="\n".join([json.dumps(entry) for entry in ret]), - stderr=to_native(stderr).strip(), + stderr=to_text(stderr).strip(), results=ret, ) except DockerException as e: diff --git a/plugins/modules/docker_stack_task_info.py b/plugins/modules/docker_stack_task_info.py index 2eba3305..e649d06a 100644 --- a/plugins/modules/docker_stack_task_info.py +++ b/plugins/modules/docker_stack_task_info.py @@ -85,7 +85,7 @@ EXAMPLES = r""" import json import traceback -from ansible.module_utils.common.text.converters import to_native +from ansible.module_utils.common.text.converters import to_text from ansible_collections.community.docker.plugins.module_utils._common_cli import ( AnsibleModuleDockerClient, @@ -108,7 +108,7 @@ def main() -> None: changed=False, rc=rc, stdout="\n".join([json.dumps(entry) for entry in ret]), - stderr=to_native(stderr).strip(), + stderr=to_text(stderr).strip(), results=ret, ) except DockerException as e: diff --git a/plugins/modules/docker_volume.py b/plugins/modules/docker_volume.py index 0c6238ea..41461031 100644 --- a/plugins/modules/docker_volume.py +++ b/plugins/modules/docker_volume.py @@ -120,7 +120,7 @@ volume: import traceback import typing as t -from ansible.module_utils.common.text.converters import to_native +from ansible.module_utils.common.text.converters import to_text from ansible_collections.community.docker.plugins.module_utils._api.errors import ( APIError, @@ -185,7 +185,7 @@ class DockerVolumeManager: try: volumes = self.client.get_json("/volumes") except APIError as e: - self.client.fail(to_native(e)) + self.client.fail(to_text(e)) if volumes["Volumes"] is None: return None @@ -259,7 +259,7 @@ class DockerVolumeManager: "/volumes/{0}", resp["Name"] ) except APIError as e: - self.client.fail(to_native(e)) + self.client.fail(to_text(e)) self.actions.append( f"Created volume {self.parameters.volume_name} with driver {self.parameters.driver}" @@ -272,7 +272,7 @@ class DockerVolumeManager: try: self.client.delete_call("/volumes/{0}", self.parameters.volume_name) except APIError as e: - self.client.fail(to_native(e)) + self.client.fail(to_text(e)) self.actions.append(f"Removed volume {self.parameters.volume_name}") self.results["changed"] = True diff --git a/tests/unit/plugins/inventory/test_docker_containers.py b/tests/unit/plugins/inventory/test_docker_containers.py index 9f1d5ee6..d4042105 100644 --- a/tests/unit/plugins/inventory/test_docker_containers.py +++ b/tests/unit/plugins/inventory/test_docker_containers.py @@ -24,14 +24,14 @@ if t.TYPE_CHECKING: from collections.abc import Callable -@pytest.fixture(scope="module") -def templar() -> Templar: +@pytest.fixture(scope="module", name="templar") +def templar_fixture() -> Templar: dataloader = create_autospec(DataLoader, instance=True) return Templar(loader=dataloader) -@pytest.fixture(scope="module") -def inventory(templar: Templar) -> InventoryModule: +@pytest.fixture(scope="module", name="inventory") +def inventory_fixture(templar: Templar) -> InventoryModule: r = InventoryModule() r.inventory = InventoryData() r.templar = templar diff --git a/tests/unit/plugins/module_utils/_api/api/test_client.py b/tests/unit/plugins/module_utils/_api/api/test_client.py index ce75f2bd..b0bf937d 100644 --- a/tests/unit/plugins/module_utils/_api/api/test_client.py +++ b/tests/unit/plugins/module_utils/_api/api/test_client.py @@ -52,7 +52,7 @@ if t.TYPE_CHECKING: DEFAULT_TIMEOUT_SECONDS = constants.DEFAULT_TIMEOUT_SECONDS -def response( +def create_response( status_code: int = 200, content: bytes | dict[str, t.Any] | list[dict[str, t.Any]] = b"", headers: dict[str, str] | None = None, @@ -95,7 +95,7 @@ def fake_resp( if not key: raise NotImplementedError(f"{method} {url}") status_code, content = fake_api.fake_responses[key]() - return response(status_code=status_code, content=content) + return create_response(status_code=status_code, content=content) fake_request = mock.Mock(side_effect=fake_resp) @@ -328,26 +328,26 @@ class DockerApiTest(BaseAPIClientTest): # pass `decode=False` to the helper raw_resp._fp.seek(0) - resp = response(status_code=status_code, content=content, raw=raw_resp) + resp = create_response(status_code=status_code, content=content, raw=raw_resp) result = next(self.client._stream_helper(resp)) assert result == content_str # pass `decode=True` to the helper raw_resp._fp.seek(0) - resp = response(status_code=status_code, content=content, raw=raw_resp) + resp = create_response(status_code=status_code, content=content, raw=raw_resp) result = next(self.client._stream_helper(resp, decode=True)) assert result == content # non-chunked response, pass `decode=False` to the helper setattr(raw_resp._fp, "chunked", False) raw_resp._fp.seek(0) - resp = response(status_code=status_code, content=content, raw=raw_resp) + resp = create_response(status_code=status_code, content=content, raw=raw_resp) result = next(self.client._stream_helper(resp)) assert result == content_str.decode("utf-8") # type: ignore # non-chunked response, pass `decode=True` to the helper raw_resp._fp.seek(0) - resp = response(status_code=status_code, content=content, raw=raw_resp) + resp = create_response(status_code=status_code, content=content, raw=raw_resp) result = next(self.client._stream_helper(resp, decode=True)) assert result == content diff --git a/tests/unit/plugins/module_utils/test__image_archive.py b/tests/unit/plugins/module_utils/test__image_archive.py index c467fb74..1a7340c8 100644 --- a/tests/unit/plugins/module_utils/test__image_archive.py +++ b/tests/unit/plugins/module_utils/test__image_archive.py @@ -22,8 +22,8 @@ from ..test_support.docker_image_archive_stubbing import ( ) -@pytest.fixture -def tar_file_name(tmpdir: t.Any) -> str: +@pytest.fixture(name="tar_file_name") +def tar_file_name_fixture(tmpdir: t.Any) -> str: """ Return the name of a non-existing tar file in an existing temporary directory. """ diff --git a/tests/unit/plugins/modules/test_docker_image.py b/tests/unit/plugins/modules/test_docker_image.py index b12a5591..050ff7eb 100644 --- a/tests/unit/plugins/modules/test_docker_image.py +++ b/tests/unit/plugins/modules/test_docker_image.py @@ -37,8 +37,8 @@ def capture_logging(messages: list[str]) -> Callable[[str], None]: return capture -@pytest.fixture -def tar_file_name(tmpdir: t.Any) -> str: +@pytest.fixture(name="tar_file_name") +def tar_file_name_fixture(tmpdir: t.Any) -> str: """ Return the name of a non-existing tar file in an existing temporary directory. """