summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Mueller <30130371+cdce8p@users.noreply.github.com>2021-08-13 19:34:19 +0200
committerGitHub <noreply@github.com>2021-08-13 19:34:19 +0200
commit61b4db0dc31fd31fcfda36e4730cb44848af2d30 (patch)
tree99969d59b7509b0c1fa718923c712d6f02d9fe00
parent4f5732095a65a50828d621ba19d67b0753cc0133 (diff)
parent941dd78d91850471cea0cac51581cd51eaae4cd7 (diff)
downloadpylint-git-61b4db0dc31fd31fcfda36e4730cb44848af2d30.tar.gz
Merge pull request #4835 from cdce8p/feature-sequence_for_iteration
Add `use-sequence-for-iteration` checker
-rw-r--r--ChangeLog2
-rw-r--r--doc/whatsnew/2.10.rst2
-rw-r--r--pylint/checkers/refactoring/recommendation_checker.py34
-rw-r--r--tests/functional/ext/code_style/code_style_consider_using_tuple.py4
-rw-r--r--tests/functional/ext/code_style/code_style_consider_using_tuple.txt2
-rw-r--r--tests/functional/u/undefined/undefined_loop_variable.py2
-rw-r--r--tests/functional/u/use/use_sequence_for_iteration.py16
-rw-r--r--tests/functional/u/use/use_sequence_for_iteration.txt4
8 files changed, 60 insertions, 6 deletions
diff --git a/ChangeLog b/ChangeLog
index fae693a3d..ecfe42ff0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -118,6 +118,8 @@ Release date: TBA
Closes #4828
+* Added ``use-sequence-for-iteration``: Emitted when iterating over an in-place defined ``set``.
+
What's New in Pylint 2.9.6?
===========================
diff --git a/doc/whatsnew/2.10.rst b/doc/whatsnew/2.10.rst
index 585ac8cc7..d13099989 100644
--- a/doc/whatsnew/2.10.rst
+++ b/doc/whatsnew/2.10.rst
@@ -28,6 +28,8 @@ New checkers
Closes #3692
+* Added ``use-sequence-for-iteration``: Emitted when iterating over an in-place defined ``set``.
+
Other Changes
=============
diff --git a/pylint/checkers/refactoring/recommendation_checker.py b/pylint/checkers/refactoring/recommendation_checker.py
index 0cb724985..b7bda5754 100644
--- a/pylint/checkers/refactoring/recommendation_checker.py
+++ b/pylint/checkers/refactoring/recommendation_checker.py
@@ -1,6 +1,6 @@
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE
-from typing import cast
+from typing import Union, cast
import astroid
@@ -43,6 +43,12 @@ class RecommendationChecker(checkers.BaseChecker):
"str.split(sep, maxsplit=1)[0] or str.rsplit(sep, maxsplit=1)[-1] "
"instead.",
),
+ "C0208": (
+ "Use a sequence type when iterating over values",
+ "use-sequence-for-iteration",
+ "When iterating over values, sequence types (e.g., ``lists``, ``tuples``, ``ranges``) "
+ "are more efficient than ``sets``.",
+ ),
}
@staticmethod
@@ -134,10 +140,15 @@ class RecommendationChecker(checkers.BaseChecker):
)
self.add_message("use-maxsplit-arg", node=node, args=(new_name,))
- @utils.check_messages("consider-using-enumerate", "consider-using-dict-items")
+ @utils.check_messages(
+ "consider-using-enumerate",
+ "consider-using-dict-items",
+ "use-sequence-for-iteration",
+ )
def visit_for(self, node: astroid.For) -> None:
self._check_consider_using_enumerate(node)
self._check_consider_using_dict_items(node)
+ self._check_use_sequence_for_iteration(node)
def _check_consider_using_enumerate(self, node: astroid.For) -> None:
"""Emit a convention whenever range and len are used for indexing."""
@@ -262,8 +273,18 @@ class RecommendationChecker(checkers.BaseChecker):
self.add_message("consider-using-dict-items", node=node)
return
- @utils.check_messages("consider-using-dict-items")
+ @utils.check_messages(
+ "consider-using-dict-items",
+ "use-sequence-for-iteration",
+ )
def visit_comprehension(self, node: astroid.Comprehension) -> None:
+ self._check_consider_using_dict_items_comprehension(node)
+ self._check_use_sequence_for_iteration(node)
+
+ def _check_consider_using_dict_items_comprehension(
+ self, node: astroid.Comprehension
+ ) -> None:
+ """Add message when accessing dict values by index lookup."""
iterating_object_name = utils.get_iterating_dictionary_name(node)
if iterating_object_name is None:
return
@@ -285,3 +306,10 @@ class RecommendationChecker(checkers.BaseChecker):
self.add_message("consider-using-dict-items", node=node)
return
+
+ def _check_use_sequence_for_iteration(
+ self, node: Union[astroid.For, astroid.Comprehension]
+ ) -> None:
+ """Check if code iterates over an in-place defined set."""
+ if isinstance(node.iter, astroid.Set):
+ self.add_message("use-sequence-for-iteration", node=node.iter)
diff --git a/tests/functional/ext/code_style/code_style_consider_using_tuple.py b/tests/functional/ext/code_style/code_style_consider_using_tuple.py
index 679ef77d2..1bf06d82c 100644
--- a/tests/functional/ext/code_style/code_style_consider_using_tuple.py
+++ b/tests/functional/ext/code_style/code_style_consider_using_tuple.py
@@ -12,7 +12,7 @@ for x in [1, 2, 3]: # [consider-using-tuple]
(x for x in var)
(x for x in (1, 2, 3))
(x for x in [1, 2, 3]) # [consider-using-tuple]
-(x for x in {1, 2, 3}) # [consider-using-tuple]
+(x for x in {1, 2, 3}) # [consider-using-tuple,use-sequence-for-iteration]
[x for x in var]
[x for x in (1, 2, 3)]
@@ -26,4 +26,4 @@ for x in [2, *var]:
pass
[x for x in [*var, 2]]
-[x for x in {*var, 2}]
+[x for x in {*var, 2}] # [use-sequence-for-iteration]
diff --git a/tests/functional/ext/code_style/code_style_consider_using_tuple.txt b/tests/functional/ext/code_style/code_style_consider_using_tuple.txt
index df796b683..622aeb33e 100644
--- a/tests/functional/ext/code_style/code_style_consider_using_tuple.txt
+++ b/tests/functional/ext/code_style/code_style_consider_using_tuple.txt
@@ -1,4 +1,6 @@
consider-using-tuple:9:9::Consider using an in-place tuple instead of list
consider-using-tuple:14:12::Consider using an in-place tuple instead of list
consider-using-tuple:15:12::Consider using an in-place tuple instead of set
+use-sequence-for-iteration:15:12::Use a sequence type when iterating over values
consider-using-tuple:19:12::Consider using an in-place tuple instead of list
+use-sequence-for-iteration:29:12::Use a sequence type when iterating over values
diff --git a/tests/functional/u/undefined/undefined_loop_variable.py b/tests/functional/u/undefined/undefined_loop_variable.py
index 317372749..3df17f7d1 100644
--- a/tests/functional/u/undefined/undefined_loop_variable.py
+++ b/tests/functional/u/undefined/undefined_loop_variable.py
@@ -44,7 +44,7 @@ def do_stuff_with_a_list():
def do_stuff_with_a_set():
- for var in {1, 2, 3}:
+ for var in {1, 2, 3}: # pylint: disable=use-sequence-for-iteration
pass
return var
diff --git a/tests/functional/u/use/use_sequence_for_iteration.py b/tests/functional/u/use/use_sequence_for_iteration.py
new file mode 100644
index 000000000..2dd1feb18
--- /dev/null
+++ b/tests/functional/u/use/use_sequence_for_iteration.py
@@ -0,0 +1,16 @@
+# pylint: disable=missing-docstring,pointless-statement,unnecessary-comprehension
+
+var = {1, 2, 3}
+
+for x in var:
+ pass
+for x in {1, 2, 3}: # [use-sequence-for-iteration]
+ pass
+
+(x for x in var)
+(x for x in {1, 2, 3}) # [use-sequence-for-iteration]
+
+[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]
diff --git a/tests/functional/u/use/use_sequence_for_iteration.txt b/tests/functional/u/use/use_sequence_for_iteration.txt
new file mode 100644
index 000000000..615df8a30
--- /dev/null
+++ b/tests/functional/u/use/use_sequence_for_iteration.txt
@@ -0,0 +1,4 @@
+use-sequence-for-iteration:7:9::Use a sequence type when iterating over values:HIGH
+use-sequence-for-iteration:11:12::Use a sequence type when iterating over values:HIGH
+use-sequence-for-iteration:14:12::Use a sequence type when iterating over values:HIGH
+use-sequence-for-iteration:16:12::Use a sequence type when iterating over values:HIGH