summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Pribysh <dmand@yandex.ru>2015-10-06 12:45:34 +0300
committerDmitry Pribysh <dmand@yandex.ru>2015-10-06 12:45:34 +0300
commit7666e2d0f386b8f4758dd8b221b9380edaf8fe8f (patch)
treec5bb27d1720bafecc0d2fb72e60d3d6fd84f3380
parentc47b60020a7e592373deaba7d1fe6f78592c534b (diff)
downloadpylint-7666e2d0f386b8f4758dd8b221b9380edaf8fe8f.tar.gz
Improve iterable inference and add more unit tests for iterable checker
-rw-r--r--pylint/checkers/base.py19
-rw-r--r--pylint/test/unittest_checker_base.py54
2 files changed, 62 insertions, 11 deletions
diff --git a/pylint/checkers/base.py b/pylint/checkers/base.py
index 7f6f44c..904cf9f 100644
--- a/pylint/checkers/base.py
+++ b/pylint/checkers/base.py
@@ -1499,15 +1499,25 @@ class IterableChecker(_BasicChecker):
is_string = self._is_string(value)
return is_iterable_value or is_string
+ def _not_an_iterable(self, value):
+ is_iterable = self._is_iterable(value)
+ is_const = isinstance(value, astroid.Const)
+ return not is_iterable and is_const
+
def _is_mapping(self, value):
- return isinstance(value, astroid.Dict)
+ return isinstance(value, (astroid.Dict, astroid.DictComp))
+
+ def _not_a_mapping(self, value):
+ is_mapping = self._is_mapping(value)
+ is_const = isinstance(value, astroid.Const)
+ return not is_mapping and is_const
def _check_iterable(self, element, root_node):
infered = helpers.safe_infer(element)
if infered is not None:
- if not self._is_iterable(infered):
+ if self._not_an_iterable(infered):
self.add_message('not-an-iterable',
- args=infered.as_string(),
+ args=element.as_string(),
node=root_node)
def _check_mapping(self, element, root_node):
@@ -1515,7 +1525,7 @@ class IterableChecker(_BasicChecker):
if infered is not None:
if not self._is_mapping(infered):
self.add_message('not-a-mapping',
- args=infered.as_string(),
+ args=element.as_string(),
node=root_node)
@check_messages('not-an-iterable')
@@ -1550,7 +1560,6 @@ class IterableChecker(_BasicChecker):
@check_messages('not-an-iterable')
def visit_generatorexp(self, node):
- import code; code.interact(local=locals())
for gen in node.generators:
self._check_iterable(gen.iter, node)
diff --git a/pylint/test/unittest_checker_base.py b/pylint/test/unittest_checker_base.py
index b58d8d9..538cf94 100644
--- a/pylint/test/unittest_checker_base.py
+++ b/pylint/test/unittest_checker_base.py
@@ -369,7 +369,7 @@ class IterableTest(CheckerTestCase):
with self.assertNoMessages():
self.walk(node.root())
- def test_non_mapping_in_kwargs(self):
+ def test_non_mapping_in_funcall_kwargs(self):
node = test_utils.extract_node("""
foo(**123)
""")
@@ -381,7 +381,7 @@ class IterableTest(CheckerTestCase):
args = [1, 2, 3]
foo(**args)
""")
- message = Message('not-a-mapping', node=node, args='[1, 2, 3]')
+ message = Message('not-a-mapping', node=node, args='args')
with self.assertAddsMessages(message):
self.walk(node.root())
@@ -398,21 +398,63 @@ class IterableTest(CheckerTestCase):
with self.assertNoMessages():
self.checker.visit_call(node)
+ node = test_utils.extract_node("""
+ foo(**{str(x): x for x in range(5)})
+ """)
+ with self.assertNoMessages():
+ self.checker.visit_call(node)
+
def test_non_iterable_in_listcomp(self):
node = test_utils.extract_node("""
- [x for x in 123]
+ [x ** 2 for x in 10]
""")
- message = Message('not-an-iterable', node=node, args='123')
+ message = Message('not-an-iterable', node=node, args='10')
with self.assertAddsMessages(message):
self.checker.visit_listcomp(node)
- # TODO: more tests
+
+ node = test_utils.extract_node("""
+ [x ** 2 for x in range(10)]
+ """)
+ with self.assertNoMessages():
+ self.checker.visit_listcomp(node)
+
+ def test_non_iterable_in_dictcomp(self):
+ node = test_utils.extract_node("""
+ {x: chr(x) for x in 256}
+ """)
+ message = Message('not-an-iterable', node=node, args='256')
+ with self.assertAddsMessages(message):
+ self.checker.visit_dictcomp(node)
+
+ node = test_utils.extract_node("""
+ {ord(x): x for x in "aoeui"}
+ """)
+ with self.assertNoMessages():
+ self.checker.visit_dictcomp(node)
+
+ def test_non_iterable_in_setcomp(self):
+ node = test_utils.extract_node("""
+ {2 ** x for x in 10}
+ """)
+ message = Message('not-an-iterable', node=node, args='10')
+ with self.assertAddsMessages(message):
+ self.checker.visit_setcomp(node)
+
+ node = test_utils.extract_node("""
+ {2 ** x for x in range(10)}
+ """)
+ with self.assertNoMessages():
+ self.checker.visit_setcomp(node)
def test_non_iterable_in_generator(self):
node = test_utils.extract_node("__(x for x in 123)")
message = Message('not-an-iterable', node=node, args='123')
with self.assertAddsMessages(message):
self.walk(node.root())
- # TODO: more tests
+
+ node = test_utils.extract_node("__(chr(x) for x in range(25))")
+ with self.assertNoMessages():
+ self.walk(node.root())
if __name__ == '__main__':