From cad22de628fba6e5d7a80f7711b96ba73191f630 Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Sat, 11 Oct 2025 23:06:50 +0200 Subject: [PATCH] Python code modernization, 4/n (#1162) * Address attribute-defined-outside-init. * Address broad-exception-raised. * Address broad-exception-caught. * Address consider-iterating-dictionary. * Address consider-using-dict-comprehension. * Address consider-using-f-string. * Address consider-using-in. * Address consider-using-max-builtin. * Address some consider-using-with. * Address invalid-name. * Address keyword-arg-before-vararg. * Address line-too-long. * Address no-else-continue. * Address no-else-raise. * Address no-else-return. * Remove broken dead code. * Make consider-using-f-string changes compatible with older Python versions. * Python 3.11 and earlier apparently do not like multi-line f-strings. --- .pylintrc | 14 - plugins/connection/docker.py | 280 +++++++++--------- plugins/connection/docker_api.py | 14 +- plugins/connection/nsenter.py | 170 +++++------ plugins/inventory/docker_machine.py | 18 +- plugins/inventory/docker_swarm.py | 8 +- plugins/module_utils/_api/_import_helper.py | 10 +- plugins/module_utils/_api/api/client.py | 30 +- plugins/module_utils/_api/auth.py | 2 +- plugins/module_utils/_api/context/config.py | 6 +- plugins/module_utils/_api/context/context.py | 22 +- .../module_utils/_api/credentials/store.py | 7 +- .../_api/transport/npipesocket.py | 14 +- .../module_utils/_api/transport/sshconn.py | 6 +- plugins/module_utils/_api/utils/build.py | 29 +- plugins/module_utils/_api/utils/config.py | 3 +- plugins/module_utils/_api/utils/decorators.py | 17 -- plugins/module_utils/_api/utils/ports.py | 11 +- plugins/module_utils/_api/utils/socket.py | 8 +- plugins/module_utils/_api/utils/utils.py | 20 +- plugins/module_utils/_common.py | 24 +- plugins/module_utils/_common_api.py | 18 +- plugins/module_utils/_common_cli.py | 4 +- plugins/module_utils/_compose_v2.py | 32 +- plugins/module_utils/_logfmt.py | 42 ++- .../module_utils/_module_container/base.py | 29 +- .../_module_container/docker_api.py | 19 +- .../module_utils/_module_container/module.py | 27 +- plugins/module_utils/_socket_handler.py | 5 +- plugins/module_utils/_socket_helper.py | 5 +- plugins/module_utils/_swarm.py | 27 +- plugins/module_utils/_util.py | 51 ++-- plugins/modules/docker_config.py | 2 +- plugins/modules/docker_container_copy_into.py | 18 +- plugins/modules/docker_host_info.py | 3 +- plugins/modules/docker_image.py | 34 +-- plugins/modules/docker_image_export.py | 6 +- plugins/modules/docker_image_info.py | 2 +- plugins/modules/docker_image_load.py | 2 +- plugins/modules/docker_image_push.py | 4 +- plugins/modules/docker_image_remove.py | 2 +- plugins/modules/docker_image_tag.py | 4 +- plugins/modules/docker_login.py | 4 +- plugins/modules/docker_network.py | 2 +- plugins/modules/docker_secret.py | 2 +- plugins/modules/docker_stack.py | 5 +- plugins/modules/docker_swarm.py | 1 + plugins/modules/docker_swarm_service.py | 34 +-- plugins/modules/docker_volume_info.py | 2 +- plugins/plugin_utils/_common.py | 4 +- plugins/plugin_utils/_common_api.py | 4 +- plugins/plugin_utils/_unsafe.py | 8 +- .../module_utils/_api/api/test_client.py | 18 +- .../plugins/module_utils/_api/fake_api.py | 4 +- .../module_utils/_api/utils/test_build.py | 34 +-- .../module_utils/_api/utils/test_config.py | 2 + .../module_utils/_api/utils/test_utils.py | 5 +- .../module_utils/compose_v2_test_cases.py | 2 + .../docker_image_archive_stubbing.py | 6 +- 59 files changed, 556 insertions(+), 630 deletions(-) diff --git a/.pylintrc b/.pylintrc index 1af1bd01..3a1f0480 100644 --- a/.pylintrc +++ b/.pylintrc @@ -381,23 +381,9 @@ disable=raw-checker-failed, # To clean up: abstract-method, arguments-differ, - attribute-defined-outside-init, - broad-exception-caught, - broad-exception-raised, - consider-iterating-dictionary, - consider-using-dict-comprehension, - consider-using-f-string, - consider-using-in, - consider-using-max-builtin, consider-using-with, fixme, import-error, # TODO figure out why pylint cannot find the module - invalid-name, - keyword-arg-before-vararg, - line-too-long, - no-else-continue, - no-else-raise, - no-else-return, no-member, no-name-in-module, # TODO figure out why pylint cannot find the module not-an-iterable, # TODO: needs better typing info diff --git a/plugins/connection/docker.py b/plugins/connection/docker.py index bb84bbcd..7d1aba90 100644 --- a/plugins/connection/docker.py +++ b/plugins/connection/docker.py @@ -155,6 +155,8 @@ class Connection(ConnectionBase): self._docker_args = [] self._container_user_cache = {} self._version = None + self.remote_user = None + self.timeout = None # Windows uses Powershell modules if getattr(self._shell, "_IS_WINDOWS", False): @@ -180,10 +182,10 @@ class Connection(ConnectionBase): old_version_subcommand = ["version"] old_docker_cmd = [self.docker_cmd] + cmd_args + old_version_subcommand - p = subprocess.Popen( + with subprocess.Popen( old_docker_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE - ) - cmd_output, err = p.communicate() + ) as p: + cmd_output, err = p.communicate() return old_docker_cmd, to_native(cmd_output), err, p.returncode @@ -194,11 +196,11 @@ class Connection(ConnectionBase): new_version_subcommand = ["version", "--format", "'{{.Server.Version}}'"] new_docker_cmd = [self.docker_cmd] + cmd_args + new_version_subcommand - p = subprocess.Popen( + with subprocess.Popen( new_docker_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE - ) - cmd_output, err = p.communicate() - return new_docker_cmd, to_native(cmd_output), err, p.returncode + ) as p: + cmd_output, err = p.communicate() + return new_docker_cmd, to_native(cmd_output), err, p.returncode def _get_docker_version(self): @@ -221,21 +223,20 @@ class Connection(ConnectionBase): container = self.get_option("remote_addr") if container in self._container_user_cache: return self._container_user_cache[container] - p = subprocess.Popen( + with subprocess.Popen( [self.docker_cmd, "inspect", "--format", "{{.Config.User}}", container], stdout=subprocess.PIPE, stderr=subprocess.PIPE, - ) + ) as p: + out, err = p.communicate() + out = to_text(out, errors="surrogate_or_strict") - out, err = p.communicate() - out = to_text(out, errors="surrogate_or_strict") - - if p.returncode != 0: - display.warning( - f"unable to retrieve default user from docker container: {out} {to_text(err)}" - ) - self._container_user_cache[container] = None - return None + if p.returncode != 0: + display.warning( + f"unable to retrieve default user from docker container: {out} {to_text(err)}" + ) + self._container_user_cache[container] = None + return None # The default exec user is root, unless it was changed in the Dockerfile with USER user = out.strip() or "root" @@ -348,21 +349,19 @@ class Connection(ConnectionBase): ) >= LooseVersion("1.7"): # Support for specifying the exec user was added in docker 1.7 return self.remote_user - else: - self.remote_user = None - actual_user = self._get_docker_remote_user() - if actual_user != self.get_option("remote_user"): - display.warning( - f'docker {self.docker_version} does not support remote_user, using container default: {actual_user or "?"}' - ) - return actual_user - elif self._display.verbosity > 2: + self.remote_user = None + actual_user = self._get_docker_remote_user() + if actual_user != self.get_option("remote_user"): + display.warning( + f'docker {self.docker_version} does not support remote_user, using container default: {actual_user or "?"}' + ) + return actual_user + if self._display.verbosity > 2: # Since we are not setting the actual_user, look it up so we have it for logging later # Only do this if display verbosity is high enough that we'll need the value # This saves overhead from calling into docker when we do not need to. return self._get_docker_remote_user() - else: - return None + return None def _connect(self, port=None): """Connect to the container. Nothing to do""" @@ -390,87 +389,87 @@ class Connection(ConnectionBase): local_cmd = [to_bytes(i, errors="surrogate_or_strict") for i in local_cmd] - p = subprocess.Popen( + with subprocess.Popen( local_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, - ) - display.debug("done running command with Popen()") + ) as p: + display.debug("done running command with Popen()") - if self.become and self.become.expect_prompt() and sudoable: - fcntl.fcntl( - p.stdout, - fcntl.F_SETFL, - fcntl.fcntl(p.stdout, fcntl.F_GETFL) | os.O_NONBLOCK, - ) - fcntl.fcntl( - p.stderr, - fcntl.F_SETFL, - fcntl.fcntl(p.stderr, fcntl.F_GETFL) | os.O_NONBLOCK, - ) - selector = selectors.DefaultSelector() - selector.register(p.stdout, selectors.EVENT_READ) - selector.register(p.stderr, selectors.EVENT_READ) - - become_output = b"" - try: - while not self.become.check_success( - become_output - ) and not self.become.check_password_prompt(become_output): - events = selector.select(self.timeout) - if not events: - stdout, stderr = p.communicate() - raise AnsibleError( - "timeout waiting for privilege escalation password prompt:\n" - + to_native(become_output) - ) - - chunks = b"" - for key, event in events: - if key.fileobj == p.stdout: - chunk = p.stdout.read() - if chunk: - chunks += chunk - elif key.fileobj == p.stderr: - chunk = p.stderr.read() - if chunk: - chunks += chunk - - if not chunks: - stdout, stderr = p.communicate() - raise AnsibleError( - "privilege output closed while waiting for password prompt:\n" - + to_native(become_output) - ) - become_output += chunks - finally: - selector.close() - - if not self.become.check_success(become_output): - become_pass = self.become.get_option( - "become_pass", playcontext=self._play_context + if self.become and self.become.expect_prompt() and sudoable: + fcntl.fcntl( + p.stdout, + fcntl.F_SETFL, + fcntl.fcntl(p.stdout, fcntl.F_GETFL) | os.O_NONBLOCK, ) - p.stdin.write( - to_bytes(become_pass, errors="surrogate_or_strict") + b"\n" + fcntl.fcntl( + p.stderr, + fcntl.F_SETFL, + fcntl.fcntl(p.stderr, fcntl.F_GETFL) | os.O_NONBLOCK, ) - fcntl.fcntl( - p.stdout, - fcntl.F_SETFL, - fcntl.fcntl(p.stdout, fcntl.F_GETFL) & ~os.O_NONBLOCK, - ) - fcntl.fcntl( - p.stderr, - fcntl.F_SETFL, - fcntl.fcntl(p.stderr, fcntl.F_GETFL) & ~os.O_NONBLOCK, - ) + selector = selectors.DefaultSelector() + selector.register(p.stdout, selectors.EVENT_READ) + selector.register(p.stderr, selectors.EVENT_READ) - display.debug("getting output with communicate()") - stdout, stderr = p.communicate(in_data) - display.debug("done communicating") + become_output = b"" + try: + while not self.become.check_success( + become_output + ) and not self.become.check_password_prompt(become_output): + events = selector.select(self.timeout) + if not events: + stdout, stderr = p.communicate() + raise AnsibleError( + "timeout waiting for privilege escalation password prompt:\n" + + to_native(become_output) + ) - display.debug("done with docker.exec_command()") - return (p.returncode, stdout, stderr) + chunks = b"" + for key, event in events: + if key.fileobj == p.stdout: + chunk = p.stdout.read() + if chunk: + chunks += chunk + elif key.fileobj == p.stderr: + chunk = p.stderr.read() + if chunk: + chunks += chunk + + if not chunks: + stdout, stderr = p.communicate() + raise AnsibleError( + "privilege output closed while waiting for password prompt:\n" + + to_native(become_output) + ) + become_output += chunks + finally: + selector.close() + + if not self.become.check_success(become_output): + become_pass = self.become.get_option( + "become_pass", playcontext=self._play_context + ) + p.stdin.write( + to_bytes(become_pass, errors="surrogate_or_strict") + b"\n" + ) + fcntl.fcntl( + p.stdout, + fcntl.F_SETFL, + fcntl.fcntl(p.stdout, fcntl.F_GETFL) & ~os.O_NONBLOCK, + ) + fcntl.fcntl( + p.stderr, + fcntl.F_SETFL, + fcntl.fcntl(p.stderr, fcntl.F_GETFL) & ~os.O_NONBLOCK, + ) + + display.debug("getting output with communicate()") + stdout, stderr = p.communicate(in_data) + display.debug("done communicating") + + display.debug("done with docker.exec_command()") + return (p.returncode, stdout, stderr) def _prefix_login_path(self, remote_path): """Make sure that we put files into a standard path @@ -486,10 +485,9 @@ class Connection(ConnectionBase): import ntpath return ntpath.normpath(remote_path) - else: - if not remote_path.startswith(os.path.sep): - remote_path = os.path.join(os.path.sep, remote_path) - return os.path.normpath(remote_path) + if not remote_path.startswith(os.path.sep): + remote_path = os.path.join(os.path.sep, remote_path) + return os.path.normpath(remote_path) def put_file(self, in_path, out_path): """Transfer a file from local to docker container""" @@ -557,45 +555,49 @@ class Connection(ConnectionBase): ] args = [to_bytes(i, errors="surrogate_or_strict") for i in args] - p = subprocess.Popen( + with subprocess.Popen( args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE - ) - p.communicate() + ) as p: + p.communicate() - if getattr(self._shell, "_IS_WINDOWS", False): - import ntpath + if getattr(self._shell, "_IS_WINDOWS", False): + import ntpath - actual_out_path = ntpath.join(out_dir, ntpath.basename(in_path)) - else: - actual_out_path = os.path.join(out_dir, os.path.basename(in_path)) + actual_out_path = ntpath.join(out_dir, ntpath.basename(in_path)) + else: + actual_out_path = os.path.join(out_dir, os.path.basename(in_path)) - if p.returncode != 0: - # Older docker does not have native support for fetching files command `cp` - # If `cp` fails, try to use `dd` instead - args = self._build_exec_cmd( - [self._play_context.executable, "-c", f"dd if={in_path} bs={BUFSIZE}"] - ) - args = [to_bytes(i, errors="surrogate_or_strict") for i in args] - with open( - to_bytes(actual_out_path, errors="surrogate_or_strict"), "wb" - ) as out_file: - try: - p = subprocess.Popen( - args, - stdin=subprocess.PIPE, - stdout=out_file, - stderr=subprocess.PIPE, - ) - except OSError: - raise AnsibleError( - "docker connection requires dd command in the container to put files" - ) - stdout, stderr = p.communicate() + if p.returncode != 0: + # Older docker does not have native support for fetching files command `cp` + # If `cp` fails, try to use `dd` instead + args = self._build_exec_cmd( + [ + self._play_context.executable, + "-c", + f"dd if={in_path} bs={BUFSIZE}", + ] + ) + args = [to_bytes(i, errors="surrogate_or_strict") for i in args] + with open( + to_bytes(actual_out_path, errors="surrogate_or_strict"), "wb" + ) as out_file: + try: + pp = subprocess.Popen( + args, + stdin=subprocess.PIPE, + stdout=out_file, + stderr=subprocess.PIPE, + ) + except OSError: + raise AnsibleError( + "docker connection requires dd command in the container to put files" + ) + stdout, stderr = pp.communicate() - if p.returncode != 0: - raise AnsibleError( - f"failed to fetch file {in_path} to {out_path}:\n{stdout}\n{stderr}" - ) + if pp.returncode != 0: + raise AnsibleError( + f"failed to fetch file {in_path} to {out_path}:\n{stdout}\n{stderr}" + ) # Rename if needed if actual_out_path != out_path: diff --git a/plugins/connection/docker_api.py b/plugins/connection/docker_api.py index 20d9bfda..cd9da076 100644 --- a/plugins/connection/docker_api.py +++ b/plugins/connection/docker_api.py @@ -159,10 +159,9 @@ class Connection(ConnectionBase): raise AnsibleConnectionFailure( f'Could not find container "{remote_addr}" or resource in it ({e})' ) - else: - raise AnsibleConnectionFailure( - f'Could not find container "{remote_addr}" ({e})' - ) + raise AnsibleConnectionFailure( + f'Could not find container "{remote_addr}" ({e})' + ) except APIError as e: if e.response is not None and e.response.status_code == 409: raise AnsibleConnectionFailure( @@ -370,10 +369,9 @@ class Connection(ConnectionBase): import ntpath return ntpath.normpath(remote_path) - else: - if not remote_path.startswith(os.path.sep): - remote_path = os.path.join(os.path.sep, remote_path) - return os.path.normpath(remote_path) + if not remote_path.startswith(os.path.sep): + remote_path = os.path.join(os.path.sep, remote_path) + return os.path.normpath(remote_path) def put_file(self, in_path, out_path): """Transfer a file from local to docker container""" diff --git a/plugins/connection/nsenter.py b/plugins/connection/nsenter.py index 086e54f5..bdf321f6 100644 --- a/plugins/connection/nsenter.py +++ b/plugins/connection/nsenter.py @@ -66,6 +66,7 @@ class Connection(ConnectionBase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.cwd = None + self._nsenter_pid = None def _connect(self): self._nsenter_pid = self.get_option("nsenter_pid") @@ -133,7 +134,7 @@ class Connection(ConnectionBase): except (IOError, OSError) as e: display.debug(f"Unable to open pty: {e}") - p = subprocess.Popen( + with subprocess.Popen( cmd, shell=isinstance(cmd, (str, bytes)), executable=executable if isinstance(cmd, (str, bytes)) else None, @@ -141,98 +142,97 @@ class Connection(ConnectionBase): stdin=stdin, stdout=subprocess.PIPE, stderr=subprocess.PIPE, - ) + ) as p: + # if we created a master, we can close the other half of the pty now, otherwise master is stdin + if master is not None: + os.close(stdin) - # if we created a master, we can close the other half of the pty now, otherwise master is stdin - if master is not None: - os.close(stdin) + display.debug("done running command with Popen()") - display.debug("done running command with Popen()") - - if self.become and self.become.expect_prompt() and sudoable: - fcntl.fcntl( - p.stdout, - fcntl.F_SETFL, - fcntl.fcntl(p.stdout, fcntl.F_GETFL) | os.O_NONBLOCK, - ) - fcntl.fcntl( - p.stderr, - fcntl.F_SETFL, - fcntl.fcntl(p.stderr, fcntl.F_GETFL) | os.O_NONBLOCK, - ) - selector = selectors.DefaultSelector() - selector.register(p.stdout, selectors.EVENT_READ) - selector.register(p.stderr, selectors.EVENT_READ) - - become_output = b"" - try: - while not self.become.check_success( - become_output - ) and not self.become.check_password_prompt(become_output): - events = selector.select(self._play_context.timeout) - if not events: - stdout, stderr = p.communicate() - raise AnsibleError( - "timeout waiting for privilege escalation password prompt:\n" - + to_native(become_output) - ) - - chunks = b"" - for key, event in events: - if key.fileobj == p.stdout: - chunk = p.stdout.read() - if chunk: - chunks += chunk - elif key.fileobj == p.stderr: - chunk = p.stderr.read() - if chunk: - chunks += chunk - - if not chunks: - stdout, stderr = p.communicate() - raise AnsibleError( - "privilege output closed while waiting for password prompt:\n" - + to_native(become_output) - ) - become_output += chunks - finally: - selector.close() - - if not self.become.check_success(become_output): - become_pass = self.become.get_option( - "become_pass", playcontext=self._play_context + if self.become and self.become.expect_prompt() and sudoable: + fcntl.fcntl( + p.stdout, + fcntl.F_SETFL, + fcntl.fcntl(p.stdout, fcntl.F_GETFL) | os.O_NONBLOCK, ) - if master is None: - p.stdin.write( - to_bytes(become_pass, errors="surrogate_or_strict") + b"\n" - ) - else: - os.write( - master, - to_bytes(become_pass, errors="surrogate_or_strict") + b"\n", + fcntl.fcntl( + p.stderr, + fcntl.F_SETFL, + fcntl.fcntl(p.stderr, fcntl.F_GETFL) | os.O_NONBLOCK, + ) + selector = selectors.DefaultSelector() + selector.register(p.stdout, selectors.EVENT_READ) + selector.register(p.stderr, selectors.EVENT_READ) + + become_output = b"" + try: + while not self.become.check_success( + become_output + ) and not self.become.check_password_prompt(become_output): + events = selector.select(self._play_context.timeout) + if not events: + stdout, stderr = p.communicate() + raise AnsibleError( + "timeout waiting for privilege escalation password prompt:\n" + + to_native(become_output) + ) + + chunks = b"" + for key, event in events: + if key.fileobj == p.stdout: + chunk = p.stdout.read() + if chunk: + chunks += chunk + elif key.fileobj == p.stderr: + chunk = p.stderr.read() + if chunk: + chunks += chunk + + if not chunks: + stdout, stderr = p.communicate() + raise AnsibleError( + "privilege output closed while waiting for password prompt:\n" + + to_native(become_output) + ) + become_output += chunks + finally: + selector.close() + + if not self.become.check_success(become_output): + become_pass = self.become.get_option( + "become_pass", playcontext=self._play_context ) + if master is None: + p.stdin.write( + to_bytes(become_pass, errors="surrogate_or_strict") + b"\n" + ) + else: + os.write( + master, + to_bytes(become_pass, errors="surrogate_or_strict") + b"\n", + ) - fcntl.fcntl( - p.stdout, - fcntl.F_SETFL, - fcntl.fcntl(p.stdout, fcntl.F_GETFL) & ~os.O_NONBLOCK, - ) - fcntl.fcntl( - p.stderr, - fcntl.F_SETFL, - fcntl.fcntl(p.stderr, fcntl.F_GETFL) & ~os.O_NONBLOCK, - ) + fcntl.fcntl( + p.stdout, + fcntl.F_SETFL, + fcntl.fcntl(p.stdout, fcntl.F_GETFL) & ~os.O_NONBLOCK, + ) + fcntl.fcntl( + p.stderr, + fcntl.F_SETFL, + fcntl.fcntl(p.stderr, fcntl.F_GETFL) & ~os.O_NONBLOCK, + ) - display.debug("getting output with communicate()") - stdout, stderr = p.communicate(in_data) - display.debug("done communicating") + display.debug("getting output with communicate()") + stdout, stderr = p.communicate(in_data) + display.debug("done communicating") - # finally, close the other half of the pty, if it was created - if master: - os.close(master) + # finally, close the other half of the pty, if it was created + if master: + os.close(master) - display.debug("done with nsenter.exec_command()") - return (p.returncode, stdout, stderr) + display.debug("done with nsenter.exec_command()") + return (p.returncode, stdout, stderr) def put_file(self, in_path, out_path): super().put_file(in_path, out_path) diff --git a/plugins/inventory/docker_machine.py b/plugins/inventory/docker_machine.py index 41230fef..d4eae1dd 100644 --- a/plugins/inventory/docker_machine.py +++ b/plugins/inventory/docker_machine.py @@ -125,16 +125,16 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable): NAME = "community.docker.docker_machine" - DOCKER_MACHINE_PATH = None + docker_machine_path = None def _run_command(self, args): - if not self.DOCKER_MACHINE_PATH: + if not self.docker_machine_path: try: - self.DOCKER_MACHINE_PATH = get_bin_path("docker-machine") + self.docker_machine_path = get_bin_path("docker-machine") except ValueError as e: raise AnsibleError(to_native(e)) - command = [self.DOCKER_MACHINE_PATH] + command = [self.docker_machine_path] command.extend(args) display.debug(f"Executing command {command}") try: @@ -217,11 +217,11 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable): if daemon_env == "require": display.warning(f"{warning_prefix}: host will be skipped") return True - else: # 'optional', 'optional-silently' - if daemon_env == "optional": - display.warning( - f"{warning_prefix}: host will lack dm_DOCKER_xxx variables" - ) + if daemon_env == "optional": + display.warning( + f"{warning_prefix}: host will lack dm_DOCKER_xxx variables" + ) + # daemon_env is 'optional-silently' return False def _populate(self): diff --git a/plugins/inventory/docker_swarm.py b/plugins/inventory/docker_swarm.py index 9a43f8d7..46faf6e0 100644 --- a/plugins/inventory/docker_swarm.py +++ b/plugins/inventory/docker_swarm.py @@ -199,7 +199,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable): ) update_tls_hostname(raw_params) connect_params = get_connect_params(raw_params, fail_function=self._fail) - self.client = docker.DockerClient(**connect_params) + client = docker.DockerClient(**connect_params) self.inventory.add_group("all") self.inventory.add_group("manager") self.inventory.add_group("worker") @@ -217,9 +217,9 @@ class InventoryModule(BaseInventoryPlugin, Constructable): host_uri_port = "2375" try: - self.nodes = self.client.nodes.list() - for node in self.nodes: - node_attrs = self.client.nodes.get(node.id).attrs + nodes = client.nodes.list() + for node in nodes: + node_attrs = client.nodes.get(node.id).attrs unsafe_node_attrs = make_unsafe(node_attrs) if not filter_host( self, unsafe_node_attrs["ID"], unsafe_node_attrs, filters diff --git a/plugins/module_utils/_api/_import_helper.py b/plugins/module_utils/_api/_import_helper.py index 1a448fdc..807b5364 100644 --- a/plugins/module_utils/_api/_import_helper.py +++ b/plugins/module_utils/_api/_import_helper.py @@ -70,14 +70,16 @@ except ImportError: self.connection = self self.connectionpool = self - self.RecentlyUsedContainer = object() - self.PoolManager = object() + self.RecentlyUsedContainer = object() # pylint: disable=invalid-name + self.PoolManager = object() # pylint: disable=invalid-name self.match_hostname = object() - self.HTTPConnectionPool = _HTTPConnectionPool + self.HTTPConnectionPool = ( # pylint: disable=invalid-name + _HTTPConnectionPool + ) class FakeURLLIB3Connection: def __init__(self): - self.HTTPConnection = _HTTPConnection + self.HTTPConnection = _HTTPConnection # pylint: disable=invalid-name urllib3 = FakeURLLIB3() urllib3_connection = FakeURLLIB3Connection() diff --git a/plugins/module_utils/_api/api/client.py b/plugins/module_utils/_api/api/client.py index 9dd0a38c..3c7b765e 100644 --- a/plugins/module_utils/_api/api/client.py +++ b/plugins/module_utils/_api/api/client.py @@ -47,7 +47,7 @@ from ..transport.sshconn import PARAMIKO_IMPORT_ERROR, SSHHTTPAdapter from ..transport.ssladapter import SSLHTTPAdapter from ..transport.unixconn import UnixHTTPAdapter from ..utils import config, json_stream, utils -from ..utils.decorators import check_resource, update_headers +from ..utils.decorators import update_headers from ..utils.proxy import ProxyConfig from ..utils.socket import consume_socket_output, demux_adaptor, frames_iter from .daemon import DaemonApiMixin @@ -278,8 +278,7 @@ class APIClient(_Session, DaemonApiMixin): if kwargs.get("versioned_api", True): return f"{self.base_url}/v{self._version}{pathfmt.format(*args)}" - else: - return f"{self.base_url}{pathfmt.format(*args)}" + return f"{self.base_url}{pathfmt.format(*args)}" def _raise_for_status(self, response): """Raises stored :class:`APIError`, if one occurred.""" @@ -427,12 +426,11 @@ class APIClient(_Session, DaemonApiMixin): if stream: return gen - else: - try: - # Wait for all the frames, concatenate them, and return the result - return consume_socket_output(gen, demux=demux) - finally: - response.close() + try: + # Wait for all the frames, concatenate them, and return the result + return consume_socket_output(gen, demux=demux) + finally: + response.close() def _disable_socket_timeout(self, socket): """Depending on the combination of python version and whether we are @@ -462,14 +460,6 @@ class APIClient(_Session, DaemonApiMixin): s.settimeout(None) - @check_resource("container") - def _check_is_tty(self, container): - cont = self.inspect_container(container) - return cont["Config"]["Tty"] - - def _get_result(self, container, stream, res): - return self._get_result_tty(stream, res, self._check_is_tty(container)) - def _get_result_tty(self, stream, res, is_tty): # We should also use raw streaming (without keep-alive) # if we are dealing with a tty-enabled container. @@ -484,8 +474,7 @@ class APIClient(_Session, DaemonApiMixin): sep = b"" if stream: return self._multiplexed_response_stream_helper(res) - else: - return sep.join(list(self._multiplexed_buffer_helper(res))) + return sep.join(list(self._multiplexed_buffer_helper(res))) def _unmount(self, *args): for proto in args: @@ -497,8 +486,7 @@ class APIClient(_Session, DaemonApiMixin): except _InvalidSchema as e: if self._custom_adapter: return self._custom_adapter - else: - raise e + raise e @property def api_version(self): diff --git a/plugins/module_utils/_api/auth.py b/plugins/module_utils/_api/auth.py index 3f7958e6..e6d44085 100644 --- a/plugins/module_utils/_api/auth.py +++ b/plugins/module_utils/_api/auth.py @@ -368,7 +368,7 @@ def _load_legacy_config(config_file): } } } - except Exception as e: + except Exception as e: # pylint: disable=broad-exception-caught log.debug(e) pass diff --git a/plugins/module_utils/_api/context/config.py b/plugins/module_utils/_api/context/config.py index 4c5b2608..b3ff0aa0 100644 --- a/plugins/module_utils/_api/context/config.py +++ b/plugins/module_utils/_api/context/config.py @@ -36,7 +36,7 @@ def get_current_context_name_with_source(): json.load(f).get("currentContext", "default"), f"configuration file {docker_cfg_path}", ) - except Exception: + except Exception: # pylint: disable=broad-exception-caught pass return "default", "fallback value" @@ -54,7 +54,7 @@ def write_context_name_to_docker_config(name=None): try: with open(docker_cfg_path, "rt", encoding="utf-8") as f: config = json.load(f) - except Exception as e: + except Exception as e: # pylint: disable=broad-exception-caught return e current_context = config.get("currentContext", None) if current_context and not name: @@ -68,7 +68,7 @@ def write_context_name_to_docker_config(name=None): try: with open(docker_cfg_path, "wt", encoding="utf-8") as f: json.dump(config, f, indent=4) - except Exception as e: + except Exception as e: # pylint: disable=broad-exception-caught return e diff --git a/plugins/module_utils/_api/context/context.py b/plugins/module_utils/_api/context/context.py index e128af2f..cc27885a 100644 --- a/plugins/module_utils/_api/context/context.py +++ b/plugins/module_utils/_api/context/context.py @@ -42,7 +42,7 @@ class Context: description=None, ): if not name: - raise Exception("Name not provided") + raise ValueError("Name not provided") self.name = name self.context_type = None self.orchestrator = orchestrator @@ -136,7 +136,7 @@ class Context: metadata = json.load(f) except (OSError, KeyError, ValueError) as e: # unknown format - raise Exception( + raise RuntimeError( f"Detected corrupted meta file for context {name} : {e}" ) from e @@ -157,7 +157,7 @@ class Context: def _load_certs(self): certs = {} tls_dir = get_tls_dir(self.name) - for endpoint in self.endpoints.keys(): + for endpoint in self.endpoints: if not os.path.isdir(os.path.join(tls_dir, endpoint)): continue ca_cert = None @@ -238,11 +238,11 @@ class Context: return self.context_type is None @property - def Name(self): + def Name(self): # pylint: disable=invalid-name return self.name @property - def Host(self): + def Host(self): # pylint: disable=invalid-name if not self.orchestrator or self.orchestrator == "swarm": endpoint = self.endpoints.get("docker", None) if endpoint: @@ -252,27 +252,27 @@ class Context: return self.endpoints[self.orchestrator].get("Host", None) @property - def Orchestrator(self): + def Orchestrator(self): # pylint: disable=invalid-name return self.orchestrator @property - def Metadata(self): + def Metadata(self): # pylint: disable=invalid-name meta = {} if self.orchestrator: meta = {"StackOrchestrator": self.orchestrator} return {"Name": self.name, "Metadata": meta, "Endpoints": self.endpoints} @property - def TLSConfig(self): + def TLSConfig(self): # pylint: disable=invalid-name key = self.orchestrator if not key or key == "swarm": key = "docker" - if key in self.tls_cfg.keys(): + if key in self.tls_cfg: return self.tls_cfg[key] return None @property - def TLSMaterial(self): + def TLSMaterial(self): # pylint: disable=invalid-name certs = {} for endpoint, tls in self.tls_cfg.items(): cert, key = tls.cert @@ -280,5 +280,5 @@ class Context: return {"TLSMaterial": certs} @property - def Storage(self): + def Storage(self): # pylint: disable=invalid-name return {"Storage": {"MetadataPath": self.meta_path, "TLSPath": self.tls_path}} diff --git a/plugins/module_utils/_api/credentials/store.py b/plugins/module_utils/_api/credentials/store.py index 7e5b662e..5bf5fd28 100644 --- a/plugins/module_utils/_api/credentials/store.py +++ b/plugins/module_utils/_api/credentials/store.py @@ -91,8 +91,7 @@ class Store: raise errors.StoreError( f"{self.program} not installed or not available in PATH" ) - else: - raise errors.StoreError( - f'Unexpected OS error "{e.strerror}", errno={e.errno}' - ) + raise errors.StoreError( + f'Unexpected OS error "{e.strerror}", errno={e.errno}' + ) return output diff --git a/plugins/module_utils/_api/transport/npipesocket.py b/plugins/module_utils/_api/transport/npipesocket.py index 732b7148..f178c8fd 100644 --- a/plugins/module_utils/_api/transport/npipesocket.py +++ b/plugins/module_utils/_api/transport/npipesocket.py @@ -28,9 +28,9 @@ except ImportError: PYWIN32_IMPORT_ERROR = traceback.format_exc() -cERROR_PIPE_BUSY = 0xE7 -cSECURITY_SQOS_PRESENT = 0x100000 -cSECURITY_ANONYMOUS = 0 +ERROR_PIPE_BUSY = 0xE7 +SECURITY_SQOS_PRESENT = 0x100000 +SECURITY_ANONYMOUS = 0 MAXIMUM_RETRY_COUNT = 10 @@ -55,7 +55,9 @@ class NpipeSocket: def __init__(self, handle=None): self._timeout = win32pipe.NMPWAIT_USE_DEFAULT_WAIT self._handle = handle + self._address = None self._closed = False + self.flags = None def accept(self): raise NotImplementedError() @@ -77,8 +79,8 @@ class NpipeSocket: None, win32file.OPEN_EXISTING, ( - cSECURITY_ANONYMOUS - | cSECURITY_SQOS_PRESENT + SECURITY_ANONYMOUS + | SECURITY_SQOS_PRESENT | win32file.FILE_FLAG_OVERLAPPED ), 0, @@ -86,7 +88,7 @@ class NpipeSocket: except win32pipe.error as e: # See Remarks: # https://msdn.microsoft.com/en-us/library/aa365800.aspx - if e.winerror == cERROR_PIPE_BUSY: + if e.winerror == ERROR_PIPE_BUSY: # Another program or thread has grabbed our pipe instance # before we got to it. Wait for availability and attempt to # connect again. diff --git a/plugins/module_utils/_api/transport/sshconn.py b/plugins/module_utils/_api/transport/sshconn.py index dde4e017..b888b9c9 100644 --- a/plugins/module_utils/_api/transport/sshconn.py +++ b/plugins/module_utils/_api/transport/sshconn.py @@ -72,7 +72,7 @@ class SSHSocket(socket.socket): env.pop("LD_LIBRARY_PATH", None) env.pop("SSL_CERT_FILE", None) - self.proc = subprocess.Popen( + self.proc = subprocess.Popen( # pylint: disable=consider-using-with args, env=env, stdout=subprocess.PIPE, @@ -82,7 +82,7 @@ class SSHSocket(socket.socket): def _write(self, data): if not self.proc or self.proc.stdin.closed: - raise Exception( + raise RuntimeError( "SSH subprocess not initiated. connect() must be called first." ) written = self.proc.stdin.write(data) @@ -97,7 +97,7 @@ class SSHSocket(socket.socket): def recv(self, n): if not self.proc: - raise Exception( + raise RuntimeError( "SSH subprocess not initiated. connect() must be called first." ) return self.proc.stdout.read(n) diff --git a/plugins/module_utils/_api/utils/build.py b/plugins/module_utils/_api/utils/build.py index 6da52457..5a06772b 100644 --- a/plugins/module_utils/_api/utils/build.py +++ b/plugins/module_utils/_api/utils/build.py @@ -125,19 +125,22 @@ def create_archive(root, files=None, fileobj=None, gzip=False, extra_files=None) def mkbuildcontext(dockerfile): - f = tempfile.NamedTemporaryFile() - t = tarfile.open(mode="w", fileobj=f) - if isinstance(dockerfile, io.StringIO): - raise TypeError("Please use io.BytesIO to create in-memory Dockerfiles") - elif isinstance(dockerfile, io.BytesIO): - dfinfo = tarfile.TarInfo("Dockerfile") - dfinfo.size = len(dockerfile.getvalue()) - dockerfile.seek(0) - else: - dfinfo = t.gettarinfo(fileobj=dockerfile, arcname="Dockerfile") - t.addfile(dfinfo, dockerfile) - t.close() - f.seek(0) + f = tempfile.NamedTemporaryFile() # pylint: disable=consider-using-with + try: + with tarfile.open(mode="w", fileobj=f) as t: + if isinstance(dockerfile, io.StringIO): + raise TypeError("Please use io.BytesIO to create in-memory Dockerfiles") + if isinstance(dockerfile, io.BytesIO): + dfinfo = tarfile.TarInfo("Dockerfile") + dfinfo.size = len(dockerfile.getvalue()) + dockerfile.seek(0) + else: + dfinfo = t.gettarinfo(fileobj=dockerfile, arcname="Dockerfile") + t.addfile(dfinfo, dockerfile) + f.seek(0) + except Exception: # noqa: E722 + f.close() + raise return f diff --git a/plugins/module_utils/_api/utils/config.py b/plugins/module_utils/_api/utils/config.py index 47bf29a0..934f2dfc 100644 --- a/plugins/module_utils/_api/utils/config.py +++ b/plugins/module_utils/_api/utils/config.py @@ -68,8 +68,7 @@ def home_dir(): """ if IS_WINDOWS_PLATFORM: return os.environ.get("USERPROFILE", "") - else: - return os.path.expanduser("~") + return os.path.expanduser("~") def load_general_config(config_path=None): diff --git a/plugins/module_utils/_api/utils/decorators.py b/plugins/module_utils/_api/utils/decorators.py index 298fe3bf..f046ebd3 100644 --- a/plugins/module_utils/_api/utils/decorators.py +++ b/plugins/module_utils/_api/utils/decorators.py @@ -17,23 +17,6 @@ from .. import errors from . import utils -def check_resource(resource_name): - def decorator(f): - @functools.wraps(f) - def wrapped(self, resource_id=None, *args, **kwargs): - if resource_id is None and kwargs.get(resource_name): - resource_id = kwargs.pop(resource_name) - if isinstance(resource_id, dict): - resource_id = resource_id.get("Id", resource_id.get("ID")) - if not resource_id: - raise errors.NullResource("Resource ID was not provided") - return f(self, resource_id, *args, **kwargs) - - return wrapped - - return decorator - - def minimum_version(version): def decorator(f): @functools.wraps(f) diff --git a/plugins/module_utils/_api/utils/ports.py b/plugins/module_utils/_api/utils/ports.py index 4d67fc04..11a350e6 100644 --- a/plugins/module_utils/_api/utils/ports.py +++ b/plugins/module_utils/_api/utils/ports.py @@ -90,9 +90,8 @@ def split_port(port): if external is not None and len(internal) != len(external): raise ValueError("Port ranges don't match in length") return internal, external - else: - if not external: - external = [None] * len(internal) - elif len(internal) != len(external): - raise ValueError("Port ranges don't match in length") - return internal, [(host, ext_port) for ext_port in external] + if not external: + external = [None] * len(internal) + elif len(internal) != len(external): + raise ValueError("Port ranges don't match in length") + return internal, [(host, ext_port) for ext_port in external] diff --git a/plugins/module_utils/_api/utils/socket.py b/plugins/module_utils/_api/utils/socket.py index 95ff3de1..615018ad 100644 --- a/plugins/module_utils/_api/utils/socket.py +++ b/plugins/module_utils/_api/utils/socket.py @@ -111,8 +111,7 @@ def frames_iter(socket, tty): """ if tty: return ((STDOUT, frame) for frame in frames_iter_tty(socket)) - else: - return frames_iter_no_tty(socket) + return frames_iter_no_tty(socket) def frames_iter_no_tty(socket): @@ -194,7 +193,6 @@ def demux_adaptor(stream_id, data): """ if stream_id == STDOUT: return (data, None) - elif stream_id == STDERR: + if stream_id == STDERR: return (None, data) - else: - raise ValueError(f"{stream_id} is not a valid stream") + raise ValueError(f"{stream_id} is not a valid stream") diff --git a/plugins/module_utils/_api/utils/utils.py b/plugins/module_utils/_api/utils/utils.py index 046c38e0..e54f6eef 100644 --- a/plugins/module_utils/_api/utils/utils.py +++ b/plugins/module_utils/_api/utils/utils.py @@ -75,10 +75,9 @@ def compare_version(v1, v2): s2 = StrictVersion(v2) if s1 == s2: return 0 - elif s1 > s2: + if s1 > s2: return -1 - else: - return 1 + return 1 def version_lt(v1, v2): @@ -250,7 +249,7 @@ def parse_host(addr, is_win32=False, tls=False): # These protos are valid aliases for our library but not for the # official spec - if proto == "http" or proto == "https": + if proto in ("http", "https"): tls = proto == "https" proto = "tcp" elif proto == "http+unix": @@ -273,12 +272,11 @@ def parse_host(addr, is_win32=False, tls=False): raise errors.DockerException( f"Invalid bind address format: no path allowed for this protocol: {addr}" ) - else: - path = parsed_url.path - if proto == "unix" and parsed_url.hostname is not None: - # For legacy reasons, we consider unix://path - # to be valid and equivalent to unix:///path - path = "/".join((parsed_url.hostname, path)) + path = parsed_url.path + if proto == "unix" and parsed_url.hostname is not None: + # For legacy reasons, we consider unix://path + # to be valid and equivalent to unix:///path + path = "/".join((parsed_url.hostname, path)) netloc = parsed_url.netloc if proto in ("tcp", "ssh"): @@ -419,7 +417,7 @@ def parse_bytes(s): else: digits_part = s[:-1] - if suffix in units.keys() or suffix.isdigit(): + if suffix in units or suffix.isdigit(): try: digits = float(digits_part) except ValueError: diff --git a/plugins/module_utils/_common.py b/plugins/module_utils/_common.py index b0bbdd1d..a3e96fd0 100644 --- a/plugins/module_utils/_common.py +++ b/plugins/module_utils/_common.py @@ -98,7 +98,7 @@ MIN_DOCKER_VERSION = "1.8.0" if not HAS_DOCKER_PY: - docker_version = None + docker_version = None # pylint: disable=invalid-name # No Docker SDK for Python. Create a place holder client to allow # instantiation of AnsibleModule and proper error handing @@ -194,7 +194,7 @@ class AnsibleDockerClientBase(Client): def __init__(self, min_docker_version=None, min_docker_api_version=None): if min_docker_version is None: min_docker_version = MIN_DOCKER_VERSION - NEEDS_DOCKER_PY2 = LooseVersion(min_docker_version) >= LooseVersion("2.0.0") + needs_docker_py2 = LooseVersion(min_docker_version) >= LooseVersion("2.0.0") self.docker_py_version = LooseVersion(docker_version) @@ -218,7 +218,7 @@ class AnsibleDockerClientBase(Client): f"Error: Docker SDK for Python version is {docker_version} ({platform.node()}'s Python {sys.executable})." f" Minimum version required is {min_docker_version}." ) - if not NEEDS_DOCKER_PY2: + if not needs_docker_py2: # The minimal required version is < 2.0 (and the current version as well). # Advertise docker (instead of docker-py). msg += DOCKERPYUPGRADE_RECOMMEND_DOCKER @@ -237,7 +237,7 @@ class AnsibleDockerClientBase(Client): self.docker_api_version_str = self.api_version except APIError as exc: self.fail(f"Docker API error: {exc}") - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error connecting: {exc}") self.docker_api_version = LooseVersion(self.docker_api_version_str) @@ -409,7 +409,7 @@ class AnsibleDockerClientBase(Client): return result except NotFound: return None - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error inspecting container: {exc}") def get_container(self, name=None): @@ -441,7 +441,7 @@ class AnsibleDockerClientBase(Client): break except SSLError as exc: self._handle_ssl_error(exc) - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error retrieving container list: {exc}") if result is None: @@ -470,7 +470,7 @@ class AnsibleDockerClientBase(Client): break except SSLError as exc: self._handle_ssl_error(exc) - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error retrieving network list: {exc}") if result is not None: @@ -483,7 +483,7 @@ class AnsibleDockerClientBase(Client): self.log("Completed network inspection") except NotFound: return None - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error inspecting network: {exc}") return result @@ -533,7 +533,7 @@ class AnsibleDockerClientBase(Client): except NotFound: self.log(f"Image {name}:{tag} not found.") return None - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error inspecting image {name}:{tag} - {exc}") return inspection @@ -555,7 +555,7 @@ class AnsibleDockerClientBase(Client): self.fail(f"Error inspecting image ID {image_id} - {exc}") self.log(f"Image {image_id} not found.") return None - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error inspecting image ID {image_id} - {exc}") return inspection @@ -567,7 +567,7 @@ class AnsibleDockerClientBase(Client): """ try: response = self.images(name=name) - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error searching for image {name} - {exc}") images = response if tag: @@ -606,7 +606,7 @@ class AnsibleDockerClientBase(Client): ) else: self.fail(f"Error pulling {name} - {line.get('error')}") - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error pulling image {name}:{tag} - {exc}") new_tag = self.find_image(name, tag) diff --git a/plugins/module_utils/_common_api.py b/plugins/module_utils/_common_api.py index 22753221..6e390e69 100644 --- a/plugins/module_utils/_common_api.py +++ b/plugins/module_utils/_common_api.py @@ -128,7 +128,7 @@ class AnsibleDockerClientBase(Client): ) except APIError as exc: self.fail(f"Docker API error: {exc}") - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error connecting: {exc}") self.docker_api_version = LooseVersion(self.docker_api_version_str) @@ -308,7 +308,7 @@ class AnsibleDockerClientBase(Client): return result except NotFound: return None - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error inspecting container: {exc}") def get_container(self, name=None): @@ -347,7 +347,7 @@ class AnsibleDockerClientBase(Client): break except SSLError as exc: self._handle_ssl_error(exc) - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error retrieving container list: {exc}") if result is None: @@ -377,7 +377,7 @@ class AnsibleDockerClientBase(Client): break except SSLError as exc: self._handle_ssl_error(exc) - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error retrieving network list: {exc}") if result is not None: @@ -390,7 +390,7 @@ class AnsibleDockerClientBase(Client): self.log("Completed network inspection") except NotFound: return None - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error inspecting network: {exc}") return result @@ -412,7 +412,7 @@ class AnsibleDockerClientBase(Client): else: params["filters"] = convert_filters({"reference": name}) images = self.get_json("/images/json", params=params) - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error searching for image {name} - {exc}") if tag: lookup = f"{name}:{tag}" @@ -472,7 +472,7 @@ class AnsibleDockerClientBase(Client): except NotFound: self.log(f"Image {name}:{tag} not found.") return None - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error inspecting image {name}:{tag} - {exc}") self.log(f"Image {name}:{tag} not found.") @@ -493,7 +493,7 @@ class AnsibleDockerClientBase(Client): self.fail(f"Error inspecting image ID {image_id} - {exc}") self.log(f"Image {image_id} not found.") return None - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error inspecting image ID {image_id} - {exc}") def pull_image(self, name, tag="latest", image_platform=None): @@ -535,7 +535,7 @@ class AnsibleDockerClientBase(Client): ) else: self.fail(f"Error pulling {name} - {line.get('error')}") - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error pulling image {name}:{tag} - {exc}") new_tag = self.find_image(name, tag) diff --git a/plugins/module_utils/_common_cli.py b/plugins/module_utils/_common_cli.py index d3fdfe24..81006d8e 100644 --- a/plugins/module_utils/_common_cli.py +++ b/plugins/module_utils/_common_cli.py @@ -159,7 +159,7 @@ class AnsibleDockerClientBase: self.warn(to_native(stderr)) try: data = json.loads(stdout) - except Exception as exc: + 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)}" ) @@ -177,7 +177,7 @@ class AnsibleDockerClientBase: line = line.strip() if line.startswith(b"{"): result.append(json.loads(line)) - except Exception as exc: + 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)}" ) diff --git a/plugins/module_utils/_compose_v2.py b/plugins/module_utils/_compose_v2.py index f18b2eae..3631a5c4 100644 --- a/plugins/module_utils/_compose_v2.py +++ b/plugins/module_utils/_compose_v2.py @@ -176,9 +176,13 @@ _RE_PULL_EVENT = re.compile( r"\s*" r"(?P\S+)" r"\s+" - r"(?P%s)" + f"(?P{'|'.join(re.escape(status) for status in DOCKER_STATUS_PULL)})" r"\s*" - r"$" % "|".join(re.escape(status) for status in DOCKER_STATUS_PULL) + r"$" +) + +_DOCKER_PULL_PROGRESS_WD = sorted( + DOCKER_PULL_PROGRESS_DONE | DOCKER_PULL_PROGRESS_WORKING ) _RE_PULL_PROGRESS = re.compile( @@ -186,14 +190,10 @@ _RE_PULL_PROGRESS = re.compile( r"\s*" r"(?P\S+)" r"\s+" - r"(?P%s)" + f"(?P{'|'.join(re.escape(status) for status in _DOCKER_PULL_PROGRESS_WD)})" r"\s*" r"(?:|\s\[[^]]+\]\s+\S+\s*|\s+[0-9.kKmMgGbB]+/[0-9.kKmMgGbB]+\s*)" r"$" - % "|".join( - re.escape(status) - for status in sorted(DOCKER_PULL_PROGRESS_DONE | DOCKER_PULL_PROGRESS_WORKING) - ) ) _RE_ERROR_EVENT = re.compile( @@ -201,10 +201,10 @@ _RE_ERROR_EVENT = re.compile( r"\s*" r"(?P\S+)" r"\s+" - r"(?P%s)" + f"(?P{'|'.join(re.escape(status) for status in DOCKER_STATUS_ERROR)})" r"\s*" r"(?P\S.*\S)?" - r"$" % "|".join(re.escape(status) for status in DOCKER_STATUS_ERROR) + r"$" ) _RE_WARNING_EVENT = re.compile( @@ -212,10 +212,10 @@ _RE_WARNING_EVENT = re.compile( r"\s*" r"(?P\S+)" r"\s+" - r"(?P%s)" + f"(?P{'|'.join(re.escape(status) for status in DOCKER_STATUS_WARNING)})" r"\s*" r"(?P\S.*\S)?" - r"$" % "|".join(re.escape(status) for status in DOCKER_STATUS_WARNING) + r"$" ) _RE_CONTINUE_EVENT = re.compile(r"^\s*(?P\S+)\s+-\s*(?P\S(?:|.*\S))$") @@ -405,7 +405,7 @@ def parse_json_events(stderr, warn_function=None): continue try: line_data = json.loads(line) - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught if warn_function: warn_function( f"Cannot parse event from line: {line!r}: {exc}. Please report this at " @@ -544,7 +544,7 @@ def parse_events(stderr, dry_run=False, warn_function=None, nonzero_rc=False): line, warn_missing_dry_run_prefix, warn_function ) continue - elif parsed: + if parsed: continue match = _RE_BUILD_PROGRESS_EVENT.match(line) if match: @@ -748,7 +748,7 @@ class BaseComposeManager(DockerBaseClass): encoding="utf-8", Dumper=_SafeDumper, ) - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error writing to {compose_file} - {exc}") else: self.project_src = os.path.abspath(parameters["project_src"]) @@ -804,7 +804,7 @@ class BaseComposeManager(DockerBaseClass): if version == "dev": return None return version.lstrip("v") - except Exception: + except Exception: # pylint: disable=broad-exception-caught return None def get_compose_version_from_api(self): @@ -946,6 +946,6 @@ class BaseComposeManager(DockerBaseClass): for directory in self.cleanup_dirs: try: shutil.rmtree(directory, True) - except Exception: + except Exception: # pylint: disable=broad-exception-caught # should not happen, but simply ignore to be on the safe side pass diff --git a/plugins/module_utils/_logfmt.py b/plugins/module_utils/_logfmt.py index f0571986..362ae4ff 100644 --- a/plugins/module_utils/_logfmt.py +++ b/plugins/module_utils/_logfmt.py @@ -133,38 +133,35 @@ def parse_line(line, logrus_mode=False): key.append(cur) parser.next() return _Mode.KEY - elif cur == "=": + if cur == "=": parser.next() return _Mode.EQUAL - else: - if logrus_mode: - raise InvalidLogFmt('Key must always be followed by "=" in logrus mode') - handle_kv(has_no_value=True) - parser.next() - return _Mode.GARBAGE + if logrus_mode: + raise InvalidLogFmt('Key must always be followed by "=" in logrus mode') + handle_kv(has_no_value=True) + parser.next() + return _Mode.GARBAGE def parse_equal(cur): if _is_ident(cur): value.append(cur) parser.next() return _Mode.IDENT_VALUE - elif cur == '"': + if cur == '"': parser.next() return _Mode.QUOTED_VALUE - else: - handle_kv() - parser.next() - return _Mode.GARBAGE + handle_kv() + parser.next() + return _Mode.GARBAGE def parse_ident_value(cur): if _is_ident(cur): value.append(cur) parser.next() return _Mode.IDENT_VALUE - else: - handle_kv() - parser.next() - return _Mode.GARBAGE + handle_kv() + parser.next() + return _Mode.GARBAGE def parse_quoted_value(cur): if cur == "\\": @@ -182,16 +179,15 @@ def parse_line(line, logrus_mode=False): value.append(parser.parse_unicode_sequence()) parser.next() return _Mode.QUOTED_VALUE - elif cur == '"': + if cur == '"': handle_kv() parser.next() return _Mode.GARBAGE - elif cur < " ": + if cur < " ": raise InvalidLogFmt("Control characters in quoted string are not allowed") - else: - value.append(cur) - parser.next() - return _Mode.QUOTED_VALUE + value.append(cur) + parser.next() + return _Mode.QUOTED_VALUE parsers = { _Mode.GARBAGE: parse_garbage, @@ -204,7 +200,7 @@ def parse_line(line, logrus_mode=False): mode = parsers[mode](parser.cur()) if mode == _Mode.KEY and logrus_mode: raise InvalidLogFmt('Key must always be followed by "=" in logrus mode') - if mode == _Mode.KEY or mode == _Mode.EQUAL: + if mode in (_Mode.KEY, _Mode.EQUAL): handle_kv(has_no_value=True) elif mode == _Mode.IDENT_VALUE: handle_kv() diff --git a/plugins/module_utils/_module_container/base.py b/plugins/module_utils/_module_container/base.py index 6b917f23..ca4c80ef 100644 --- a/plugins/module_utils/_module_container/base.py +++ b/plugins/module_utils/_module_container/base.py @@ -58,7 +58,7 @@ def _get_ansible_type(value_type): if value_type == "set": return "list" if value_type not in ("list", "dict", "bool", "int", "float", "str"): - raise Exception(f'Invalid type "{value_type}"') + raise ValueError(f'Invalid type "{value_type}"') return value_type @@ -87,13 +87,13 @@ class Option: needs_elements = self.value_type in ("list", "set") needs_ansible_elements = self.ansible_type in ("list",) if elements is not None and not needs_elements: - raise Exception("elements only allowed for lists/sets") + raise ValueError("elements only allowed for lists/sets") if elements is None and needs_elements: - raise Exception("elements required for lists/sets") + raise ValueError("elements required for lists/sets") if ansible_elements is not None and not needs_ansible_elements: - raise Exception("Ansible elements only allowed for Ansible lists") + raise ValueError("Ansible elements only allowed for Ansible lists") if (elements is None and ansible_elements is None) and needs_ansible_elements: - raise Exception("Ansible elements required for Ansible lists") + raise ValueError("Ansible elements required for Ansible lists") self.elements = elements if needs_elements else None self.ansible_elements = ( (ansible_elements or _get_ansible_type(elements)) @@ -104,7 +104,7 @@ class Option: self.ansible_type == "list" and self.ansible_elements == "dict" ) or (self.ansible_type == "dict") if ansible_suboptions is not None and not needs_suboptions: - raise Exception( + raise ValueError( "suboptions only allowed for Ansible lists with dicts, or Ansible dicts" ) if ( @@ -113,7 +113,7 @@ class Option: and not needs_no_suboptions and not not_an_ansible_option ): - raise Exception( + raise ValueError( "suboptions required for Ansible lists with dicts, or Ansible dicts" ) self.ansible_suboptions = ansible_suboptions if needs_suboptions else None @@ -431,16 +431,15 @@ def _parse_port_range(range_or_port, module): if "-" in range_or_port: try: start, end = [int(port) for port in range_or_port.split("-")] - except Exception: + except ValueError: module.fail_json(msg=f'Invalid port range: "{range_or_port}"') if end < start: module.fail_json(msg=f'Invalid port range: "{range_or_port}"') return list(range(start, end + 1)) - else: - try: - return [int(range_or_port)] - except Exception: - module.fail_json(msg=f'Invalid port: "{range_or_port}"') + try: + return [int(range_or_port)] + except ValueError: + module.fail_json(msg=f'Invalid port: "{range_or_port}"') def _split_colon_ipv6(text, module): @@ -707,7 +706,7 @@ def _preprocess_mounts(module, values): if mount_dict["tmpfs_mode"] is not None: try: mount_dict["tmpfs_mode"] = int(mount_dict["tmpfs_mode"], 8) - except Exception: + except ValueError: module.fail_json( msg=f'tmp_fs mode of mount "{target}" is not an octal string!' ) @@ -747,7 +746,7 @@ def _preprocess_mounts(module, values): check_collision(container, "volumes") new_vols.append(f"{host}:{container}:{mode}") continue - elif len(parts) == 2: + if len(parts) == 2: if not _is_volume_permissions(parts[1]) and re.match( r"[.~]", parts[0] ): diff --git a/plugins/module_utils/_module_container/docker_api.py b/plugins/module_utils/_module_container/docker_api.py index 756f5e6a..95b286c8 100644 --- a/plugins/module_utils/_module_container/docker_api.py +++ b/plugins/module_utils/_module_container/docker_api.py @@ -124,7 +124,7 @@ def _get_ansible_type(our_type): if our_type == "set": return "list" if our_type not in ("list", "dict", "bool", "int", "float", "str"): - raise Exception(f'Invalid type "{our_type}"') + raise ValueError(f'Invalid type "{our_type}"') return our_type @@ -266,7 +266,7 @@ class DockerAPIEngineDriver(EngineDriver): # Ensure driver_opts values are strings for key, val in value.items(): if not isinstance(val, str): - raise Exception( + raise ValueError( f"driver_opts values must be strings, got {type(val).__name__} for key '{key}'" ) params[dest_para] = value @@ -278,7 +278,7 @@ class DockerAPIEngineDriver(EngineDriver): params[dest_para] = value if parameters: ups = ", ".join([f'"{p}"' for p in sorted(parameters)]) - raise Exception( + raise ValueError( f"Unknown parameter(s) for connect_container_to_network for Docker API driver: {ups}" ) ipam_config = {} @@ -347,8 +347,7 @@ class DockerAPIEngineDriver(EngineDriver): ) output = client._get_result_tty(False, res, config["Config"]["Tty"]) return output, True - else: - return f"Result logged using `{logging_driver}` driver", False + return f"Result logged using `{logging_driver}` driver", False def update_container(self, client, container_id, update_parameters): result = client.post_json_to_json( @@ -399,13 +398,13 @@ 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 Exception(f"{exc} [tried to unpause three times]") + raise RuntimeError(f"{exc} [tried to unpause three times]") count += 1 # Unpause try: self.unpause_container(client, container_id) except Exception as exc2: - raise Exception(f"{exc2} [while unpausing]") + raise RuntimeError(f"{exc2} [while unpausing]") # Now try again continue raise @@ -430,13 +429,13 @@ 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 Exception(f"{exc} [tried to unpause three times]") + raise RuntimeError(f"{exc} [tried to unpause three times]") count += 1 # Unpause try: self.unpause_container(client, container_id) except Exception as exc2: - raise Exception(f"{exc2} [while unpausing]") + raise RuntimeError(f"{exc2} [while unpausing]") # Now try again continue if ( @@ -1060,7 +1059,7 @@ def _get_network_id(module, client, network_name): network_id = network["Id"] break return network_id - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught client.fail(f"Error getting network id for {network_name} - {exc}") diff --git a/plugins/module_utils/_module_container/module.py b/plugins/module_utils/_module_container/module.py index 0e9ef972..535ed875 100644 --- a/plugins/module_utils/_module_container/module.py +++ b/plugins/module_utils/_module_container/module.py @@ -134,6 +134,7 @@ class ContainerManager(DockerBaseClass): "The value of default_host_ip must be an empty string, an IPv4 address, " f'or an IPv6 address. Got "{self.param_default_host_ip}" instead.' ) + self.parameters = None def _collect_all_options(self, active_options): all_options = {} @@ -480,7 +481,7 @@ class ContainerManager(DockerBaseClass): self.engine_driver.unpause_container( self.client, container.id ) - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail( f"Error {'pausing' if self.param_paused else 'unpausing'} container {container.id}: {exc}" ) @@ -567,13 +568,13 @@ class ContainerManager(DockerBaseClass): if not image or self.param_pull == "always": if not self.check_mode: self.log("Pull the image.") - image, alreadyToLatest = self.engine_driver.pull_image( + image, already_to_latest = self.engine_driver.pull_image( self.client, repository, tag, image_platform=self.module.params["platform"], ) - if alreadyToLatest: + if already_to_latest: self.results["changed"] = False self.results["actions"].append( dict(pulled_image=f"{repository}:{tag}", changed=False) @@ -950,7 +951,7 @@ class ContainerManager(DockerBaseClass): self.engine_driver.disconnect_container_from_network( self.client, container.id, diff["parameter"]["id"] ) - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail( f"Error disconnecting container from network {diff['parameter']['name']} - {exc}" ) @@ -975,7 +976,7 @@ class ContainerManager(DockerBaseClass): self.engine_driver.connect_container_to_network( self.client, container.id, diff["parameter"]["id"], params ) - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail( f"Error connecting container to network {diff['parameter']['name']} - {exc}" ) @@ -989,7 +990,7 @@ class ContainerManager(DockerBaseClass): self.engine_driver.disconnect_container_from_network( self.client, container.id, network["name"] ) - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail( f"Error disconnecting container from network {network['name']} - {exc}" ) @@ -1027,7 +1028,7 @@ class ContainerManager(DockerBaseClass): container_id = self.engine_driver.create_container( self.client, self.param_name, create_parameters, networks=networks ) - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error creating container: {exc}") return self._get_container(container_id) return new_container @@ -1039,7 +1040,7 @@ class ContainerManager(DockerBaseClass): if not self.check_mode: try: self.engine_driver.start_container(self.client, container_id) - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error starting container {container_id}: {exc}") if self.module.params["detach"] is False: @@ -1096,7 +1097,7 @@ class ContainerManager(DockerBaseClass): link=link, force=force, ) - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.client.fail(f"Error removing container {container_id}: {exc}") def container_update(self, container_id, update_parameters): @@ -1112,7 +1113,7 @@ class ContainerManager(DockerBaseClass): self.engine_driver.update_container( self.client, container_id, update_parameters ) - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error updating container {container_id}: {exc}") return self._get_container(container_id) @@ -1126,7 +1127,7 @@ class ContainerManager(DockerBaseClass): self.engine_driver.kill_container( self.client, container_id, kill_signal=self.param_kill_signal ) - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error killing container {container_id}: {exc}") def container_restart(self, container_id): @@ -1139,7 +1140,7 @@ class ContainerManager(DockerBaseClass): self.engine_driver.restart_container( self.client, container_id, self.module.params["stop_timeout"] or 10 ) - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error restarting container {container_id}: {exc}") return self._get_container(container_id) @@ -1156,7 +1157,7 @@ class ContainerManager(DockerBaseClass): self.engine_driver.stop_container( self.client, container_id, self.module.params["stop_timeout"] ) - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error stopping container {container_id}: {exc}") diff --git a/plugins/module_utils/_socket_handler.py b/plugins/module_utils/_socket_handler.py index 8630b923..315af0cf 100644 --- a/plugins/module_utils/_socket_handler.py +++ b/plugins/module_utils/_socket_handler.py @@ -78,15 +78,14 @@ class DockerSocketHandlerBase: if hasattr(self._sock, "recv"): try: data = self._sock.recv(262144) - except Exception as e: + except Exception as e: # pylint: disable=broad-exception-caught # After calling self._sock.shutdown(), OpenSSL's/urllib3's # WrappedSocket seems to eventually raise ZeroReturnError in # case of EOF if "OpenSSL.SSL.ZeroReturnError" in str(type(e)): self._eof = True return - else: - raise + raise elif isinstance(self._sock, getattr(pysocket, "SocketIO")): data = self._sock.read() else: diff --git a/plugins/module_utils/_socket_helper.py b/plugins/module_utils/_socket_helper.py index abd95800..defaf252 100644 --- a/plugins/module_utils/_socket_helper.py +++ b/plugins/module_utils/_socket_helper.py @@ -67,7 +67,6 @@ def write_to_socket(sock, data): # WrappedSocket (urllib3/contrib/pyopenssl) does not have `send`, but # only `sendall`, which uses `_send_until_done` under the hood. return sock._send_until_done(data) - elif hasattr(sock, "send"): + if hasattr(sock, "send"): return sock.send(data) - else: - return os.write(sock.fileno(), data) + return os.write(sock.fileno(), data) diff --git a/plugins/module_utils/_swarm.py b/plugins/module_utils/_swarm.py index 34a6f4ef..93b08d5d 100644 --- a/plugins/module_utils/_swarm.py +++ b/plugins/module_utils/_swarm.py @@ -74,22 +74,18 @@ class AnsibleDockerSwarmClient(AnsibleDockerClient): swarm_info = json.loads(json_str) if swarm_info["Swarm"]["NodeID"]: return True - if swarm_info["Swarm"]["LocalNodeState"] in ( + return swarm_info["Swarm"]["LocalNodeState"] in ( "active", "pending", "locked", - ): - return True + ) return False - else: - try: - node_info = self.get_node_inspect(node_id=node_id) - except APIError: - return + try: + node_info = self.get_node_inspect(node_id=node_id) + except APIError: + return - if node_info["ID"] is not None: - return True - return False + return node_info["ID"] is not None def check_if_swarm_manager(self): """ @@ -138,8 +134,7 @@ class AnsibleDockerSwarmClient(AnsibleDockerClient): True if node is part of swarm but its state is down, False otherwise """ - if repeat_check < 1: - repeat_check = 1 + repeat_check = max(1, repeat_check) if node_id is None: node_id = self.get_swarm_node_id() @@ -179,7 +174,7 @@ class AnsibleDockerSwarmClient(AnsibleDockerClient): if skip_missing: return None self.fail(f"Error while reading from Swarm manager: {exc}") - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error inspecting swarm node: {exc}") json_str = json.dumps(node_info, ensure_ascii=False) @@ -215,7 +210,7 @@ class AnsibleDockerSwarmClient(AnsibleDockerClient): "Cannot inspect node: To inspect node execute module on Swarm Manager" ) self.fail(f"Error while reading from Swarm manager: {exc}") - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error inspecting swarm node: {exc}") json_str = json.dumps(node_info, ensure_ascii=False) @@ -295,7 +290,7 @@ class AnsibleDockerSwarmClient(AnsibleDockerClient): "Cannot inspect service: To inspect service execute module on Swarm Manager" ) self.fail(f"Error inspecting swarm service: {exc}") - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error inspecting swarm service: {exc}") json_str = json.dumps(service_info, ensure_ascii=False) diff --git a/plugins/module_utils/_util.py b/plugins/module_utils/_util.py index 0d9ea39f..ec01a299 100644 --- a/plugins/module_utils/_util.py +++ b/plugins/module_utils/_util.py @@ -56,13 +56,11 @@ DOCKER_COMMON_ARGS = dict( debug=dict(type="bool", default=False), ) -DOCKER_COMMON_ARGS_VARS = dict( - [ - [option_name, f"ansible_docker_{option_name}"] - for option_name in DOCKER_COMMON_ARGS - if option_name != "debug" - ] -) +DOCKER_COMMON_ARGS_VARS = { + option_name: f"ansible_docker_{option_name}" + for option_name in DOCKER_COMMON_ARGS + if option_name != "debug" +} DOCKER_MUTUALLY_EXCLUSIVE = [] @@ -100,10 +98,9 @@ def sanitize_result(data): """ if isinstance(data, dict): return dict((k, sanitize_result(v)) for k, v in data.items()) - elif isinstance(data, (list, tuple)): + if isinstance(data, (list, tuple)): return [sanitize_result(v) for v in data] - else: - return data + return data def log_debug(msg, pretty_print=False): @@ -196,31 +193,28 @@ def compare_generic(a, b, method, datatype): # Do proper comparison (both objects not None) if datatype == "value": return a == b - elif datatype == "list": + if datatype == "list": if method == "strict": return a == b - else: - i = 0 - for v in a: - while i < len(b) and b[i] != v: - i += 1 - if i == len(b): - return False + i = 0 + for v in a: + while i < len(b) and b[i] != v: i += 1 - return True - elif datatype == "dict": + if i == len(b): + return False + i += 1 + return True + if datatype == "dict": if method == "strict": return a == b - else: - return compare_dict_allow_more_present(a, b) - elif datatype == "set": + return compare_dict_allow_more_present(a, b) + if datatype == "set": set_a = set(a) set_b = set(b) if method == "strict": return set_a == set_b - else: - return set_b >= set_a - elif datatype == "set(dict)": + return set_b >= set_a + if datatype == "set(dict)": for av in a: found = False for bv in b: @@ -337,10 +331,9 @@ def clean_dict_booleans_for_docker_api(data, allow_sequences=False): def sanitize(value): if value is True: return "true" - elif value is False: + if value is False: return "false" - else: - return str(value) + return str(value) result = dict() if data is not None: diff --git a/plugins/modules/docker_config.py b/plugins/modules/docker_config.py index 1af51533..b494095d 100644 --- a/plugins/modules/docker_config.py +++ b/plugins/modules/docker_config.py @@ -243,7 +243,7 @@ class ConfigManager(DockerBaseClass): try: with open(data_src, "rb") as f: self.data = f.read() - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.client.fail(f"Error while reading {data_src}: {exc}") self.labels = parameters.get("labels") self.force = parameters.get("force") diff --git a/plugins/modules/docker_container_copy_into.py b/plugins/modules/docker_container_copy_into.py index 86159d88..f2f9d49c 100644 --- a/plugins/modules/docker_container_copy_into.py +++ b/plugins/modules/docker_container_copy_into.py @@ -343,31 +343,31 @@ def retrieve_diff( diff["before_header"] = container_path diff["before"] = "(directory)" return - elif regular_stat["mode"] & (1 << (32 - 4)) != 0: + if regular_stat["mode"] & (1 << (32 - 4)) != 0: diff["before_header"] = container_path diff["before"] = "(temporary file)" return - elif regular_stat["mode"] & (1 << (32 - 5)) != 0: + if regular_stat["mode"] & (1 << (32 - 5)) != 0: diff["before_header"] = container_path diff["before"] = link_target return - elif regular_stat["mode"] & (1 << (32 - 6)) != 0: + if regular_stat["mode"] & (1 << (32 - 6)) != 0: diff["before_header"] = container_path diff["before"] = "(device)" return - elif regular_stat["mode"] & (1 << (32 - 7)) != 0: + if regular_stat["mode"] & (1 << (32 - 7)) != 0: diff["before_header"] = container_path diff["before"] = "(named pipe)" return - elif regular_stat["mode"] & (1 << (32 - 8)) != 0: + if regular_stat["mode"] & (1 << (32 - 8)) != 0: diff["before_header"] = container_path diff["before"] = "(socket)" return - elif regular_stat["mode"] & (1 << (32 - 11)) != 0: + if regular_stat["mode"] & (1 << (32 - 11)) != 0: diff["before_header"] = container_path diff["before"] = "(character device)" return - elif regular_stat["mode"] & (1 << (32 - 13)) != 0: + if regular_stat["mode"] & (1 << (32 - 13)) != 0: diff["before_header"] = container_path diff["before"] = "(unknown filesystem object)" return @@ -1084,9 +1084,7 @@ def main(): if client.module.params["content_is_b64"]: try: content = base64.b64decode(content) - except ( - Exception - ) as e: # depending on Python version and error, multiple different exceptions can be raised + except Exception as e: # pylint: disable=broad-exception-caught client.fail(f"Cannot Base64 decode the content option: {e}") else: content = to_bytes(content) diff --git a/plugins/modules/docker_host_info.py b/plugins/modules/docker_host_info.py index 746bbd20..8bd12f30 100644 --- a/plugins/modules/docker_host_info.py +++ b/plugins/modules/docker_host_info.py @@ -271,8 +271,7 @@ class DockerHostManager(DockerBaseClass): try: if self.verbose_output: return self.client.df() - else: - return dict(LayersSize=self.client.df()["LayersSize"]) + return dict(LayersSize=self.client.df()["LayersSize"]) except APIError as exc: self.client.fail(f"Error inspecting docker host: {exc}") diff --git a/plugins/modules/docker_image.py b/plugins/modules/docker_image.py index 353f407c..b7ee1131 100644 --- a/plugins/modules/docker_image.py +++ b/plugins/modules/docker_image.py @@ -618,7 +618,7 @@ class ImageManager(DockerBaseClass): except NotFound: # If the image vanished while we were trying to remove it, do not fail pass - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error removing image {name} - {exc}") self.results["changed"] = True @@ -656,17 +656,16 @@ class ImageManager(DockerBaseClass): if archived is None: return build_msg("since none present") - elif ( + if ( current_image_id == api_image_id(archived.image_id) and [current_image_name] == archived.repo_tags ): return None - else: - name = ", ".join(archived.repo_tags) + name = ", ".join(archived.repo_tags) - return build_msg( - f"overwriting archive with image {archived.image_id} named {name}" - ) + return build_msg( + f"overwriting archive with image {archived.image_id} named {name}" + ) def archive_image(self, name, tag): """ @@ -714,14 +713,14 @@ class ImageManager(DockerBaseClass): DEFAULT_DATA_CHUNK_SIZE, False, ) - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error getting image {image_name} - {exc}") try: with open(self.archive_path, "wb") as fd: for chunk in saved_image: fd.write(chunk) - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error writing image archive {self.archive_path} - {exc}") self.results["image"] = image @@ -779,12 +778,12 @@ class ImageManager(DockerBaseClass): for line in self.client._stream_helper(response, decode=True): self.log(line, pretty_print=True) if line.get("errorDetail"): - raise Exception(line["errorDetail"]["message"]) + raise RuntimeError(line["errorDetail"]["message"]) status = line.get("status") if status == "Pushing": changed = True self.results["changed"] = changed - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught if "unauthorized" in str(exc): if "authentication required" in str(exc): self.fail( @@ -842,8 +841,8 @@ class ImageManager(DockerBaseClass): ) self.client._raise_for_status(res) if res.status_code != 201: - raise Exception("Tag operation failed.") - except Exception as exc: + raise RuntimeError("Tag operation failed.") + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error: failed to tag image - {exc}") self.results["image"] = self.client.find_image(name=repo, tag=repo_tag) if image and image["Id"] == self.results["image"]["Id"]: @@ -969,9 +968,9 @@ class ImageManager(DockerBaseClass): if line.get("error"): if line.get("errorDetail"): - errorDetail = line.get("errorDetail") + error_detail = line.get("errorDetail") self.fail( - f"Error building {self.name} - code: {errorDetail.get('code')}, message: {errorDetail.get('message')}, logs: {build_output}" + f"Error building {self.name} - code: {error_detail.get('code')}, message: {error_detail.get('message')}, logs: {build_output}" ) else: self.fail( @@ -1019,7 +1018,7 @@ class ImageManager(DockerBaseClass): f"Error loading image {self.name} - {exc}", stdout="\n".join(load_output), ) - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.client.fail( f"Error loading image {self.name} - {exc}", stdout="\n".join(load_output), @@ -1076,8 +1075,7 @@ class ImageManager(DockerBaseClass): if is_image_name_id(self.name): return self.client.find_image_by_id(self.name, accept_missing_image=True) - else: - return self.client.find_image(self.name, self.tag) + return self.client.find_image(self.name, self.tag) def main(): diff --git a/plugins/modules/docker_image_export.py b/plugins/modules/docker_image_export.py index 1f856a38..eb32f9a4 100644 --- a/plugins/modules/docker_image_export.py +++ b/plugins/modules/docker_image_export.py @@ -189,7 +189,7 @@ class ImageExportManager(DockerBaseClass): with open(self.path, "wb") as fd: for chunk in chunks: fd.write(chunk) - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error writing image archive {self.path} - {exc}") def export_images(self): @@ -205,7 +205,7 @@ class ImageExportManager(DockerBaseClass): DEFAULT_DATA_CHUNK_SIZE, False, ) - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error getting image {image_names[0]} - {exc}") else: self.log(f"Getting archive of images {image_names_str}") @@ -219,7 +219,7 @@ class ImageExportManager(DockerBaseClass): DEFAULT_DATA_CHUNK_SIZE, False, ) - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error getting images {image_names_str} - {exc}") self.write_chunks(chunks) diff --git a/plugins/modules/docker_image_info.py b/plugins/modules/docker_image_info.py index 9b5f5322..a9ca0405 100644 --- a/plugins/modules/docker_image_info.py +++ b/plugins/modules/docker_image_info.py @@ -212,7 +212,7 @@ class ImageManager(DockerBaseClass): inspection = self.client.get_json("/images/{0}/json", image["Id"]) except NotFound: inspection = None - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error inspecting image {image['Id']} - {exc}") results.append(inspection) return results diff --git a/plugins/modules/docker_image_load.py b/plugins/modules/docker_image_load.py index 0b1d96b8..e49a5b4c 100644 --- a/plugins/modules/docker_image_load.py +++ b/plugins/modules/docker_image_load.py @@ -141,7 +141,7 @@ class ImageManager(DockerBaseClass): f"Error loading archive {self.path} - {exc}", stdout="\n".join(load_output), ) - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.client.fail( f"Error loading archive {self.path} - {exc}", stdout="\n".join(load_output), diff --git a/plugins/modules/docker_image_push.py b/plugins/modules/docker_image_push.py index 5a8d60c5..a6d711b2 100644 --- a/plugins/modules/docker_image_push.py +++ b/plugins/modules/docker_image_push.py @@ -155,11 +155,11 @@ class ImagePusher(DockerBaseClass): for line in self.client._stream_helper(response, decode=True): self.log(line, pretty_print=True) if line.get("errorDetail"): - raise Exception(line["errorDetail"]["message"]) + raise RuntimeError(line["errorDetail"]["message"]) status = line.get("status") if status == "Pushing": results["changed"] = True - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught if "unauthorized" in str(exc): if "authentication required" in str(exc): self.client.fail( diff --git a/plugins/modules/docker_image_remove.py b/plugins/modules/docker_image_remove.py index 97ceaf4f..ca2d7569 100644 --- a/plugins/modules/docker_image_remove.py +++ b/plugins/modules/docker_image_remove.py @@ -194,7 +194,7 @@ class ImageRemover(DockerBaseClass): except NotFound: # If the image vanished while we were trying to remove it, do not fail res = [] - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error removing image {name} - {exc}") for entry in res: diff --git a/plugins/modules/docker_image_tag.py b/plugins/modules/docker_image_tag.py index 131b8d97..d27553ac 100644 --- a/plugins/modules/docker_image_tag.py +++ b/plugins/modules/docker_image_tag.py @@ -214,8 +214,8 @@ class ImageTagger(DockerBaseClass): ) self.client._raise_for_status(res) if res.status_code != 201: - raise Exception("Tag operation failed.") - except Exception as exc: + raise RuntimeError("Tag operation failed.") + except Exception as exc: # pylint: disable=broad-exception-caught self.fail(f"Error: failed to tag image as {name}:{tag} - {exc}") return True, msg, tagged_image diff --git a/plugins/modules/docker_login.py b/plugins/modules/docker_login.py index e1e1c2d2..9de88be0 100644 --- a/plugins/modules/docker_login.py +++ b/plugins/modules/docker_login.py @@ -309,7 +309,7 @@ class LoginManager(DockerBaseClass): self.log(f"Log into {self.registry_url} with username {self.username}") try: response = self._login(self.reauthorize) - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail( f"Logging into {self.registry_url} for user {self.username} failed - {exc}" ) @@ -322,7 +322,7 @@ class LoginManager(DockerBaseClass): if not self.reauthorize and response["password"] != self.password: try: response = self._login(True) - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.fail( f"Logging into {self.registry_url} for user {self.username} failed - {exc}" ) diff --git a/plugins/modules/docker_network.py b/plugins/modules/docker_network.py index 8f988ba4..34edb46a 100644 --- a/plugins/modules/docker_network.py +++ b/plugins/modules/docker_network.py @@ -359,7 +359,7 @@ def validate_cidr(cidr): """ if CIDR_IPV4.match(cidr): return "ipv4" - elif CIDR_IPV6.match(cidr): + if CIDR_IPV6.match(cidr): return "ipv6" raise ValueError(f'"{cidr}" is not a valid CIDR') diff --git a/plugins/modules/docker_secret.py b/plugins/modules/docker_secret.py index d4e20f11..378876a0 100644 --- a/plugins/modules/docker_secret.py +++ b/plugins/modules/docker_secret.py @@ -235,7 +235,7 @@ class SecretManager(DockerBaseClass): try: with open(data_src, "rb") as f: self.data = f.read() - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught self.client.fail(f"Error while reading {data_src}: {exc}") self.labels = parameters.get("labels") self.force = parameters.get("force") diff --git a/plugins/modules/docker_stack.py b/plugins/modules/docker_stack.py index 07da50c9..06fdef48 100644 --- a/plugins/modules/docker_stack.py +++ b/plugins/modules/docker_stack.py @@ -196,9 +196,8 @@ def docker_service_inspect(client, service_name): rc, out, err = client.call_cli("service", "inspect", service_name) if rc != 0: return None - else: - ret = json.loads(out)[0]["Spec"] - return ret + ret = json.loads(out)[0]["Spec"] + return ret def docker_stack_deploy(client, stack_name, compose_files): diff --git a/plugins/modules/docker_swarm.py b/plugins/modules/docker_swarm.py index e1c4c50a..d55b52c1 100644 --- a/plugins/modules/docker_swarm.py +++ b/plugins/modules/docker_swarm.py @@ -323,6 +323,7 @@ class TaskParameters(DockerBaseClass): self.join_token = None self.data_path_addr = None self.data_path_port = None + self.spec = None # Spec self.snapshot_interval = None diff --git a/plugins/modules/docker_swarm_service.py b/plugins/modules/docker_swarm_service.py index 90889390..754b750f 100644 --- a/plugins/modules/docker_swarm_service.py +++ b/plugins/modules/docker_swarm_service.py @@ -932,8 +932,7 @@ def get_docker_environment(env, env_files): if not env_list: if env is not None or env_files is not None: return [] - else: - return None + return None return sorted(env_list) @@ -992,17 +991,16 @@ def get_docker_networks(networks, network_ids): def get_nanoseconds_from_raw_option(name, value): if value is None: return None - elif isinstance(value, int): + if isinstance(value, int): return value - elif isinstance(value, str): + if isinstance(value, str): try: return int(value) except ValueError: return convert_duration_to_nanosecond(value) - else: - raise ValueError( - f"Invalid type for {name} {value} ({type(value)}). Only string or int allowed." - ) + raise ValueError( + f"Invalid type for {name} {value} ({type(value)}). Only string or int allowed." + ) def get_value(key, values, default=None): @@ -1046,9 +1044,8 @@ def has_list_changed(new_list, old_list, sort_lists=True, sort_key=None): if unsorted_list and isinstance(unsorted_list[0], dict): if not sort_key: - raise Exception("A sort key was not specified when sorting list") - else: - return sorted(unsorted_list, key=lambda k: k[sort_key]) + raise ValueError("A sort key was not specified when sorting list") + return sorted(unsorted_list, key=lambda k: k[sort_key]) # Either the list is empty or does not contain dictionaries try: @@ -1081,8 +1078,7 @@ def has_list_changed(new_list, old_list, sort_lists=True, sort_key=None): old_item_casted = new_item_type(old_item) if new_item != old_item_casted: return True - else: - continue + continue except UnicodeEncodeError: # Fallback to assuming the strings are different return True @@ -1374,7 +1370,7 @@ class DockerService(DockerBaseClass): try: memory = human_to_bytes(memory) except ValueError as exc: - raise Exception(f"Failed to convert limit_memory to bytes: {exc}") + raise ValueError(f"Failed to convert limit_memory to bytes: {exc}") return { "limit_cpu": cpus, "limit_memory": memory, @@ -1396,7 +1392,7 @@ class DockerService(DockerBaseClass): try: memory = human_to_bytes(memory) except ValueError as exc: - raise Exception(f"Failed to convert reserve_memory to bytes: {exc}") + raise ValueError(f"Failed to convert reserve_memory to bytes: {exc}") return { "reserve_cpu": cpus, "reserve_memory": memory, @@ -1470,7 +1466,7 @@ class DockerService(DockerBaseClass): for index, item in invalid_items ] ) - raise Exception( + raise ValueError( "All items in a command list need to be strings. " f"Check quoting. Invalid items: {errors}." ) @@ -2339,7 +2335,7 @@ class DockerServiceManager: ds.mode = to_text("replicated-job", encoding="utf-8") ds.replicas = mode["ReplicatedJob"]["TotalCompletions"] else: - raise Exception(f"Unknown service mode: {mode}") + raise ValueError(f"Unknown service mode: {mode}") raw_data_mounts = task_template_data["ContainerSpec"].get("Mounts") if raw_data_mounts: @@ -2510,7 +2506,7 @@ class DockerServiceManager: try: current_service = self.get_service(module.params["name"]) - except Exception as e: + except Exception as e: # pylint: disable=broad-exception-caught self.client.fail( f"Error looking for service named {module.params['name']}: {e}" ) @@ -2527,7 +2523,7 @@ class DockerServiceManager: network_ids, self.client, ) - except Exception as e: + except Exception as e: # pylint: disable=broad-exception-caught return self.client.fail(f"Error parsing module parameters: {e}") changed = False diff --git a/plugins/modules/docker_volume_info.py b/plugins/modules/docker_volume_info.py index e051bd77..e0f99a50 100644 --- a/plugins/modules/docker_volume_info.py +++ b/plugins/modules/docker_volume_info.py @@ -87,7 +87,7 @@ def get_existing_volume(client, volume_name): return client.get_json("/volumes/{0}", volume_name) except NotFound: return None - except Exception as exc: + except Exception as exc: # pylint: disable=broad-exception-caught client.fail(f"Error inspecting volume: {exc}") diff --git a/plugins/plugin_utils/_common.py b/plugins/plugin_utils/_common.py index 9700ed00..1803df67 100644 --- a/plugins/plugin_utils/_common.py +++ b/plugins/plugin_utils/_common.py @@ -40,6 +40,4 @@ class AnsibleDockerClient(AnsibleDockerClientBase): ) def _get_params(self): - return dict( - [(option, self.plugin.get_option(option)) for option in DOCKER_COMMON_ARGS] - ) + return {option: self.plugin.get_option(option) for option in DOCKER_COMMON_ARGS} diff --git a/plugins/plugin_utils/_common_api.py b/plugins/plugin_utils/_common_api.py index 1f40b5f7..340a7565 100644 --- a/plugins/plugin_utils/_common_api.py +++ b/plugins/plugin_utils/_common_api.py @@ -37,6 +37,4 @@ class AnsibleDockerClient(AnsibleDockerClientBase): ) def _get_params(self): - return dict( - [(option, self.plugin.get_option(option)) for option in DOCKER_COMMON_ARGS] - ) + return {option: self.plugin.get_option(option) for option in DOCKER_COMMON_ARGS} diff --git a/plugins/plugin_utils/_unsafe.py b/plugins/plugin_utils/_unsafe.py index c70959d6..29576dce 100644 --- a/plugins/plugin_utils/_unsafe.py +++ b/plugins/plugin_utils/_unsafe.py @@ -27,15 +27,15 @@ def make_unsafe(value): if isinstance(value, Mapping): return dict((make_unsafe(key), make_unsafe(val)) for key, val in value.items()) - elif isinstance(value, Set): + if isinstance(value, Set): return set(make_unsafe(elt) for elt in value) - elif is_sequence(value): + if is_sequence(value): return type(value)(make_unsafe(elt) for elt in value) - elif isinstance(value, bytes): + if isinstance(value, bytes): if _RE_TEMPLATE_CHARS_BYTES.search(value): value = _make_unsafe(value) return value - elif isinstance(value, str): + if isinstance(value, str): if _RE_TEMPLATE_CHARS.search(value): value = _make_unsafe(value) return value 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 2f77b2c0..918d4686 100644 --- a/tests/unit/plugins/module_utils/_api/api/test_client.py +++ b/tests/unit/plugins/module_utils/_api/api/test_client.py @@ -72,7 +72,9 @@ def response( return res -def fake_resolve_authconfig(authconfig, registry=None, *args, **kwargs): +def fake_resolve_authconfig( + authconfig, registry=None, *args, **kwargs +): # pylint: disable=keyword-arg-before-vararg return None @@ -87,7 +89,7 @@ def fake_resp(method, url, *args, **kwargs): elif (url, method) in fake_api.fake_responses: key = (url, method) if not key: - raise Exception(f"{method} {url}") + raise NotImplementedError(f"{method} {url}") status_code, content = fake_api.fake_responses[key]() return response(status_code=status_code, content=content) @@ -115,8 +117,8 @@ def fake_read_from_socket(self, response, stream, tty=False, demux=False): return b"" -url_base = f"{fake_api.prefix}/" -url_prefix = f"{url_base}v{DEFAULT_DOCKER_API_VERSION}/" +url_base = f"{fake_api.prefix}/" # pylint: disable=invalid-name +url_prefix = f"{url_base}v{DEFAULT_DOCKER_API_VERSION}/" # pylint: disable=invalid-name class BaseAPIClientTest(unittest.TestCase): @@ -482,7 +484,7 @@ class TCPSocketStreamTest(unittest.TestCase): stderr_data = cls.stderr_data class Handler(BaseHTTPRequestHandler): - def do_POST(self): + def do_POST(self): # pylint: disable=invalid-name resp_data = self.get_resp_data() self.send_response(101) self.send_header("Content-Type", "application/vnd.docker.raw-stream") @@ -498,15 +500,14 @@ class TCPSocketStreamTest(unittest.TestCase): path = self.path.split("/")[-1] if path == "tty": return stdout_data + stderr_data - elif path == "no-tty": + if path == "no-tty": data = b"" data += self.frame_header(1, stdout_data) data += stdout_data data += self.frame_header(2, stderr_data) data += stderr_data return data - else: - raise Exception(f"Unknown path {path}") + raise NotImplementedError(f"Unknown path {path}") @staticmethod def frame_header(stream, data): @@ -604,6 +605,7 @@ class DisableSocketTest(unittest.TestCase): class DummySocket: def __init__(self, timeout=60): self.timeout = timeout + self._sock = None def settimeout(self, timeout): self.timeout = timeout diff --git a/tests/unit/plugins/module_utils/_api/fake_api.py b/tests/unit/plugins/module_utils/_api/fake_api.py index 23ddc9f4..41c5ed4c 100644 --- a/tests/unit/plugins/module_utils/_api/fake_api.py +++ b/tests/unit/plugins/module_utils/_api/fake_api.py @@ -537,9 +537,9 @@ def post_fake_secret(): # Maps real api url to fake response callback -prefix = "http+docker://localhost" +prefix = "http+docker://localhost" # pylint: disable=invalid-name if constants.IS_WINDOWS_PLATFORM: - prefix = "http+docker://localnpipe" + prefix = "http+docker://localnpipe" # pylint: disable=invalid-name fake_responses = { f"{prefix}/version": get_fake_version, diff --git a/tests/unit/plugins/module_utils/_api/utils/test_build.py b/tests/unit/plugins/module_utils/_api/utils/test_build.py index eb537d35..043bd958 100644 --- a/tests/unit/plugins/module_utils/_api/utils/test_build.py +++ b/tests/unit/plugins/module_utils/_api/utils/test_build.py @@ -417,8 +417,8 @@ class TarTest(unittest.TestCase): self.addCleanup(shutil.rmtree, base) with tar(base, exclude=exclude) as archive: - tar_data = tarfile.open(fileobj=archive) - assert sorted(tar_data.getnames()) == sorted(expected_names) + with tarfile.open(fileobj=archive) as tar_data: + assert sorted(tar_data.getnames()) == sorted(expected_names) def test_tar_with_empty_directory(self): base = tempfile.mkdtemp() @@ -426,8 +426,8 @@ class TarTest(unittest.TestCase): for d in ["foo", "bar"]: os.makedirs(os.path.join(base, d)) with tar(base) as archive: - tar_data = tarfile.open(fileobj=archive) - assert sorted(tar_data.getnames()) == ["bar", "foo"] + with tarfile.open(fileobj=archive) as tar_data: + assert sorted(tar_data.getnames()) == ["bar", "foo"] @pytest.mark.skipif( IS_WINDOWS_PLATFORM or os.geteuid() == 0, @@ -454,8 +454,8 @@ class TarTest(unittest.TestCase): os.makedirs(os.path.join(base, "bar")) os.symlink("../foo", os.path.join(base, "bar/foo")) with tar(base) as archive: - tar_data = tarfile.open(fileobj=archive) - assert sorted(tar_data.getnames()) == ["bar", "bar/foo", "foo"] + with tarfile.open(fileobj=archive) as tar_data: + assert sorted(tar_data.getnames()) == ["bar", "bar/foo", "foo"] @pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason="No symlinks on Windows") def test_tar_with_directory_symlinks(self): @@ -465,8 +465,8 @@ class TarTest(unittest.TestCase): os.makedirs(os.path.join(base, d)) os.symlink("../foo", os.path.join(base, "bar/foo")) with tar(base) as archive: - tar_data = tarfile.open(fileobj=archive) - assert sorted(tar_data.getnames()) == ["bar", "bar/foo", "foo"] + with tarfile.open(fileobj=archive) as tar_data: + assert sorted(tar_data.getnames()) == ["bar", "bar/foo", "foo"] @pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason="No symlinks on Windows") def test_tar_with_broken_symlinks(self): @@ -477,8 +477,8 @@ class TarTest(unittest.TestCase): os.symlink("../baz", os.path.join(base, "bar/foo")) with tar(base) as archive: - tar_data = tarfile.open(fileobj=archive) - assert sorted(tar_data.getnames()) == ["bar", "bar/foo", "foo"] + with tarfile.open(fileobj=archive) as tar_data: + assert sorted(tar_data.getnames()) == ["bar", "bar/foo", "foo"] @pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason="No UNIX sockets on Win32") def test_tar_socket_file(self): @@ -490,8 +490,8 @@ class TarTest(unittest.TestCase): self.addCleanup(sock.close) sock.bind(os.path.join(base, "test.sock")) with tar(base) as archive: - tar_data = tarfile.open(fileobj=archive) - assert sorted(tar_data.getnames()) == ["bar", "foo"] + with tarfile.open(fileobj=archive) as tar_data: + assert sorted(tar_data.getnames()) == ["bar", "foo"] def tar_test_negative_mtime_bug(self): base = tempfile.mkdtemp() @@ -501,9 +501,9 @@ class TarTest(unittest.TestCase): f.write("Invisible Full Moon") os.utime(filename, (12345, -3600.0)) with tar(base) as archive: - tar_data = tarfile.open(fileobj=archive) - assert tar_data.getnames() == ["th.txt"] - assert tar_data.getmember("th.txt").mtime == -3600 + with tarfile.open(fileobj=archive) as tar_data: + assert tar_data.getnames() == ["th.txt"] + assert tar_data.getmember("th.txt").mtime == -3600 @pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason="No symlinks on Windows") def test_tar_directory_link(self): @@ -513,8 +513,8 @@ class TarTest(unittest.TestCase): self.addCleanup(shutil.rmtree, base) os.symlink(os.path.join(base, "b"), os.path.join(base, "a/c/b")) with tar(base) as archive: - tar_data = tarfile.open(fileobj=archive) - names = tar_data.getnames() + with tarfile.open(fileobj=archive) as tar_data: + names = tar_data.getnames() for member in dirs + files: assert member in names assert "a/c/b" in names diff --git a/tests/unit/plugins/module_utils/_api/utils/test_config.py b/tests/unit/plugins/module_utils/_api/utils/test_config.py index 6b400694..324e81b9 100644 --- a/tests/unit/plugins/module_utils/_api/utils/test_config.py +++ b/tests/unit/plugins/module_utils/_api/utils/test_config.py @@ -12,6 +12,7 @@ import json import os import shutil import tempfile +import typing as t import unittest from pytest import fixture, mark @@ -26,6 +27,7 @@ except ImportError: class FindConfigFileTest(unittest.TestCase): + mkdir: t.Callable[[str], os.PathLike[str]] @fixture(autouse=True) def tmpdir(self, tmpdir): diff --git a/tests/unit/plugins/module_utils/_api/utils/test_utils.py b/tests/unit/plugins/module_utils/_api/utils/test_utils.py index 9344d60e..85b4619d 100644 --- a/tests/unit/plugins/module_utils/_api/utils/test_utils.py +++ b/tests/unit/plugins/module_utils/_api/utils/test_utils.py @@ -205,9 +205,8 @@ class ParseEnvFileTest(unittest.TestCase): of 'file_content' and returns the filename. Don't forget to unlink the file with os.unlink() after. """ - local_tempfile = tempfile.NamedTemporaryFile(delete=False) - local_tempfile.write(file_content.encode("UTF-8")) - local_tempfile.close() + with tempfile.NamedTemporaryFile(delete=False) as local_tempfile: + local_tempfile.write(file_content.encode("UTF-8")) return local_tempfile.name def test_parse_env_file_proper(self): diff --git a/tests/unit/plugins/module_utils/compose_v2_test_cases.py b/tests/unit/plugins/module_utils/compose_v2_test_cases.py index 1b948caa..c9da99a6 100644 --- a/tests/unit/plugins/module_utils/compose_v2_test_cases.py +++ b/tests/unit/plugins/module_utils/compose_v2_test_cases.py @@ -2,6 +2,8 @@ # 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 +# pylint: disable=line-too-long + from __future__ import annotations from ansible_collections.community.docker.plugins.module_utils._compose_v2 import ( diff --git a/tests/unit/plugins/test_support/docker_image_archive_stubbing.py b/tests/unit/plugins/test_support/docker_image_archive_stubbing.py index 3c4de73c..06bd1a42 100644 --- a/tests/unit/plugins/test_support/docker_image_archive_stubbing.py +++ b/tests/unit/plugins/test_support/docker_image_archive_stubbing.py @@ -50,8 +50,7 @@ def write_irrelevant_tar(file_name): :type file_name: str """ - tf = tarfile.open(file_name, "w") - try: + with tarfile.open(file_name, "w") as tf: with TemporaryFile() as f: f.write("Hello, world.".encode("utf-8")) @@ -60,6 +59,3 @@ def write_irrelevant_tar(file_name): f.seek(0) tf.addfile(ti, f) - - finally: - tf.close()