summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudiu Popa <cpopa@cloudbasesolutions.com>2015-02-28 16:09:39 +0200
committerClaudiu Popa <cpopa@cloudbasesolutions.com>2015-02-28 16:09:39 +0200
commit97bebf6a35f0581491f261e922c8ff0c07cd3eee (patch)
tree86416f00cf6d74a2ad40bd552226965526c9e81f
parentdd276720942e6481b6a1676d2a272e986a411528 (diff)
downloadpylint-97bebf6a35f0581491f261e922c8ff0c07cd3eee.tar.gz
Add a new warning for the Python 3 porting checker, 'using-cmp-argument'.
This warning is emitted when the `cmp` argument for the `list.sort` or `sorted builtin` is encountered, since it was removed in Python 3. This is part of the issue #376.
-rw-r--r--ChangeLog6
-rw-r--r--pylint/checkers/python3.py39
-rw-r--r--pylint/test/unittest_checker_python3.py13
3 files changed, 57 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index 9977d16..821e826 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,7 +1,7 @@
ChangeLog for Pylint
--------------------
-NOT RELEASED YET -- VERSION
+RELEASE DATE -- VERSION
* Don't require a docstring for empty modules. Closes issue #261.
* Fix a false positive with `too-few-format-args` string warning,
@@ -44,6 +44,10 @@ NOT RELEASED YET -- VERSION
* Add support for combining the Python 3 checker mode with the --jobs
flag (--py3k and --jobs). Closes issue #467.
+ * Add a new warning for the Python 3 porting checker, 'using-cmp-argument',
+ emitted when the `cmp` argument for the `list.sort` or `sorted builtin`
+ is encountered.
+
2015-01-16 -- 1.4.1
diff --git a/pylint/checkers/python3.py b/pylint/checkers/python3.py
index 3ddf495..cf5e888 100644
--- a/pylint/checkers/python3.py
+++ b/pylint/checkers/python3.py
@@ -18,6 +18,7 @@ import re
import tokenize
import astroid
+from astroid import bases
from pylint import checkers, interfaces
from pylint.utils import WarningScope
from pylint.checkers import utils
@@ -326,6 +327,13 @@ class Python3Checker(checkers.BaseChecker):
'Used when the filter built-in is referenced in a non-iterating '
'context (returns an iterator in Python 3)',
{'maxversion': (3, 0)}),
+ 'W1640': ('Using the cmp argument for list.sort / sorted',
+ 'using-cmp-argument',
+ 'Using the cmp argument for list.sort or the sorted '
+ 'builtin should be avoided, since it was removed in '
+ 'Python 3. Using either `key` or `functools.cmp_to_key` '
+ 'should be preferred.',
+ {'maxversion': (3, 0)}),
}
_bad_builtins = frozenset([
@@ -425,7 +433,38 @@ class Python3Checker(checkers.BaseChecker):
else:
self.add_message('old-division', node=node)
+ def _check_cmp_argument(self, node):
+ # Check that the `cmp` argument is used
+ args = []
+ if (isinstance(node.func, astroid.Getattr)
+ and node.func.attrname == 'sort'):
+ inferred = utils.safe_infer(node.func.expr)
+ if not inferred:
+ return
+
+ builtins_list = "{}.list".format(bases.BUILTINS)
+ if (isinstance(inferred, astroid.List)
+ or inferred.qname() == builtins_list):
+ args = node.args
+
+ elif (isinstance(node.func, astroid.Name)
+ and node.func.name == 'sorted'):
+ inferred = utils.safe_infer(node.func)
+ if not inferred:
+ return
+
+ builtins_sorted = "{}.sorted".format(bases.BUILTINS)
+ if inferred.qname() == builtins_sorted:
+ args = node.args
+
+ for arg in args:
+ if isinstance(arg, astroid.Keyword) and arg.arg == 'cmp':
+ self.add_message('using-cmp-argument', node=node)
+ return
+
def visit_callfunc(self, node):
+ self._check_cmp_argument(node)
+
if isinstance(node.func, astroid.Getattr):
if any([node.args, node.starargs, node.kwargs]):
return
diff --git a/pylint/test/unittest_checker_python3.py b/pylint/test/unittest_checker_python3.py
index 825e827..bac3f4a 100644
--- a/pylint/test/unittest_checker_python3.py
+++ b/pylint/test/unittest_checker_python3.py
@@ -384,6 +384,19 @@ class Python3CheckerTest(testutils.CheckerTestCase):
with self.assertNoMessages():
self.walk(node)
+ def test_using_cmp_argument(self):
+ nodes = test_utils.extract_node("""
+ [].sort(cmp=lambda x: x) #@
+ a = list(range(x))
+ a.sort(cmp=lambda x: x) #@
+
+ sorted([], cmp=lambda x: x) #@
+ """)
+ for node in nodes:
+ message = testutils.Message('using-cmp-argument', node=node)
+ with self.assertAddsMessages(message):
+ self.checker.visit_callfunc(node)
+
@python2_only
class Python3TokenCheckerTest(testutils.CheckerTestCase):