mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-08 11:46:35 +00:00
Extends ``[tool.ruff.lint].select`` with six additional rule families:
``RUF`` (ruff-specific), ``SIM`` (flake8-simplify), ``C4``
(flake8-comprehensions), ``PERF`` (perflint), ``RET`` (flake8-return),
``PIE`` (flake8-pie). Adds ``RUF001/002/003`` to ``ignore`` because
those exist for homoglyph-attack detection, not English typography —
the project uses em/en-dashes and ``ℹ`` as a UI-hint glyph in CLI help
output deliberately.
Auto-fixed (~225, mechanical & behavior-preserving)
====================================================
- RUF005: ``a + [b]`` → ``[*a, b]``
- C408: ``dict(k=v)`` → ``{"k": v}``
- C420: ``dict.fromkeys(seq)`` shape simplifications
- SIM103/SIM110/SIM118: truthy-return / dict-key / dict-method
idiom simplifications
- RET504/RET505: drop unneeded final assigns / ``else`` after
``return``
- PIE810: combine ``str.startswith(a) or .startswith(b)``
into one call with a tuple
- RUF010: ``f"{str(x)}"`` → ``f"{x\!s}"``
- RUF100: removed unused ``# noqa`` directives that
became stale (mostly old ``# noqa: E402``
markers that ruff's smart E402 implementation
no longer flags after ``sys.path`` shims)
- RUF015 / RUF013 / RUF022 / RUF046 / RUF059: misc small wins
- I001: re-sorted import blocks where the new
imports above shifted them
Hand-fixed (~140, scripted where mechanical)
============================================
PERF401 (42): scripted AST rewrite of
``for x in iter: target.append(expr)`` (with optional ``if`` guard)
→ ``target.extend(expr for x in iter [if cond])``.
``list.extend(genexp)`` consumes the generator immediately, so the
rewrite is semantically equivalent to the original eager loop.
SIM117 (41): scripted AST combiner for nested ``with`` blocks where
the inner is the only statement of the outer (38 sites). The remaining
3 multi-line ``patch.object(...)`` chains were combined by hand using
the parenthesised ``with (\\n A,\\n B,\\n):`` form.
SIM102 (14): scripted AST combiner for nested ``if`` (10 sites). The
remaining 4 carry an inline ``# noqa: SIM102`` with rationale —
combining would either change semantics (the outer body has siblings
beyond the inner ``if``, e.g. ``cli/encrypt/inventory/__main__.py``
where ``encrypted_value = …`` runs regardless of ``ask_confirmation``)
or hurt readability (long literal whitelists).
RUF012 (9): annotated mutable class attributes with ``ClassVar[…]``
and added ``from typing import ClassVar``.
SIM105 (6): ``try/except: pass`` → ``with contextlib.suppress(…):``
with the necessary ``import contextlib`` added. Verified on
``utils/templating.py`` (3 occurrences in a ``finally`` block) —
cleanup behaviour is identical.
SIM115 (4): wrapped ``tempfile.NamedTemporaryFile(..., delete=False)``
call patterns in a ``with`` block; ``delete=False`` keeps the file
on disk after the block, so callers' ``return f.name`` still works.
PERF402, PERF403, B007, SIM108, SIM103: 5 misc fixes (loop→list-copy,
loop→dict-comprehension, unused-loop-var rename, ternary, return
expression).
Verification
============
- ``ruff check .`` → All checks passed
- ``ruff format --check .`` → 894 files already formatted
- 1621 unit tests → all pass
- Integration suite: 44 baseline failures, 1 skipped (unchanged)
- Sample-audited PERF401 rewrites in ``resolver.py``, ``inventory.py``,
``cache/files.py``, ``ressources/__main__.py``; SIM117 in
``test_main.py``; SIM105 in ``utils/templating.py``; SIM102 noqa
rationales in ``cli/encrypt/inventory/__main__.py``.
182 files changed, +993 / −960. With this and the prior strict-rule
commit the branch satisfies 11 ruff rule families end-to-end.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
131 lines
3.8 KiB
Python
131 lines
3.8 KiB
Python
from __future__ import annotations
|
|
|
|
import argparse
|
|
import os
|
|
import re
|
|
from typing import Any
|
|
|
|
MODE_LINE_RE = re.compile(
|
|
r"""^\s*(?P<key>[A-Z0-9_]+)\s*:\s*(?P<value>.+?)\s*(?:#\s*(?P<cmt>.*))?\s*$"""
|
|
)
|
|
|
|
|
|
def _parse_bool_literal(text: str) -> bool | None:
|
|
"""Convert simple true/false/yes/no/on/off into boolean."""
|
|
t = text.strip().lower()
|
|
if t in ("true", "yes", "on"):
|
|
return True
|
|
if t in ("false", "no", "off"):
|
|
return False
|
|
return None
|
|
|
|
|
|
def load_modes_from_yaml(modes_yaml_path: str) -> list[dict[str, Any]]:
|
|
"""
|
|
Load MODE_* definitions from a YAML-like key/value file.
|
|
|
|
Expected lines:
|
|
MODE_FOO: true # comment
|
|
MODE_BAR: false # comment
|
|
MODE_BAZ: null # comment
|
|
"""
|
|
if not os.path.exists(modes_yaml_path):
|
|
raise FileNotFoundError(f"Modes file not found: {modes_yaml_path}")
|
|
|
|
modes: list[dict[str, Any]] = []
|
|
|
|
with open(modes_yaml_path, encoding="utf-8") as fh:
|
|
for raw in fh:
|
|
line = raw.rstrip()
|
|
if not line or line.lstrip().startswith("#"):
|
|
continue
|
|
|
|
m = MODE_LINE_RE.match(line)
|
|
if not m:
|
|
continue
|
|
|
|
key = m.group("key")
|
|
val = m.group("value").strip()
|
|
cmt = (m.group("cmt") or "").strip()
|
|
|
|
if not key.startswith("MODE_"):
|
|
continue
|
|
|
|
default_bool = _parse_bool_literal(val)
|
|
|
|
modes.append(
|
|
{
|
|
"name": key,
|
|
"default": default_bool, # True/False/None
|
|
"help": cmt or f"Toggle {key}",
|
|
}
|
|
)
|
|
|
|
return modes
|
|
|
|
|
|
def add_dynamic_mode_args(
|
|
parser: argparse.ArgumentParser, modes_meta: list[dict[str, Any]]
|
|
) -> dict[str, dict[str, Any]]:
|
|
"""
|
|
Add command-line args dynamically based on MODE_* metadata.
|
|
|
|
Returns a spec mapping MODE_NAME -> info used by build_modes_from_args().
|
|
"""
|
|
spec: dict[str, dict[str, Any]] = {}
|
|
|
|
for meta in modes_meta:
|
|
name = meta["name"]
|
|
default = meta["default"]
|
|
desc = meta["help"]
|
|
short = name.replace("MODE_", "").lower()
|
|
|
|
if default is True:
|
|
# MODE_FOO: true → --skip-foo disables it
|
|
opt = f"--skip-{short}"
|
|
dest = f"skip_{short}"
|
|
parser.add_argument(opt, action="store_true", dest=dest, help=desc)
|
|
spec[name] = {"dest": dest, "default": True, "kind": "bool_true"}
|
|
|
|
elif default is False:
|
|
# MODE_BAR: false → --bar enables it
|
|
opt = f"--{short}"
|
|
dest = short
|
|
parser.add_argument(opt, action="store_true", dest=dest, help=desc)
|
|
spec[name] = {"dest": dest, "default": False, "kind": "bool_false"}
|
|
|
|
else:
|
|
# MODE_XYZ: null → --xyz true|false
|
|
opt = f"--{short}"
|
|
dest = short
|
|
parser.add_argument(opt, choices=["true", "false"], dest=dest, help=desc)
|
|
spec[name] = {"dest": dest, "default": None, "kind": "explicit"}
|
|
|
|
return spec
|
|
|
|
|
|
def build_modes_from_args(
|
|
spec: dict[str, dict[str, Any]], args_namespace: argparse.Namespace
|
|
) -> dict[str, Any]:
|
|
"""Resolve CLI arguments into a MODE_* dictionary."""
|
|
modes: dict[str, Any] = {}
|
|
|
|
for mode_name, info in spec.items():
|
|
dest = info["dest"]
|
|
kind = info["kind"]
|
|
value = getattr(args_namespace, dest, None)
|
|
|
|
if kind == "bool_true":
|
|
# if user passed --skip-foo => disable => False, otherwise True
|
|
modes[mode_name] = not value
|
|
|
|
elif kind == "bool_false":
|
|
# if user passed --bar => enable => True, otherwise False
|
|
modes[mode_name] = bool(value)
|
|
|
|
else: # explicit
|
|
if value is not None:
|
|
modes[mode_name] = value == "true"
|
|
|
|
return modes
|