From 23d3b126dbbb228f1bba5edba996a68e92da90c0 Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Sun, 12 Oct 2025 10:16:53 +0200 Subject: [PATCH] Address raise-missing-from. --- .pylintrc | 1 - plugins/connection/docker.py | 12 ++++++------ plugins/connection/docker_api.py | 16 ++++++++-------- plugins/connection/nsenter.py | 6 ++++-- plugins/inventory/docker_containers.py | 10 ++++++---- plugins/inventory/docker_machine.py | 2 +- plugins/inventory/docker_swarm.py | 2 +- plugins/module_utils/_api/api/client.py | 8 +++++--- plugins/module_utils/_api/tls.py | 2 +- plugins/module_utils/_api/transport/npipeconn.py | 8 ++++---- plugins/module_utils/_api/transport/sshconn.py | 8 ++++---- plugins/module_utils/_api/types/daemon.py | 8 ++++---- plugins/module_utils/_api/utils/build.py | 4 ++-- plugins/module_utils/_api/utils/json_stream.py | 2 +- plugins/module_utils/_api/utils/utils.py | 4 ++-- plugins/module_utils/_copy.py | 6 +++--- plugins/module_utils/_logfmt.py | 2 +- .../module_utils/_module_container/docker_api.py | 12 ++++++++---- plugins/module_utils/_util.py | 4 ++-- plugins/modules/docker_container_copy_into.py | 2 +- plugins/modules/docker_swarm_service.py | 16 ++++++++++------ .../unit/plugins/module_utils/_api/test_auth.py | 2 +- 22 files changed, 75 insertions(+), 62 deletions(-) diff --git a/.pylintrc b/.pylintrc index 3a1f0480..8f0bddaf 100644 --- a/.pylintrc +++ b/.pylintrc @@ -388,7 +388,6 @@ disable=raw-checker-failed, no-name-in-module, # TODO figure out why pylint cannot find the module not-an-iterable, # TODO: needs better typing info protected-access, - raise-missing-from, redefined-outer-name, # needed for test fixtures simplifiable-if-expression, subprocess-popen-preexec-fn, diff --git a/plugins/connection/docker.py b/plugins/connection/docker.py index 7d1aba90..a8e53044 100644 --- a/plugins/connection/docker.py +++ b/plugins/connection/docker.py @@ -167,8 +167,8 @@ class Connection(ConnectionBase): else: try: self.docker_cmd = get_bin_path("docker") - except ValueError: - raise AnsibleError("docker command not found in PATH") + except ValueError as exc: + raise AnsibleError("docker command not found in PATH") from exc @staticmethod def _sanitize_version(version): @@ -523,10 +523,10 @@ class Connection(ConnectionBase): p = subprocess.Popen( args, stdin=in_file, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) - except OSError: + except OSError as exc: raise AnsibleError( "docker connection requires dd command in the container to put files" - ) + ) from exc stdout, stderr = p.communicate() if p.returncode != 0: @@ -588,10 +588,10 @@ class Connection(ConnectionBase): stdout=out_file, stderr=subprocess.PIPE, ) - except OSError: + except OSError as exc: raise AnsibleError( "docker connection requires dd command in the container to put files" - ) + ) from exc stdout, stderr = pp.communicate() if pp.returncode != 0: diff --git a/plugins/connection/docker_api.py b/plugins/connection/docker_api.py index cd9da076..754687bb 100644 --- a/plugins/connection/docker_api.py +++ b/plugins/connection/docker_api.py @@ -158,15 +158,15 @@ class Connection(ConnectionBase): if not_found_can_be_resource: raise AnsibleConnectionFailure( f'Could not find container "{remote_addr}" or resource in it ({e})' - ) + ) from e raise AnsibleConnectionFailure( f'Could not find container "{remote_addr}" ({e})' - ) + ) from e except APIError as e: if e.response is not None and e.response.status_code == 409: raise AnsibleConnectionFailure( f'The container "{remote_addr}" has been paused ({e})' - ) + ) from e self.client.fail( f'An unexpected Docker error occurred for container "{remote_addr}": {e}' ) @@ -393,7 +393,7 @@ class Connection(ConnectionBase): except Exception as e: raise AnsibleConnectionFailure( f'Error while determining user and group ID of current user in container "{remote_addr}": {e}\nGot value: {ids!r}' - ) + ) from e user_id, group_id = self.ids[self.actual_user] try: @@ -411,9 +411,9 @@ class Connection(ConnectionBase): not_found_can_be_resource=True, ) except DockerFileNotFound as exc: - raise AnsibleFileNotFound(to_native(exc)) + raise AnsibleFileNotFound(to_native(exc)) from exc except DockerFileCopyError as exc: - raise AnsibleConnectionFailure(to_native(exc)) + raise AnsibleConnectionFailure(to_native(exc)) from exc def fetch_file(self, in_path, out_path): """Fetch a file from container to local.""" @@ -439,9 +439,9 @@ class Connection(ConnectionBase): not_found_can_be_resource=True, ) except DockerFileNotFound as exc: - raise AnsibleFileNotFound(to_native(exc)) + raise AnsibleFileNotFound(to_native(exc)) from exc except DockerFileCopyError as exc: - raise AnsibleConnectionFailure(to_native(exc)) + raise AnsibleConnectionFailure(to_native(exc)) from exc def close(self): """Terminate the connection. Nothing to do for Docker""" diff --git a/plugins/connection/nsenter.py b/plugins/connection/nsenter.py index bdf321f6..07a995b1 100644 --- a/plugins/connection/nsenter.py +++ b/plugins/connection/nsenter.py @@ -248,7 +248,7 @@ class Connection(ConnectionBase): if rc != 0: raise AnsibleError(f"failed to transfer file to {out_path}: {err}") except IOError as e: - raise AnsibleError(f"failed to transfer file to {out_path}: {e}") + raise AnsibleError(f"failed to transfer file to {out_path}: {e}") from e def fetch_file(self, in_path, out_path): super().fetch_file(in_path, out_path) @@ -268,7 +268,9 @@ class Connection(ConnectionBase): ) as out_file: out_file.write(out) except IOError as e: - raise AnsibleError(f"failed to transfer file to {to_native(out_path)}: {e}") + raise AnsibleError( + f"failed to transfer file to {to_native(out_path)}: {e}" + ) from e def close(self): """terminate the connection; nothing to do here""" diff --git a/plugins/inventory/docker_containers.py b/plugins/inventory/docker_containers.py index 1aead1de..0ce54134 100644 --- a/plugins/inventory/docker_containers.py +++ b/plugins/inventory/docker_containers.py @@ -228,7 +228,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable): } containers = client.get_json("/containers/json", params=params) except APIError as exc: - raise AnsibleError(f"Error listing containers: {exc}") + raise AnsibleError(f"Error listing containers: {exc}") from exc if add_legacy_groups: self.inventory.add_group("running") @@ -262,7 +262,9 @@ class InventoryModule(BaseInventoryPlugin, Constructable): try: inspect = client.get_json("/containers/{0}/json", container_id) except APIError as exc: - raise AnsibleError(f"Error inspecting container {name} - {exc}") + raise AnsibleError( + f"Error inspecting container {name} - {exc}" + ) from exc state = inspect.get("State") or dict() config = inspect.get("Config") or dict() @@ -401,8 +403,8 @@ class InventoryModule(BaseInventoryPlugin, Constructable): try: self._populate(client) except DockerException as e: - raise AnsibleError(f"An unexpected Docker error occurred: {e}") + raise AnsibleError(f"An unexpected Docker error occurred: {e}") from e except RequestException as e: raise AnsibleError( f"An unexpected requests error occurred when trying to talk to the Docker daemon: {e}" - ) + ) from e diff --git a/plugins/inventory/docker_machine.py b/plugins/inventory/docker_machine.py index d4eae1dd..87f44101 100644 --- a/plugins/inventory/docker_machine.py +++ b/plugins/inventory/docker_machine.py @@ -132,7 +132,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)) + raise AnsibleError(to_native(e)) from e command = [self.docker_machine_path] command.extend(args) diff --git a/plugins/inventory/docker_swarm.py b/plugins/inventory/docker_swarm.py index 46faf6e0..8475dc7e 100644 --- a/plugins/inventory/docker_swarm.py +++ b/plugins/inventory/docker_swarm.py @@ -305,7 +305,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable): except Exception as e: raise AnsibleError( f"Unable to fetch hosts from Docker swarm API, this was the original exception: {e}" - ) + ) from e def verify_file(self, path): """Return the possibly of a file being consumable by this plugin.""" diff --git a/plugins/module_utils/_api/api/client.py b/plugins/module_utils/_api/api/client.py index 3c7b765e..af5d1db0 100644 --- a/plugins/module_utils/_api/api/client.py +++ b/plugins/module_utils/_api/api/client.py @@ -227,18 +227,20 @@ class APIClient(_Session, DaemonApiMixin): try: version_result = self.version(api_version=False) except Exception as e: - raise DockerException(f"Error while fetching server API version: {e}") + raise DockerException( + f"Error while fetching server API version: {e}" + ) from e try: return version_result["ApiVersion"] except KeyError: raise DockerException( 'Invalid response from docker daemon: key "ApiVersion" is missing.' - ) + ) from None except Exception as e: raise DockerException( f"Error while fetching server API version: {e}. Response seems to be broken." - ) + ) from e def _set_request_timeout(self, kwargs): """Prepare the kwargs for an HTTP request by inserting the timeout diff --git a/plugins/module_utils/_api/tls.py b/plugins/module_utils/_api/tls.py index 38ce5ba0..1b81c193 100644 --- a/plugins/module_utils/_api/tls.py +++ b/plugins/module_utils/_api/tls.py @@ -71,7 +71,7 @@ class TLSConfig: except ValueError: raise errors.TLSParameterError( "client_cert must be a tuple of (client certificate, key file)" - ) + ) from None if not (tls_cert and tls_key) or ( not os.path.isfile(tls_cert) or not os.path.isfile(tls_key) diff --git a/plugins/module_utils/_api/transport/npipeconn.py b/plugins/module_utils/_api/transport/npipeconn.py index 2c056d44..ca348426 100644 --- a/plugins/module_utils/_api/transport/npipeconn.py +++ b/plugins/module_utils/_api/transport/npipeconn.py @@ -52,15 +52,15 @@ class NpipeHTTPConnectionPool(urllib3.connectionpool.HTTPConnectionPool): try: conn = self.pool.get(block=self.block, timeout=timeout) - except AttributeError: # self.pool is None - raise urllib3.exceptions.ClosedPoolError(self, "Pool is closed.") + except AttributeError as exc: # self.pool is None + raise urllib3.exceptions.ClosedPoolError(self, "Pool is closed.") from exc - except Empty: + except Empty as exc: if self.block: raise urllib3.exceptions.EmptyPoolError( self, "Pool reached maximum size and no more connections are allowed.", - ) + ) from exc pass # Oh well, we'll create a new connection then return conn or self._new_conn() diff --git a/plugins/module_utils/_api/transport/sshconn.py b/plugins/module_utils/_api/transport/sshconn.py index b888b9c9..0a4bcb1a 100644 --- a/plugins/module_utils/_api/transport/sshconn.py +++ b/plugins/module_utils/_api/transport/sshconn.py @@ -159,15 +159,15 @@ class SSHConnectionPool(urllib3.connectionpool.HTTPConnectionPool): try: conn = self.pool.get(block=self.block, timeout=timeout) - except AttributeError: # self.pool is None - raise urllib3.exceptions.ClosedPoolError(self, "Pool is closed.") + except AttributeError as exc: # self.pool is None + raise urllib3.exceptions.ClosedPoolError(self, "Pool is closed.") from exc - except Empty: + except Empty as exc: if self.block: raise urllib3.exceptions.EmptyPoolError( self, "Pool reached maximum size and no more connections are allowed.", - ) + ) from exc pass # Oh well, we'll create a new connection then return conn or self._new_conn() diff --git a/plugins/module_utils/_api/types/daemon.py b/plugins/module_utils/_api/types/daemon.py index c22ad9b5..6defe9b2 100644 --- a/plugins/module_utils/_api/types/daemon.py +++ b/plugins/module_utils/_api/types/daemon.py @@ -39,10 +39,10 @@ class CancellableStream: def __next__(self): try: return next(self._stream) - except urllib3.exceptions.ProtocolError: - raise StopIteration - except socket.error: - raise StopIteration + except urllib3.exceptions.ProtocolError as exc: + raise StopIteration from exc + except socket.error as exc: + raise StopIteration from exc next = __next__ diff --git a/plugins/module_utils/_api/utils/build.py b/plugins/module_utils/_api/utils/build.py index 5a06772b..d15774be 100644 --- a/plugins/module_utils/_api/utils/build.py +++ b/plugins/module_utils/_api/utils/build.py @@ -107,8 +107,8 @@ def create_archive(root, files=None, fileobj=None, gzip=False, extra_files=None) try: with open(full_path, "rb") as f: t.addfile(i, f) - except IOError: - raise IOError(f"Can not read file in context: {full_path}") + 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) diff --git a/plugins/module_utils/_api/utils/json_stream.py b/plugins/module_utils/_api/utils/json_stream.py index 164c5c9e..dac3d0ca 100644 --- a/plugins/module_utils/_api/utils/json_stream.py +++ b/plugins/module_utils/_api/utils/json_stream.py @@ -85,4 +85,4 @@ def split_buffer(stream, splitter=None, decoder=lambda a: a): try: yield decoder(buffered) except Exception as e: - raise StreamParseError(e) + raise StreamParseError(e) from e diff --git a/plugins/module_utils/_api/utils/utils.py b/plugins/module_utils/_api/utils/utils.py index e54f6eef..31c9b39f 100644 --- a/plugins/module_utils/_api/utils/utils.py +++ b/plugins/module_utils/_api/utils/utils.py @@ -420,10 +420,10 @@ def parse_bytes(s): if suffix in units or suffix.isdigit(): try: digits = float(digits_part) - except ValueError: + except ValueError as exc: raise errors.DockerException( f"Failed converting the string value for memory ({digits_part}) to an integer." - ) + ) from exc # Reconvert to long for the final result s = int(digits * units[suffix]) diff --git a/plugins/module_utils/_copy.py b/plugins/module_utils/_copy.py index 2641b63f..62c8d50f 100644 --- a/plugins/module_utils/_copy.py +++ b/plugins/module_utils/_copy.py @@ -285,7 +285,7 @@ def stat_file(client, container, in_path, follow_links=False, log=None): except Exception as exc: raise DockerUnexpectedError( f"When retrieving information for {in_path} from {container}, obtained header {header!r} that cannot be loaded as JSON: {exc}" - ) + ) from exc # https://pkg.go.dev/io/fs#FileMode: bit 32 - 5 means ModeSymlink if stat_data["mode"] & (1 << (32 - 5)) != 0: @@ -513,7 +513,7 @@ def determine_user_group(client, container, log=None): user_id, group_id = stdout_lines try: return int(user_id), int(group_id) - except ValueError: + except ValueError as exc: raise DockerUnexpectedError( f'Expected two-line output with numeric IDs to obtain user and group ID for container {container}, but got "{user_id}" and "{group_id}" instead' - ) + ) from exc diff --git a/plugins/module_utils/_logfmt.py b/plugins/module_utils/_logfmt.py index 362ae4ff..159281ac 100644 --- a/plugins/module_utils/_logfmt.py +++ b/plugins/module_utils/_logfmt.py @@ -103,7 +103,7 @@ class _Parser: except KeyError: raise InvalidLogFmt( f"Invalid unicode escape digit {self.line[self.index]!r}" - ) + ) from None self.index += 6 return chr(v) diff --git a/plugins/module_utils/_module_container/docker_api.py b/plugins/module_utils/_module_container/docker_api.py index 95b286c8..e66b29e4 100644 --- a/plugins/module_utils/_module_container/docker_api.py +++ b/plugins/module_utils/_module_container/docker_api.py @@ -398,13 +398,15 @@ class DockerAPIEngineDriver(EngineDriver): # New docker daemon versions do not allow containers to be removed # if they are paused. Make sure we do not end up in an infinite loop. if count == 3: - raise RuntimeError(f"{exc} [tried to unpause three times]") + raise RuntimeError( + f"{exc} [tried to unpause three times]" + ) from exc count += 1 # Unpause try: self.unpause_container(client, container_id) except Exception as exc2: - raise RuntimeError(f"{exc2} [while unpausing]") + raise RuntimeError(f"{exc2} [while unpausing]") from exc2 # Now try again continue raise @@ -429,13 +431,15 @@ class DockerAPIEngineDriver(EngineDriver): # New docker daemon versions do not allow containers to be removed # if they are paused. Make sure we do not end up in an infinite loop. if count == 3: - raise RuntimeError(f"{exc} [tried to unpause three times]") + raise RuntimeError( + f"{exc} [tried to unpause three times]" + ) from exc count += 1 # Unpause try: self.unpause_container(client, container_id) except Exception as exc2: - raise RuntimeError(f"{exc2} [while unpausing]") + raise RuntimeError(f"{exc2} [while unpausing]") from exc2 # Now try again continue if ( diff --git a/plugins/module_utils/_util.py b/plugins/module_utils/_util.py index ec01a299..2fc49e23 100644 --- a/plugins/module_utils/_util.py +++ b/plugins/module_utils/_util.py @@ -420,10 +420,10 @@ def normalize_healthcheck(healthcheck, normalize_test=False): if key == "retries": try: value = int(value) - except ValueError: + except ValueError as exc: raise ValueError( f'Cannot parse number of retries for healthcheck. Expected an integer, got "{value}".' - ) + ) from exc if key == "test" and value and normalize_test: value = normalize_healthcheck_test(value) result[key] = value diff --git a/plugins/modules/docker_container_copy_into.py b/plugins/modules/docker_container_copy_into.py index f2f9d49c..ccd5ccd9 100644 --- a/plugins/modules/docker_container_copy_into.py +++ b/plugins/modules/docker_container_copy_into.py @@ -484,7 +484,7 @@ def is_file_idempotent( ) except OSError as exc: if exc.errno == 2: - raise DockerFileNotFound(f"Cannot find local file {managed_path}") + raise DockerFileNotFound(f"Cannot find local file {managed_path}") from exc raise if mode is None: mode = stat.S_IMODE(file_stat.st_mode) diff --git a/plugins/modules/docker_swarm_service.py b/plugins/modules/docker_swarm_service.py index 754b750f..d703128b 100644 --- a/plugins/modules/docker_swarm_service.py +++ b/plugins/modules/docker_swarm_service.py @@ -919,10 +919,10 @@ def get_docker_environment(env, env_files): for item in env: try: name, value = item.split("=", 1) - except ValueError: + except ValueError as exc: raise ValueError( "Invalid environment variable found in list, needs to be in format KEY=VALUE." - ) + ) from exc env_dict[name] = value elif env is not None: raise ValueError( @@ -983,7 +983,7 @@ def get_docker_networks(networks, network_ids): try: parsed_network["id"] = network_ids[network_name] except KeyError as e: - raise ValueError(f"Could not find a network named: {e}.") + raise ValueError(f"Could not find a network named: {e}.") from None parsed_networks.append(parsed_network) return parsed_networks or [] @@ -1370,7 +1370,9 @@ class DockerService(DockerBaseClass): try: memory = human_to_bytes(memory) except ValueError as exc: - raise ValueError(f"Failed to convert limit_memory to bytes: {exc}") + raise ValueError( + f"Failed to convert limit_memory to bytes: {exc}" + ) from exc return { "limit_cpu": cpus, "limit_memory": memory, @@ -1392,7 +1394,9 @@ class DockerService(DockerBaseClass): try: memory = human_to_bytes(memory) except ValueError as exc: - raise ValueError(f"Failed to convert reserve_memory to bytes: {exc}") + raise ValueError( + f"Failed to convert reserve_memory to bytes: {exc}" + ) from exc return { "reserve_cpu": cpus, "reserve_memory": memory, @@ -1559,7 +1563,7 @@ class DockerService(DockerBaseClass): except ValueError as exc: raise ValueError( f"Failed to convert tmpfs_size to bytes: {exc}" - ) + ) from exc service_m["tmpfs_size"] = tmpfs_size s.mounts.append(service_m) diff --git a/tests/unit/plugins/module_utils/_api/test_auth.py b/tests/unit/plugins/module_utils/_api/test_auth.py index 363d51e2..217618c7 100644 --- a/tests/unit/plugins/module_utils/_api/test_auth.py +++ b/tests/unit/plugins/module_utils/_api/test_auth.py @@ -807,7 +807,7 @@ class InMemoryStore(Store): try: return self.__store[server] except KeyError: - raise CredentialsNotFound() + raise CredentialsNotFound() from None def store(self, server, username, secret): self.__store[server] = {