Skip to content

Commit cf5ea8a

Browse files
authored
Fix use-sequence-for-iteration when unpacking a set with * (#7975)
1 parent c35f5a6 commit cf5ea8a

File tree

7 files changed

+46
-12
lines changed

7 files changed

+46
-12
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix ``use-sequence-for-iteration`` when unpacking a set with ``*``.
2+
3+
Closes #5788

pylint/checkers/refactoring/recommendation_checker.py

+11-4
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
from pylint import checkers
1111
from pylint.checkers import utils
12-
from pylint.interfaces import INFERENCE
12+
from pylint.interfaces import HIGH, INFERENCE
1313

1414

1515
class RecommendationChecker(checkers.BaseChecker):
@@ -333,9 +333,16 @@ def _check_consider_using_dict_items_comprehension(
333333
def _check_use_sequence_for_iteration(
334334
self, node: nodes.For | nodes.Comprehension
335335
) -> None:
336-
"""Check if code iterates over an in-place defined set."""
337-
if isinstance(node.iter, nodes.Set):
338-
self.add_message("use-sequence-for-iteration", node=node.iter)
336+
"""Check if code iterates over an in-place defined set.
337+
338+
Sets using `*` are not considered in-place.
339+
"""
340+
if isinstance(node.iter, nodes.Set) and not any(
341+
utils.has_starred_node_recursive(node)
342+
):
343+
self.add_message(
344+
"use-sequence-for-iteration", node=node.iter, confidence=HIGH
345+
)
339346

340347
@utils.only_required_for_messages("consider-using-f-string")
341348
def visit_const(self, node: nodes.Const) -> None:

pylint/checkers/utils.py

+14
Original file line numberDiff line numberDiff line change
@@ -2030,6 +2030,20 @@ def find_assigned_names_recursive(
20302030
yield from find_assigned_names_recursive(elt)
20312031

20322032

2033+
def has_starred_node_recursive(
2034+
node: nodes.For | nodes.Comprehension | nodes.Set,
2035+
) -> Iterator[bool]:
2036+
"""Yield ``True`` if a Starred node is found recursively."""
2037+
if isinstance(node, nodes.Starred):
2038+
yield True
2039+
elif isinstance(node, nodes.Set):
2040+
for elt in node.elts:
2041+
yield from has_starred_node_recursive(elt)
2042+
elif isinstance(node, (nodes.For, nodes.Comprehension)):
2043+
for elt in node.iter.elts:
2044+
yield from has_starred_node_recursive(elt)
2045+
2046+
20332047
def is_hashable(node: nodes.NodeNG) -> bool:
20342048
"""Return whether any inferred value of `node` is hashable.
20352049

tests/functional/ext/code_style/cs_consider_using_tuple.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,4 @@
2828

2929
# Don't emit warning for sets as this is handled by builtin checker
3030
(x for x in {1, 2, 3}) # [use-sequence-for-iteration]
31-
[x for x in {*var, 2}] # [use-sequence-for-iteration]
31+
[x for x in {*var, 2}]

tests/functional/ext/code_style/cs_consider_using_tuple.txt

+1-2
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,4 @@ consider-using-tuple:18:12:18:21::Consider using an in-place tuple instead of li
44
consider-using-tuple:21:9:21:15::Consider using an in-place tuple instead of list:UNDEFINED
55
consider-using-tuple:23:9:23:18::Consider using an in-place tuple instead of list:UNDEFINED
66
consider-using-tuple:26:12:26:21::Consider using an in-place tuple instead of list:UNDEFINED
7-
use-sequence-for-iteration:30:12:30:21::Use a sequence type when iterating over values:UNDEFINED
8-
use-sequence-for-iteration:31:12:31:21::Use a sequence type when iterating over values:UNDEFINED
7+
use-sequence-for-iteration:30:12:30:21::Use a sequence type when iterating over values:HIGH

tests/functional/u/use/use_sequence_for_iteration.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,16 @@
1313
[x for x in var]
1414
[x for x in {1, 2, 3}] # [use-sequence-for-iteration]
1515

16-
[x for x in {*var, 4}] # [use-sequence-for-iteration]
16+
[x for x in {*var, 4}]
17+
18+
def deduplicate(list_in):
19+
for thing in {*list_in}:
20+
print(thing)
21+
22+
def deduplicate_two_lists(input1, input2):
23+
for thing in {*input1, *input2}:
24+
print(thing)
25+
26+
def deduplicate_nested_sets(input1, input2, input3, input4):
27+
for thing in {{*input1, *input2}, {*input3, *input4}}:
28+
print(thing)
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use-sequence-for-iteration:7:9:7:18::Use a sequence type when iterating over values:UNDEFINED
2-
use-sequence-for-iteration:11:12:11:21::Use a sequence type when iterating over values:UNDEFINED
3-
use-sequence-for-iteration:14:12:14:21::Use a sequence type when iterating over values:UNDEFINED
4-
use-sequence-for-iteration:16:12:16:21::Use a sequence type when iterating over values:UNDEFINED
1+
use-sequence-for-iteration:7:9:7:18::Use a sequence type when iterating over values:HIGH
2+
use-sequence-for-iteration:11:12:11:21::Use a sequence type when iterating over values:HIGH
3+
use-sequence-for-iteration:14:12:14:21::Use a sequence type when iterating over values:HIGH

0 commit comments

Comments
 (0)