diff options
author | Claudiu Popa <cpopa@cloudbasesolutions.com> | 2015-02-28 16:09:39 +0200 |
---|---|---|
committer | Claudiu Popa <cpopa@cloudbasesolutions.com> | 2015-02-28 16:09:39 +0200 |
commit | 97bebf6a35f0581491f261e922c8ff0c07cd3eee (patch) | |
tree | 86416f00cf6d74a2ad40bd552226965526c9e81f | |
parent | dd276720942e6481b6a1676d2a272e986a411528 (diff) | |
download | pylint-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-- | ChangeLog | 6 | ||||
-rw-r--r-- | pylint/checkers/python3.py | 39 | ||||
-rw-r--r-- | pylint/test/unittest_checker_python3.py | 13 |
3 files changed, 57 insertions, 1 deletions
@@ -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): |