ruff.toml ignored E402 everywhere for main.py's logging setup. Measured: 28 hits, of which 11 had nothing to do with it — runner.py's logger line between its imports, models.py importing canonical_email mid-file, a test constant above its imports, and main.py's own third-party and mimetypes imports. Those are moved up. What stays after configure_logging in main.py is marked per statement (noqa E402, logging is configured first), its comment now says why the order matters (a line logged while importing, not the logger's creation). The register row goes, the ruff key whitelist loses ignore, and a late import is red again. The T20 comment counts the third deliberate print (scripts/e2e_seed.py).
53 lines
3.8 KiB
TOML
53 lines
3.8 KiB
TOML
# 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 — <why>`).
|
|
# `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 — <why>`,
|
|
# 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: <why>`. 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"]
|