Commit Graph

2159 Commits

Author SHA1 Message Date
Wei Lee a507c1b8b3
[`airflow`] Remove `airflow.utils.dag_parsing_context.get_parsing_context` (`AIR301`) (#17852)
<!--
Thank you for contributing to Ruff! 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?
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->
Remove `airflow.utils.dag_parsing_context.get_parsing_context` from
AIR301 as it has been moved to AIR311

## Test Plan

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

the test fixture was updated in the previous PR
2025-05-05 09:31:57 -04:00
Dylan a95c73d5d0
Implement deferred annotations for Python 3.14 (#17658)
This PR updates the semantic model for Python 3.14 by essentially
equating "run using Python 3.14" with "uses `from __future__ import
annotations`".

While this is not technically correct under the hood, it appears to be
correct for the purposes of our semantic model. That is: from the point
of view of deciding when to parse, bind, etc. annotations, these two
contexts behave the same. More generally these contexts behave the same
unless you are performing some kind of introspection like the following:


Without future import:
```pycon
>>> from annotationlib import get_annotations,Format
>>> def foo()->Bar:...
...
>>> get_annotations(foo,format=Format.FORWARDREF)
{'return': ForwardRef('Bar')}
>>> get_annotations(foo,format=Format.STRING)
{'return': 'Bar'}
>>> get_annotations(foo,format=Format.VALUE)
Traceback (most recent call last):
[...]
NameError: name 'Bar' is not defined
>>> get_annotations(foo)
Traceback (most recent call last):
[...]
NameError: name 'Bar' is not defined
```

With future import:
```
>>> from __future__ import annotations
>>> from annotationlib import get_annotations,Format
>>> def foo()->Bar:...
...
>>> get_annotations(foo,format=Format.FORWARDREF)
{'return': 'Bar'}
>>> get_annotations(foo,format=Format.STRING)
{'return': 'Bar'}
>>> get_annotations(foo,format=Format.VALUE)
{'return': 'Bar'}
>>> get_annotations(foo)
{'return': 'Bar'}
```

(Note: the result of the last call to `get_annotations` in these
examples relies on the fact that, as of this writing, the default value
for `format` is `Format.VALUE`).

If one day we support lint rules targeting code that introspects using
the new `annotationlib`, then it is possible we will need to revisit our
approximation.

Closes #15100
2025-05-05 06:40:36 -05:00
Micha Reiser fa628018b2
Use `#[expect(lint)]` over `#[allow(lint)]` where possible (#17822) 2025-05-03 21:20:31 +02:00
Micha Reiser b51c4f82ea
Rename Red Knot (#17820) 2025-05-03 19:49:15 +02:00
Victor Hugo Gomes 097af060c9
[`refurb`] Fix false positive for float and complex numbers in `FURB116` (#17661) 2025-05-03 15:59:46 +02:00
Micha Reiser 17050e2ec5
doc: Add link to `check-typed-exception` from `S110` and `S112` (#17786) 2025-05-02 09:25:58 +02:00
Micha Reiser a6dc04f96e
Fix module name in ASYNC110, 115, and 116 fixes (#17774) 2025-05-01 23:37:09 +02:00
Brent Westbrook 75effb8ed7
Bump 0.11.8 (#17766) 2025-05-01 10:19:58 -04:00
Victor Hugo Gomes 3353d07938
[`flake8-use-pathlib`] Fix `PTH104`false positive when `rename` is passed a file descriptor (#17712)
## Summary
Contains the same changes to the semantic type inference as
https://github.com/astral-sh/ruff/pull/17705.

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

## Test Plan

<!-- How was it tested? -->
Snapshot tests.

---------

Co-authored-by: Dhruv Manilawala <dhruvmanila@gmail.com>
Co-authored-by: Brent Westbrook <brentrwestbrook@gmail.com>
2025-05-01 10:01:17 -04:00
Victor Hugo Gomes 67ef370733
[`flake8-use-pathlib`] Fix `PTH116` false positive when `stat` is passed a file descriptor (#17709)
Co-authored-by: Dhruv Manilawala <dhruvmanila@gmail.com>
2025-05-01 08:16:28 +02:00
Wei Lee 6e765b4527
[`airflow`] apply Replacement::AutoImport to `AIR312` (#17570)
## Summary

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

This is not yet fixing anything as the names are not changed, but it
lays down the foundation for fixing.

## Test Plan

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

the existing test fixture should already cover this change
2025-04-30 15:53:10 -04:00
Vasco Schiavo c5e41c278c
[`ruff`] Add fix safety section (`RUF028`) (#17722)
The PR add the fix safety section for rule `RUF028`
(https://github.com/astral-sh/ruff/issues/15584 )

See also
[here](https://github.com/astral-sh/ruff/issues/15584#issuecomment-2820424485)
for the reason behind the _unsafe_ of the fix.
2025-04-30 15:06:25 -04:00
Hans 0e85cbdd91
[`flake8-use-pathlib`] Avoid suggesting `Path.iterdir()` for `os.listdir` with file descriptor (`PTH208`) (#17715)
## Summary

Fixes: #17695

---------

Co-authored-by: Dhruv Manilawala <dhruvmanila@gmail.com>
2025-04-30 20:08:57 +05:30
Max Mynter f584b66824
Expand Semantic Syntax Coverage (#17725)
Re: #17526 

## Summary
Adds tests to red knot and `linter.rs` for the semantic syntax. 

Specifically add tests for `ReboundComprehensionVariable`,
`DuplicateTypeParameter`, and `MultipleCaseAssignment`.

Refactor the `test_async_comprehension_in_sync_comprehension` →
`test_semantic_error` to be more general for all semantic syntax test
cases.

## Test Plan
This is a test.

## Question
I'm happy to contribute more tests the coming days. 

Should that happen here or should we merge this PR such that the
refactor `test_async_comprehension_in_sync_comprehension` →
`test_semantic_error` is available on main and others can chime in, too?
2025-04-30 10:14:08 -04:00
Victor Hugo Gomes 8c68d30c3a
[`flake8-use-pathlib`] Fix `PTH123` false positive when `open` is passed a file descriptor from a function call (#17705)
## Summary
Includes minor changes to the semantic type inference to help detect the
return type of function call.

Fixes #17691

## Test Plan

Snapshot tests
2025-04-29 16:51:38 -04:00
Hans 7d46579808
[docs] fix duplicated 'are' in comment for PTH123 rule (#17714) 2025-04-29 17:58:39 +02:00
Vasco Schiavo 5096824793
[`ruff`] add fix safety section (`RUF017`) (#17480)
The PR add the `fix safety` section for rule `RUF017` (#15584 )
2025-04-28 22:07:22 +00:00
Dylan ae7691b026
Add Python 3.14 to configuration options (#17647)
A small PR that just updates the various settings/configurations to
allow Python 3.14. At the moment selecting that target version will
have no impact compared to Python 3.13 - except that a warning
is emitted if the user does so with `preview` disabled.
2025-04-28 16:29:00 -05:00
Wei Lee 504fa20057
[`airflow`] Apply auto fixes to cases where the names have changed in Airflow 3 (`AIR302`) (#17553)
## Summary

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

Apply auto fixes to cases where the names have changed in Airflow 3 in
AIR302 and split the huge test cases into different test cases based on
proivder

## Test Plan

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

the test cases has been split into multiple for easier checking
2025-04-28 16:35:17 -04:00
Brent Westbrook 01a31c08f5
Add config option to disable `typing_extensions` imports (#17611)
Summary
--

This PR resolves https://github.com/astral-sh/ruff/issues/9761 by adding
a linter configuration option to disable
`typing_extensions` imports. As mentioned [here], it would be ideal if
we could
detect whether or not `typing_extensions` is available as a dependency
automatically, but this seems like a much easier fix in the meantime.

The default for the new option, `typing-extensions`, is `true`,
preserving the current behavior. Setting it to `false` will bail out of
the new
`Checker::typing_importer` method, which has been refactored from the 
`Checker::import_from_typing` method in
https://github.com/astral-sh/ruff/pull/17340),
with `None`, which is then handled specially by each rule that calls it.

I considered some alternatives to a config option, such as checking if
`typing_extensions` has been imported or checking for a `TYPE_CHECKING`
block we could use, but I think defaulting to allowing
`typing_extensions` imports and allowing the user to disable this with
an option is both simple to implement and pretty intuitive.

[here]:
https://github.com/astral-sh/ruff/issues/9761#issuecomment-2790492853

Test Plan
--

New linter tests exercising several combinations of Python versions and
the new config option for PYI019. I also added tests for the other
affected rules, but only in the case where the new config option is
enabled. The rules' existing tests also cover the default case.
2025-04-28 14:57:36 -04:00
Dylan 1e8881f9af
[`refurb`] Mark fix as safe for `readlines-in-for` (`FURB129`) (#17644)
This PR promotes the fix applicability of [readlines-in-for
(FURB129)](https://docs.astral.sh/ruff/rules/readlines-in-for/#readlines-in-for-furb129)
to always safe.

In the original PR (https://github.com/astral-sh/ruff/pull/9880), the
author marked the rule as unsafe because Ruff's type inference couldn't
quite guarantee that we had an `IOBase` object in hand. Some false
positives were recorded in the test fixture. However, before the PR was
merged, Charlie added the necessary type inference and the false
positives went away.

According to the [Python
documentation](https://docs.python.org/3/library/io.html#io.IOBase), I
believe this fix is safe for any proper implementation of `IOBase`:

>[IOBase](https://docs.python.org/3/library/io.html#io.IOBase) (and its
subclasses) supports the iterator protocol, meaning that an
[IOBase](https://docs.python.org/3/library/io.html#io.IOBase) object can
be iterated over yielding the lines in a stream. Lines are defined
slightly differently depending on whether the stream is a binary stream
(yielding bytes), or a text stream (yielding character strings). See
[readline()](https://docs.python.org/3/library/io.html#io.IOBase.readline)
below.

and then in the [documentation for
`readlines`](https://docs.python.org/3/library/io.html#io.IOBase.readlines):

>Read and return a list of lines from the stream. hint can be specified
to control the number of lines read: no more lines will be read if the
total size (in bytes/characters) of all lines so far exceeds hint. [...]
>Note that it’s already possible to iterate on file objects using for
line in file: ... without calling file.readlines().

I believe that a careful reading of our [versioning
policy](https://docs.astral.sh/ruff/versioning/#version-changes)
requires that this change be deferred to a minor release - but please
correct me if I'm wrong!
2025-04-28 09:39:55 -05:00
Dylan 152a0b6585
Collect preview lint behaviors in separate module (#17646)
This PR collects all behavior gated under preview into a new module
`ruff_linter::preview` that exposes functions like
`is_my_new_feature_enabled` - just as is done in the formatter crate.
2025-04-28 09:12:24 -05:00
Victor Hugo Gomes ceb2bf1168
[`flake8-pyi`] Ensure `Literal[None,] | Literal[None,]` is not autofixed to `None | None` (`PYI061`) (#17659)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2025-04-28 12:23:29 +01:00
Victor Hugo Gomes 826b2c9ff3
[`pycodestyle`] Fix duplicated diagnostic in `E712` (#17651) 2025-04-28 08:31:16 +01:00
jie211 a3e55cfd8f
[airflow] fix typos `AIR312` (#17673) 2025-04-28 08:31:41 +02:00
Micha Reiser 1c65e0ad25
Split `SourceLocation` into `LineColumn` and `SourceLocation` (#17587) 2025-04-27 11:27:33 +01:00
Vasco Schiavo b0d475f353
[`ruff`] add fix safety section (`RUF027`) (#17485)
The PR add the `fix safety` section for rule `RUF027` (#15584 ).

Actually, I have an example of a false positive. Should I include it in
the` fix safety` section?

---------

Co-authored-by: Dylan <dylwil3@gmail.com>
2025-04-26 16:43:53 -05:00
Vasco Schiavo b578a828ef
[`ruff`] add fix safety section (`RUF005`) (#17484)
The PR add the `fix safety` section for rule `RUF005` (#15584 ).

---------

Co-authored-by: Dylan <dylwil3@gmail.com>
2025-04-26 16:43:02 -05:00
Vasco Schiavo 64ba39a385
[`flynt`] add fix safety section (`FLY002`) (#17496)
The PR add the fix safety section for rule `FLY002` (#15584 )

The motivation for the content of the fix safety section is given by the
following example

```python
foo = 1
bar = [2, 3]

try:
    result_join = " ".join((foo, bar))
    print(f"Join result: {result_join}")
except TypeError as e:
    print(f"Join error: {e}")
```

which print `Join error: sequence item 0: expected str instance, int
found`

But after the fix is applied, we have

```python
foo = 1
bar = [2, 3]

try:
    result_join = f"{foo} {bar}"
    print(f"Join result: {result_join}")
except TypeError as e:
    print(f"Join error: {e}")
```

which print `Join result: 1 [2, 3]`

---------

Co-authored-by: dylwil3 <dylwil3@gmail.com>
2025-04-26 16:00:01 +00:00
Hans a4e225ee8a
[`flake8-async`] Add fix safety section (`ASYNC116`) (#17497)
## Summary

This PR add the `fix safety` section for rule `ASYNC116` in
`long_sleep_not_forever.rs` for #15584

---------

Co-authored-by: dylwil3 <dylwil3@gmail.com>
2025-04-26 10:40:51 -05:00
Vasco Schiavo 45d0634b01
[`pydocstyle`] add fix safety section (`D200`) (#17502)
The PR add the fix safety section for rule `D200` (#15584 )
2025-04-26 08:59:05 -05:00
Vasco Schiavo 4bcf1778fa
[`ruff`] add fix safety section (`RUF057`) (#17483)
The PR add the `fix safety` section for rule `RUF057` (#15584 )
2025-04-26 06:58:52 -05:00
Wei Lee aba21a5d47
[`airflow`] Extend `AIR301` rule (#17598)
## Summary

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

Add "airflow.operators.python.get_current_context" →
"airflow.sdk.get_current_context" rule

## Test Plan

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

the test fixture has been updated accordingly
2025-04-25 12:49:32 -04:00
Wei Lee b6281a8805
[`airflow`] update existing `AIR302` rules with better suggestions (#17542)
## Summary

Even though the original suggestion works, they've been removed in later
version and is no longer the best practices.

e.g., many sql realted operators have been removed and are now suggested
to use SQLExecuteQueryOperator instead

## Test Plan

The existing test fixtures have been updated
2025-04-25 12:44:28 -04:00
Brent Westbrook 6d3b1d13d6
[`pylint`] Detect `global` declarations in module scope (`PLE0118`) (#17411)
Summary
--

While going through the syntax errors in [this comment], I was surprised
to see the error `name 'x' is assigned to before global declaration`,
which corresponds to [load-before-global-declaration (PLE0118)] and has
also been reimplemented as a syntax error (#17135). However, it looks
like neither of the implementations consider `global` declarations in
the top-level module scope, which is a syntax error in CPython:

```python
# try.py
x = None
global x
```

```shell
> python -m compileall -f try.py
Compiling 'try.py'...
***   File "try.py", line 2
    global x
    ^^^^^^^^
SyntaxError: name 'x' is assigned to before global declaration
```

I'm not sure this is the best or most elegant solution, but it was a
quick fix that passed all of our tests.

Test Plan
--

New PLE0118 test case.

[this comment]:
https://github.com/astral-sh/ruff/issues/7633#issuecomment-1740424031
[load-before-global-declaration (PLE0118)]:
https://docs.astral.sh/ruff/rules/load-before-global-declaration/#load-before-global-declaration-ple0118
2025-04-25 08:37:16 -04:00
Max Mynter 3f84e75e20
Add Semantic Error Test for LateFutureImport (#17612)
Adresses a question in #17526.

## Summary
Adds a syntax error test for `__future__` import not at top of file. 

## Question: 
Is this a redundant with
8d2c79276d/crates/ruff_linter/resources/test/fixtures/pyflakes/F404_0.py (L1-L8)
and
8d2c79276d/crates/ruff_linter/resources/test/fixtures/pyflakes/F404_1.py (L1-L5)

which test pyflake `F404`?
<!-- What's the purpose of the change? What does it do, and why? -->

## Test Plan
This is a test
<!-- How was it tested? -->
2025-04-25 08:32:57 -04:00
Vasco Schiavo 4eecc40110
[`semantic-syntax-errors`] test for `LoadBeforeGlobalDeclaration` - ruff linter (#17592)
Hey @ntBre 

just one easy case to see if I understood the issue #17526 

Let me know if is this what you had in mind.
2025-04-24 16:14:33 -04:00
Abhijeet Prasad Bodas cf59cee928
[syntax-errors] `nonlocal` declaration at module level (#17559)
## Summary

Part of #17412

Add a new compile-time syntax error for detecting `nonlocal`
declarations at a module level.

## Test Plan

- Added new inline tests for the syntax error
- Updated existing tests for `nonlocal` statement parsing to be inside a
function scope

Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
2025-04-24 16:11:46 -04:00
Wei Lee 538393d1f3
[`airflow`] Apply auto fix to cases where name has been changed in Airflow 3 (`AIR311`) (#17571)
## Summary

Apply auto fix to cases where the name has been changed in Airflow 3
(`AIR311`)

## Test Plan

The test features has been updated
2025-04-24 15:48:54 -04:00
Brent Westbrook 92ecfc908b
[syntax-errors] Make `async-comprehension-in-sync-comprehension` more specific (#17460)
## Summary

While adding semantic error support to red-knot, I noticed duplicate
diagnostics for code like this:

```py
# error: [invalid-syntax] "cannot use an asynchronous comprehension outside of an asynchronous function on Python 3.9 (syntax was added in 3.11)"
# error: [invalid-syntax] "`asynchronous comprehension` outside of an asynchronous function"
 [reveal_type(x) async for x in AsyncIterable()]
```

Beyond the duplication, the first error message doesn't make much sense
because this syntax is _not_ allowed on Python 3.11 either.

To fix this, this PR renames the
`async-comprehension-outside-async-function` semantic syntax error to
`async-comprehension-in-sync-comprehension` and fixes the rule to avoid
applying outside of sync comprehensions at all.

## Test Plan

New linter test demonstrating the false positive. The mdtests from my red-knot 
PR also reflect this change.
2025-04-24 15:45:54 -04:00
Dylan f7b48510b5
Bump 0.11.7 (#17613) 2025-04-24 13:06:38 -05:00
Max Mynter a01f25107a
[`pyupgrade`] Preserve parenthesis when fixing native literals containing newlines (`UP018`) (#17220) 2025-04-24 08:48:02 +02:00
camper42 48a85c4ed4
[`airflow`] fix typos (`AIR302`, `AIR312`) (#17574) 2025-04-24 08:06:32 +02:00
Brent Westbrook d5410ef9fe
[syntax-errors] Make duplicate parameter names a semantic error (#17131)
Status
--

This is a pretty minor change, but it was breaking a red-knot mdtest
until #17463 landed. Now this should close #11934 as the last syntax
error being tracked there!

Summary
--

Moves `Parser::validate_parameters` to
`SemanticSyntaxChecker::duplicate_parameter_name`.

Test Plan
--

Existing tests, with `## Errors` replaced with `## Semantic Syntax
Errors`.
2025-04-23 15:45:51 -04:00
Wei Lee b537552927
[`airflow`] Apply auto fixes to cases where the names have changed in Airflow 3 (`AIR301`) (#17355)
## Summary

Apply auto fixes to cases where the names have changed in Airflow 3

## Test Plan

Add `AIR301_names_fix.py` and `AIR301_provider_names_fix.py` test fixtures
2025-04-23 12:43:41 -04:00
Navdeep K 5a719f2d60
[`pycodestyle`] Auto-fix redundant boolean comparison (`E712`) (#17090)
This pull request fixes https://github.com/astral-sh/ruff/issues/17014

changes this
```python
from __future__ import annotations

flag1 = True
flag2 = True

if flag1 == True or flag2 == True:
    pass

if flag1 == False and flag2 == False:
    pass

flag3 = True
if flag1 == flag3 and (flag2 == False or flag3 == True):  # Should become: if flag1==flag3 and (not flag2 or flag3)
    pass

if flag1 == True and (flag2 == False or not flag3 == True):  # Should become: if flag1 and (not flag2 or not flag3)
    pass

if flag1 != True and (flag2 != False or not flag3 == True):  # Should become: if not flag1 and (flag2 or not flag3)
    pass


flag = True
while flag == True:  # Should become: while flag
    flag = False

flag = True
x = 5
if flag == True and x > 0:  # Should become: if flag and x > 0
    print("ok")

flag = True
result = "yes" if flag == True else "no"  # Should become: result = "yes" if flag else "no"

x = flag == True < 5

x = (flag == True) == False < 5
```

to this 
```python
from __future__ import annotations

flag1 = True
flag2 = True

if flag1 or flag2:
    pass

if not flag1 and not flag2:
    pass

flag3 = True
if flag1 == flag3 and (not flag2 or flag3):  # Should become: if flag1 == flag3 and (not flag2 or flag3)
    pass

if flag1 and (not flag2 or not flag3):  # Should become: if flag1 and (not flag2 or not flag3)
    pass

if not flag1 and (flag2 or not flag3):  # Should become: if not flag1 and (flag2 or not flag3)
    pass


flag = True
while flag:  # Should become: while flag
    flag = False

flag = True
x = 5
if flag and x > 0:  # Should become: if flag and x > 0
    print("ok")

flag = True
result = "yes" if flag else "no"  # Should become: result = "yes" if flag else "no"

x = flag is True < 5

x = (flag) is False < 5
```

---------

Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
2025-04-23 11:49:20 -04:00
Brent Westbrook e7f38fe74b
[red-knot] Detect semantic syntax errors (#17463)
Summary
--

This PR extends semantic syntax error detection to red-knot. The main
changes here are:

1. Adding `SemanticSyntaxChecker` and `Vec<SemanticSyntaxError>` fields
to the `SemanticIndexBuilder`
2. Calling `SemanticSyntaxChecker::visit_stmt` and `visit_expr` in the
`SemanticIndexBuilder`'s `visit_stmt` and `visit_expr` methods
3. Implementing `SemanticSyntaxContext` for `SemanticIndexBuilder`
4. Adding new mdtests to test the context implementation and show
diagnostics

(3) is definitely the trickiest and required (I think) a minor addition
to the `SemanticIndexBuilder`. I tried to look around for existing code
performing the necessary checks, but I definitely could have missed
something or misused the existing code even when I found it.

There's still one TODO around `global` statement handling. I don't think
there's an existing way to look this up, but I'm happy to work on that
here or in a separate PR. This currently only affects detection of one
error (`LoadBeforeGlobalDeclaration` or
[PLE0118](https://docs.astral.sh/ruff/rules/load-before-global-declaration/)
in ruff), so it's not too big of a problem even if we leave the TODO.

Test Plan
--

New mdtests, as well as new errors for existing mdtests

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2025-04-23 09:52:58 -04:00
David Salvisberg f36262d970
Fixes how the checker visits `typing.cast`/`typing.NewType` arguments (#17538) 2025-04-23 09:26:00 +02:00
Hans 21561000b1
[`pyupgrade`] Add fix safety section to docs (`UP030`) (#17443)
## Summary

add fix safety section to format_literals, for #15584
2025-04-21 14:14:58 -04:00
w0nder1ng 9c0772d8f0
[`perflint`] Allow list function calls to be replaced with a comprehension (`PERF401`) (#17519)
This is an implementation of the discussion from #16719. 

This change will allow list function calls to be replaced with
comprehensions:

```python
result = list()
for i in range(3):
    result.append(i + 1)
# becomes
result = [i + 1 for i in range(3)]
```

I added a new test to `PERF401.py` to verify that this fix will now work
for `list()`.
2025-04-21 13:29:24 -04:00
Hans fd3fc34a9e
[`pyflakes`] Add fix safety section to docs (`F601`, `F602`) (#17440)
## Summary

add fix safety section to repeated_keys_docs, for #15584

---------

Co-authored-by: Brent Westbrook <brentrwestbrook@gmail.com>
2025-04-18 18:27:40 +00:00
Hans c550b4d565
[`pyupgrade`] Add fix safety section to docs (`UP008`, `UP022`) (#17441)
## Summary

add fix safety section to replace_stdout_stderr and
super_call_with_parameters, for #15584
I checked the behavior and found that these two files could only
potentially delete the appended comments, so I submitted them as a PR.
2025-04-18 13:48:13 -04:00
Vasco Schiavo f8061e8b99
[`refurb`] Mark the `FURB161` fix unsafe except for integers and booleans (#17240)
The PR fixes #16457 .

Specifically, `FURB161` is marked safe, but the rule generates safe
fixes only in specific cases. Therefore, we attempt to mark the fix as
unsafe when we are not in one of these cases.

For instances, the fix is marked as aunsafe just in case of strings (as
pointed out in the issue). Let me know if I should change something.

---------

Co-authored-by: Brent Westbrook <brentrwestbrook@gmail.com>
2025-04-18 13:46:01 -04:00
w0nder1ng 08221454f6
[`perflint`] Implement fix for `manual-dict-comprehension` (`PERF403`) (#16719)
## Summary

This change adds an auto-fix for manual dict comprehensions. It also
copies many of the improvements from #13919 (and associated PRs fixing
issues with it), and moves some of the utility functions from
`manual_list_comprehension.rs` into a separate `helpers.rs` to be used
in both.

## Test Plan

I added a preview test case to showcase the new fix and added a test
case in `PERF403.py` to make sure lines with semicolons function. I
didn't yet make similar tests to the ones I added earlier to
`PERF401.py`, but the logic is the same, so it might be good to add
those to make sure they work.
2025-04-18 13:10:40 -04:00
Vasco Schiavo 5fec1039ed
[`pylint`] Make fix unsafe if it deletes comments (`PLR1730`) (#17459)
The PR addresses issue #17311

---------

Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
2025-04-18 12:49:01 -04:00
Hans c7372d218d
[`pyupgrade`] Add fix safety section to docs (`UP036`) (#17444)
## Summary

add fix safety section to outdated_version_block, for #15584
2025-04-17 22:45:53 -04:00
Hans d2ebfd6ed7
[`pyflakes`] Add fix safety section (`F841`) (#17410)
add fix safety section to docs for #15584, I'm new to ruff and not sure
if the content of this PR is correct, but I hope it can be helpful.

---------

Co-authored-by: Brent Westbrook <brentrwestbrook@gmail.com>
2025-04-17 09:58:26 -04:00
Brent Westbrook fcd50a0496
Bump 0.11.6 (#17449) 2025-04-17 09:20:29 -04:00
Wei Lee 1a79722ee0
[`airflow`] Extend `AIR311` rules (#17422)
<!--
Thank you for contributing to Ruff! 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?
- Does this pull request include references to any relevant issues?
-->

## Summary

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

* Extend the following AIR311 rules
* `airflow.io.path.ObjectStoragePath` → `airflow.sdk.ObjectStoragePath`
    * `airflow.io.storage.attach` → `airflow.sdk.io.attach`
    * `airflow.models.dag.DAG` → `airflow.sdk.DAG`
    * `airflow.models.DAG` → `airflow.sdk.DAG`
    * `airflow.decorators.dag` → `airflow.sdk.dag`
    * `airflow.decorators.task` → `airflow.sdk.task`
    * `airflow.decorators.task_group` → `airflow.sdk.task_group`
    * `airflow.decorators.setup` → `airflow.sdk.setup`
    * `airflow.decorators.teardown` → `airflow.sdk.teardown`

## Test Plan

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

The test case has been added to the button of the existing test
fixtures, confirmed to be correct and later reorgnaized
2025-04-16 12:40:15 -04:00
Wei Lee e6a2de3ac6
[`airflow`] Extract `AIR311` from `AIR301` rules (`AIR301`, `AIR311`) (#17310)
<!--
Thank you for contributing to Ruff! 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?
- Does this pull request include references to any relevant issues?
-->

## Summary

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

As discussed in
https://github.com/astral-sh/ruff/issues/14626#issuecomment-2766146129,
we're to separate suggested changes from required changes.

The following symbols have been moved to AIR311 from AIR301. They still
work in Airflow 3.0, but they're suggested to be changed as they're
expected to be removed in a future version.

* arguments
    * `airflow..DAG | dag`
        * `sla_miss_callback`
    * operators
        * `sla`
* name
* `airflow.Dataset] | [airflow.datasets.Dataset` → `airflow.sdk.Asset`
    * `airflow.datasets, rest @ ..`
        * `DatasetAlias` → `airflow.sdk.AssetAlias`
        * `DatasetAll` → `airflow.sdk.AssetAll`
        * `DatasetAny` → `airflow.sdk.AssetAny`
* `expand_alias_to_datasets` → `airflow.sdk.expand_alias_to_assets`
        * `metadata.Metadata` → `airflow.sdk.Metadata`
    <!--airflow.models.baseoperator-->
    * `airflow.models.baseoperator.chain` → `airflow.sdk.chain`
* `airflow.models.baseoperator.chain_linear` →
`airflow.sdk.chain_linear`
* `airflow.models.baseoperator.cross_downstream` →
`airflow.sdk.cross_downstream`
* `airflow.models.baseoperatorlink.BaseOperatorLink` →
`airflow.sdk.definitions.baseoperatorlink.BaseOperatorLink`
    * `airflow.timetables, rest @ ..`
* `datasets.DatasetOrTimeSchedule` → *
`airflow.timetables.assets.AssetOrTimeSchedule`
    * `airflow.utils, rest @ ..`
        <!--airflow.utils.dag_parsing_context-->
* `dag_parsing_context.get_parsing_context` →
`airflow.sdk.get_parsing_context`

## Test Plan

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

The test fixture has been updated acccordingly
2025-04-16 11:06:57 -04:00
Andrew Gallant 1d49e71ddd dependencies: switch from `chrono` to `jiff`
We weren't really using `chrono` for anything other than getting the
current time and formatting it for logs.

Unfortunately, this doesn't quite get us to a point where `chrono`
can be removed. From what I can tell, we're still bringing it via
[`tracing-subscriber`](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/)
and
[`quick-junit`](https://docs.rs/quick-junit/latest/quick_junit/).
`tracing-subscriber` does have an
[issue open about Jiff](https://github.com/tokio-rs/tracing/discussions/3128),
but there's no movement on it.

Normally I'd suggest holding off on this since it doesn't get us all of
the way there and it would be better to avoid bringing in two datetime
libraries, but we are, it appears, already there. In particular,
`env_logger` brings in Jiff. So this PR doesn't really make anything
worse, but it does bring us closer to an all-Jiff world.
2025-04-15 07:47:55 -04:00
Brent Westbrook 014bb526f4
[syntax-errors] `await` outside async functions (#17363)
Summary
--

This PR implements detecting the use of `await` expressions outside of
async functions. This is a reimplementation of
[await-outside-async
(PLE1142)](https://docs.astral.sh/ruff/rules/await-outside-async/) as a
semantic syntax error.

Despite the rule name, PLE1142 also applies to `async for` and `async
with`, so these are covered here too.

Test Plan
--

Existing PLE1142 tests.

I also deleted more code from the `SemanticSyntaxCheckerVisitor` to
avoid changes in other parser tests.
2025-04-14 13:01:48 -04:00
Brent Westbrook da32a83c9f
[syntax-errors] `return` outside function (#17300)
Summary
--

This PR reimplements [return-outside-function
(F706)](https://docs.astral.sh/ruff/rules/return-outside-function/) as a
semantic syntax error.

These changes are very similar to those in
https://github.com/astral-sh/ruff/pull/17298.

Test Plan
--

New linter tests, plus existing F706 tests.
2025-04-11 17:05:54 +00:00
Brent Westbrook ffef71d106
[syntax-errors] `yield`, `yield from`, and `await` outside functions (#17298)
Summary
--

This PR reimplements [yield-outside-function
(F704)](https://docs.astral.sh/ruff/rules/yield-outside-function/) as a
semantic syntax error. Despite the name, this rule covers `yield from`
and `await` in addition to `yield`.

Test Plan
--

New linter tests, along with the existing F704 test.

---------

Co-authored-by: Dhruv Manilawala <dhruvmanila@gmail.com>
2025-04-11 10:16:23 -04:00
Brent Westbrook 8e11c53310
Add `Checker::import_from_typing` (#17340)
Summary
--

This PR replaces uses of version-dependent imports from `typing` or
`typing_extensions` with a centralized `Checker::import_from_typing`
method.

The idea here is to make the fix for #9761 (whatever it ends up being)
applicable to all of the rules performing similar checks.

Test Plan
--

Existing tests for the affected rules.
2025-04-11 13:37:55 +00:00
Dylan 7186d5e9ad
Bump 0.11.5 (#17337) 2025-04-10 11:57:44 -05:00
David Peter 5fef4d4572
Use python.typing.org for typing documentation links (#17323)
## Summary

There is a new official URL for the typing documentation:
https://typing.python.org/

Change all https://typing.readthedocs.io/ links to use the new sub
domain, which is slightly shorter and looks more official.

## Test Plan

Tested to see if each and every new URL is accessible. I noticed that
some links go to https://typing.python.org/en/latest/source/stubs.html
which seems to be outdated, but that is a separate issue. The same page
shows up for the old URL.
2025-04-09 20:38:20 +02:00
Brent Westbrook 144484d46c
Refactor semantic syntax error scope handling (#17314)
## Summary

Based on the discussion in
https://github.com/astral-sh/ruff/pull/17298#discussion_r2033975460, we
decided to move the scope handling out of the `SemanticSyntaxChecker`
and into the `SemanticSyntaxContext` trait. This PR implements that
refactor by:

- Reverting all of the `Checkpoint` and `in_async_context` code in the
`SemanticSyntaxChecker`
- Adding four new methods to the `SemanticSyntaxContext` trait
- `in_async_context`: matches `SemanticModel::in_async_context` and only
detects the nearest enclosing function
- `in_sync_comprehension`: uses the new `is_async` tracking on
`Generator` scopes to detect any enclosing sync comprehension
  - `in_module_scope`: reports whether we're at the top-level scope
  - `in_notebook`: reports whether we're in a Jupyter notebook
- In-lining the `TestContext` directly into the
`SemanticSyntaxCheckerVisitor`
- This allows modifying the context as the visitor traverses the AST,
which wasn't possible before

One potential question here is "why not add a single method returning a
`Scope` or `Scopes` to the context?" The main reason is that the `Scope`
type is defined in the `ruff_python_semantic` crate, which is not
currently a dependency of the parser. It also doesn't appear to be used
in red-knot. So it seemed best to use these more granular methods
instead of trying to access `Scope` in `ruff_python_parser` (and
red-knot).

## Test Plan

Existing parser and linter tests.
2025-04-09 14:23:29 -04:00
Wei Lee c87e3ccb2f
[`airflow`] Add missing `AIR302` attribute check (#17115)
<!--
Thank you for contributing to Ruff! 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?
- Does this pull request include references to any relevant issues?
-->

## Summary

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

attribute check was missing in the previous implementation

e.g.

```python
from airflow.api.auth.backend import basic_auth

basic_auth.auth_current_user
```

This PR adds this kind of check.

## Test Plan

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

The test case has been added to the button of the existing test
fixtures, confirmed to be correct and later reorgnaized
2025-04-09 13:58:41 -04:00
Wei Lee 7c81408c54
[`airflow`] Refactor `AIR301` logic and fix typos (`AIR301`) (#17293)
<!--
Thank you for contributing to Ruff! 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?
- Does this pull request include references to any relevant issues?
-->

## Summary

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

* Simplify match conditions in AIR301
* Fix
* `airflow.datasets.manager.DatasetManager` →
`airflow.assets.manager.AssetManager`
* `airflow.www.auth.has_access_dataset` →
`airflow.www.auth.has_access_dataset`

## Test Plan

<!-- How was it tested? -->
The test fixture has been updated accordingly
2025-04-09 10:46:17 -04:00
Wei Lee 7207c86971
[`airflow`] Extract `AIR312` from `AIR302` rules (`AIR302`, `AIR312`) (#17152)
<!--
Thank you for contributing to Ruff! 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?
- Does this pull request include references to any relevant issues?
-->

## Summary

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

As discussed in
https://github.com/astral-sh/ruff/issues/14626#issuecomment-2766146129,
we're to separate suggested changes from required changes.

The following symbols has been moved to AIR312 from AIR302. They still
work in Airflow 3.0, but they're suggested to be changed as they're
expected to be removed in future version

```python
from airflow.hooks.filesystem import FSHook
from airflow.hooks.package_index import PackageIndexHook
from airflow.hooks.subprocess import (SubprocessHook, SubprocessResult, working_directory)
from airflow.operators.bash import BashOperator
from airflow.operators.datetime import BranchDateTimeOperator, target_times_as_dates
from airflow.operators.trigger_dagrun import TriggerDagRunLink, TriggerDagRunOperator
from airflow.operators.empty import EmptyOperator
from airflow.operators.latest_only import LatestOnlyOperator
from airflow.operators.python import (BranchPythonOperator, PythonOperator, PythonVirtualenvOperator, ShortCircuitOperator)
from airflow.operators.weekday import BranchDayOfWeekOperator
from airflow.sensors.date_time import DateTimeSensor, DateTimeSensorAsync
from airflow.sensors.external_task import ExternalTaskMarker, ExternalTaskSensor, ExternalTaskSensorLink
from airflow.sensors.filesystem import FileSensor
from airflow.sensors.time_sensor import TimeSensor, TimeSensorAsync
from airflow.sensors.time_delta import TimeDeltaSensor, TimeDeltaSensorAsync, WaitSensor
from airflow.sensors.weekday import DayOfWeekSensor
from airflow.triggers.external_task import DagStateTrigger, WorkflowTrigger
from airflow.triggers.file import FileTrigger
from airflow.triggers.temporal import DateTimeTrigger, TimeDeltaTrigger
```

## Test Plan

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

The test fixture has been updated acccordingly

---------

Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
2025-04-09 10:43:07 -04:00
Denys Kyslytsyn ed14dbb1a2
[`flake8-pie`] Avoid false positive for multiple assignment with `auto()` (`PIE796`) (#17274)
This fix closes #16868 

I noticed the issue is assigned, but the assignee appears to be actively
working on another pull request. I hope that’s okay!

<!--
Thank you for contributing to Ruff! 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?
- Does this pull request include references to any relevant issues?
-->

## Summary

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

As of Python 3.11.1, `enum.auto()` can be used in multiple assignments.
This pattern should not trigger non-unique-enums check.
Reference: [Python docs on
enum.auto()](https://docs.python.org/3/library/enum.html#enum.auto)

This fix updates the check logic to skip enum variant statements where
the right-hand side is a tuple containing a call to `enum.auto()`.

## Test Plan

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

The added test case uses the example from the original issue. It
previously triggered a false positive, but now passes successfully.
2025-04-08 15:53:27 -04:00
Brent Westbrook 058439d5d3
[syntax-errors] Async comprehension in sync comprehension (#17177)
Summary
--

Detect async comprehensions nested in sync comprehensions in async
functions before Python 3.11, when this was [changed].

The actual logic of this rule is very straightforward, but properly
tracking the async scopes took a bit of work. An alternative to the
current approach is to offload the `in_async_context` check into the
`SemanticSyntaxContext` trait, but that actually required much more
extensive changes to the `TestContext` and also to ruff's semantic
model, as you can see in the changes up to
31554b473507034735bd410760fde6341d54a050. This version has the benefit
of mostly centralizing the state tracking in `SemanticSyntaxChecker`,
although there was some subtlety around deferred function body traversal
that made the changes to `Checker` more intrusive too (hence the new
linter test).

The `Checkpoint` struct/system is obviously overkill for now since it's
only tracking a single `bool`, but I thought it might be more useful
later.

[changed]: https://github.com/python/cpython/issues/77527

Test Plan
--

New inline tests and a new linter integration test.
2025-04-08 12:50:52 -04:00
Wei Lee dc02732d4d
[`airflow`] Expand module path check to individual symbols (`AIR302`) (#17278)
## Summary

### Improvement
Expand the following moved module into individual symbols.

* airflow.triggers.temporal
* airflow.triggers.file
* airflow.triggers.external_task
* airflow.hooks.subprocess
* airflow.hooks.package_index
* airflow.hooks.filesystem
* airflow.sensors.weekday
* airflow.sensors.time_delta
* airflow.sensors.time_sensor
* airflow.sensors.date_time
* airflow.operators.weekday
* airflow.operators.datetime
* airflow.operators.bash 

This removes `Replacement::ImportPathMoved`.

## Fix
During the expansion, the following paths were also fixed

* airflow.sensors.s3_key_sensor.S3KeySensor →
airflow.providers.amazon.aws.sensors.S3KeySensor
* airflow.operators.sql.SQLThresholdCheckOperator →
airflow.providers.common.sql.operators.sql.SQLThresholdCheckOperator
* airflow.hooks.druid_hook.DruidDbApiHook →
airflow.providers.apache.druid.hooks.druid.DruidDbApiHook
* airflow.hooks.druid_hook.DruidHook →
airflow.providers.apache.druid.hooks.druid.DruidHook
* airflow.kubernetes.pod_generator.extend_object_field →
airflow.providers.cncf.kubernetes.pod_generator.extend_object_field
* airflow.kubernetes.pod_launcher.PodLauncher →
airflow.providers.cncf.kubernetes.pod_launcher_deprecated.PodLauncher
* airflow.kubernetes.pod_launcher.PodStatus →
airflow.providers.cncf.kubernetes.pod_launcher_deprecated.PodStatus
* airflow.kubernetes.pod_generator.PodDefaults →
airflow.providers.cncf.kubernetes.pod_generator.PodDefaults
* airflow.kubernetes.pod_launcher_deprecated.PodDefaults →
airflow.providers.cncf.kubernetes.pod_launcher_deprecated.PodDefaults

### Refactor
As many symbols are moved into the same module,
`SourceModuleMovedToProvider` is introduced for grouping similar logic

## Test Plan
2025-04-08 09:03:27 -04:00
Denys Kyslytsyn 97dd6d120c
[`flake8-pytest-style`] Avoid false positive for legacy form of `pytest.raises` (`PT011`) (#17231)
This fix closes #17026 

## Summary

The check for the `PytestRaisesTooBroad` rule is now skipped if there is
a second positional argument present, which means `pytest.raises` is
used as a function.

## Test Plan

Tested on the example from the issue, which now passes the check.
```Python3
pytest.raises(Exception, func, *func_args, **func_kwargs).match("error message")
```

---------

Co-authored-by: Micha Reiser <micha@reiser.io>
2025-04-08 09:24:47 +02:00
Max Mynter f1d4ba32cc
Fix RUF100 to detect unused file-level noqa directives with specific codes (#17042) (#17061)
Closes #17042

## Summary
This PR fixes the issue outlined in #17042 where RUF100 (unused-noqa)
fails to detect unused file-level noqa directives (`# ruff: noqa` or `#
ruff: noqa: {code}`).

The issue stems from two underlying causes:

1. For blanket file-level directives (`# ruff: noqa`), there's a
circular dependency: the directive exempts all rules including RUF100
itself, which prevents checking for usage. This isn't changed by this
PR. I would argue it is intendend behavior - a blanket `# ruff: noqa`
directive should exempt all rules including RUF100 itself.

2. For code-specific file-level directives (e.g. `# ruff: noqa: F841`),
the handling was missing in the `check_noqa` function. This is added in
this PR.

## Notes
- For file-level directives, the `matches` array is pre-populated with
the specified codes during parsing, unlike line-level directives which
only populate their `matches` array when actually suppressing
diagnostics. This difference requires the somewhat clunky handling of
both cases. I would appreciate guidance on a cleaner design :)

- A more fundamental solution would be to change how file-level
directives initialize the `matches` array in
`FileNoqaDirectives::extract()`, but that requires more substantial
changes as it breaks existing functionality. I suspect discussions in
#16483 are relevant for this.

## Test Plan
- Local verification
- Added a test case and fixture
2025-04-07 09:21:52 -05:00
Wei Lee 1e9e423362
[`airflow`] Update oudated `AIR301`, `AIR302` rules (#17123)
## Summary

Some of the migration rules has been changed during Airflow 3
development. The following are new AIR302 rules. Corresponding AIR301
has also been removed.

* airflow.sensors.external_task_sensor.ExternalTaskMarker →
airflow.providers.standard.sensors.external_task.ExternalTaskMarker
* airflow.sensors.external_task_sensor.ExternalTaskSensor →
airflow.providers.standard.sensors.external_task.ExternalTaskSensor
* airflow.sensors.external_task_sensor.ExternalTaskSensorLink →
airflow.providers.standard.sensors.external_task.ExternalTaskSensorLink
* airflow.sensors.time_delta_sensor.TimeDeltaSensor →
airflow.providers.standard.sensors.time_delta.TimeDeltaSensor
* airflow.operators.dagrun_operator.TriggerDagRunLink →
airflow.providers.standard.operators.trigger_dagrun.TriggerDagRunLink
* airflow.operators.dagrun_operator.TriggerDagRunOperator →
airflow.providers.standard.operators.trigger_dagrun.TriggerDagRunOperator
* airflow.operators.python_operator.BranchPythonOperator →
airflow.providers.standard.operators.python.BranchPythonOperator
* airflow.operators.python_operator.PythonOperator →
airflow.providers.standard.operators.python.PythonOperator
* airflow.operators.python_operator.PythonVirtualenvOperator →
airflow.providers.standard.operators.python.PythonVirtualenvOperator
* airflow.operators.python_operator.ShortCircuitOperator →
airflow.providers.standard.operators.python.ShortCircuitOperator
* airflow.operators.latest_only_operator.LatestOnlyOperator →
airflow.providers.standard.operators.latest_only.LatestOnlyOperator
* airflow.sensors.date_time_sensor.DateTimeSensor →
airflow.providers.standard.sensors.DateTimeSensor
* airflow.operators.email_operator.EmailOperator →
airflow.providers.smtp.operators.smtp.EmailOperator
* airflow.operators.email.EmailOperator →
airflow.providers.smtp.operators.smtp.EmailOperator
* airflow.operators.bash.BashOperator →
airflow.providers.standard.operators.bash.BashOperator
* airflow.operators.EmptyOperator →
airflow.providers.standard.operators.empty.EmptyOperator

closes: https://github.com/astral-sh/ruff/issues/17103

## Test Plan

The test fixture has been updated and checked after each change and
later reorganized in the latest commit
2025-04-07 09:45:56 -04:00
Brent Westbrook 95d6ed40cc
Bump 0.11.4 (#17212) 2025-04-04 14:09:10 -04:00
Brent Westbrook acc5662e8b
[syntax-errors] Allow `yield` in base classes and annotations (#17206)
Summary
--

This PR fixes the issue pointed out by @JelleZijlstra in
https://github.com/astral-sh/ruff/pull/17101#issuecomment-2777480204.
Namely, I conflated two very different errors from CPython:

```pycon
>>> def m[T](x: (yield from 1)): ...
  File "<python-input-310>", line 1
    def m[T](x: (yield from 1)): ...
                 ^^^^^^^^^^^^
SyntaxError: yield expression cannot be used within the definition of a generic
>>> def m(x: (yield from 1)): ...
  File "<python-input-311>", line 1
    def m(x: (yield from 1)): ...
              ^^^^^^^^^^^^
SyntaxError: 'yield from' outside function
>>> def outer():
...     def m(x: (yield from 1)): ...
...
>>>
```

I thought the second error was the same as the first, but `yield` (and
`yield from`) is actually valid in this position when inside a function
scope. The same is true for base classes, as pointed out in the original
comment.

We don't currently raise an error for `yield` outside of a function, but
that should be handled separately.

On the upside, this had the benefit of removing the
`InvalidExpressionPosition::BaseClass` variant and the
`allow_named_expr` field from the visitor because they were both no
longer used.

Test Plan
--

Updated inline tests.
2025-04-04 13:48:28 -04:00
David Salvisberg 33a56f198b
Don't skip visiting non-tuple slice in `typing.Annotated` subscripts (#17201)
Fixes: #17196

## Summary

Skipping these nodes for malformed type expressions would lead to
incorrect semantic state, which can in turn mean we emit false positives
for rules like `unused-variable`(`F841`)

## Test Plan

`cargo nextest run`
2025-04-04 18:47:40 +05:30
Max Mynter 98b95c9c38
Implement `Invalid rule provided` as rule RUF102 with `--fix` (#17138)
<!--
Thank you for contributing to Ruff! 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?
- Does this pull request include references to any relevant issues?
-->

Closes #17084

## Summary
This PR adds a new rule (RUF102) to detect and fix invalid rule codes in
`noqa` comments.
Invalid rule codes in `noqa` directives serve no purpose and may
indicate outdated code suppressions.

This extends the previous behaviour originating from
`crates/ruff_linter/src/noqa.rs` which would only emit a warnigs.
With this rule a `--fix` is available.

The rule:
1. Analyzes all `noqa` directives to identify invalid rule codes
2. Provides autofix functionality to:
   - Remove the entire comment if all codes are invalid
   - Remove only the invalid codes when mixed with valid codes
3. Preserves original comment formatting and whitespace where possible

Example cases:
- `# noqa: XYZ111` → Remove entire comment (keep empty line)
- `# noqa: XYZ222, XYZ333` → Remove entire comment (keep empty line)
-  `# noqa: F401, INVALID123` → Keep only valid codes (`# noqa: F401`)

## Test Plan
- Added tests in
`crates/ruff_linter/resources/test/fixtures/ruff/RUF102.py` covering
different example cases.

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

## Notes 
- This does not handle cases where parsing fails. E.g. `# noqa:
NON_EXISTENT, ANOTHER_INVALID` causes a `LexicalError` and the
diagnostic is not propagated and we cannot handle the diagnostic. I am
also unsure what proper `fix` handling would be and making the user
aware we don't understand the codes is probably the best bet.
- The rule is added to the Preview rule group as it's a new addition

## Questions
- Should we remove the warnings, now that we have a rule?
- Is the current fix behavior appropriate for all cases, particularly
the handling of whitespace and line deletions?
- I'm new to the codebase; let me know if there are rule utilities which
could have used but didn't.

---------

Co-authored-by: Micha Reiser <micha@reiser.io>
2025-04-04 08:05:59 +00:00
Brent Westbrook c2b2e42ad3
[syntax-errors] Invalid syntax in annotations (#17101)
Summary
--

This PR detects the use of invalid syntax in annotation scopes,
including
`yield` and `yield from` expressions and named expressions. I combined a
few
different types of CPython errors here, but I think the resulting error
messages
still make sense and are even preferable to what CPython gives. For
example, we
report `yield expression cannot be used in a type annotation` for both
of these:

```pycon
>>> def f[T](x: (yield 1)): ...
  File "<python-input-26>", line 1
    def f[T](x: (yield 1)): ...
                 ^^^^^^^
SyntaxError: yield expression cannot be used within the definition of a generic
>>> def foo() -> (yield x): ...
  File "<python-input-28>", line 1
    def foo() -> (yield x): ...
                  ^^^^^^^
SyntaxError: 'yield' outside function
```

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

Test Plan
--

New inline tests, along with some updates to existing tests.
2025-04-03 17:56:55 -04:00
Brent Westbrook 24b1b1d52c
[syntax-errors] Duplicate attributes in match class pattern (#17186)
Summary
--

Detects duplicate attributes in a `match` class pattern:

```python
match x:
    case Class(x=1, x=2): ...
```

which are more analogous to the similar check for mapping patterns than
to the
multiple assignments rule.

I also realized that both this and the mapping check would only work on
top-level patterns, despite the possibility that they can be nested
inside other
patterns:

```python
match x:
    case [{"x": 1, "x": 2}]: ...  # false negative in the old version
```

and moved these checks into the recursive pattern visitor instead.

I also tidied up some of the names like the `multiple_case_assignment`
function
and the `MultipleCaseAssignmentVisitor`, which are now doing more than
checking
for multiple assignments.

Test Plan
--

New inline tests for both classes and mappings.
2025-04-03 17:55:37 -04:00
Micha Reiser 8a4158c5f8
Upgrade to Rust 1.86 and bump MSRV to 1.84 (#17171)
<!--
Thank you for contributing to Ruff! 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?
- Does this pull request include references to any relevant issues?
-->

## Summary

I decided to disable the new
[`needless_continue`](https://rust-lang.github.io/rust-clippy/master/index.html#needless_continue)
rule because I often found the explicit `continue` more readable over an
empty block or having to invert the condition of an other branch.


## Test Plan

`cargo test`

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2025-04-03 15:59:44 +00:00
Brent Westbrook 6e2b8f9696
[syntax-errors] Detect duplicate keys in `match` mapping patterns (#17129)
Summary
--

Detects duplicate literals in `match` mapping keys.

This PR also adds a `source` method to `SemanticSyntaxContext` to
display the duplicated key in the error message by slicing out its
range.

Test Plan
--

New inline tests.
2025-04-03 10:22:37 -04:00
Dylan d401a5440e
Control flow: `return` and `raise` (#17121)
We add support for `return` and `raise` statements in the control flow
graph: we simply add an edge to the terminal block, push the statements
to the current block, and proceed.

This implementation will have to be modified somewhat once we add
support for `try` statements - then we will need to check whether to
_defer_ the jump. But for now this will do!

Also in this PR: We fix the `unreachable` diagnostic range so that it
lumps together consecutive unreachable blocks.
2025-04-03 08:30:29 -05:00
Brent Westbrook 755ece0c36
Bump 0.11.3 (#17173) 2025-04-03 09:05:40 -04:00
Wei Lee 8833484b10
[`airflow`] Move `AIR302` to `AIR301` and `AIR303` to `AIR302` (#17151)
## Summary

Following up the discussion in
https://github.com/astral-sh/ruff/issues/14626#issuecomment-2766548545,
we're to reorganize airflow rules. Before this discussion happens, we
combine required changes and suggested changes in to one single error
code.

This PR first rename the original error code to the new error code as we
discussed. We will gradually extract suggested changes out of AIR301 and
AIR302 to AIR311 and AIR312 in the following PRs

## Test Plan

Except for file, error code rename, the test case should work as it used
to be.
2025-04-02 23:01:31 +05:30
Wei Lee f989c2c3af
[`airflow`] Add autofix infrastructure to `AIR302` name checks (#16965)
## Summary

Add autofix infrastructure to `AIR302` name checks and use this logic to 
fix`"airflow", "api_connexion", "security", "requires_access_dataset"`, `"airflow", "Dataset"` and `"airflow",
"datasets", "Dataset"`

## Test Plan

The existing test fixture reflects the update
2025-04-02 15:27:51 +00:00
trag1c c2512b4c50
[`flake8-bandit`] Mark `str` and `list[str]` literals as trusted input (`S603`) (#17136)
## Summary

Closes #17112. Allows passing in string and list-of-strings literals
into `subprocess.run` (and related) calls without marking them as
untrusted input:
```py
import subprocess

subprocess.run("true")

# "instant" named expressions are also allowed
subprocess.run(c := "ls")
```

## Test Plan

Added test cases covering new behavior, passed with `cargo nextest run`.
2025-04-02 11:22:37 -04:00
Wei Lee 6bc2b04c49
[`airflow`] Add autofix for `AIR302` attribute checks (#16977)
## Summary

Add autofix logic to AIR302 check_method

## Test Plan

test fixtures have been updated accordingly
2025-04-02 15:18:24 +00:00
Wei Lee fc2a0950eb
[`airflow`] Extend `AIR302` with additional symbols (#17085)
## Summary

* ``airflow.auth.managers.base_auth_manager.is_authorized_dataset`` has
been moved to
``airflow.api_fastapi.auth.managers.base_auth_manager.is_authorized_asset``
in Airflow 3.0
* ``airflow.auth.managers.models.resource_details.DatasetDetails`` has
been moved to
``airflow.api_fastapi.auth.managers.models.resource_details.AssetDetails``
in Airflow 3.0
* Dag arguments `default_view` and `orientation` has been removed in
Airflow 3.0
* `airflow.models.baseoperatorlink.BaseOperatorLink` has been moved to
`airflow.sdk.definitions.baseoperatorlink.BaseOperatorLink` in Airflow
3.0
* ``airflow.notifications.basenotifier.BaseNotifier`` has been moved to
``airflow.sdk.BaseNotifier`` in Airflow 3.0
* ``airflow.utils.log.secrets_masker`` has been moved to
``airflow.sdk.execution_time.secrets_masker`` in Airflow 3.0
* ``airflow...DAG.allow_future_exec_dates`` has been removed in Airflow
3.0
* `airflow.utils.db.create_session` has een removed in Airflow 3.0
* `airflow.sensors.base_sensor_operator.BaseSensorOperator` has been
moved to `airflow.sdk.bases.sensor.BaseSensorOperator` removed Airflow
3.0
* `airflow.utils.file.TemporaryDirectory` has been removed in Airflow
3.0 and can be replaced by `tempfile.TemporaryDirectory`
* `airflow.utils.file.mkdirs` has been removed in Airflow 3.0 and can be
replaced by `pathlib.Path({path}).mkdir`

## Test Plan

Test fixture has been added for these changes
2025-04-02 20:38:52 +05:30
Wei Lee 33bd08f49b
[`airflow`] Move `AIR301` to `AIR002` (#16978)
## Summary

Unlike other AIR3XX rules, this best practice can be applied to Airflow
1 and Airflow 2 as well. Thus, we think it might make sense for use to
move it to AIR002 so that the first number of the error align to Airflow
version as possible to reduce confusion

## Test Plan

the test fixture has been updated
2025-04-02 20:37:35 +05:30
Wei Lee 5d57788328
[`airflow`] Add autofix for `AIR302` method checks (#16976)
## Summary

Add autofix logic to `AIR302` method checks

## Test Plan

Test fixtures have been updated accordingly
2025-04-02 20:35:49 +05:30
Brent Westbrook d382065f8a
[syntax-errors] Reimplement PLE0118 (#17135)
Summary
--

This PR reimplements
[load-before-global-declaration
(PLE0118)](https://docs.astral.sh/ruff/rules/load-before-global-declaration/)
as a semantic syntax error.

I added a `global` method to the `SemanticSyntaxContext` trait to make
this very easy, at least in ruff. Does red-knot have something similar?

If this approach will also work in red-knot, I think some of the other
PLE rules are also compile-time errors in CPython, PLE0117 in
particular. 0115 and 0116 also mention `SyntaxError`s in their docs, but
I haven't confirmed them in the REPL yet.

Test Plan
--

Existing linter tests for PLE0118. I think this actually can't be tested
very easily in an inline test because the `TestContext` doesn't have a
real way to track globals.

---------

Co-authored-by: Micha Reiser <micha@reiser.io>
2025-04-02 13:03:44 +00:00
Brent Westbrook d45593288f
[syntax-errors] Starred expressions in return, yield, and for (#17134)
Summary
--

Fixes https://github.com/astral-sh/ruff/issues/16520 by flagging single,
starred expressions in `return`, `yield`, and
`for` statements.

I thought `yield from` would also be included here, but that error is
emitted by
the CPython parser:

```pycon
>>> ast.parse("def f(): yield from *x")
Traceback (most recent call last):
  File "<python-input-214>", line 1, in <module>
    ast.parse("def f(): yield from *x")
    ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/ast.py", line 54, in parse
    return compile(source, filename, mode, flags,
                   _feature_version=feature_version, optimize=optimize)
  File "<unknown>", line 1
    def f(): yield from *x
                        ^
SyntaxError: invalid syntax
```

And we also already catch it in our parser.

Test Plan
--

New inline tests and updates to existing tests.
2025-04-02 08:38:25 -04:00
Mohammad Amin Ghasemi e1b5b0de71
[flake8-import-conventions] Add import `numpy.typing as npt` to default `flake8-import-conventions.aliases` (#17133)
## Summary
Adds import `numpy.typing as npt` to `default in
flake8-import-conventions.aliases`
Resolves #17028

## Test Plan
Manually ran local ruff on the altered fixture and also ran `cargo test`
2025-04-02 09:25:46 +02:00
Micha Reiser 5a876ed25e
Visit `Identifier` node as part of the `SourceOrderVisitor` (#17110)
## Summary

I don't remember exactly when we made `Identifier` a node but it is now
considered a node (it implements `AnyNodeRef`, it has a range). However,
we never updated
the `SourceOrderVisitor` to visit identifiers because we never had a use
case for it and visiting new nodes can change how the formatter
associates comments (breaking change!).
This PR updates the `SourceOrderVisitor` to visit identifiers and
changes the formatter comment visitor to skip identifiers (updating the
visitor might be desired because it could help simplifying some comment
placement logic but this is out of scope for this PR).

## Test Plan

Tests, updated snapshot tests
2025-04-01 16:58:09 +02:00
Dylan aa93005d8d
Control flow graph: setup (#17064)
This PR contains the scaffolding for a new control flow graph
implementation, along with its application to the `unreachable` rule. At
the moment, the implementation is a maximal over-approximation: no
control flow is modeled and all statements are counted as reachable.
With each additional statement type we support, this approximation will
improve.

So this PR just contains:
- A `ControlFlowGraph` struct and builder
- Support for printing the flow graph as a Mermaid graph
- Snapshot tests for the actual graphs
- (a very bad!) reimplementation of `unreachable` using the new structs
- Snapshot tests for `unreachable`

# Instructions for Viewing Mermaid snapshots
Unfortunately I don't know how to convince GitHub to render the Mermaid
graphs in the snapshots. However, you can view these locally in VSCode
if you install an extension that supports Mermaid graphs in Markdown,
and then add this to your `settings.json`:

```json
  "files.associations": {
"*.md.snap": "markdown",
  }
  ```
2025-04-01 05:53:42 -05:00
Aarni Koskela 491a51960e
[`ruff`] Support slices in `RUF005` (#17078)
## Summary

Teaches `RUF005` to also consider slices for concatenation. Other
indexing (`foo[0] + [7, 8, 9] + bar[1]`) is explicitly not considered.

```diff
 foo = [4, 5, 6]
-bar = [1, 2, 3] + foo
-slicing1 = foo[:1] + [7, 8, 9]
-slicing2 = [7, 8, 9] + bar[1:]
-slicing3 = foo[:1] + [7, 8, 9] + bar[1:]
+bar = [1, 2, 3, *foo]
+slicing1 = [*foo[:1], 7, 8, 9]
+slicing2 = [7, 8, 9, *bar[1:]]
+slicing3 = [*foo[:1], 7, 8, 9, *bar[1:]]
```

## Test Plan

Manually tested (diff above from `ruff check --diff`), snapshot updated.
2025-03-31 09:09:39 -04:00