diff options
author | Ikraduya Edian <ikraduya@gmail.com> | 2021-02-20 21:50:19 +0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-02-20 15:50:19 +0100 |
commit | 45c824549f9a7fa38df04ae8648d1647c82ba9b4 (patch) | |
tree | c6d05e8979245ddb0c5ed84437ac8219616858bb | |
parent | 570e65536147b00ab8a5743e761d7caa326afa21 (diff) | |
download | pylint-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.txt | 3 | ||||
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | doc/whatsnew/2.7.rst | 2 | ||||
-rw-r--r-- | pylint/checkers/refactoring/refactoring_checker.py | 61 | ||||
-rw-r--r-- | tests/functional/c/consider_using_generator.py | 11 | ||||
-rw-r--r-- | tests/functional/c/consider_using_generator.txt | 2 | ||||
-rw-r--r-- | tests/functional/u/use_a_generator.py | 11 | ||||
-rw-r--r-- | tests/functional/u/use_a_generator.txt | 2 |
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 @@ -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)))' |