-
Notifications
You must be signed in to change notification settings - Fork 903
/
unsupported_method_call_on_all.rs
80 lines (74 loc) · 1.99 KB
/
unsupported_method_call_on_all.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
use ruff_python_ast::{self as ast, Expr};
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_text_size::Ranged;
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
/// import sys
///
/// __all__ = ["A", "B"]
///
/// if sys.version_info >= (3, 10):
/// __all__.append("C")
///
/// if sys.version_info >= (3, 11):
/// __all__.remove("B")
/// ```
///
/// Use instead:
/// ```python
/// import sys
///
/// __all__ = ["A"]
///
/// if sys.version_info < (3, 11):
/// __all__ += ["B"]
///
/// if sys.version_info >= (3, 10):
/// __all__ += ["C"]
/// ```
#[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")
}