Skip to content

Commit c9a283a

Browse files
augustelalandeMichaReiser
authored andcommitted
[pycodestyle] Remove deprecated functionality from type-comparison (E721) (astral-sh#11220)
## Summary Stabilizes `E721` behavior implemented in astral-sh#7905. The functionality change in `E721` was implemented in astral-sh#7905, released in [v0.1.2](https://github.com/astral-sh/ruff/releases/tag/v0.1.2). And seems functionally stable since astral-sh#9676, without an explicit release but would correspond to [v0.2.0](https://github.com/astral-sh/ruff/releases/tag/v0.2.0). So the deprecated functionally should be removable in the next minor release. resolves: astral-sh#6465
1 parent c54bf0c commit c9a283a

File tree

4 files changed

+35
-317
lines changed

4 files changed

+35
-317
lines changed

crates/ruff_linter/src/rules/pycodestyle/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ mod tests {
6969
}
7070

7171
#[test_case(Rule::IsLiteral, Path::new("constant_literals.py"))]
72-
#[test_case(Rule::TypeComparison, Path::new("E721.py"))]
7372
#[test_case(Rule::ModuleImportNotAtTopOfFile, Path::new("E402_2.py"))]
7473
#[test_case(Rule::RedundantBackslash, Path::new("E502.py"))]
7574
#[test_case(Rule::TooManyNewlinesAtEndOfFile, Path::new("W391_0.py"))]

crates/ruff_linter/src/rules/pycodestyle/rules/type_comparison.rs

Lines changed: 7 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ use ruff_python_semantic::SemanticModel;
77
use ruff_text_size::Ranged;
88

99
use crate::checkers::ast::Checker;
10-
use crate::settings::types::PreviewMode;
1110

1211
/// ## What it does
1312
/// Checks for object type comparisons using `==` and other comparison
@@ -37,119 +36,19 @@ use crate::settings::types::PreviewMode;
3736
/// pass
3837
/// ```
3938
#[violation]
40-
pub struct TypeComparison {
41-
preview: PreviewMode,
42-
}
39+
pub struct TypeComparison;
4340

4441
impl Violation for TypeComparison {
4542
#[derive_message_formats]
4643
fn message(&self) -> String {
47-
match self.preview {
48-
PreviewMode::Disabled => format!("Do not compare types, use `isinstance()`"),
49-
PreviewMode::Enabled => format!(
50-
"Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks"
51-
),
52-
}
44+
format!(
45+
"Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks"
46+
)
5347
}
5448
}
5549

5650
/// E721
5751
pub(crate) fn type_comparison(checker: &mut Checker, compare: &ast::ExprCompare) {
58-
match checker.settings.preview {
59-
PreviewMode::Disabled => deprecated_type_comparison(checker, compare),
60-
PreviewMode::Enabled => preview_type_comparison(checker, compare),
61-
}
62-
}
63-
64-
fn deprecated_type_comparison(checker: &mut Checker, compare: &ast::ExprCompare) {
65-
for ((left, right), op) in std::iter::once(compare.left.as_ref())
66-
.chain(compare.comparators.iter())
67-
.tuple_windows()
68-
.zip(compare.ops.iter())
69-
{
70-
if !matches!(op, CmpOp::Is | CmpOp::IsNot | CmpOp::Eq | CmpOp::NotEq) {
71-
continue;
72-
}
73-
74-
// Left-hand side must be, e.g., `type(obj)`.
75-
let Expr::Call(ast::ExprCall { func, .. }) = left else {
76-
continue;
77-
};
78-
79-
let semantic = checker.semantic();
80-
81-
if !semantic.match_builtin_expr(func, "type") {
82-
continue;
83-
}
84-
85-
// Right-hand side must be, e.g., `type(1)` or `int`.
86-
match right {
87-
Expr::Call(ast::ExprCall {
88-
func, arguments, ..
89-
}) => {
90-
// Ex) `type(obj) is type(1)`
91-
if semantic.match_builtin_expr(func, "type") {
92-
// Allow comparison for types which are not obvious.
93-
if arguments
94-
.args
95-
.first()
96-
.is_some_and(|arg| !arg.is_name_expr() && !arg.is_none_literal_expr())
97-
{
98-
checker.diagnostics.push(Diagnostic::new(
99-
TypeComparison {
100-
preview: PreviewMode::Disabled,
101-
},
102-
compare.range(),
103-
));
104-
}
105-
}
106-
}
107-
Expr::Attribute(ast::ExprAttribute { value, .. }) => {
108-
// Ex) `type(obj) is types.NoneType`
109-
if semantic
110-
.resolve_qualified_name(value.as_ref())
111-
.is_some_and(|qualified_name| {
112-
matches!(qualified_name.segments(), ["types", ..])
113-
})
114-
{
115-
checker.diagnostics.push(Diagnostic::new(
116-
TypeComparison {
117-
preview: PreviewMode::Disabled,
118-
},
119-
compare.range(),
120-
));
121-
}
122-
}
123-
Expr::Name(ast::ExprName { id, .. }) => {
124-
// Ex) `type(obj) is int`
125-
if matches!(
126-
id.as_str(),
127-
"int"
128-
| "str"
129-
| "float"
130-
| "bool"
131-
| "complex"
132-
| "bytes"
133-
| "list"
134-
| "dict"
135-
| "set"
136-
| "memoryview"
137-
) && semantic.has_builtin_binding(id)
138-
{
139-
checker.diagnostics.push(Diagnostic::new(
140-
TypeComparison {
141-
preview: PreviewMode::Disabled,
142-
},
143-
compare.range(),
144-
));
145-
}
146-
}
147-
_ => {}
148-
}
149-
}
150-
}
151-
152-
pub(crate) fn preview_type_comparison(checker: &mut Checker, compare: &ast::ExprCompare) {
15352
for (left, right) in std::iter::once(compare.left.as_ref())
15453
.chain(compare.comparators.iter())
15554
.tuple_windows()
@@ -165,12 +64,9 @@ pub(crate) fn preview_type_comparison(checker: &mut Checker, compare: &ast::Expr
16564
}
16665

16766
// Disallow the comparison.
168-
checker.diagnostics.push(Diagnostic::new(
169-
TypeComparison {
170-
preview: PreviewMode::Enabled,
171-
},
172-
compare.range(),
173-
));
67+
checker
68+
.diagnostics
69+
.push(Diagnostic::new(TypeComparison, compare.range()));
17470
}
17571
}
17672
}

crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E721_E721.py.snap

Lines changed: 28 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
source: crates/ruff_linter/src/rules/pycodestyle/mod.rs
33
---
4-
E721.py:2:4: E721 Do not compare types, use `isinstance()`
4+
E721.py:2:4: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks
55
|
66
1 | #: E721
77
2 | if type(res) == type(42):
@@ -10,7 +10,7 @@ E721.py:2:4: E721 Do not compare types, use `isinstance()`
1010
4 | #: E721
1111
|
1212

13-
E721.py:5:4: E721 Do not compare types, use `isinstance()`
13+
E721.py:5:4: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks
1414
|
1515
3 | pass
1616
4 | #: E721
@@ -20,7 +20,7 @@ E721.py:5:4: E721 Do not compare types, use `isinstance()`
2020
7 | #: E721
2121
|
2222

23-
E721.py:8:4: E721 Do not compare types, use `isinstance()`
23+
E721.py:8:4: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks
2424
|
2525
6 | pass
2626
7 | #: E721
@@ -30,17 +30,7 @@ E721.py:8:4: E721 Do not compare types, use `isinstance()`
3030
10 | #: Okay
3131
|
3232

33-
E721.py:18:4: E721 Do not compare types, use `isinstance()`
34-
|
35-
16 | import types
36-
17 |
37-
18 | if type(res) is not types.ListType:
38-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ E721
39-
19 | pass
40-
20 | #: E721
41-
|
42-
43-
E721.py:21:8: E721 Do not compare types, use `isinstance()`
33+
E721.py:21:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks
4434
|
4535
19 | pass
4636
20 | #: E721
@@ -50,7 +40,7 @@ E721.py:21:8: E721 Do not compare types, use `isinstance()`
5040
23 | assert type(res) == type([])
5141
|
5242

53-
E721.py:23:8: E721 Do not compare types, use `isinstance()`
43+
E721.py:23:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks
5444
|
5545
21 | assert type(res) == type(False) or type(res) == type(None)
5646
22 | #: E721
@@ -60,7 +50,7 @@ E721.py:23:8: E721 Do not compare types, use `isinstance()`
6050
25 | assert type(res) == type(())
6151
|
6252

63-
E721.py:25:8: E721 Do not compare types, use `isinstance()`
53+
E721.py:25:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks
6454
|
6555
23 | assert type(res) == type([])
6656
24 | #: E721
@@ -70,7 +60,7 @@ E721.py:25:8: E721 Do not compare types, use `isinstance()`
7060
27 | assert type(res) == type((0,))
7161
|
7262

73-
E721.py:27:8: E721 Do not compare types, use `isinstance()`
63+
E721.py:27:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks
7464
|
7565
25 | assert type(res) == type(())
7666
26 | #: E721
@@ -80,7 +70,7 @@ E721.py:27:8: E721 Do not compare types, use `isinstance()`
8070
29 | assert type(res) == type((0))
8171
|
8272

83-
E721.py:29:8: E721 Do not compare types, use `isinstance()`
73+
E721.py:29:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks
8474
|
8575
27 | assert type(res) == type((0,))
8676
28 | #: E721
@@ -90,7 +80,7 @@ E721.py:29:8: E721 Do not compare types, use `isinstance()`
9080
31 | assert type(res) != type((1, ))
9181
|
9282

93-
E721.py:31:8: E721 Do not compare types, use `isinstance()`
83+
E721.py:31:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks
9484
|
9585
29 | assert type(res) == type((0))
9686
30 | #: E721
@@ -100,27 +90,7 @@ E721.py:31:8: E721 Do not compare types, use `isinstance()`
10090
33 | assert type(res) is type((1, ))
10191
|
10292

103-
E721.py:33:8: E721 Do not compare types, use `isinstance()`
104-
|
105-
31 | assert type(res) != type((1, ))
106-
32 | #: Okay
107-
33 | assert type(res) is type((1, ))
108-
| ^^^^^^^^^^^^^^^^^^^^^^^^ E721
109-
34 | #: Okay
110-
35 | assert type(res) is not type((1, ))
111-
|
112-
113-
E721.py:35:8: E721 Do not compare types, use `isinstance()`
114-
|
115-
33 | assert type(res) is type((1, ))
116-
34 | #: Okay
117-
35 | assert type(res) is not type((1, ))
118-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ E721
119-
36 | #: E211 E721
120-
37 | assert type(res) == type ([2, ])
121-
|
122-
123-
E721.py:37:8: E721 Do not compare types, use `isinstance()`
93+
E721.py:37:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks
12494
|
12595
35 | assert type(res) is not type((1, ))
12696
36 | #: E211 E721
@@ -130,7 +100,7 @@ E721.py:37:8: E721 Do not compare types, use `isinstance()`
130100
39 | assert type(res) == type( ( ) )
131101
|
132102

133-
E721.py:39:8: E721 Do not compare types, use `isinstance()`
103+
E721.py:39:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks
134104
|
135105
37 | assert type(res) == type ([2, ])
136106
38 | #: E201 E201 E202 E721
@@ -140,7 +110,7 @@ E721.py:39:8: E721 Do not compare types, use `isinstance()`
140110
41 | assert type(res) == type( (0, ) )
141111
|
142112

143-
E721.py:41:8: E721 Do not compare types, use `isinstance()`
113+
E721.py:41:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks
144114
|
145115
39 | assert type(res) == type( ( ) )
146116
40 | #: E201 E202 E721
@@ -149,25 +119,26 @@ E721.py:41:8: E721 Do not compare types, use `isinstance()`
149119
42 | #:
150120
|
151121

152-
E721.py:107:12: E721 Do not compare types, use `isinstance()`
153-
|
154-
105 | def asdf(self, value: str | None):
155-
106 | #: E721
156-
107 | if type(value) is str:
157-
| ^^^^^^^^^^^^^^^^^^ E721
158-
108 | ...
159-
|
122+
E721.py:59:4: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks
123+
|
124+
57 | pass
125+
58 | #: E721
126+
59 | if type(res) == type:
127+
| ^^^^^^^^^^^^^^^^^ E721
128+
60 | pass
129+
61 | #: Okay
130+
|
160131

161-
E721.py:117:12: E721 Do not compare types, use `isinstance()`
132+
E721.py:140:1: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks
162133
|
163-
115 | def asdf(self, value: str | None):
164-
116 | #: E721
165-
117 | if type(value) is str:
166-
| ^^^^^^^^^^^^^^^^^^ E721
167-
118 | ...
134+
139 | #: E721
135+
140 | dtype == float
136+
| ^^^^^^^^^^^^^^ E721
137+
141 |
138+
142 | import builtins
168139
|
169140

170-
E721.py:144:4: E721 Do not compare types, use `isinstance()`
141+
E721.py:144:4: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks
171142
|
172143
142 | import builtins
173144
143 |

0 commit comments

Comments
 (0)