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.
This commit is contained in:
Felix Fontein
2025-10-11 23:06:50 +02:00
committed by GitHub
parent 33c8a49191
commit cad22de628
59 changed files with 556 additions and 630 deletions
+141 -139
View File
@@ -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:
+6 -8
View File
@@ -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"""
+85 -85
View File
@@ -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)