## Summary
Closes#25173
This PR changes behavior of flake8-bugbear in regard to
`weakref.WeakKeyDictionary`, `weakref.WeakValueDictionary`,
`weakref.WeakSet`, `collections.ChainMap`, `collections.UserDict`,
`collections.UserList`, and `collections.UserString`, so that instead of
reporting the error B008 ("function call in argument defaults"), it
reports B006 ("mutable data structures for argument defaults"). These
types are similar to `dict` and `list` in terms of being containers and
are considered to be mutable, and therefore are suitable for B006,
allowing for fixing the code via replacing a default value with `None`
and making the object construction inside the body of the function.
### Implementation details
In this PR, those seven types are added to `is_mutable_return_type` in
`crates/ruff_python_stdlib/src/typing.rs` file along with other types
like `dict`, `list`, `set`, `Counter`, `OrderedDict`, `defaultdict`, and
`deque`. As B008 purposefully skips objects matching
`is_mutable_return_type` condition, this solves the categorization
mistake while avoiding duplicates.
As discussed with maintainers, this change doesn't use `--preview`
option. Because `is_mutable_return_type` is a shared helper, another
side effect of this PR is that B039, RUF008, RUF012, RUF024, and PLW2901
rules will also treat those seven types as mutable data structures.
According to the review comments, `collections.UserList` and
`collections.UserString` are also included; even though `str` is
immutable, a `UserString` instance is mutable due to `.data` attribute
being reassignable.
## Test Plan
A new mdtest was added at
`crates/ruff_linter/resources/mdtest/flake8-bugbear/mutable-argument-default.md`.
The new mdtest is set up to generate results for B006 and B008 and to
include a single import case per type. The purpose of the test is to
verify that B006 is triggered and that B008 ignores all those seven
types strictly.
No `ruff_linter` snapshot changes in the existing tests. Ecosystem check
results come from CI.
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.
Summary
--
This moves `__cached__` from the main list of `MAGIC_GLOBALS` to a
version-specific list because it will be
[removed](https://docs.python.org/3/reference/datamodel.html#module.__cached__)
in 3.15.
Test Plan
--
A new mdtest for `undefined-name` (`F821`), which is just one of the
rules affected but the easiest to test.
Fix PLW0133's Python version gating for `ImportCycleError`.
`ImportCycleError` was added in Python 3.15, but Ruff currently treats
it as available starting in Python 3.13.
This updates the builtin exception classification so that:
- `PythonFinalizationError` remains available for Python 3.13+
- `ImportCycleError` is only considered available for Python 3.15+
Also adds regression coverage for the behavior across target Python
versions.
Closes part of #28206.
Fixed a link to `frozen.discard` in the Python docs this was a valid
link in older Python docs but has been broken.
While I was there I noticed a few other uncanonical links so replaced
them with more canonical versions and removed some links to specific
Python versions that are unnecessary.
## Summary
This PR removes an unused API from ruff_python_stdlib identified by Hawk
0.1.11. It is split from #27339 so the removal can be reviewed
independently at the crate boundary.
- 6 net lines removed
- 6 deletions
- 1 file changed
## 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.
Summary
--
Fixes#27245.
Test Plan
--
Updated existing snapshots. These were previously emitting both B006 on
the outer comprehensions and
B008 on the inner `range` call, but now the inner diagnostic is omitted
because `range` is
immutable.
## 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.
## Summary
1. Manually update various functions in
`crates/ruff_python_stdlib/src/builtins.rs` to reflect new APIs added in
Python 3.15.
2. Manually remove the incorrect inclusion of `frozenset` from
`is_immutable_non_generic_type` in
`crates/ruff_python_stdlib/src/typing.rs`. `frozenset` is a generic
type.
3. Manually add `frozendict` to `is_immutable_generic_type` and
`is_immutable_return_type` in `crates/ruff_python_stdlib/src/typing.rs`
4. Manually updates to `scripts/generate_builtin_modules.py`: use uv to
invoke Python rather than relying on many different Python versions all
being on `PATH`, drop support for Python 3.7 from the script (it can't
be installed using uv), and apply various other simplifications.
5. Regenerate `is_builtin_module` in
`crates/ruff_python_stdlib/src/sys/builtin_modules.rs` following the
changes made in (4). Note that switching to uv-managed Python installs
(PBS) appears to mean that quite a few more stdlib modules are
recognised as being builtin modules, which is interesting.
I also ran `scripts/generate_known_standard_library.py`, but it didn't
make any changes to the Rust function generated by that script.
## Test Plan
`cargo test`
## Summary
Register `frozendict` (PEP 814) as a version-gated builtin for Python
3.15+, fixing `F821` when `target-version = "py315"`
Closes#24095
## Test plan
- `frozendict` with `target-version >= py315` → no diagnostic
- `frozendict` with `target-version < py315` → `F821` with version hint
suggesting `py315`
- Existing version-gated builtin tests still pass (e.g.
`PythonFinalizationError`, `__annotate__`)
## Local run
```────────────
Nextest run ID ab77447d-80be-48fe-ba42-d98e29697619 with nextest profile: default
Starting 2 tests across 1 binary (2697 tests skipped)
PASS [ 0.049s] ruff_linter rules::pyflakes::tests::f821_frozendict_py315_available
PASS [ 0.254s] ruff_linter rules::pyflakes::tests::f821_frozendict_pre_py315_undefined
```
Closes issue #21565
## Summary
As pointed out in the issue, slices are currently flagged by B008 but
this behavior is incorrect because slices are immutable.
## Test Plan
Added a test case in the "B006_B008.py" fixture. Sorry for the diff in
the snapshots, the only thing that changes in those flies is the line
numbers, though.
You can also test this manually with this file:
```py
# test_slice.py
def c(d=slice(0, 3)): ...
```
```sh
> target/debug/ruff check tmp/test_slice.py --no-cache --select B008
All checks passed!
```
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.
<!--
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/future-feature-not-defined/ (F407) as
a semantic syntax error.
## Test Plan
<!-- How was it tested? -->
I have written inline tests as directed in #17412
---------
Signed-off-by: 11happy <soni5happy@gmail.com>
## Summary
Added version 3.14 to the script generating the `known_stdlib.rs` file.
Rebuilt the known stdlibs with latest version (2025.5.10) of [stdlibs
Python lib](https://pypi.org/project/stdlibs/) (which added support for
3.14.0b1).
_Note: Python 3.14 is now in [feature
freeze](https://peps.python.org/pep-0745/) so the modules in stdlib
should be stable._
_See also: #15506_
## Test Plan
The following command has been run. Using for tests the `compression`
module which been introduced with Python 3.14.
```sh
ruff check --no-cache --select I001 --target-version py314 --fix
```
With ruff 0.11.9:
```python
import base64
import datetime
import compression
print(base64, compression, datetime)
```
With this PR:
```python
import base64
import compression
import datetime
print(base64, compression, datetime)
```