## Summary
Changing the lexer's keyword set now takes one edit to the Rust list.
The compiler finds a collision-free multiplier and builds the 64-slot
table, so we can remove the Python generator and its lockfile.
A two-byte keyword like `if` packs to `0x6669_0000_0000_0000`. Only the
low two bytes of the multiplier affect its slot. We place keywords from
shortest to longest, choosing each new byte of the multiplier without
disturbing the shorter keywords. The lexer still selects a slot with one
multiply and shift, then compares the full word.
## Summary
We scan ASCII identifier continuations in sixteen-byte batches using a
byte lookup table, avoiding per-character decoding. Keyword lookup
filters by length and initial byte, then uses a compact hash table with
a full-word comparison to reject collisions. Non-ASCII suffixes retain
the existing Unicode path.
Report comments include a redundant ZIP download link after the hosted
HTML links. Show the ZIP link only when the HTML report is unavailable,
including when its upload fails.
Co-authored-by: zaniebot <242828183+zaniebot@users.noreply.github.com>
ty ecosystem comments currently require downloading a ZIP to view the
full reports. Add an optional `upload-html` mode to the shared report
publisher and enable it for ty, linking directly to the diagnostic diff
and timing results while retaining the downloadable artifact.
The publisher runs from `main`, uses STS for GitHub credentials, and
obtains temporary AWS upload credentials through GitHub OIDC when
hosting is enabled. Each caller supplies filenames and content types,
with optional link labels. The publisher reads only those files from a
bounded archive without extracting or executing them during publication,
and stores reports under separate paths for each PR, report, run, and
attempt. If an upload fails, the publisher still attempts to post the
summary and, when available, the artifact link.
The `automations` environment requires `REPORTS_BUCKET`, `REPORTS_URL`,
`REPORTS_ROLE_ARN`, and `REPORTS_REGION` from the report hosting
infrastructure.
---------
Co-authored-by: Zanie Blue <2586601+zanieb@users.noreply.github.com>
Co-authored-by: zaniebot <242828183+zaniebot@users.noreply.github.com>
The report footer renders the commit SHA as code, so it is not
clickable. Link the commit, label it as the revision the results
describe, and separate the footer from the report.
---------
Co-authored-by: zaniebot <242828183+zaniebot@users.noreply.github.com>
Add `publish-pull-request-report.yml` as a shared publisher for
automation reports, using STS for GitHub writes and the KV actions for
comment IDs. Store IDs in `pull-request` scope so later runs can update
the same report.
Look up each stored ID directly and verify the bot, PR, marker, and run
metadata. When a report is published, missing or expired keys create a
new comment without scanning existing comments; deleted comments are
replaced. Malformed IDs, IDs belonging to another comment, and KV errors
fail the job. The publisher verifies the source run and current PR head
before writing; report workflows enable it separately.
---------
Co-authored-by: zaniebot <242828183+zaniebot@users.noreply.github.com>
Move reviewer selection from `astral-bot` into a serialized Actions
worker triggered by Ruff's dispatch policy. The worker uses the
repository's reviewer pools and requests reviews as
`astral-automations-bot[bot]` using STS. Store round-robin credits in
`workflow` scope, with read and write access restricted to
`pull-request-reviewers.yml` on `main` in the `automations` environment.
When no reviewer state is stored, credits start at zero.
---------
Co-authored-by: zaniebot <242828183+zaniebot@users.noreply.github.com>
Enable `require-build-hashes` for the Python projects and inline scripts
so isolated builds require declared hashes for their build dependencies.
Pin the build backends and their dependencies with hashes.
---------
Co-authored-by: zaniebot <242828183+zaniebot@users.noreply.github.com>
## Summary
Use thin LTO for the instrumented release executable in the PGO build,
while keeping fat LTO for the final executable. Pass the override
through `cargo rustc` so dependency compilation and the workspace's
release profile are unchanged. Debug builds are unchanged.
This reduces the estimated PGO pipeline time by 54% in a Linux x86-64
comparison, with essentially unchanged final binary size and no
consistent runtime regression across the holdout projects used for the
original PGO work in #27570.
## Build results
| Measurement | Fat training | Thin training |
| --- | ---: | ---: |
| Instrumented build | 487.86 s | 85.50 s |
| Final fat-LTO build, median | 247.75 s | 250.43 s |
| Estimated complete PGO pipeline | 738.02 s | 338.26 s |
| Final stripped executable, median | 22.719 MiB | 22.724 MiB |
Instrumented builds were measured once per mode. Final build times and
sizes are medians of three independently collected profiles per mode.
Pipeline estimates add the instrumented build, median training and
profile merge, and median final build; corpus downloads are excluded.
These are clean local build measurements, not CI timing predictions.
## Runtime results
We trained on the canonical 618-file corpus and evaluated linting and
formatting on Django, pandas, scikit-learn, SciPy, and SymPy, whose
repositories are disjoint from the training corpus. The holdout pins
come from the contemporaneous Windows follow-up in #27573, since the
initial Linux PR did not record exact holdout revisions.
Each case used three independent profile pairs and 12 interleaved
fat/thin timing pairs per profile, for 720 timed runs in total. Runs
used eight pinned CPUs and eight threads, with balanced execution order
and warm caches. Diagnostics and formatting diffs were checked
separately from the quiet timed commands and matched across all six
final binaries.
Positive changes below mean thin training was slower. Intervals are
per-workload hierarchical bootstrap 95% confidence intervals, resampling
profile pairs and then paired timing observations; they are not adjusted
for multiple comparisons.
| Holdout | CPU change (95% CI) | Wall change (95% CI) |
| --- | ---: | ---: |
| Django lint | -0.21% [-0.77%, +0.49%] | +0.10% [-1.41%, +1.29%] |
| Django format | -0.10% [-1.18%, +0.72%] | -0.27% [-1.37%, +1.45%] |
| pandas lint | -0.01% [-0.45%, +0.39%] | -0.67% [-2.49%, +1.26%] |
| pandas format | -0.26% [-1.10%, +0.67%] | -0.84% [-2.81%, +2.12%] |
| scikit-learn lint | +0.02% [-0.62%, +1.12%] | -0.02% [-1.11%, +1.86%]
|
| scikit-learn format | -0.52% [-2.14%, +0.62%] | -0.79% [-2.08%,
+1.03%] |
| SciPy lint | -0.21% [-0.70%, +0.43%] | -0.64% [-4.59%, +1.52%] |
| SciPy format | -0.52% [-1.03%, +0.13%] | -2.47% [-6.20%, +1.61%] |
| SymPy lint | +0.01% [-0.30%, +0.27%] | -0.77% [-3.23%, +0.88%] |
| SymPy format | -0.18% [-1.89%, +1.84%] | -0.58% [-3.58%, +3.30%] |
A longer SymPy formatting repeat with the same three profile pairs and
48 timing pairs per profile measured -0.18% CPU [-1.96%, +1.66%] and
-0.28% wall time [-2.19%, +1.58%]. Individual profiles varied in both
directions, so the near-flat average should not be interpreted as
identical performance for every trained binary. The pandas formatting
wall-time interval remains inconclusive at a 2% slowdown threshold.
All six profiles had matching function/CFG identities and counter
layouts, with no missing-profile or profile-mismatch compiler
diagnostics. Their counter values and `.profdata` bytes were not
identical.
Measurements used the Rust/Cargo source at
`7c6f8fc8fc5655dfa47e125b05453007b9e7a6c7`, the standard release
codegen-unit settings, and Ohm Rust 1.99.0-dev (`08bbd755a`, LLVM
23.1.1) with experimental defaults disabled. The benchmark was not rerun
on this PR's newer base revision. This is an exploratory Linux x86-64
study with three profiles per mode, not a guarantee of zero runtime cost
or equivalent results on macOS, Windows, or ARM.
Follow-up to #29151: upgrade the benchmark dependency from hyperfine
2.0.0-alpha.2 to 2.0.0.
Use `--env RAYON_NUM_THREADS=1` instead of an `env` command prefix for
the single-threaded formatter benchmarks. This avoids measuring the
overhead of `env` itself (~5 ms).
## Summary
Upgrade hyperfine to 2.0.0-alpha.2, which now includes support for
memory measurements (see output below).
Tested:
<details>
<summary>Formatter benchmark output</summary>
```text
Benchmark 1: ./target/release/ruff format ./fixture (2 runs)
mean ± σ min … max
Wall Time 12.8 ms ± 0.2 ms 12.7 ms … 12.9 ms
Memory 16.6 MiB ± 0.1 MiB 16.5 MiB … 16.6 MiB
Benchmark 2: black --no-cache ./fixture --safe (2 runs)
mean ± σ min … max
Wall Time 207.1 ms ± 4.8 ms 203.7 ms … 210.5 ms +1517.9% (16.2x slower)
Memory 37.3 MiB ± 0.1 MiB 37.2 MiB … 37.4 MiB +125.2% (2.3x more)
Benchmark 3: black --no-cache ./fixture --fast (2 runs)
mean ± σ min … max
Wall Time 226.6 ms ± 7.4 ms 221.4 ms … 231.9 ms +1670.7% (17.7x slower)
Memory 37.4 MiB ± 0.1 MiB 37.3 MiB … 37.5 MiB +126.2% (2.3x more)
Benchmark 4: black --no-cache ./fixture --safe --preview (2 runs)
mean ± σ min … max
Wall Time 250.1 ms ± 41.8 ms 220.6 ms … 279.6 ms +1854.3% (19.5x slower)
Memory 37.4 MiB ± 0.3 MiB 37.2 MiB … 37.6 MiB +126.0% (2.3x more)
Benchmark 5: black --no-cache ./fixture --fast --preview (2 runs)
mean ± σ min … max
Wall Time 186.2 ms ± 2.5 ms 184.5 ms … 188.0 ms +1355.1% (14.6x slower)
Memory 37.3 MiB ± 0.0 MiB 37.3 MiB … 37.3 MiB +125.2% (2.3x more)
Benchmark 6: autopep8 ./fixture --recursive --in-place (2 runs)
mean ± σ min … max
Wall Time 41.6 ms ± 0.7 ms 41.1 ms … 42.1 ms +225.2% (3.3x slower)
Memory 26.3 MiB ± 0.0 MiB 26.3 MiB … 26.3 MiB +58.8% (1.6x more)
Benchmark 7: yapf ./fixture --parallel --recursive --in-place (2 runs)
mean ± σ min … max
Wall Time 142.1 ms ± 4.8 ms 138.7 ms … 145.5 ms +1010.6% (11.1x slower)
Memory 29.1 MiB ± 0.3 MiB 28.9 MiB … 29.4 MiB +76.0% (1.8x more)
Benchmark 1: env RAYON_NUM_THREADS=1 ./target/release/ruff format ./fixture (2 runs)
mean ± σ min … max
Wall Time 12.7 ms ± 2.5 ms 10.9 ms … 14.4 ms
Memory 14.6 MiB ± 0.1 MiB 14.6 MiB … 14.7 MiB
Benchmark 2: black --no-cache ./fixture --workers=1 --safe (2 runs)
mean ± σ min … max
Wall Time 95.2 ms ± 3.2 ms 92.9 ms … 97.4 ms +650.6% (7.5x slower)
Memory 38.4 MiB ± 0.0 MiB 38.4 MiB … 38.4 MiB +162.6% (2.6x more)
Benchmark 3: black --no-cache ./fixture --workers=1 --fast (2 runs)
mean ± σ min … max
Wall Time 89.6 ms ± 2.8 ms 87.6 ms … 91.6 ms +606.5% (7.1x slower)
Memory 38.4 MiB ± 0.0 MiB 38.4 MiB … 38.4 MiB +162.7% (2.6x more)
Benchmark 4: black --no-cache ./fixture --workers=1 --safe --preview (2 runs)
mean ± σ min … max
Wall Time 94.7 ms ± 0.6 ms 94.3 ms … 95.2 ms +646.9% (7.5x slower)
Memory 38.5 MiB ± 0.1 MiB 38.5 MiB … 38.6 MiB +163.5% (2.6x more)
Benchmark 5: black --no-cache ./fixture --workers=1 --fast --preview (2 runs)
mean ± σ min … max
Wall Time 92.7 ms ± 0.6 ms 92.3 ms … 93.2 ms +631.4% (7.3x slower)
Memory 38.4 MiB ± 0.1 MiB 38.3 MiB … 38.4 MiB +162.5% (2.6x more)
Benchmark 6: autopep8 ./fixture --in-place --recursive --jobs=1 (2 runs)
mean ± σ min … max
Wall Time 43.5 ms ± 3.7 ms 40.9 ms … 46.1 ms +242.7% (3.4x slower)
Memory 26.5 MiB ± 0.1 MiB 26.4 MiB … 26.6 MiB +81.2% (1.8x more)
Benchmark 7: yapf ./fixture --recursive --in-place (2 runs)
mean ± σ min … max
Wall Time 56.8 ms ± 1.2 ms 55.9 ms … 57.6 ms +347.8% (4.5x slower)
Memory 27.3 MiB ± 0.1 MiB 27.2 MiB … 27.4 MiB +86.5% (1.9x more)
Benchmark 1: ./target/release/ruff format ./fixture --check (2 runs)
mean ± σ min … max
Wall Time 10.2 ms ± 0.3 ms 9.9 ms … 10.4 ms
Memory 16.9 MiB ± 0.1 MiB 16.8 MiB … 17.0 MiB
Benchmark 2: black --no-cache ./fixture --check --safe (2 runs)
mean ± σ min … max
Wall Time 193.8 ms ± 6.2 ms 189.5 ms … 198.2 ms +1806.9% (19.1x slower)
Memory 37.3 MiB ± 0.1 MiB 37.2 MiB … 37.4 MiB +120.8% (2.2x more)
Benchmark 3: black --no-cache ./fixture --check --fast (2 runs)
mean ± σ min … max
Wall Time 188.2 ms ± 1.9 ms 186.8 ms … 189.6 ms +1751.4% (18.5x slower)
Memory 37.3 MiB ± 0.1 MiB 37.3 MiB … 37.4 MiB +121.1% (2.2x more)
Benchmark 4: black --no-cache ./fixture --check --safe --preview (2 runs)
mean ± σ min … max
Wall Time 202.1 ms ± 6.3 ms 197.7 ms … 206.6 ms +1888.5% (19.9x slower)
Memory 37.2 MiB ± 0.0 MiB 37.2 MiB … 37.2 MiB +120.5% (2.2x more)
Benchmark 5: black --no-cache ./fixture --check --fast --preview (2 runs)
mean ± σ min … max
Wall Time 197.0 ms ± 20.1 ms 182.8 ms … 211.2 ms +1837.8% (19.4x slower)
Memory 37.2 MiB ± 0.0 MiB 37.2 MiB … 37.2 MiB +120.5% (2.2x more)
Benchmark 6: autopep8 ./fixture --recursive --diff (2 runs)
mean ± σ min … max
Wall Time 38.5 ms ± 0.1 ms 38.4 ms … 38.6 ms +278.4% (3.8x slower)
Memory 26.3 MiB ± 0.0 MiB 26.3 MiB … 26.4 MiB +56.0% (1.6x more)
Benchmark 7: yapf ./fixture --parallel --recursive --quiet (2 runs)
mean ± σ min … max
Wall Time 144.8 ms ± 7.4 ms 139.6 ms … 150.1 ms +1324.8% (14.2x slower)
Memory 29.0 MiB ± 0.2 MiB 28.9 MiB … 29.1 MiB +71.6% (1.7x more)
```
</details>
<details>
<summary>ty_benchmark (multi-threaded, then single-threaded)</summary>
```text
jinja
-----
Benchmark 1: ty (2 runs)
mean ± σ min … max
Wall Time 73.0 ms ± 5.6 ms 69.0 ms … 76.9 ms
Memory 100.1 MiB ± 0.1 MiB 100.0 MiB … 100.2 MiB
Warning: Ignoring non-zero exit code.
Benchmark 2: Pyrefly (2 runs)
mean ± σ min … max
Wall Time 118.3 ms ± 6.0 ms 114.0 ms … 122.5 ms +62.1% (1.6x slower)
Memory 130.9 MiB ± 0.2 MiB 130.8 MiB … 131.1 MiB +30.8% (1.3x more)
Warning: Ignoring non-zero exit code.
Benchmark 3: mypy (2 runs)
mean ± σ min … max
Wall Time 802.9 ms ± 8.0 ms 797.2 ms … 808.6 ms +1000.2% (11.0x slower)
Memory 143.4 MiB ± 0.1 MiB 143.3 MiB … 143.5 MiB +43.2% (1.4x more)
Warning: Ignoring non-zero exit code.
Benchmark 4: mypy (warm) (2 runs)
mean ± σ min … max
Wall Time 208.8 ms ± 5.6 ms 204.9 ms … 212.7 ms +186.1% (2.9x slower)
Memory 51.9 MiB ± 0.2 MiB 51.8 MiB … 52.0 MiB -48.2% (1.9x less)
Warning: Ignoring non-zero exit code.
Benchmark 5: Pyright (2 runs)
mean ± σ min … max
Wall Time 1198.8 ms ± 12.0 ms 1190.3 ms … 1207.3 ms +1542.8% (16.4x slower)
Memory 251.6 MiB ± 1.3 MiB 250.7 MiB … 252.5 MiB +151.3% (2.5x more)
Warning: Ignoring non-zero exit code.
jinja
-----
Benchmark 1: ty (2 runs)
mean ± σ min … max
Wall Time 226.1 ms ± 14.0 ms 216.2 ms … 236.0 ms
Memory 84.9 MiB ± 0.2 MiB 84.8 MiB … 85.0 MiB
Warning: Ignoring non-zero exit code.
Benchmark 2: Pyrefly (2 runs)
mean ± σ min … max
Wall Time 210.4 ms ± 6.9 ms 205.5 ms … 215.3 ms -7.0%
Memory 92.3 MiB ± 0.1 MiB 92.2 MiB … 92.4 MiB +8.8%
Warning: Ignoring non-zero exit code.
Benchmark 3: mypy (2 runs)
mean ± σ min … max
Wall Time 896.4 ms ± 88.8 ms 833.7 ms … 959.2 ms +296.4% (4.0x slower)
Memory 144.3 MiB ± 0.6 MiB 143.9 MiB … 144.7 MiB +70.0% (1.7x more)
Warning: Ignoring non-zero exit code.
Benchmark 4: mypy (warm) (2 runs)
mean ± σ min … max
Wall Time 213.0 ms ± 3.7 ms 210.4 ms … 215.6 ms -5.8%
Memory 51.7 MiB ± 0.1 MiB 51.6 MiB … 51.8 MiB -39.1% (1.6x less)
Warning: Ignoring non-zero exit code.
Benchmark 5: Pyright (2 runs)
mean ± σ min … max
Wall Time 981.9 ms ± 13.0 ms 972.6 ms … 991.1 ms +334.2% (4.3x slower)
Memory 315.4 MiB ± 5.9 MiB 311.2 MiB … 319.5 MiB +271.6% (3.7x more)
Warning: Ignoring non-zero exit code.
```
</details>
I also tested most of the other hyperfine invocations mentioned
somewhere in this repo.
## Summary
Enable `truthiness-test-of-none-union` in the standalone scripts' inline
configuration and in the `py-fuzzer` and `ty_benchmark` projects,
following #28889.
this is primarily useful for testing the sts token exchange in a
non-load bearing environment ahead of merging #28484
, but may be useful for maintainers :)
`automations` environment has been created and `STS_API_URL` secret set
## Summary
Removes the "Who's using ruff?" list.
The section was useful when Ruff was young and not well known. Ruff is
now widely used in the ecosystem, so that this list provides diminishing
returns and we also lack a clear guidance on what it takes for a project
to be added.
Release archives already have `.sha256` files, but the custom binary
build jobs don't put those hashes in cargo-dist's manifest. The
generated shell installer therefore has no expected archive hashes to
check.
Add a job that imports the built archives' checksums into a local
manifest before cargo-dist generates the installers. Run the helper
through uv with a script lockfile, require a valid sidecar for every
downloaded executable archive, and require the job to succeed before
hosting the release.
Release preparation still directs new crates to the local bootstrap
utility, which requires a crates.io owner token and tracks configured
crates in `.known-crates`. Use `astral-sh/crates-policies` as the source
of truth instead, matching
[astral-sh/uv#20449](https://github.com/astral-sh/uv/pull/20449).
`scripts/release.sh` now runs the shared workspace checker, the
contribution guide points to the central registration process, and the
duplicate setup utility and local crate list are removed.
Co-authored-by: Zanie Blue <contact@zanie.dev>
## Summary
Continues #28197 by lifting `cargo-fuzz` into the dev toolchain.
<!-- What's the purpose of the change? What does it do, and why? -->
## Test Plan
NFC, internal only. I confirmed that `./init-fuzzer.sh` still runs as
expected. I'm less positive about the CI changes.
<!-- How was it tested? -->
---------
Signed-off-by: William Woodruff <william@yossarian.net>
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
## Summary
The upstream https://github.com/python/typing generated html now has a
breakdown of total test cases passing for each typechecker.
These total don't match what the `conformance.py` emits in it's summary:
https://github.com/astral-sh/ruff/pull/28001#issuecomment-5410032559
> The number of fully passing files held steady at 112/136.
versus
<img width="235" height="132" alt="image"
src="https://github.com/user-attachments/assets/6af76b8d-9002-4b00-ac87-b55afb0c15f8"
/>
This is because the summary is generated from `TestCase` which track
`ty` diagnostics, if there are no diagnostics because the relevant test
is designed to emit none they are not included in the count.
So instead we also use the full `test_files` to fill in the missing
stats.
NOTE: I have also bumped `CONFORMANCE_SUITE_COMMIT` which brings in some
recent spec related changes (not just version bumps)
## Test Plan
`CONFORMANCE_SUITE_COMMIT=cf943ccbea5596ef969eec6e2260097ff697b7ba uv
run --no-project --python 3.12 scripts/conformance.py --old-ty uvx
ty@0.0.75 --new-ty uvx ty@0.0.75 --tests-path ~/dev/typing/conformance`
```md
## [Typing conformance results](https://github.com/python/typing/blob/cf943ccbea5596ef969eec6e2260097ff697b7ba/conformance/)
### No changes detected ✅
<details>
<summary>Current numbers</summary>
<br>
The percentage of diagnostics emitted that were expected errors held steady at <b>97.79%</b>. The percentage of expected errors that received a diagnostic held steady at <b>94.41%</b>. The number of fully passing files held steady at <b>121/145</b>.
</details>
```
Summary
--
This PR updates our ruff-pre-commit dependency to 0.16.5, which supports
the new category selectors,
and then enables `lint.preview` and the new default categories so that
we can dogfood them on our
code. There were 66 diagnostics initially, which I also fixed or
ignored:
```
28 FURB113 [ ] repeated-append
12 ASYNC240 [ ] blocking-path-method-in-async-function
6 RUF105 [*] noqa-comments
5 PLW1510 [ ] subprocess-run-without-check
3 PLW0108 [ ] unnecessary-lambda
2 EXE001 [ ] shebang-not-executable
2 RUF039 [*] unraw-re-pattern
1 B024 [ ] abstract-base-class-without-abstract-method
1 FURB142 [*] for-loop-set-mutations
1 PERF102 [ ] incorrect-dict-iterator
1 PLC0207 [*] missing-maxsplit-arg
1 PLW0127 [ ] self-assigning-variable
1 TRY004 [ ] type-check-without-type-error
1 PLW0120 [*] useless-else-on-loop
1 TRY201 [ ] verbose-raise
```
Of these, I ignored `repeated-append` and `blocking-path-method-in-async-function`. I think they are
still reasonable defaults, just less useful/important in our uses.
0.16.5 also includes https://github.com/astral-sh/ruff-pre-commit/pull/159, so I removed `markdown` from our main `ruff-format` hook, leaving it for the later mdtest formatting stage.
I also had to make a few changes related to config discovery in tests:
- move our cached ecosystem checkouts to `$RUNNER_TEMP` instead of inside of our checkout
- convert some CLI tests to use the `CliTest` helpers
- add `configurationPreference: editorOnly` to some notebook tests
In these cases, our own Ruff settings were being inherited by test code. This likely affects many other tests, but I only updated the obviously failing ones for now. I'm least confident about the notebook tests, but as far as I can tell from the history (https://github.com/astral-sh/ruff/pull/11944, https://github.com/astral-sh/ruff/pull/22810), the specific diagnostics are not the important parts being asserted.
Test Plan
--
CI on this PR
Summary
--
This PR allows adding rules that only belong to categories and only have
names rather than requiring
a linter group and code.
The first non-empty commit uses `Rule::name` instead of
`Rule::noqa_code` throughout the linter tests, causing a huge number of
file renames without changes.
The second commit updates `FixTable` from a mapping of `SecondaryCode ->
(name, fix_count)` to
`DiagnosticId -> (Option<SecondaryCode>, fix_count)`. This doesn't
really change its usage but
involves minor diffs to a substantial number of lines. It also allows us
to drop some of the special
`hashbrown` handling and the `hashbrown` dependency in `ruff_linter`,
which is nice.
The third commit contains the bulk of the change, including the macro
changes needed to support
`map_codes` entries like that for the `pytest-fixture-autouse` rule in
the fourth commit:
```rust
() => rules::ruff::rules::PytestFixtureAutouse,
```
These changes are pretty mechanical overall, just handling cases where
the linter or noqa code could
be missing, which fortunately seemed pretty straightforward in every
case.
The fourth commit takes advantage of these changes to reinstate `RUF076`
as our first purely
`pedantic` rule. I'm happy to drop that if it's too controversial or
opens too many questions about
the previously-removed rule and its code, but I thought it was nice to
have a motivating example. We
moved this rule from `preview` to `removed` because it was too pedantic
for the `RUF` category, even
in preview, so it's exactly the kind of rule we can support now with the
categories.
Finally, the fifth commit updates the contributing docs to reflect that
linters and codes are
optional. This may need to be adjusted if we back out the `RUF076`
change.
Test Plan
--
Existing tests, plus a few new ones for `pytest-fixture-autouse`
Summary
--
This PR includes the contributor-facing documentation for the new
categories, as well as updated
rule acceptance guidelines built atop them.
I think we could also update our rule request template based on some of
these guidelines, but I'll save that for a follow-up once these are
solidified.
Test Plan
--
Future rule requests
---------
Co-authored-by: Micha Reiser <micha@reiser.io>
## Summary
This PR introduces clippy-style rule categories that can be used
alongside existing linter-based categories in preview. The categories
have a lower `specificity` than linter groups, meaning that `select =
UP` and `ignore = correctness` will not ignore `UP` correctness rules.
In general this leads to more rules being enabled than the alternative
we considered where categories and linter groups had equal precedence,
which makes it seem like a safer default. We can revisit this if it
proves to be unintuitive, or we can add a Cargo-style `priority` field
in the worst case.
I've tried to organize the commits such that this can be reviewed
commit-by-commit and could also be split into multiple PRs. The first
two commits update the `ViolationMetadata` macro to allow providing a
`category` argument and add such arguments for all rules. This part
could be a standalone change without exposing the categories to users
but still depends on reaching consensus on all rule categories. The
second pair of commits allows using the new categories as selectors
alongside existing selectors, including some precedence tests with other
selector types.
This mostly addresses #1774, but there are some sub-issues there to
resolve before closing the issue.
## Test Plan
New CLI tests and a new mdtest suite around rule precedence