Commit Graph

2654 Commits

Author SHA1 Message Date
Hengky Kurniawan a802d7a0ea
[`fastapi`] Handle ellipsis defaults in FAST002 autofix (`FAST002`) (#20810)
## Summary

Implement handling of ellipsis (`...`) defaults in the `FAST002` autofix
to correctly differentiate between required and optional parameters in
FastAPI route definitions.

Previously, the autofix did not properly handle cases where parameters
used `...` as a default value (to indicate required parameters). This
could lead to incorrect transformations when applying the autofix.

This change updates the `FAST002` autofix logic to:
- Correctly recognize `...` as a valid FastAPI required default.
- Preserve the semantics of required parameters while still applying
other autofix improvements.
- Avoid incorrectly substituting or removing ellipsis defaults.

Fixes https://github.com/astral-sh/ruff/issues/20800

## Test Plan

Added a new test fixture at:
```crates/ruff_linter/resources/test/fixtures/fastapi/FAST002_2.py```
2025-10-21 02:47:13 +00:00
Takayuki Maeda 692b7d7f0c
[`ruff`] Skip autofix for keyword and `__debug__` path params (#20960)
<!--
Thank you for contributing to Ruff/ty! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title? (Please prefix
with `[ty]` for ty pull
  requests.)
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

Fixes #20941

Skip autofix for keyword and __debug__ path params

## Test Plan

<!-- How was it tested? -->

I added two test cases to
crates/ruff_linter/resources/test/fixtures/fastapi/FAST003.py.
2025-10-20 16:37:20 -07:00
Dylan d363d49ab7
[`flake8-bugbear`] Skip `B905` and `B912` if <2 iterables and no starred arguments (#20998)
Closes #20997

This will _decrease_ the number of diagnostics emitted for
[zip-without-explicit-strict
(B905)](https://docs.astral.sh/ruff/rules/zip-without-explicit-strict/#zip-without-explicit-strict-b905),
since previously it triggered on any `zip` call no matter the number of
arguments. It may _increase_ the number of diagnostics for
[map-without-explicit-strict
(B912)](https://docs.astral.sh/ruff/rules/map-without-explicit-strict/#map-without-explicit-strict-b912)
since it will now trigger on a single starred argument where before it
would not. However, the latter rule is in `preview` so this is
acceptable.

Note - we do not need to make any changes to
[batched-without-explicit-strict
(B911)](https://docs.astral.sh/ruff/rules/batched-without-explicit-strict/#batched-without-explicit-strict-b911)
since that just takes a single iterable.

I am doing this in one PR rather than two because we should keep the
behavior of these rules consistent with one another.

For review: apologies for the unreadability of the snapshot for `B905`.
Unfortunately I saw no way of keeping a small diff and a correct fixture
(the fixture labeled a whole block as `# Error` whereas now several in
the block became `# Ok`).Probably simplest to just view the actual
snapshot - it's relatively small.
2025-10-20 18:35:32 -05:00
Dylan 281ae8eb34
[`pyupgrade`] Always parenthesize assignment expressions in fix for `f-string` (`UP032`) (#21003)
Closes #21000
2025-10-20 18:34:02 -05:00
Robsdedude 511710e1ef
[`flake8-gettext`] Resolve qualified names and built-in bindings (`INT001`, `INT002`, `INT003`) (#19045)
## Summary
Make rules `INT001`, `INT002`, and `INT003` also 
* trigger on qualified names when we're sure the calls are calls to the
`gettext` module. For example
  ```python
  from gettext import gettext as foo
  
foo(f"{'bar'}") # very certain that this is a call to a real `gettext`
function => worth linting
  ```
* trigger on `builtins` bindings
  ```python
  from builtins, gettext
  
  gettext.install("...")  # binds `gettext.gettext` to `builtins._`
  builtins.__dict__["_"] = ...  # also a common pattern

  _(f"{'bar'}")  # should therefore also be linted
  ```

Fixes: https://github.com/astral-sh/ruff/issues/19028

## Test Plan

Tests have been added to all three rules.

---------

Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
2025-10-20 18:24:55 -04:00
Loïc Riegel c2ae9c7806
feat: 'ruff rule' provides more easily parsable JSON ouput (#20168) 2025-10-20 09:09:51 +02:00
Takayuki Maeda 48b50128eb
[`ruff`] Update schemars to v1 (#20942) 2025-10-20 08:59:52 +02:00
Takayuki Maeda b6b96d75eb
[`ruff`] Use DiagnosticTag for more pyflakes and panda rules (#20801) 2025-10-19 11:07:16 +02:00
Bhuminjay Soni 7198e53182
[syntax-errors] Alternative `match` patterns bind different names (#20682)
<!--
Thank you for contributing to Ruff/ty! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title? (Please prefix
with `[ty]` for ty pull
  requests.)
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->
This PR implements semantic syntax error where alternative patterns bind
different names

## Test Plan

<!-- How was it tested? -->
I have written inline tests as directed in #17412

---------

Signed-off-by: 11happy <soni5happy@gmail.com>
Co-authored-by: Brent Westbrook <brentrwestbrook@gmail.com>
2025-10-17 21:35:48 +00:00
Dylan 2bffef5966
Bump 0.14.1 (#20925) 2025-10-16 12:44:13 -05:00
Brent Westbrook e64d772788
Standardize syntax error construction (#20903)
Summary
--

This PR unifies the two different ways Ruff and ty construct syntax
errors. Ruff has been storing the primary message in the diagnostic
itself, while ty attached the message to the primary annotation:

```
> ruff check try.py
invalid-syntax: name capture `x` makes remaining patterns unreachable
 --> try.py:2:10
  |
1 | match 42:
2 |     case x: ...
  |          ^
3 |     case y: ...
  |

Found 1 error.
> uvx ty check try.py
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
Checking ------------------------------------------------------------ 1/1 files                                                                                                 
error[invalid-syntax]
 --> try.py:2:10
  |
1 | match 42:
2 |     case x: ...
  |          ^ name capture `x` makes remaining patterns unreachable
3 |     case y: ...
  |

Found 1 diagnostic
```

I think there are benefits to both approaches, and I do like ty's
version, but I feel like we should pick one (and it might help with
#20901 eventually). I slightly prefer Ruff's version, so I went with
that. Hopefully this isn't too controversial, but I'm happy to close
this if it is.

Note that this shouldn't change any other diagnostic formats in ty
because
[`Diagnostic::primary_message`](98d27c4128/crates/ruff_db/src/diagnostic/mod.rs (L177))
was already falling back to the primary annotation message if the
diagnostic message was empty. As a result, I think this change will
partially resolve the FIXME therein.

Test Plan
--

Existing tests with updated snapshots
2025-10-16 11:56:32 -04:00
Auguste Lalande 03696687ea
[`pydoclint`] Implement `docstring-extraneous-parameter` (`DOC102`) (#20376)
## Summary

Implement `docstring-extraneous-parameter` (`DOC102`). This rule checks
that all parameters present in a functions docstring are also present in
its signature.

Split from #13280, per this
[comment](https://github.com/astral-sh/ruff/pull/13280#issuecomment-3280575506).

Part of #12434.

## Test Plan

Test cases added.

---------

Co-authored-by: Brent Westbrook <brentrwestbrook@gmail.com>
2025-10-16 11:26:51 -04:00
Bhuminjay Soni 73520e4acd
[syntax-errors]: implement F702 as semantic syntax error (#20869)
<!--
Thank you for contributing to Ruff/ty! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title? (Please prefix
with `[ty]` for ty pull
  requests.)
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

This PR implements `F702`
https://docs.astral.sh/ruff/rules/continue-outside-loop/ as semantic
syntax error.

## Test Plan

<!-- How was it tested? -->
Tests are already previously written in F702

---------

Signed-off-by: 11happy <soni5happy@gmail.com>
2025-10-15 19:27:15 +00:00
Wei Lee d2a6ef7491
[`airflow`] Add warning to `airflow.datasets.DatasetEvent` usage (`AIR301`) (#20551)
<!--
Thank you for contributing to Ruff/ty! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title? (Please prefix
with `[ty]` for ty pull
  requests.)
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

`airflow.datasets.DatasetEvent` has been removed in 3 but `AssetEvent`
might be added in the future

## Test Plan

<!-- How was it tested? -->

update the test fixture and reorg in the second commit
2025-10-15 12:19:55 -04:00
Dan Parizher 98d27c4128
[`flake8-pyi`] Fix operator precedence by adding parentheses when needed (`PYI061`) (#20508)
## Summary

Fixes #20265

---------

Co-authored-by: Brent Westbrook <brentrwestbrook@gmail.com>
2025-10-15 15:06:03 +00:00
Dan Parizher c06c3f9505
[`pyupgrade`] Fix false negative for `TypeVar` with default argument in `non-pep695-generic-class` (`UP046`) (#20660)
## Summary

Fixes #20656

---------

Co-authored-by: Brent Westbrook <brentrwestbrook@gmail.com>
2025-10-15 14:51:55 +00:00
Micha Reiser 4fc7dd300c
Improved error recovery for unclosed strings (including f- and t-strings) (#20848) 2025-10-15 09:50:56 +02:00
Dan Parizher 9e1aafd0ce
[`pyupgrade`] Extend `UP019` to detect `typing_extensions.Text` (`UP019`) (#20825)
Co-authored-by: Micha Reiser <micha@reiser.io>
2025-10-15 06:52:14 +00:00
Dylan abf685b030
[`flake8-bugbear`] Omit annotation in preview fix for `B006` (#20877)
Closes #20864
2025-10-15 01:14:01 +00:00
Paillat e1e3eb7209
fix(docs): Fix typo in `RUF015` description (#20873)
## Summary
Fixed a typo. It should be "or", not "of". Both `.pop()` and `next()` on
an empty collection will raise `IndexError`, not "`[0]` of the `pop()`
function"

## Test Plan

n/a
2025-10-14 21:38:31 +00:00
Dan Parizher c69fa75cd5
Fix false negatives in `Truthiness::from_expr` for lambdas, generators, and f-strings (#20704) 2025-10-14 03:06:17 -05:00
Bhuminjay Soni 2b729b4d52
[syntax-errors]: break outside loop F701 (#20556)
<!--
Thank you for contributing to Ruff/ty! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title? (Please prefix
with `[ty]` for ty pull
  requests.)
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

This PR implements https://docs.astral.sh/ruff/rules/break-outside-loop/
(F701) as a semantic syntax error.

## Test Plan

<!-- How was it tested? -->

---------

Signed-off-by: 11happy <soni5happy@gmail.com>
Co-authored-by: Brent Westbrook <brentrwestbrook@gmail.com>
2025-10-13 20:00:59 +00:00
Brent Westbrook 975891fc90
Render unsupported syntax errors in formatter tests (#20777)
## Summary

Based on the suggestion in
https://github.com/astral-sh/ruff/issues/20774#issuecomment-3383153511,
I added rendering of unsupported syntax errors in our `format` test.

In support of this, I added a `DummyFileResolver` type to `ruff_db` to
pass to `DisplayDiagnostics::new` (first commit). Another option would
obviously be implementing this directly in the fixtures, but we'd have
to import a `NotebookIndex` somehow; either by depending directly on
`ruff_notebook` or re-exporting it from `ruff_db`. I thought it might be
convenient elsewhere to have a dummy resolver, for example in the
parser, where we currently have a separate rendering pipeline
[copied](https://github.com/astral-sh/ruff/blob/main/crates/ruff_python_parser/tests/fixtures.rs#L321)
from our old rendering code in `ruff_linter`. I also briefly tried
implementing a `TestDb` in the formatter since I noticed the
`ruff_python_formatter::db` module, but that was turning into a lot more
code than the dummy resolver.

We could also push this a bit further if we wanted. I didn't add the new
snapshots to the black compatibility tests or to the preview snapshots,
for example. I thought it was kind of noisy enough (and helpful enough)
already, though. We could also use a shorter diagnostic format, but the
full output seems most useful once we accept this initial large batch of
changes.

## Test Plan

I went through the baseline snapshots pretty quickly, but they all
looked reasonable to me, with one exception I noted below. I also tested
that the case from #20774 produces a new unsupported syntax error.
2025-10-13 10:00:37 -04:00
Takayuki Maeda f715d70be1
[`ruff`] Use DiagnosticTag for more flake8 and numpy rules (#20758) 2025-10-13 10:29:15 +02:00
ageorgou bbd3856de8
[`flake8-datetimez`] Clarify docs for several rules (#20778)
## Summary

Resolves #19384.

- Distinguishes more clearly between `date` and `datetime` objects.
- Uniformly links to the relevant Python docs from rules in this
category.

I've tried to be clearer, but there's still a contradiction in the rules
as written: we say "use timezone-aware objects", but `date`s are
inherently timezone-naive.

Also, the full docs don't always match the error message: for instance,
in [DTZ012](https://docs.astral.sh/ruff/rules/call-date-fromtimestamp/),
the example says to use:
```python
datetime.datetime.fromtimestamp(946684800, tz=datetime.UTC)
```
while `fix_title` returns "Use `datetime.datetime.fromtimestamp(ts,
tz=...)**.date()**` instead".
I have left this as it was for now.

## Test Plan
Ran `mkdocs` locally and inspected result.
2025-10-10 13:02:24 +00:00
pieterh-oai 66885e4bce
[`flake8-logging-format`] Avoid dropping implicitly concatenated pieces in the `G004` fix (#20793)
## Summary

The original autofix for G004 was quietly dropping everything but the
f-string components of any implicit concatenation sequence; this
addresses that.

Side note: It looks like `f_strings` is a bit risky to use (since it
implicitly skips non-f-string parts); use iter and include implicitly
concatenated pieces. We should consider if it's worth having
(convenience vs. bit risky).

## Test Plan

```
cargo test -p ruff_linter
```

Backtest (run new testcases against previous implementation):
```
git checkout HEAD^ crates/ruff_linter/src/rules/flake8_logging_format/rules/logging_call.rs
cargot test -p ruff_linter

```
2025-10-09 18:14:38 -04:00
Dan Parizher 537ec5f012
[`fastapi`] Fix false positives for path parameters that FastAPI doesn't recognize (`FAST003`) (#20687)
## Summary

Fixes #20680

---------

Co-authored-by: Brent Westbrook <brentrwestbrook@gmail.com>
2025-10-09 16:10:21 -04:00
Takayuki Maeda abbbe8f3af
[`ruff`] Use `DiagnosticTag` for more pyupgrade rules (#20734) 2025-10-08 06:52:43 +02:00
Dan Parizher 1bf4969c96
[`ruff`] Suppress diagnostic for f-string interpolations with debug text (`RUF010`) (#20525)
## Summary

Fixes #20519
2025-10-07 16:57:59 -04:00
liam 2be73e9afb
[`flake8-bugbear`] Mark `B905` and `B912` fixes as unsafe (#20695)
Resolves https://github.com/astral-sh/ruff/issues/20694

This PR updates the `zip_without_explicit_strict` and
`map_without_explicit_strict` rules so their fixes are always marked
unsafe, following Brent's guidance that adding `strict=False` can
silently preserve buggy behaviour when inputs differ. The fix safety
docs now spell out that reasoning, the applicability drops to `Unsafe`,
and the snapshots were refreshed so Ruff clearly warns users before
applying the edit.
2025-10-07 16:55:56 -04:00
Amethyst Reese beea8cdfec
Bump 0.14.0 (#20751) 2025-10-07 11:05:47 -07:00
Brent Westbrook 88c0ce3e38
Update default and latest Python versions for 3.14 (#20725)
Summary
--

Closes #19467 and also removes the warning about using Python 3.14
without
preview enabled.

I also bumped `PythonVersion::default` to 3.9 because it reaches EOL
this month,
but we could also defer that for now if we wanted.

The first three commits are related to the `latest` bump to 3.14; the
fourth commit
bumps the default to 3.10.

Note that this PR also bumps the default Python version for ty to 3.10
because
there was a test asserting that it stays in sync with
`ast::PythonVersion`.

Test Plan
--

Existing tests

I spot-checked the ecosystem report, and I believe these are all
expected. Inbits doesn't specify a target Python version, so I guess
we're applying the default. UP007, UP035, and UP045 all use the new
default value to emit new diagnostics.
2025-10-07 12:23:11 -04:00
chiri b66a3e7451
[`refurb`] Add fixes for `FURB101`, `FURB103` (#20520)
## Summary

Part of `PTH-*` fixes:
https://github.com/astral-sh/ruff/pull/19404#issuecomment-3089639686

## Test Plan
`cargo nextest run furb`
2025-10-06 18:09:07 -04:00
Dan Parizher 9a29f7a339
[`isort`] Fix inserting required imports before future imports (`I002`) (#20676)
## Summary

Fixes #20674

---------

Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
2025-10-06 13:40:36 +00:00
Nikolas Hearp 1c5666ce5d
[`RUF051`] Ignore if `else`/`elif` block is present (#20705)
## Summary

Fixes #20700

`else` and `elif` blocks could previously be deleted when applying a fix
for this rule. If an `else` or `elif` branch is detected the rule will
not trigger. So now the rule will only flag if it is safe.
2025-10-06 08:02:27 -05:00
Igor Drokin 673167a565
[`flake8-bugbear`] Include certain guaranteed-mutable expressions: tuples, generators, and assignment expressions (`B006`) (#20024)
## Summary
Resolves #20004

The implementation now supports guaranteed-mutable expressions in the
following cases:
- Tuple literals with mutable elements (supporting deep nesting)
- Generator expressions
- Named expressions (walrus operator) containing mutable components

Preserves original formatting for assignment value:

```python
# Test case
def f5(x=([1, ])):
    print(x)
```
```python
# Fix before
def f5(x=(None)):
    if x is None:
        x = [1]
    print(x)
```
```python
# Fix after 
def f5(x=None):
    if x is None:
        x = ([1, ])
    print(x)
```
The expansion of detected expressions and the new fixes gated behind
previews.

## Test Plan
- Added B006_9.py with a bunch of test cases
- Generated snapshots

---------

Co-authored-by: Igor Drokin <drokinii1017@gmail.com>
Co-authored-by: dylwil3 <dylwil3@gmail.com>
2025-10-03 09:29:36 -05:00
Dan Parizher 805d179dc0
[`flake8-comprehensions`] Clarify fix safety documentation (`C413`) (#20640)
## Summary

Fixes #20632
2025-10-03 09:23:57 -05:00
liam ebfb33c30b
[`ruff`] Extend FA102 with listed PEP 585-compatible APIs (#20659)
Resolves https://github.com/astral-sh/ruff/issues/20512

This PR expands FA102’s preview coverage to flag every
PEP 585-compatible API that breaks without from `from __future__ import
annotations`, including `collections.abc`. The rule now treats asyncio
futures, pathlib-style queues, weakref containers, shelve proxies, and
the full `collections.abc` family as generics once preview mode is
enabled.

Stable behavior is unchanged; the broader matching runs behind
`is_future_required_preview_generics_enabled`, letting us vet the new
diagnostics before marking them as stable.

I've also added a snapshot test that covers all of the newly supported
types.

Check out
https://docs.python.org/3/library/stdtypes.html#standard-generic-classes
for a list of commonly used PEP 585-compatible APIs.
2025-10-03 09:45:32 -04:00
Takayuki Maeda 542f080035
[`flynt`] Fix f-string quoting for mixed quote joiners (`FLY002`) (#20662)
<!--
Thank you for contributing to Ruff/ty! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title? (Please prefix
with `[ty]` for ty pull
  requests.)
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

Fixes #19837

Track quote usage across the joiner and parts to choose a safe f-string
quote or skip the fix when both appear.

## Test Plan

<!-- How was it tested? -->

Add regression coverage to FLY002.py
2025-10-03 09:15:57 -04:00
Dan Parizher f9688bd05c
[`flake8-annotations`] Fix return type annotations to handle shadowed builtin symbols (`ANN201`, `ANN202`, `ANN204`, `ANN205`, `ANN206`) (#20612)
## Summary

Fixes #20610

---------

Co-authored-by: Brent Westbrook <brentrwestbrook@gmail.com>
2025-10-02 22:44:06 +00:00
Dylan 188c0dce29
Bump 0.13.3 (#20685) 2025-10-02 14:14:05 -05:00
Dan Parizher caf48f4bfc
[`pylint`] Clarify fix safety to include left-hand hashability (`PLR6201`) (#20518)
## Summary

Fixes #20510
2025-10-01 13:58:24 -04:00
Igor Drokin 11dae2cf1b
[`pyupgrade`] Prevent infinite loop with `I002` and `UP026` (#20634)
## Summary
Closes #20601

Do not treat imports as unused for the rule [unnecessary-builtin-import
(UP029)](https://docs.astral.sh/ruff/rules/unnecessary-builtin-import/)
if they are required by
`isort`([missing-required-import](https://docs.astral.sh/ruff/rules/missing-required-import/))

## Test Plan
- Added test case `i002_up029_conflict` to ensure there is no conflict

Co-authored-by: Igor Drokin <drokinii1017@gmail.com>
2025-09-30 17:11:34 -04:00
Wei Lee 7fee877c50
[`airflow`]: rename `AutoImport` as `Rename` (internal) (#20563)
<!--
Thank you for contributing to Ruff/ty! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title? (Please prefix
with `[ty]` for ty pull
  requests.)
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

Since we are trying to import both `AutoImport` and `SourceModuleMoved`,
the previous naming was not as descriptive. Renaming it to `Rename`
better reflects the intention.

## Test Plan

<!-- How was it tested? -->

no functionality change
2025-09-30 15:56:26 -04:00
Dan Parizher 7c87b31533
[`ruff`] Do not flag `%r` + `repr()` combinations (`RUF065`) (#20600)
## Summary

Fixes the first part of #20583
2025-09-30 15:49:50 -04:00
Brent Westbrook 2b1d3c60fa
Display diffs for `ruff format --check` and add support for different output formats (#20443)
## Summary

This PR uses the new `Diagnostic` type for rendering formatter
diagnostics. This allows the formatter to inherit all of the output
formats already implemented in the linter and ty. For example, here's
the new `full` output format, with the formatting diff displayed using
the same infrastructure as the linter:

<img width="592" height="364" alt="image"
src="https://github.com/user-attachments/assets/6d09817d-3f27-4960-aa8b-41ba47fb4dc0"
/>


<details><summary>Resolved TODOs</summary>
<p>

~~There are several limitiations/todos here still, especially around the
`OutputFormat` type~~:
- [x] A few literal `todo!`s for the remaining `OutputFormat`s without
matching `DiagnosticFormat`s
- [x] The default output format is `full` instead of something more
concise like the current output
- [x] Some of the output formats (namely JSON) have information that
doesn't make much sense for these diagnostics

The first of these is definitely resolved, and I think the other two are
as well, based on discussion on the design document. In brief, we're
okay inheriting the default `OutputFormat` and can separate the global
option into `lint.output-format` and `format.output-format` in the
future, if needed; and we're okay including redundant information in the
non-human-readable output formats.

My last major concern is with the performance of the new code, as
discussed in the `Benchmarks` section below.

A smaller question is whether we should use `Diagnostic`s for formatting
errors too. I think the answer to this is yes, in line with changes
we're making in the linter too. I still need to implement that here.

</p>
</details> 

<details><summary>Benchmarks</summary>
<p>


The values in the table are from a large benchmark on the CPython 3.10
code
base, which involves checking 2011 files, 1872 of which need to be
reformatted.
`stable` corresponds to the same code used on `main`, while
`preview-full` and
`preview-concise` use the new `Diagnostic` code gated behind `--preview`
for the
`full` and `concise` output formats, respectively. `stable-diff` uses
the
`--diff` to compare the two diff rendering approaches. See the full
hyperfine
command below for more details. For a sense of scale, the `stable`
output format
produces 1873 lines on stdout, compared to 855,278 for `preview-full`
and
857,798 for `stable-diff`.

| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |

|:------------------|--------------:|---------:|---------:|-------------:|
| `stable` | 201.2 ± 6.8 | 192.9 | 220.6 | 1.00 |
| `preview-full` | 9113.2 ± 31.2 | 9076.1 | 9152.0 | 45.29 ± 1.54 |
| `preview-concise` | 214.2 ± 1.4 | 212.0 | 217.6 | 1.06 ± 0.04 |
| `stable-diff` | 3308.6 ± 20.2 | 3278.6 | 3341.8 | 16.44 ± 0.56 |

In summary, the `preview-concise` diagnostics are ~6% slower than the
stable
output format, increasing the average runtime from 201.2 ms to 214.2 ms.
The
`full` preview diagnostics are much more expensive, taking over 9113.2
ms to
complete, which is ~3x more expensive even than the stable diffs
produced by the
`--diff` flag.

My main takeaways here are:
1. Rendering `Edit`s is much more expensive than rendering the diffs
from `--diff`
2. Constructing `Edit`s actually isn't too bad

### Constructing `Edit`s

I also took a closer look at `Edit` construction by modifying the code
and
repeating the `preview-concise` benchmark and found that the main issue
is
constructing a `SourceFile` for use in the `Edit` rendering. Commenting
out the
`Edit` construction itself has basically no effect:

| Command   |   Mean [ms] | Min [ms] | Max [ms] |    Relative |
|:----------|------------:|---------:|---------:|------------:|
| `stable`  | 197.5 ± 1.6 |    195.0 |    200.3 |        1.00 |
| `no-edit` | 208.9 ± 2.2 |    204.8 |    212.2 | 1.06 ± 0.01 |

However, also omitting the source text from the `SourceFile`
construction
resolves the slowdown compared to `stable`. So it seems that copying the
full
source text into a `SourceFile` is the main cause of the slowdown for
non-`full`
diagnostics.

| Command          |   Mean [ms] | Min [ms] | Max [ms] |    Relative |
|:-----------------|------------:|---------:|---------:|------------:|
| `stable`         | 202.4 ± 2.9 |    197.6 |    207.9 |        1.00 |
| `no-source-text` | 202.7 ± 3.3 |    196.3 |    209.1 | 1.00 ± 0.02 |

### Rendering diffs

The main difference between `stable-diff` and `preview-full` seems to be
the diffing strategy we use from `similar`. Both versions use the same
algorithm, but in the existing
[`CodeDiff`](https://github.com/astral-sh/ruff/blob/main/crates/ruff_linter/src/source_kind.rs#L259)
rendering for the `--diff` flag, we only do line-level diffing, whereas
for `Diagnostic`s we use `TextDiff::iter_inline_changes` to highlight
word-level changes too. Skipping the word diff for `Diagnostic`s closes
most of the gap:

| Command | Mean [s] | Min [s] | Max [s] | Relative |
|:---|---:|---:|---:|---:|
| `stable-diff` | 3.323 ± 0.015 | 3.297 | 3.341 | 1.00 |
| `preview-full` | 3.654 ± 0.019 | 3.618 | 3.682 | 1.10 ± 0.01 |

(In some repeated runs, I've seen as small as a ~5% difference, down
from 10% in the table)

This doesn't actually change any of our snapshots, but it would
obviously change the rendered result in a terminal since we wouldn't
highlight the specific words that changed within a line.

Another much smaller change that we can try is removing the deadline
from the `iter_inline_changes` call. It looks like there's a fair amount
of overhead from the default 500 ms deadline for computing these, and
using `iter_inline_changes(op, None)` (`None` for the optional deadline
argument) improves the runtime quite a bit:

| Command | Mean [s] | Min [s] | Max [s] | Relative |
|:---|---:|---:|---:|---:|
| `stable-diff` | 3.322 ± 0.013 | 3.298 | 3.341 | 1.00 |
| `preview-full` | 5.296 ± 0.030 | 5.251 | 5.366 | 1.59 ± 0.01 |

<hr>

<details><summary>hyperfine command</summary>

```shell
cargo build --release --bin ruff && hyperfine --ignore-failure --warmup 10 --export-markdown /tmp/table.md \
  -n stable -n preview-full -n preview-concise -n stable-diff \
  "./target/release/ruff format --check ./crates/ruff_linter/resources/test/cpython/ --no-cache" \
  "./target/release/ruff format --check ./crates/ruff_linter/resources/test/cpython/ --no-cache --preview --output-format=full" \
  "./target/release/ruff format --check ./crates/ruff_linter/resources/test/cpython/ --no-cache --preview --output-format=concise" \
  "./target/release/ruff format --check ./crates/ruff_linter/resources/test/cpython/ --no-cache --diff"
```

</details>

</p>
</details> 

## Test Plan

Some new CLI tests and manual testing
2025-09-30 12:00:51 -04:00
Brent Westbrook 00c8851ef8
Remove `TextEmitter` (#20595)
## Summary

Addresses
https://github.com/astral-sh/ruff/pull/20443#discussion_r2381237640 by
factoring out the `match` on the ruff output format in a way that should
be reusable by the formatter.

I didn't think this was going to work at first, but the fact that the
config holds options that apply only to certain output formats works in
our favor here. We can set up a single config for all of the output
formats and then use `try_from` to convert the `OutputFormat` to a
`DiagnosticFormat` later.

## Test Plan

Existing tests, plus a few new ones to make sure relocating the
`SHOW_FIX_SUMMARY` rendering worked, that was untested before. I deleted
a bunch of test code along with the `text` module, but I believe all of
it is now well-covered by the `full` and `concise` tests in `ruff_db`.

I also merged this branch into
https://github.com/astral-sh/ruff/pull/20443 locally and made sure that
the API actually helps. `render_diagnostics` dropped in perfectly and
passed the tests there too.
2025-09-29 08:46:25 -04:00
Takayuki Maeda 666f53331f
[`ruff`] Fix minor typos in doc comments (#20623) 2025-09-29 08:56:23 +02:00
Rahul Sahoo 4e33501115
Fixed documentation for try_consider_else (#20587)
<!--
Thank you for contributing to Ruff/ty! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title? (Please prefix
with `[ty]` for ty pull
  requests.)
- Does this pull request include references to any relevant issues?
-->

## Summary

This PR addresses #20570 . In the example, the correct usage had a
bug/issue where in the except block after logging exception, None was
getting returned, which made the linters flag out the code. So adding an
empty raise solves the issue.

## Test Plan

Tested it by building the doc locally.
2025-09-27 13:50:51 +00:00
Dylan 57e1ff8294
[`pyflakes`] Handle some common submodule import situations for `unused-import` (`F401`) (#20200)
# Summary

The PR under review attempts to make progress towards the age-old
problem of submodule imports, specifically with regards to their
treatment by the rule [`unused-import`
(`F401`)](https://docs.astral.sh/ruff/rules/unused-import/).

Some related issues:
- https://github.com/astral-sh/ruff/issues/60
- https://github.com/astral-sh/ruff/issues/4656

Prior art:
- https://github.com/astral-sh/ruff/pull/13965
- https://github.com/astral-sh/ruff/pull/5010
- https://github.com/astral-sh/ruff/pull/5011
- https://github.com/astral-sh/ruff/pull/666

See the PR summary for a detailed description.
2025-09-26 08:22:26 -05:00