# 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: UP/RUF/PLR/ # S/TRY/PERF/FURB/YTT/ASYNC...). The same tree therefore produced different findings on # different machines and between a developer and a runner. Never rely on tool defaults. # # Policy, decided from the measured findings rather than from taste: # # * `select` is explicit. High-signal correctness rules first, then only the mechanical # modernisation rules we are willing to apply without human review. # * BLE001 is selected so existing `# noqa: BLE001 - ` suppressions stay *used* and # RUF100 can never delete their rationale — a broad `except Exception` is a legitimate # choice around device I/O, capture probes and teardown. It is NOT part of the gate. # * S110 / S112 / E722 ARE part of the gate: a silent handler hides a failure. This matters # most in the live capture path, where a swallowed read error kills a source silently. # * RUF100 reports unused suppressions but is `unfixable`: a machine must not remove a # suppression whose comment records why it exists. Triage those by hand. # * The mechanical sweep never uses `--unsafe-fixes`. # # The gate selects the narrow set explicitly, so BLE001 cannot fail a build, and only ever # touches changed files: # # 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 in examples/ and scripts/ # (the environment must be set before Qt/cv2/orisys load). 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 a # `# noqa: E402 - ` when it is touched. "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"