From a61e0a6a246995b1a8c0816f5a3a9dbb82e96c91 Mon Sep 17 00:00:00 2001 From: Mickael Farina Date: Fri, 24 Jul 2026 18:38:13 +0200 Subject: [PATCH] build(lint): pin ruff's select explicitly, then unpin the version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The real fix for the 0.16 breakage, replacing the <0.16 stopgap. ruff.toml only ever set `ignore` and relied on ruff's DEFAULT selection being "E4/E7/E9 + F". Ruff 0.16.0 widened those defaults, so `ruff check .` went from clean to 3117 errors with no code change — BLE001 x1029, I001 x402, UP006 x309, S110, DTZ005, ASYNC230, none of which this project ever chose. Inheriting a moving default meant CI's gate could change under us at any release. Naming the selection makes it version-proof: a future ruff can add whatever defaults it likes and this repo's gate stays exactly what it was. Widening is now a deliberate edit, not a surprise. Because the gate no longer depends on ruff's defaults, the <0.16 pin is unnecessary — removed from both the workflow and requirements-dev, so dependabot can keep upgrading. Verified "All checks passed" on 0.15.22 AND 0.16.0 with the same tree. Adopting 0.16's new rules (imports sorting, blind-except, datetime-tz) is now a separate, opt-in decision rather than something a release forces. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/ci.yml | 2 +- requirements-dev.txt | 9 ++++----- ruff.toml | 14 +++++++++++++- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2267ed1..81dd58c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: # tests on main-as-is (verified via a no-op canary PR) — CI was # testing a dependency set production never runs. Bump these pins # together with a production upgrade, not before. - pip install pytest fastmcp httpx requests pynput 'pydantic==2.11.10' 'ruff>=0.15.22,<0.16' \ + pip install pytest fastmcp httpx requests pynput 'pydantic==2.11.10' ruff \ 'fastapi==0.129.0' 'starlette==0.52.1' numpy pyotp 'qrcode[pil]' - name: Lint (ruff) — F-4 gate, config in ruff.toml run: ruff check . diff --git a/requirements-dev.txt b/requirements-dev.txt index b8385ec..ed0f356 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -12,8 +12,7 @@ # Test + lint toolchain (matches CI) pytest>=9.1.1 -# Upper bound is deliberate: ruff 0.16 changed the default rule selection AND -# stopped honouring this repo's ruff.toml in CI — `ruff check .` went from clean -# to 3117 errors (E402 fired 535 times despite being in our ignore list), with -# no code change. Unpinning again needs a real 0.16 migration, not a drift. -ruff>=0.15.22,<0.16 +# No upper bound needed: ruff.toml now pins `select` explicitly, so a release +# that widens ruff's defaults can't silently change this repo's gate. +# Verified clean on both 0.15.22 and 0.16.0. +ruff>=0.15.22 diff --git a/ruff.toml b/ruff.toml index 3219345..6892bce 100644 --- a/ruff.toml +++ b/ruff.toml @@ -14,7 +14,19 @@ line-length = 120 extend-exclude = ["pilot", "swift-overlay"] # pilot is a separate repo; swift is not Python [lint] -# Ruff's default selection is E4/E7/E9 + F. Keep it; drop the house-style stylistic rules. +# Selection is EXPLICIT, not inherited. Relying on ruff's default `select` broke +# the repo on 2026-07-24: ruff 0.16.0 widened its defaults and `ruff check .` +# went from clean to 3117 errors with no code change — BLE001 x1029, I001 x402, +# UP006 x309, S110, DTZ005, ASYNC230 … none of which this project ever chose. +# Naming the set here means a future ruff release can add whatever defaults it +# likes without silently changing this repo's gate. Widen it deliberately. +select = [ + "E4", # pycodestyle — imports + "E7", # pycodestyle — statements + "E9", # pycodestyle — runtime/syntax errors + "F", # pyflakes — unused imports, undefined names, f-string bugs, redefinitions +] +# Drop the house-style stylistic rules from the selection above. ignore = [ "E402", # module-import-not-at-top — lazy/conditional imports + sys.path setup (intentional) "E701", # multiple-statements-on-one-line (colon) — compact `if x: return`