summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudiu Popa <pcmanticore@gmail.com>2018-04-18 09:11:12 +0200
committerClaudiu Popa <pcmanticore@gmail.com>2018-04-18 09:11:12 +0200
commitf6f13d7684dbe068eb381e536e0af4379c0da8a7 (patch)
tree977b0e5f40166678742594f3a5b6b5b179bc5e01
parent37129d948d336e9a617520a91393646f7c7aff6e (diff)
downloadpylint-git-f6f13d7684dbe068eb381e536e0af4379c0da8a7.tar.gz
Handle dict subclasses for dict-not-iterating checks
-rw-r--r--pylint/checkers/python3.py15
-rw-r--r--pylint/test/unittest_checker_python3.py21
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'):