From fd3144a5f9319bf36228e05cab8a2f03acfcb3e8 Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Sat, 4 Nov 2023 22:13:19 -0700 Subject: [PATCH 1/5] Flag all comparisons against builtin types in E721 See #8483. Generalised fix on top of #8485 Based on the output of `print("\n".join(k for k, v in builtins.__dict__.items() if isinstance(v, type)))` --- .../pycodestyle/rules/type_comparison.rs | 96 +++++++++++++++++-- 1 file changed, 89 insertions(+), 7 deletions(-) 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 b5a5eb56d715b..30473f1720402 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/rules/type_comparison.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/rules/type_comparison.rs @@ -129,16 +129,98 @@ fn deprecated_type_comparison(checker: &mut Checker, compare: &ast::ExprCompare) // Ex) `type(obj) is int` if matches!( id.as_str(), - "int" - | "str" - | "float" - | "bool" - | "complex" + "bool" + | "bytearray" | "bytes" - | "list" + | "classmethod" + | "complex" | "dict" - | "set" + | "enumerate" + | "filter" + | "float" + | "frozenset" + | "int" + | "list" + | "map" | "memoryview" + | "object" + | "property" + | "range" + | "reversed" + | "set" + | "slice" + | "staticmethod" + | "str" + | "super" + | "tuple" + | "type" + | "zip" + | "ArithmeticError" + | "AssertionError" + | "AttributeError" + | "BaseException" + | "BlockingIOError" + | "BrokenPipeError" + | "BufferError" + | "BytesWarning" + | "ChildProcessError" + | "ConnectionAbortedError" + | "ConnectionError" + | "ConnectionRefusedError" + | "ConnectionResetError" + | "DeprecationWarning" + | "EnvironmentError" + | "EOFError" + | "Exception" + | "FileExistsError" + | "FileNotFoundError" + | "FloatingPointError" + | "FutureWarning" + | "GeneratorExit" + | "ImportError" + | "ImportWarning" + | "IndentationError" + | "IndexError" + | "InterruptedError" + | "IOError" + | "IsADirectoryError" + | "KeyboardInterrupt" + | "KeyError" + | "LookupError" + | "MemoryError" + | "ModuleNotFoundError" + | "NameError" + | "NotADirectoryError" + | "NotImplementedError" + | "OSError" + | "OverflowError" + | "PendingDeprecationWarning" + | "PermissionError" + | "ProcessLookupError" + | "RecursionError" + | "ReferenceError" + | "ResourceWarning" + | "RuntimeError" + | "RuntimeWarning" + | "StopAsyncIteration" + | "StopIteration" + | "SyntaxError" + | "SyntaxWarning" + | "SystemError" + | "SystemExit" + | "TabError" + | "TimeoutError" + | "TypeError" + | "UnboundLocalError" + | "UnicodeDecodeError" + | "UnicodeEncodeError" + | "UnicodeError" + | "UnicodeTranslateError" + | "UnicodeWarning" + | "UserWarning" + | "ValueError" + | "Warning" + | "ZeroDivisionError" ) && checker.semantic().is_builtin(id) { checker.diagnostics.push(Diagnostic::new( From 7dd66a0d18993653cfd036bfe11437a2ee88c85f Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Sat, 4 Nov 2023 22:53:08 -0700 Subject: [PATCH 2/5] . --- .../pycodestyle/rules/type_comparison.rs | 96 +++++++++++++++++-- 1 file changed, 89 insertions(+), 7 deletions(-) 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 30473f1720402..72a39ab9f07c9 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/rules/type_comparison.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/rules/type_comparison.rs @@ -280,16 +280,98 @@ fn is_type(expr: &Expr, semantic: &SemanticModel) -> bool { // Ex) `type(obj) == int` matches!( id.as_str(), - "int" - | "str" - | "float" - | "bool" - | "complex" + "bool" + | "bytearray" | "bytes" - | "list" + | "classmethod" + | "complex" | "dict" - | "set" + | "enumerate" + | "filter" + | "float" + | "frozenset" + | "int" + | "list" + | "map" | "memoryview" + | "object" + | "property" + | "range" + | "reversed" + | "set" + | "slice" + | "staticmethod" + | "str" + | "super" + | "tuple" + | "type" + | "zip" + | "ArithmeticError" + | "AssertionError" + | "AttributeError" + | "BaseException" + | "BlockingIOError" + | "BrokenPipeError" + | "BufferError" + | "BytesWarning" + | "ChildProcessError" + | "ConnectionAbortedError" + | "ConnectionError" + | "ConnectionRefusedError" + | "ConnectionResetError" + | "DeprecationWarning" + | "EnvironmentError" + | "EOFError" + | "Exception" + | "FileExistsError" + | "FileNotFoundError" + | "FloatingPointError" + | "FutureWarning" + | "GeneratorExit" + | "ImportError" + | "ImportWarning" + | "IndentationError" + | "IndexError" + | "InterruptedError" + | "IOError" + | "IsADirectoryError" + | "KeyboardInterrupt" + | "KeyError" + | "LookupError" + | "MemoryError" + | "ModuleNotFoundError" + | "NameError" + | "NotADirectoryError" + | "NotImplementedError" + | "OSError" + | "OverflowError" + | "PendingDeprecationWarning" + | "PermissionError" + | "ProcessLookupError" + | "RecursionError" + | "ReferenceError" + | "ResourceWarning" + | "RuntimeError" + | "RuntimeWarning" + | "StopAsyncIteration" + | "StopIteration" + | "SyntaxError" + | "SyntaxWarning" + | "SystemError" + | "SystemExit" + | "TabError" + | "TimeoutError" + | "TypeError" + | "UnboundLocalError" + | "UnicodeDecodeError" + | "UnicodeEncodeError" + | "UnicodeError" + | "UnicodeTranslateError" + | "UnicodeWarning" + | "UserWarning" + | "ValueError" + | "Warning" + | "ZeroDivisionError" ) && semantic.is_builtin(id) } _ => false, From f869ffabd6ad3082d9bfbc680d1f24e48fe92c90 Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Sat, 4 Nov 2023 22:54:34 -0700 Subject: [PATCH 3/5] . --- .../test/fixtures/pycodestyle/E721.py | 3 +++ .../pycodestyle/rules/type_comparison.rs | 2 -- ...les__pycodestyle__tests__E721_E721.py.snap | 20 +++++++++---------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/pycodestyle/E721.py b/crates/ruff_linter/resources/test/fixtures/pycodestyle/E721.py index 2c6ad7fcb9a1c..d29dbfb95ec9f 100644 --- a/crates/ruff_linter/resources/test/fixtures/pycodestyle/E721.py +++ b/crates/ruff_linter/resources/test/fixtures/pycodestyle/E721.py @@ -53,6 +53,9 @@ if isinstance(res, memoryview): pass #: Okay +if type(res) is type: + pass +#: Okay def func_histype(a, b, c): pass #: E722 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 72a39ab9f07c9..888d767267a55 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/rules/type_comparison.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/rules/type_comparison.rs @@ -153,7 +153,6 @@ fn deprecated_type_comparison(checker: &mut Checker, compare: &ast::ExprCompare) | "str" | "super" | "tuple" - | "type" | "zip" | "ArithmeticError" | "AssertionError" @@ -304,7 +303,6 @@ fn is_type(expr: &Expr, semantic: &SemanticModel) -> bool { | "str" | "super" | "tuple" - | "type" | "zip" | "ArithmeticError" | "AssertionError" 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 e0a5626238114..f06e35b3aa4ca 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 @@ -149,22 +149,22 @@ E721.py:41:8: E721 Do not compare types, use `isinstance()` 42 | #: | -E721.py:101:12: E721 Do not compare types, use `isinstance()` +E721.py:104:12: E721 Do not compare types, use `isinstance()` | - 99 | def asdf(self, value: str | None): -100 | #: E721 -101 | if type(value) is str: +102 | def asdf(self, value: str | None): +103 | #: E721 +104 | if type(value) is str: | ^^^^^^^^^^^^^^^^^^ E721 -102 | ... +105 | ... | -E721.py:111:12: E721 Do not compare types, use `isinstance()` +E721.py:114:12: E721 Do not compare types, use `isinstance()` | -109 | def asdf(self, value: str | None): -110 | #: E721 -111 | if type(value) is str: +112 | def asdf(self, value: str | None): +113 | #: E721 +114 | if type(value) is str: | ^^^^^^^^^^^^^^^^^^ E721 -112 | ... +115 | ... | From 2329326e02209e6562c14dc252288d8937cb29ad Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Sun, 5 Nov 2023 18:06:05 -0800 Subject: [PATCH 4/5] . --- .../test/fixtures/pycodestyle/E721.py | 3 + .../pycodestyle/rules/type_comparison.rs | 95 ++----------------- ...les__pycodestyle__tests__E721_E721.py.snap | 20 ++-- 3 files changed, 20 insertions(+), 98 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/pycodestyle/E721.py b/crates/ruff_linter/resources/test/fixtures/pycodestyle/E721.py index d29dbfb95ec9f..872fa7042aded 100644 --- a/crates/ruff_linter/resources/test/fixtures/pycodestyle/E721.py +++ b/crates/ruff_linter/resources/test/fixtures/pycodestyle/E721.py @@ -55,6 +55,9 @@ #: Okay if type(res) is type: pass +#: E721 +if type(res) == type: + pass #: Okay def func_histype(a, b, c): pass 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 888d767267a55..78f88ff5100c5 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/rules/type_comparison.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/rules/type_comparison.rs @@ -129,97 +129,16 @@ fn deprecated_type_comparison(checker: &mut Checker, compare: &ast::ExprCompare) // Ex) `type(obj) is int` if matches!( id.as_str(), - "bool" - | "bytearray" - | "bytes" - | "classmethod" - | "complex" - | "dict" - | "enumerate" - | "filter" + "int" + | "str" | "float" - | "frozenset" - | "int" + | "bool" + | "complex" + | "bytes" | "list" - | "map" - | "memoryview" - | "object" - | "property" - | "range" - | "reversed" + | "dict" | "set" - | "slice" - | "staticmethod" - | "str" - | "super" - | "tuple" - | "zip" - | "ArithmeticError" - | "AssertionError" - | "AttributeError" - | "BaseException" - | "BlockingIOError" - | "BrokenPipeError" - | "BufferError" - | "BytesWarning" - | "ChildProcessError" - | "ConnectionAbortedError" - | "ConnectionError" - | "ConnectionRefusedError" - | "ConnectionResetError" - | "DeprecationWarning" - | "EnvironmentError" - | "EOFError" - | "Exception" - | "FileExistsError" - | "FileNotFoundError" - | "FloatingPointError" - | "FutureWarning" - | "GeneratorExit" - | "ImportError" - | "ImportWarning" - | "IndentationError" - | "IndexError" - | "InterruptedError" - | "IOError" - | "IsADirectoryError" - | "KeyboardInterrupt" - | "KeyError" - | "LookupError" - | "MemoryError" - | "ModuleNotFoundError" - | "NameError" - | "NotADirectoryError" - | "NotImplementedError" - | "OSError" - | "OverflowError" - | "PendingDeprecationWarning" - | "PermissionError" - | "ProcessLookupError" - | "RecursionError" - | "ReferenceError" - | "ResourceWarning" - | "RuntimeError" - | "RuntimeWarning" - | "StopAsyncIteration" - | "StopIteration" - | "SyntaxError" - | "SyntaxWarning" - | "SystemError" - | "SystemExit" - | "TabError" - | "TimeoutError" - | "TypeError" - | "UnboundLocalError" - | "UnicodeDecodeError" - | "UnicodeEncodeError" - | "UnicodeError" - | "UnicodeTranslateError" - | "UnicodeWarning" - | "UserWarning" - | "ValueError" - | "Warning" - | "ZeroDivisionError" + | "memoryview" ) && checker.semantic().is_builtin(id) { checker.diagnostics.push(Diagnostic::new( 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 f06e35b3aa4ca..415b71d592217 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 @@ -149,22 +149,22 @@ E721.py:41:8: E721 Do not compare types, use `isinstance()` 42 | #: | -E721.py:104:12: E721 Do not compare types, use `isinstance()` +E721.py:107:12: E721 Do not compare types, use `isinstance()` | -102 | def asdf(self, value: str | None): -103 | #: E721 -104 | if type(value) is str: +105 | def asdf(self, value: str | None): +106 | #: E721 +107 | if type(value) is str: | ^^^^^^^^^^^^^^^^^^ E721 -105 | ... +108 | ... | -E721.py:114:12: E721 Do not compare types, use `isinstance()` +E721.py:117:12: E721 Do not compare types, use `isinstance()` | -112 | def asdf(self, value: str | None): -113 | #: E721 -114 | if type(value) is str: +115 | def asdf(self, value: str | None): +116 | #: E721 +117 | if type(value) is str: | ^^^^^^^^^^^^^^^^^^ E721 -115 | ... +118 | ... | From 256507e6965cda461b29b8e4d27058e43c64f697 Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Sun, 5 Nov 2023 18:10:59 -0800 Subject: [PATCH 5/5] . --- .../src/rules/pycodestyle/rules/type_comparison.rs | 1 + ...les__pycodestyle__tests__preview__E721_E721.py.snap | 10 ++++++++++ 2 files changed, 11 insertions(+) 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 78f88ff5100c5..598b9a9c11972 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/rules/type_comparison.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/rules/type_comparison.rs @@ -222,6 +222,7 @@ fn is_type(expr: &Expr, semantic: &SemanticModel) -> bool { | "str" | "super" | "tuple" + | "type" | "zip" | "ArithmeticError" | "AssertionError" 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 index cd70263e68075..8971d3f3ccf06 100644 --- 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 @@ -119,4 +119,14 @@ E721.py:41:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` 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 + | +