From ccb316845d633eae9036e8cc3f70f5c9c76ae842 Mon Sep 17 00:00:00 2001 From: Dani Alcala <112832187+clavedeluna@users.noreply.github.com> Date: Mon, 26 Dec 2022 11:37:58 -0300 Subject: [PATCH] Fix `use-sequence-for-iteration` when unpacking a set with `*` (#7975) --- doc/whatsnew/fragments/5788.false_positive | 3 +++ .../checkers/refactoring/recommendation_checker.py | 14 +++++++++++--- pylint/checkers/utils.py | 14 ++++++++++++++ .../ext/code_style/cs_consider_using_tuple.py | 2 +- .../ext/code_style/cs_consider_using_tuple.txt | 3 +-- .../functional/u/use/use_sequence_for_iteration.py | 14 +++++++++++++- .../u/use/use_sequence_for_iteration.txt | 7 +++---- 7 files changed, 46 insertions(+), 11 deletions(-) create mode 100644 doc/whatsnew/fragments/5788.false_positive diff --git a/doc/whatsnew/fragments/5788.false_positive b/doc/whatsnew/fragments/5788.false_positive new file mode 100644 index 0000000000..65fc29fe4d --- /dev/null +++ b/doc/whatsnew/fragments/5788.false_positive @@ -0,0 +1,3 @@ +Fix ``use-sequence-for-iteration`` when unpacking a set with ``*``. + +Closes #5788 diff --git a/pylint/checkers/refactoring/recommendation_checker.py b/pylint/checkers/refactoring/recommendation_checker.py index 7873dc25ed..e1634fd8c4 100644 --- a/pylint/checkers/refactoring/recommendation_checker.py +++ b/pylint/checkers/refactoring/recommendation_checker.py @@ -9,6 +9,7 @@ from pylint import checkers from pylint.checkers import utils +from pylint.interfaces import HIGH class RecommendationChecker(checkers.BaseChecker): @@ -326,9 +327,16 @@ def _check_consider_using_dict_items_comprehension( def _check_use_sequence_for_iteration( self, node: nodes.For | nodes.Comprehension ) -> None: - """Check if code iterates over an in-place defined set.""" - if isinstance(node.iter, nodes.Set): - self.add_message("use-sequence-for-iteration", node=node.iter) + """Check if code iterates over an in-place defined set. + + Sets using `*` are not considered in-place. + """ + if isinstance(node.iter, nodes.Set) and not any( + utils.has_starred_node_recursive(node) + ): + self.add_message( + "use-sequence-for-iteration", node=node.iter, confidence=HIGH + ) @utils.only_required_for_messages("consider-using-f-string") def visit_const(self, node: nodes.Const) -> None: diff --git a/pylint/checkers/utils.py b/pylint/checkers/utils.py index 90339ad508..da7667f46a 100644 --- a/pylint/checkers/utils.py +++ b/pylint/checkers/utils.py @@ -1961,6 +1961,20 @@ def find_assigned_names_recursive( yield from find_assigned_names_recursive(elt) +def has_starred_node_recursive( + node: nodes.For | nodes.Comprehension | nodes.Set, +) -> Iterator[bool]: + """Yield ``True`` if a Starred node is found recursively.""" + if isinstance(node, nodes.Starred): + yield True + elif isinstance(node, nodes.Set): + for elt in node.elts: + yield from has_starred_node_recursive(elt) + elif isinstance(node, (nodes.For, nodes.Comprehension)): + for elt in node.iter.elts: + yield from has_starred_node_recursive(elt) + + def is_hashable(node: nodes.NodeNG) -> bool: """Return whether any inferred value of `node` is hashable. diff --git a/tests/functional/ext/code_style/cs_consider_using_tuple.py b/tests/functional/ext/code_style/cs_consider_using_tuple.py index d243960795..57178c34ea 100644 --- a/tests/functional/ext/code_style/cs_consider_using_tuple.py +++ b/tests/functional/ext/code_style/cs_consider_using_tuple.py @@ -28,4 +28,4 @@ # Don't emit warning for sets as this is handled by builtin checker (x for x in {1, 2, 3}) # [use-sequence-for-iteration] -[x for x in {*var, 2}] # [use-sequence-for-iteration] +[x for x in {*var, 2}] diff --git a/tests/functional/ext/code_style/cs_consider_using_tuple.txt b/tests/functional/ext/code_style/cs_consider_using_tuple.txt index cd8ffb1e7b..565f5f7784 100644 --- a/tests/functional/ext/code_style/cs_consider_using_tuple.txt +++ b/tests/functional/ext/code_style/cs_consider_using_tuple.txt @@ -4,5 +4,4 @@ consider-using-tuple:18:12:18:21::Consider using an in-place tuple instead of li consider-using-tuple:21:9:21:15::Consider using an in-place tuple instead of list:UNDEFINED consider-using-tuple:23:9:23:18::Consider using an in-place tuple instead of list:UNDEFINED consider-using-tuple:26:12:26:21::Consider using an in-place tuple instead of list:UNDEFINED -use-sequence-for-iteration:30:12:30:21::Use a sequence type when iterating over values:UNDEFINED -use-sequence-for-iteration:31:12:31:21::Use a sequence type when iterating over values:UNDEFINED +use-sequence-for-iteration:30:12:30:21::Use a sequence type when iterating over values:HIGH diff --git a/tests/functional/u/use/use_sequence_for_iteration.py b/tests/functional/u/use/use_sequence_for_iteration.py index 2dd1feb187..264e6e7b9d 100644 --- a/tests/functional/u/use/use_sequence_for_iteration.py +++ b/tests/functional/u/use/use_sequence_for_iteration.py @@ -13,4 +13,16 @@ [x for x in var] [x for x in {1, 2, 3}] # [use-sequence-for-iteration] -[x for x in {*var, 4}] # [use-sequence-for-iteration] +[x for x in {*var, 4}] + +def deduplicate(list_in): + for thing in {*list_in}: + print(thing) + +def deduplicate_two_lists(input1, input2): + for thing in {*input1, *input2}: + print(thing) + +def deduplicate_nested_sets(input1, input2, input3, input4): + for thing in {{*input1, *input2}, {*input3, *input4}}: + print(thing) diff --git a/tests/functional/u/use/use_sequence_for_iteration.txt b/tests/functional/u/use/use_sequence_for_iteration.txt index beb23a4dfd..3787b7a0eb 100644 --- a/tests/functional/u/use/use_sequence_for_iteration.txt +++ b/tests/functional/u/use/use_sequence_for_iteration.txt @@ -1,4 +1,3 @@ -use-sequence-for-iteration:7:9:7:18::Use a sequence type when iterating over values:UNDEFINED -use-sequence-for-iteration:11:12:11:21::Use a sequence type when iterating over values:UNDEFINED -use-sequence-for-iteration:14:12:14:21::Use a sequence type when iterating over values:UNDEFINED -use-sequence-for-iteration:16:12:16:21::Use a sequence type when iterating over values:UNDEFINED +use-sequence-for-iteration:7:9:7:18::Use a sequence type when iterating over values:HIGH +use-sequence-for-iteration:11:12:11:21::Use a sequence type when iterating over values:HIGH +use-sequence-for-iteration:14:12:14:21::Use a sequence type when iterating over values:HIGH