Skip to content

Upgrade ruff to 0.16.0#92

Draft
davegaeddert wants to merge 1 commit into
masterfrom
claude/ruff-version-update-yafyyi
Draft

Upgrade ruff to 0.16.0#92
davegaeddert wants to merge 1 commit into
masterfrom
claude/ruff-version-update-yafyyi

Conversation

@davegaeddert

Copy link
Copy Markdown
Member

Upgrades ruff 0.12.00.16.0 (lockfile), and raises the plain.code floor from ruff>=0.1.0 to ruff>=0.16.0.

Ruff 0.16 changes two defaults that plain.code inherits. Because ruff_defaults.toml ships to every Plain project and the old floor was >=0.1.0, both would have reached users through a transitive ruff resolve without them changing anything — so most of this PR is pinning the config so the shipped rule set stops moving with ruff's.

Default rule set: extend-selectselect

Ruff 0.16 grew its built-in default selection from 59 rules to 413. ruff_defaults.toml used extend-select, which layers on top of that default, so plain code check went from 155 rules to 445 and reported 1474 errors across this repo (RUF012 ×427, DTZ001 ×96, BLE001 ×94, …).

Spelling out the old base (E4, E7, E9, F) alongside the existing category selectors makes the shipped set version-independent. The category selectors stay whole — "UP" still means every stable UP rule, not the subset ruff now defaults to — so upgrades continue to pick up new rules inside a category we've opted into.

Net rule change is what a version bump should be:

Rule Change
UP038 removed upstream
UP042, UP050, ISC004 added

Markdown

Ruff 0.16 lints and formats Python code blocks inside Markdown, on by default. Left alone it reformats historical CHANGELOGs and doc examples that are deliberately partial. ruff_defaults.toml now sets extend-exclude = ["*.md"].

This also keeps a single owner for Markdown in this repo — scripts/fix already runs prettier with --embedded-language-formatting off. Documented as an FAQ in the plain.code README, since users reading ruff's release notes may expect the new behavior.

isort and the plain namespace

Ruff 0.16 resolves namespace packages per-submodule. In a checkout with part of plain on disk (this monorepo — plain/ sits at the project root), bare plain sorted as first-party while plain.postgres stayed third-party, splitting one namespace across two import blocks.

known-third-party = ["plain"] makes grouping identical everywhere. It's a no-op for projects that install Plain from PyPI, where ruff already resolves plain as third-party. This is what regroups imports across 230+ files here — mechanical, and the result now matches what a Plain app sees.

Violations fixed

  • ISC004 — wrapped implicit string concatenations inside collection literals (plain-postgres health runner, tools/server-worker-test.py).
  • UP042 — suppressed on TextChoices. It can't become an enum.StrEnum without losing its deliberately overridden __str__ and _generate_next_value_.
  • One formatter improvement in plain-postgres/plain/postgres/expressions.py (lambda + conditional parenthesization).

Verification

  • ruff check / ruff format --check / ty check / annotations — all pass.
  • Full test suite passes (~2,000 tests, 1 pre-existing skip).
  • oxlint/oxfmt were not exercised — the binary download fails TLS in the sandbox. Untouched by this change.

Follow-up worth considering separately

Ruff's new defaults are a curated set aimed at severe issues, and a lot of it looks worth having (RUF012 mutable class defaults, DTZ naive datetimes, BLE001 blind excepts). Adopting any of it means fixing hundreds of real violations, so it should be a deliberate pass rather than a side effect of a version bump.


Generated by Claude Code

Ruff 0.16 changes two defaults that plain.code inherits, and since
`ruff_defaults.toml` ships to every Plain project, both would have reached
users through a transitive ruff resolve without them changing anything.

Pin the rule set explicitly. Ruff grew its built-in default selection from 59
rules to 413, and `ruff_defaults.toml` used `extend-select`, which layers on
top of that default — `plain code check` went from 155 rules to 445, firing
1474 errors across this repo. Spelling out the old base (`E4`, `E7`, `E9`,
`F`) alongside the existing category selectors keeps the shipped set stable
across ruff versions. The categories stay whole (all of `UP`, not ruff's
subset of it), so upgrades still pick up new rules we've opted into. Net rule
change is what the version bump should be: `UP038` removed upstream, `UP042`,
`UP050`, and `ISC004` added.

Exclude `*.md`. Ruff 0.16 formats Python code blocks in Markdown by default,
which rewrites changelogs and doc examples that are deliberately partial.
This repo already runs prettier with `--embedded-language-formatting off`,
so opting out keeps one owner for Markdown.

Pin `plain` as third-party for isort. Ruff 0.16 resolves namespace packages
per-submodule, so a checkout with part of `plain` on disk sorted bare `plain`
as first-party while `plain.postgres` stayed third-party, splitting one
namespace across two blocks. Pinning it makes grouping identical everywhere
and is a no-op for projects that install Plain from PyPI. This regroups
imports across the repo so they match what a Plain app sees.

Fix the violations the new rules found: wrap implicit string concatenations
inside collections (`ISC004`), and suppress `UP042` on `TextChoices`, which
can't become a `StrEnum` without losing its overridden `__str__` and
`_generate_next_value_`.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VeLG1nWiLA3tFMWfGwMiQV
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.

2 participants