Skip to content

Commit 06825f2

Browse files
committed
Merge branch 'main' into dcreager/union-callables
* main: (53 commits) [syntax-errors] Tuple unpacking in `for` statement iterator clause before Python 3.9 (#16558) Ruff v0.10 Release (#16708) Add new `noqa` specification to the docs (#16703) describe requires-python fallback in docs (#16704) [red-knot] handle cycles in MRO/bases resolution (#16693) [red-knot] Auto generate statement nodes (#16645) [`pylint`] Better inference for `str.strip` (`PLE310`) (#16671) [`pylint`] Improve `repeated-equality-comparison` fix to use a `set` when all elements are hashable (`PLR1714`) (#16685) [`pylint`/`pep8-naming`] Check `__new__` argument name in `bad-staticmethod-argument` and not `invalid-first-argument-name-for-class-method` (`PLW0211`/`N804`) (#16676) [`flake8-pyi`] Stabilize fix for `unused-private-type-var` (`PYI018`) (#16682) [`flake8-bandit`] Deprecate `suspicious-xmle-tree-usage` (`S320`) (#16680) [`flake8-simplify`] Avoid double negation in fixes (`SIM103`) (#16684) [`pyupgrade`]: Improve diagnostic range for `redundant-open-mode` (`UP015`) (#16672) Consider all `TYPE_CHECKING` symbols for type-checking blocks (#16669) [`pep8-naming`]: Ignore methods decorated with `@typing.override` (`invalid-argument-name`) (#16667) Stabilize FURB169 preview behavior (#16666) [`pylint`] Detect invalid default value type for `os.environ.get` (`PLW1508`) (#16674) [`flake8-pytest-style`] Allow for loops with empty bodies (`PT012`, `PT031`) (#16678) [`pyupgrade`]: Deprecate `non-pep604-isinstance` (`UP038`) (#16681) [`flake8-type-checking`] Stabilize `runtime-cast-value` (`TC006`) (#16637) ...
2 parents 0bf32e3 + 2382fe1 commit 06825f2

File tree

194 files changed

+5885
-7404
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

194 files changed

+5885
-7404
lines changed

.github/workflows/build-docker.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ jobs:
163163
# Mapping of base image followed by a comma followed by one or more base tags (comma separated)
164164
# Note, org.opencontainers.image.version label will use the first base tag (use the most specific tag first)
165165
image-mapping:
166-
- alpine:3.20,alpine3.20,alpine
166+
- alpine:3.21,alpine3.21,alpine
167167
- debian:bookworm-slim,bookworm-slim,debian-slim
168168
- buildpack-deps:bookworm,bookworm,debian
169169
steps:

BREAKING_CHANGES.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,46 @@
11
# Breaking Changes
22

3+
## 0.10.0
4+
5+
- **Changes to how the Python version is inferred when a `target-version` is not specified** ([#16319](https://github.com/astral-sh/ruff/pull/16319))
6+
7+
In previous versions of Ruff, you could specify your Python version with:
8+
9+
- The `target-version` option in a `ruff.toml` file or the `[tool.ruff]` section of a pyproject.toml file.
10+
- The `project.requires-python` field in a `pyproject.toml` file with a `[tool.ruff]` section.
11+
12+
These options worked well in most cases, and are still recommended for fine control of the Python version. However, because of the way Ruff discovers config files, `pyproject.toml` files without a `[tool.ruff]` section would be ignored, including the `requires-python` setting. Ruff would then use the default Python version (3.9 as of this writing) instead, which is surprising when you've attempted to request another version.
13+
14+
In v0.10, config discovery has been updated to address this issue:
15+
16+
- If Ruff finds a `ruff.toml` file without a `target-version`, it will check
17+
for a `pyproject.toml` file in the same directory and respect its
18+
`requires-python` version, even if it does not contain a `[tool.ruff]`
19+
section.
20+
- If Ruff finds a user-level configuration, the `requires-python` field of the closest `pyproject.toml` in a parent directory will take precedence.
21+
- If there is no config file (`ruff.toml`or `pyproject.toml` with a
22+
`[tool.ruff]` section) in the directory of the file being checked, Ruff will
23+
search for the closest `pyproject.toml` in the parent directories and use its
24+
`requires-python` setting.
25+
26+
- **Updated `TYPE_CHECKING` behavior** ([#16669](https://github.com/astral-sh/ruff/pull/16669))
27+
28+
Previously, Ruff only recognized typechecking blocks that tested the `typing.TYPE_CHECKING` symbol. Now, Ruff recognizes any local variable named `TYPE_CHECKING`. This release also removes support for the legacy `if 0:` and `if False:` typechecking checks. Use a local `TYPE_CHECKING` variable instead.
29+
30+
- **More robust noqa parsing** ([#16483](https://github.com/astral-sh/ruff/pull/16483))
31+
32+
The syntax for both file-level and in-line suppression comments has been unified and made more robust to certain errors. In most cases, this will result in more suppression comments being read by Ruff, but there are a few instances where previously read comments will now log an error to the user instead. Please refer to the documentation on [_Error suppression_](https://docs.astral.sh/ruff/linter/#error-suppression) for the full specification.
33+
34+
- **Avoid unnecessary parentheses around with statements with a single context manager and a trailing comment** ([#14005](https://github.com/astral-sh/ruff/pull/14005))
35+
36+
This change fixes a bug in the formatter where it introduced unnecessary parentheses around with statements with a single context manager and a trailing comment. This change may result in a change in formatting for some users.
37+
38+
- **Bump alpine default tag to 3.21 for derived Docker images** ([#16456](https://github.com/astral-sh/ruff/pull/16456))
39+
40+
Alpine 3.21 was released in Dec 2024 and is used in the official Alpine-based Python images. Now the ruff:alpine image will use 3.21 instead of 3.20 and ruff:alpine3.20 will no longer be updated.
41+
42+
- **\[`unsafe-markup-use`\]: `RUF035` has been recoded to `S704`** ([#15957](https://github.com/astral-sh/ruff/pull/15957))
43+
344
## 0.9.0
445

546
Ruff now formats your code according to the 2025 style guide. As a result, your code might now get formatted differently. See the [changelog](./CHANGELOG.md#090) for a detailed list of changes.

CHANGELOG.md

Lines changed: 120 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,122 @@
11
# Changelog
22

3+
## 0.10.0
4+
5+
Check out the [blog post](https://astral.sh/blog/ruff-v0.10.0) for a migration guide and overview of the changes!
6+
7+
### Breaking changes
8+
9+
See also, the "Remapped rules" section which may result in disabled rules.
10+
11+
- **Changes to how the Python version is inferred when a `target-version` is not specified** ([#16319](https://github.com/astral-sh/ruff/pull/16319))
12+
13+
In previous versions of Ruff, you could specify your Python version with:
14+
15+
- The `target-version` option in a `ruff.toml` file or the `[tool.ruff]` section of a pyproject.toml file.
16+
- The `project.requires-python` field in a `pyproject.toml` file with a `[tool.ruff]` section.
17+
18+
These options worked well in most cases, and are still recommended for fine control of the Python version. However, because of the way Ruff discovers config files, `pyproject.toml` files without a `[tool.ruff]` section would be ignored, including the `requires-python` setting. Ruff would then use the default Python version (3.9 as of this writing) instead, which is surprising when you've attempted to request another version.
19+
20+
In v0.10, config discovery has been updated to address this issue:
21+
22+
- If Ruff finds a `ruff.toml` file without a `target-version`, it will check
23+
for a `pyproject.toml` file in the same directory and respect its
24+
`requires-python` version, even if it does not contain a `[tool.ruff]`
25+
section.
26+
- If Ruff finds a user-level configuration, the `requires-python` field of the closest `pyproject.toml` in a parent directory will take precedence.
27+
- If there is no config file (`ruff.toml`or `pyproject.toml` with a
28+
`[tool.ruff]` section) in the directory of the file being checked, Ruff will
29+
search for the closest `pyproject.toml` in the parent directories and use its
30+
`requires-python` setting.
31+
32+
- **Updated `TYPE_CHECKING` behavior** ([#16669](https://github.com/astral-sh/ruff/pull/16669))
33+
34+
Previously, Ruff only recognized typechecking blocks that tested the `typing.TYPE_CHECKING` symbol. Now, Ruff recognizes any local variable named `TYPE_CHECKING`. This release also removes support for the legacy `if 0:` and `if False:` typechecking checks. Use a local `TYPE_CHECKING` variable instead.
35+
36+
- **More robust noqa parsing** ([#16483](https://github.com/astral-sh/ruff/pull/16483))
37+
38+
The syntax for both file-level and in-line suppression comments has been unified and made more robust to certain errors. In most cases, this will result in more suppression comments being read by Ruff, but there are a few instances where previously read comments will now log an error to the user instead. Please refer to the documentation on [_Error suppression_](https://docs.astral.sh/ruff/linter/#error-suppression) for the full specification.
39+
40+
- **Avoid unnecessary parentheses around with statements with a single context manager and a trailing comment** ([#14005](https://github.com/astral-sh/ruff/pull/14005))
41+
42+
This change fixes a bug in the formatter where it introduced unnecessary parentheses around with statements with a single context manager and a trailing comment. This change may result in a change in formatting for some users.
43+
44+
- **Bump alpine default tag to 3.21 for derived Docker images** ([#16456](https://github.com/astral-sh/ruff/pull/16456))
45+
46+
Alpine 3.21 was released in Dec 2024 and is used in the official Alpine-based Python images. Now the ruff:alpine image will use 3.21 instead of 3.20 and ruff:alpine3.20 will no longer be updated.
47+
48+
### Deprecated Rules
49+
50+
The following rules have been deprecated:
51+
52+
- [`non-pep604-isinstance`](https://docs.astral.sh/ruff/rules/non-pep604-isinstance/) (`UP038`)
53+
- [`suspicious-xmle-tree-usage`](https://docs.astral.sh/ruff/rules/suspicious-xmle-tree-usage/) (`S320`)
54+
55+
### Remapped rules
56+
57+
The following rules have been remapped to new rule codes:
58+
59+
- \[`unsafe-markup-use`\]: `RUF035` to `S704`
60+
61+
### Stabilization
62+
63+
The following rules have been stabilized and are no longer in preview:
64+
65+
- [`batched-without-explicit-strict`](https://docs.astral.sh/ruff/rules/batched-without-explicit-strict) (`B911`)
66+
- [`unnecessary-dict-comprehension-for-iterable`](https://docs.astral.sh/ruff/rules/unnecessary-dict-comprehension-for-iterable) (`C420`)
67+
- [`datetime-min-max`](https://docs.astral.sh/ruff/rules/datetime-min-max) (`DTZ901`)
68+
- [`fast-api-unused-path-parameter`](https://docs.astral.sh/ruff/rules/fast-api-unused-path-parameter) (`FAST003`)
69+
- [`root-logger-call`](https://docs.astral.sh/ruff/rules/root-logger-call) (`LOG015`)
70+
- [`len-test`](https://docs.astral.sh/ruff/rules/len-test) (`PLC1802`)
71+
- [`shallow-copy-environ`](https://docs.astral.sh/ruff/rules/shallow-copy-environ) (`PLW1507`)
72+
- [`os-listdir`](https://docs.astral.sh/ruff/rules/os-listdir) (`PTH208`)
73+
- [`invalid-pathlib-with-suffix`](https://docs.astral.sh/ruff/rules/invalid-pathlib-with-suffix) (`PTH210`)
74+
- [`invalid-assert-message-literal-argument`](https://docs.astral.sh/ruff/rules/invalid-assert-message-literal-argument) (`RUF040`)
75+
- [`unnecessary-nested-literal`](https://docs.astral.sh/ruff/rules/unnecessary-nested-literal) (`RUF041`)
76+
- [`unnecessary-cast-to-int`](https://docs.astral.sh/ruff/rules/unnecessary-cast-to-int) (`RUF046`)
77+
- [`map-int-version-parsing`](https://docs.astral.sh/ruff/rules/map-int-version-parsing) (`RUF048`)
78+
- [`if-key-in-dict-del`](https://docs.astral.sh/ruff/rules/if-key-in-dict-del) (`RUF051`)
79+
- [`unsafe-markup-use`](https://docs.astral.sh/ruff/rules/unsafe-markup-use) (`S704`). This rule has also been renamed from `RUF035`.
80+
- [`split-static-string`](https://docs.astral.sh/ruff/rules/split-static-string) (`SIM905`)
81+
- [`runtime-cast-value`](https://docs.astral.sh/ruff/rules/runtime-cast-value) (`TC006`)
82+
- [`unquoted-type-alias`](https://docs.astral.sh/ruff/rules/unquoted-type-alias) (`TC007`)
83+
- [`non-pep646-unpack`](https://docs.astral.sh/ruff/rules/non-pep646-unpack) (`UP044`)
84+
85+
The following behaviors have been stabilized:
86+
87+
- [`bad-staticmethod-argument`](https://docs.astral.sh/ruff/rules/bad-staticmethod-argument/) (`PLW0211`) [`invalid-first-argument-name-for-class-method`](https://docs.astral.sh/ruff/rules/invalid-first-argument-name-for-class-method/) (`N804`): `__new__` methods are now no longer flagged by `invalid-first-argument-name-for-class-method` (`N804`) but instead by `bad-staticmethod-argument` (`PLW0211`)
88+
- [`bad-str-strip-call`](https://docs.astral.sh/ruff/rules/bad-str-strip-call/) (`PLE1310`): The rule now applies to objects which are known to have type `str` or `bytes`.
89+
- [`blanket-noqa`](https://docs.astral.sh/ruff/rules/blanket-noqa/) (`PGH004`): Also detect blanked file-level noqa comments (and not just line level comments).
90+
- [`custom-type-var-for-self`](https://docs.astral.sh/ruff/rules/custom-type-var-for-self/) (`PYI019`): More accurate detection of custom `TypeVars` replaceable by `Self`. The range of the diagnostic is now the full function header rather than just the return annotation.
91+
- [`invalid-argument-name`](https://docs.astral.sh/ruff/rules/invalid-argument-name/) (`N803`): Ignore argument names of functions decorated with `typing.override`
92+
- [`invalid-envvar-default`](https://docs.astral.sh/ruff/rules/invalid-envvar-default/) (`PLW1508`): Detect default value arguments to `os.environ.get` with invalid type.
93+
- [`pytest-raises-with-multiple-statements`](https://docs.astral.sh/ruff/rules/pytest-raises-with-multiple-statements/) (`PT012`) [`pytest-warns-with-multiple-statements`](https://docs.astral.sh/ruff/rules/pytest-warns-with-multiple-statements/) (`PT031`): Allow `for` statements with an empty body in `pytest.raises` and `pytest.warns` `with` statements.
94+
- [`redundant-open-modes`](https://docs.astral.sh/ruff/rules/redundant-open-modes/) (`UP015`): The diagnostic range is now the range of the redundant mode argument where it previously was the range of the entire open call. You may have to replace your `noqa` comments when suppressing `UP015`.
95+
- [`stdlib-module-shadowing`](https://docs.astral.sh/ruff/rules/stdlib-module-shadowing/) (`A005`): Changes the default value of `lint.flake8-builtins.strict-checking` from `true` to `false`.
96+
- [`type-none-comparison`](https://docs.astral.sh/ruff/rules/type-none-comparison/) (`FURB169`): Now also recognizes `type(expr) is type(None)` comparisons where `expr` isn't a name expression.
97+
98+
The following fixes or improvements to fixes have been stabilized:
99+
100+
- [`repeated-equality-comparison`](https://docs.astral.sh/ruff/rules/repeated-equality-comparison/) (`PLR1714`) ([#16685](https://github.com/astral-sh/ruff/pull/16685))
101+
- [`needless-bool`](https://docs.astral.sh/ruff/rules/needless-bool/) (`SIM103`) ([#16684](https://github.com/astral-sh/ruff/pull/16684))
102+
- [`unused-private-type-var`](https://docs.astral.sh/ruff/rules/unused-private-type-var/) (`PYI018`) ([#16682](https://github.com/astral-sh/ruff/pull/16682))
103+
104+
### Server
105+
106+
- Remove logging output for `ruff.printDebugInformation` ([#16617](https://github.com/astral-sh/ruff/pull/16617))
107+
108+
### Configuration
109+
110+
- \[`flake8-builtins`\] Deprecate the `builtins-` prefixed options in favor of the unprefixed options (e.g. `builtins-allowed-modules` is now deprecated in favor of `allowed-modules`) ([#16092](https://github.com/astral-sh/ruff/pull/16092))
111+
112+
### Bug fixes
113+
114+
- [flake8-bandit] Fix mixed-case hash algorithm names (S324) ([#16552](https://github.com/astral-sh/ruff/pull/16552))
115+
116+
### CLI
117+
118+
- [ruff] Fix `last_tag`/`commits_since_last_tag` for `version` command ([#16686](https://github.com/astral-sh/ruff/pull/16686))
119+
3120
## 0.9.10
4121

5122
### Preview features
@@ -1331,7 +1448,7 @@ The following fixes have been stabilized:
13311448

13321449
## 0.5.6
13331450

1334-
Ruff 0.5.6 automatically enables linting and formatting of notebooks in *preview mode*.
1451+
Ruff 0.5.6 automatically enables linting and formatting of notebooks in _preview mode_.
13351452
You can opt-out of this behavior by adding `*.ipynb` to the `extend-exclude` setting.
13361453

13371454
```toml
@@ -2084,7 +2201,7 @@ To setup `ruff server` with your editor, refer to the [README.md](https://github
20842201

20852202
### Server
20862203

2087-
*This section is devoted to updates for our new language server, written in Rust.*
2204+
_This section is devoted to updates for our new language server, written in Rust._
20882205

20892206
- Enable ruff-specific source actions ([#10916](https://github.com/astral-sh/ruff/pull/10916))
20902207
- Refreshes diagnostics for open files when file configuration is changed ([#10988](https://github.com/astral-sh/ruff/pull/10988))
@@ -3491,7 +3608,7 @@ Read Ruff's new [versioning policy](https://docs.astral.sh/ruff/versioning/).
34913608
- \[`refurb`\] Add `single-item-membership-test` (`FURB171`) ([#7815](https://github.com/astral-sh/ruff/pull/7815))
34923609
- \[`pylint`\] Add `and-or-ternary` (`R1706`) ([#7811](https://github.com/astral-sh/ruff/pull/7811))
34933610

3494-
*New rules are added in [preview](https://docs.astral.sh/ruff/preview/).*
3611+
_New rules are added in [preview](https://docs.astral.sh/ruff/preview/)._
34953612

34963613
### Configuration
34973614

Cargo.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,8 @@ curl -LsSf https://astral.sh/ruff/install.sh | sh
149149
powershell -c "irm https://astral.sh/ruff/install.ps1 | iex"
150150

151151
# For a specific version.
152-
curl -LsSf https://astral.sh/ruff/0.9.10/install.sh | sh
153-
powershell -c "irm https://astral.sh/ruff/0.9.10/install.ps1 | iex"
152+
curl -LsSf https://astral.sh/ruff/0.10.0/install.sh | sh
153+
powershell -c "irm https://astral.sh/ruff/0.10.0/install.ps1 | iex"
154154
```
155155

156156
You can also install Ruff via [Homebrew](https://formulae.brew.sh/formula/ruff), [Conda](https://anaconda.org/conda-forge/ruff),
@@ -183,7 +183,7 @@ Ruff can also be used as a [pre-commit](https://pre-commit.com/) hook via [`ruff
183183
```yaml
184184
- repo: https://github.com/astral-sh/ruff-pre-commit
185185
# Ruff version.
186-
rev: v0.9.10
186+
rev: v0.10.0
187187
hooks:
188188
# Run the linter.
189189
- id: ruff
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Running `mypy_primer`
2+
3+
## Basics
4+
5+
For now, we use our own [fork of mypy primer]. It can be run using `uvx --from "…" mypy_primer`. For example, to see the help message, run:
6+
7+
```sh
8+
uvx --from "git+https://github.com/astral-sh/mypy_primer.git@add-red-knot-support" mypy_primer -h
9+
```
10+
11+
Alternatively, you can install the forked version of `mypy_primer` using:
12+
13+
```sh
14+
uv tool install "git+https://github.com/astral-sh/mypy_primer.git@add-red-knot-support"
15+
```
16+
17+
and then run it using `uvx mypy_primer` or just `mypy_primer`, if your `PATH` is set up accordingly (see: [Tool executables]).
18+
19+
## Showing the diagnostics diff between two Git revisions
20+
21+
To show the diagnostics diff between two Git revisions (e.g. your feature branch and `main`), run:
22+
23+
```sh
24+
mypy_primer \
25+
--type-checker knot \
26+
--old origin/main \
27+
--new my/feature \
28+
--debug \
29+
--output concise \
30+
--project-selector '/black$'
31+
```
32+
33+
This will show the diagnostics diff for the `black` project between the `main` branch and your `my/feature` branch. To run the
34+
diff for all projects, you currently need to copy the project-selector regex from the CI pipeline in `.github/workflows/mypy_primer.yaml`.
35+
36+
You can also take a look at the [full list of ecosystem projects]. Note that some of them might still need a `knot_paths` configuration
37+
option to work correctly.
38+
39+
## Avoiding recompilation
40+
41+
If you want to run `mypy_primer` repeatedly, e.g. for different projects, but for the same combination of `--old` and `--new`, you
42+
can use set the `MYPY_PRIMER_NO_REBUILD` environment variable to avoid recompilation of Red Knot:
43+
44+
```sh
45+
MYPY_PRIMER_NO_REBUILD=1 mypy_primer …
46+
```
47+
48+
## Running from a local copy of the repository
49+
50+
If you are working on a local branch, you can use `mypy_primer`'s `--repo` option to specify the path to your local copy of the `ruff` repository.
51+
This allows `mypy_primer` to check out local branches:
52+
53+
```sh
54+
mypy_primer --repo /path/to/ruff --old origin/main --new my/local-branch …
55+
```
56+
57+
Note that you might need to clean up `/tmp/mypy_primer` in order for this to work correctly.
58+
59+
[fork of mypy primer]: https://github.com/astral-sh/mypy_primer/tree/add-red-knot-support
60+
[full list of ecosystem projects]: https://github.com/astral-sh/mypy_primer/blob/add-red-knot-support/mypy_primer/projects.py
61+
[tool executables]: https://docs.astral.sh/uv/concepts/tools/#tool-executables

crates/red_knot_python_semantic/resources/mdtest/generics/classes.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ class Sub(Base[Sub]): ...
162162
reveal_type(Sub) # revealed: Literal[Sub]
163163
```
164164

165+
A similar case can work in a non-stub file, if forward references are stringified:
166+
165167
`string_annotation.py`:
166168

167169
```py
@@ -174,6 +176,8 @@ class Sub(Base["Sub"]): ...
174176
reveal_type(Sub) # revealed: Literal[Sub]
175177
```
176178

179+
In a non-stub file, without stringified forward references, this raises a `NameError`:
180+
177181
`bare_annotation.py`:
178182

179183
```py
@@ -184,5 +188,13 @@ class Base[T]: ...
184188
class Sub(Base[Sub]): ...
185189
```
186190

191+
## Another cyclic case
192+
193+
```pyi
194+
# TODO no error (generics)
195+
# error: [invalid-base]
196+
class Derived[T](list[Derived[T]]): ...
197+
```
198+
187199
[crtp]: https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
188200
[f-bound]: https://en.wikipedia.org/wiki/Bounded_quantification#F-bounded_quantification

0 commit comments

Comments
 (0)