Skip to content

py(deps[dev]): Require ruff>=0.16.0 - #63

Merged
tony merged 7 commits into
masterfrom
ruff-0.16
Jul 26, 2026
Merged

py(deps[dev]): Require ruff>=0.16.0#63
tony merged 7 commits into
masterfrom
ruff-0.16

Conversation

@tony

@tony tony commented Jul 26, 2026

Copy link
Copy Markdown
Member

Summary

  • Pin a ruff>=0.16.0 floor in the dev and lint dependency groups so contributors and CI resolve the same linter and see the same diagnostics.
  • Relock uv.lock onto ruff 0.16.0.
  • Adopt ruff's default rule set. select becomes extend-select, so this project's linters layer on top of ruff's curated default set instead of replacing it. Enabled rules go from 351 to 565.
  • One new finding, scoped as an ignore. The wider rule set surfaced a single diagnostic — S102 on the exec in docs/conf.py — and it is intentional.

Changes

pyproject.tomlruff raised to >=0.16.0 in [dependency-groups] dev and lint; [tool.ruff.lint] select renamed to extend-select with a comment recording why select stays unset; S102 per-file-ignored for docs/conf.py.

uv.lock — ruff 0.15.22 -> 0.16.0.

CHANGES — entries for the floor bump and the rule-set adoption.

Design decisions

Why extend-select rather than a wider select

ruff 0.16 ships a curated default rule set as its recommended baseline. An explicit select replaces that set rather than extending it, so this project was silently opting out of everything ruff considers a sensible default. There is no token that names the default set from inside select — ruff's selector grammar has no DEFAULT — so the only way to get defaults-plus-extras is to leave select unset and layer the project's linters through extend-select.

The alternative of naming whole prefixes (PL, S, PYI, ...) in select was rejected: it drags in the full contents of each family rather than the curated subset, which is far noisier for no added signal.

Every extend-select entry stays on its own line with a trailing comment naming the linter it selects. FA100's comment now names flake8-future-annotations rather than describing the rule.

The one finding

S102 (exec-builtin) in docs/conf.py. Sphinx collects the project's title, copyright, and URLs by exec'ing the package's __about__.py into a dict, because g/__init__.py re-exports only __version__. The exec'd input is a tracked file in this repository, not user data, so the flake8-bandit warning has nothing to warn about here. Scoped as a per-file-ignore on docs/conf.py rather than repo-wide, with the reason recorded in the config.

No code changes were needed: nothing else in src/, tests/, or docs/ trips a default rule.

ruff 0.16 rule stabilizations

ruff 0.16.0 stabilizes several rules that live inside prefixes this project already selects, notably RUF036, RUF063, and RUF068, plus behavior changes to UP019 and the B/SIM/TRY families. None of them fire here.

ruff 0.16.0 also formats Python and pycon code blocks inside Markdown by default. All Markdown under the repo (including docs/) is picked up by ruff format and came back already formatted, so there is no churn. CHANGES has no .md extension and is not in scope for ruff format; it stays on the prettier path in the format_markdown make target.

See https://astral.sh/blog/ruff-v0.16.0 for the full release notes.

Test plan

  • uv run ruff check . — all checks passed
  • uv run ruff format --check . — every file already formatted
  • uv run mypy . — no issues found
  • uv run py.test — passes in a normal checkout

Note on running the suite from a linked worktree: tests/test_cli.py::test_command_line[g-cmd-inside-git-dir] and [g-cmd-help-inside-git-dir] fail there because find_repo_type requires .git to be a directory, and a linked worktree's .git is a file. Both fail identically at the base commit, so this is not a regression from this branch, and CI's plain checkout is unaffected.

tony added 2 commits July 26, 2026 13:22
why: uv's global `exclude-newer = "3 days"` supply-chain cooldown hides
ruff 0.16.0 (released 2026-07-23) from the resolver, so the version
floor in the next commit cannot resolve.

what:
- Add `ruff = false` to `[tool.uv.exclude-newer-package]`

Temporary. Revert before merge - the cooldown clears on its own and the
`ruff>=0.16` floor is what actually holds the version.
why: ruff 0.16.0 stabilizes rules inside prefixes this project already
selects and starts formatting Python code blocks in Markdown. Pinning a
floor keeps contributors and CI on the same diagnostics instead of
splitting on whatever ruff each machine resolved.

what:
- Raise `ruff` to `>=0.16.0` in the `dev` and `lint` dependency groups
- Relock `uv.lock`: ruff 0.15.22 -> 0.16.0

https://astral.sh/blog/ruff-v0.16.0
@codecov-commenter

codecov-commenter commented Jul 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.89%. Comparing base (c3da8ed) to head (2fc33bf).

Additional details and impacted files
@@           Coverage Diff           @@
##           master      #63   +/-   ##
=======================================
  Coverage   96.89%   96.89%           
=======================================
  Files           5        5           
  Lines         129      129           
=======================================
  Hits          125      125           
  Misses          4        4           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

tony added 5 commits July 26, 2026 13:26
why: The unreleased entry tracks dev-tooling floors so contributors
know which linter version the repo's diagnostics assume.

what:
- Add a `### Development` bullet for the `ruff>=0.16.0` floor
why: ruff 0.16.0 published 2026-07-23T19:10Z and has now cleared uv's
3-day supply-chain cooldown, so the resolver reaches it unaided. The
`ruff>=0.16.0` floor is what holds the version; leaving the exemption
would permanently opt ruff out of the cooldown guard.

what:
- Drop `ruff = false` from `[tool.uv.exclude-newer-package]`
- Relock: the setting is recorded in `uv.lock`, so removing it forces a
  re-resolve. ruff stays at 0.16.0 and no other package moves.

This reverts commit ea200b3.
why: ruff 0.16 ships a curated 413-rule default set as its recommended
baseline. An explicit `select` replaces that set rather than extending
it, so this project was running 351 rules and silently opting out of
the default set. `extend-select` layers the project's own linters on
top of the default set instead of in place of it.

what:
- Replace `select` with `extend-select`, same entries, one per line
- Note in the file why `select` stays unset
- Name the linter behind `FA100` instead of describing the rule

Enabled rules go from 351 to 565.
https://docs.astral.sh/ruff/linter/#rule-selection
why: `docs/conf.py` collects the project's title, copyright, and URLs by
exec'ing the package's `__about__.py` into a dict, because
`g/__init__.py` re-exports only `__version__`. The input is a tracked
file in this repository, not user data, so the flake8-bandit warning has
nothing to warn about here.

what:
- Per-file-ignore S102 for `docs/conf.py`

https://docs.astral.sh/ruff/rules/exec-builtin/
why: The ruff floor entry covered the version bump but not the rule
selection change that rides with it.

what:
- Note that lint runs on ruff's default set plus this project's linters
- Name the scoped per-file ignore and why it exists
@tony
tony merged commit c8b5bd1 into master Jul 26, 2026
7 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.

2 participants