425 Commits
Author SHA1 Message Date
astral-automations-bot[bot]andBrent Westbrook ba65abf8ba Bump version to 0.17.3 (#29745)
Co-authored-by: astral-automations-bot[bot] <305554984+astral-automations-bot[bot]@users.noreply.github.com>
Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
2026-10-26 20:14:27 -04:00
astral-automations-bot[bot]andBrent Westbrook 30516b42ab Bump version to 0.17.2 (#29637)
Co-authored-by: astral-automations-bot[bot] <305554984+astral-automations-bot[bot]@users.noreply.github.com>
Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
2026-10-22 13:54:24 -04:00
Micha Reiser 2983c7c529 Avoid intermediate names in lint name resolution (#29506) 2026-10-20 10:35:07 -07:00
astral-automations-bot[bot] 4683270c69 Bump version to 0.17.1 (#29420)
Co-authored-by: astral-automations-bot[bot] <305554984+astral-automations-bot[bot]@users.noreply.github.com>
2026-10-15 10:56:41 -04:00
astral-automations-bot[bot]andBrent Westbrook 5b27c1ccfa Bump version to 0.17.0 (#29259)
Co-authored-by: astral-automations-bot[bot] <305554984+astral-automations-bot[bot]@users.noreply.github.com>
Co-authored-by: Brent Westbrook <brentrwestbrook@gmail.com>
2026-10-09 13:45:29 -04:00
David Salvisberg 5409291eb1 [flake8-type-checking] Add the notion of runtime-ambiguous references (#26508)
This is a partial solution for #16412

I would still like to add something like
`runtime-evaluated-generic-subscripts`, but that will require further
consideration about how the presence of such subscripts should affect
the rest of the type expression, or in more extreme cases, the other
annotations in the function/class definition.

## Summary

For things like SQLAlchemy's `Mapped` the evaluation of the annotations
only requires a subset of all the symbols to be resolvable at runtime,
this is sometimes necessary to make forward references to other models
work without causing import cycles.

But this means we can neither assume that the annotations are
runtime-required, nor can we assume, that they are typing-only. So we
should assume the referenced binding is already in its correct execution
context, i.e. we should neither emit TC001-003, nor TC004 violations.

Instead of adding two additional settings now and potentially two more
settings later, the existing two settings for runtime-required
annotations now accept a table in addition to the list to flag
individual imports with individual runtime requirements.

For example:
```toml
[lint.flake8-type-checking.runtime-evaluated-base-classes]
"pydantic.BaseModel" = "required"
"sqlalchemy.orm.DeclarativeBase" = "ambiguous"

[lint.flake8-type-checking.runtime-evaluated-decorators]
"pydantic.validate_call" = "required"
"sqlalchemy.orm.declared_attr" = "ambiguous"
```

## Test Plan

`cargo nextest run`
2026-10-06 21:13:09 +00:00
astral-automations-bot[bot]andBrent Westbrook 3265ed1f94 Bump version to 0.16.10 (#29055)
Co-authored-by: astral-automations-bot[bot] <305554984+astral-automations-bot[bot]@users.noreply.github.com>
Co-authored-by: Brent Westbrook <brentrwestbrook@gmail.com>
2026-10-01 13:40:09 -04:00
astral-automations-bot[bot]andBrent Westbrook 0be08a206f Bump version to 0.16.9 (#28882)
Co-authored-by: astral-automations-bot[bot] <305554984+astral-automations-bot[bot]@users.noreply.github.com>
Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
2026-09-24 16:21:50 -04:00
astral-automations-bot[bot]andBrent Westbrook 62914c4b9b Bump version to 0.16.8 (#28648)
Co-authored-by: astral-automations-bot[bot] <305554984+astral-automations-bot[bot]@users.noreply.github.com>
Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
2026-09-16 11:31:02 -04:00
Brent Westbrook 652bfea146 Recognize quoted types in typing.TypeForm (#28507)
Summary
--

`typing.TypeForm` was introduced in Python 3.15 and [PEP
747](https://peps.python.org/pep-0747/) as
a way to annotate the passing of type objects like `int | str`,
`list[int]`, or `MyTypeAlias`. It
can be used either as a subscripted generic, as in this example from the
PEP:

```py
from typing import TypeForm

def trycast[T](typx: TypeForm[T], value: object) -> T | None: ...
```

or as a callable, which returns its argument unchanged:

```py
from typing import TypeForm

TypeForm("list[int]")
```

This PR recognizes `typing.TypeForm` as a standard-library generic and
as a known `typing` callable
and visits its argument or subscript as a type definition.

While I was reading the [typing docs], I realized that a couple of
nearby types were also not
listed, so I've attempted to sneak them in here but could split them off
if needed. We already had
coverage for `typing.TypeGuard` but not `typing_extensions.TypeGuard`
(added in 3.10), and we were
missing both variants of `TypeIs` (added in 3.13). These are only valid
in the subscript form, so
they don't need new `Callable` entries.

[typing docs]:
https://docs.python.org/3.15/library/typing.html#typing.TypeForm

Test Plan
--

New mdtests, using `unused-import` (`F401`) to demonstrate that visiting
these arguments as type
definitions marks them as used, but other rules will be affected as
well.
2026-09-11 14:12:38 +00:00
Brent Westbrook 26752e1c55 Support conditional assignment to __lazy_modules__ (#28491)
Summary
--

This is a follow-up to #28459 adding simple support for conditionally
defining `__lazy_modules__`. We now track per-module laziness, which
allows us to merge definitions like:

```py
__lazy_modules__ = ["foo"]

if condition:
    __lazy_modules__ = ["foo", "bar"]
```

into known laziness for `foo` and unknown laziness for `bar`. As in
#28459, that unknown laziness is still helpful and distinct from known
eagerness because it suppresses diagnostics.

The one quirk with the `branch_id` tracking used here is that it doesn't
handle exhaustive branches. For example, it would be nice if we noticed
that `foo` is always lazy here:

```py
if condition:
    __lazy_modules__ = ["foo", "bar"]
else:
    __lazy_modules__ = ["foo", "baz"]
```

but it's instead merged with the implicit known eagerness of all imports
before any `__lazy_modules__` assignment, producing `(foo, Unknown)`. So
this is effectively equivalent to the version without an `else` for
`foo`.

I think this is a decent tradeoff that biases us against false
positives, though, and doesn't involve any extra bookkeeping in `if`
statement traversal.

One of my three Codex reviewers also identified this as a false
negative, where the assignment and
use are in the same branch, but we've already marked the module as
`Unknown`:

```py
if condition:
    __lazy_modules__ = ["json"]
    import json
    json.dumps({})
```

But again we're at least biased in the right direction, and we'd need
more bookkeeping to identify
this, so I was okay accepting that for now.

Test Plan
--

New mdtests for TID254 that exercise this behavior
2026-09-11 09:55:43 -04:00
Brent Westbrook 67d03a5447 Add support for __lazy_modules__ (#28459)
Summary
--

For a bit of background, `__lazy_modules__` is a backwards compatibility
mechanism for lazy imports, introduced in [PEP
810](https://peps.python.org/pep-0810/) alongside the `lazy` keyword
itself. Instead of declaring an import `lazy` with the keyword, it can
also be listed in a module-level constant named `__lazy_modules__`:

```py
lazy import foo

# equivalently
__lazy_modules__ = ["foo"]
import foo
```

This can be used in projects that support older Python versions, as well
as 3.15.

It also supports more dynamic approaches (that this PR doesn't), as
noted in one of my inline comments, such as:

```py
class LazyImporter:
    def __contains__(self, name): return True

__lazy_modules__ = LazyImporter()
```

As one example from the PEP for emulating wildcard lazy imports.

<hr>

The PR is pretty big in total, but it's intended to be reviewed
commit-by-commit. As usual, the very
first commit is empty for filling the PR summary, so the numbers below
refer to the remaining
non-empty commits.

The first commit adds `__lazy_modules__` tracking to the semantic model.
Because the declaration
affects later imports and can also be overwritten, we just store
whatever was assigned to it last
for later lookup when visiting other code.

The second commit expands [TID254] to recognize `__lazy_modules__` and
includes a few helper methods
on the semantic model that are used by later rules as well.

The third commit adds `__lazy_modules__` support to [TID255], which also
relies on a new
`BindingFlags::LAZY` variant. This marks bindings as originating from a
lazy import, which is easier
than trying to resolve a sequence of potentially shadowed
`__lazy_modules__` bindings to check if an
import was lazy. For example, we set the `LAZY` flag on `foo` here,
which would otherwise require
resolve multiple previous bindings:

```py
__lazy_modules__ = ["foo"]
import foo

__lazy_modules__ = []

class C(foo.Something): ...
```

The last four commits make smaller changes to four other rules. As with
TID254 and TID255, the
primary change is that we withhold a fix that involves
`__lazy_modules__` when it would change the
module's lazy status. Initially I had hoped to add fixes that modified
`__lazy_modules__` (adding to
it when we'd otherwise add `lazy`, removing from it when we'd remove
`lazy`), but this turned out to
be quite complicated. Unlike the `lazy` keyword, `__lazy_modules__` has
nonlocal effects that could
change the behavior of _any_ import from the same module in the file.
Trying to resolve all of that
to be sure the fix is reasaonable was a real mess, and reverting Codex's
attempt saved almost 700
lines for TID255 alone.

Similarly, in case this comes up in someone else's Codex review, my
Codex initially tried to handle
even more edge cases with `__lazy_modules__` definitions, such as
definitions in a loop or
redefining it with `*` imports and things like that. I tried to rein it
in toward something more
like our `__all__` and `from __future__ import annotations` handling,
which again seemed like the
better tradeoff to me.

Closes #25170.

[TID254]: https://docs.astral.sh/ruff/rules/lazy-import-mismatch/
[TID255]:
https://docs.astral.sh/ruff/rules/lazy-import-immediately-resolved/

Test Plan
--

New mdtests. The ecosystem results all look correct. They are cases
where `TID255` now fires in modules where `__lazy_modules__` is defined.
2026-09-11 09:55:42 -04:00
astral-automations-bot[bot]andBrent Westbrook b5dba861cc Bump version to 0.16.7 (#28496)
Co-authored-by: astral-automations-bot[bot] <305554984+astral-automations-bot[bot]@users.noreply.github.com>
Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
2026-09-10 13:47:30 -04:00
JohnKagundaandBrent Westbrook 6748126256 [ruff] Add rule for default values on method receivers (RUF077) (#26700)
## Summary

Adds a new Ruff rule that flags method receiver parameters (`self` /
`cls`) when they are given a default value.

The rule targets functions defined directly inside a class body and uses
semantic context to ensure it only applies to methods, not standalone
functions. It determines the receiver kind, inspects the first
positional parameter, and reports a diagnostic when that receiver has a
default value.

Closes #25820

## Test Plan

Tested by adding a Ruff fixture and snapshot for RUF077, and verifying
the rule is triggered for methods whose receiver parameter has a default
value.

Files added/updated for testing include:

- `crates/ruff_linter/resources/test/fixtures/ruff/RUF077.py`
-
`crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF077_RUF077.py.snap`

I also validated the rule integration by building Ruff locally after
registering the rule and hooking it into AST statement analysis.

---------

Signed-off-by: John Kagunda <rafaeljohb@gmail.com>
Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
2026-09-09 10:47:24 -04:00
Brent Westbrook 22f65a2ab5 Bump 0.16.6 (#28280) 2026-09-03 12:36:42 -04:00
Brent Westbrook 9e4938c4a6 Bump 0.16.5 (#28110) 2026-08-27 12:09:07 -04:00
Brent Westbrook 11c76bf48f Bump 0.16.4 (#27937) 2026-08-20 13:14:29 -04:00
Brent Westbrook b0e47022cf Bump 0.16.3 (#27723) 2026-08-13 09:39:16 -04:00
Alex Waygood c0824de94a Enable rustfmt on more files (#27630) 2026-08-10 15:30:41 +01:00
Brent Westbrook 5b48a04097 Bump 0.16.2 (#27555) 2026-08-07 09:12:50 -04:00
Charlie Marsh c4fb1f4f57 Remove unused ClassMemberBoundness predicates (#27389)
## Summary

This PR removes the unused `ClassMemberBoundness::{is_bound,
is_possibly_unbound}` predicates identified by Hawk 0.1.11. The other
APIs and CFG visualization support considered in #27339 remain
unchanged.

- 2 unused public methods removed
- 10 deletions
- 1 file changed
2026-08-01 16:56:18 +00:00
Charlie Marsh 6cfeb8aa07 Narrow internal visibility with Hawk (#27339)
## Summary

This PR uses Hawk 0.1.11 to narrow internal declarations to the
visibility they actually need.

Here, I've intentionally _only_ made visibility changes; unused API
removals are split into follow-up PRs. In total, 1,201 declaration
visibility modifiers are narrowed. Public generated formatter APIs and
other declarations whose narrower visibility would activate dead-code or
API-shape lints remain unchanged.
2026-07-31 22:08:13 -04:00
Brent Westbrook 80790b348b Bump 0.16.1 (#27330) 2026-07-30 13:54:42 -04:00
Brent Westbrook a2635fd8f3 Bump 0.16.0 (#27136) 2026-07-23 14:37:34 -04:00
Brent Westbrook 40e43bc8e5 [flake8-future-annotations] Stabilize additional PEP 585-compatible APIs (FA102) (#26953)
Preview feature: https://github.com/astral-sh/ruff/pull/20659

Rule documentation:
https://docs.astral.sh/ruff/rules/future-required-type-annotation/
2026-07-23 13:38:29 -04:00
Brent Westbrook 0177a7e0d2 Bump 0.15.22 (#26884) 2026-07-16 10:54:43 -04:00
Charlie Marsh bdf1320bba Update Rust toolchain to 1.97 and MSRV to 1.95 (#26844) 2026-07-15 08:12:16 +02:00
Brent Westbrook 3e1f636451 Bump 0.15.21 (#26676) 2026-07-09 15:42:27 -04:00
Charlie MarshandCharlie Marsh 2dff4da98e Lazily create builtin bindings (#26510)
## Summary

The linter previously inserted every version-specific builtin, magic
global, notebook builtin, and configured custom builtin into the module
scope before walking the AST, even when a file never referenced most of
those names.

This moves builtin identification into `SemanticModel` and creates
concrete builtin bindings only when a load or binding operation needs
them.

---------

Co-authored-by: Charlie Marsh <charliemarsh@openai.com>
2026-07-07 09:55:04 -04:00
Brent Westbrook f82a36b6ba Bump 0.15.20 (#26376) 2026-06-25 10:00:55 -07:00
Charlie Marsh 7f0436561d Bump version to 0.15.19 (#26291) 2026-06-23 20:42:26 -04:00
Charlie Marsh dff016b7a4 Publish Ruff crates to crates.io (#26271)
## Summary

Publish Ruff's production Rust crates to crates.io as part of the
existing release workflow. This follows uv's setup: workspace
dependencies carry registry-compatible version pins, internal crates
receive generated READMEs and an explicit versioning policy, CI dry-runs
the full workspace publish, and release jobs publish missing crate
versions idempotently through crates.io trusted publishing.

The publishing set contains 32 packages: Ruff's CLI, WASM package,
server, linter, formatter, parser, and the internal Ruff component
crates required by them. It also includes `ty_module_resolver`,
`ty_site_packages`, and `ty_static`, because those three crates are part
of Ruff's normal dependency closure.

The publishing set deliberately excludes:

- Test-only crates: `mdtest`, `ruff_mdtest`,
`ruff_python_ast_integration_tests`, and
`ruff_python_trivia_integration_tests`.
- Benchmark and development crates: `ruff_benchmark` and `ruff_dev`.
- All remaining `ty_*` crates.

These packages retain `publish = false`, so bootstrap, version bumping,
README generation, CI dry-runs, and release publishing skip them through
Cargo metadata instead of a separate hard-coded allowlist.

The crates.io job is intentionally independent of release announcement,
so a crates.io outage cannot block the existing binary, PyPI, npm, or
GitHub release outputs. A bootstrap script reserves new crate names,
configures the release workflow as each crate's trusted publisher,
enables trusted-publishing-only releases, and records configured crates
for idempotent reruns.

The full workspace publish dry-run packages and verifies all 32 selected
crates.

Closes https://github.com/astral-sh/ruff/issues/43.
2026-06-23 12:49:23 -04:00
Micha ReiserandMicha Reiser 9e8c4530ba Reserve capacity for builtin bindings (#26229)
Co-authored-by: Micha Reiser <micha@openai.com>
2026-06-22 18:01:36 +02:00
Charlie Marsh 948359fd97 Enable Clippy's iter_over_hash_type lint (#25732)
## Summary

Stacks on #25726 and enables Clippy's `iter_over_hash_type` restriction
lint across the workspace, so new hash-map and hash-set iterations must
make their ordering assumptions explicit.

Most existing loops are order-independent and use a site-local
`#[expect(clippy::iter_over_hash_type)]`. At the order-sensitive sites,
this sorts before iteration. (In practice, that should stabilize some
parser fixtures, configuration diagnostics, union normalization, etc.).

This lint is kind of annoying, but given how much we want to crack down
on non-determinism in ty, it seems worthwhile to enable IMO.
2026-06-09 16:35:09 +00:00
Ruchir 7c2e9fbc83 [pyflakes] Treat function-scope bare annotations as locals per PEP 526 (F821) (#21540)
## Summary

Resolves #21494 

Treat function-scope annotated variables as locals per PEP 526 ,
preventing F821 false positives.

## Test Plan

Added tests for these cases in
`crates/ruff_linter/resources/test/fixtures/pyflakes/F821_34.py`
2026-05-26 14:51:25 -07:00
Alex Waygood 581b3fa230 Update Rust toolchain to 1.95 and MSRV to 1.93 (#24677) 2026-04-17 11:39:14 +01:00
Micha Reiser 3ffa53af20 Use dyn dispatch internally only for any_over methods (#24468) 2026-04-07 13:58:54 +02:00
Micha Reiser 2d6ce56125 Fix all cargo shear warnings (#24268) 2026-03-29 13:57:30 +01:00
Dylan 1a2e402cfe [pyflakes] Skip undefined-name (F821) for conditionally deleted variables (#24088)
We already skip `F821` for things like this:

```python
x = 1
if cond:
    del x
print(x) # no diagnostic here
```

But when we checked for "conditional branches" we were only looking for
`match`, `if`, and `while` statements.

Here we also check for except handlers and `else` clauses. We continue
to regard `try` statements as "unconditionally executing" even though
that's not quite true.

Closes #6242

As an aside: I originally wanted to use the `BindingKind` variant
`ConditionalDeletion` introduced way back in #10415, but it turns out we
never actually constructed an instance of it! We could, if we ever
needed to track the "thing that was conditionally deleted". But since
that doesn't seem to have ever arisen in practice, I just got rid of the
variant and its references altogether.
2026-03-21 08:17:32 -05:00
Charlie Marsh 8a10b6743c Add support for lazy import parsing (#23755)
## Summary

This PR adds `is_lazy` to the AST and parser, and supports `lazy` import
formatting in the formatter. The name `is_lazy` matches the [CPython
AST](https://github.com/python/cpython/blob/c3fb0d9d96902774c08b199dda0479a8d31398a5/Parser/Python.asdl#L48),
though we could modify it if there's demand.

There are no further changes to Ruff rules or even to Ruff import
sorting, since those deserve separate design discussions.

I've also omitted support for flagging semantic syntax errors (e.g.,
`lazy import` inside `def`).

See: https://github.com/astral-sh/ruff/issues/21305.
2026-03-06 09:12:21 -05:00
Brent Westbrook fd09d37007 Fix panic on access to definitions after analyzing definitions (#23588)
Summary
--

This PR fixes #23587 by removing this `std::mem::take` call:


https://github.com/astral-sh/ruff/blob/a62ba8c6e2bac0b899d90fd30a1b26c07aac44bb/crates/ruff_linter/src/checkers/ast/analyze/definitions.rs#L120

This was previously moving the `Definitions` out of the `Checker` and
causing
this operation to panic if the definitions were accessed in a later
analysis
phase:


https://github.com/astral-sh/ruff/blob/a62ba8c6e2bac0b899d90fd30a1b26c07aac44bb/crates/ruff_linter/src/checkers/ast/analyze/definitions.rs#L120

which was apparently never done before `PLR1712` was added.

I don't see any reason why this really needed to be a move as it only
took a
couple of lifetimes to handle it with borrowing, so this seems like the
easiest
fix.

I also changed the indexing operation to a `get` call (with a
`debug_assert`)
since the method already returns an `Option`, but doing that alone would
prevent
`PLR1712` from firing in the module scope.

Test Plan
--

A new test based on the issue that also covers the module scope
mentioned above
2026-02-26 14:19:32 -05:00
81d655fadc [pyflakes] suppress false positive in F821 for names used before del in stub files (#23550)
Co-authored-by: stakeswky <stakeswky@users.noreply.github.com>
Co-authored-by: Amethyst Reese <amethyst@n7.gg>
2026-02-26 18:41:05 +00:00
kar-ganapandBrent Westbrook e462c03f03 Fix F811 false positive for overloaded functions from typing-modules (#23357)
## Summary

Fixes #19632.

When `@overload` is imported from a custom module listed in
`typing-modules` (e.g., `from std import overload`), Ruff fails to
recognize it as the `typing.overload` decorator and emits false F811
diagnostics for each overloaded function definition.

The root cause is in `SemanticModel::match_typing_qualified_name`:
`QualifiedName::from_dotted_name` splits on dots, so a single-segment
module like `std` still works, but the internal representation stores it
differently from what `QualifiedName::user_defined` produces. Use
`user_defined` instead to match the internal representation
consistently.

## Test plan

- Reproduction case: `ruff check --select F811 --config ruff.toml
temp.py` no longer emits false positives for `@overload` from custom
typing-modules
- `cargo test -p ruff_linter -- pyflakes` — all 462 tests pass

---------

Co-authored-by: Brent Westbrook <brentrwestbrook@gmail.com>
2026-02-23 15:50:32 +00:00
Dylan 1465b5de38 [flake8-async] Fix in_async_context logic (#23426)
We move the logic from `Checker::in_async_context` (from when it
implements `SemanticSyntaxContext`) into the similarly named method in
`SemanticModel`. This affects the following rules:

- ASYNC105
- ASYNC210
- ASYNC212
- ASYNC220 
- ASYNC221 
- ASYNC222
- ASYNC230
- ASYNC240
- ASYNC250
- ASYNC251
- UP028

Closes #23425
2026-02-19 13:08:50 -06:00
Dan ParizherandBrent Westbrook 95e517fae7 [flake8-annotations] Don't suggest NoReturn for functions raising NotImplementedError (ANN201, ANN202, ANN205, ANN206) (#21311)
## Summary

Fix ANN201, ANN202, ANN205, and ANN206 to not automatically suggest
`NoReturn`/`Never` return type annotations for functions that raise
`NotImplementedError`. These rules will still flag missing return type
annotations but won't provide an auto-fix, allowing developers to
manually specify the actual return type that implementations should
return.

Fixes #18886

## Problem Analysis

The bug occurred because the `auto_return_type` function in
`flake8_annotations/helpers.rs` detects when all control flow paths in a
function raise an exception (`Terminal::Raise`) and automatically
suggests `NoReturn`/`Never` as the return type. However,
`NotImplementedError` is semantically different from other exceptions -
it's used to indicate abstract methods that should be implemented by
subclasses, not methods that truly never return.

When a function raises `NotImplementedError`, it's typically an abstract
method pattern where:
- The base class defines the method signature but doesn't implement it
- Subclasses are expected to override the method with a proper
implementation
- The return type should reflect what implementations will actually
return, not `NoReturn`

For example, in Django's serializer pattern:

```py
class BaseSerializer:
    def to_internal_value(self, data):
        raise NotImplementedError('`to_internal_value()` must be implemented.')
```

This method should have a return type annotation like `dict` or `Any`,
not `NoReturn`, because implementations will return actual values.

## Approach

The fix modifies the `auto_return_type` function to:

1. **Added semantic analysis capability**: Modified `auto_return_type`
to accept a `SemanticModel` parameter, enabling it to analyze exception
types in raise statements.

2. **Created detection helper**: Implemented
`only_raises_not_implemented_error()` function that:
- Traverses the function body using a custom visitor to collect all
`raise` statements
- Checks if all raises are `NotImplementedError` (or `NotImplemented`)
using semantic analysis
   - Returns `true` only if all raises are `NotImplementedError`

3. **Modified return type inference**: When `Terminal::Raise` is
detected, the function now:
   - First checks if all raises are `NotImplementedError`
- If yes, returns `None` (no auto-fix suggested, but diagnostic still
emitted)
- If no, returns `AutoPythonType::Never` as before (suggesting
`NoReturn`/`Never`)

4. **Updated all call sites**: Updated all 4 call sites in
`definition.rs` to pass `checker.semantic()`:
   - ANN201 (public functions)
   - ANN202 (private functions)  
   - ANN205 (static methods)
   - ANN206 (class methods)

The fix ensures that:
- Functions raising `NotImplementedError` still get flagged for missing
return type annotations
- But no auto-fix is suggested, allowing manual specification of the
correct return type
- Functions raising other exceptions (like `ValueError`) still correctly
get `NoReturn`/`Never` suggestions

---------

Co-authored-by: Brent Westbrook <brentrwestbrook@gmail.com>
2026-01-27 17:42:11 -05:00
Alex Waygood d0f841bff2 Add help: subdiagnostics for several Ruff rules that can sometimes appear to disagree with ty (#22331) 2026-01-02 22:10:39 +00:00
Matthew Mckee a2e0ff57c3 Run cargo sort (#22310) 2026-01-02 19:58:15 +00:00
33713a7e2a Add rule to detect unnecessary class properties (#21535)
Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
Co-authored-by: Amethyst Reese <amethyst@n7.gg>
Co-authored-by: Micha Reiser <micha@reiser.io>
2025-11-26 09:31:22 +01:00
Dylan fffbe5a879 [pyflakes] Revert to stable behavior if imports for module lie in alternate branches for F401 (#20878)
Closes #20839
2025-10-27 10:23:36 -05:00
7576669297 [flake8-pyi] Fix PYI034 to not trigger on metaclasses (PYI034) (#20881)
## Summary

Fixes #20781

---------

Co-authored-by: Alex Waygood <alex.waygood@gmail.com>
Co-authored-by: Brent Westbrook <brentrwestbrook@gmail.com>
Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
2025-10-24 13:40:26 +00:00