summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Pribysh <dmand@yandex.ru>2015-10-07 02:39:08 +0300
committerDmitry Pribysh <dmand@yandex.ru>2015-10-07 02:39:08 +0300
commitaa68ce1b13aed050373c1953e6b92987633d4777 (patch)
treea498f1ae1162d533c3b1fda86c7cea0c3562a51f
parent7666e2d0f386b8f4758dd8b221b9380edaf8fe8f (diff)
downloadpylint-aa68ce1b13aed050373c1953e6b92987633d4777.tar.gz
Alter inference strategy in iterable/mapping checker
-rw-r--r--pylint/checkers/base.py49
-rw-r--r--pylint/test/unittest_checker_base.py25
2 files changed, 22 insertions, 52 deletions
diff --git a/pylint/checkers/base.py b/pylint/checkers/base.py
index 904cf9f..b68b082 100644
--- a/pylint/checkers/base.py
+++ b/pylint/checkers/base.py
@@ -1478,39 +1478,29 @@ class ComparisonChecker(_BasicChecker):
class IterableChecker(_BasicChecker):
"""
- TODO:
+ Checks for non-iterables used in an iterable context.
+ Contexts include:
+ - for-statement
+ - starargs in function call
+ - `yield from`-statement
+ - list, dict and set comprehensions
+ - generator expressions
+ Also checks for non-mappings in function call kwargs.
"""
- msgs = {'E0121': ('Non-iterable value %s is used in an iterating context',
+ msgs = {'E0118': ('Non-iterable value %s is used in an iterating context',
'not-an-iterable',
- 'YOLO'),
- 'E0122': ('Non-mapping value %s is used in an mapping context',
+ 'Used when a non-iterable value is used in place where'
+ 'iterable is expected'),
+ 'E0119': ('Non-mapping value %s is used in a mapping context',
'not-a-mapping',
- 'YOLO'),
+ 'Used when a non-mapping value is used in place where'
+ 'mapping is expected'),
}
- def _is_string(self, node):
- return isinstance(node, astroid.Const) and \
- isinstance(node.value, six.string_types)
-
- def _is_iterable(self, value):
- is_iterable_value = isinstance(value, (astroid.List, astroid.Tuple,
- astroid.Set, astroid.Dict,
- astroid.bases.Generator))
- 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, 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 _not_an_iterable(self, node):
+ is_const = isinstance(node, astroid.Const)
+ is_string = is_const and isinstance(node.value, six.string_types)
+ return is_const and not is_string
def _check_iterable(self, element, root_node):
infered = helpers.safe_infer(element)
@@ -1523,7 +1513,7 @@ class IterableChecker(_BasicChecker):
def _check_mapping(self, element, root_node):
infered = helpers.safe_infer(element)
if infered is not None:
- if not self._is_mapping(infered):
+ if isinstance(infered, astroid.Const):
self.add_message('not-a-mapping',
args=element.as_string(),
node=root_node)
@@ -1573,3 +1563,4 @@ def register(linter):
linter.register_checker(PassChecker(linter))
linter.register_checker(LambdaForComprehensionChecker(linter))
linter.register_checker(ComparisonChecker(linter))
+ linter.register_checker(IterableChecker(linter))
diff --git a/pylint/test/unittest_checker_base.py b/pylint/test/unittest_checker_base.py
index 538cf94..0b1cddd 100644
--- a/pylint/test/unittest_checker_base.py
+++ b/pylint/test/unittest_checker_base.py
@@ -354,7 +354,7 @@ class IterableTest(CheckerTestCase):
with self.assertNoMessages():
self.checker.visit_yieldfrom(node)
- def test_non_iterable_in_starargs(self):
+ def test_non_iterable_in_funcall_starargs(self):
node = test_utils.extract_node("""
foo(*123)
""")
@@ -378,32 +378,11 @@ class IterableTest(CheckerTestCase):
self.checker.visit_call(node)
node = test_utils.extract_node("""
- args = [1, 2, 3]
- foo(**args)
- """)
- message = Message('not-a-mapping', node=node, args='args')
- with self.assertAddsMessages(message):
- self.walk(node.root())
-
- node = test_utils.extract_node("""
- kwargs = {'answer': 42}
- foo(**kwargs)
+ foo(**retdict())
""")
with self.assertNoMessages():
self.walk(node.root())
- node = test_utils.extract_node("""
- foo(**dict(a=1, b=2))
- """)
- 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 ** 2 for x in 10]