diff --git a/crates/ruff_linter/resources/test/fixtures/pylint/iteration_over_set.py b/crates/ruff_linter/resources/test/fixtures/pylint/iteration_over_set.py index 673a49ed5c389..38a20dcc1ed55 100644 --- a/crates/ruff_linter/resources/test/fixtures/pylint/iteration_over_set.py +++ b/crates/ruff_linter/resources/test/fixtures/pylint/iteration_over_set.py @@ -6,6 +6,14 @@ for item in {"apples", "lemons", "water"}: # flags in-line set literals print(f"I like {item}.") +for item in {1,}: + print(f"I can count to {item}!") + +for item in { + "apples", "lemons", "water" +}: # flags in-line set literals + print(f"I like {item}.") + numbers_list = [i for i in {1, 2, 3}] # flags sets in list comprehensions numbers_set = {i for i in {1, 2, 3}} # flags sets in set comprehensions diff --git a/crates/ruff_linter/src/rules/pylint/rules/iteration_over_set.rs b/crates/ruff_linter/src/rules/pylint/rules/iteration_over_set.rs index 98146923b5d77..647f0d8c5d3eb 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/iteration_over_set.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/iteration_over_set.rs @@ -1,9 +1,7 @@ -use ast::ExprContext; -use ruff_python_ast::{self as ast, Expr}; - use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; -use ruff_text_size::{Ranged, TextRange}; +use ruff_python_ast::{self as ast, Expr}; +use ruff_text_size::Ranged; use crate::checkers::ast::Checker; @@ -38,7 +36,7 @@ impl AlwaysFixableViolation for IterationOverSet { } fn fix_title(&self) -> String { - format!("Use a sequence type instead of a `set` when iterating over values") + format!("Convert to `tuple`") } } @@ -54,15 +52,14 @@ pub(crate) fn iteration_over_set(checker: &mut Checker, expr: &Expr) { let mut diagnostic = Diagnostic::new(IterationOverSet, expr.range()); - let tuple = checker.generator().expr(&Expr::Tuple(ast::ExprTuple { - elts: elts.clone(), - ctx: ExprContext::Store, - range: TextRange::default(), - })); - diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( - format!("({tuple})"), - expr.range(), - ))); + let tuple = if let [elt] = elts.as_slice() { + let elt = checker.locator().slice(elt); + format!("({elt},)") + } else { + let set = checker.locator().slice(expr); + format!("({})", &set[1..set.len() - 1]) + }; + diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(tuple, expr.range()))); checker.diagnostics.push(diagnostic); } diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLC0208_iteration_over_set.py.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLC0208_iteration_over_set.py.snap index 5be17ebe998aa..91fa2dc50a1f8 100644 --- a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLC0208_iteration_over_set.py.snap +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLC0208_iteration_over_set.py.snap @@ -9,7 +9,7 @@ iteration_over_set.py:3:13: PLC0208 [*] Use a sequence type instead of a `set` w | ^^^ PLC0208 4 | print(f"I can count to {item}!") | - = help: Use a sequence type instead of a `set` when iterating over values + = help: Convert to `tuple` ℹ Fix 1 1 | # Errors @@ -28,7 +28,7 @@ iteration_over_set.py:6:13: PLC0208 [*] Use a sequence type instead of a `set` w | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLC0208 7 | print(f"I like {item}.") | - = help: Use a sequence type instead of a `set` when iterating over values + = help: Convert to `tuple` ℹ Fix 3 3 | for item in {1}: @@ -38,90 +38,136 @@ iteration_over_set.py:6:13: PLC0208 [*] Use a sequence type instead of a `set` w 6 |+for item in ("apples", "lemons", "water"): # flags in-line set literals 7 7 | print(f"I like {item}.") 8 8 | -9 9 | numbers_list = [i for i in {1, 2, 3}] # flags sets in list comprehensions +9 9 | for item in {1,}: -iteration_over_set.py:9:28: PLC0208 [*] Use a sequence type instead of a `set` when iterating over values +iteration_over_set.py:9:13: PLC0208 [*] Use a sequence type instead of a `set` when iterating over values | 7 | print(f"I like {item}.") 8 | - 9 | numbers_list = [i for i in {1, 2, 3}] # flags sets in list comprehensions - | ^^^^^^^^^ PLC0208 -10 | -11 | numbers_set = {i for i in {1, 2, 3}} # flags sets in set comprehensions + 9 | for item in {1,}: + | ^^^^ PLC0208 +10 | print(f"I can count to {item}!") | - = help: Use a sequence type instead of a `set` when iterating over values + = help: Convert to `tuple` ℹ Fix 6 6 | for item in {"apples", "lemons", "water"}: # flags in-line set literals 7 7 | print(f"I like {item}.") 8 8 | -9 |-numbers_list = [i for i in {1, 2, 3}] # flags sets in list comprehensions - 9 |+numbers_list = [i for i in (1, 2, 3)] # flags sets in list comprehensions -10 10 | -11 11 | numbers_set = {i for i in {1, 2, 3}} # flags sets in set comprehensions -12 12 | +9 |-for item in {1,}: + 9 |+for item in (1,): +10 10 | print(f"I can count to {item}!") +11 11 | +12 12 | for item in { -iteration_over_set.py:11:27: PLC0208 [*] Use a sequence type instead of a `set` when iterating over values +iteration_over_set.py:12:13: PLC0208 [*] Use a sequence type instead of a `set` when iterating over values | - 9 | numbers_list = [i for i in {1, 2, 3}] # flags sets in list comprehensions -10 | -11 | numbers_set = {i for i in {1, 2, 3}} # flags sets in set comprehensions - | ^^^^^^^^^ PLC0208 -12 | -13 | numbers_dict = {str(i): i for i in {1, 2, 3}} # flags sets in dict comprehensions +10 | print(f"I can count to {item}!") +11 | +12 | for item in { + | _____________^ +13 | | "apples", "lemons", "water" +14 | | }: # flags in-line set literals + | |_^ PLC0208 +15 | print(f"I like {item}.") | - = help: Use a sequence type instead of a `set` when iterating over values + = help: Convert to `tuple` ℹ Fix -8 8 | -9 9 | numbers_list = [i for i in {1, 2, 3}] # flags sets in list comprehensions -10 10 | -11 |-numbers_set = {i for i in {1, 2, 3}} # flags sets in set comprehensions - 11 |+numbers_set = {i for i in (1, 2, 3)} # flags sets in set comprehensions -12 12 | -13 13 | numbers_dict = {str(i): i for i in {1, 2, 3}} # flags sets in dict comprehensions -14 14 | - -iteration_over_set.py:13:36: PLC0208 [*] Use a sequence type instead of a `set` when iterating over values +9 9 | for item in {1,}: +10 10 | print(f"I can count to {item}!") +11 11 | +12 |-for item in { + 12 |+for item in ( +13 13 | "apples", "lemons", "water" +14 |-}: # flags in-line set literals + 14 |+): # flags in-line set literals +15 15 | print(f"I like {item}.") +16 16 | +17 17 | numbers_list = [i for i in {1, 2, 3}] # flags sets in list comprehensions + +iteration_over_set.py:17:28: PLC0208 [*] Use a sequence type instead of a `set` when iterating over values | -11 | numbers_set = {i for i in {1, 2, 3}} # flags sets in set comprehensions -12 | -13 | numbers_dict = {str(i): i for i in {1, 2, 3}} # flags sets in dict comprehensions - | ^^^^^^^^^ PLC0208 -14 | -15 | numbers_gen = (i for i in {1, 2, 3}) # flags sets in generator expressions +15 | print(f"I like {item}.") +16 | +17 | numbers_list = [i for i in {1, 2, 3}] # flags sets in list comprehensions + | ^^^^^^^^^ PLC0208 +18 | +19 | numbers_set = {i for i in {1, 2, 3}} # flags sets in set comprehensions | - = help: Use a sequence type instead of a `set` when iterating over values + = help: Convert to `tuple` ℹ Fix -10 10 | -11 11 | numbers_set = {i for i in {1, 2, 3}} # flags sets in set comprehensions -12 12 | -13 |-numbers_dict = {str(i): i for i in {1, 2, 3}} # flags sets in dict comprehensions - 13 |+numbers_dict = {str(i): i for i in (1, 2, 3)} # flags sets in dict comprehensions -14 14 | -15 15 | numbers_gen = (i for i in {1, 2, 3}) # flags sets in generator expressions +14 14 | }: # flags in-line set literals +15 15 | print(f"I like {item}.") 16 16 | +17 |-numbers_list = [i for i in {1, 2, 3}] # flags sets in list comprehensions + 17 |+numbers_list = [i for i in (1, 2, 3)] # flags sets in list comprehensions +18 18 | +19 19 | numbers_set = {i for i in {1, 2, 3}} # flags sets in set comprehensions +20 20 | -iteration_over_set.py:15:27: PLC0208 [*] Use a sequence type instead of a `set` when iterating over values +iteration_over_set.py:19:27: PLC0208 [*] Use a sequence type instead of a `set` when iterating over values | -13 | numbers_dict = {str(i): i for i in {1, 2, 3}} # flags sets in dict comprehensions -14 | -15 | numbers_gen = (i for i in {1, 2, 3}) # flags sets in generator expressions +17 | numbers_list = [i for i in {1, 2, 3}] # flags sets in list comprehensions +18 | +19 | numbers_set = {i for i in {1, 2, 3}} # flags sets in set comprehensions | ^^^^^^^^^ PLC0208 -16 | -17 | # Non-errors +20 | +21 | numbers_dict = {str(i): i for i in {1, 2, 3}} # flags sets in dict comprehensions | - = help: Use a sequence type instead of a `set` when iterating over values + = help: Convert to `tuple` ℹ Fix -12 12 | -13 13 | numbers_dict = {str(i): i for i in {1, 2, 3}} # flags sets in dict comprehensions -14 14 | -15 |-numbers_gen = (i for i in {1, 2, 3}) # flags sets in generator expressions - 15 |+numbers_gen = (i for i in (1, 2, 3)) # flags sets in generator expressions 16 16 | -17 17 | # Non-errors +17 17 | numbers_list = [i for i in {1, 2, 3}] # flags sets in list comprehensions 18 18 | +19 |-numbers_set = {i for i in {1, 2, 3}} # flags sets in set comprehensions + 19 |+numbers_set = {i for i in (1, 2, 3)} # flags sets in set comprehensions +20 20 | +21 21 | numbers_dict = {str(i): i for i in {1, 2, 3}} # flags sets in dict comprehensions +22 22 | + +iteration_over_set.py:21:36: PLC0208 [*] Use a sequence type instead of a `set` when iterating over values + | +19 | numbers_set = {i for i in {1, 2, 3}} # flags sets in set comprehensions +20 | +21 | numbers_dict = {str(i): i for i in {1, 2, 3}} # flags sets in dict comprehensions + | ^^^^^^^^^ PLC0208 +22 | +23 | numbers_gen = (i for i in {1, 2, 3}) # flags sets in generator expressions + | + = help: Convert to `tuple` + +ℹ Fix +18 18 | +19 19 | numbers_set = {i for i in {1, 2, 3}} # flags sets in set comprehensions +20 20 | +21 |-numbers_dict = {str(i): i for i in {1, 2, 3}} # flags sets in dict comprehensions + 21 |+numbers_dict = {str(i): i for i in (1, 2, 3)} # flags sets in dict comprehensions +22 22 | +23 23 | numbers_gen = (i for i in {1, 2, 3}) # flags sets in generator expressions +24 24 | + +iteration_over_set.py:23:27: PLC0208 [*] Use a sequence type instead of a `set` when iterating over values + | +21 | numbers_dict = {str(i): i for i in {1, 2, 3}} # flags sets in dict comprehensions +22 | +23 | numbers_gen = (i for i in {1, 2, 3}) # flags sets in generator expressions + | ^^^^^^^^^ PLC0208 +24 | +25 | # Non-errors + | + = help: Convert to `tuple` + +ℹ Fix +20 20 | +21 21 | numbers_dict = {str(i): i for i in {1, 2, 3}} # flags sets in dict comprehensions +22 22 | +23 |-numbers_gen = (i for i in {1, 2, 3}) # flags sets in generator expressions + 23 |+numbers_gen = (i for i in (1, 2, 3)) # flags sets in generator expressions +24 24 | +25 25 | # Non-errors +26 26 |