Skip to content

chore(py): pin ruff rules with select, adopt 0.16 - #1231

Merged
dekobon merged 1 commit into
mainfrom
fix/1222-ruff-016-select
Aug 8, 2026
Merged

chore(py): pin ruff rules with select, adopt 0.16#1231
dekobon merged 1 commit into
mainfrom
fix/1222-ruff-016-select

Conversation

@dekobon

@dekobon dekobon commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Adopts ruff 0.16 by stating the bindings' rule set absolutely instead of
relative to ruff's defaults.

Why

big-code-analysis-py/pyproject.toml selected rules with
extend-select, which extends ruff's defaults rather than replacing
them — so the effective set moved whenever upstream moved. ruff 0.16.0
grew its default rule set from 59 rules to 413, and 28 families arrived
that this config never asked for. Among them PLC / PLE / PLR /
PLW, silently overriding the deliberate Pylint omission that the
comment immediately above the setting states:

Full PL (Pylint) is deliberately omitted — its design rules
(PLR0913 too-many-arguments, PLR0915 too-many-statements) would force
test-suite refactors that belong in a follow-up issue.

The same release dropped 18 opinionated E / F rules from the
defaults, which a defaults-relative config would have lost just as
quietly. The three diagnostics 0.16 reported were the symptom; the
moving baseline was the bug.

Measurements

Counted from ruff check --show-settings, linter.rules.enabled:

ruff extend-select (before) select (after)
0.15.22 265 265
0.16.1 501 268
0.16.2 501 268

The 265→265 cell is the load-bearing one: dropping the implicit
defaults costs this config nothing, because select = ["E", "F", …]
already names those families whole. The +3 on 0.16.x are RUF036,
RUF063 and RUF068 — new rules inside an already-selected family,
which is how the set is supposed to grow. Set difference confirms
nothing was lost.

ruff check passes on 0.15.22 and 0.16.2 with no noqa, no
suppressions and no source changes. Reverting select back to
extend-select under 0.16.2 reproduces exactly the three reported
diagnostics (DTZ001, BLE001, PYI044), all in families never
selected; with the fix, zero.

Beyond the issue's task list

  • make py-relock alone would not have adopted 0.16. uv lock
    keeps a package at its locked version while that version still
    satisfies the requirement, so raising the ceiling re-resolved to a
    still-locked ruff==0.15.22. Adopting 0.16.2 needed an explicit
    uv lock --upgrade-package ruff. Documented in CONTRIBUTING.md so the
    next bound widening does not ship the same no-op.
  • .pre-commit-config.yaml had already driftedrev: v0.15.14
    against a locked 0.15.22, with the comment quoting the old <0.16
    bound. Both sat inside that bound so nothing failed, but
    pre-commit run --all-files ran a different ruff than CI. Now
    v0.16.2, with the comment pointing at requirements/dev.txt as the
    authority.
  • The >=0.6 floor was fiction. UP038 (non-pep604-isinstance)
    left ruff's stable set in 0.13, and this tree has five
    isinstance(x, (A, B)) sites. Measured: 0.6.0, 0.9.0, 0.12.0 and
    0.12.12 each report the same five; 0.13.0 / 0.14.0 / 0.14.5 / 0.15.0
    report none — identically under the pre-fix config, so this is
    pre-existing rather than anything select introduced. Raised to
    >=0.13 with the measurement inline, following the precedent the
    mypy>=2.3 entry three lines above already set in the same file.

Not addressed here

ruff 0.16 formats Python code blocks inside Markdown, so make py-fmt
now includes big-code-analysis-py/README.md where 0.15 skipped it
(32 files → 33). Already clean, so nothing churns, but it is
version-dependent behaviour that select does not govern — it is the
formatter, not the linter.

The remaining version-drift channels are filed as #1230: the
honour-system rev: lockstep, and make py-lint / py-fmt resolving
ruff from PATH — where mise.toml ("pipx:ruff" = "latest"),
Dockerfile:284 (uv tool install ruff) and a bare pipx install ruff
all install unpinned — while CI uses the locked venv copy. These are
robustness rather than breakage now: with select, a version difference
can no longer silently enable 28 rule families.

Validation

make pre-commitBCA_GATE: pass (gate=pre-commit), with zero
skipped stages (mypy, pyright, 363 pytest tests + 1 xfail, stubtest,
5166 cargo tests). CI's exact ruff steps — ruff format --check . and
ruff check . from big-code-analysis-py — pass under the locked
0.16.2, as do make py-lint / py-fmt-check over both the bindings
tree and the separate scripts/smoke invocation with --config.

No coverage impact: the diff is TOML, YAML and Markdown only, with no
.rs, .py or .pyi file touched, so it contains no coverable lines.

Fixes #1222

The bindings config selected rules with `extend-select`, which extends
ruff's defaults rather than replacing them, so the effective rule set
moved with upstream. ruff 0.16.0 grew its defaults from 59 rules to
413: measured on this tree, same config, the enabled count went from
265 (0.15.22) to 501 (0.16.1), pulling in 28 families the config never
asked for. Among them PLC/PLE/PLR/PLW, which silently overrode the
deliberate omission of Pylint's design rules that the comment above
the setting states. The same release dropped 18 opinionated E/F rules
from the defaults, which a defaults-relative config would have lost
just as quietly.

State the set absolutely with `select` and raise the ceiling to <0.17.
Under `select` the count is 265 on 0.15.22 — unchanged, so nothing was
lost by dropping the implicit defaults — and 268 on 0.16.2, the three
additions being new RUF rules in an already-selected family. `ruff
check` passes on both with no noqa, no suppressions and no source
changes; the three diagnostics 0.16 reported (DTZ001, BLE001, PYI044)
were all in families never selected.

`uv lock` keeps a package at its locked version while that version
still satisfies the requirement, so widening the ceiling alone left
ruff at 0.15.22. Adopting 0.16.2 took an explicit `uv lock
--upgrade-package ruff`; CONTRIBUTING.md now documents that step.

The floor moves 0.6 -> 0.13 because it was already fiction. UP038 left
ruff's stable set in 0.13, and 0.6.0, 0.9.0, 0.12.0 and 0.12.12 each
flag the same five isinstance(x, (A, B)) sites here — identically
under the old extend-select config, so this changes nothing beyond
saying what was always true.

The ruff-pre-commit `rev:` moves to v0.16.2 to match what uv.lock
resolves. It had drifted to v0.15.14 against a locked 0.15.22 — inside
the old bound, so nothing failed, but the two ran different ruffs.

Fixes #1222
@dekobon
dekobon merged commit d5fba4f into main Aug 8, 2026
50 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

deps(py): adopt ruff 0.16 by pinning the rule set with select

1 participant