-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[
flake8-pyi
] Implement PYI056 (#5959)
## Summary Checks that `append`, `extend` and `remove` methods are not called on `__all__`. See [original implementation](https://github.com/PyCQA/flake8-pyi/blob/2a86db8271dc500247a8a69419536240334731cf/pyi.py#L1133-L1138). ``` $ flake8 --select Y026 crates/ruff/resources/test/fixtures/flake8_pyi/PYI056.pyi crates/ruff/resources/test/fixtures/flake8_pyi/PYI056.pyi:3:1: Y056 Calling ".append()" on "__all__" may not be supported by all type checkers (use += instead) crates/ruff/resources/test/fixtures/flake8_pyi/PYI056.pyi:4:1: Y056 Calling ".extend()" on "__all__" may not be supported by all type checkers (use += instead) crates/ruff/resources/test/fixtures/flake8_pyi/PYI056.pyi:5:1: Y056 Calling ".remove()" on "__all__" may not be supported by all type checkers (use += instead) ``` ``` $ ./target/debug/ruff --select PYI026 crates/ruff/resources/test/fixtures/flake8_pyi/PYI056.pyi --no-cache crates/ruff/resources/test/fixtures/flake8_pyi/PYI056.pyi:3:1: PYI056 Calling ".append()" on "__all__" may not be supported by all type checkers (use += instead) crates/ruff/resources/test/fixtures/flake8_pyi/PYI056.pyi:4:1: PYI056 Calling ".extend()" on "__all__" may not be supported by all type checkers (use += instead) crates/ruff/resources/test/fixtures/flake8_pyi/PYI056.pyi:5:1: PYI056 Calling ".remove()" on "__all__" may not be supported by all type checkers (use += instead) Found 3 errors. ``` ref #848 ## Test Plan Snapshots and manual runs of flake8.
- Loading branch information
1 parent
45318d0
commit 33657d3
Showing
10 changed files
with
134 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
__all__ = ["A", "B", "C"] | ||
|
||
# Errors | ||
__all__.append("D") | ||
__all__.extend(["E", "Foo"]) | ||
__all__.remove("A") | ||
|
||
# OK | ||
__all__ += ["D"] | ||
foo = ["Hello"] | ||
foo.append("World") | ||
foo.bar.append("World") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
__all__ = ["A", "B", "C"] | ||
|
||
# Errors | ||
__all__.append("D") | ||
__all__.extend(["E", "Foo"]) | ||
__all__.remove("A") | ||
|
||
# OK | ||
__all__ += ["D"] | ||
foo = ["Hello"] | ||
foo.append("World") | ||
foo.bar.append("World") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
65 changes: 65 additions & 0 deletions
65
crates/ruff/src/rules/flake8_pyi/rules/unsupported_method_call_on_all.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
use rustpython_parser::ast::{self, Expr, Ranged}; | ||
|
||
use ruff_diagnostics::{Diagnostic, Violation}; | ||
use ruff_macros::{derive_message_formats, violation}; | ||
|
||
use crate::checkers::ast::Checker; | ||
|
||
/// ## What it does | ||
/// Checks that `append`, `extend` and `remove` methods are not called on | ||
/// `__all__`. | ||
/// | ||
/// ## Why is this bad? | ||
/// Different type checkers have varying levels of support for calling these | ||
/// methods on `__all__`. Instead, use the `+=` operator to add items to | ||
/// `__all__`, which is known to be supported by all major type checkers. | ||
/// | ||
/// ## Example | ||
/// ```python | ||
/// __all__ = ["A"] | ||
/// __all__.append("B") | ||
/// ``` | ||
/// | ||
/// Use instead: | ||
/// ```python | ||
/// __all__ = ["A"] | ||
/// __all__ += "B" | ||
/// ``` | ||
#[violation] | ||
pub struct UnsupportedMethodCallOnAll { | ||
name: String, | ||
} | ||
|
||
impl Violation for UnsupportedMethodCallOnAll { | ||
#[derive_message_formats] | ||
fn message(&self) -> String { | ||
let UnsupportedMethodCallOnAll { name } = self; | ||
format!("Calling `.{name}()` on `__all__` may not be supported by all type checkers (use `+=` instead)") | ||
} | ||
} | ||
|
||
/// PYI056 | ||
pub(crate) fn unsupported_method_call_on_all(checker: &mut Checker, func: &Expr) { | ||
let Expr::Attribute(ast::ExprAttribute { value, attr, .. }) = func else { | ||
return; | ||
}; | ||
let Expr::Name(ast::ExprName { id, .. }) = value.as_ref() else { | ||
return; | ||
}; | ||
if id.as_str() != "__all__" { | ||
return; | ||
} | ||
if !is_unsupported_method(attr.as_str()) { | ||
return; | ||
} | ||
checker.diagnostics.push(Diagnostic::new( | ||
UnsupportedMethodCallOnAll { | ||
name: attr.to_string(), | ||
}, | ||
func.range(), | ||
)); | ||
} | ||
|
||
fn is_unsupported_method(name: &str) -> bool { | ||
matches!(name, "append" | "extend" | "remove") | ||
} |
4 changes: 4 additions & 0 deletions
4
...ruff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI056_PYI056.py.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
--- | ||
source: crates/ruff/src/rules/flake8_pyi/mod.rs | ||
--- | ||
|
32 changes: 32 additions & 0 deletions
32
...uff/src/rules/flake8_pyi/snapshots/ruff__rules__flake8_pyi__tests__PYI056_PYI056.pyi.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
--- | ||
source: crates/ruff/src/rules/flake8_pyi/mod.rs | ||
--- | ||
PYI056.pyi:4:1: PYI056 Calling `.append()` on `__all__` may not be supported by all type checkers (use `+=` instead) | ||
| | ||
3 | # Errors | ||
4 | __all__.append("D") | ||
| ^^^^^^^^^^^^^^ PYI056 | ||
5 | __all__.extend(["E", "Foo"]) | ||
6 | __all__.remove("A") | ||
| | ||
|
||
PYI056.pyi:5:1: PYI056 Calling `.extend()` on `__all__` may not be supported by all type checkers (use `+=` instead) | ||
| | ||
3 | # Errors | ||
4 | __all__.append("D") | ||
5 | __all__.extend(["E", "Foo"]) | ||
| ^^^^^^^^^^^^^^ PYI056 | ||
6 | __all__.remove("A") | ||
| | ||
|
||
PYI056.pyi:6:1: PYI056 Calling `.remove()` on `__all__` may not be supported by all type checkers (use `+=` instead) | ||
| | ||
4 | __all__.append("D") | ||
5 | __all__.extend(["E", "Foo"]) | ||
6 | __all__.remove("A") | ||
| ^^^^^^^^^^^^^^ PYI056 | ||
7 | | ||
8 | # OK | ||
| | ||
|
||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.