summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudiu Popa <pcmanticore@gmail.com>2018-04-18 08:34:21 +0200
committerClaudiu Popa <pcmanticore@gmail.com>2018-04-18 08:34:21 +0200
commit37129d948d336e9a617520a91393646f7c7aff6e (patch)
tree27d966261dd2e26a5fe86854330a7f45d833c188
parent50e28f28a3785cc9fa6cdb6efec1daf7f38f09ed (diff)
downloadpylint-git-37129d948d336e9a617520a91393646f7c7aff6e.tar.gz
defaultdict and subclasses of dict are now handled for dict-iter-* checks
Close #2005
-rw-r--r--ChangeLog4
-rw-r--r--doc/whatsnew/1.9.rst11
-rw-r--r--pylint/checkers/python3.py11
-rw-r--r--pylint/test/unittest_checker_python3.py32
4 files changed, 48 insertions, 10 deletions
diff --git a/ChangeLog b/ChangeLog
index 45e018202..8941e8f8b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -7,6 +7,10 @@ What's New in Pylint 1.9.0?
Release date:
+ * defaultdict and subclasses of dict are now handled for dict-iter-* checks
+
+ Close #2005
+
* Added a new Python 2/3 check for invalid raise syntax.
Close #1937
diff --git a/doc/whatsnew/1.9.rst b/doc/whatsnew/1.9.rst
index 954a22f20..e71a277d8 100644
--- a/doc/whatsnew/1.9.rst
+++ b/doc/whatsnew/1.9.rst
@@ -47,3 +47,14 @@ New checkers
Other Changes
=============
+
+* `defaultdict` and subclasses of `dict` are now handled for `dict-iter-*` checks. That
+ means that the following code will now emit warnings for when `iteritems` and friends
+ are accessed:
+
+ .. code-block:: python
+
+ some_dict = defaultdict(list)
+ ...
+ some_dict.iterkeys()
+
diff --git a/pylint/checkers/python3.py b/pylint/checkers/python3.py
index 1556bf0da..315d2d7da 100644
--- a/pylint/checkers/python3.py
+++ b/pylint/checkers/python3.py
@@ -62,8 +62,15 @@ def _check_dict_node(node):
inferred_types.add(inferred_node)
except astroid.InferenceError:
pass
- return (not inferred_types
- or any(isinstance(x, astroid.Dict) for x in inferred_types))
+
+ 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
def _is_builtin(node):
diff --git a/pylint/test/unittest_checker_python3.py b/pylint/test/unittest_checker_python3.py
index 98c56e89e..76b8adff7 100644
--- a/pylint/test/unittest_checker_python3.py
+++ b/pylint/test/unittest_checker_python3.py
@@ -384,10 +384,18 @@ class TestPython3Checker(testutils.CheckerTestCase):
self.checker.visit_call(node)
def test_dict_iter_method_on_dict(self):
- node = astroid.extract_node('{}.iterkeys()')
- message = testutils.Message('dict-iter-method', node=node)
- with self.assertAddsMessages(message):
- self.checker.visit_call(node)
+ nodes = astroid.extract_node('''
+ from collections import defaultdict
+ {}.iterkeys() #@
+ defaultdict(list).iterkeys() #@
+ class Someclass(dict):
+ pass
+ Someclass().iterkeys() #@
+ ''')
+ for node in nodes:
+ message = testutils.Message('dict-iter-method', node=node)
+ with self.assertAddsMessages(message):
+ self.checker.visit_call(node)
def test_dict_not_iter_method(self):
arg_node = astroid.extract_node('x.iterkeys(x) #@')
@@ -406,10 +414,18 @@ class TestPython3Checker(testutils.CheckerTestCase):
self.checker.visit_call(node)
def test_dict_view_method_on_dict(self):
- node = astroid.extract_node('{}.viewkeys()')
- message = testutils.Message('dict-view-method', node=node)
- with self.assertAddsMessages(message):
- self.checker.visit_call(node)
+ nodes = astroid.extract_node('''
+ from collections import defaultdict
+ {}.viewkeys() #@
+ defaultdict(list).viewkeys() #@
+ class Someclass(dict):
+ pass
+ Someclass().viewkeys() #@
+ ''')
+ for node in nodes:
+ message = testutils.Message('dict-view-method', node=node)
+ with self.assertAddsMessages(message):
+ self.checker.visit_call(node)
def test_dict_not_view_method(self):
arg_node = astroid.extract_node('x.viewkeys(x) #@')