# Ruff configuration — pinned deliberately. # # Before this file existed the repo had no Ruff config, so `ruff check .` ran whatever the # installed Ruff version enables by default (Ruff 0.16 turns on a very broad set). Findings # were therefore not reproducible between machines. Never rely on tool defaults. # # Policy, decided from the measured findings: # # * `select` is explicit: high-signal correctness rules first, then the mechanical # modernisation rules only. # * BLE001 is selected so existing reasoned suppressions stay *used* and RUF100 cannot # delete their rationale. Broad catches around Blender/environment probing are legitimate. # BLE001 is NOT part of the gate. # * S110 / S112 / E722 ARE part of the gate. The Blender scripts are the riskiest place for # a silent swallow: they run headless, so a swallowed error becomes a silently wrong or # missing artefact rather than a visible crash. # * B023 (loop-variable closure) matters here more than anywhere else in the workspace — # the geometry/patch scripts define callbacks inside loops over axes and signs. # * RUF100 is `unfixable`: a machine must not remove a suppression whose comment records # why it exists. # * The mechanical sweep never uses `--unsafe-fixes`. # # The gate selects the narrow set explicitly: # # tools/lint_gate.py # the gate: changed files, machine-readable target-version = "py310" line-length = 88 [lint] select = [ "E9", "E722", # syntax/IO errors, and bare `except:` "E402", # module import not at top of file — SELECTED for visibility, NOT gated. # `import` after `os.environ[...]` is deliberate where the environment or # the SDK path must be set first. E402 is the only rule that would catch an # accidental import moved above that setup, so it stays reported without # failing a build. An intentional site belongs in `# noqa: E402 - `. "F", # pyflakes: unused import, redefinition, undefined name "S110", "S112", # try-except-pass / try-except-continue — an invisible failure "B023", # function definition does not bind loop variable "PLW1510", # subprocess.run without an explicit check "RUF100", # unused noqa — reported for triage, never auto-removed "UP", # pyupgrade "I", # import sorting "RUF022", "RUF023", # __all__ / __slots__ ordering "PIE", # flake8-pie "RET501", "PLR1711", "SIM114", "BLE001", # selected for suppression hygiene only — excluded from the gate ] unfixable = ["RUF100"] [format] quote-style = "double" indent-style = "space"