diff options
-rw-r--r-- | pylint/checkers/base.py | 49 | ||||
-rw-r--r-- | pylint/test/unittest_checker_base.py | 25 |
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] |