Skip to content

Commit

Permalink
lint: Add Ruff rules (#283)
Browse files Browse the repository at this point in the history
  • Loading branch information
pederhan authored Jan 17, 2025
1 parent 7eed0f7 commit 2b2aadb
Show file tree
Hide file tree
Showing 17 changed files with 52 additions and 31 deletions.
18 changes: 17 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -154,11 +154,27 @@ extend-include = [
"tests/**/*.py",
]


[tool.ruff.lint.pydocstyle]
convention = "google"

[tool.ruff.lint]
extend-select = ["I"]
extend-select = [
"E", # pydecodestyle (errors)
"W", # pydecodestyle (warnings)
"G", # flake8-logging-format
"I", # isort
"LOG", # flake8-logging
"PLE1205", # pylint (too many logging args)
"PLE1206", # pylint (too few logging args)
"TID252", # flake8-tidy-imports (prefer absolute imports)
"C4", # flake8-comprehensions
"B", # flake8-bugbear
]
ignore = [
"E501", # Avoid enforcing line-length violations
"B008", # Argument default function call (incompatible with typer)
]


[tool.ruff.lint.isort]
Expand Down
2 changes: 1 addition & 1 deletion tests/test_prompts.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,5 @@ def _do_test_is_headless(envvar: str, value: str | None, expected: bool):
assert is_headless() == expected
finally:
# IMPORTANT: Remove envvar and clear cache after each test
os.environ = _orig_environ # type: ignore
os.environ = _orig_environ # type: ignore # noqa: B003 # I _think_ this is fine?
is_headless.cache_clear()
7 changes: 4 additions & 3 deletions zabbix_cli/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -604,7 +604,8 @@ def load_auth_token_file(self) -> Union[tuple[Path, str], tuple[None, None]]:
if contents:
return path, contents
logger.info(
f"No auth token file found. Searched in {', '.join(str(p) for p in paths)}"
"No auth token file found. Searched in %s",
{", ".join(str(p) for p in paths)},
)
return None, None

Expand All @@ -616,7 +617,7 @@ def load_auth_file(self) -> tuple[Optional[Path], Optional[str]]:
if contents:
return path, contents
logger.info(
f"No auth file found. Searched in {', '.join(str(p) for p in paths)}"
"No auth file found. Searched in %s", {", ".join(str(p) for p in paths)}
)
return None, None

Expand Down Expand Up @@ -709,7 +710,7 @@ def write_auth_token_file(

try:
file.write_text(f"{username}::{auth_token}")
logger.info(f"Wrote auth token file {file}")
logger.info("Wrote auth token file %s", file)
except OSError as e:
raise AuthTokenFileError(f"Unable to write auth token file {file}: {e}") from e

Expand Down
2 changes: 1 addition & 1 deletion zabbix_cli/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def populate(self) -> None:
self._populate_hostgroup_cache()
self._populate_templategroup_cache()
except Exception as e:
raise ZabbixCLIError(f"Failed to populate Zabbix cache: {e}")
raise ZabbixCLIError(f"Failed to populate Zabbix cache: {e}") from e

def _populate_hostgroup_cache(self) -> None:
"""Populates the hostgroup caches with data from the Zabbix API."""
Expand Down
4 changes: 2 additions & 2 deletions zabbix_cli/commands/proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ def load_balance_proxy_hosts(
all_hosts = list(itertools.chain.from_iterable(p.hosts for p in proxies))
if not all_hosts:
exit_err("Proxies have no hosts to load balance.")
logging.debug(f"Found {len(all_hosts)} hosts to load balance.")
logging.debug("Found %d hosts to load balance.", len(all_hosts))

lb_proxies = {
p.proxyid: LBProxy(proxy=p, weight=w) for p, w in zip(proxies, weights)
Expand All @@ -226,7 +226,7 @@ def load_balance_proxy_hosts(
"Proxy '%s' has no hosts after balancing.", lb_proxy.proxy.name
)
continue
logging.debug(f"Moving {n_hosts} hosts to proxy {lb_proxy.proxy.name!r}")
logging.debug("Moving %d hosts to proxy %r", n_hosts, lb_proxy.proxy.name)

app.state.client.move_hosts_to_proxy(
hosts=lb_proxy.hosts,
Expand Down
2 changes: 1 addition & 1 deletion zabbix_cli/commands/usergroup.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def sort_ugroups(
try:
return sorted(ugroups, key=lambda ug: int(ug.usrgrpid))
except Exception as e:
logging.error(f"Failed to sort user groups by ID: {e}")
logging.error("Failed to sort user groups by ID: %s", e)
# Fall back on unsorted (likely sorted by ID anyway)
return ugroups

Expand Down
4 changes: 3 additions & 1 deletion zabbix_cli/config/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,9 @@ def get(
adapter = _get_type_adapter(type)
return adapter.validate_python(attr)
except AttributeError:
raise ConfigOptionNotFound(f"Plugin configuration key '{key}' not found")
raise ConfigOptionNotFound(
f"Plugin configuration key '{key}' not found"
) from None
except ValidationError as e:
raise PluginConfigTypeError(
f"Plugin config key '{key}' failed to validate as type {type}: {e}"
Expand Down
4 changes: 2 additions & 2 deletions zabbix_cli/output/formatting/dates.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

from datetime import datetime

from ...logs import logger
from .constants import NONE_STR
from zabbix_cli.logs import logger
from zabbix_cli.output.formatting.constants import NONE_STR


def datetime_str(
Expand Down
2 changes: 1 addition & 1 deletion zabbix_cli/pyzabbix/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ def parse_name_or_id_arg(

# If we have a wildcard, we can omit names or IDs entirely
if "*" in names_or_ids:
names_or_ids = tuple()
names_or_ids = ()

if len(names_or_ids) > 1:
logger.debug(
Expand Down
2 changes: 1 addition & 1 deletion zabbix_cli/pyzabbix/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ def get_port(self: InterfaceType) -> str:
try:
return self.value.metadata["port"]
except KeyError:
raise ZabbixCLIError(f"Unknown interface type: {self}")
raise ZabbixCLIError(f"Unknown interface type: {self}") from None


class InventoryMode(APIStrEnum):
Expand Down
4 changes: 2 additions & 2 deletions zabbix_cli/pyzabbix/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ def get_random_proxy(client: ZabbixAPI, pattern: Optional[str] = None) -> Proxy:
if pattern:
try:
re_pattern = re.compile(pattern)
except re.error:
raise ZabbixAPICallError(f"Invalid proxy regex pattern: {pattern!r}")
except re.error as e:
raise ZabbixAPICallError(f"Invalid proxy regex pattern: {pattern!r}") from e
proxies = [proxy for proxy in proxies if re_pattern.match(proxy.name)]
if not proxies:
raise ZabbixNotFoundError(f"No proxies matching pattern {pattern!r}")
Expand Down
2 changes: 1 addition & 1 deletion zabbix_cli/repl/completer.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ def _get_completion_for_cmd_args(
current_args = args[param.nargs * -1 :]

# Show only unused opts
already_present = any([opt in previous_args for opt in opts])
already_present = any(opt in previous_args for opt in opts)
hide = self.show_only_unused and already_present and not param.multiple

# Show only shortest opt
Expand Down
2 changes: 1 addition & 1 deletion zabbix_cli/repl/repl.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class InternalCommand(NamedTuple):
description: str


_internal_commands: dict[str, InternalCommand] = dict()
_internal_commands: dict[str, InternalCommand] = {}


def _register_internal_command(
Expand Down
12 changes: 7 additions & 5 deletions zabbix_cli/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,8 +358,10 @@ def get_release_version(self) -> str:
raise UpdateError(f"Failed to get latest release: {resp.text}")
try:
release = GitHubRelease.model_validate_json(resp.text)
except ValidationError:
raise UpdateError(f"Failed to parse GitHub release info: {resp.text}")
except ValidationError as e:
raise UpdateError(
f"Failed to parse GitHub release info: {resp.text}"
) from e
if not release.tag_name:
raise UpdateError(f"Latest GitHub release {release.url!r} has no tag name.")
return release.tag_name
Expand All @@ -377,7 +379,7 @@ def resolve_path(self, path: Path) -> Path:
if alias_path.name == "python":
raise UpdateError(
"Unable to resolve PyInstaller executable. Please update manually."
)
) from None
return alias_path

@staticmethod
Expand Down Expand Up @@ -459,7 +461,7 @@ def to_path(p: str) -> Optional[Path]:
try:
return Path(p).expanduser().resolve()
except Exception as e:
logger.debug(f"Unable to resolve path {p}: {e}")
logger.debug("Unable to resolve path %s: %s", p, e)
return None


Expand Down Expand Up @@ -525,7 +527,7 @@ def get_pipx_bin_dir() -> Optional[Path]:
["pipx", "environment", "--value", "PIPX_BIN_DIR"], text=True
)
except subprocess.CalledProcessError as e:
logger.error(f"Failed to get pipx bin dir with command {e.cmd!r}: {e}")
logger.error("Failed to get pipx bin dir with command %r: %s", e.cmd, e)
return
except FileNotFoundError:
return # pipx not installed
Expand Down
2 changes: 1 addition & 1 deletion zabbix_cli/utils/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def is_set(ctx: typer.Context, option: str) -> bool:

src = ctx.get_parameter_source(option)
if not src:
logging.warning(f"Parameter {option} not found in context.")
logging.warning("Parameter %s not found in context.", option)
return False

# HACK: A typer callback that sets an empty list as a default value
Expand Down
12 changes: 6 additions & 6 deletions zabbix_cli/utils/fs.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ def open_directory(
if not directory.exists():
raise FileNotFoundError
directory = directory.resolve(strict=True)
except FileNotFoundError:
raise ZabbixCLIError(f"Directory {directory} does not exist")
except OSError:
raise ZabbixCLIError(f"Unable to resolve symlinks for {directory}")
except FileNotFoundError as e:
raise ZabbixCLIError(f"Directory {directory} does not exist") from e
except OSError as e:
raise ZabbixCLIError(f"Unable to resolve symlinks for {directory}") from e
if not directory.is_dir():
raise ZabbixCLIError(f"{directory} is not a directory")

Expand Down Expand Up @@ -80,7 +80,7 @@ def mkdir_if_not_exists(path: Path) -> None:
except Exception as e:
raise ZabbixCLIFileError(f"Failed to create directory {path}: {e}") from e
else:
logger.info(f"Created directory: {path}")
logger.info("Created directory: %s", path)


def sanitize_filename(filename: str) -> str:
Expand Down Expand Up @@ -120,7 +120,7 @@ def move_file(src: Path, dest: Path, mkdir: bool = True) -> None:
except Exception as e:
raise ZabbixCLIError(f"Failed to move {src} to {dest}: {e}") from e
else:
logger.info(f"Moved {src} to {dest}")
logger.info("Moved %s to %s", src, dest)


@contextmanager
Expand Down
2 changes: 1 addition & 1 deletion zabbix_cli/utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ def try_convert_int(s: str) -> int:
try:
return int(s)
except ValueError:
raise ZabbixCLIError(f"Invalid time value: {s}")
raise ZabbixCLIError(f"Invalid time value: {s}") from None

time = time.replace(" ", "")
for time_value in TIME_VALUES:
Expand Down

0 comments on commit 2b2aadb

Please sign in to comment.