summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Pool <mbp@google.com>2013-02-26 23:17:31 +0100
committerMartin Pool <mbp@google.com>2013-02-26 23:17:31 +0100
commitb4e221395733240b6e45861433e2d0bec1a2a615 (patch)
tree8924034a7dc7545e65365d0a49fb8b7ff2c9e911
parentabeafad3d1503dcaa0586369dfe591fb9dd3a466 (diff)
downloadpylint-git-b4e221395733240b6e45861433e2d0bec1a2a615.tar.gz
give [deprecated-lambda] when a map/filter of a lambda could be a comprehension. Closes #120657
-rw-r--r--ChangeLog3
-rw-r--r--checkers/base.py40
-rw-r--r--test/input/func_deprecated_lambda.py22
-rw-r--r--test/messages/func_deprecated_lambda.txt2
4 files changed, 65 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index ee4b529c4..908cf3a02 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -24,6 +24,9 @@ ChangeLog for PyLint
* #112728: add warning E0604 for non-string objects in __all__
(patch by Torsten Marek)
+ * #120657: add warning W0110/deprecated-lambda when a map/filter
+ of a lambda could be a comprehension (patch by Martin Pool)
+
* #113231: logging checker now looks at instances of Logger classes
in addition to the base logging module. (patch by Mike Bryant)
diff --git a/checkers/base.py b/checkers/base.py
index 3cd592267..41e4b931f 100644
--- a/checkers/base.py
+++ b/checkers/base.py
@@ -23,7 +23,12 @@ from logilab.astng import are_exclusive
from pylint.interfaces import IASTNGChecker
from pylint.reporters import diff_string
from pylint.checkers import BaseChecker, EmptyReport
-from pylint.checkers.utils import check_messages, clobber_in_except, is_inside_except
+from pylint.checkers.utils import (
+ check_messages,
+ clobber_in_except,
+ is_inside_except,
+ safe_infer,
+ )
import re
@@ -798,7 +803,7 @@ class PassChecker(_BasicChecker):
msgs = {'W0107': ('Unnecessary pass statement',
'unnecessary-pass',
'Used when a "pass" statement that can be avoided is '
- 'encountered.)'),
+ 'encountered.'),
}
def visit_pass(self, node):
@@ -806,6 +811,36 @@ class PassChecker(_BasicChecker):
self.add_message('W0107', node=node)
+class LambdaForComprehensionChecker(_BasicChecker):
+ """check for using a lambda where a comprehension would do.
+
+ See <http://www.artima.com/weblogs/viewpost.jsp?thread=98196>
+ where GvR says comprehensions would be clearer.
+ """
+
+ msgs = {'W0110': ('map/filter on lambda could be replaced by comprehension',
+ 'deprecated-lambda',
+ 'Used when a lambda is the first argument to "map" or '
+ '"filter". It could be clearer as a list '
+ 'comprehension or generator expression.'),
+ }
+
+ @check_messages('W0110')
+ def visit_callfunc(self, node):
+ """visit a CallFunc node, check if map or filter are called with a
+ lambda
+ """
+ if not node.args:
+ return
+ if not isinstance(node.args[0], astng.Lambda):
+ return
+ infered = safe_infer(node.func)
+ if (infered
+ and infered.parent.name == '__builtin__'
+ and infered.name in ['map', 'filter']):
+ self.add_message('W0110', node=node)
+
+
def register(linter):
"""required method to auto register this checker"""
linter.register_checker(BasicErrorChecker(linter))
@@ -813,3 +848,4 @@ def register(linter):
linter.register_checker(NameChecker(linter))
linter.register_checker(DocStringChecker(linter))
linter.register_checker(PassChecker(linter))
+ linter.register_checker(LambdaForComprehensionChecker(linter))
diff --git a/test/input/func_deprecated_lambda.py b/test/input/func_deprecated_lambda.py
new file mode 100644
index 000000000..973bb320f
--- /dev/null
+++ b/test/input/func_deprecated_lambda.py
@@ -0,0 +1,22 @@
+# pylint: disable=missing-docstring,bad-builtin,invalid-name
+__revision__ = "$Id$"
+
+# Don't do this, use a comprehension instead.
+assert map(lambda x: x*2, [1, 2, 3]) == [2, 4, 6]
+
+assert filter(lambda x: x != 1, [1, 2, 3]) == [2, 3]
+
+# It's still ok to use map and filter with anything but an inline lambda.
+double = lambda x: x * 2
+assert map(double, [1, 2, 3]) == [2, 4, 6]
+
+# It's also ok to pass lambdas to other functions.
+assert reduce(lambda x, y: x * y, [1, 2, 3, 4]) == 24
+
+# Or to a undefined function or one with varargs
+def f(*a):
+ return len(a)
+
+f(lambda x, y: x + y, [1, 2, 3])
+
+undefined_function(lambda: 2) # pylint: disable=undefined-variable
diff --git a/test/messages/func_deprecated_lambda.txt b/test/messages/func_deprecated_lambda.txt
new file mode 100644
index 000000000..e7ecd5bda
--- /dev/null
+++ b/test/messages/func_deprecated_lambda.txt
@@ -0,0 +1,2 @@
+W: 5: map/filter on lambda could be replaced by comprehension
+W: 7: map/filter on lambda could be replaced by comprehension