From a1afff6fa9fdd354e66d4170daddf89590fa0370 Mon Sep 17 00:00:00 2001 From: Tom Kuson Date: Sat, 4 Nov 2023 16:20:15 +0000 Subject: [PATCH 1/5] Fix false negative --- .../test/fixtures/pyflakes/F841_1.py | 8 +- .../test/fixtures/pyflakes/F841_4.py | 32 ++++++ crates/ruff_linter/src/rules/pyflakes/mod.rs | 1 + .../rules/pyflakes/rules/unused_variable.rs | 4 +- ...ules__pyflakes__tests__F841_F841_0.py.snap | 98 ++++++++++++++++ ...ules__pyflakes__tests__F841_F841_1.py.snap | 70 +++++++++++- ...ules__pyflakes__tests__F841_F841_3.py.snap | 108 ++++++++++++++++++ ...ules__pyflakes__tests__F841_F841_4.py.snap | 41 +++++++ ...lakes__tests__f841_dummy_variable_rgx.snap | 98 ++++++++++++++++ 9 files changed, 449 insertions(+), 11 deletions(-) create mode 100644 crates/ruff_linter/resources/test/fixtures/pyflakes/F841_4.py create mode 100644 crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_4.py.snap diff --git a/crates/ruff_linter/resources/test/fixtures/pyflakes/F841_1.py b/crates/ruff_linter/resources/test/fixtures/pyflakes/F841_1.py index 082646100dade..24c051d9bd503 100644 --- a/crates/ruff_linter/resources/test/fixtures/pyflakes/F841_1.py +++ b/crates/ruff_linter/resources/test/fixtures/pyflakes/F841_1.py @@ -1,5 +1,5 @@ def f(tup): - x, y = tup # this does NOT trigger F841 + x, y = tup def f(): @@ -7,17 +7,17 @@ def f(): def f(): - (x, y) = coords = 1, 2 # this does NOT trigger F841 + (x, y) = coords = 1, 2 if x > 1: print(coords) def f(): - (x, y) = coords = 1, 2 # this triggers F841 on coords + (x, y) = coords = 1, 2 def f(): - coords = (x, y) = 1, 2 # this triggers F841 on coords + coords = (x, y) = 1, 2 def f(): diff --git a/crates/ruff_linter/resources/test/fixtures/pyflakes/F841_4.py b/crates/ruff_linter/resources/test/fixtures/pyflakes/F841_4.py new file mode 100644 index 0000000000000..af1e73344853e --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/pyflakes/F841_4.py @@ -0,0 +1,32 @@ +"""Test fix for issue #8441. + +Ref: https://github.com/astral-sh/ruff/issues/8441 +""" + + +def foo(): + ... + + +def bar(): + a = foo() + b, c = foo() + + +def baz(): + d, _e = foo() + print(d) + + +def qux(): + f, _ = foo() + print(f) + + +def quux(): + g, h = foo() + print(g, h) + + +def quuz(): + _i, _j = foo() diff --git a/crates/ruff_linter/src/rules/pyflakes/mod.rs b/crates/ruff_linter/src/rules/pyflakes/mod.rs index 4cb3a9f8953b5..7299925b2554e 100644 --- a/crates/ruff_linter/src/rules/pyflakes/mod.rs +++ b/crates/ruff_linter/src/rules/pyflakes/mod.rs @@ -145,6 +145,7 @@ mod tests { #[test_case(Rule::UnusedVariable, Path::new("F841_1.py"))] #[test_case(Rule::UnusedVariable, Path::new("F841_2.py"))] #[test_case(Rule::UnusedVariable, Path::new("F841_3.py"))] + #[test_case(Rule::UnusedVariable, Path::new("F841_4.py"))] #[test_case(Rule::UnusedAnnotation, Path::new("F842.py"))] #[test_case(Rule::RaiseNotImplemented, Path::new("F901.py"))] fn rules(rule_code: Rule, path: &Path) -> Result<()> { diff --git a/crates/ruff_linter/src/rules/pyflakes/rules/unused_variable.rs b/crates/ruff_linter/src/rules/pyflakes/rules/unused_variable.rs index b72bb5372f235..87693f67c0564 100644 --- a/crates/ruff_linter/src/rules/pyflakes/rules/unused_variable.rs +++ b/crates/ruff_linter/src/rules/pyflakes/rules/unused_variable.rs @@ -318,7 +318,9 @@ pub(crate) fn unused_variable(checker: &Checker, scope: &Scope, diagnostics: &mu .bindings() .map(|(name, binding_id)| (name, checker.semantic().binding(binding_id))) .filter_map(|(name, binding)| { - if (binding.kind.is_assignment() || binding.kind.is_named_expr_assignment()) + if (binding.kind.is_assignment() + || binding.kind.is_named_expr_assignment() + || binding.kind.is_unpacked_assignment()) && !binding.is_nonlocal() && !binding.is_global() && !binding.is_used() diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_0.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_0.py.snap index e3f2fc6d0237e..5b6851d0cc45b 100644 --- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_0.py.snap +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_0.py.snap @@ -79,6 +79,44 @@ F841_0.py:21:9: F841 Local variable `b` is assigned to but never used | = help: Remove assignment to unused variable `b` +F841_0.py:24:6: F841 Local variable `c` is assigned to but never used + | +23 | bar = (1, 2) +24 | (c, d) = bar + | ^ F841 +25 | +26 | (x, y) = baz = bar + | + = help: Remove assignment to unused variable `c` + +F841_0.py:24:9: F841 Local variable `d` is assigned to but never used + | +23 | bar = (1, 2) +24 | (c, d) = bar + | ^ F841 +25 | +26 | (x, y) = baz = bar + | + = help: Remove assignment to unused variable `d` + +F841_0.py:26:6: F841 Local variable `x` is assigned to but never used + | +24 | (c, d) = bar +25 | +26 | (x, y) = baz = bar + | ^ F841 + | + = help: Remove assignment to unused variable `x` + +F841_0.py:26:9: F841 Local variable `y` is assigned to but never used + | +24 | (c, d) = bar +25 | +26 | (x, y) = baz = bar + | ^ F841 + | + = help: Remove assignment to unused variable `y` + F841_0.py:26:14: F841 [*] Local variable `baz` is assigned to but never used | 24 | (c, d) = bar @@ -119,6 +157,26 @@ F841_0.py:51:9: F841 [*] Local variable `b` is assigned to but never used 53 53 | def d(): 54 54 | nonlocal b +F841_0.py:66:24: F841 Local variable `connection` is assigned to but never used + | +64 | return None, None +65 | +66 | with connect() as (connection, cursor): + | ^^^^^^^^^^ F841 +67 | cursor.execute("SELECT * FROM users") + | + = help: Remove assignment to unused variable `connection` + +F841_0.py:74:24: F841 Local variable `connection` is assigned to but never used + | +72 | return None, None +73 | +74 | with connect() as (connection, cursor): + | ^^^^^^^^^^ F841 +75 | cursor.execute("SELECT * FROM users") + | + = help: Remove assignment to unused variable `connection` + F841_0.py:79:26: F841 [*] Local variable `my_file` is assigned to but never used | 78 | def f(): @@ -138,6 +196,24 @@ F841_0.py:79:26: F841 [*] Local variable `my_file` is assigned to but never used 81 81 | 82 82 | +F841_0.py:79:49: F841 Local variable `this` is assigned to but never used + | +78 | def f(): +79 | with open("file") as my_file, open("") as ((this, that)): + | ^^^^ F841 +80 | print("hello") + | + = help: Remove assignment to unused variable `this` + +F841_0.py:79:55: F841 Local variable `that` is assigned to but never used + | +78 | def f(): +79 | with open("file") as my_file, open("") as ((this, that)): + | ^^^^ F841 +80 | print("hello") + | + = help: Remove assignment to unused variable `that` + F841_0.py:85:25: F841 [*] Local variable `my_file` is assigned to but never used | 83 | def f(): @@ -159,6 +235,28 @@ F841_0.py:85:25: F841 [*] Local variable `my_file` is assigned to but never used 87 87 | ): 88 88 | print("hello") +F841_0.py:86:23: F841 Local variable `this` is assigned to but never used + | +84 | with ( +85 | open("file") as my_file, +86 | open("") as ((this, that)), + | ^^^^ F841 +87 | ): +88 | print("hello") + | + = help: Remove assignment to unused variable `this` + +F841_0.py:86:29: F841 Local variable `that` is assigned to but never used + | +84 | with ( +85 | open("file") as my_file, +86 | open("") as ((this, that)), + | ^^^^ F841 +87 | ): +88 | print("hello") + | + = help: Remove assignment to unused variable `that` + F841_0.py:102:5: F841 [*] Local variable `msg3` is assigned to but never used | 100 | msg1 = "Hello, world!" diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_1.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_1.py.snap index 21aec0a0e51ae..fc5d3dcc0f392 100644 --- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_1.py.snap +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_1.py.snap @@ -1,6 +1,22 @@ --- source: crates/ruff_linter/src/rules/pyflakes/mod.rs --- +F841_1.py:2:5: F841 Local variable `x` is assigned to but never used + | +1 | def f(tup): +2 | x, y = tup + | ^ F841 + | + = help: Remove assignment to unused variable `x` + +F841_1.py:2:8: F841 Local variable `y` is assigned to but never used + | +1 | def f(tup): +2 | x, y = tup + | ^ F841 + | + = help: Remove assignment to unused variable `y` + F841_1.py:6:5: F841 Local variable `x` is assigned to but never used | 5 | def f(): @@ -17,10 +33,36 @@ F841_1.py:6:8: F841 Local variable `y` is assigned to but never used | = help: Remove assignment to unused variable `y` +F841_1.py:10:9: F841 Local variable `y` is assigned to but never used + | + 9 | def f(): +10 | (x, y) = coords = 1, 2 + | ^ F841 +11 | if x > 1: +12 | print(coords) + | + = help: Remove assignment to unused variable `y` + +F841_1.py:16:6: F841 Local variable `x` is assigned to but never used + | +15 | def f(): +16 | (x, y) = coords = 1, 2 + | ^ F841 + | + = help: Remove assignment to unused variable `x` + +F841_1.py:16:9: F841 Local variable `y` is assigned to but never used + | +15 | def f(): +16 | (x, y) = coords = 1, 2 + | ^ F841 + | + = help: Remove assignment to unused variable `y` + F841_1.py:16:14: F841 [*] Local variable `coords` is assigned to but never used | 15 | def f(): -16 | (x, y) = coords = 1, 2 # this triggers F841 on coords +16 | (x, y) = coords = 1, 2 | ^^^^^^ F841 | = help: Remove assignment to unused variable `coords` @@ -29,8 +71,8 @@ F841_1.py:16:14: F841 [*] Local variable `coords` is assigned to but never used 13 13 | 14 14 | 15 15 | def f(): -16 |- (x, y) = coords = 1, 2 # this triggers F841 on coords - 16 |+ (x, y) = 1, 2 # this triggers F841 on coords +16 |- (x, y) = coords = 1, 2 + 16 |+ (x, y) = 1, 2 17 17 | 18 18 | 19 19 | def f(): @@ -38,7 +80,7 @@ F841_1.py:16:14: F841 [*] Local variable `coords` is assigned to but never used F841_1.py:20:5: F841 [*] Local variable `coords` is assigned to but never used | 19 | def f(): -20 | coords = (x, y) = 1, 2 # this triggers F841 on coords +20 | coords = (x, y) = 1, 2 | ^^^^^^ F841 | = help: Remove assignment to unused variable `coords` @@ -47,12 +89,28 @@ F841_1.py:20:5: F841 [*] Local variable `coords` is assigned to but never used 17 17 | 18 18 | 19 19 | def f(): -20 |- coords = (x, y) = 1, 2 # this triggers F841 on coords - 20 |+ (x, y) = 1, 2 # this triggers F841 on coords +20 |- coords = (x, y) = 1, 2 + 20 |+ (x, y) = 1, 2 21 21 | 22 22 | 23 23 | def f(): +F841_1.py:20:15: F841 Local variable `x` is assigned to but never used + | +19 | def f(): +20 | coords = (x, y) = 1, 2 + | ^ F841 + | + = help: Remove assignment to unused variable `x` + +F841_1.py:20:18: F841 Local variable `y` is assigned to but never used + | +19 | def f(): +20 | coords = (x, y) = 1, 2 + | ^ F841 + | + = help: Remove assignment to unused variable `y` + F841_1.py:24:6: F841 Local variable `a` is assigned to but never used | 23 | def f(): diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_3.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_3.py.snap index 7527c4e2cd846..2b971873144c5 100644 --- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_3.py.snap +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_3.py.snap @@ -96,6 +96,26 @@ F841_3.py:21:19: F841 [*] Local variable `x1` is assigned to but never used 23 23 | 24 24 | with foo() as (x2, y2): +F841_3.py:24:20: F841 Local variable `x2` is assigned to but never used + | +22 | pass +23 | +24 | with foo() as (x2, y2): + | ^^ F841 +25 | pass + | + = help: Remove assignment to unused variable `x2` + +F841_3.py:24:24: F841 Local variable `y2` is assigned to but never used + | +22 | pass +23 | +24 | with foo() as (x2, y2): + | ^^ F841 +25 | pass + | + = help: Remove assignment to unused variable `y2` + F841_3.py:27:20: F841 [*] Local variable `x3` is assigned to but never used | 25 | pass @@ -176,6 +196,26 @@ F841_3.py:32:10: F841 Local variable `y1` is assigned to but never used | = help: Remove assignment to unused variable `y1` +F841_3.py:33:6: F841 Local variable `x2` is assigned to but never used + | +31 | def f(): +32 | (x1, y1) = (1, 2) +33 | (x2, y2) = coords2 = (1, 2) + | ^^ F841 +34 | coords3 = (x3, y3) = (1, 2) + | + = help: Remove assignment to unused variable `x2` + +F841_3.py:33:10: F841 Local variable `y2` is assigned to but never used + | +31 | def f(): +32 | (x1, y1) = (1, 2) +33 | (x2, y2) = coords2 = (1, 2) + | ^^ F841 +34 | coords3 = (x3, y3) = (1, 2) + | + = help: Remove assignment to unused variable `y2` + F841_3.py:33:16: F841 [*] Local variable `coords2` is assigned to but never used | 31 | def f(): @@ -215,6 +255,24 @@ F841_3.py:34:5: F841 [*] Local variable `coords3` is assigned to but never used 36 36 | 37 37 | def f(): +F841_3.py:34:16: F841 Local variable `x3` is assigned to but never used + | +32 | (x1, y1) = (1, 2) +33 | (x2, y2) = coords2 = (1, 2) +34 | coords3 = (x3, y3) = (1, 2) + | ^^ F841 + | + = help: Remove assignment to unused variable `x3` + +F841_3.py:34:20: F841 Local variable `y3` is assigned to but never used + | +32 | (x1, y1) = (1, 2) +33 | (x2, y2) = coords2 = (1, 2) +34 | coords3 = (x3, y3) = (1, 2) + | ^^ F841 + | + = help: Remove assignment to unused variable `y3` + F841_3.py:40:26: F841 [*] Local variable `x1` is assigned to but never used | 38 | try: @@ -377,6 +435,24 @@ F841_3.py:77:25: F841 [*] Local variable `cm` is assigned to but never used 79 79 | 80 80 | +F841_3.py:82:24: F841 Local variable `x` is assigned to but never used + | +81 | def f(): +82 | with Nested(m) as (x, y): + | ^ F841 +83 | pass + | + = help: Remove assignment to unused variable `x` + +F841_3.py:82:27: F841 Local variable `y` is assigned to but never used + | +81 | def f(): +82 | with Nested(m) as (x, y): + | ^ F841 +83 | pass + | + = help: Remove assignment to unused variable `y` + F841_3.py:87:26: F841 [*] Local variable `cm` is assigned to but never used | 86 | def f(): @@ -470,6 +546,38 @@ F841_3.py:102:5: F841 [*] Local variable `toplevel` is assigned to but never use 104 104 | 105 105 | def f(): +F841_3.py:102:17: F841 Local variable `a` is assigned to but never used + | +101 | def f(): +102 | toplevel = (a, b) = lexer.get_token() + | ^ F841 + | + = help: Remove assignment to unused variable `a` + +F841_3.py:102:20: F841 Local variable `b` is assigned to but never used + | +101 | def f(): +102 | toplevel = (a, b) = lexer.get_token() + | ^ F841 + | + = help: Remove assignment to unused variable `b` + +F841_3.py:106:6: F841 Local variable `a` is assigned to but never used + | +105 | def f(): +106 | (a, b) = toplevel = lexer.get_token() + | ^ F841 + | + = help: Remove assignment to unused variable `a` + +F841_3.py:106:9: F841 Local variable `b` is assigned to but never used + | +105 | def f(): +106 | (a, b) = toplevel = lexer.get_token() + | ^ F841 + | + = help: Remove assignment to unused variable `b` + F841_3.py:106:14: F841 [*] Local variable `toplevel` is assigned to but never used | 105 | def f(): diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_4.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_4.py.snap new file mode 100644 index 0000000000000..1627e74b9aabd --- /dev/null +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_4.py.snap @@ -0,0 +1,41 @@ +--- +source: crates/ruff_linter/src/rules/pyflakes/mod.rs +--- +F841_4.py:12:5: F841 [*] Local variable `a` is assigned to but never used + | +11 | def bar(): +12 | a = foo() + | ^ F841 +13 | b, c = foo() + | + = help: Remove assignment to unused variable `a` + +ℹ Suggested fix +9 9 | +10 10 | +11 11 | def bar(): +12 |- a = foo() + 12 |+ foo() +13 13 | b, c = foo() +14 14 | +15 15 | + +F841_4.py:13:5: F841 Local variable `b` is assigned to but never used + | +11 | def bar(): +12 | a = foo() +13 | b, c = foo() + | ^ F841 + | + = help: Remove assignment to unused variable `b` + +F841_4.py:13:8: F841 Local variable `c` is assigned to but never used + | +11 | def bar(): +12 | a = foo() +13 | b, c = foo() + | ^ F841 + | + = help: Remove assignment to unused variable `c` + + diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__f841_dummy_variable_rgx.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__f841_dummy_variable_rgx.snap index c117fdff6e54d..a2624eabfc5e6 100644 --- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__f841_dummy_variable_rgx.snap +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__f841_dummy_variable_rgx.snap @@ -60,6 +60,44 @@ F841_0.py:21:9: F841 Local variable `b` is assigned to but never used | = help: Remove assignment to unused variable `b` +F841_0.py:24:6: F841 Local variable `c` is assigned to but never used + | +23 | bar = (1, 2) +24 | (c, d) = bar + | ^ F841 +25 | +26 | (x, y) = baz = bar + | + = help: Remove assignment to unused variable `c` + +F841_0.py:24:9: F841 Local variable `d` is assigned to but never used + | +23 | bar = (1, 2) +24 | (c, d) = bar + | ^ F841 +25 | +26 | (x, y) = baz = bar + | + = help: Remove assignment to unused variable `d` + +F841_0.py:26:6: F841 Local variable `x` is assigned to but never used + | +24 | (c, d) = bar +25 | +26 | (x, y) = baz = bar + | ^ F841 + | + = help: Remove assignment to unused variable `x` + +F841_0.py:26:9: F841 Local variable `y` is assigned to but never used + | +24 | (c, d) = bar +25 | +26 | (x, y) = baz = bar + | ^ F841 + | + = help: Remove assignment to unused variable `y` + F841_0.py:26:14: F841 [*] Local variable `baz` is assigned to but never used | 24 | (c, d) = bar @@ -156,6 +194,26 @@ F841_0.py:51:9: F841 [*] Local variable `b` is assigned to but never used 53 53 | def d(): 54 54 | nonlocal b +F841_0.py:66:24: F841 Local variable `connection` is assigned to but never used + | +64 | return None, None +65 | +66 | with connect() as (connection, cursor): + | ^^^^^^^^^^ F841 +67 | cursor.execute("SELECT * FROM users") + | + = help: Remove assignment to unused variable `connection` + +F841_0.py:74:24: F841 Local variable `connection` is assigned to but never used + | +72 | return None, None +73 | +74 | with connect() as (connection, cursor): + | ^^^^^^^^^^ F841 +75 | cursor.execute("SELECT * FROM users") + | + = help: Remove assignment to unused variable `connection` + F841_0.py:79:26: F841 [*] Local variable `my_file` is assigned to but never used | 78 | def f(): @@ -175,6 +233,24 @@ F841_0.py:79:26: F841 [*] Local variable `my_file` is assigned to but never used 81 81 | 82 82 | +F841_0.py:79:49: F841 Local variable `this` is assigned to but never used + | +78 | def f(): +79 | with open("file") as my_file, open("") as ((this, that)): + | ^^^^ F841 +80 | print("hello") + | + = help: Remove assignment to unused variable `this` + +F841_0.py:79:55: F841 Local variable `that` is assigned to but never used + | +78 | def f(): +79 | with open("file") as my_file, open("") as ((this, that)): + | ^^^^ F841 +80 | print("hello") + | + = help: Remove assignment to unused variable `that` + F841_0.py:85:25: F841 [*] Local variable `my_file` is assigned to but never used | 83 | def f(): @@ -196,6 +272,28 @@ F841_0.py:85:25: F841 [*] Local variable `my_file` is assigned to but never used 87 87 | ): 88 88 | print("hello") +F841_0.py:86:23: F841 Local variable `this` is assigned to but never used + | +84 | with ( +85 | open("file") as my_file, +86 | open("") as ((this, that)), + | ^^^^ F841 +87 | ): +88 | print("hello") + | + = help: Remove assignment to unused variable `this` + +F841_0.py:86:29: F841 Local variable `that` is assigned to but never used + | +84 | with ( +85 | open("file") as my_file, +86 | open("") as ((this, that)), + | ^^^^ F841 +87 | ): +88 | print("hello") + | + = help: Remove assignment to unused variable `that` + F841_0.py:102:5: F841 [*] Local variable `msg3` is assigned to but never used | 100 | msg1 = "Hello, world!" From 6fd30e0e14b982bf37e9aa15ca41b9ea5b1b898e Mon Sep 17 00:00:00 2001 From: Tom Kuson Date: Sat, 4 Nov 2023 16:30:27 +0000 Subject: [PATCH 2/5] Update old test --- crates/ruff_linter/src/rules/pyflakes/mod.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/crates/ruff_linter/src/rules/pyflakes/mod.rs b/crates/ruff_linter/src/rules/pyflakes/mod.rs index 7299925b2554e..f4a9298fd1c8e 100644 --- a/crates/ruff_linter/src/rules/pyflakes/mod.rs +++ b/crates/ruff_linter/src/rules/pyflakes/mod.rs @@ -1128,26 +1128,31 @@ mod tests { #[test] fn used_as_star_unpack() { // Star names in unpack are used if RHS is not a tuple/list literal. + // EDIT: Behaviour changed to fix issue #8441. flakes( r#" def f(): a, *b = range(10) "#, - &[], + &[Rule::UnusedVariable, Rule::UnusedVariable], ); flakes( r#" def f(): (*a, b) = range(10) "#, - &[], + &[Rule::UnusedVariable, Rule::UnusedVariable], ); flakes( r#" def f(): [a, *b, c] = range(10) "#, - &[], + &[ + Rule::UnusedVariable, + Rule::UnusedVariable, + Rule::UnusedVariable, + ], ); } From 9de7a7de9a0325a78b7ea1361baa178c11bf0f78 Mon Sep 17 00:00:00 2001 From: Tom Kuson Date: Sat, 4 Nov 2023 17:13:50 +0000 Subject: [PATCH 3/5] Move change behind preview flag --- crates/ruff_linter/src/rules/pyflakes/mod.rs | 21 +++- .../rules/pyflakes/rules/unused_variable.rs | 7 +- ...ules__pyflakes__tests__F841_F841_0.py.snap | 98 --------------- ...ules__pyflakes__tests__F841_F841_1.py.snap | 58 --------- ...ules__pyflakes__tests__F841_F841_3.py.snap | 108 ----------------- ...ules__pyflakes__tests__F841_F841_4.py.snap | 18 --- ...lakes__tests__f841_dummy_variable_rgx.snap | 98 --------------- ...yflakes__tests__preview__E721_E721.py.snap | 112 ++++++++++++++++++ 8 files changed, 138 insertions(+), 382 deletions(-) create mode 100644 crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__preview__E721_E721.py.snap diff --git a/crates/ruff_linter/src/rules/pyflakes/mod.rs b/crates/ruff_linter/src/rules/pyflakes/mod.rs index f4a9298fd1c8e..537ecacb8e1e1 100644 --- a/crates/ruff_linter/src/rules/pyflakes/mod.rs +++ b/crates/ruff_linter/src/rules/pyflakes/mod.rs @@ -26,10 +26,11 @@ mod tests { use crate::linter::{check_path, LinterResult}; use crate::registry::{AsRule, Linter, Rule}; use crate::rules::pyflakes; + use crate::settings::types::PreviewMode; use crate::settings::{flags, LinterSettings}; use crate::source_kind::SourceKind; use crate::test::{test_path, test_snippet}; - use crate::{assert_messages, directives}; + use crate::{assert_messages, directives, settings}; #[test_case(Rule::UnusedImport, Path::new("F401_0.py"))] #[test_case(Rule::UnusedImport, Path::new("F401_1.py"))] @@ -146,6 +147,24 @@ mod tests { #[test_case(Rule::UnusedVariable, Path::new("F841_2.py"))] #[test_case(Rule::UnusedVariable, Path::new("F841_3.py"))] #[test_case(Rule::UnusedVariable, Path::new("F841_4.py"))] + #[test_case(Rule::TypeComparison, Path::new("E721.py"))] + fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> { + let snapshot = format!( + "preview__{}_{}", + rule_code.noqa_code(), + path.to_string_lossy() + ); + let diagnostics = test_path( + Path::new("pycodestyle").join(path).as_path(), + &settings::LinterSettings { + preview: PreviewMode::Enabled, + ..settings::LinterSettings::for_rule(rule_code) + }, + )?; + assert_messages!(snapshot, diagnostics); + Ok(()) + } + #[test_case(Rule::UnusedAnnotation, Path::new("F842.py"))] #[test_case(Rule::RaiseNotImplemented, Path::new("F901.py"))] fn rules(rule_code: Rule, path: &Path) -> Result<()> { diff --git a/crates/ruff_linter/src/rules/pyflakes/rules/unused_variable.rs b/crates/ruff_linter/src/rules/pyflakes/rules/unused_variable.rs index 87693f67c0564..2bf9ee37213e3 100644 --- a/crates/ruff_linter/src/rules/pyflakes/rules/unused_variable.rs +++ b/crates/ruff_linter/src/rules/pyflakes/rules/unused_variable.rs @@ -12,6 +12,7 @@ use ruff_text_size::{Ranged, TextRange, TextSize}; use crate::checkers::ast::Checker; use crate::fix::edits::delete_stmt; +use crate::settings::types::PreviewMode; /// ## What it does /// Checks for the presence of unused variables in function scopes. @@ -24,6 +25,9 @@ use crate::fix::edits::delete_stmt; /// prefixed with an underscore, or some other value that adheres to the /// [`dummy-variable-rgx`] pattern. /// +/// Under [preview mode](https://docs.astral.sh/ruff/preview), this rule also +/// triggers on unused unpacked assignments (for example, `x, y = foo()`). +/// /// ## Example /// ```python /// def foo(): @@ -320,7 +324,8 @@ pub(crate) fn unused_variable(checker: &Checker, scope: &Scope, diagnostics: &mu .filter_map(|(name, binding)| { if (binding.kind.is_assignment() || binding.kind.is_named_expr_assignment() - || binding.kind.is_unpacked_assignment()) + || (matches!(checker.settings.preview, PreviewMode::Enabled) + && binding.kind.is_unpacked_assignment())) && !binding.is_nonlocal() && !binding.is_global() && !binding.is_used() diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_0.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_0.py.snap index 5b6851d0cc45b..e3f2fc6d0237e 100644 --- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_0.py.snap +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_0.py.snap @@ -79,44 +79,6 @@ F841_0.py:21:9: F841 Local variable `b` is assigned to but never used | = help: Remove assignment to unused variable `b` -F841_0.py:24:6: F841 Local variable `c` is assigned to but never used - | -23 | bar = (1, 2) -24 | (c, d) = bar - | ^ F841 -25 | -26 | (x, y) = baz = bar - | - = help: Remove assignment to unused variable `c` - -F841_0.py:24:9: F841 Local variable `d` is assigned to but never used - | -23 | bar = (1, 2) -24 | (c, d) = bar - | ^ F841 -25 | -26 | (x, y) = baz = bar - | - = help: Remove assignment to unused variable `d` - -F841_0.py:26:6: F841 Local variable `x` is assigned to but never used - | -24 | (c, d) = bar -25 | -26 | (x, y) = baz = bar - | ^ F841 - | - = help: Remove assignment to unused variable `x` - -F841_0.py:26:9: F841 Local variable `y` is assigned to but never used - | -24 | (c, d) = bar -25 | -26 | (x, y) = baz = bar - | ^ F841 - | - = help: Remove assignment to unused variable `y` - F841_0.py:26:14: F841 [*] Local variable `baz` is assigned to but never used | 24 | (c, d) = bar @@ -157,26 +119,6 @@ F841_0.py:51:9: F841 [*] Local variable `b` is assigned to but never used 53 53 | def d(): 54 54 | nonlocal b -F841_0.py:66:24: F841 Local variable `connection` is assigned to but never used - | -64 | return None, None -65 | -66 | with connect() as (connection, cursor): - | ^^^^^^^^^^ F841 -67 | cursor.execute("SELECT * FROM users") - | - = help: Remove assignment to unused variable `connection` - -F841_0.py:74:24: F841 Local variable `connection` is assigned to but never used - | -72 | return None, None -73 | -74 | with connect() as (connection, cursor): - | ^^^^^^^^^^ F841 -75 | cursor.execute("SELECT * FROM users") - | - = help: Remove assignment to unused variable `connection` - F841_0.py:79:26: F841 [*] Local variable `my_file` is assigned to but never used | 78 | def f(): @@ -196,24 +138,6 @@ F841_0.py:79:26: F841 [*] Local variable `my_file` is assigned to but never used 81 81 | 82 82 | -F841_0.py:79:49: F841 Local variable `this` is assigned to but never used - | -78 | def f(): -79 | with open("file") as my_file, open("") as ((this, that)): - | ^^^^ F841 -80 | print("hello") - | - = help: Remove assignment to unused variable `this` - -F841_0.py:79:55: F841 Local variable `that` is assigned to but never used - | -78 | def f(): -79 | with open("file") as my_file, open("") as ((this, that)): - | ^^^^ F841 -80 | print("hello") - | - = help: Remove assignment to unused variable `that` - F841_0.py:85:25: F841 [*] Local variable `my_file` is assigned to but never used | 83 | def f(): @@ -235,28 +159,6 @@ F841_0.py:85:25: F841 [*] Local variable `my_file` is assigned to but never used 87 87 | ): 88 88 | print("hello") -F841_0.py:86:23: F841 Local variable `this` is assigned to but never used - | -84 | with ( -85 | open("file") as my_file, -86 | open("") as ((this, that)), - | ^^^^ F841 -87 | ): -88 | print("hello") - | - = help: Remove assignment to unused variable `this` - -F841_0.py:86:29: F841 Local variable `that` is assigned to but never used - | -84 | with ( -85 | open("file") as my_file, -86 | open("") as ((this, that)), - | ^^^^ F841 -87 | ): -88 | print("hello") - | - = help: Remove assignment to unused variable `that` - F841_0.py:102:5: F841 [*] Local variable `msg3` is assigned to but never used | 100 | msg1 = "Hello, world!" diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_1.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_1.py.snap index fc5d3dcc0f392..9ddfa6f5d026f 100644 --- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_1.py.snap +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_1.py.snap @@ -1,22 +1,6 @@ --- source: crates/ruff_linter/src/rules/pyflakes/mod.rs --- -F841_1.py:2:5: F841 Local variable `x` is assigned to but never used - | -1 | def f(tup): -2 | x, y = tup - | ^ F841 - | - = help: Remove assignment to unused variable `x` - -F841_1.py:2:8: F841 Local variable `y` is assigned to but never used - | -1 | def f(tup): -2 | x, y = tup - | ^ F841 - | - = help: Remove assignment to unused variable `y` - F841_1.py:6:5: F841 Local variable `x` is assigned to but never used | 5 | def f(): @@ -33,32 +17,6 @@ F841_1.py:6:8: F841 Local variable `y` is assigned to but never used | = help: Remove assignment to unused variable `y` -F841_1.py:10:9: F841 Local variable `y` is assigned to but never used - | - 9 | def f(): -10 | (x, y) = coords = 1, 2 - | ^ F841 -11 | if x > 1: -12 | print(coords) - | - = help: Remove assignment to unused variable `y` - -F841_1.py:16:6: F841 Local variable `x` is assigned to but never used - | -15 | def f(): -16 | (x, y) = coords = 1, 2 - | ^ F841 - | - = help: Remove assignment to unused variable `x` - -F841_1.py:16:9: F841 Local variable `y` is assigned to but never used - | -15 | def f(): -16 | (x, y) = coords = 1, 2 - | ^ F841 - | - = help: Remove assignment to unused variable `y` - F841_1.py:16:14: F841 [*] Local variable `coords` is assigned to but never used | 15 | def f(): @@ -95,22 +53,6 @@ F841_1.py:20:5: F841 [*] Local variable `coords` is assigned to but never used 22 22 | 23 23 | def f(): -F841_1.py:20:15: F841 Local variable `x` is assigned to but never used - | -19 | def f(): -20 | coords = (x, y) = 1, 2 - | ^ F841 - | - = help: Remove assignment to unused variable `x` - -F841_1.py:20:18: F841 Local variable `y` is assigned to but never used - | -19 | def f(): -20 | coords = (x, y) = 1, 2 - | ^ F841 - | - = help: Remove assignment to unused variable `y` - F841_1.py:24:6: F841 Local variable `a` is assigned to but never used | 23 | def f(): diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_3.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_3.py.snap index 2b971873144c5..7527c4e2cd846 100644 --- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_3.py.snap +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_3.py.snap @@ -96,26 +96,6 @@ F841_3.py:21:19: F841 [*] Local variable `x1` is assigned to but never used 23 23 | 24 24 | with foo() as (x2, y2): -F841_3.py:24:20: F841 Local variable `x2` is assigned to but never used - | -22 | pass -23 | -24 | with foo() as (x2, y2): - | ^^ F841 -25 | pass - | - = help: Remove assignment to unused variable `x2` - -F841_3.py:24:24: F841 Local variable `y2` is assigned to but never used - | -22 | pass -23 | -24 | with foo() as (x2, y2): - | ^^ F841 -25 | pass - | - = help: Remove assignment to unused variable `y2` - F841_3.py:27:20: F841 [*] Local variable `x3` is assigned to but never used | 25 | pass @@ -196,26 +176,6 @@ F841_3.py:32:10: F841 Local variable `y1` is assigned to but never used | = help: Remove assignment to unused variable `y1` -F841_3.py:33:6: F841 Local variable `x2` is assigned to but never used - | -31 | def f(): -32 | (x1, y1) = (1, 2) -33 | (x2, y2) = coords2 = (1, 2) - | ^^ F841 -34 | coords3 = (x3, y3) = (1, 2) - | - = help: Remove assignment to unused variable `x2` - -F841_3.py:33:10: F841 Local variable `y2` is assigned to but never used - | -31 | def f(): -32 | (x1, y1) = (1, 2) -33 | (x2, y2) = coords2 = (1, 2) - | ^^ F841 -34 | coords3 = (x3, y3) = (1, 2) - | - = help: Remove assignment to unused variable `y2` - F841_3.py:33:16: F841 [*] Local variable `coords2` is assigned to but never used | 31 | def f(): @@ -255,24 +215,6 @@ F841_3.py:34:5: F841 [*] Local variable `coords3` is assigned to but never used 36 36 | 37 37 | def f(): -F841_3.py:34:16: F841 Local variable `x3` is assigned to but never used - | -32 | (x1, y1) = (1, 2) -33 | (x2, y2) = coords2 = (1, 2) -34 | coords3 = (x3, y3) = (1, 2) - | ^^ F841 - | - = help: Remove assignment to unused variable `x3` - -F841_3.py:34:20: F841 Local variable `y3` is assigned to but never used - | -32 | (x1, y1) = (1, 2) -33 | (x2, y2) = coords2 = (1, 2) -34 | coords3 = (x3, y3) = (1, 2) - | ^^ F841 - | - = help: Remove assignment to unused variable `y3` - F841_3.py:40:26: F841 [*] Local variable `x1` is assigned to but never used | 38 | try: @@ -435,24 +377,6 @@ F841_3.py:77:25: F841 [*] Local variable `cm` is assigned to but never used 79 79 | 80 80 | -F841_3.py:82:24: F841 Local variable `x` is assigned to but never used - | -81 | def f(): -82 | with Nested(m) as (x, y): - | ^ F841 -83 | pass - | - = help: Remove assignment to unused variable `x` - -F841_3.py:82:27: F841 Local variable `y` is assigned to but never used - | -81 | def f(): -82 | with Nested(m) as (x, y): - | ^ F841 -83 | pass - | - = help: Remove assignment to unused variable `y` - F841_3.py:87:26: F841 [*] Local variable `cm` is assigned to but never used | 86 | def f(): @@ -546,38 +470,6 @@ F841_3.py:102:5: F841 [*] Local variable `toplevel` is assigned to but never use 104 104 | 105 105 | def f(): -F841_3.py:102:17: F841 Local variable `a` is assigned to but never used - | -101 | def f(): -102 | toplevel = (a, b) = lexer.get_token() - | ^ F841 - | - = help: Remove assignment to unused variable `a` - -F841_3.py:102:20: F841 Local variable `b` is assigned to but never used - | -101 | def f(): -102 | toplevel = (a, b) = lexer.get_token() - | ^ F841 - | - = help: Remove assignment to unused variable `b` - -F841_3.py:106:6: F841 Local variable `a` is assigned to but never used - | -105 | def f(): -106 | (a, b) = toplevel = lexer.get_token() - | ^ F841 - | - = help: Remove assignment to unused variable `a` - -F841_3.py:106:9: F841 Local variable `b` is assigned to but never used - | -105 | def f(): -106 | (a, b) = toplevel = lexer.get_token() - | ^ F841 - | - = help: Remove assignment to unused variable `b` - F841_3.py:106:14: F841 [*] Local variable `toplevel` is assigned to but never used | 105 | def f(): diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_4.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_4.py.snap index 1627e74b9aabd..f11e0a7a6e621 100644 --- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_4.py.snap +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__F841_F841_4.py.snap @@ -20,22 +20,4 @@ F841_4.py:12:5: F841 [*] Local variable `a` is assigned to but never used 14 14 | 15 15 | -F841_4.py:13:5: F841 Local variable `b` is assigned to but never used - | -11 | def bar(): -12 | a = foo() -13 | b, c = foo() - | ^ F841 - | - = help: Remove assignment to unused variable `b` - -F841_4.py:13:8: F841 Local variable `c` is assigned to but never used - | -11 | def bar(): -12 | a = foo() -13 | b, c = foo() - | ^ F841 - | - = help: Remove assignment to unused variable `c` - diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__f841_dummy_variable_rgx.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__f841_dummy_variable_rgx.snap index a2624eabfc5e6..c117fdff6e54d 100644 --- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__f841_dummy_variable_rgx.snap +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__f841_dummy_variable_rgx.snap @@ -60,44 +60,6 @@ F841_0.py:21:9: F841 Local variable `b` is assigned to but never used | = help: Remove assignment to unused variable `b` -F841_0.py:24:6: F841 Local variable `c` is assigned to but never used - | -23 | bar = (1, 2) -24 | (c, d) = bar - | ^ F841 -25 | -26 | (x, y) = baz = bar - | - = help: Remove assignment to unused variable `c` - -F841_0.py:24:9: F841 Local variable `d` is assigned to but never used - | -23 | bar = (1, 2) -24 | (c, d) = bar - | ^ F841 -25 | -26 | (x, y) = baz = bar - | - = help: Remove assignment to unused variable `d` - -F841_0.py:26:6: F841 Local variable `x` is assigned to but never used - | -24 | (c, d) = bar -25 | -26 | (x, y) = baz = bar - | ^ F841 - | - = help: Remove assignment to unused variable `x` - -F841_0.py:26:9: F841 Local variable `y` is assigned to but never used - | -24 | (c, d) = bar -25 | -26 | (x, y) = baz = bar - | ^ F841 - | - = help: Remove assignment to unused variable `y` - F841_0.py:26:14: F841 [*] Local variable `baz` is assigned to but never used | 24 | (c, d) = bar @@ -194,26 +156,6 @@ F841_0.py:51:9: F841 [*] Local variable `b` is assigned to but never used 53 53 | def d(): 54 54 | nonlocal b -F841_0.py:66:24: F841 Local variable `connection` is assigned to but never used - | -64 | return None, None -65 | -66 | with connect() as (connection, cursor): - | ^^^^^^^^^^ F841 -67 | cursor.execute("SELECT * FROM users") - | - = help: Remove assignment to unused variable `connection` - -F841_0.py:74:24: F841 Local variable `connection` is assigned to but never used - | -72 | return None, None -73 | -74 | with connect() as (connection, cursor): - | ^^^^^^^^^^ F841 -75 | cursor.execute("SELECT * FROM users") - | - = help: Remove assignment to unused variable `connection` - F841_0.py:79:26: F841 [*] Local variable `my_file` is assigned to but never used | 78 | def f(): @@ -233,24 +175,6 @@ F841_0.py:79:26: F841 [*] Local variable `my_file` is assigned to but never used 81 81 | 82 82 | -F841_0.py:79:49: F841 Local variable `this` is assigned to but never used - | -78 | def f(): -79 | with open("file") as my_file, open("") as ((this, that)): - | ^^^^ F841 -80 | print("hello") - | - = help: Remove assignment to unused variable `this` - -F841_0.py:79:55: F841 Local variable `that` is assigned to but never used - | -78 | def f(): -79 | with open("file") as my_file, open("") as ((this, that)): - | ^^^^ F841 -80 | print("hello") - | - = help: Remove assignment to unused variable `that` - F841_0.py:85:25: F841 [*] Local variable `my_file` is assigned to but never used | 83 | def f(): @@ -272,28 +196,6 @@ F841_0.py:85:25: F841 [*] Local variable `my_file` is assigned to but never used 87 87 | ): 88 88 | print("hello") -F841_0.py:86:23: F841 Local variable `this` is assigned to but never used - | -84 | with ( -85 | open("file") as my_file, -86 | open("") as ((this, that)), - | ^^^^ F841 -87 | ): -88 | print("hello") - | - = help: Remove assignment to unused variable `this` - -F841_0.py:86:29: F841 Local variable `that` is assigned to but never used - | -84 | with ( -85 | open("file") as my_file, -86 | open("") as ((this, that)), - | ^^^^ F841 -87 | ): -88 | print("hello") - | - = help: Remove assignment to unused variable `that` - F841_0.py:102:5: F841 [*] Local variable `msg3` is assigned to but never used | 100 | msg1 = "Hello, world!" diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__preview__E721_E721.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__preview__E721_E721.py.snap new file mode 100644 index 0000000000000..6faca091b1576 --- /dev/null +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__preview__E721_E721.py.snap @@ -0,0 +1,112 @@ +--- +source: crates/ruff_linter/src/rules/pyflakes/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 | #: Okay + | + +E721.py:18:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks + | +16 | pass +17 | #: E721 +18 | assert type(res) == type(False) or type(res) == type(None) + | ^^^^^^^^^^^^^^^^^^^^^^^^ E721 +19 | #: E721 +20 | assert type(res) == type([]) + | + +E721.py:20:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks + | +18 | assert type(res) == type(False) or type(res) == type(None) +19 | #: E721 +20 | assert type(res) == type([]) + | ^^^^^^^^^^^^^^^^^^^^^ E721 +21 | #: E721 +22 | assert type(res) == type(()) + | + +E721.py:22:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks + | +20 | assert type(res) == type([]) +21 | #: E721 +22 | assert type(res) == type(()) + | ^^^^^^^^^^^^^^^^^^^^^ E721 +23 | #: E721 +24 | assert type(res) == type((0,)) + | + +E721.py:24:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks + | +22 | assert type(res) == type(()) +23 | #: E721 +24 | assert type(res) == type((0,)) + | ^^^^^^^^^^^^^^^^^^^^^^^ E721 +25 | #: E721 +26 | assert type(res) == type((0)) + | + +E721.py:26:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks + | +24 | assert type(res) == type((0,)) +25 | #: E721 +26 | assert type(res) == type((0)) + | ^^^^^^^^^^^^^^^^^^^^^^ E721 +27 | #: E721 +28 | assert type(res) != type((1, )) + | + +E721.py:28:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks + | +26 | assert type(res) == type((0)) +27 | #: E721 +28 | assert type(res) != type((1, )) + | ^^^^^^^^^^^^^^^^^^^^^^^^ E721 +29 | #: Okay +30 | assert type(res) is type((1, )) + | + +E721.py:34:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks + | +32 | assert type(res) is not type((1, )) +33 | #: E211 E721 +34 | assert type(res) == type ([2, ]) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ E721 +35 | #: E201 E201 E202 E721 +36 | assert type(res) == type( ( ) ) + | + +E721.py:36:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks + | +34 | assert type(res) == type ([2, ]) +35 | #: E201 E201 E202 E721 +36 | assert type(res) == type( ( ) ) + | ^^^^^^^^^^^^^^^^^^^^^^^^ E721 +37 | #: E201 E202 E721 +38 | assert type(res) == type( (0, ) ) + | + +E721.py:38:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks + | +36 | assert type(res) == type( ( ) ) +37 | #: E201 E202 E721 +38 | assert type(res) == type( (0, ) ) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ E721 +39 | #: + | + + From b5ff2c83abfa62e71ddf08c3ed26912135a4e9d6 Mon Sep 17 00:00:00 2001 From: Tom Kuson Date: Sat, 4 Nov 2023 17:35:32 +0000 Subject: [PATCH 4/5] Fix test screw-up --- crates/ruff_linter/src/rules/pyflakes/mod.rs | 44 ++++--- ...yflakes__tests__preview__E721_E721.py.snap | 112 ------------------ ...lakes__tests__preview__F841_F841_4.py.snap | 41 +++++++ 3 files changed, 61 insertions(+), 136 deletions(-) delete mode 100644 crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__preview__E721_E721.py.snap create mode 100644 crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__preview__F841_F841_4.py.snap diff --git a/crates/ruff_linter/src/rules/pyflakes/mod.rs b/crates/ruff_linter/src/rules/pyflakes/mod.rs index 537ecacb8e1e1..e5b1ad111c6e8 100644 --- a/crates/ruff_linter/src/rules/pyflakes/mod.rs +++ b/crates/ruff_linter/src/rules/pyflakes/mod.rs @@ -30,7 +30,7 @@ mod tests { use crate::settings::{flags, LinterSettings}; use crate::source_kind::SourceKind; use crate::test::{test_path, test_snippet}; - use crate::{assert_messages, directives, settings}; + use crate::{assert_messages, directives}; #[test_case(Rule::UnusedImport, Path::new("F401_0.py"))] #[test_case(Rule::UnusedImport, Path::new("F401_1.py"))] @@ -147,7 +147,19 @@ mod tests { #[test_case(Rule::UnusedVariable, Path::new("F841_2.py"))] #[test_case(Rule::UnusedVariable, Path::new("F841_3.py"))] #[test_case(Rule::UnusedVariable, Path::new("F841_4.py"))] - #[test_case(Rule::TypeComparison, Path::new("E721.py"))] + #[test_case(Rule::UnusedAnnotation, Path::new("F842.py"))] + #[test_case(Rule::RaiseNotImplemented, Path::new("F901.py"))] + fn rules(rule_code: Rule, path: &Path) -> Result<()> { + let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy()); + let diagnostics = test_path( + Path::new("pyflakes").join(path).as_path(), + &LinterSettings::for_rule(rule_code), + )?; + assert_messages!(snapshot, diagnostics); + Ok(()) + } + + #[test_case(Rule::UnusedVariable, Path::new("F841_4.py"))] fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> { let snapshot = format!( "preview__{}_{}", @@ -155,28 +167,16 @@ mod tests { path.to_string_lossy() ); let diagnostics = test_path( - Path::new("pycodestyle").join(path).as_path(), - &settings::LinterSettings { + Path::new("pyflakes").join(path).as_path(), + &LinterSettings { preview: PreviewMode::Enabled, - ..settings::LinterSettings::for_rule(rule_code) + ..LinterSettings::for_rule(rule_code) }, )?; assert_messages!(snapshot, diagnostics); Ok(()) } - #[test_case(Rule::UnusedAnnotation, Path::new("F842.py"))] - #[test_case(Rule::RaiseNotImplemented, Path::new("F901.py"))] - fn rules(rule_code: Rule, path: &Path) -> Result<()> { - let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy()); - let diagnostics = test_path( - Path::new("pyflakes").join(path).as_path(), - &LinterSettings::for_rule(rule_code), - )?; - assert_messages!(snapshot, diagnostics); - Ok(()) - } - #[test] fn f841_dummy_variable_rgx() -> Result<()> { let diagnostics = test_path( @@ -1153,25 +1153,21 @@ mod tests { def f(): a, *b = range(10) "#, - &[Rule::UnusedVariable, Rule::UnusedVariable], + &[], ); flakes( r#" def f(): (*a, b) = range(10) "#, - &[Rule::UnusedVariable, Rule::UnusedVariable], + &[], ); flakes( r#" def f(): [a, *b, c] = range(10) "#, - &[ - Rule::UnusedVariable, - Rule::UnusedVariable, - Rule::UnusedVariable, - ], + &[], ); } diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__preview__E721_E721.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__preview__E721_E721.py.snap deleted file mode 100644 index 6faca091b1576..0000000000000 --- a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__preview__E721_E721.py.snap +++ /dev/null @@ -1,112 +0,0 @@ ---- -source: crates/ruff_linter/src/rules/pyflakes/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 | #: Okay - | - -E721.py:18:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks - | -16 | pass -17 | #: E721 -18 | assert type(res) == type(False) or type(res) == type(None) - | ^^^^^^^^^^^^^^^^^^^^^^^^ E721 -19 | #: E721 -20 | assert type(res) == type([]) - | - -E721.py:20:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks - | -18 | assert type(res) == type(False) or type(res) == type(None) -19 | #: E721 -20 | assert type(res) == type([]) - | ^^^^^^^^^^^^^^^^^^^^^ E721 -21 | #: E721 -22 | assert type(res) == type(()) - | - -E721.py:22:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks - | -20 | assert type(res) == type([]) -21 | #: E721 -22 | assert type(res) == type(()) - | ^^^^^^^^^^^^^^^^^^^^^ E721 -23 | #: E721 -24 | assert type(res) == type((0,)) - | - -E721.py:24:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks - | -22 | assert type(res) == type(()) -23 | #: E721 -24 | assert type(res) == type((0,)) - | ^^^^^^^^^^^^^^^^^^^^^^^ E721 -25 | #: E721 -26 | assert type(res) == type((0)) - | - -E721.py:26:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks - | -24 | assert type(res) == type((0,)) -25 | #: E721 -26 | assert type(res) == type((0)) - | ^^^^^^^^^^^^^^^^^^^^^^ E721 -27 | #: E721 -28 | assert type(res) != type((1, )) - | - -E721.py:28:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks - | -26 | assert type(res) == type((0)) -27 | #: E721 -28 | assert type(res) != type((1, )) - | ^^^^^^^^^^^^^^^^^^^^^^^^ E721 -29 | #: Okay -30 | assert type(res) is type((1, )) - | - -E721.py:34:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks - | -32 | assert type(res) is not type((1, )) -33 | #: E211 E721 -34 | assert type(res) == type ([2, ]) - | ^^^^^^^^^^^^^^^^^^^^^^^^^ E721 -35 | #: E201 E201 E202 E721 -36 | assert type(res) == type( ( ) ) - | - -E721.py:36:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks - | -34 | assert type(res) == type ([2, ]) -35 | #: E201 E201 E202 E721 -36 | assert type(res) == type( ( ) ) - | ^^^^^^^^^^^^^^^^^^^^^^^^ E721 -37 | #: E201 E202 E721 -38 | assert type(res) == type( (0, ) ) - | - -E721.py:38:8: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks - | -36 | assert type(res) == type( ( ) ) -37 | #: E201 E202 E721 -38 | assert type(res) == type( (0, ) ) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ E721 -39 | #: - | - - diff --git a/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__preview__F841_F841_4.py.snap b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__preview__F841_F841_4.py.snap new file mode 100644 index 0000000000000..1627e74b9aabd --- /dev/null +++ b/crates/ruff_linter/src/rules/pyflakes/snapshots/ruff_linter__rules__pyflakes__tests__preview__F841_F841_4.py.snap @@ -0,0 +1,41 @@ +--- +source: crates/ruff_linter/src/rules/pyflakes/mod.rs +--- +F841_4.py:12:5: F841 [*] Local variable `a` is assigned to but never used + | +11 | def bar(): +12 | a = foo() + | ^ F841 +13 | b, c = foo() + | + = help: Remove assignment to unused variable `a` + +ℹ Suggested fix +9 9 | +10 10 | +11 11 | def bar(): +12 |- a = foo() + 12 |+ foo() +13 13 | b, c = foo() +14 14 | +15 15 | + +F841_4.py:13:5: F841 Local variable `b` is assigned to but never used + | +11 | def bar(): +12 | a = foo() +13 | b, c = foo() + | ^ F841 + | + = help: Remove assignment to unused variable `b` + +F841_4.py:13:8: F841 Local variable `c` is assigned to but never used + | +11 | def bar(): +12 | a = foo() +13 | b, c = foo() + | ^ F841 + | + = help: Remove assignment to unused variable `c` + + From a54fe5232f373af88f5556151a26801846a063b0 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Sun, 5 Nov 2023 11:49:06 -0500 Subject: [PATCH 5/5] Tweak --- crates/ruff_linter/src/rules/pyflakes/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ruff_linter/src/rules/pyflakes/mod.rs b/crates/ruff_linter/src/rules/pyflakes/mod.rs index e5b1ad111c6e8..cfd3f54749261 100644 --- a/crates/ruff_linter/src/rules/pyflakes/mod.rs +++ b/crates/ruff_linter/src/rules/pyflakes/mod.rs @@ -1146,8 +1146,8 @@ mod tests { #[test] fn used_as_star_unpack() { - // Star names in unpack are used if RHS is not a tuple/list literal. - // EDIT: Behaviour changed to fix issue #8441. + // In stable, starred names in unpack are used if RHS is not a tuple/list literal. + // In preview, these should be marked as unused. flakes( r#" def f():