diff --git a/crates/ruff_linter/src/rules/pycodestyle/mod.rs b/crates/ruff_linter/src/rules/pycodestyle/mod.rs index dbb9a293b8735..3528436baa508 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/mod.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/mod.rs @@ -69,7 +69,6 @@ mod tests { } #[test_case(Rule::IsLiteral, Path::new("constant_literals.py"))] - #[test_case(Rule::TypeComparison, Path::new("E721.py"))] #[test_case(Rule::ModuleImportNotAtTopOfFile, Path::new("E402_2.py"))] #[test_case(Rule::RedundantBackslash, Path::new("E502.py"))] #[test_case(Rule::TooManyNewlinesAtEndOfFile, Path::new("W391_0.py"))] diff --git a/crates/ruff_linter/src/rules/pycodestyle/rules/type_comparison.rs b/crates/ruff_linter/src/rules/pycodestyle/rules/type_comparison.rs index e90c1f4d1f74a..da713b11e924a 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/rules/type_comparison.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/rules/type_comparison.rs @@ -7,7 +7,6 @@ use ruff_python_semantic::SemanticModel; use ruff_text_size::Ranged; use crate::checkers::ast::Checker; -use crate::settings::types::PreviewMode; /// ## What it does /// Checks for object type comparisons using `==` and other comparison @@ -37,119 +36,19 @@ use crate::settings::types::PreviewMode; /// pass /// ``` #[violation] -pub struct TypeComparison { - preview: PreviewMode, -} +pub struct TypeComparison; impl Violation for TypeComparison { #[derive_message_formats] fn message(&self) -> String { - match self.preview { - PreviewMode::Disabled => format!("Do not compare types, use `isinstance()`"), - PreviewMode::Enabled => format!( - "Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks" - ), - } + format!( + "Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks" + ) } } /// E721 pub(crate) fn type_comparison(checker: &mut Checker, compare: &ast::ExprCompare) { - match checker.settings.preview { - PreviewMode::Disabled => deprecated_type_comparison(checker, compare), - PreviewMode::Enabled => preview_type_comparison(checker, compare), - } -} - -fn deprecated_type_comparison(checker: &mut Checker, compare: &ast::ExprCompare) { - for ((left, right), op) in std::iter::once(compare.left.as_ref()) - .chain(compare.comparators.iter()) - .tuple_windows() - .zip(compare.ops.iter()) - { - if !matches!(op, CmpOp::Is | CmpOp::IsNot | CmpOp::Eq | CmpOp::NotEq) { - continue; - } - - // Left-hand side must be, e.g., `type(obj)`. - let Expr::Call(ast::ExprCall { func, .. }) = left else { - continue; - }; - - let semantic = checker.semantic(); - - if !semantic.match_builtin_expr(func, "type") { - continue; - } - - // Right-hand side must be, e.g., `type(1)` or `int`. - match right { - Expr::Call(ast::ExprCall { - func, arguments, .. - }) => { - // Ex) `type(obj) is type(1)` - if semantic.match_builtin_expr(func, "type") { - // Allow comparison for types which are not obvious. - if arguments - .args - .first() - .is_some_and(|arg| !arg.is_name_expr() && !arg.is_none_literal_expr()) - { - checker.diagnostics.push(Diagnostic::new( - TypeComparison { - preview: PreviewMode::Disabled, - }, - compare.range(), - )); - } - } - } - Expr::Attribute(ast::ExprAttribute { value, .. }) => { - // Ex) `type(obj) is types.NoneType` - if semantic - .resolve_qualified_name(value.as_ref()) - .is_some_and(|qualified_name| { - matches!(qualified_name.segments(), ["types", ..]) - }) - { - checker.diagnostics.push(Diagnostic::new( - TypeComparison { - preview: PreviewMode::Disabled, - }, - compare.range(), - )); - } - } - Expr::Name(ast::ExprName { id, .. }) => { - // Ex) `type(obj) is int` - if matches!( - id.as_str(), - "int" - | "str" - | "float" - | "bool" - | "complex" - | "bytes" - | "list" - | "dict" - | "set" - | "memoryview" - ) && semantic.has_builtin_binding(id) - { - checker.diagnostics.push(Diagnostic::new( - TypeComparison { - preview: PreviewMode::Disabled, - }, - compare.range(), - )); - } - } - _ => {} - } - } -} - -pub(crate) fn preview_type_comparison(checker: &mut Checker, compare: &ast::ExprCompare) { for (left, right) in std::iter::once(compare.left.as_ref()) .chain(compare.comparators.iter()) .tuple_windows() @@ -165,12 +64,9 @@ pub(crate) fn preview_type_comparison(checker: &mut Checker, compare: &ast::Expr } // Disallow the comparison. - checker.diagnostics.push(Diagnostic::new( - TypeComparison { - preview: PreviewMode::Enabled, - }, - compare.range(), - )); + checker + .diagnostics + .push(Diagnostic::new(TypeComparison, compare.range())); } } } diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E721_E721.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E721_E721.py.snap index a0592c9af8da7..749cc427ed7ac 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E721_E721.py.snap +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__E721_E721.py.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/rules/pycodestyle/mod.rs --- -E721.py:2:4: E721 Do not compare types, use `isinstance()` +E721.py:2:4: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks | 1 | #: E721 2 | if type(res) == type(42): @@ -10,7 +10,7 @@ E721.py:2:4: E721 Do not compare types, use `isinstance()` 4 | #: E721 | -E721.py:5:4: E721 Do not compare types, use `isinstance()` +E721.py:5:4: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks | 3 | pass 4 | #: E721 @@ -20,7 +20,7 @@ E721.py:5:4: E721 Do not compare types, use `isinstance()` 7 | #: E721 | -E721.py:8:4: E721 Do not compare types, use `isinstance()` +E721.py:8:4: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks | 6 | pass 7 | #: E721 @@ -30,17 +30,7 @@ E721.py:8:4: E721 Do not compare types, use `isinstance()` 10 | #: Okay | -E721.py:18:4: E721 Do not compare types, use `isinstance()` - | -16 | import types -17 | -18 | if type(res) is not types.ListType: - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ E721 -19 | pass -20 | #: E721 - | - -E721.py:21:8: E721 Do not compare types, use `isinstance()` +E721.py:21:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks | 19 | pass 20 | #: E721 @@ -50,7 +40,7 @@ E721.py:21:8: E721 Do not compare types, use `isinstance()` 23 | assert type(res) == type([]) | -E721.py:23:8: E721 Do not compare types, use `isinstance()` +E721.py:23:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks | 21 | assert type(res) == type(False) or type(res) == type(None) 22 | #: E721 @@ -60,7 +50,7 @@ E721.py:23:8: E721 Do not compare types, use `isinstance()` 25 | assert type(res) == type(()) | -E721.py:25:8: E721 Do not compare types, use `isinstance()` +E721.py:25:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks | 23 | assert type(res) == type([]) 24 | #: E721 @@ -70,7 +60,7 @@ E721.py:25:8: E721 Do not compare types, use `isinstance()` 27 | assert type(res) == type((0,)) | -E721.py:27:8: E721 Do not compare types, use `isinstance()` +E721.py:27:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks | 25 | assert type(res) == type(()) 26 | #: E721 @@ -80,7 +70,7 @@ E721.py:27:8: E721 Do not compare types, use `isinstance()` 29 | assert type(res) == type((0)) | -E721.py:29:8: E721 Do not compare types, use `isinstance()` +E721.py:29:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks | 27 | assert type(res) == type((0,)) 28 | #: E721 @@ -90,7 +80,7 @@ E721.py:29:8: E721 Do not compare types, use `isinstance()` 31 | assert type(res) != type((1, )) | -E721.py:31:8: E721 Do not compare types, use `isinstance()` +E721.py:31:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks | 29 | assert type(res) == type((0)) 30 | #: E721 @@ -100,27 +90,7 @@ E721.py:31:8: E721 Do not compare types, use `isinstance()` 33 | assert type(res) is type((1, )) | -E721.py:33:8: E721 Do not compare types, use `isinstance()` - | -31 | assert type(res) != type((1, )) -32 | #: Okay -33 | assert type(res) is type((1, )) - | ^^^^^^^^^^^^^^^^^^^^^^^^ E721 -34 | #: Okay -35 | assert type(res) is not type((1, )) - | - -E721.py:35:8: E721 Do not compare types, use `isinstance()` - | -33 | assert type(res) is type((1, )) -34 | #: Okay -35 | assert type(res) is not type((1, )) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ E721 -36 | #: E211 E721 -37 | assert type(res) == type ([2, ]) - | - -E721.py:37:8: E721 Do not compare types, use `isinstance()` +E721.py:37:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks | 35 | assert type(res) is not type((1, )) 36 | #: E211 E721 @@ -130,7 +100,7 @@ E721.py:37:8: E721 Do not compare types, use `isinstance()` 39 | assert type(res) == type( ( ) ) | -E721.py:39:8: E721 Do not compare types, use `isinstance()` +E721.py:39:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks | 37 | assert type(res) == type ([2, ]) 38 | #: E201 E201 E202 E721 @@ -140,7 +110,7 @@ E721.py:39:8: E721 Do not compare types, use `isinstance()` 41 | assert type(res) == type( (0, ) ) | -E721.py:41:8: E721 Do not compare types, use `isinstance()` +E721.py:41:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks | 39 | assert type(res) == type( ( ) ) 40 | #: E201 E202 E721 @@ -149,25 +119,26 @@ E721.py:41:8: E721 Do not compare types, use `isinstance()` 42 | #: | -E721.py:107:12: E721 Do not compare types, use `isinstance()` - | -105 | def asdf(self, value: str | None): -106 | #: E721 -107 | if type(value) is str: - | ^^^^^^^^^^^^^^^^^^ E721 -108 | ... - | +E721.py:59:4: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks + | +57 | pass +58 | #: E721 +59 | if type(res) == type: + | ^^^^^^^^^^^^^^^^^ E721 +60 | pass +61 | #: Okay + | -E721.py:117:12: E721 Do not compare types, use `isinstance()` +E721.py:140:1: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks | -115 | def asdf(self, value: str | None): -116 | #: E721 -117 | if type(value) is str: - | ^^^^^^^^^^^^^^^^^^ E721 -118 | ... +139 | #: E721 +140 | dtype == float + | ^^^^^^^^^^^^^^ E721 +141 | +142 | import builtins | -E721.py:144:4: E721 Do not compare types, use `isinstance()` +E721.py:144:4: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks | 142 | import builtins 143 | diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__preview__E721_E721.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__preview__E721_E721.py.snap deleted file mode 100644 index 749cc427ed7ac..0000000000000 --- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__preview__E721_E721.py.snap +++ /dev/null @@ -1,148 +0,0 @@ ---- -source: crates/ruff_linter/src/rules/pycodestyle/mod.rs ---- -E721.py:2:4: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks - | -1 | #: E721 -2 | if type(res) == type(42): - | ^^^^^^^^^^^^^^^^^^^^^ E721 -3 | pass -4 | #: E721 - | - -E721.py:5:4: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks - | -3 | pass -4 | #: E721 -5 | if type(res) != type(""): - | ^^^^^^^^^^^^^^^^^^^^^ E721 -6 | pass -7 | #: E721 - | - -E721.py:8:4: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks - | - 6 | pass - 7 | #: E721 - 8 | if type(res) == memoryview: - | ^^^^^^^^^^^^^^^^^^^^^^^ E721 - 9 | pass -10 | #: Okay - | - -E721.py:21:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks - | -19 | pass -20 | #: E721 -21 | assert type(res) == type(False) or type(res) == type(None) - | ^^^^^^^^^^^^^^^^^^^^^^^^ E721 -22 | #: E721 -23 | assert type(res) == type([]) - | - -E721.py:23:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks - | -21 | assert type(res) == type(False) or type(res) == type(None) -22 | #: E721 -23 | assert type(res) == type([]) - | ^^^^^^^^^^^^^^^^^^^^^ E721 -24 | #: E721 -25 | assert type(res) == type(()) - | - -E721.py:25:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks - | -23 | assert type(res) == type([]) -24 | #: E721 -25 | assert type(res) == type(()) - | ^^^^^^^^^^^^^^^^^^^^^ E721 -26 | #: E721 -27 | assert type(res) == type((0,)) - | - -E721.py:27:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks - | -25 | assert type(res) == type(()) -26 | #: E721 -27 | assert type(res) == type((0,)) - | ^^^^^^^^^^^^^^^^^^^^^^^ E721 -28 | #: E721 -29 | assert type(res) == type((0)) - | - -E721.py:29:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks - | -27 | assert type(res) == type((0,)) -28 | #: E721 -29 | assert type(res) == type((0)) - | ^^^^^^^^^^^^^^^^^^^^^^ E721 -30 | #: E721 -31 | assert type(res) != type((1, )) - | - -E721.py:31:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks - | -29 | assert type(res) == type((0)) -30 | #: E721 -31 | assert type(res) != type((1, )) - | ^^^^^^^^^^^^^^^^^^^^^^^^ E721 -32 | #: Okay -33 | assert type(res) is type((1, )) - | - -E721.py:37:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks - | -35 | assert type(res) is not type((1, )) -36 | #: E211 E721 -37 | assert type(res) == type ([2, ]) - | ^^^^^^^^^^^^^^^^^^^^^^^^^ E721 -38 | #: E201 E201 E202 E721 -39 | assert type(res) == type( ( ) ) - | - -E721.py:39:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks - | -37 | assert type(res) == type ([2, ]) -38 | #: E201 E201 E202 E721 -39 | assert type(res) == type( ( ) ) - | ^^^^^^^^^^^^^^^^^^^^^^^^ E721 -40 | #: E201 E202 E721 -41 | assert type(res) == type( (0, ) ) - | - -E721.py:41:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks - | -39 | assert type(res) == type( ( ) ) -40 | #: E201 E202 E721 -41 | assert type(res) == type( (0, ) ) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ E721 -42 | #: - | - -E721.py:59:4: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks - | -57 | pass -58 | #: E721 -59 | if type(res) == type: - | ^^^^^^^^^^^^^^^^^ E721 -60 | pass -61 | #: Okay - | - -E721.py:140:1: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks - | -139 | #: E721 -140 | dtype == float - | ^^^^^^^^^^^^^^ E721 -141 | -142 | import builtins - | - -E721.py:144:4: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks - | -142 | import builtins -143 | -144 | if builtins.type(res) == memoryview: # E721 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ E721 -145 | pass - |