Skip to content

Commit b3230fc

Browse files
Merge pull request #37 from SomethingGeneric/copilot/fix-pylint-ci-score
Fix Pylint CI score to meet 8.0+ requirement
2 parents 151cc3d + f4cb704 commit b3230fc

File tree

8 files changed

+137
-118
lines changed

8 files changed

+137
-118
lines changed

miniupdate/config.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@
55
email credentials and inventory paths.
66
"""
77

8-
import toml
8+
import os
99
from pathlib import Path
1010
from typing import Dict, Any, Optional, List
11-
import os
11+
12+
import toml
1213

1314

1415
class Config:
@@ -55,7 +56,7 @@ def _load_config(self) -> Dict[str, Any]:
5556
with open(self.config_path, "r", encoding="utf-8") as f:
5657
return toml.load(f)
5758
except Exception as e:
58-
raise ValueError(f"Error parsing configuration file: {e}")
59+
raise ValueError(f"Error parsing configuration file: {e}") from e
5960

6061
@property
6162
def smtp_config(self) -> Dict[str, Any]:
@@ -178,7 +179,8 @@ def create_example_config(path: str = "config.toml.example") -> None:
178179
"snapshot_name_prefix": "pre-update",
179180
"cleanup_snapshots": True,
180181
"snapshot_retention_days": 7,
181-
"opt_out_hosts": [], # List of hosts to exclude from automatic updates (check-only mode)
182+
# List of hosts to exclude from automatic updates (check-only mode)
183+
"opt_out_hosts": [],
182184
},
183185
}
184186

miniupdate/host_checker.py

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
Provides utilities to check if hosts are reachable via ping and SSH.
55
"""
66

7-
import subprocess
87
import logging
8+
import subprocess
99
import time
10-
from typing import Optional
11-
from .ssh_manager import SSHManager
10+
1211
from .inventory import Host
12+
from .ssh_manager import SSHManager
1313

1414
logger = logging.getLogger(__name__)
1515

@@ -40,7 +40,9 @@ def ping_host(self, hostname: str, timeout: int = 5) -> bool:
4040
try:
4141
# Use ping command with timeout
4242
cmd = ["ping", "-c", "1", "-W", str(timeout), hostname]
43-
result = subprocess.run(cmd, capture_output=True, timeout=timeout + 2)
43+
result = subprocess.run(
44+
cmd, capture_output=True, timeout=timeout + 2, check=False
45+
)
4446
return result.returncode == 0
4547
except (subprocess.TimeoutExpired, subprocess.SubprocessError):
4648
return False
@@ -65,7 +67,9 @@ def wait_for_host_availability(
6567
True if host becomes available, False if timeout
6668
"""
6769
logger.info(
68-
f"Waiting for {host.name} to become available (timeout: {max_wait_time}s)"
70+
"Waiting for %s to become available (timeout: %ss)",
71+
host.name,
72+
max_wait_time,
6973
)
7074

7175
start_time = time.time()
@@ -76,34 +80,36 @@ def wait_for_host_availability(
7680
elapsed = int(time.time() - start_time)
7781

7882
logger.debug(
79-
f"Checking {host.name} availability - attempt {attempt} ({elapsed}s elapsed)"
83+
"Checking %s availability - attempt %s (%ss elapsed)",
84+
host.name,
85+
attempt,
86+
elapsed,
8087
)
8188

8289
# First check ping
8390
if not self.ping_host(host.hostname):
84-
logger.debug(f"{host.name} not responding to ping")
91+
logger.debug("%s not responding to ping", host.name)
8592
time.sleep(check_interval)
8693
continue
8794

88-
logger.debug(f"{host.name} responding to ping")
95+
logger.debug("%s responding to ping", host.name)
8996

9097
# If SSH check is requested, verify SSH connectivity
9198
if use_ssh:
9299
if self._check_ssh_connectivity(host):
93100
logger.info(
94-
f"{host.name} is available (ping + SSH) after {elapsed}s"
101+
"%s is available (ping + SSH) after %ss", host.name, elapsed
95102
)
96103
return True
97-
else:
98-
logger.debug(f"{host.name} ping OK but SSH not ready")
104+
logger.debug("%s ping OK but SSH not ready", host.name)
99105
else:
100-
logger.info(f"{host.name} is available (ping only) after {elapsed}s")
106+
logger.info("%s is available (ping only) after %ss", host.name, elapsed)
101107
return True
102108

103109
time.sleep(check_interval)
104110

105111
elapsed = int(time.time() - start_time)
106-
logger.warning(f"{host.name} did not become available within {elapsed}s")
112+
logger.warning("%s did not become available within %ss", host.name, elapsed)
107113
return False
108114

109115
def _check_ssh_connectivity(self, host: Host) -> bool:
@@ -125,7 +131,7 @@ def _check_ssh_connectivity(self, host: Host) -> bool:
125131
return exit_code == 0
126132
return False
127133
except Exception as e:
128-
logger.debug(f"SSH connectivity check failed for {host.name}: {e}")
134+
logger.debug("SSH connectivity check failed for %s: %s", host.name, e)
129135
return False
130136

131137
def reboot_host_via_ssh(self, host: Host, timeout: int = 30) -> bool:
@@ -143,21 +149,21 @@ def reboot_host_via_ssh(self, host: Host, timeout: int = 30) -> bool:
143149
with SSHManager(self.ssh_config) as ssh_manager:
144150
connection = ssh_manager.connect_to_host(host, timeout=timeout)
145151
if not connection:
146-
logger.error(f"Failed to connect to {host.name} for reboot")
152+
logger.error("Failed to connect to %s for reboot", host.name)
147153
return False
148154

149-
logger.info(f"Sending reboot command to {host.name}")
155+
logger.info("Sending reboot command to %s", host.name)
150156

151157
# Send reboot command (don't wait for response as connection will drop)
152-
exit_code, stdout, stderr = connection.execute_command(
158+
_exit_code, _stdout, _stderr = connection.execute_command(
153159
"shutdown -r now || reboot",
154160
timeout=5, # Short timeout as system will reboot
155161
)
156162

157163
# Command may not return exit code due to immediate reboot
158-
logger.info(f"Reboot command sent to {host.name}")
164+
logger.info("Reboot command sent to %s", host.name)
159165
return True
160166

161167
except Exception as e:
162-
logger.error(f"Failed to reboot {host.name} via SSH: {e}")
168+
logger.error("Failed to reboot %s via SSH: %s", host.name, e)
163169
return False

miniupdate/inventory.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
Supports parsing YAML and INI format Ansible inventory files.
55
"""
66

7-
import yaml
7+
import logging
88
from pathlib import Path
99
from typing import List, Dict, Any, Optional
10-
import configparser
11-
import logging
10+
11+
import yaml
1212

1313

1414
logger = logging.getLogger(__name__)
@@ -47,26 +47,25 @@ def parse(self) -> List[Host]:
4747
"""Parse inventory file and return list of hosts."""
4848
if self.inventory_path.suffix.lower() in [".yml", ".yaml"]:
4949
return self._parse_yaml()
50-
elif self.inventory_path.suffix.lower() in [
50+
if self.inventory_path.suffix.lower() in [
5151
".ini",
5252
".cfg",
5353
"",
5454
] or self.inventory_path.name in ["hosts", "inventory"]:
5555
return self._parse_ini()
56-
else:
57-
# Try YAML first, then INI
58-
try:
59-
return self._parse_yaml()
60-
except Exception:
61-
return self._parse_ini()
56+
# Try YAML first, then INI
57+
try:
58+
return self._parse_yaml()
59+
except Exception:
60+
return self._parse_ini()
6261

6362
def _parse_yaml(self) -> List[Host]:
6463
"""Parse YAML format inventory."""
6564
try:
6665
with open(self.inventory_path, "r", encoding="utf-8") as f:
6766
inventory = yaml.safe_load(f)
6867
except Exception as e:
69-
raise ValueError(f"Error parsing YAML inventory: {e}")
68+
raise ValueError(f"Error parsing YAML inventory: {e}") from e
7069

7170
hosts = []
7271

@@ -80,7 +79,7 @@ def _parse_yaml(self) -> List[Host]:
8079
if "hosts" in all_section:
8180
hosts.extend(self._parse_yaml_hosts(all_section["hosts"]))
8281
if "children" in all_section:
83-
for group_name, group_data in all_section["children"].items():
82+
for _group_name, group_data in all_section["children"].items():
8483
if "hosts" in group_data:
8584
hosts.extend(self._parse_yaml_hosts(group_data["hosts"]))
8685
else:
@@ -122,7 +121,7 @@ def _parse_ini(self) -> List[Host]:
122121
with open(self.inventory_path, "r", encoding="utf-8") as f:
123122
content = f.read()
124123
except Exception as e:
125-
raise ValueError(f"Error reading INI inventory: {e}")
124+
raise ValueError(f"Error reading INI inventory: {e}") from e
126125

127126
# Split into lines and process
128127
lines = content.split("\n")

miniupdate/os_detector.py

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
Detects the operating system and distribution of remote hosts.
55
"""
66

7-
import re
87
import logging
9-
from typing import Optional, Dict, Any, Tuple
8+
from typing import Optional, Dict, Tuple
9+
1010
from .ssh_manager import SSHConnection
1111

1212

@@ -112,16 +112,16 @@ def detect_os(self) -> Optional[OSInfo]:
112112
architecture=architecture,
113113
)
114114

115-
logger.info(f"Detected OS on {self.connection.host.name}: {os_info}")
115+
logger.info("Detected OS on %s: %s", self.connection.host.name, os_info)
116116
return os_info
117117

118118
except Exception as e:
119-
logger.error(f"Failed to detect OS on {self.connection.host.name}: {e}")
119+
logger.error("Failed to detect OS on %s: %s", self.connection.host.name, e)
120120
return None
121121

122122
def _get_uname_info(self) -> Dict[str, str]:
123123
"""Get uname information."""
124-
exit_code, stdout, stderr = self.connection.execute_command("uname -a")
124+
exit_code, stdout, _stderr = self.connection.execute_command("uname -a")
125125
if exit_code != 0:
126126
return {}
127127

@@ -139,7 +139,7 @@ def _get_uname_info(self) -> Dict[str, str]:
139139

140140
def _get_os_release_info(self) -> Dict[str, str]:
141141
"""Get information from /etc/os-release."""
142-
exit_code, stdout, stderr = self.connection.execute_command(
142+
exit_code, stdout, _stderr = self.connection.execute_command(
143143
"cat /etc/os-release 2>/dev/null || true"
144144
)
145145
if exit_code != 0 or not stdout.strip():
@@ -157,7 +157,7 @@ def _get_os_release_info(self) -> Dict[str, str]:
157157

158158
def _get_lsb_info(self) -> Dict[str, str]:
159159
"""Get LSB information."""
160-
exit_code, stdout, stderr = self.connection.execute_command(
160+
exit_code, stdout, _stderr = self.connection.execute_command(
161161
"lsb_release -a 2>/dev/null || true"
162162
)
163163
if exit_code != 0 or not stdout.strip():
@@ -237,33 +237,33 @@ def _normalize_distribution_name(self, distribution: str) -> str:
237237
# Handle common variations
238238
if "red hat" in distribution or "redhat" in distribution:
239239
return "rhel"
240-
elif "centos" in distribution:
240+
if "centos" in distribution:
241241
return "centos"
242-
elif "ubuntu" in distribution:
242+
if "ubuntu" in distribution:
243243
return "ubuntu"
244-
elif (
244+
if (
245245
"linuxmint" in distribution
246246
or "linux mint" in distribution
247247
or distribution == "mint"
248248
):
249249
return "linuxmint"
250-
elif "debian" in distribution:
250+
if "debian" in distribution:
251251
return "debian"
252-
elif "fedora" in distribution:
252+
if "fedora" in distribution:
253253
return "fedora"
254-
elif "opensuse" in distribution or "suse" in distribution:
254+
if "opensuse" in distribution or "suse" in distribution:
255255
return "opensuse"
256-
elif "arch" in distribution:
256+
if "arch" in distribution:
257257
return "arch"
258-
elif "manjaro" in distribution:
258+
if "manjaro" in distribution:
259259
return "manjaro"
260-
elif "alpine" in distribution:
260+
if "alpine" in distribution:
261261
return "alpine"
262-
elif "freebsd" in distribution:
262+
if "freebsd" in distribution:
263263
return "freebsd"
264-
elif "openbsd" in distribution:
264+
if "openbsd" in distribution:
265265
return "openbsd"
266-
elif "darwin" in distribution or "macos" in distribution:
266+
if "darwin" in distribution or "macos" in distribution:
267267
return "macos"
268268

269269
return distribution
@@ -278,7 +278,7 @@ def _detect_package_manager(self, distribution: str) -> str:
278278
return default_pm
279279

280280
# Fallback: check for available package managers
281-
for pm_name, commands in self.PACKAGE_MANAGERS.items():
281+
for pm_name, _commands in self.PACKAGE_MANAGERS.items():
282282
if self._check_package_manager_exists(pm_name):
283283
return pm_name
284284

@@ -303,13 +303,12 @@ def _get_architecture(self, uname_info: Dict[str, str]) -> str:
303303
# Normalize common architectures
304304
if arch in ["x86_64", "amd64"]:
305305
return "x86_64"
306-
elif arch in ["i386", "i686"]:
306+
if arch in ["i386", "i686"]:
307307
return "i386"
308-
elif arch.startswith("arm"):
308+
if arch.startswith("arm"):
309309
return "arm"
310-
elif arch.startswith("aarch64"):
310+
if arch.startswith("aarch64"):
311311
return "arm64"
312-
else:
313-
return arch
312+
return arch
314313

315314
return "unknown"

0 commit comments

Comments
 (0)