mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-02 09:52:18 +00:00
Add new rule RUF059: Unused unpacked assignment (#16449)
Split from F841 following discussion in #8884. Fixes #8884. <!-- Thank you for contributing to Ruff! To help us out with reviewing, please consider the following: - Does this pull request include a summary of the change? (See below.) - Does this pull request include a descriptive title? - Does this pull request include references to any relevant issues? --> ## Summary <!-- What's the purpose of the change? What does it do, and why? --> Add a new rule for unused assignments in tuples. Remove similar behavior from F841. ## Test Plan Adapt F841 tests and move them over to the new rule. <!-- How was it tested? --> --------- Co-authored-by: Micha Reiser <micha@reiser.io>
This commit is contained in:
parent
be239b9f25
commit
c80678a1c0
20 changed files with 893 additions and 132 deletions
96
crates/ruff_linter/resources/test/fixtures/ruff/RUF059_0.py
vendored
Normal file
96
crates/ruff_linter/resources/test/fixtures/ruff/RUF059_0.py
vendored
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
try:
|
||||||
|
1 / 0
|
||||||
|
except ValueError as e:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
1 / 0
|
||||||
|
except ValueError as e:
|
||||||
|
print(e)
|
||||||
|
|
||||||
|
|
||||||
|
def f():
|
||||||
|
x = 1
|
||||||
|
y = 2
|
||||||
|
z = x + y
|
||||||
|
|
||||||
|
|
||||||
|
def f():
|
||||||
|
foo = (1, 2)
|
||||||
|
(a, b) = (1, 2)
|
||||||
|
|
||||||
|
bar = (1, 2)
|
||||||
|
(c, d) = bar
|
||||||
|
|
||||||
|
(x, y) = baz = bar
|
||||||
|
|
||||||
|
|
||||||
|
def f():
|
||||||
|
locals()
|
||||||
|
x = 1
|
||||||
|
|
||||||
|
|
||||||
|
def f():
|
||||||
|
_ = 1
|
||||||
|
__ = 1
|
||||||
|
_discarded = 1
|
||||||
|
|
||||||
|
|
||||||
|
a = 1
|
||||||
|
|
||||||
|
|
||||||
|
def f():
|
||||||
|
global a
|
||||||
|
|
||||||
|
# Used in `c` via `nonlocal`.
|
||||||
|
b = 1
|
||||||
|
|
||||||
|
def c():
|
||||||
|
# F841
|
||||||
|
b = 1
|
||||||
|
|
||||||
|
def d():
|
||||||
|
nonlocal b
|
||||||
|
|
||||||
|
|
||||||
|
def f():
|
||||||
|
annotations = []
|
||||||
|
assert len([annotations for annotations in annotations])
|
||||||
|
|
||||||
|
|
||||||
|
def f():
|
||||||
|
def connect():
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
with connect() as (connection, cursor):
|
||||||
|
cursor.execute("SELECT * FROM users")
|
||||||
|
|
||||||
|
|
||||||
|
def f():
|
||||||
|
def connect():
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
with connect() as (connection, cursor):
|
||||||
|
cursor.execute("SELECT * FROM users")
|
||||||
|
|
||||||
|
|
||||||
|
def f():
|
||||||
|
with open("file") as my_file, open("") as ((this, that)):
|
||||||
|
print("hello")
|
||||||
|
|
||||||
|
|
||||||
|
def f():
|
||||||
|
with (
|
||||||
|
open("file") as my_file,
|
||||||
|
open("") as ((this, that)),
|
||||||
|
):
|
||||||
|
print("hello")
|
||||||
|
|
||||||
|
|
||||||
|
def f():
|
||||||
|
exponential, base_multiplier = 1, 2
|
||||||
|
hash_map = {
|
||||||
|
(exponential := (exponential * base_multiplier) % 3): i + 1 for i in range(2)
|
||||||
|
}
|
||||||
|
return hash_map
|
24
crates/ruff_linter/resources/test/fixtures/ruff/RUF059_1.py
vendored
Normal file
24
crates/ruff_linter/resources/test/fixtures/ruff/RUF059_1.py
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
def f(tup):
|
||||||
|
x, y = tup
|
||||||
|
|
||||||
|
|
||||||
|
def f():
|
||||||
|
x, y = 1, 2 # this triggers RUF059 as it's just a simple assignment where unpacking isn't needed
|
||||||
|
|
||||||
|
|
||||||
|
def f():
|
||||||
|
(x, y) = coords = 1, 2
|
||||||
|
if x > 1:
|
||||||
|
print(coords)
|
||||||
|
|
||||||
|
|
||||||
|
def f():
|
||||||
|
(x, y) = coords = 1, 2
|
||||||
|
|
||||||
|
|
||||||
|
def f():
|
||||||
|
coords = (x, y) = 1, 2
|
||||||
|
|
||||||
|
|
||||||
|
def f():
|
||||||
|
(a, b) = (x, y) = 1, 2 # this triggers RUF059 on everything
|
31
crates/ruff_linter/resources/test/fixtures/ruff/RUF059_2.py
vendored
Normal file
31
crates/ruff_linter/resources/test/fixtures/ruff/RUF059_2.py
vendored
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
"""Test case for fixing RUF059 violations."""
|
||||||
|
|
||||||
|
|
||||||
|
def f():
|
||||||
|
with foo() as x1:
|
||||||
|
pass
|
||||||
|
|
||||||
|
with foo() as (x2, y2):
|
||||||
|
pass
|
||||||
|
|
||||||
|
with (foo() as x3, foo() as y3, foo() as z3):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def f():
|
||||||
|
(x1, y1) = (1, 2)
|
||||||
|
(x2, y2) = coords2 = (1, 2)
|
||||||
|
coords3 = (x3, y3) = (1, 2)
|
||||||
|
|
||||||
|
|
||||||
|
def f():
|
||||||
|
with Nested(m) as (x, y):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def f():
|
||||||
|
toplevel = (a, b) = lexer.get_token()
|
||||||
|
|
||||||
|
|
||||||
|
def f():
|
||||||
|
(a, b) = toplevel = lexer.get_token()
|
|
@ -48,6 +48,7 @@ pub(crate) fn deferred_scopes(checker: &Checker) {
|
||||||
Rule::UnusedPrivateTypedDict,
|
Rule::UnusedPrivateTypedDict,
|
||||||
Rule::UnusedPrivateTypeVar,
|
Rule::UnusedPrivateTypeVar,
|
||||||
Rule::UnusedStaticMethodArgument,
|
Rule::UnusedStaticMethodArgument,
|
||||||
|
Rule::UnusedUnpackedVariable,
|
||||||
Rule::UnusedVariable,
|
Rule::UnusedVariable,
|
||||||
]) {
|
]) {
|
||||||
return;
|
return;
|
||||||
|
@ -390,8 +391,43 @@ pub(crate) fn deferred_scopes(checker: &Checker) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if matches!(scope.kind, ScopeKind::Function(_) | ScopeKind::Lambda(_)) {
|
if matches!(scope.kind, ScopeKind::Function(_) | ScopeKind::Lambda(_)) {
|
||||||
if checker.enabled(Rule::UnusedVariable) {
|
if checker.any_enabled(&[Rule::UnusedVariable, Rule::UnusedUnpackedVariable])
|
||||||
pyflakes::rules::unused_variable(checker, scope);
|
&& !(scope.uses_locals() && scope.kind.is_function())
|
||||||
|
{
|
||||||
|
let unused_bindings = scope
|
||||||
|
.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()
|
||||||
|
|| binding.kind.is_with_item_var())
|
||||||
|
&& binding.is_unused()
|
||||||
|
&& !binding.is_nonlocal()
|
||||||
|
&& !binding.is_global()
|
||||||
|
&& !checker.settings.dummy_variable_rgx.is_match(name)
|
||||||
|
&& !matches!(
|
||||||
|
name,
|
||||||
|
"__tracebackhide__"
|
||||||
|
| "__traceback_info__"
|
||||||
|
| "__traceback_supplement__"
|
||||||
|
| "__debuggerskip__"
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return Some((name, binding));
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
});
|
||||||
|
|
||||||
|
for (unused_name, unused_binding) in unused_bindings {
|
||||||
|
if checker.enabled(Rule::UnusedVariable) {
|
||||||
|
pyflakes::rules::unused_variable(checker, unused_name, unused_binding);
|
||||||
|
}
|
||||||
|
|
||||||
|
if checker.enabled(Rule::UnusedUnpackedVariable) {
|
||||||
|
ruff::rules::unused_unpacked_variable(checker, unused_name, unused_binding);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if checker.enabled(Rule::UnusedAnnotation) {
|
if checker.enabled(Rule::UnusedAnnotation) {
|
||||||
|
|
|
@ -1012,6 +1012,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
||||||
(Ruff, "056") => (RuleGroup::Preview, rules::ruff::rules::FalsyDictGetFallback),
|
(Ruff, "056") => (RuleGroup::Preview, rules::ruff::rules::FalsyDictGetFallback),
|
||||||
(Ruff, "057") => (RuleGroup::Preview, rules::ruff::rules::UnnecessaryRound),
|
(Ruff, "057") => (RuleGroup::Preview, rules::ruff::rules::UnnecessaryRound),
|
||||||
(Ruff, "058") => (RuleGroup::Preview, rules::ruff::rules::StarmapZip),
|
(Ruff, "058") => (RuleGroup::Preview, rules::ruff::rules::StarmapZip),
|
||||||
|
(Ruff, "059") => (RuleGroup::Preview, rules::ruff::rules::UnusedUnpackedVariable),
|
||||||
(Ruff, "100") => (RuleGroup::Stable, rules::ruff::rules::UnusedNOQA),
|
(Ruff, "100") => (RuleGroup::Stable, rules::ruff::rules::UnusedNOQA),
|
||||||
(Ruff, "101") => (RuleGroup::Stable, rules::ruff::rules::RedirectedNOQA),
|
(Ruff, "101") => (RuleGroup::Stable, rules::ruff::rules::RedirectedNOQA),
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_linter/src/message/sarif.rs
|
source: crates/ruff_linter/src/message/sarif.rs
|
||||||
expression: value
|
expression: value
|
||||||
snapshot_kind: text
|
|
||||||
---
|
---
|
||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/sarif-2.1.0.json",
|
"$schema": "https://json.schemastore.org/sarif-2.1.0.json",
|
||||||
|
@ -120,7 +119,7 @@ snapshot_kind: text
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fullDescription": {
|
"fullDescription": {
|
||||||
"text": "## What it does\nChecks for the presence of unused variables in function scopes.\n\n## Why is this bad?\nA variable that is defined but not used is likely a mistake, and should\nbe removed to avoid confusion.\n\nIf a variable is intentionally defined-but-not-used, it should be\nprefixed with an underscore, or some other value that adheres to the\n[`lint.dummy-variable-rgx`] pattern.\n\nUnder [preview mode](https://docs.astral.sh/ruff/preview), this rule also\ntriggers on unused unpacked assignments (for example, `x, y = foo()`).\n\n## Example\n```python\ndef foo():\n x = 1\n y = 2\n return x\n```\n\nUse instead:\n```python\ndef foo():\n x = 1\n return x\n```\n\n## Options\n- `lint.dummy-variable-rgx`\n"
|
"text": "## What it does\nChecks for the presence of unused variables in function scopes.\n\n## Why is this bad?\nA variable that is defined but not used is likely a mistake, and should\nbe removed to avoid confusion.\n\nIf a variable is intentionally defined-but-not-used, it should be\nprefixed with an underscore, or some other value that adheres to the\n[`lint.dummy-variable-rgx`] pattern.\n\n## Example\n```python\ndef foo():\n x = 1\n y = 2\n return x\n```\n\nUse instead:\n```python\ndef foo():\n x = 1\n return x\n```\n\n## Options\n- `lint.dummy-variable-rgx`\n"
|
||||||
},
|
},
|
||||||
"help": {
|
"help": {
|
||||||
"text": "Local variable `{name}` is assigned to but never used"
|
"text": "Local variable `{name}` is assigned to but never used"
|
||||||
|
|
|
@ -178,7 +178,6 @@ mod tests {
|
||||||
#[test_case(Rule::UnusedVariable, Path::new("F841_1.py"))]
|
#[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_2.py"))]
|
||||||
#[test_case(Rule::UnusedVariable, Path::new("F841_3.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::UnusedAnnotation, Path::new("F842.py"))]
|
||||||
#[test_case(Rule::RaiseNotImplemented, Path::new("F901.py"))]
|
#[test_case(Rule::RaiseNotImplemented, Path::new("F901.py"))]
|
||||||
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||||
|
@ -226,7 +225,6 @@ mod tests {
|
||||||
assert_messages!(diagnostics);
|
assert_messages!(diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test_case(Rule::UnusedVariable, Path::new("F841_4.py"))]
|
|
||||||
#[test_case(Rule::UnusedImport, Path::new("__init__.py"))]
|
#[test_case(Rule::UnusedImport, Path::new("__init__.py"))]
|
||||||
#[test_case(Rule::UnusedImport, Path::new("F401_24/__init__.py"))]
|
#[test_case(Rule::UnusedImport, Path::new("F401_24/__init__.py"))]
|
||||||
#[test_case(Rule::UnusedImport, Path::new("F401_25__all_nonempty/__init__.py"))]
|
#[test_case(Rule::UnusedImport, Path::new("F401_25__all_nonempty/__init__.py"))]
|
||||||
|
|
|
@ -6,7 +6,7 @@ use ruff_python_ast::helpers::contains_effect;
|
||||||
use ruff_python_ast::parenthesize::parenthesized_range;
|
use ruff_python_ast::parenthesize::parenthesized_range;
|
||||||
use ruff_python_ast::{self as ast, Stmt};
|
use ruff_python_ast::{self as ast, Stmt};
|
||||||
use ruff_python_parser::{TokenKind, Tokens};
|
use ruff_python_parser::{TokenKind, Tokens};
|
||||||
use ruff_python_semantic::{Binding, Scope};
|
use ruff_python_semantic::Binding;
|
||||||
use ruff_text_size::{Ranged, TextRange, TextSize};
|
use ruff_text_size::{Ranged, TextRange, TextSize};
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
|
@ -23,9 +23,6 @@ use crate::fix::edits::delete_stmt;
|
||||||
/// prefixed with an underscore, or some other value that adheres to the
|
/// prefixed with an underscore, or some other value that adheres to the
|
||||||
/// [`lint.dummy-variable-rgx`] pattern.
|
/// [`lint.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
|
/// ## Example
|
||||||
/// ```python
|
/// ```python
|
||||||
/// def foo():
|
/// def foo():
|
||||||
|
@ -249,47 +246,19 @@ fn remove_unused_variable(binding: &Binding, checker: &Checker) -> Option<Fix> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// F841
|
/// F841
|
||||||
pub(crate) fn unused_variable(checker: &Checker, scope: &Scope) {
|
pub(crate) fn unused_variable(checker: &Checker, name: &str, binding: &Binding) {
|
||||||
if scope.uses_locals() && scope.kind.is_function() {
|
if binding.is_unpacked_assignment() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (name, binding) in scope
|
let mut diagnostic = Diagnostic::new(
|
||||||
.bindings()
|
UnusedVariable {
|
||||||
.map(|(name, binding_id)| (name, checker.semantic().binding(binding_id)))
|
name: name.to_string(),
|
||||||
.filter_map(|(name, binding)| {
|
},
|
||||||
if (binding.kind.is_assignment()
|
binding.range(),
|
||||||
|| binding.kind.is_named_expr_assignment()
|
);
|
||||||
|| binding.kind.is_with_item_var())
|
if let Some(fix) = remove_unused_variable(binding, checker) {
|
||||||
// Stabilization depends on resolving https://github.com/astral-sh/ruff/issues/8884
|
diagnostic.set_fix(fix);
|
||||||
&& (!binding.is_unpacked_assignment() || checker.settings.preview.is_enabled())
|
|
||||||
&& binding.is_unused()
|
|
||||||
&& !binding.is_nonlocal()
|
|
||||||
&& !binding.is_global()
|
|
||||||
&& !checker.settings.dummy_variable_rgx.is_match(name)
|
|
||||||
&& !matches!(
|
|
||||||
name,
|
|
||||||
"__tracebackhide__"
|
|
||||||
| "__traceback_info__"
|
|
||||||
| "__traceback_supplement__"
|
|
||||||
| "__debuggerskip__"
|
|
||||||
)
|
|
||||||
{
|
|
||||||
return Some((name, binding));
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
})
|
|
||||||
{
|
|
||||||
let mut diagnostic = Diagnostic::new(
|
|
||||||
UnusedVariable {
|
|
||||||
name: name.to_string(),
|
|
||||||
},
|
|
||||||
binding.range(),
|
|
||||||
);
|
|
||||||
if let Some(fix) = remove_unused_variable(binding, checker) {
|
|
||||||
diagnostic.set_fix(fix);
|
|
||||||
}
|
|
||||||
checker.report_diagnostic(diagnostic);
|
|
||||||
}
|
}
|
||||||
|
checker.report_diagnostic(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
---
|
|
||||||
source: crates/ruff_linter/src/rules/pyflakes/mod.rs
|
|
||||||
snapshot_kind: text
|
|
||||||
---
|
|
||||||
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`
|
|
||||||
|
|
||||||
ℹ Unsafe fix
|
|
||||||
9 9 |
|
|
||||||
10 10 |
|
|
||||||
11 11 | def bar():
|
|
||||||
12 |- a = foo()
|
|
||||||
12 |+ foo()
|
|
||||||
13 13 | b, c = foo()
|
|
||||||
14 14 |
|
|
||||||
15 15 |
|
|
|
@ -1,60 +0,0 @@
|
||||||
---
|
|
||||||
source: crates/ruff_linter/src/rules/pyflakes/mod.rs
|
|
||||||
snapshot_kind: text
|
|
||||||
---
|
|
||||||
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`
|
|
||||||
|
|
||||||
ℹ Unsafe 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`
|
|
||||||
|
|
||||||
ℹ Unsafe fix
|
|
||||||
10 10 |
|
|
||||||
11 11 | def bar():
|
|
||||||
12 12 | a = foo()
|
|
||||||
13 |- b, c = foo()
|
|
||||||
13 |+ _b, c = foo()
|
|
||||||
14 14 |
|
|
||||||
15 15 |
|
|
||||||
16 16 | def baz():
|
|
||||||
|
|
||||||
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`
|
|
||||||
|
|
||||||
ℹ Unsafe fix
|
|
||||||
10 10 |
|
|
||||||
11 11 | def bar():
|
|
||||||
12 12 | a = foo()
|
|
||||||
13 |- b, c = foo()
|
|
||||||
13 |+ b, _c = foo()
|
|
||||||
14 14 |
|
|
||||||
15 15 |
|
|
||||||
16 16 | def baz():
|
|
|
@ -90,6 +90,10 @@ mod tests {
|
||||||
#[test_case(Rule::IfKeyInDictDel, Path::new("RUF051.py"))]
|
#[test_case(Rule::IfKeyInDictDel, Path::new("RUF051.py"))]
|
||||||
#[test_case(Rule::UsedDummyVariable, Path::new("RUF052.py"))]
|
#[test_case(Rule::UsedDummyVariable, Path::new("RUF052.py"))]
|
||||||
#[test_case(Rule::FalsyDictGetFallback, Path::new("RUF056.py"))]
|
#[test_case(Rule::FalsyDictGetFallback, Path::new("RUF056.py"))]
|
||||||
|
#[test_case(Rule::UnusedUnpackedVariable, Path::new("RUF059_0.py"))]
|
||||||
|
#[test_case(Rule::UnusedUnpackedVariable, Path::new("RUF059_1.py"))]
|
||||||
|
#[test_case(Rule::UnusedUnpackedVariable, Path::new("RUF059_2.py"))]
|
||||||
|
#[test_case(Rule::UnusedUnpackedVariable, Path::new("RUF059_3.py"))]
|
||||||
#[test_case(Rule::RedirectedNOQA, Path::new("RUF101_0.py"))]
|
#[test_case(Rule::RedirectedNOQA, Path::new("RUF101_0.py"))]
|
||||||
#[test_case(Rule::RedirectedNOQA, Path::new("RUF101_1.py"))]
|
#[test_case(Rule::RedirectedNOQA, Path::new("RUF101_1.py"))]
|
||||||
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||||
|
|
|
@ -50,6 +50,7 @@ pub(crate) use unraw_re_pattern::*;
|
||||||
pub(crate) use unsafe_markup_use::*;
|
pub(crate) use unsafe_markup_use::*;
|
||||||
pub(crate) use unused_async::*;
|
pub(crate) use unused_async::*;
|
||||||
pub(crate) use unused_noqa::*;
|
pub(crate) use unused_noqa::*;
|
||||||
|
pub(crate) use unused_unpacked_variable::*;
|
||||||
pub(crate) use used_dummy_variable::*;
|
pub(crate) use used_dummy_variable::*;
|
||||||
pub(crate) use useless_if_else::*;
|
pub(crate) use useless_if_else::*;
|
||||||
pub(crate) use zip_instead_of_pairwise::*;
|
pub(crate) use zip_instead_of_pairwise::*;
|
||||||
|
@ -110,6 +111,7 @@ mod unraw_re_pattern;
|
||||||
mod unsafe_markup_use;
|
mod unsafe_markup_use;
|
||||||
mod unused_async;
|
mod unused_async;
|
||||||
mod unused_noqa;
|
mod unused_noqa;
|
||||||
|
mod unused_unpacked_variable;
|
||||||
mod used_dummy_variable;
|
mod used_dummy_variable;
|
||||||
mod useless_if_else;
|
mod useless_if_else;
|
||||||
mod zip_instead_of_pairwise;
|
mod zip_instead_of_pairwise;
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
|
||||||
|
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
||||||
|
use ruff_python_semantic::Binding;
|
||||||
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
|
use crate::checkers::ast::Checker;
|
||||||
|
|
||||||
|
/// ## What it does
|
||||||
|
/// Checks for the presence of unused variables in unpacked assignments.
|
||||||
|
///
|
||||||
|
/// ## Why is this bad?
|
||||||
|
/// A variable that is defined but never used can confuse readers.
|
||||||
|
///
|
||||||
|
/// If a variable is intentionally defined-but-not-used, it should be
|
||||||
|
/// prefixed with an underscore, or some other value that adheres to the
|
||||||
|
/// [`lint.dummy-variable-rgx`] pattern.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
///
|
||||||
|
/// ```python
|
||||||
|
/// def get_pair():
|
||||||
|
/// return 1, 2
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// def foo():
|
||||||
|
/// x, y = get_pair()
|
||||||
|
/// return x
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Use instead:
|
||||||
|
///
|
||||||
|
/// ```python
|
||||||
|
/// def foo():
|
||||||
|
/// x, _ = get_pair()
|
||||||
|
/// return x
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## Options
|
||||||
|
/// - `lint.dummy-variable-rgx`
|
||||||
|
#[derive(ViolationMetadata)]
|
||||||
|
pub(crate) struct UnusedUnpackedVariable {
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Violation for UnusedUnpackedVariable {
|
||||||
|
const FIX_AVAILABILITY: FixAvailability = FixAvailability::Sometimes;
|
||||||
|
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
let UnusedUnpackedVariable { name } = self;
|
||||||
|
format!("Unpacked variable `{name}` is never used")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fix_title(&self) -> Option<String> {
|
||||||
|
Some("Prefix it with an underscore or any other dummy variable pattern".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate a [`Edit`] to remove an unused variable assignment to a [`Binding`].
|
||||||
|
fn remove_unused_variable(binding: &Binding, checker: &Checker) -> Option<Fix> {
|
||||||
|
let node_id = binding.source?;
|
||||||
|
let isolation = Checker::isolation(checker.semantic().parent_statement_id(node_id));
|
||||||
|
|
||||||
|
let name = binding.name(checker.source());
|
||||||
|
let renamed = format!("_{name}");
|
||||||
|
if checker.settings.dummy_variable_rgx.is_match(&renamed) {
|
||||||
|
let edit = Edit::range_replacement(renamed, binding.range());
|
||||||
|
|
||||||
|
return Some(Fix::unsafe_edit(edit).isolate(isolation));
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// RUF059
|
||||||
|
pub(crate) fn unused_unpacked_variable(checker: &Checker, name: &str, binding: &Binding) {
|
||||||
|
if !binding.is_unpacked_assignment() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut diagnostic = Diagnostic::new(
|
||||||
|
UnusedUnpackedVariable {
|
||||||
|
name: name.to_string(),
|
||||||
|
},
|
||||||
|
binding.range(),
|
||||||
|
);
|
||||||
|
if let Some(fix) = remove_unused_variable(binding, checker) {
|
||||||
|
diagnostic.set_fix(fix);
|
||||||
|
}
|
||||||
|
checker.report_diagnostic(diagnostic);
|
||||||
|
}
|
|
@ -0,0 +1,200 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/ruff/mod.rs
|
||||||
|
---
|
||||||
|
RUF059_0.py:24:6: RUF059 [*] Unpacked variable `c` is never used
|
||||||
|
|
|
||||||
|
23 | bar = (1, 2)
|
||||||
|
24 | (c, d) = bar
|
||||||
|
| ^ RUF059
|
||||||
|
25 |
|
||||||
|
26 | (x, y) = baz = bar
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
21 21 | (a, b) = (1, 2)
|
||||||
|
22 22 |
|
||||||
|
23 23 | bar = (1, 2)
|
||||||
|
24 |- (c, d) = bar
|
||||||
|
24 |+ (_c, d) = bar
|
||||||
|
25 25 |
|
||||||
|
26 26 | (x, y) = baz = bar
|
||||||
|
27 27 |
|
||||||
|
|
||||||
|
RUF059_0.py:24:9: RUF059 [*] Unpacked variable `d` is never used
|
||||||
|
|
|
||||||
|
23 | bar = (1, 2)
|
||||||
|
24 | (c, d) = bar
|
||||||
|
| ^ RUF059
|
||||||
|
25 |
|
||||||
|
26 | (x, y) = baz = bar
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
21 21 | (a, b) = (1, 2)
|
||||||
|
22 22 |
|
||||||
|
23 23 | bar = (1, 2)
|
||||||
|
24 |- (c, d) = bar
|
||||||
|
24 |+ (c, _d) = bar
|
||||||
|
25 25 |
|
||||||
|
26 26 | (x, y) = baz = bar
|
||||||
|
27 27 |
|
||||||
|
|
||||||
|
RUF059_0.py:26:6: RUF059 [*] Unpacked variable `x` is never used
|
||||||
|
|
|
||||||
|
24 | (c, d) = bar
|
||||||
|
25 |
|
||||||
|
26 | (x, y) = baz = bar
|
||||||
|
| ^ RUF059
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
23 23 | bar = (1, 2)
|
||||||
|
24 24 | (c, d) = bar
|
||||||
|
25 25 |
|
||||||
|
26 |- (x, y) = baz = bar
|
||||||
|
26 |+ (_x, y) = baz = bar
|
||||||
|
27 27 |
|
||||||
|
28 28 |
|
||||||
|
29 29 | def f():
|
||||||
|
|
||||||
|
RUF059_0.py:26:9: RUF059 [*] Unpacked variable `y` is never used
|
||||||
|
|
|
||||||
|
24 | (c, d) = bar
|
||||||
|
25 |
|
||||||
|
26 | (x, y) = baz = bar
|
||||||
|
| ^ RUF059
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
23 23 | bar = (1, 2)
|
||||||
|
24 24 | (c, d) = bar
|
||||||
|
25 25 |
|
||||||
|
26 |- (x, y) = baz = bar
|
||||||
|
26 |+ (x, _y) = baz = bar
|
||||||
|
27 27 |
|
||||||
|
28 28 |
|
||||||
|
29 29 | def f():
|
||||||
|
|
||||||
|
RUF059_0.py:66:24: RUF059 [*] Unpacked variable `connection` is never used
|
||||||
|
|
|
||||||
|
64 | return None, None
|
||||||
|
65 |
|
||||||
|
66 | with connect() as (connection, cursor):
|
||||||
|
| ^^^^^^^^^^ RUF059
|
||||||
|
67 | cursor.execute("SELECT * FROM users")
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
63 63 | def connect():
|
||||||
|
64 64 | return None, None
|
||||||
|
65 65 |
|
||||||
|
66 |- with connect() as (connection, cursor):
|
||||||
|
66 |+ with connect() as (_connection, cursor):
|
||||||
|
67 67 | cursor.execute("SELECT * FROM users")
|
||||||
|
68 68 |
|
||||||
|
69 69 |
|
||||||
|
|
||||||
|
RUF059_0.py:74:24: RUF059 [*] Unpacked variable `connection` is never used
|
||||||
|
|
|
||||||
|
72 | return None, None
|
||||||
|
73 |
|
||||||
|
74 | with connect() as (connection, cursor):
|
||||||
|
| ^^^^^^^^^^ RUF059
|
||||||
|
75 | cursor.execute("SELECT * FROM users")
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
71 71 | def connect():
|
||||||
|
72 72 | return None, None
|
||||||
|
73 73 |
|
||||||
|
74 |- with connect() as (connection, cursor):
|
||||||
|
74 |+ with connect() as (_connection, cursor):
|
||||||
|
75 75 | cursor.execute("SELECT * FROM users")
|
||||||
|
76 76 |
|
||||||
|
77 77 |
|
||||||
|
|
||||||
|
RUF059_0.py:79:49: RUF059 [*] Unpacked variable `this` is never used
|
||||||
|
|
|
||||||
|
78 | def f():
|
||||||
|
79 | with open("file") as my_file, open("") as ((this, that)):
|
||||||
|
| ^^^^ RUF059
|
||||||
|
80 | print("hello")
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
76 76 |
|
||||||
|
77 77 |
|
||||||
|
78 78 | def f():
|
||||||
|
79 |- with open("file") as my_file, open("") as ((this, that)):
|
||||||
|
79 |+ with open("file") as my_file, open("") as ((_this, that)):
|
||||||
|
80 80 | print("hello")
|
||||||
|
81 81 |
|
||||||
|
82 82 |
|
||||||
|
|
||||||
|
RUF059_0.py:79:55: RUF059 [*] Unpacked variable `that` is never used
|
||||||
|
|
|
||||||
|
78 | def f():
|
||||||
|
79 | with open("file") as my_file, open("") as ((this, that)):
|
||||||
|
| ^^^^ RUF059
|
||||||
|
80 | print("hello")
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
76 76 |
|
||||||
|
77 77 |
|
||||||
|
78 78 | def f():
|
||||||
|
79 |- with open("file") as my_file, open("") as ((this, that)):
|
||||||
|
79 |+ with open("file") as my_file, open("") as ((this, _that)):
|
||||||
|
80 80 | print("hello")
|
||||||
|
81 81 |
|
||||||
|
82 82 |
|
||||||
|
|
||||||
|
RUF059_0.py:86:23: RUF059 [*] Unpacked variable `this` is never used
|
||||||
|
|
|
||||||
|
84 | with (
|
||||||
|
85 | open("file") as my_file,
|
||||||
|
86 | open("") as ((this, that)),
|
||||||
|
| ^^^^ RUF059
|
||||||
|
87 | ):
|
||||||
|
88 | print("hello")
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
83 83 | def f():
|
||||||
|
84 84 | with (
|
||||||
|
85 85 | open("file") as my_file,
|
||||||
|
86 |- open("") as ((this, that)),
|
||||||
|
86 |+ open("") as ((_this, that)),
|
||||||
|
87 87 | ):
|
||||||
|
88 88 | print("hello")
|
||||||
|
89 89 |
|
||||||
|
|
||||||
|
RUF059_0.py:86:29: RUF059 [*] Unpacked variable `that` is never used
|
||||||
|
|
|
||||||
|
84 | with (
|
||||||
|
85 | open("file") as my_file,
|
||||||
|
86 | open("") as ((this, that)),
|
||||||
|
| ^^^^ RUF059
|
||||||
|
87 | ):
|
||||||
|
88 | print("hello")
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
83 83 | def f():
|
||||||
|
84 84 | with (
|
||||||
|
85 85 | open("file") as my_file,
|
||||||
|
86 |- open("") as ((this, that)),
|
||||||
|
86 |+ open("") as ((this, _that)),
|
||||||
|
87 87 | ):
|
||||||
|
88 88 | print("hello")
|
||||||
|
89 89 |
|
|
@ -0,0 +1,126 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/ruff/mod.rs
|
||||||
|
---
|
||||||
|
RUF059_1.py:2:5: RUF059 [*] Unpacked variable `x` is never used
|
||||||
|
|
|
||||||
|
1 | def f(tup):
|
||||||
|
2 | x, y = tup
|
||||||
|
| ^ RUF059
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
1 1 | def f(tup):
|
||||||
|
2 |- x, y = tup
|
||||||
|
2 |+ _x, y = tup
|
||||||
|
3 3 |
|
||||||
|
4 4 |
|
||||||
|
5 5 | def f():
|
||||||
|
|
||||||
|
RUF059_1.py:2:8: RUF059 [*] Unpacked variable `y` is never used
|
||||||
|
|
|
||||||
|
1 | def f(tup):
|
||||||
|
2 | x, y = tup
|
||||||
|
| ^ RUF059
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
1 1 | def f(tup):
|
||||||
|
2 |- x, y = tup
|
||||||
|
2 |+ x, _y = tup
|
||||||
|
3 3 |
|
||||||
|
4 4 |
|
||||||
|
5 5 | def f():
|
||||||
|
|
||||||
|
RUF059_1.py:10:9: RUF059 [*] Unpacked variable `y` is never used
|
||||||
|
|
|
||||||
|
9 | def f():
|
||||||
|
10 | (x, y) = coords = 1, 2
|
||||||
|
| ^ RUF059
|
||||||
|
11 | if x > 1:
|
||||||
|
12 | print(coords)
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
7 7 |
|
||||||
|
8 8 |
|
||||||
|
9 9 | def f():
|
||||||
|
10 |- (x, y) = coords = 1, 2
|
||||||
|
10 |+ (x, _y) = coords = 1, 2
|
||||||
|
11 11 | if x > 1:
|
||||||
|
12 12 | print(coords)
|
||||||
|
13 13 |
|
||||||
|
|
||||||
|
RUF059_1.py:16:6: RUF059 [*] Unpacked variable `x` is never used
|
||||||
|
|
|
||||||
|
15 | def f():
|
||||||
|
16 | (x, y) = coords = 1, 2
|
||||||
|
| ^ RUF059
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
13 13 |
|
||||||
|
14 14 |
|
||||||
|
15 15 | def f():
|
||||||
|
16 |- (x, y) = coords = 1, 2
|
||||||
|
16 |+ (_x, y) = coords = 1, 2
|
||||||
|
17 17 |
|
||||||
|
18 18 |
|
||||||
|
19 19 | def f():
|
||||||
|
|
||||||
|
RUF059_1.py:16:9: RUF059 [*] Unpacked variable `y` is never used
|
||||||
|
|
|
||||||
|
15 | def f():
|
||||||
|
16 | (x, y) = coords = 1, 2
|
||||||
|
| ^ RUF059
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
13 13 |
|
||||||
|
14 14 |
|
||||||
|
15 15 | def f():
|
||||||
|
16 |- (x, y) = coords = 1, 2
|
||||||
|
16 |+ (x, _y) = coords = 1, 2
|
||||||
|
17 17 |
|
||||||
|
18 18 |
|
||||||
|
19 19 | def f():
|
||||||
|
|
||||||
|
RUF059_1.py:20:15: RUF059 [*] Unpacked variable `x` is never used
|
||||||
|
|
|
||||||
|
19 | def f():
|
||||||
|
20 | coords = (x, y) = 1, 2
|
||||||
|
| ^ RUF059
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
17 17 |
|
||||||
|
18 18 |
|
||||||
|
19 19 | def f():
|
||||||
|
20 |- coords = (x, y) = 1, 2
|
||||||
|
20 |+ coords = (_x, y) = 1, 2
|
||||||
|
21 21 |
|
||||||
|
22 22 |
|
||||||
|
23 23 | def f():
|
||||||
|
|
||||||
|
RUF059_1.py:20:18: RUF059 [*] Unpacked variable `y` is never used
|
||||||
|
|
|
||||||
|
19 | def f():
|
||||||
|
20 | coords = (x, y) = 1, 2
|
||||||
|
| ^ RUF059
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
17 17 |
|
||||||
|
18 18 |
|
||||||
|
19 19 | def f():
|
||||||
|
20 |- coords = (x, y) = 1, 2
|
||||||
|
20 |+ coords = (x, _y) = 1, 2
|
||||||
|
21 21 |
|
||||||
|
22 22 |
|
||||||
|
23 23 | def f():
|
|
@ -0,0 +1,224 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/ruff/mod.rs
|
||||||
|
---
|
||||||
|
RUF059_2.py:8:20: RUF059 [*] Unpacked variable `x2` is never used
|
||||||
|
|
|
||||||
|
6 | pass
|
||||||
|
7 |
|
||||||
|
8 | with foo() as (x2, y2):
|
||||||
|
| ^^ RUF059
|
||||||
|
9 | pass
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
5 5 | with foo() as x1:
|
||||||
|
6 6 | pass
|
||||||
|
7 7 |
|
||||||
|
8 |- with foo() as (x2, y2):
|
||||||
|
8 |+ with foo() as (_x2, y2):
|
||||||
|
9 9 | pass
|
||||||
|
10 10 |
|
||||||
|
11 11 | with (foo() as x3, foo() as y3, foo() as z3):
|
||||||
|
|
||||||
|
RUF059_2.py:8:24: RUF059 [*] Unpacked variable `y2` is never used
|
||||||
|
|
|
||||||
|
6 | pass
|
||||||
|
7 |
|
||||||
|
8 | with foo() as (x2, y2):
|
||||||
|
| ^^ RUF059
|
||||||
|
9 | pass
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
5 5 | with foo() as x1:
|
||||||
|
6 6 | pass
|
||||||
|
7 7 |
|
||||||
|
8 |- with foo() as (x2, y2):
|
||||||
|
8 |+ with foo() as (x2, _y2):
|
||||||
|
9 9 | pass
|
||||||
|
10 10 |
|
||||||
|
11 11 | with (foo() as x3, foo() as y3, foo() as z3):
|
||||||
|
|
||||||
|
RUF059_2.py:17:6: RUF059 [*] Unpacked variable `x2` is never used
|
||||||
|
|
|
||||||
|
15 | def f():
|
||||||
|
16 | (x1, y1) = (1, 2)
|
||||||
|
17 | (x2, y2) = coords2 = (1, 2)
|
||||||
|
| ^^ RUF059
|
||||||
|
18 | coords3 = (x3, y3) = (1, 2)
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
14 14 |
|
||||||
|
15 15 | def f():
|
||||||
|
16 16 | (x1, y1) = (1, 2)
|
||||||
|
17 |- (x2, y2) = coords2 = (1, 2)
|
||||||
|
17 |+ (_x2, y2) = coords2 = (1, 2)
|
||||||
|
18 18 | coords3 = (x3, y3) = (1, 2)
|
||||||
|
19 19 |
|
||||||
|
20 20 |
|
||||||
|
|
||||||
|
RUF059_2.py:17:10: RUF059 [*] Unpacked variable `y2` is never used
|
||||||
|
|
|
||||||
|
15 | def f():
|
||||||
|
16 | (x1, y1) = (1, 2)
|
||||||
|
17 | (x2, y2) = coords2 = (1, 2)
|
||||||
|
| ^^ RUF059
|
||||||
|
18 | coords3 = (x3, y3) = (1, 2)
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
14 14 |
|
||||||
|
15 15 | def f():
|
||||||
|
16 16 | (x1, y1) = (1, 2)
|
||||||
|
17 |- (x2, y2) = coords2 = (1, 2)
|
||||||
|
17 |+ (x2, _y2) = coords2 = (1, 2)
|
||||||
|
18 18 | coords3 = (x3, y3) = (1, 2)
|
||||||
|
19 19 |
|
||||||
|
20 20 |
|
||||||
|
|
||||||
|
RUF059_2.py:18:16: RUF059 [*] Unpacked variable `x3` is never used
|
||||||
|
|
|
||||||
|
16 | (x1, y1) = (1, 2)
|
||||||
|
17 | (x2, y2) = coords2 = (1, 2)
|
||||||
|
18 | coords3 = (x3, y3) = (1, 2)
|
||||||
|
| ^^ RUF059
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
15 15 | def f():
|
||||||
|
16 16 | (x1, y1) = (1, 2)
|
||||||
|
17 17 | (x2, y2) = coords2 = (1, 2)
|
||||||
|
18 |- coords3 = (x3, y3) = (1, 2)
|
||||||
|
18 |+ coords3 = (_x3, y3) = (1, 2)
|
||||||
|
19 19 |
|
||||||
|
20 20 |
|
||||||
|
21 21 | def f():
|
||||||
|
|
||||||
|
RUF059_2.py:18:20: RUF059 [*] Unpacked variable `y3` is never used
|
||||||
|
|
|
||||||
|
16 | (x1, y1) = (1, 2)
|
||||||
|
17 | (x2, y2) = coords2 = (1, 2)
|
||||||
|
18 | coords3 = (x3, y3) = (1, 2)
|
||||||
|
| ^^ RUF059
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
15 15 | def f():
|
||||||
|
16 16 | (x1, y1) = (1, 2)
|
||||||
|
17 17 | (x2, y2) = coords2 = (1, 2)
|
||||||
|
18 |- coords3 = (x3, y3) = (1, 2)
|
||||||
|
18 |+ coords3 = (x3, _y3) = (1, 2)
|
||||||
|
19 19 |
|
||||||
|
20 20 |
|
||||||
|
21 21 | def f():
|
||||||
|
|
||||||
|
RUF059_2.py:22:24: RUF059 [*] Unpacked variable `x` is never used
|
||||||
|
|
|
||||||
|
21 | def f():
|
||||||
|
22 | with Nested(m) as (x, y):
|
||||||
|
| ^ RUF059
|
||||||
|
23 | pass
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
19 19 |
|
||||||
|
20 20 |
|
||||||
|
21 21 | def f():
|
||||||
|
22 |- with Nested(m) as (x, y):
|
||||||
|
22 |+ with Nested(m) as (_x, y):
|
||||||
|
23 23 | pass
|
||||||
|
24 24 |
|
||||||
|
25 25 |
|
||||||
|
|
||||||
|
RUF059_2.py:22:27: RUF059 [*] Unpacked variable `y` is never used
|
||||||
|
|
|
||||||
|
21 | def f():
|
||||||
|
22 | with Nested(m) as (x, y):
|
||||||
|
| ^ RUF059
|
||||||
|
23 | pass
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
19 19 |
|
||||||
|
20 20 |
|
||||||
|
21 21 | def f():
|
||||||
|
22 |- with Nested(m) as (x, y):
|
||||||
|
22 |+ with Nested(m) as (x, _y):
|
||||||
|
23 23 | pass
|
||||||
|
24 24 |
|
||||||
|
25 25 |
|
||||||
|
|
||||||
|
RUF059_2.py:27:17: RUF059 [*] Unpacked variable `a` is never used
|
||||||
|
|
|
||||||
|
26 | def f():
|
||||||
|
27 | toplevel = (a, b) = lexer.get_token()
|
||||||
|
| ^ RUF059
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
24 24 |
|
||||||
|
25 25 |
|
||||||
|
26 26 | def f():
|
||||||
|
27 |- toplevel = (a, b) = lexer.get_token()
|
||||||
|
27 |+ toplevel = (_a, b) = lexer.get_token()
|
||||||
|
28 28 |
|
||||||
|
29 29 |
|
||||||
|
30 30 | def f():
|
||||||
|
|
||||||
|
RUF059_2.py:27:20: RUF059 [*] Unpacked variable `b` is never used
|
||||||
|
|
|
||||||
|
26 | def f():
|
||||||
|
27 | toplevel = (a, b) = lexer.get_token()
|
||||||
|
| ^ RUF059
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
24 24 |
|
||||||
|
25 25 |
|
||||||
|
26 26 | def f():
|
||||||
|
27 |- toplevel = (a, b) = lexer.get_token()
|
||||||
|
27 |+ toplevel = (a, _b) = lexer.get_token()
|
||||||
|
28 28 |
|
||||||
|
29 29 |
|
||||||
|
30 30 | def f():
|
||||||
|
|
||||||
|
RUF059_2.py:31:6: RUF059 [*] Unpacked variable `a` is never used
|
||||||
|
|
|
||||||
|
30 | def f():
|
||||||
|
31 | (a, b) = toplevel = lexer.get_token()
|
||||||
|
| ^ RUF059
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
28 28 |
|
||||||
|
29 29 |
|
||||||
|
30 30 | def f():
|
||||||
|
31 |- (a, b) = toplevel = lexer.get_token()
|
||||||
|
31 |+ (_a, b) = toplevel = lexer.get_token()
|
||||||
|
|
||||||
|
RUF059_2.py:31:9: RUF059 [*] Unpacked variable `b` is never used
|
||||||
|
|
|
||||||
|
30 | def f():
|
||||||
|
31 | (a, b) = toplevel = lexer.get_token()
|
||||||
|
| ^ RUF059
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
28 28 |
|
||||||
|
29 29 |
|
||||||
|
30 30 | def f():
|
||||||
|
31 |- (a, b) = toplevel = lexer.get_token()
|
||||||
|
31 |+ (a, _b) = toplevel = lexer.get_token()
|
|
@ -0,0 +1,40 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/ruff/mod.rs
|
||||||
|
---
|
||||||
|
RUF059_3.py:13:5: RUF059 [*] Unpacked variable `b` is never used
|
||||||
|
|
|
||||||
|
11 | def bar():
|
||||||
|
12 | a = foo()
|
||||||
|
13 | b, c = foo()
|
||||||
|
| ^ RUF059
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
10 10 |
|
||||||
|
11 11 | def bar():
|
||||||
|
12 12 | a = foo()
|
||||||
|
13 |- b, c = foo()
|
||||||
|
13 |+ _b, c = foo()
|
||||||
|
14 14 |
|
||||||
|
15 15 |
|
||||||
|
16 16 | def baz():
|
||||||
|
|
||||||
|
RUF059_3.py:13:8: RUF059 [*] Unpacked variable `c` is never used
|
||||||
|
|
|
||||||
|
11 | def bar():
|
||||||
|
12 | a = foo()
|
||||||
|
13 | b, c = foo()
|
||||||
|
| ^ RUF059
|
||||||
|
|
|
||||||
|
= help: Prefix it with an underscore or any other dummy variable pattern
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
10 10 |
|
||||||
|
11 11 | def bar():
|
||||||
|
12 12 | a = foo()
|
||||||
|
13 |- b, c = foo()
|
||||||
|
13 |+ b, _c = foo()
|
||||||
|
14 14 |
|
||||||
|
15 15 |
|
||||||
|
16 16 | def baz():
|
|
@ -445,7 +445,8 @@ fn tags(code: &str) -> Option<Vec<lsp_types::DiagnosticTag>> {
|
||||||
match code {
|
match code {
|
||||||
// F401: <module> imported but unused
|
// F401: <module> imported but unused
|
||||||
// F841: local variable <name> is assigned to but never used
|
// F841: local variable <name> is assigned to but never used
|
||||||
"F401" | "F841" => Some(vec![lsp_types::DiagnosticTag::UNNECESSARY]),
|
// RUF059: Unused unpacked variable
|
||||||
|
"F401" | "F841" | "RUF059" => Some(vec![lsp_types::DiagnosticTag::UNNECESSARY]),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
1
ruff.schema.json
generated
1
ruff.schema.json
generated
|
@ -3972,6 +3972,7 @@
|
||||||
"RUF056",
|
"RUF056",
|
||||||
"RUF057",
|
"RUF057",
|
||||||
"RUF058",
|
"RUF058",
|
||||||
|
"RUF059",
|
||||||
"RUF1",
|
"RUF1",
|
||||||
"RUF10",
|
"RUF10",
|
||||||
"RUF100",
|
"RUF100",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue