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::UnusedPrivateTypeVar,
|
||||
Rule::UnusedStaticMethodArgument,
|
||||
Rule::UnusedUnpackedVariable,
|
||||
Rule::UnusedVariable,
|
||||
]) {
|
||||
return;
|
||||
|
@ -390,8 +391,43 @@ pub(crate) fn deferred_scopes(checker: &Checker) {
|
|||
}
|
||||
|
||||
if matches!(scope.kind, ScopeKind::Function(_) | ScopeKind::Lambda(_)) {
|
||||
if checker.any_enabled(&[Rule::UnusedVariable, Rule::UnusedUnpackedVariable])
|
||||
&& !(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, scope);
|
||||
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) {
|
||||
|
|
|
@ -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, "057") => (RuleGroup::Preview, rules::ruff::rules::UnnecessaryRound),
|
||||
(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, "101") => (RuleGroup::Stable, rules::ruff::rules::RedirectedNOQA),
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/message/sarif.rs
|
||||
expression: value
|
||||
snapshot_kind: text
|
||||
---
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/sarif-2.1.0.json",
|
||||
|
@ -120,7 +119,7 @@ snapshot_kind: text
|
|||
},
|
||||
{
|
||||
"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": {
|
||||
"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_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<()> {
|
||||
|
@ -226,7 +225,6 @@ mod tests {
|
|||
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("F401_24/__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::{self as ast, Stmt};
|
||||
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 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
|
||||
/// [`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
|
||||
/// ```python
|
||||
/// def foo():
|
||||
|
@ -249,38 +246,11 @@ fn remove_unused_variable(binding: &Binding, checker: &Checker) -> Option<Fix> {
|
|||
}
|
||||
|
||||
/// F841
|
||||
pub(crate) fn unused_variable(checker: &Checker, scope: &Scope) {
|
||||
if scope.uses_locals() && scope.kind.is_function() {
|
||||
pub(crate) fn unused_variable(checker: &Checker, name: &str, binding: &Binding) {
|
||||
if binding.is_unpacked_assignment() {
|
||||
return;
|
||||
}
|
||||
|
||||
for (name, binding) in 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())
|
||||
// Stabilization depends on resolving https://github.com/astral-sh/ruff/issues/8884
|
||||
&& (!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(),
|
||||
|
@ -291,5 +261,4 @@ pub(crate) fn unused_variable(checker: &Checker, scope: &Scope) {
|
|||
diagnostic.set_fix(fix);
|
||||
}
|
||||
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::UsedDummyVariable, Path::new("RUF052.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_1.py"))]
|
||||
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 unused_async::*;
|
||||
pub(crate) use unused_noqa::*;
|
||||
pub(crate) use unused_unpacked_variable::*;
|
||||
pub(crate) use used_dummy_variable::*;
|
||||
pub(crate) use useless_if_else::*;
|
||||
pub(crate) use zip_instead_of_pairwise::*;
|
||||
|
@ -110,6 +111,7 @@ mod unraw_re_pattern;
|
|||
mod unsafe_markup_use;
|
||||
mod unused_async;
|
||||
mod unused_noqa;
|
||||
mod unused_unpacked_variable;
|
||||
mod used_dummy_variable;
|
||||
mod useless_if_else;
|
||||
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 {
|
||||
// F401: <module> imported but unused
|
||||
// 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,
|
||||
}
|
||||
}
|
||||
|
|
1
ruff.schema.json
generated
1
ruff.schema.json
generated
|
@ -3972,6 +3972,7 @@
|
|||
"RUF056",
|
||||
"RUF057",
|
||||
"RUF058",
|
||||
"RUF059",
|
||||
"RUF1",
|
||||
"RUF10",
|
||||
"RUF100",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue