diff options
author | Claudiu Popa <pcmanticore@gmail.com> | 2018-04-18 09:11:12 +0200 |
---|---|---|
committer | Claudiu Popa <pcmanticore@gmail.com> | 2018-04-18 09:11:12 +0200 |
commit | f6f13d7684dbe068eb381e536e0af4379c0da8a7 (patch) | |
tree | 977b0e5f40166678742594f3a5b6b5b179bc5e01 | |
parent | 37129d948d336e9a617520a91393646f7c7aff6e (diff) | |
download | pylint-git-f6f13d7684dbe068eb381e536e0af4379c0da8a7.tar.gz |
Handle dict subclasses for dict-not-iterating checks
-rw-r--r-- | pylint/checkers/python3.py | 15 | ||||
-rw-r--r-- | pylint/test/unittest_checker_python3.py | 21 |
2 files changed, 27 insertions, 9 deletions
diff --git a/pylint/checkers/python3.py b/pylint/checkers/python3.py index 315d2d7da..e1835a142 100644 --- a/pylint/checkers/python3.py +++ b/pylint/checkers/python3.py @@ -53,6 +53,12 @@ def _is_old_octal(literal): return None +def _inferred_value_is_dict(value): + if isinstance(value, astroid.Dict): + return True + return isinstance(value, astroid.Instance) and 'dict' in value.basenames + + def _check_dict_node(node): inferred_types = set() try: @@ -65,12 +71,7 @@ def _check_dict_node(node): if not inferred_types: return True - for elem in inferred_types: - if isinstance(elem, astroid.Dict): - return True - if isinstance(elem, astroid.Instance) and 'dict' in elem.basenames: - return True - return False + return any(_inferred_value_is_dict(value) for value in inferred_types) def _is_builtin(node): @@ -802,7 +803,7 @@ class Python3Checker(checkers.BaseChecker): self._warn_if_deprecated(node, inferred_receiver.name, {node.func.attrname}, report_on_modules=False) - if (isinstance(inferred_receiver, astroid.Dict) + if (_inferred_value_is_dict(inferred_receiver) and node.func.attrname in DICT_METHODS): if not _in_iterating_context(node): checker = 'dict-{}-not-iterating'.format(node.func.attrname) diff --git a/pylint/test/unittest_checker_python3.py b/pylint/test/unittest_checker_python3.py index 76b8adff7..327677ea0 100644 --- a/pylint/test/unittest_checker_python3.py +++ b/pylint/test/unittest_checker_python3.py @@ -181,17 +181,34 @@ class TestPython3Checker(testutils.CheckerTestCase): self.as_argument_to_callable_constructor_test(fxn, func) @python2_only + def test_dict_subclasses_methods_in_iterating_context(self): + iterating, not_iterating = astroid.extract_node(''' + from __future__ import absolute_import + from collections import defaultdict + d = defaultdict(list) + a, b = d.keys() #@ + x = d.keys() #@ + ''') + + with self.assertNoMessages(): + self.checker.visit_call(iterating.value) + + message = testutils.Message('dict-keys-not-iterating', node=not_iterating.value) + with self.assertAddsMessages(message): + self.checker.visit_call(not_iterating.value) + + @python2_only def test_dict_methods_in_iterating_context(self): iterating_code = [ 'for x in {}: pass', '(x for x in {})', '[x for x in {}]', 'func({})', - 'a, b = {}' + 'a, b = {}', ] non_iterating_code = [ 'x = __({}())', - '__({}())[0]' + '__({}())[0]', ] for method in ('keys', 'items', 'values'): |