summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudiu Popa <cpopa@cloudbasesolutions.com>2014-11-17 20:39:29 +0200
committerClaudiu Popa <cpopa@cloudbasesolutions.com>2014-11-17 20:39:29 +0200
commitd07a5fd7e25f9517c8100f1d77dd5640eb3755fa (patch)
tree20c77383d2e144501777c7bdfa3cd0907d2abad3
parentd5042c3db7e2489fc442f3ce91ef1d9d5adb53c0 (diff)
downloadpylint-d07a5fd7e25f9517c8100f1d77dd5640eb3755fa.tar.gz
Add 'implicit-map-evaluation' to Python 3 porting checker.
This warning is emitted when encountering the use of map builtin, without explicit evaluation, as in "map(func, args)" on a single line. This behaviour is removed in Python 3, where map is a generator and must be explicitly evaluated.
-rw-r--r--ChangeLog3
-rw-r--r--checkers/python3.py16
-rw-r--r--test/unittest_checker_python3.py10
3 files changed, 29 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index a877b66..cc970e5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -182,6 +182,9 @@ ChangeLog for Pylint
* Add 'old-octal-literal' to Python 3 porting checker, emitted when
encountering octals with the old syntax.
+
+ * Add 'implicit-map-evaluation' to Python 3 porting checker, emitted
+ when encountering the use of map builtin, without explicit evaluation.
diff --git a/checkers/python3.py b/checkers/python3.py
index e428a60..472e328 100644
--- a/checkers/python3.py
+++ b/checkers/python3.py
@@ -237,6 +237,14 @@ class Python3Checker(checkers.BaseChecker):
'Used when a __cmp__ method is defined '
'(method is not used by Python 3)',
{'maxversion': (3, 0)}),
+ 'W1631': ('map is used as implicitly evaluated call',
+ 'implicit-map-evaluation',
+ 'Used when the map builtin is used as implicitly '
+ 'evaluated call, as in "map(func, args)" on a single line. '
+ 'This behaviour will not work in Python 3, where '
+ 'map is a generator and must be evaluated. '
+ 'Prefer a for-loop as alternative.',
+ {'maxversion': (3, 0)}),
}
_missing_builtins = frozenset([
@@ -285,6 +293,14 @@ class Python3Checker(checkers.BaseChecker):
if isinstance(arg, astroid.Tuple):
self.add_message('parameter-unpacking', node=arg)
+ @utils.check_messages('implicit-map-evaluation')
+ def visit_discard(self, node):
+ if (isinstance(node.value, astroid.CallFunc) and
+ node.value.func.name == 'map'):
+ module = node.value.func.lookup('map')[0]
+ if getattr(module, 'name', None) == '__builtin__':
+ self.add_message('implicit-map-evaluation', node=node)
+
def visit_name(self, node):
"""Detect when a built-in that is missing in Python 3 is referenced."""
found_node = node.lookup(node.name)[0]
diff --git a/test/unittest_checker_python3.py b/test/unittest_checker_python3.py
index b57fc96..f7eead9 100644
--- a/test/unittest_checker_python3.py
+++ b/test/unittest_checker_python3.py
@@ -200,6 +200,16 @@ class Python3CheckerTest(testutils.CheckerTestCase):
with self.assertAddsMessages(message):
self.checker.visit_callfunc(node)
+ @python2_only
+ def test_implicit_map_evaluation(self):
+ node = test_utils.extract_node('map(str, [1, 2, 3])')
+ discard = node.parent
+ message = testutils.Message('implicit-map-evaluation', node=discard)
+ with self.assertAddsMessages(message):
+ # Use node.parent because extract_node returns the value
+ # of a discard node, not the discard itself.
+ self.checker.visit_discard(discard)
+
def test_not_next_method(self):
arg_node = test_utils.extract_node('x.next(x) #@')
stararg_node = test_utils.extract_node('x.next(*x) #@')