# Ruff config for the Siftlode backend. Keeps ruff's default rule set (E4/E7/E9 + F = the # high-signal pyflakes/pycodestyle checks that catch real dead code + bugs), all of it on. E402 was # ignored for main.py's logging setup; the ignore had let 11 incidental late imports in elsewhere # (E32 review), so it is on now and main.py marks each deliberate one (`# noqa: E402 — `). # `scripts/e2e_seed.py` edits `sys.path` before its imports, which E402 itself allows. # # line-length 100 (ruff's default is 88): matches the frontend prettier printWidth so both halves of # the repo wrap at the same width, and it's the width `ruff format` enforces (gated via # `ruff format --check` alongside `ruff check`). line-length = 100 # The interpreter this code actually runs on, so ruff judges syntax and upgrade hints against the # right one. Left unset it falls back to a default that has nothing to do with us. `/.python-version` # is the single source of truth; tests/test_python_engine_contract.py holds this to it. target-version = "py312" [lint] # Beyond the default set, the rules that hold a LOG LINE to what E22.5 makes of it: # LOG — stdlib logging misuse (`.warn()`, a logger built by hand, `exc_info` on `.exception`) # G — the call's shape: %-style args, never an f-string the level filter cannot skip, and # never `str(exc)` where `exc_info` would carry the traceback # T20 — `print` instead of a log line. Three deliberate ones remain, each with its `# noqa` # and a why: `downloads/runner.py`'s usage line is for whoever typed it, `logsink.py` # reports the SINK's own failure, which cannot be logged into the sink, and # `scripts/e2e_seed.py` prints the seeded ids for the e2e run that reads them. # TRY400 — `.error()` in an `except` where `.exception()` would keep the traceback # TRY401 — the exception spelled into the message AND passed as `exc_info` (it is in both) # S112 — `except: continue`, the silent swallow inside a loop # S110 — `except: pass`, the same thing outside one # BLE001 — a blind `except Exception`. Every one that remains carries `# noqa: BLE001 — `, # which is the point: catching everything is sometimes right (a worker thread with # nobody to raise to, a best-effort backfill inside a sync) and always worth a sentence. # The wider rule these two enforce lives in tests/test_swallowed_exceptions.py: a handler that # neither logs nor re-raises says `# silent-ok: `. Ruff sees only the two narrow shapes. # # E32 (gate integrity) added three more, each measured before it went on and with every hit fixed: # RUF100 — a `# noqa` that suppresses nothing. A stale one is a claim with no rule behind it, and # it stays armed for the day the line changes (24 were removed). A comment that merely # explains a noqa below it names the rule as `# TRY400: …`, never `# noqa TRY400`. # PLW1510 — `subprocess.run` without an explicit `check=`. Found the real E32 bug: three ffprobe # probes read the output of a probe that had FAILED and took it for the file's truth. # B — flake8-bugbear: loop-variable capture, `raise` without `from` inside `except`, a # `zip` that silently truncates (each one is `strict=True` now — the lengths are an # invariant, so a mismatch should be loud). B008 (a call in a default argument) stays ON: # FastAPI's `Depends(...)` / `Query(...)` ARE that shape by design (474 hits, all of # them), so those two are declared immutable below instead of switching the rule off — # any other call in a default still fails. extend-select = [ "LOG", "G", "T20", "TRY400", "TRY401", "S110", "S112", "BLE001", "RUF100", "PLW1510", "B", ] [lint.flake8-bugbear] extend-immutable-calls = ["fastapi.Depends", "fastapi.Query"]