From c98d8a040fbcd3428f1b0189ebdc9fbb8183b215 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Wed, 26 Jun 2024 11:49:01 -0400 Subject: [PATCH] [`pyflakes`] Stabilize detection of is comparisons to lists, etc. (`F632`) (#12049) ## Summary See: https://github.com/astral-sh/ruff/pull/8607. Rare but uncontroversial. --- .../ruff_linter/src/rules/pycodestyle/mod.rs | 1 - ...pycodestyle__tests__constant_literals.snap | 372 ++++++++++++++ ...s__preview__F632_constant_literals.py.snap | 481 ------------------ .../rules/invalid_literal_comparisons.rs | 27 +- 4 files changed, 384 insertions(+), 497 deletions(-) delete mode 100644 crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__preview__F632_constant_literals.py.snap diff --git a/crates/ruff_linter/src/rules/pycodestyle/mod.rs b/crates/ruff_linter/src/rules/pycodestyle/mod.rs index 08b7a4d3a3456..c220c24a61681 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/mod.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/mod.rs @@ -68,7 +68,6 @@ mod tests { Ok(()) } - #[test_case(Rule::IsLiteral, Path::new("constant_literals.py"))] #[test_case(Rule::RedundantBackslash, Path::new("E502.py"))] #[test_case(Rule::TooManyNewlinesAtEndOfFile, Path::new("W391_0.py"))] #[test_case(Rule::TooManyNewlinesAtEndOfFile, Path::new("W391_1.py"))] diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__constant_literals.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__constant_literals.snap index 23cbd094618d0..83478872dfd16 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__constant_literals.snap +++ b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__constant_literals.snap @@ -187,3 +187,375 @@ constant_literals.py:16:4: E712 [*] Avoid equality comparisons to `False`; use ` 17 17 | pass 18 18 | 19 19 | named_var = [] + +constant_literals.py:20:4: F632 [*] Use `==` to compare constant literals + | +19 | named_var = [] +20 | if [] is []: # F632 (fix) + | ^^^^^^^^ F632 +21 | pass +22 | if named_var is []: # F632 (fix) + | + = help: Replace `is` with `==` + +ℹ Safe fix +17 17 | pass +18 18 | +19 19 | named_var = [] +20 |-if [] is []: # F632 (fix) + 20 |+if [] == []: # F632 (fix) +21 21 | pass +22 22 | if named_var is []: # F632 (fix) +23 23 | pass + +constant_literals.py:22:4: F632 [*] Use `==` to compare constant literals + | +20 | if [] is []: # F632 (fix) +21 | pass +22 | if named_var is []: # F632 (fix) + | ^^^^^^^^^^^^^^^ F632 +23 | pass +24 | if [] is named_var: # F632 (fix) + | + = help: Replace `is` with `==` + +ℹ Safe fix +19 19 | named_var = [] +20 20 | if [] is []: # F632 (fix) +21 21 | pass +22 |-if named_var is []: # F632 (fix) + 22 |+if named_var == []: # F632 (fix) +23 23 | pass +24 24 | if [] is named_var: # F632 (fix) +25 25 | pass + +constant_literals.py:24:4: F632 [*] Use `==` to compare constant literals + | +22 | if named_var is []: # F632 (fix) +23 | pass +24 | if [] is named_var: # F632 (fix) + | ^^^^^^^^^^^^^^^ F632 +25 | pass +26 | if named_var is [1]: # F632 (fix) + | + = help: Replace `is` with `==` + +ℹ Safe fix +21 21 | pass +22 22 | if named_var is []: # F632 (fix) +23 23 | pass +24 |-if [] is named_var: # F632 (fix) + 24 |+if [] == named_var: # F632 (fix) +25 25 | pass +26 26 | if named_var is [1]: # F632 (fix) +27 27 | pass + +constant_literals.py:26:4: F632 [*] Use `==` to compare constant literals + | +24 | if [] is named_var: # F632 (fix) +25 | pass +26 | if named_var is [1]: # F632 (fix) + | ^^^^^^^^^^^^^^^^ F632 +27 | pass +28 | if [1] is named_var: # F632 (fix) + | + = help: Replace `is` with `==` + +ℹ Safe fix +23 23 | pass +24 24 | if [] is named_var: # F632 (fix) +25 25 | pass +26 |-if named_var is [1]: # F632 (fix) + 26 |+if named_var == [1]: # F632 (fix) +27 27 | pass +28 28 | if [1] is named_var: # F632 (fix) +29 29 | pass + +constant_literals.py:28:4: F632 [*] Use `==` to compare constant literals + | +26 | if named_var is [1]: # F632 (fix) +27 | pass +28 | if [1] is named_var: # F632 (fix) + | ^^^^^^^^^^^^^^^^ F632 +29 | pass +30 | if named_var is [i for i in [1]]: # F632 (fix) + | + = help: Replace `is` with `==` + +ℹ Safe fix +25 25 | pass +26 26 | if named_var is [1]: # F632 (fix) +27 27 | pass +28 |-if [1] is named_var: # F632 (fix) + 28 |+if [1] == named_var: # F632 (fix) +29 29 | pass +30 30 | if named_var is [i for i in [1]]: # F632 (fix) +31 31 | pass + +constant_literals.py:30:4: F632 [*] Use `==` to compare constant literals + | +28 | if [1] is named_var: # F632 (fix) +29 | pass +30 | if named_var is [i for i in [1]]: # F632 (fix) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ F632 +31 | pass + | + = help: Replace `is` with `==` + +ℹ Safe fix +27 27 | pass +28 28 | if [1] is named_var: # F632 (fix) +29 29 | pass +30 |-if named_var is [i for i in [1]]: # F632 (fix) + 30 |+if named_var == [i for i in [1]]: # F632 (fix) +31 31 | pass +32 32 | +33 33 | named_var = {} + +constant_literals.py:34:4: F632 [*] Use `==` to compare constant literals + | +33 | named_var = {} +34 | if {} is {}: # F632 (fix) + | ^^^^^^^^ F632 +35 | pass +36 | if named_var is {}: # F632 (fix) + | + = help: Replace `is` with `==` + +ℹ Safe fix +31 31 | pass +32 32 | +33 33 | named_var = {} +34 |-if {} is {}: # F632 (fix) + 34 |+if {} == {}: # F632 (fix) +35 35 | pass +36 36 | if named_var is {}: # F632 (fix) +37 37 | pass + +constant_literals.py:36:4: F632 [*] Use `==` to compare constant literals + | +34 | if {} is {}: # F632 (fix) +35 | pass +36 | if named_var is {}: # F632 (fix) + | ^^^^^^^^^^^^^^^ F632 +37 | pass +38 | if {} is named_var: # F632 (fix) + | + = help: Replace `is` with `==` + +ℹ Safe fix +33 33 | named_var = {} +34 34 | if {} is {}: # F632 (fix) +35 35 | pass +36 |-if named_var is {}: # F632 (fix) + 36 |+if named_var == {}: # F632 (fix) +37 37 | pass +38 38 | if {} is named_var: # F632 (fix) +39 39 | pass + +constant_literals.py:38:4: F632 [*] Use `==` to compare constant literals + | +36 | if named_var is {}: # F632 (fix) +37 | pass +38 | if {} is named_var: # F632 (fix) + | ^^^^^^^^^^^^^^^ F632 +39 | pass +40 | if named_var is {1}: # F632 (fix) + | + = help: Replace `is` with `==` + +ℹ Safe fix +35 35 | pass +36 36 | if named_var is {}: # F632 (fix) +37 37 | pass +38 |-if {} is named_var: # F632 (fix) + 38 |+if {} == named_var: # F632 (fix) +39 39 | pass +40 40 | if named_var is {1}: # F632 (fix) +41 41 | pass + +constant_literals.py:40:4: F632 [*] Use `==` to compare constant literals + | +38 | if {} is named_var: # F632 (fix) +39 | pass +40 | if named_var is {1}: # F632 (fix) + | ^^^^^^^^^^^^^^^^ F632 +41 | pass +42 | if {1} is named_var: # F632 (fix) + | + = help: Replace `is` with `==` + +ℹ Safe fix +37 37 | pass +38 38 | if {} is named_var: # F632 (fix) +39 39 | pass +40 |-if named_var is {1}: # F632 (fix) + 40 |+if named_var == {1}: # F632 (fix) +41 41 | pass +42 42 | if {1} is named_var: # F632 (fix) +43 43 | pass + +constant_literals.py:42:4: F632 [*] Use `==` to compare constant literals + | +40 | if named_var is {1}: # F632 (fix) +41 | pass +42 | if {1} is named_var: # F632 (fix) + | ^^^^^^^^^^^^^^^^ F632 +43 | pass +44 | if named_var is {i for i in [1]}: # F632 (fix) + | + = help: Replace `is` with `==` + +ℹ Safe fix +39 39 | pass +40 40 | if named_var is {1}: # F632 (fix) +41 41 | pass +42 |-if {1} is named_var: # F632 (fix) + 42 |+if {1} == named_var: # F632 (fix) +43 43 | pass +44 44 | if named_var is {i for i in [1]}: # F632 (fix) +45 45 | pass + +constant_literals.py:44:4: F632 [*] Use `==` to compare constant literals + | +42 | if {1} is named_var: # F632 (fix) +43 | pass +44 | if named_var is {i for i in [1]}: # F632 (fix) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ F632 +45 | pass + | + = help: Replace `is` with `==` + +ℹ Safe fix +41 41 | pass +42 42 | if {1} is named_var: # F632 (fix) +43 43 | pass +44 |-if named_var is {i for i in [1]}: # F632 (fix) + 44 |+if named_var == {i for i in [1]}: # F632 (fix) +45 45 | pass +46 46 | +47 47 | named_var = {1: 1} + +constant_literals.py:48:4: F632 [*] Use `==` to compare constant literals + | +47 | named_var = {1: 1} +48 | if {1: 1} is {1: 1}: # F632 (fix) + | ^^^^^^^^^^^^^^^^ F632 +49 | pass +50 | if named_var is {1: 1}: # F632 (fix) + | + = help: Replace `is` with `==` + +ℹ Safe fix +45 45 | pass +46 46 | +47 47 | named_var = {1: 1} +48 |-if {1: 1} is {1: 1}: # F632 (fix) + 48 |+if {1: 1} == {1: 1}: # F632 (fix) +49 49 | pass +50 50 | if named_var is {1: 1}: # F632 (fix) +51 51 | pass + +constant_literals.py:50:4: F632 [*] Use `==` to compare constant literals + | +48 | if {1: 1} is {1: 1}: # F632 (fix) +49 | pass +50 | if named_var is {1: 1}: # F632 (fix) + | ^^^^^^^^^^^^^^^^^^^ F632 +51 | pass +52 | if {1: 1} is named_var: # F632 (fix) + | + = help: Replace `is` with `==` + +ℹ Safe fix +47 47 | named_var = {1: 1} +48 48 | if {1: 1} is {1: 1}: # F632 (fix) +49 49 | pass +50 |-if named_var is {1: 1}: # F632 (fix) + 50 |+if named_var == {1: 1}: # F632 (fix) +51 51 | pass +52 52 | if {1: 1} is named_var: # F632 (fix) +53 53 | pass + +constant_literals.py:52:4: F632 [*] Use `==` to compare constant literals + | +50 | if named_var is {1: 1}: # F632 (fix) +51 | pass +52 | if {1: 1} is named_var: # F632 (fix) + | ^^^^^^^^^^^^^^^^^^^ F632 +53 | pass +54 | if named_var is {1: 1}: # F632 (fix) + | + = help: Replace `is` with `==` + +ℹ Safe fix +49 49 | pass +50 50 | if named_var is {1: 1}: # F632 (fix) +51 51 | pass +52 |-if {1: 1} is named_var: # F632 (fix) + 52 |+if {1: 1} == named_var: # F632 (fix) +53 53 | pass +54 54 | if named_var is {1: 1}: # F632 (fix) +55 55 | pass + +constant_literals.py:54:4: F632 [*] Use `==` to compare constant literals + | +52 | if {1: 1} is named_var: # F632 (fix) +53 | pass +54 | if named_var is {1: 1}: # F632 (fix) + | ^^^^^^^^^^^^^^^^^^^ F632 +55 | pass +56 | if {1: 1} is named_var: # F632 (fix) + | + = help: Replace `is` with `==` + +ℹ Safe fix +51 51 | pass +52 52 | if {1: 1} is named_var: # F632 (fix) +53 53 | pass +54 |-if named_var is {1: 1}: # F632 (fix) + 54 |+if named_var == {1: 1}: # F632 (fix) +55 55 | pass +56 56 | if {1: 1} is named_var: # F632 (fix) +57 57 | pass + +constant_literals.py:56:4: F632 [*] Use `==` to compare constant literals + | +54 | if named_var is {1: 1}: # F632 (fix) +55 | pass +56 | if {1: 1} is named_var: # F632 (fix) + | ^^^^^^^^^^^^^^^^^^^ F632 +57 | pass +58 | if named_var is {i: 1 for i in [1]}: # F632 (fix) + | + = help: Replace `is` with `==` + +ℹ Safe fix +53 53 | pass +54 54 | if named_var is {1: 1}: # F632 (fix) +55 55 | pass +56 |-if {1: 1} is named_var: # F632 (fix) + 56 |+if {1: 1} == named_var: # F632 (fix) +57 57 | pass +58 58 | if named_var is {i: 1 for i in [1]}: # F632 (fix) +59 59 | pass + +constant_literals.py:58:4: F632 [*] Use `==` to compare constant literals + | +56 | if {1: 1} is named_var: # F632 (fix) +57 | pass +58 | if named_var is {i: 1 for i in [1]}: # F632 (fix) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ F632 +59 | pass + | + = help: Replace `is` with `==` + +ℹ Safe fix +55 55 | pass +56 56 | if {1: 1} is named_var: # F632 (fix) +57 57 | pass +58 |-if named_var is {i: 1 for i in [1]}: # F632 (fix) + 58 |+if named_var == {i: 1 for i in [1]}: # F632 (fix) +59 59 | pass +60 60 | +61 61 | ### diff --git a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__preview__F632_constant_literals.py.snap b/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__preview__F632_constant_literals.py.snap deleted file mode 100644 index fb6fc26d24c06..0000000000000 --- a/crates/ruff_linter/src/rules/pycodestyle/snapshots/ruff_linter__rules__pycodestyle__tests__preview__F632_constant_literals.py.snap +++ /dev/null @@ -1,481 +0,0 @@ ---- -source: crates/ruff_linter/src/rules/pycodestyle/mod.rs ---- -constant_literals.py:4:4: F632 [*] Use `==` to compare constant literals - | -2 | # Errors -3 | ### -4 | if "abc" is "def": # F632 (fix) - | ^^^^^^^^^^^^^^ F632 -5 | pass -6 | if "abc" is None: # F632 (fix, but leaves behind unfixable E711) - | - = help: Replace `is` with `==` - -ℹ Safe fix -1 1 | ### -2 2 | # Errors -3 3 | ### -4 |-if "abc" is "def": # F632 (fix) - 4 |+if "abc" == "def": # F632 (fix) -5 5 | pass -6 6 | if "abc" is None: # F632 (fix, but leaves behind unfixable E711) -7 7 | pass - -constant_literals.py:6:4: F632 [*] Use `==` to compare constant literals - | -4 | if "abc" is "def": # F632 (fix) -5 | pass -6 | if "abc" is None: # F632 (fix, but leaves behind unfixable E711) - | ^^^^^^^^^^^^^ F632 -7 | pass -8 | if None is "abc": # F632 (fix, but leaves behind unfixable E711) - | - = help: Replace `is` with `==` - -ℹ Safe fix -3 3 | ### -4 4 | if "abc" is "def": # F632 (fix) -5 5 | pass -6 |-if "abc" is None: # F632 (fix, but leaves behind unfixable E711) - 6 |+if "abc" == None: # F632 (fix, but leaves behind unfixable E711) -7 7 | pass -8 8 | if None is "abc": # F632 (fix, but leaves behind unfixable E711) -9 9 | pass - -constant_literals.py:8:4: F632 [*] Use `==` to compare constant literals - | - 6 | if "abc" is None: # F632 (fix, but leaves behind unfixable E711) - 7 | pass - 8 | if None is "abc": # F632 (fix, but leaves behind unfixable E711) - | ^^^^^^^^^^^^^ F632 - 9 | pass -10 | if "abc" is False: # F632 (fix, but leaves behind unfixable E712) - | - = help: Replace `is` with `==` - -ℹ Safe fix -5 5 | pass -6 6 | if "abc" is None: # F632 (fix, but leaves behind unfixable E711) -7 7 | pass -8 |-if None is "abc": # F632 (fix, but leaves behind unfixable E711) - 8 |+if None == "abc": # F632 (fix, but leaves behind unfixable E711) -9 9 | pass -10 10 | if "abc" is False: # F632 (fix, but leaves behind unfixable E712) -11 11 | pass - -constant_literals.py:10:4: F632 [*] Use `==` to compare constant literals - | - 8 | if None is "abc": # F632 (fix, but leaves behind unfixable E711) - 9 | pass -10 | if "abc" is False: # F632 (fix, but leaves behind unfixable E712) - | ^^^^^^^^^^^^^^ F632 -11 | pass -12 | if False is "abc": # F632 (fix, but leaves behind unfixable E712) - | - = help: Replace `is` with `==` - -ℹ Safe fix -7 7 | pass -8 8 | if None is "abc": # F632 (fix, but leaves behind unfixable E711) -9 9 | pass -10 |-if "abc" is False: # F632 (fix, but leaves behind unfixable E712) - 10 |+if "abc" == False: # F632 (fix, but leaves behind unfixable E712) -11 11 | pass -12 12 | if False is "abc": # F632 (fix, but leaves behind unfixable E712) -13 13 | pass - -constant_literals.py:12:4: F632 [*] Use `==` to compare constant literals - | -10 | if "abc" is False: # F632 (fix, but leaves behind unfixable E712) -11 | pass -12 | if False is "abc": # F632 (fix, but leaves behind unfixable E712) - | ^^^^^^^^^^^^^^ F632 -13 | pass -14 | if False == None: # E711, E712 (fix) - | - = help: Replace `is` with `==` - -ℹ Safe fix -9 9 | pass -10 10 | if "abc" is False: # F632 (fix, but leaves behind unfixable E712) -11 11 | pass -12 |-if False is "abc": # F632 (fix, but leaves behind unfixable E712) - 12 |+if False == "abc": # F632 (fix, but leaves behind unfixable E712) -13 13 | pass -14 14 | if False == None: # E711, E712 (fix) -15 15 | pass - -constant_literals.py:20:4: F632 [*] Use `==` to compare constant literals - | -19 | named_var = [] -20 | if [] is []: # F632 (fix) - | ^^^^^^^^ F632 -21 | pass -22 | if named_var is []: # F632 (fix) - | - = help: Replace `is` with `==` - -ℹ Safe fix -17 17 | pass -18 18 | -19 19 | named_var = [] -20 |-if [] is []: # F632 (fix) - 20 |+if [] == []: # F632 (fix) -21 21 | pass -22 22 | if named_var is []: # F632 (fix) -23 23 | pass - -constant_literals.py:22:4: F632 [*] Use `==` to compare constant literals - | -20 | if [] is []: # F632 (fix) -21 | pass -22 | if named_var is []: # F632 (fix) - | ^^^^^^^^^^^^^^^ F632 -23 | pass -24 | if [] is named_var: # F632 (fix) - | - = help: Replace `is` with `==` - -ℹ Safe fix -19 19 | named_var = [] -20 20 | if [] is []: # F632 (fix) -21 21 | pass -22 |-if named_var is []: # F632 (fix) - 22 |+if named_var == []: # F632 (fix) -23 23 | pass -24 24 | if [] is named_var: # F632 (fix) -25 25 | pass - -constant_literals.py:24:4: F632 [*] Use `==` to compare constant literals - | -22 | if named_var is []: # F632 (fix) -23 | pass -24 | if [] is named_var: # F632 (fix) - | ^^^^^^^^^^^^^^^ F632 -25 | pass -26 | if named_var is [1]: # F632 (fix) - | - = help: Replace `is` with `==` - -ℹ Safe fix -21 21 | pass -22 22 | if named_var is []: # F632 (fix) -23 23 | pass -24 |-if [] is named_var: # F632 (fix) - 24 |+if [] == named_var: # F632 (fix) -25 25 | pass -26 26 | if named_var is [1]: # F632 (fix) -27 27 | pass - -constant_literals.py:26:4: F632 [*] Use `==` to compare constant literals - | -24 | if [] is named_var: # F632 (fix) -25 | pass -26 | if named_var is [1]: # F632 (fix) - | ^^^^^^^^^^^^^^^^ F632 -27 | pass -28 | if [1] is named_var: # F632 (fix) - | - = help: Replace `is` with `==` - -ℹ Safe fix -23 23 | pass -24 24 | if [] is named_var: # F632 (fix) -25 25 | pass -26 |-if named_var is [1]: # F632 (fix) - 26 |+if named_var == [1]: # F632 (fix) -27 27 | pass -28 28 | if [1] is named_var: # F632 (fix) -29 29 | pass - -constant_literals.py:28:4: F632 [*] Use `==` to compare constant literals - | -26 | if named_var is [1]: # F632 (fix) -27 | pass -28 | if [1] is named_var: # F632 (fix) - | ^^^^^^^^^^^^^^^^ F632 -29 | pass -30 | if named_var is [i for i in [1]]: # F632 (fix) - | - = help: Replace `is` with `==` - -ℹ Safe fix -25 25 | pass -26 26 | if named_var is [1]: # F632 (fix) -27 27 | pass -28 |-if [1] is named_var: # F632 (fix) - 28 |+if [1] == named_var: # F632 (fix) -29 29 | pass -30 30 | if named_var is [i for i in [1]]: # F632 (fix) -31 31 | pass - -constant_literals.py:30:4: F632 [*] Use `==` to compare constant literals - | -28 | if [1] is named_var: # F632 (fix) -29 | pass -30 | if named_var is [i for i in [1]]: # F632 (fix) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ F632 -31 | pass - | - = help: Replace `is` with `==` - -ℹ Safe fix -27 27 | pass -28 28 | if [1] is named_var: # F632 (fix) -29 29 | pass -30 |-if named_var is [i for i in [1]]: # F632 (fix) - 30 |+if named_var == [i for i in [1]]: # F632 (fix) -31 31 | pass -32 32 | -33 33 | named_var = {} - -constant_literals.py:34:4: F632 [*] Use `==` to compare constant literals - | -33 | named_var = {} -34 | if {} is {}: # F632 (fix) - | ^^^^^^^^ F632 -35 | pass -36 | if named_var is {}: # F632 (fix) - | - = help: Replace `is` with `==` - -ℹ Safe fix -31 31 | pass -32 32 | -33 33 | named_var = {} -34 |-if {} is {}: # F632 (fix) - 34 |+if {} == {}: # F632 (fix) -35 35 | pass -36 36 | if named_var is {}: # F632 (fix) -37 37 | pass - -constant_literals.py:36:4: F632 [*] Use `==` to compare constant literals - | -34 | if {} is {}: # F632 (fix) -35 | pass -36 | if named_var is {}: # F632 (fix) - | ^^^^^^^^^^^^^^^ F632 -37 | pass -38 | if {} is named_var: # F632 (fix) - | - = help: Replace `is` with `==` - -ℹ Safe fix -33 33 | named_var = {} -34 34 | if {} is {}: # F632 (fix) -35 35 | pass -36 |-if named_var is {}: # F632 (fix) - 36 |+if named_var == {}: # F632 (fix) -37 37 | pass -38 38 | if {} is named_var: # F632 (fix) -39 39 | pass - -constant_literals.py:38:4: F632 [*] Use `==` to compare constant literals - | -36 | if named_var is {}: # F632 (fix) -37 | pass -38 | if {} is named_var: # F632 (fix) - | ^^^^^^^^^^^^^^^ F632 -39 | pass -40 | if named_var is {1}: # F632 (fix) - | - = help: Replace `is` with `==` - -ℹ Safe fix -35 35 | pass -36 36 | if named_var is {}: # F632 (fix) -37 37 | pass -38 |-if {} is named_var: # F632 (fix) - 38 |+if {} == named_var: # F632 (fix) -39 39 | pass -40 40 | if named_var is {1}: # F632 (fix) -41 41 | pass - -constant_literals.py:40:4: F632 [*] Use `==` to compare constant literals - | -38 | if {} is named_var: # F632 (fix) -39 | pass -40 | if named_var is {1}: # F632 (fix) - | ^^^^^^^^^^^^^^^^ F632 -41 | pass -42 | if {1} is named_var: # F632 (fix) - | - = help: Replace `is` with `==` - -ℹ Safe fix -37 37 | pass -38 38 | if {} is named_var: # F632 (fix) -39 39 | pass -40 |-if named_var is {1}: # F632 (fix) - 40 |+if named_var == {1}: # F632 (fix) -41 41 | pass -42 42 | if {1} is named_var: # F632 (fix) -43 43 | pass - -constant_literals.py:42:4: F632 [*] Use `==` to compare constant literals - | -40 | if named_var is {1}: # F632 (fix) -41 | pass -42 | if {1} is named_var: # F632 (fix) - | ^^^^^^^^^^^^^^^^ F632 -43 | pass -44 | if named_var is {i for i in [1]}: # F632 (fix) - | - = help: Replace `is` with `==` - -ℹ Safe fix -39 39 | pass -40 40 | if named_var is {1}: # F632 (fix) -41 41 | pass -42 |-if {1} is named_var: # F632 (fix) - 42 |+if {1} == named_var: # F632 (fix) -43 43 | pass -44 44 | if named_var is {i for i in [1]}: # F632 (fix) -45 45 | pass - -constant_literals.py:44:4: F632 [*] Use `==` to compare constant literals - | -42 | if {1} is named_var: # F632 (fix) -43 | pass -44 | if named_var is {i for i in [1]}: # F632 (fix) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ F632 -45 | pass - | - = help: Replace `is` with `==` - -ℹ Safe fix -41 41 | pass -42 42 | if {1} is named_var: # F632 (fix) -43 43 | pass -44 |-if named_var is {i for i in [1]}: # F632 (fix) - 44 |+if named_var == {i for i in [1]}: # F632 (fix) -45 45 | pass -46 46 | -47 47 | named_var = {1: 1} - -constant_literals.py:48:4: F632 [*] Use `==` to compare constant literals - | -47 | named_var = {1: 1} -48 | if {1: 1} is {1: 1}: # F632 (fix) - | ^^^^^^^^^^^^^^^^ F632 -49 | pass -50 | if named_var is {1: 1}: # F632 (fix) - | - = help: Replace `is` with `==` - -ℹ Safe fix -45 45 | pass -46 46 | -47 47 | named_var = {1: 1} -48 |-if {1: 1} is {1: 1}: # F632 (fix) - 48 |+if {1: 1} == {1: 1}: # F632 (fix) -49 49 | pass -50 50 | if named_var is {1: 1}: # F632 (fix) -51 51 | pass - -constant_literals.py:50:4: F632 [*] Use `==` to compare constant literals - | -48 | if {1: 1} is {1: 1}: # F632 (fix) -49 | pass -50 | if named_var is {1: 1}: # F632 (fix) - | ^^^^^^^^^^^^^^^^^^^ F632 -51 | pass -52 | if {1: 1} is named_var: # F632 (fix) - | - = help: Replace `is` with `==` - -ℹ Safe fix -47 47 | named_var = {1: 1} -48 48 | if {1: 1} is {1: 1}: # F632 (fix) -49 49 | pass -50 |-if named_var is {1: 1}: # F632 (fix) - 50 |+if named_var == {1: 1}: # F632 (fix) -51 51 | pass -52 52 | if {1: 1} is named_var: # F632 (fix) -53 53 | pass - -constant_literals.py:52:4: F632 [*] Use `==` to compare constant literals - | -50 | if named_var is {1: 1}: # F632 (fix) -51 | pass -52 | if {1: 1} is named_var: # F632 (fix) - | ^^^^^^^^^^^^^^^^^^^ F632 -53 | pass -54 | if named_var is {1: 1}: # F632 (fix) - | - = help: Replace `is` with `==` - -ℹ Safe fix -49 49 | pass -50 50 | if named_var is {1: 1}: # F632 (fix) -51 51 | pass -52 |-if {1: 1} is named_var: # F632 (fix) - 52 |+if {1: 1} == named_var: # F632 (fix) -53 53 | pass -54 54 | if named_var is {1: 1}: # F632 (fix) -55 55 | pass - -constant_literals.py:54:4: F632 [*] Use `==` to compare constant literals - | -52 | if {1: 1} is named_var: # F632 (fix) -53 | pass -54 | if named_var is {1: 1}: # F632 (fix) - | ^^^^^^^^^^^^^^^^^^^ F632 -55 | pass -56 | if {1: 1} is named_var: # F632 (fix) - | - = help: Replace `is` with `==` - -ℹ Safe fix -51 51 | pass -52 52 | if {1: 1} is named_var: # F632 (fix) -53 53 | pass -54 |-if named_var is {1: 1}: # F632 (fix) - 54 |+if named_var == {1: 1}: # F632 (fix) -55 55 | pass -56 56 | if {1: 1} is named_var: # F632 (fix) -57 57 | pass - -constant_literals.py:56:4: F632 [*] Use `==` to compare constant literals - | -54 | if named_var is {1: 1}: # F632 (fix) -55 | pass -56 | if {1: 1} is named_var: # F632 (fix) - | ^^^^^^^^^^^^^^^^^^^ F632 -57 | pass -58 | if named_var is {i: 1 for i in [1]}: # F632 (fix) - | - = help: Replace `is` with `==` - -ℹ Safe fix -53 53 | pass -54 54 | if named_var is {1: 1}: # F632 (fix) -55 55 | pass -56 |-if {1: 1} is named_var: # F632 (fix) - 56 |+if {1: 1} == named_var: # F632 (fix) -57 57 | pass -58 58 | if named_var is {i: 1 for i in [1]}: # F632 (fix) -59 59 | pass - -constant_literals.py:58:4: F632 [*] Use `==` to compare constant literals - | -56 | if {1: 1} is named_var: # F632 (fix) -57 | pass -58 | if named_var is {i: 1 for i in [1]}: # F632 (fix) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ F632 -59 | pass - | - = help: Replace `is` with `==` - -ℹ Safe fix -55 55 | pass -56 56 | if {1: 1} is named_var: # F632 (fix) -57 57 | pass -58 |-if named_var is {i: 1 for i in [1]}: # F632 (fix) - 58 |+if named_var == {i: 1 for i in [1]}: # F632 (fix) -59 59 | pass -60 60 | -61 61 | ### - - diff --git a/crates/ruff_linter/src/rules/pyflakes/rules/invalid_literal_comparisons.rs b/crates/ruff_linter/src/rules/pyflakes/rules/invalid_literal_comparisons.rs index be201527cdd8b..cd10455d43a3c 100644 --- a/crates/ruff_linter/src/rules/pyflakes/rules/invalid_literal_comparisons.rs +++ b/crates/ruff_linter/src/rules/pyflakes/rules/invalid_literal_comparisons.rs @@ -1,17 +1,17 @@ use log::error; -use ruff_python_ast::{CmpOp, Expr}; use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::helpers; +use ruff_python_ast::{CmpOp, Expr}; use ruff_python_parser::{TokenKind, Tokens}; use ruff_text_size::{Ranged, TextRange}; use crate::checkers::ast::Checker; /// ## What it does -/// Checks for `is` and `is not` comparisons against constant literals, like -/// integers and strings. +/// Checks for `is` and `is not` comparisons against literals, like integers, +/// strings, or lists. /// /// ## Why is this bad? /// The `is` and `is not` comparators operate on identity, in that they check @@ -23,14 +23,14 @@ use crate::checkers::ast::Checker; /// As of Python 3.8, using `is` and `is not` with constant literals will produce /// a `SyntaxWarning`. /// -/// Instead, use `==` and `!=` to compare constant literals, which will compare -/// the values of the objects instead of their identities. +/// This rule will also flag `is` and `is not` comparisons against non-constant +/// literals, like lists, sets, and dictionaries. While such comparisons will +/// not raise a `SyntaxWarning`, they are still likely to be incorrect, as they +/// will compare the identities of the objects instead of their values, which +/// will always evaluate to `False`. /// -/// In [preview], this rule will also flag `is` and `is not` comparisons against -/// non-constant literals, like lists, sets, and dictionaries. While such -/// comparisons will not raise a `SyntaxWarning`, they are still likely to be -/// incorrect, as they will compare the identities of the objects instead of -/// their values, which will always evaluate to `False`. +/// Instead, use `==` and `!=` to compare literals, which will compare the +/// values of the objects instead of their identities. /// /// ## Example /// ```python @@ -50,8 +50,6 @@ use crate::checkers::ast::Checker; /// - [Python documentation: Identity comparisons](https://docs.python.org/3/reference/expressions.html#is-not) /// - [Python documentation: Value comparisons](https://docs.python.org/3/reference/expressions.html#value-comparisons) /// - [_Why does Python log a SyntaxWarning for ‘is’ with literals?_ by Adam Johnson](https://adamj.eu/tech/2020/01/21/why-does-python-3-8-syntaxwarning-for-is-literal/) -/// -/// [preview]: https://docs.astral.sh/ruff/preview/ #[violation] pub struct IsLiteral { cmp_op: IsCmpOp, @@ -90,9 +88,8 @@ pub(crate) fn invalid_literal_comparison( if matches!(op, CmpOp::Is | CmpOp::IsNot) && (helpers::is_constant_non_singleton(left) || helpers::is_constant_non_singleton(right) - || (checker.settings.preview.is_enabled() - && (helpers::is_mutable_iterable_initializer(left) - || helpers::is_mutable_iterable_initializer(right)))) + || helpers::is_mutable_iterable_initializer(left) + || helpers::is_mutable_iterable_initializer(right)) { let mut diagnostic = Diagnostic::new(IsLiteral { cmp_op: op.into() }, expr.range()); if lazy_located.is_none() {