Compare commits
9 Commits
0.13.3
...
brent/new-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3d26e1a62 | ||
|
|
2caf2987c0 | ||
|
|
5dfc47ff3b | ||
|
|
20cbbf03b8 | ||
|
|
f707bf6cf8 | ||
|
|
2230ab07d0 | ||
|
|
3a779a237e | ||
|
|
cf0d026b41 | ||
|
|
1c5a9681a5 |
4
.github/workflows/ci.yaml
vendored
4
.github/workflows/ci.yaml
vendored
@@ -932,7 +932,7 @@ jobs:
|
||||
tool: cargo-codspeed
|
||||
|
||||
- name: "Build benchmarks"
|
||||
run: cargo codspeed build --features "codspeed,instrumented" --no-default-features -p ruff_benchmark --bench formatter --bench lexer --bench linter --bench parser
|
||||
run: cargo codspeed build --features "codspeed,instrumented" --no-default-features -p ruff_benchmark formatter lexer linter parser
|
||||
|
||||
- name: "Run benchmarks"
|
||||
uses: CodSpeedHQ/action@653fdc30e6c40ffd9739e40c8a0576f4f4523ca1 # v4.0.1
|
||||
@@ -967,7 +967,7 @@ jobs:
|
||||
tool: cargo-codspeed
|
||||
|
||||
- name: "Build benchmarks"
|
||||
run: cargo codspeed build --features "codspeed,instrumented" --no-default-features -p ruff_benchmark --bench ty
|
||||
run: cargo codspeed build --features "codspeed,instrumented" --no-default-features -p ruff_benchmark ty
|
||||
|
||||
- name: "Run benchmarks"
|
||||
uses: CodSpeedHQ/action@653fdc30e6c40ffd9739e40c8a0576f4f4523ca1 # v4.0.1
|
||||
|
||||
43
CHANGELOG.md
43
CHANGELOG.md
@@ -1,48 +1,5 @@
|
||||
# Changelog
|
||||
|
||||
## 0.13.3
|
||||
|
||||
Released on 2025-10-02.
|
||||
|
||||
### Preview features
|
||||
|
||||
- Display diffs for `ruff format --check` and add support for different output formats ([#20443](https://github.com/astral-sh/ruff/pull/20443))
|
||||
- \[`pyflakes`\] Handle some common submodule import situations for `unused-import` (`F401`) ([#20200](https://github.com/astral-sh/ruff/pull/20200))
|
||||
- \[`ruff`\] Do not flag `%r` + `repr()` combinations (`RUF065`) ([#20600](https://github.com/astral-sh/ruff/pull/20600))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- \[`cli`\] Add conflict between `--add-noqa` and `--diff` options ([#20642](https://github.com/astral-sh/ruff/pull/20642))
|
||||
- \[`pylint`\] Exempt required imports from `PLR0402` ([#20381](https://github.com/astral-sh/ruff/pull/20381))
|
||||
- \[`pylint`\] Fix missing `max-nested-blocks` in settings display ([#20574](https://github.com/astral-sh/ruff/pull/20574))
|
||||
- \[`pyupgrade`\] Prevent infinite loop with `I002` and `UP026` ([#20634](https://github.com/astral-sh/ruff/pull/20634))
|
||||
|
||||
### Rule changes
|
||||
|
||||
- \[`flake8-simplify`\] Improve help message clarity (`SIM105`) ([#20548](https://github.com/astral-sh/ruff/pull/20548))
|
||||
|
||||
### Documentation
|
||||
|
||||
- Add the *The Basics* title back to CONTRIBUTING.md ([#20624](https://github.com/astral-sh/ruff/pull/20624))
|
||||
- Fixed documentation for try_consider_else ([#20587](https://github.com/astral-sh/ruff/pull/20587))
|
||||
- \[`isort`\] Clarify dependency between `order-by-type` and `case-sensitive` settings ([#20559](https://github.com/astral-sh/ruff/pull/20559))
|
||||
- \[`pylint`\] Clarify fix safety to include left-hand hashability (`PLR6201`) ([#20518](https://github.com/astral-sh/ruff/pull/20518))
|
||||
|
||||
### Other changes
|
||||
|
||||
- \[`playground`\] Fix quick fixes for empty ranges in playground ([#20599](https://github.com/astral-sh/ruff/pull/20599))
|
||||
|
||||
### Contributors
|
||||
|
||||
- [@TaKO8Ki](https://github.com/TaKO8Ki)
|
||||
- [@ntBre](https://github.com/ntBre)
|
||||
- [@dylwil3](https://github.com/dylwil3)
|
||||
- [@MichaReiser](https://github.com/MichaReiser)
|
||||
- [@danparizher](https://github.com/danparizher)
|
||||
- [@LilMonk](https://github.com/LilMonk)
|
||||
- [@mgiovani](https://github.com/mgiovani)
|
||||
- [@IDrokin117](https://github.com/IDrokin117)
|
||||
|
||||
## 0.13.2
|
||||
|
||||
Released on 2025-09-25.
|
||||
|
||||
6
Cargo.lock
generated
6
Cargo.lock
generated
@@ -2738,7 +2738,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.13.3"
|
||||
version = "0.13.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argfile",
|
||||
@@ -2994,7 +2994,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_linter"
|
||||
version = "0.13.3"
|
||||
version = "0.13.2"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"anyhow",
|
||||
@@ -3348,7 +3348,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_wasm"
|
||||
version = "0.13.3"
|
||||
version = "0.13.2"
|
||||
dependencies = [
|
||||
"console_error_panic_hook",
|
||||
"console_log",
|
||||
|
||||
14
README.md
14
README.md
@@ -148,8 +148,8 @@ curl -LsSf https://astral.sh/ruff/install.sh | sh
|
||||
powershell -c "irm https://astral.sh/ruff/install.ps1 | iex"
|
||||
|
||||
# For a specific version.
|
||||
curl -LsSf https://astral.sh/ruff/0.13.3/install.sh | sh
|
||||
powershell -c "irm https://astral.sh/ruff/0.13.3/install.ps1 | iex"
|
||||
curl -LsSf https://astral.sh/ruff/0.13.2/install.sh | sh
|
||||
powershell -c "irm https://astral.sh/ruff/0.13.2/install.ps1 | iex"
|
||||
```
|
||||
|
||||
You can also install Ruff via [Homebrew](https://formulae.brew.sh/formula/ruff), [Conda](https://anaconda.org/conda-forge/ruff),
|
||||
@@ -182,7 +182,7 @@ Ruff can also be used as a [pre-commit](https://pre-commit.com/) hook via [`ruff
|
||||
```yaml
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: v0.13.3
|
||||
rev: v0.13.2
|
||||
hooks:
|
||||
# Run the linter.
|
||||
- id: ruff-check
|
||||
@@ -311,9 +311,11 @@ for more on the linting and formatting commands, respectively.
|
||||
isort, pyupgrade, and others. Regardless of the rule's origin, Ruff re-implements every rule in
|
||||
Rust as a first-party feature.
|
||||
|
||||
By default, Ruff enables Flake8's `F` rules, along with a subset of the `E` rules, omitting any
|
||||
stylistic rules that overlap with the use of a formatter, like `ruff format` or
|
||||
[Black](https://github.com/psf/black).
|
||||
By default, Ruff enables Flake8's `F` rules, along with a subset of the `E`
|
||||
rules, omitting any stylistic rules that overlap with the use of a formatter,
|
||||
like `ruff format` or [Black](https://github.com/psf/black). Ruff also enables
|
||||
`B012`, which corresponds to a `SyntaxWarning`, and `PYI057`, which flags
|
||||
usage of some long-deprecated APIs in the standard library.
|
||||
|
||||
If you're just getting started with Ruff, **the default rule set is a great place to start**: it
|
||||
catches a wide variety of common errors (like unused imports) with zero configuration.
|
||||
|
||||
@@ -31,7 +31,6 @@ extend-ignore-re = [
|
||||
"typ",
|
||||
# TODO: Remove this once the `TYP` redirects are removed from `rule_redirects.rs`
|
||||
"TYP",
|
||||
"ntBre"
|
||||
]
|
||||
|
||||
[default.extend-identifiers]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.13.3"
|
||||
version = "0.13.2"
|
||||
publish = true
|
||||
authors = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
|
||||
@@ -21,12 +21,13 @@ fn lint_select() {
|
||||
specific prefixes. `ignore` takes precedence over `select` if the
|
||||
same prefix appears in both.
|
||||
|
||||
Default value: ["E4", "E7", "E9", "F"]
|
||||
Default value: ["E4", "E7", "E9", "F", "B012", "PYI057"]
|
||||
Type: list[RuleSelector]
|
||||
Example usage:
|
||||
```toml
|
||||
# On top of the defaults (`E4`, E7`, `E9`, and `F`), enable flake8-bugbear (`B`) and flake8-quotes (`Q`).
|
||||
select = ["E4", "E7", "E9", "F", "B", "Q"]
|
||||
# On top of the defaults (`E4`, E7`, `E9`, `F`, `B012`, and `PYI057`),
|
||||
# enable flake8-bugbear (`B`) and flake8-quotes (`Q`).
|
||||
select = ["E4", "E7", "E9", "F", "PYI057", "B", "Q"]
|
||||
```
|
||||
|
||||
----- stderr -----
|
||||
@@ -43,10 +44,10 @@ fn lint_select_json() {
|
||||
----- stdout -----
|
||||
{
|
||||
"doc": "A list of rule codes or prefixes to enable. Prefixes can specify exact\nrules (like `F841`), entire categories (like `F`), or anything in\nbetween.\n\nWhen breaking ties between enabled and disabled rules (via `select` and\n`ignore`, respectively), more specific prefixes override less\nspecific prefixes. `ignore` takes precedence over `select` if the\nsame prefix appears in both.",
|
||||
"default": "[\"E4\", \"E7\", \"E9\", \"F\"]",
|
||||
"default": "[\"E4\", \"E7\", \"E9\", \"F\", \"B012\", \"PYI057\"]",
|
||||
"value_type": "list[RuleSelector]",
|
||||
"scope": null,
|
||||
"example": "# On top of the defaults (`E4`, E7`, `E9`, and `F`), enable flake8-bugbear (`B`) and flake8-quotes (`Q`).\nselect = [\"E4\", \"E7\", \"E9\", \"F\", \"B\", \"Q\"]",
|
||||
"example": "# On top of the defaults (`E4`, E7`, `E9`, `F`, `B012`, and `PYI057`),\n# enable flake8-bugbear (`B`) and flake8-quotes (`Q`).\nselect = [\"E4\", \"E7\", \"E9\", \"F\", \"PYI057\", \"B\", \"Q\"]",
|
||||
"deprecated": null
|
||||
}
|
||||
|
||||
|
||||
@@ -6595,3 +6595,38 @@ fn supported_file_extensions_preview_enabled() -> Result<()> {
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn default_rules() {
|
||||
let stdin = "\
|
||||
def f():
|
||||
try:
|
||||
from typing import ByteString as TypingByteString # PYI057
|
||||
from collections.abc import ByteString as CollectionsByteString # PYI057
|
||||
except:
|
||||
pass
|
||||
finally:
|
||||
return # B012
|
||||
";
|
||||
|
||||
assert_cmd_snapshot!(
|
||||
Command::new(get_cargo_bin(BIN_NAME))
|
||||
.args(["check", "--output-format=concise", "--no-cache", "--stdin-filename=test.py", "-"])
|
||||
.pass_stdin(stdin),
|
||||
@r"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
test.py:3:23: PYI057 Do not use `typing.ByteString`, which has unclear semantics and is deprecated
|
||||
test.py:3:37: F401 [*] `typing.ByteString` imported but unused
|
||||
test.py:4:32: PYI057 Do not use `collections.abc.ByteString`, which has unclear semantics and is deprecated
|
||||
test.py:4:46: F401 [*] `collections.abc.ByteString` imported but unused
|
||||
test.py:5:3: E722 Do not use bare `except`
|
||||
test.py:8:4: B012 `return` inside `finally` blocks cause exceptions to be silenced
|
||||
Found 6 errors.
|
||||
[*] 2 fixable with the `--fix` option.
|
||||
|
||||
----- stderr -----
|
||||
",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -65,6 +65,8 @@ file_resolver.project_root = "<temp_dir>/"
|
||||
linter.exclude = []
|
||||
linter.project_root = "<temp_dir>/"
|
||||
linter.rules.enabled = [
|
||||
jump-statement-in-finally (B012),
|
||||
byte-string-usage (PYI057),
|
||||
multiple-imports-on-one-line (E401),
|
||||
module-import-not-at-top-of-file (E402),
|
||||
multiple-statements-on-one-line-colon (E701),
|
||||
@@ -126,6 +128,8 @@ linter.rules.enabled = [
|
||||
raise-not-implemented (F901),
|
||||
]
|
||||
linter.rules.should_fix = [
|
||||
jump-statement-in-finally (B012),
|
||||
byte-string-usage (PYI057),
|
||||
multiple-imports-on-one-line (E401),
|
||||
module-import-not-at-top-of-file (E402),
|
||||
multiple-statements-on-one-line-colon (E701),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_linter"
|
||||
version = "0.13.3"
|
||||
version = "0.13.2"
|
||||
publish = false
|
||||
authors = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
|
||||
@@ -18,6 +18,9 @@ use crate::checkers::ast::Checker;
|
||||
/// `break`, `continue`, or `return` statement is reached in a `finally` block,
|
||||
/// any exception raised in the `try` or `except` blocks will be silenced.
|
||||
///
|
||||
/// [PEP 765](https://peps.python.org/pep-0765/) additionally made this a `SyntaxWarning` starting
|
||||
/// in Python 3.14. It may become a `SyntaxError` in the future.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def speed(distance, time):
|
||||
|
||||
@@ -11,20 +11,32 @@ use crate::{FixAvailability, Violation};
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// `ByteString` has been deprecated since Python 3.9 and will be removed in
|
||||
/// Python 3.14. The Python documentation recommends using either
|
||||
/// Python 3.17. The Python documentation recommends using either
|
||||
/// `collections.abc.Buffer` (or the `typing_extensions` backport
|
||||
/// on Python <3.12) or a union like `bytes | bytearray | memoryview` instead.
|
||||
/// on Python versions before 3.12) or a union like `bytes | bytearray | memoryview` instead.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// from typing import ByteString
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// On Python versions after 3.12, use the `Buffer` type from the standard library instead:
|
||||
/// ```python
|
||||
/// from collections.abc import Buffer
|
||||
/// ```
|
||||
///
|
||||
/// For earlier Python versions, you can use `typing_extensions`:
|
||||
/// ```python
|
||||
/// from typing_extensions import Buffer
|
||||
/// ```
|
||||
///
|
||||
/// or a union:
|
||||
/// ```python
|
||||
/// from typing import Union
|
||||
///
|
||||
/// x: Union[bytes, bytearray, memoryview]
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [Python documentation: The `ByteString` type](https://docs.python.org/3/library/typing.html#typing.ByteString)
|
||||
#[derive(ViolationMetadata)]
|
||||
|
||||
@@ -369,6 +369,17 @@ pub const DEFAULT_SELECTORS: &[RuleSelector] = &[
|
||||
prefix: RuleCodePrefix::Pycodestyle(codes::Pycodestyle::E9),
|
||||
redirected_from: None,
|
||||
},
|
||||
// Additionally include rules that will correspond to CPython errors in the future:
|
||||
// - B012 is a syntax warning in 3.14 and will become an error in the future
|
||||
// - PYI057 reports deprecated members of the standard library
|
||||
RuleSelector::Rule {
|
||||
prefix: RuleCodePrefix::Flake8Bugbear(codes::Flake8Bugbear::_012),
|
||||
redirected_from: None,
|
||||
},
|
||||
RuleSelector::Rule {
|
||||
prefix: RuleCodePrefix::Flake8Pyi(codes::Flake8Pyi::_057),
|
||||
redirected_from: None,
|
||||
},
|
||||
];
|
||||
|
||||
pub const TASK_TAGS: &[&str] = &["TODO", "FIXME", "XXX"];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_wasm"
|
||||
version = "0.13.3"
|
||||
version = "0.13.2"
|
||||
publish = false
|
||||
authors = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
|
||||
@@ -804,11 +804,12 @@ pub struct LintCommonOptions {
|
||||
/// specific prefixes. `ignore` takes precedence over `select` if the
|
||||
/// same prefix appears in both.
|
||||
#[option(
|
||||
default = r#"["E4", "E7", "E9", "F"]"#,
|
||||
default = r#"["E4", "E7", "E9", "F", "B012", "PYI057"]"#,
|
||||
value_type = "list[RuleSelector]",
|
||||
example = r#"
|
||||
# On top of the defaults (`E4`, E7`, `E9`, and `F`), enable flake8-bugbear (`B`) and flake8-quotes (`Q`).
|
||||
select = ["E4", "E7", "E9", "F", "B", "Q"]
|
||||
# On top of the defaults (`E4`, E7`, `E9`, `F`, `B012`, and `PYI057`),
|
||||
# enable flake8-bugbear (`B`) and flake8-quotes (`Q`).
|
||||
select = ["E4", "E7", "E9", "F", "PYI057", "B", "Q"]
|
||||
"#
|
||||
)]
|
||||
pub select: Option<Vec<RuleSelector>>,
|
||||
|
||||
@@ -139,7 +139,8 @@ reveal_type(f(A())) # revealed: A
|
||||
reveal_type(f(*(A(),))) # revealed: A
|
||||
|
||||
reveal_type(f(B())) # revealed: A
|
||||
reveal_type(f(*(B(),))) # revealed: A
|
||||
# TODO: revealed: A
|
||||
reveal_type(f(*(B(),))) # revealed: Unknown
|
||||
|
||||
# But, in this case, the arity check filters out the first overload, so we only have one match:
|
||||
reveal_type(f(B(), 1)) # revealed: B
|
||||
@@ -550,13 +551,16 @@ from overloaded import MyEnumSubclass, ActualEnum, f
|
||||
|
||||
def _(actual_enum: ActualEnum, my_enum_instance: MyEnumSubclass):
|
||||
reveal_type(f(actual_enum)) # revealed: Both
|
||||
reveal_type(f(*(actual_enum,))) # revealed: Both
|
||||
# TODO: revealed: Both
|
||||
reveal_type(f(*(actual_enum,))) # revealed: Unknown
|
||||
|
||||
reveal_type(f(ActualEnum.A)) # revealed: OnlyA
|
||||
reveal_type(f(*(ActualEnum.A,))) # revealed: OnlyA
|
||||
# TODO: revealed: OnlyA
|
||||
reveal_type(f(*(ActualEnum.A,))) # revealed: Unknown
|
||||
|
||||
reveal_type(f(ActualEnum.B)) # revealed: OnlyB
|
||||
reveal_type(f(*(ActualEnum.B,))) # revealed: OnlyB
|
||||
# TODO: revealed: OnlyB
|
||||
reveal_type(f(*(ActualEnum.B,))) # revealed: Unknown
|
||||
|
||||
reveal_type(f(my_enum_instance)) # revealed: MyEnumSubclass
|
||||
reveal_type(f(*(my_enum_instance,))) # revealed: MyEnumSubclass
|
||||
@@ -1093,10 +1097,12 @@ reveal_type(f(*(1,))) # revealed: str
|
||||
|
||||
def _(list_int: list[int], list_any: list[Any]):
|
||||
reveal_type(f(list_int)) # revealed: int
|
||||
reveal_type(f(*(list_int,))) # revealed: int
|
||||
# TODO: revealed: int
|
||||
reveal_type(f(*(list_int,))) # revealed: Unknown
|
||||
|
||||
reveal_type(f(list_any)) # revealed: int
|
||||
reveal_type(f(*(list_any,))) # revealed: int
|
||||
# TODO: revealed: int
|
||||
reveal_type(f(*(list_any,))) # revealed: Unknown
|
||||
```
|
||||
|
||||
### Single list argument (ambiguous)
|
||||
@@ -1130,7 +1136,8 @@ def _(list_int: list[int], list_any: list[Any]):
|
||||
# All materializations of `list[int]` are assignable to `list[int]`, so it matches the first
|
||||
# overload.
|
||||
reveal_type(f(list_int)) # revealed: int
|
||||
reveal_type(f(*(list_int,))) # revealed: int
|
||||
# TODO: revealed: int
|
||||
reveal_type(f(*(list_int,))) # revealed: Unknown
|
||||
|
||||
# All materializations of `list[Any]` are assignable to `list[int]` and `list[Any]`, but the
|
||||
# return type of first and second overloads are not equivalent, so the overload matching
|
||||
@@ -1163,21 +1170,25 @@ reveal_type(f("a")) # revealed: str
|
||||
reveal_type(f(*("a",))) # revealed: str
|
||||
|
||||
reveal_type(f((1, "b"))) # revealed: int
|
||||
reveal_type(f(*((1, "b"),))) # revealed: int
|
||||
# TODO: revealed: int
|
||||
reveal_type(f(*((1, "b"),))) # revealed: Unknown
|
||||
|
||||
reveal_type(f((1, 2))) # revealed: int
|
||||
reveal_type(f(*((1, 2),))) # revealed: int
|
||||
# TODO: revealed: int
|
||||
reveal_type(f(*((1, 2),))) # revealed: Unknown
|
||||
|
||||
def _(int_str: tuple[int, str], int_any: tuple[int, Any], any_any: tuple[Any, Any]):
|
||||
# All materializations are assignable to first overload, so second and third overloads are
|
||||
# eliminated
|
||||
reveal_type(f(int_str)) # revealed: int
|
||||
reveal_type(f(*(int_str,))) # revealed: int
|
||||
# TODO: revealed: int
|
||||
reveal_type(f(*(int_str,))) # revealed: Unknown
|
||||
|
||||
# All materializations are assignable to second overload, so the third overload is eliminated;
|
||||
# the return type of first and second overload is equivalent
|
||||
reveal_type(f(int_any)) # revealed: int
|
||||
reveal_type(f(*(int_any,))) # revealed: int
|
||||
# TODO: revealed: int
|
||||
reveal_type(f(*(int_any,))) # revealed: Unknown
|
||||
|
||||
# All materializations of `tuple[Any, Any]` are assignable to the parameters of all the
|
||||
# overloads, but the return types aren't equivalent, so the overload matching is ambiguous
|
||||
@@ -1255,22 +1266,26 @@ def _(list_int: list[int], list_any: list[Any], int_str: tuple[int, str], int_an
|
||||
# All materializations of both argument types are assignable to the first overload, so the
|
||||
# second and third overloads are filtered out
|
||||
reveal_type(f(list_int, int_str)) # revealed: A
|
||||
reveal_type(f(*(list_int, int_str))) # revealed: A
|
||||
# TODO: revealed: A
|
||||
reveal_type(f(*(list_int, int_str))) # revealed: Unknown
|
||||
|
||||
# All materialization of first argument is assignable to first overload and for the second
|
||||
# argument, they're assignable to the second overload, so the third overload is filtered out
|
||||
reveal_type(f(list_int, int_any)) # revealed: A
|
||||
reveal_type(f(*(list_int, int_any))) # revealed: A
|
||||
# TODO: revealed: A
|
||||
reveal_type(f(*(list_int, int_any))) # revealed: Unknown
|
||||
|
||||
# All materialization of first argument is assignable to second overload and for the second
|
||||
# argument, they're assignable to the first overload, so the third overload is filtered out
|
||||
reveal_type(f(list_any, int_str)) # revealed: A
|
||||
reveal_type(f(*(list_any, int_str))) # revealed: A
|
||||
# TODO: revealed: A
|
||||
reveal_type(f(*(list_any, int_str))) # revealed: Unknown
|
||||
|
||||
# All materializations of both arguments are assignable to the second overload, so the third
|
||||
# overload is filtered out
|
||||
reveal_type(f(list_any, int_any)) # revealed: A
|
||||
reveal_type(f(*(list_any, int_any))) # revealed: A
|
||||
# TODO: revealed: A
|
||||
reveal_type(f(*(list_any, int_any))) # revealed: Unknown
|
||||
|
||||
# All materializations of first argument is assignable to the second overload and for the second
|
||||
# argument, they're assignable to the third overload, so no overloads are filtered out; the
|
||||
@@ -1301,7 +1316,8 @@ from overloaded import f
|
||||
|
||||
def _(literal: LiteralString, string: str, any: Any):
|
||||
reveal_type(f(literal)) # revealed: LiteralString
|
||||
reveal_type(f(*(literal,))) # revealed: LiteralString
|
||||
# TODO: revealed: LiteralString
|
||||
reveal_type(f(*(literal,))) # revealed: Unknown
|
||||
|
||||
reveal_type(f(string)) # revealed: str
|
||||
reveal_type(f(*(string,))) # revealed: str
|
||||
@@ -1339,10 +1355,12 @@ from overloaded import f
|
||||
|
||||
def _(list_int: list[int], list_str: list[str], list_any: list[Any], any: Any):
|
||||
reveal_type(f(list_int)) # revealed: A
|
||||
reveal_type(f(*(list_int,))) # revealed: A
|
||||
# TODO: revealed: A
|
||||
reveal_type(f(*(list_int,))) # revealed: Unknown
|
||||
|
||||
reveal_type(f(list_str)) # revealed: str
|
||||
reveal_type(f(*(list_str,))) # revealed: str
|
||||
# TODO: Should be `str`
|
||||
reveal_type(f(*(list_str,))) # revealed: Unknown
|
||||
|
||||
reveal_type(f(list_any)) # revealed: Unknown
|
||||
reveal_type(f(*(list_any,))) # revealed: Unknown
|
||||
@@ -1543,10 +1561,12 @@ def _(any: Any):
|
||||
reveal_type(f(*(any,), flag=False)) # revealed: str
|
||||
|
||||
def _(args: tuple[Any, Literal[True]]):
|
||||
reveal_type(f(*args)) # revealed: int
|
||||
# TODO: revealed: int
|
||||
reveal_type(f(*args)) # revealed: Unknown
|
||||
|
||||
def _(args: tuple[Any, Literal[False]]):
|
||||
reveal_type(f(*args)) # revealed: str
|
||||
# TODO: revealed: str
|
||||
reveal_type(f(*args)) # revealed: Unknown
|
||||
```
|
||||
|
||||
### Argument type expansion
|
||||
|
||||
@@ -32,7 +32,7 @@ use crate::types::tuple::{TupleLength, TupleType};
|
||||
use crate::types::{
|
||||
BoundMethodType, ClassLiteral, DataclassParams, FieldInstance, KnownBoundMethodType,
|
||||
KnownClass, KnownInstanceType, MemberLookupPolicy, PropertyInstanceType, SpecialFormType,
|
||||
TrackedConstraintSet, TypeAliasType, TypeContext, TypeMapping, UnionBuilder, UnionType,
|
||||
TrackedConstraintSet, TypeAliasType, TypeContext, TypeMapping, UnionType,
|
||||
WrapperDescriptorKind, enums, ide_support, todo_type,
|
||||
};
|
||||
use ruff_db::diagnostic::{Annotation, Diagnostic, SubDiagnostic, SubDiagnosticSeverity};
|
||||
@@ -1588,14 +1588,6 @@ impl<'db> CallableBinding<'db> {
|
||||
arguments: &CallArguments<'_, 'db>,
|
||||
matching_overload_indexes: &[usize],
|
||||
) {
|
||||
// The maximum number of parameters across all the overloads that are being considered
|
||||
// for filtering.
|
||||
let max_parameter_count = matching_overload_indexes
|
||||
.iter()
|
||||
.map(|&index| self.overloads[index].signature.parameters().len())
|
||||
.max()
|
||||
.unwrap_or(0);
|
||||
|
||||
// These are the parameter indexes that matches the arguments that participate in the
|
||||
// filtering process.
|
||||
//
|
||||
@@ -1603,67 +1595,41 @@ impl<'db> CallableBinding<'db> {
|
||||
// gradual equivalent to the parameter types at the same index for other overloads.
|
||||
let mut participating_parameter_indexes = HashSet::new();
|
||||
|
||||
// The parameter types at each index for the first overload containing a parameter at
|
||||
// that index.
|
||||
let mut first_parameter_types: Vec<Option<Type<'db>>> = vec![None; max_parameter_count];
|
||||
|
||||
for argument_index in 0..arguments.len() {
|
||||
for overload_index in matching_overload_indexes {
|
||||
let overload = &self.overloads[*overload_index];
|
||||
for ¶meter_index in &overload.argument_matches[argument_index].parameters {
|
||||
// TODO: For an unannotated `self` / `cls` parameter, the type should be
|
||||
// `typing.Self` / `type[typing.Self]`
|
||||
let current_parameter_type = overload.signature.parameters()[parameter_index]
|
||||
.annotated_type()
|
||||
.unwrap_or(Type::unknown());
|
||||
let first_parameter_type = &mut first_parameter_types[parameter_index];
|
||||
if let Some(first_parameter_type) = first_parameter_type {
|
||||
if !first_parameter_type.is_equivalent_to(db, current_parameter_type) {
|
||||
participating_parameter_indexes.insert(parameter_index);
|
||||
}
|
||||
} else {
|
||||
*first_parameter_type = Some(current_parameter_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut union_argument_type_builders = std::iter::repeat_with(|| UnionBuilder::new(db))
|
||||
.take(max_parameter_count)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for (argument_index, argument_type) in arguments.iter_types().enumerate() {
|
||||
for overload_index in matching_overload_indexes {
|
||||
let overload = &self.overloads[*overload_index];
|
||||
for (parameter_index, variadic_argument_type) in
|
||||
overload.argument_matches[argument_index].iter()
|
||||
{
|
||||
if !participating_parameter_indexes.contains(¶meter_index) {
|
||||
continue;
|
||||
}
|
||||
union_argument_type_builders[parameter_index].add_in_place(
|
||||
variadic_argument_type
|
||||
.unwrap_or(argument_type)
|
||||
.top_materialization(db),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// These only contain the top materialized argument types for the corresponding
|
||||
// participating parameter indexes.
|
||||
let top_materialized_argument_type = Type::heterogeneous_tuple(
|
||||
db,
|
||||
union_argument_type_builders
|
||||
.into_iter()
|
||||
.filter_map(|builder| {
|
||||
if builder.is_empty() {
|
||||
None
|
||||
let mut top_materialized_argument_types = vec![];
|
||||
|
||||
for (argument_index, argument_type) in arguments.iter_types().enumerate() {
|
||||
let mut first_parameter_type: Option<Type<'db>> = None;
|
||||
let mut participating_parameter_index = None;
|
||||
|
||||
'overload: for overload_index in matching_overload_indexes {
|
||||
let overload = &self.overloads[*overload_index];
|
||||
for parameter_index in &overload.argument_matches[argument_index].parameters {
|
||||
// TODO: For an unannotated `self` / `cls` parameter, the type should be
|
||||
// `typing.Self` / `type[typing.Self]`
|
||||
let current_parameter_type = overload.signature.parameters()[*parameter_index]
|
||||
.annotated_type()
|
||||
.unwrap_or(Type::unknown());
|
||||
if let Some(first_parameter_type) = first_parameter_type {
|
||||
if !first_parameter_type.is_equivalent_to(db, current_parameter_type) {
|
||||
participating_parameter_index = Some(*parameter_index);
|
||||
break 'overload;
|
||||
}
|
||||
} else {
|
||||
Some(builder.build())
|
||||
first_parameter_type = Some(current_parameter_type);
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(parameter_index) = participating_parameter_index {
|
||||
participating_parameter_indexes.insert(parameter_index);
|
||||
top_materialized_argument_types.push(argument_type.top_materialization(db));
|
||||
}
|
||||
}
|
||||
|
||||
let top_materialized_argument_type =
|
||||
Type::heterogeneous_tuple(db, top_materialized_argument_types);
|
||||
|
||||
// A flag to indicate whether we've found the overload that makes the remaining overloads
|
||||
// unmatched for the given argument types.
|
||||
@@ -1674,22 +1640,15 @@ impl<'db> CallableBinding<'db> {
|
||||
self.overloads[*current_index].mark_as_unmatched_overload();
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut union_parameter_types = std::iter::repeat_with(|| UnionBuilder::new(db))
|
||||
.take(max_parameter_count)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// The number of parameters that have been skipped because they don't participate in
|
||||
// the filtering process. This is used to make sure the types are added to the
|
||||
// corresponding parameter index in `union_parameter_types`.
|
||||
let mut skipped_parameters = 0;
|
||||
|
||||
let mut parameter_types = Vec::with_capacity(arguments.len());
|
||||
for argument_index in 0..arguments.len() {
|
||||
// The parameter types at the current argument index.
|
||||
let mut current_parameter_types = vec![];
|
||||
for overload_index in &matching_overload_indexes[..=upto] {
|
||||
let overload = &self.overloads[*overload_index];
|
||||
for parameter_index in &overload.argument_matches[argument_index].parameters {
|
||||
if !participating_parameter_indexes.contains(parameter_index) {
|
||||
skipped_parameters += 1;
|
||||
// This parameter doesn't participate in the filtering process.
|
||||
continue;
|
||||
}
|
||||
// TODO: For an unannotated `self` / `cls` parameter, the type should be
|
||||
@@ -1705,24 +1664,17 @@ impl<'db> CallableBinding<'db> {
|
||||
parameter_type =
|
||||
parameter_type.apply_specialization(db, inherited_specialization);
|
||||
}
|
||||
union_parameter_types[parameter_index.saturating_sub(skipped_parameters)]
|
||||
.add_in_place(parameter_type);
|
||||
current_parameter_types.push(parameter_type);
|
||||
}
|
||||
}
|
||||
if current_parameter_types.is_empty() {
|
||||
continue;
|
||||
}
|
||||
parameter_types.push(UnionType::from_elements(db, current_parameter_types));
|
||||
}
|
||||
|
||||
let parameter_types = Type::heterogeneous_tuple(
|
||||
db,
|
||||
union_parameter_types.into_iter().filter_map(|builder| {
|
||||
if builder.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(builder.build())
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
if top_materialized_argument_type.is_assignable_to(db, parameter_types) {
|
||||
if top_materialized_argument_type
|
||||
.is_assignable_to(db, Type::heterogeneous_tuple(db, parameter_types))
|
||||
{
|
||||
filter_remaining_overloads = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,10 +51,12 @@ If left unspecified, Ruff's default configuration is equivalent to:
|
||||
target-version = "py39"
|
||||
|
||||
[tool.ruff.lint]
|
||||
# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default.
|
||||
# Enable Pyflakes (`F`), a subset of the pycodestyle (`E`) codes,
|
||||
# and a couple of other codes corresponding to CPython deprecations
|
||||
# and syntax warnings by default.
|
||||
# Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or
|
||||
# McCabe complexity (`C901`) by default.
|
||||
select = ["E4", "E7", "E9", "F"]
|
||||
select = ["E4", "E7", "E9", "F", "PYI057", "B012"]
|
||||
ignore = []
|
||||
|
||||
# Allow fix for all enabled rules (when `--fix`) is provided.
|
||||
|
||||
@@ -80,7 +80,7 @@ You can add the following configuration to `.gitlab-ci.yml` to run a `ruff forma
|
||||
stage: build
|
||||
interruptible: true
|
||||
image:
|
||||
name: ghcr.io/astral-sh/ruff:0.13.3-alpine
|
||||
name: ghcr.io/astral-sh/ruff:0.13.2-alpine
|
||||
before_script:
|
||||
- cd $CI_PROJECT_DIR
|
||||
- ruff --version
|
||||
@@ -106,7 +106,7 @@ Ruff can be used as a [pre-commit](https://pre-commit.com) hook via [`ruff-pre-c
|
||||
```yaml
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: v0.13.3
|
||||
rev: v0.13.2
|
||||
hooks:
|
||||
# Run the linter.
|
||||
- id: ruff-check
|
||||
@@ -119,7 +119,7 @@ To enable lint fixes, add the `--fix` argument to the lint hook:
|
||||
```yaml
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: v0.13.3
|
||||
rev: v0.13.2
|
||||
hooks:
|
||||
# Run the linter.
|
||||
- id: ruff-check
|
||||
@@ -133,7 +133,7 @@ To avoid running on Jupyter Notebooks, remove `jupyter` from the list of allowed
|
||||
```yaml
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: v0.13.3
|
||||
rev: v0.13.2
|
||||
hooks:
|
||||
# Run the linter.
|
||||
- id: ruff-check
|
||||
|
||||
@@ -369,7 +369,7 @@ This tutorial has focused on Ruff's command-line interface, but Ruff can also be
|
||||
```yaml
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: v0.13.3
|
||||
rev: v0.13.2
|
||||
hooks:
|
||||
# Run the linter.
|
||||
- id: ruff
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "maturin"
|
||||
|
||||
[project]
|
||||
name = "ruff"
|
||||
version = "0.13.3"
|
||||
version = "0.13.2"
|
||||
description = "An extremely fast Python linter and code formatter, written in Rust."
|
||||
authors = [{ name = "Astral Software Inc.", email = "hey@astral.sh" }]
|
||||
readme = "README.md"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "scripts"
|
||||
version = "0.13.3"
|
||||
version = "0.13.2"
|
||||
description = ""
|
||||
authors = ["Charles Marsh <charlie.r.marsh@gmail.com>"]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user