summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIkraduya Edian <ikraduya@gmail.com>2021-02-20 21:50:19 +0700
committerGitHub <noreply@github.com>2021-02-20 15:50:19 +0100
commit45c824549f9a7fa38df04ae8648d1647c82ba9b4 (patch)
treec6d05e8979245ddb0c5ed84437ac8219616858bb
parent570e65536147b00ab8a5743e761d7caa326afa21 (diff)
downloadpylint-git-45c824549f9a7fa38df04ae8648d1647c82ba9b4.tar.gz
Add new `consider-using-generator` and 'use-a-generator' checkers
See issue #3165 (#3309) See https://github.com/PyCQA/pylint/pull/3309#discussion_r576683109 Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com> Co-authored-by: Daniel Hahler <github@thequod.de>
-rw-r--r--CONTRIBUTORS.txt3
-rw-r--r--ChangeLog9
-rw-r--r--doc/whatsnew/2.7.rst2
-rw-r--r--pylint/checkers/refactoring/refactoring_checker.py61
-rw-r--r--tests/functional/c/consider_using_generator.py11
-rw-r--r--tests/functional/c/consider_using_generator.txt2
-rw-r--r--tests/functional/u/use_a_generator.py11
-rw-r--r--tests/functional/u/use_a_generator.txt2
8 files changed, 101 insertions, 0 deletions
diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt
index 8eef266d4..5667f4859 100644
--- a/CONTRIBUTORS.txt
+++ b/CONTRIBUTORS.txt
@@ -446,4 +446,7 @@ contributors:
* David Gilman: contributor
+* Ikraduya Edian: contributor
+ - Added new checks 'consider-using-generator' and 'use-a-generator'.
+
* Tiago Honorato: contributor
diff --git a/ChangeLog b/ChangeLog
index 698fe434f..ed2e2398d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -168,8 +168,17 @@ What's New in Pylint 2.7.0?
Close #3555
+* New check: ``consider-using-generator``
+
+ This check warns when a comprehension is used inside an `any` or `all` function,
+ since it is unnecessary and should be replaced by a generator instead.
+ Using a generator would be less code and way faster.
+
+ Close #3165
+
* Add Github Actions to replace Travis and AppVeyor in the future
+
What's New in Pylint 2.6.1?
===========================
diff --git a/doc/whatsnew/2.7.rst b/doc/whatsnew/2.7.rst
index 7b0fd859f..520c68cd5 100644
--- a/doc/whatsnew/2.7.rst
+++ b/doc/whatsnew/2.7.rst
@@ -26,6 +26,8 @@ New checkers
* Add `condition-evals-to-constant` check for conditionals using and/or that evaluate to a constant.
+* Add `consider-using-generator` check for the use of list comprehension inside ``any`` or ``all`` function.
+
Other Changes
=============
diff --git a/pylint/checkers/refactoring/refactoring_checker.py b/pylint/checkers/refactoring/refactoring_checker.py
index 81bb18213..07d9d5f58 100644
--- a/pylint/checkers/refactoring/refactoring_checker.py
+++ b/pylint/checkers/refactoring/refactoring_checker.py
@@ -1,4 +1,22 @@
# -*- coding: utf-8 -*-
+# Copyright (c) 2016-2018 Claudiu Popa <pcmanticore@gmail.com>
+# Copyright (c) 2016-2017 Łukasz Rogalski <rogalski.91@gmail.com>
+# Copyright (c) 2016 Moises Lopez <moylop260@vauxoo.com>
+# Copyright (c) 2016 Alexander Todorov <atodorov@otb.bg>
+# Copyright (c) 2017-2018 hippo91 <guillaume.peillex@gmail.com>
+# Copyright (c) 2017 Ville Skyttä <ville.skytta@iki.fi>
+# Copyright (c) 2017-2018 Bryce Guinta <bryce.paul.guinta@gmail.com>
+# Copyright (c) 2017 Hugo <hugovk@users.noreply.github.com>
+# Copyright (c) 2017 Łukasz Sznuk <ls@rdprojekt.pl>
+# Copyright (c) 2017 Alex Hearn <alex.d.hearn@gmail.com>
+# Copyright (c) 2017 Antonio Ossa <aaossa@uc.cl>
+# Copyright (c) 2018 Konstantin Manna <Konstantin@Manna.uno>
+# Copyright (c) 2018 Konstantin <Github@pheanex.de>
+# Copyright (c) 2018 Sushobhit <31987769+sushobhit27@users.noreply.github.com>
+# Copyright (c) 2018 Matej Marušák <marusak.matej@gmail.com>
+# Copyright (c) 2018 Ville Skyttä <ville.skytta@upcloud.com>
+# Copyright (c) 2018 Mr. Senko <atodorov@mrsenko.com>
+# Copyright (c) 2019 Ikraduya Edian <ikraduya@gmail.com>
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
@@ -282,6 +300,18 @@ class RefactoringChecker(checkers.BaseTokenChecker):
"Emitted when calling the super() builtin with the current class "
"and instance. On Python 3 these arguments are the default and they can be omitted.",
),
+ "R1728": (
+ "Consider using a generator instead '%s(%s)'",
+ "consider-using-generator",
+ "If your container can be large using "
+ "a generator will bring better performance.",
+ ),
+ "R1729": (
+ "Use a generator instead '%s(%s)'",
+ "use-a-generator",
+ "Comprehension inside of 'any' or 'all' is unnecessary. "
+ "A generator would be sufficient and faster.",
+ ),
}
options = (
(
@@ -684,18 +714,49 @@ class RefactoringChecker(checkers.BaseTokenChecker):
message_name = "consider-using-set-comprehension"
self.add_message(message_name, node=node)
+ def _check_consider_using_generator(self, node):
+ # 'any' and 'all' definitely should use generator, while 'list' and 'tuple' need to be considered first
+ # See https://github.com/PyCQA/pylint/pull/3309#discussion_r576683109
+ checked_call = ["any", "all", "list", "tuple"]
+ if (
+ isinstance(node, astroid.Call)
+ and node.func
+ and isinstance(node.func, astroid.Name)
+ and node.func.name in checked_call
+ ):
+ # functions in checked_calls take exactly one argument
+ # check whether the argument is list comprehension
+ if len(node.args) == 1 and isinstance(node.args[0], astroid.ListComp):
+ # remove square brackets '[]'
+ inside_comp = node.args[0].as_string()[1:-1]
+ call_name = node.func.name
+ if call_name in ["any", "all"]:
+ self.add_message(
+ "use-a-generator",
+ node=node,
+ args=(call_name, inside_comp),
+ )
+ else:
+ self.add_message(
+ "consider-using-generator",
+ node=node,
+ args=(call_name, inside_comp),
+ )
+
@utils.check_messages(
"stop-iteration-return",
"consider-using-dict-comprehension",
"consider-using-set-comprehension",
"consider-using-sys-exit",
"super-with-arguments",
+ "consider-using-generator",
)
def visit_call(self, node):
self._check_raising_stopiteration_in_generator_next_call(node)
self._check_consider_using_comprehension_constructor(node)
self._check_quit_exit_call(node)
self._check_super_with_arguments(node)
+ self._check_consider_using_generator(node)
@staticmethod
def _has_exit_in_scope(scope):
diff --git a/tests/functional/c/consider_using_generator.py b/tests/functional/c/consider_using_generator.py
new file mode 100644
index 000000000..eadb34a56
--- /dev/null
+++ b/tests/functional/c/consider_using_generator.py
@@ -0,0 +1,11 @@
+# pylint: disable=missing-docstring, invalid-name
+# https://github.com/PyCQA/pylint/issues/3165
+
+list([])
+tuple([])
+
+list([0 for y in list(range(10))]) # [consider-using-generator]
+tuple([0 for y in list(range(10))]) # [consider-using-generator]
+
+list(0 for y in list(range(10)))
+tuple(0 for y in list(range(10)))
diff --git a/tests/functional/c/consider_using_generator.txt b/tests/functional/c/consider_using_generator.txt
new file mode 100644
index 000000000..3d3c5a494
--- /dev/null
+++ b/tests/functional/c/consider_using_generator.txt
@@ -0,0 +1,2 @@
+consider-using-generator:7:0::Consider using a generator instead 'list(0 for y in list(range(10)))'
+consider-using-generator:8:0::Consider using a generator instead 'tuple(0 for y in list(range(10)))'
diff --git a/tests/functional/u/use_a_generator.py b/tests/functional/u/use_a_generator.py
new file mode 100644
index 000000000..279deb46f
--- /dev/null
+++ b/tests/functional/u/use_a_generator.py
@@ -0,0 +1,11 @@
+# pylint: disable=missing-docstring, invalid-name
+# https://github.com/PyCQA/pylint/issues/3165
+
+any([])
+all([])
+
+any([0 for x in list(range(10))]) # [use-a-generator]
+all([0 for y in list(range(10))]) # [use-a-generator]
+
+any(0 for x in list(range(10)))
+all(0 for y in list(range(10)))
diff --git a/tests/functional/u/use_a_generator.txt b/tests/functional/u/use_a_generator.txt
new file mode 100644
index 000000000..e7be228f0
--- /dev/null
+++ b/tests/functional/u/use_a_generator.txt
@@ -0,0 +1,2 @@
+use-a-generator:7:0::Use a generator instead 'any(0 for x in list(range(10)))'
+use-a-generator:8:0::Use a generator instead 'all(0 for y in list(range(10)))'