diff options
author | Daniƫl van Noord <13665637+DanielNoord@users.noreply.github.com> | 2021-09-14 18:49:32 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-09-14 18:49:32 +0200 |
commit | af407c73064c1a9cb3cce5f056fa1e26c9e7b540 (patch) | |
tree | bb83ec0f57bd35c40443c061d3a0ba747570c697 | |
parent | de9af75104f74f954f3eae0085cc0c400f04511d (diff) | |
download | pylint-af407c73064c1a9cb3cce5f056fa1e26c9e7b540.tar.gz |
Make consider-iterating-dictionary consider membership check (#4997)
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | doc/whatsnew/2.11.rst | 4 | ||||
-rw-r--r-- | pylint/checkers/refactoring/recommendation_checker.py | 29 | ||||
-rw-r--r-- | tests/functional/c/consider/consider_iterating_dictionary.py | 32 | ||||
-rw-r--r-- | tests/functional/c/consider/consider_iterating_dictionary.txt | 33 |
5 files changed, 75 insertions, 27 deletions
@@ -97,6 +97,10 @@ Release date: TBA Closes #5000 +* The ``consider-iterating-dictionary`` checker now also considers membership checks + + Closes #4069 + What's New in Pylint 2.10.3? ============================ diff --git a/doc/whatsnew/2.11.rst b/doc/whatsnew/2.11.rst index 6ace2f633..0a239025f 100644 --- a/doc/whatsnew/2.11.rst +++ b/doc/whatsnew/2.11.rst @@ -85,3 +85,7 @@ Other Changes Closes #1375 Closes #330 + +* The ``consider-iterating-dictionary`` checker now also considers membership checks + + Closes #4069 diff --git a/pylint/checkers/refactoring/recommendation_checker.py b/pylint/checkers/refactoring/recommendation_checker.py index 5982a0ec6..a765eca01 100644 --- a/pylint/checkers/refactoring/recommendation_checker.py +++ b/pylint/checkers/refactoring/recommendation_checker.py @@ -24,9 +24,11 @@ class RecommendationChecker(checkers.BaseChecker): "C0201": ( "Consider iterating the dictionary directly instead of calling .keys()", "consider-iterating-dictionary", - "Emitted when the keys of a dictionary are iterated through the .keys() " - "method. It is enough to just iterate through the dictionary itself, as " - 'in "for key in dictionary".', + "Emitted when the keys of a dictionary are iterated through the ``.keys()`` " + "method or when ``.keys()`` is used for a membership check. " + "It is enough to iterate through the dictionary itself, " + "``for key in dictionary``. For membership checks, " + "``if key in dictionary`` is faster.", ), "C0206": ( "Consider iterating with .items()", @@ -75,16 +77,21 @@ class RecommendationChecker(checkers.BaseChecker): return if node.func.attrname != "keys": return - if not isinstance(node.parent, (nodes.For, nodes.Comprehension)): - return - - inferred = utils.safe_infer(node.func) - if not isinstance(inferred, astroid.BoundMethod) or not isinstance( - inferred.bound, nodes.Dict + if ( + isinstance(node.parent, (nodes.For, nodes.Comprehension)) + or isinstance(node.parent, nodes.Compare) + and any( + op + for op, comparator in node.parent.ops + if op == "in" and comparator is node + ) ): - return + inferred = utils.safe_infer(node.func) + if not isinstance(inferred, astroid.BoundMethod) or not isinstance( + inferred.bound, nodes.Dict + ): + return - if isinstance(node.parent, (nodes.For, nodes.Comprehension)): self.add_message("consider-iterating-dictionary", node=node) def _check_use_maxsplit_arg(self, node: nodes.Call) -> None: diff --git a/tests/functional/c/consider/consider_iterating_dictionary.py b/tests/functional/c/consider/consider_iterating_dictionary.py index 1198de1cb..996fa5429 100644 --- a/tests/functional/c/consider/consider_iterating_dictionary.py +++ b/tests/functional/c/consider/consider_iterating_dictionary.py @@ -1,4 +1,6 @@ -# pylint: disable=missing-docstring, expression-not-assigned, too-few-public-methods, no-member, import-error, no-self-use, line-too-long, useless-object-inheritance, unnecessary-comprehension +# pylint: disable=missing-docstring, expression-not-assigned, too-few-public-methods +# pylint: disable=no-member, import-error, no-self-use, line-too-long, useless-object-inheritance +# pylint: disable=unnecessary-comprehension, use-dict-literal from unknown import Unknown @@ -36,3 +38,31 @@ DICT = {'a': 1, 'b': 2} COMP1 = [k * 2 for k in DICT.keys()] + [k * 3 for k in DICT.keys()] # [consider-iterating-dictionary,consider-iterating-dictionary] COMP2, COMP3 = [k * 2 for k in DICT.keys()], [k * 3 for k in DICT.keys()] # [consider-iterating-dictionary,consider-iterating-dictionary] SOME_TUPLE = ([k * 2 for k in DICT.keys()], [k * 3 for k in DICT.keys()]) # [consider-iterating-dictionary,consider-iterating-dictionary] + +# Checks for membership checks +if 1 in dict().keys(): # [consider-iterating-dictionary] + pass +if 1 in {}.keys(): # [consider-iterating-dictionary] + pass +if 1 in Unknown().keys(): + pass +if 1 in Unknown.keys(): + pass +if 1 in CustomClass().keys(): + pass +if 1 in dict(): + pass +if 1 in dict().values(): + pass +if (1, 1) in dict().items(): + pass +if [1] == {}.keys(): + pass +if [1] == {}: + pass +if [1] == dict(): + pass +VAR = 1 in {}.keys() # [consider-iterating-dictionary] +VAR = 1 in {} +VAR = 1 in dict() +VAR = [1, 2] == {}.keys() in {False} diff --git a/tests/functional/c/consider/consider_iterating_dictionary.txt b/tests/functional/c/consider/consider_iterating_dictionary.txt index c1b12f976..a3ebbac2a 100644 --- a/tests/functional/c/consider/consider_iterating_dictionary.txt +++ b/tests/functional/c/consider/consider_iterating_dictionary.txt @@ -1,15 +1,18 @@ -consider-iterating-dictionary:23:16::Consider iterating the dictionary directly instead of calling .keys() -consider-iterating-dictionary:24:16::Consider iterating the dictionary directly instead of calling .keys() -consider-iterating-dictionary:25:16::Consider iterating the dictionary directly instead of calling .keys() -consider-iterating-dictionary:26:21::Consider iterating the dictionary directly instead of calling .keys() -consider-iterating-dictionary:27:24::Consider iterating the dictionary directly instead of calling .keys() -consider-iterating-dictionary:28:24::Consider iterating the dictionary directly instead of calling .keys() -consider-iterating-dictionary:29:24::Consider iterating the dictionary directly instead of calling .keys() -consider-iterating-dictionary:30:29::Consider iterating the dictionary directly instead of calling .keys() -consider-iterating-dictionary:31:11::Consider iterating the dictionary directly instead of calling .keys() -consider-iterating-dictionary:36:24::Consider iterating the dictionary directly instead of calling .keys() -consider-iterating-dictionary:36:55::Consider iterating the dictionary directly instead of calling .keys() -consider-iterating-dictionary:37:31::Consider iterating the dictionary directly instead of calling .keys() -consider-iterating-dictionary:37:61::Consider iterating the dictionary directly instead of calling .keys() -consider-iterating-dictionary:38:30::Consider iterating the dictionary directly instead of calling .keys() -consider-iterating-dictionary:38:60::Consider iterating the dictionary directly instead of calling .keys() +consider-iterating-dictionary:25:16::Consider iterating the dictionary directly instead of calling .keys():HIGH +consider-iterating-dictionary:26:16::Consider iterating the dictionary directly instead of calling .keys():HIGH +consider-iterating-dictionary:27:16::Consider iterating the dictionary directly instead of calling .keys():HIGH +consider-iterating-dictionary:28:21::Consider iterating the dictionary directly instead of calling .keys():HIGH +consider-iterating-dictionary:29:24::Consider iterating the dictionary directly instead of calling .keys():HIGH +consider-iterating-dictionary:30:24::Consider iterating the dictionary directly instead of calling .keys():HIGH +consider-iterating-dictionary:31:24::Consider iterating the dictionary directly instead of calling .keys():HIGH +consider-iterating-dictionary:32:29::Consider iterating the dictionary directly instead of calling .keys():HIGH +consider-iterating-dictionary:33:11::Consider iterating the dictionary directly instead of calling .keys():HIGH +consider-iterating-dictionary:38:24::Consider iterating the dictionary directly instead of calling .keys():HIGH +consider-iterating-dictionary:38:55::Consider iterating the dictionary directly instead of calling .keys():HIGH +consider-iterating-dictionary:39:31::Consider iterating the dictionary directly instead of calling .keys():HIGH +consider-iterating-dictionary:39:61::Consider iterating the dictionary directly instead of calling .keys():HIGH +consider-iterating-dictionary:40:30::Consider iterating the dictionary directly instead of calling .keys():HIGH +consider-iterating-dictionary:40:60::Consider iterating the dictionary directly instead of calling .keys():HIGH +consider-iterating-dictionary:43:8::Consider iterating the dictionary directly instead of calling .keys():HIGH +consider-iterating-dictionary:45:8::Consider iterating the dictionary directly instead of calling .keys():HIGH +consider-iterating-dictionary:65:11::Consider iterating the dictionary directly instead of calling .keys():HIGH |