Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(91)

Unified Diff: third_party/pylint/pylint/checkers/python3.py

Issue 1920403002: [content/test/gpu] Run pylint check of gpu tests in unittest instead of PRESUBMIT (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Update path to LICENSE.txt of logilab/README.chromium Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/pylint/pylint/checkers/newstyle.py ('k') | third_party/pylint/pylint/checkers/raw_metrics.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/pylint/pylint/checkers/python3.py
diff --git a/third_party/pylint/pylint/checkers/python3.py b/third_party/pylint/pylint/checkers/python3.py
new file mode 100644
index 0000000000000000000000000000000000000000..59c37bf9c91a1284c7c198f5f919065ccdfeea2b
--- /dev/null
+++ b/third_party/pylint/pylint/checkers/python3.py
@@ -0,0 +1,476 @@
+# Copyright 2014 Google Inc.
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+"""Check Python 2 code for Python 2/3 source-compatible issues."""
+from __future__ import absolute_import
+
+import re
+import tokenize
+
+import astroid
+from pylint import checkers, interfaces
+from pylint.utils import WarningScope
+from pylint.checkers import utils
+
+
+_ZERO = re.compile("^0+$")
+
+def _is_old_octal(literal):
+ if _ZERO.match(literal):
+ return False
+ if re.match('0\d+', literal):
+ try:
+ int(literal, 8)
+ except ValueError:
+ return False
+ return True
+
+def _check_dict_node(node):
+ inferred_types = set()
+ try:
+ inferred = node.infer()
+ for inferred_node in inferred:
+ inferred_types.add(inferred_node)
+ except (astroid.InferenceError, astroid.UnresolvableName):
+ pass
+ return (not inferred_types
+ or any(isinstance(x, astroid.Dict) for x in inferred_types))
+
+
+class Python3Checker(checkers.BaseChecker):
+
+ __implements__ = interfaces.IAstroidChecker
+ enabled = False
+ name = 'python3'
+
+ msgs = {
+ # Errors for what will syntactically break in Python 3, warnings for
+ # everything else.
+ 'E1601': ('print statement used',
+ 'print-statement',
+ 'Used when a print statement is used '
+ '(`print` is a function in Python 3)',
+ {'maxversion': (3, 0)}),
+ 'E1602': ('Parameter unpacking specified',
+ 'parameter-unpacking',
+ 'Used when parameter unpacking is specified for a function'
+ "(Python 3 doesn't allow it)",
+ {'maxversion': (3, 0)}),
+ 'E1603': ('Implicit unpacking of exceptions is not supported '
+ 'in Python 3',
+ 'unpacking-in-except',
+ 'Python3 will not allow implicit unpacking of '
+ 'exceptions in except clauses. '
+ 'See http://www.python.org/dev/peps/pep-3110/',
+ {'maxversion': (3, 0),
+ 'old_names': [('W0712', 'unpacking-in-except')]}),
+ 'E1604': ('Use raise ErrorClass(args) instead of '
+ 'raise ErrorClass, args.',
+ 'old-raise-syntax',
+ "Used when the alternate raise syntax "
+ "'raise foo, bar' is used "
+ "instead of 'raise foo(bar)'.",
+ {'maxversion': (3, 0),
+ 'old_names': [('W0121', 'old-raise-syntax')]}),
+ 'E1605': ('Use of the `` operator',
+ 'backtick',
+ 'Used when the deprecated "``" (backtick) operator is used '
+ 'instead of the str() function.',
+ {'scope': WarningScope.NODE,
+ 'maxversion': (3, 0),
+ 'old_names': [('W0333', 'backtick')]}),
+ 'W1601': ('apply built-in referenced',
+ 'apply-builtin',
+ 'Used when the apply built-in function is referenced '
+ '(missing from Python 3)',
+ {'maxversion': (3, 0)}),
+ 'W1602': ('basestring built-in referenced',
+ 'basestring-builtin',
+ 'Used when the basestring built-in function is referenced '
+ '(missing from Python 3)',
+ {'maxversion': (3, 0)}),
+ 'W1603': ('buffer built-in referenced',
+ 'buffer-builtin',
+ 'Used when the buffer built-in function is referenced '
+ '(missing from Python 3)',
+ {'maxversion': (3, 0)}),
+ 'W1604': ('cmp built-in referenced',
+ 'cmp-builtin',
+ 'Used when the cmp built-in function is referenced '
+ '(missing from Python 3)',
+ {'maxversion': (3, 0)}),
+ 'W1605': ('coerce built-in referenced',
+ 'coerce-builtin',
+ 'Used when the coerce built-in function is referenced '
+ '(missing from Python 3)',
+ {'maxversion': (3, 0)}),
+ 'W1606': ('execfile built-in referenced',
+ 'execfile-builtin',
+ 'Used when the execfile built-in function is referenced '
+ '(missing from Python 3)',
+ {'maxversion': (3, 0)}),
+ 'W1607': ('file built-in referenced',
+ 'file-builtin',
+ 'Used when the file built-in function is referenced '
+ '(missing from Python 3)',
+ {'maxversion': (3, 0)}),
+ 'W1608': ('long built-in referenced',
+ 'long-builtin',
+ 'Used when the long built-in function is referenced '
+ '(missing from Python 3)',
+ {'maxversion': (3, 0)}),
+ 'W1609': ('raw_input built-in referenced',
+ 'raw_input-builtin',
+ 'Used when the raw_input built-in function is referenced '
+ '(missing from Python 3)',
+ {'maxversion': (3, 0)}),
+ 'W1610': ('reduce built-in referenced',
+ 'reduce-builtin',
+ 'Used when the reduce built-in function is referenced '
+ '(missing from Python 3)',
+ {'maxversion': (3, 0)}),
+ 'W1611': ('StandardError built-in referenced',
+ 'standarderror-builtin',
+ 'Used when the StandardError built-in function is referenced '
+ '(missing from Python 3)',
+ {'maxversion': (3, 0)}),
+ 'W1612': ('unicode built-in referenced',
+ 'unicode-builtin',
+ 'Used when the unicode built-in function is referenced '
+ '(missing from Python 3)',
+ {'maxversion': (3, 0)}),
+ 'W1613': ('xrange built-in referenced',
+ 'xrange-builtin',
+ 'Used when the xrange built-in function is referenced '
+ '(missing from Python 3)',
+ {'maxversion': (3, 0)}),
+ 'W1614': ('__coerce__ method defined',
+ 'coerce-method',
+ 'Used when a __coerce__ method is defined '
+ '(method is not used by Python 3)',
+ {'maxversion': (3, 0)}),
+ 'W1615': ('__delslice__ method defined',
+ 'delslice-method',
+ 'Used when a __delslice__ method is defined '
+ '(method is not used by Python 3)',
+ {'maxversion': (3, 0)}),
+ 'W1616': ('__getslice__ method defined',
+ 'getslice-method',
+ 'Used when a __getslice__ method is defined '
+ '(method is not used by Python 3)',
+ {'maxversion': (3, 0)}),
+ 'W1617': ('__setslice__ method defined',
+ 'setslice-method',
+ 'Used when a __setslice__ method is defined '
+ '(method is not used by Python 3)',
+ {'maxversion': (3, 0)}),
+ 'W1618': ('import missing `from __future__ import absolute_import`',
+ 'no-absolute-import',
+ 'Used when an import is not accompanied by '
+ '`from __future__ import absolute_import`'
+ ' (default behaviour in Python 3)',
+ {'maxversion': (3, 0)}),
+ 'W1619': ('division w/o __future__ statement',
+ 'old-division',
+ 'Used for non-floor division w/o a float literal or '
+ '``from __future__ import division``'
+ '(Python 3 returns a float for int division unconditionally)',
+ {'maxversion': (3, 0)}),
+ 'W1620': ('Calling a dict.iter*() method',
+ 'dict-iter-method',
+ 'Used for calls to dict.iterkeys(), itervalues() or iteritems() '
+ '(Python 3 lacks these methods)',
+ {'maxversion': (3, 0)}),
+ 'W1621': ('Calling a dict.view*() method',
+ 'dict-view-method',
+ 'Used for calls to dict.viewkeys(), viewvalues() or viewitems() '
+ '(Python 3 lacks these methods)',
+ {'maxversion': (3, 0)}),
+ 'W1622': ('Called a next() method on an object',
+ 'next-method-called',
+ "Used when an object's next() method is called "
+ '(Python 3 uses the next() built-in function)',
+ {'maxversion': (3, 0)}),
+ 'W1623': ("Assigning to a class' __metaclass__ attribute",
+ 'metaclass-assignment',
+ "Used when a metaclass is specified by assigning to __metaclass__ "
+ '(Python 3 specifies the metaclass as a class statement argument)',
+ {'maxversion': (3, 0)}),
+ 'W1624': ('Indexing exceptions will not work on Python 3',
+ 'indexing-exception',
+ 'Indexing exceptions will not work on Python 3. Use '
+ '`exception.args[index]` instead.',
+ {'maxversion': (3, 0),
+ 'old_names': [('W0713', 'indexing-exception')]}),
+ 'W1625': ('Raising a string exception',
+ 'raising-string',
+ 'Used when a string exception is raised. This will not '
+ 'work on Python 3.',
+ {'maxversion': (3, 0),
+ 'old_names': [('W0701', 'raising-string')]}),
+ 'W1626': ('reload built-in referenced',
+ 'reload-builtin',
+ 'Used when the reload built-in function is referenced '
+ '(missing from Python 3). You can use instead imp.reload '
+ 'or importlib.reload.',
+ {'maxversion': (3, 0)}),
+ 'W1627': ('__oct__ method defined',
+ 'oct-method',
+ 'Used when a __oct__ method is defined '
+ '(method is not used by Python 3)',
+ {'maxversion': (3, 0)}),
+ 'W1628': ('__hex__ method defined',
+ 'hex-method',
+ 'Used when a __hex__ method is defined '
+ '(method is not used by Python 3)',
+ {'maxversion': (3, 0)}),
+ 'W1629': ('__nonzero__ method defined',
+ 'nonzero-method',
+ 'Used when a __nonzero__ method is defined '
+ '(method is not used by Python 3)',
+ {'maxversion': (3, 0)}),
+ 'W1630': ('__cmp__ method defined',
+ 'cmp-method',
+ '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)}),
+ 'W1632': ('input built-in referenced',
+ 'input-builtin',
+ 'Used when the input built-in is referenced '
+ '(backwards-incompatible semantics in Python 3)',
+ {'maxversion': (3, 0)}),
+ 'W1633': ('round built-in referenced',
+ 'round-builtin',
+ 'Used when the round built-in is referenced '
+ '(backwards-incompatible semantics in Python 3)',
+ {'maxversion': (3, 0)}),
+ }
+
+ _bad_builtins = frozenset([
+ 'apply',
+ 'basestring',
+ 'buffer',
+ 'cmp',
+ 'coerce',
+ 'execfile',
+ 'file',
+ 'input', # Not missing, but incompatible semantics
+ 'long',
+ 'raw_input',
+ 'reduce',
+ 'round', # Not missing, but incompatible semantics
+ 'StandardError',
+ 'unicode',
+ 'xrange',
+ 'reload',
+ ])
+
+ _unused_magic_methods = frozenset([
+ '__coerce__',
+ '__delslice__',
+ '__getslice__',
+ '__setslice__',
+ '__oct__',
+ '__hex__',
+ '__nonzero__',
+ '__cmp__',
+ ])
+
+ def __init__(self, *args, **kwargs):
+ self._future_division = False
+ self._future_absolute_import = False
+ super(Python3Checker, self).__init__(*args, **kwargs)
+
+ def visit_function(self, node):
+ if node.is_method() and node.name in self._unused_magic_methods:
+ method_name = node.name
+ if node.name.startswith('__'):
+ method_name = node.name[2:-2]
+ self.add_message(method_name + '-method', node=node)
+
+ @utils.check_messages('parameter-unpacking')
+ def visit_arguments(self, node):
+ for arg in node.args:
+ 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
+ isinstance(node.value.func, astroid.Name) 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 "bad" built-in is referenced."""
+ found_node = node.lookup(node.name)[0]
+ if getattr(found_node, 'name', None) == '__builtin__':
+ if node.name in self._bad_builtins:
+ message = node.name.lower() + '-builtin'
+ self.add_message(message, node=node)
+
+ @utils.check_messages('print-statement')
+ def visit_print(self, node):
+ self.add_message('print-statement', node=node)
+
+ @utils.check_messages('no-absolute-import')
+ def visit_from(self, node):
+ if node.modname == '__future__':
+ for name, _ in node.names:
+ if name == 'division':
+ self._future_division = True
+ elif name == 'absolute_import':
+ self._future_absolute_import = True
+ elif not self._future_absolute_import:
+ self.add_message('no-absolute-import', node=node)
+
+ @utils.check_messages('no-absolute-import')
+ def visit_import(self, node):
+ if not self._future_absolute_import:
+ self.add_message('no-absolute-import', node=node)
+
+ @utils.check_messages('metaclass-assignment')
+ def visit_class(self, node):
+ if '__metaclass__' in node.locals:
+ self.add_message('metaclass-assignment', node=node)
+
+ @utils.check_messages('old-division')
+ def visit_binop(self, node):
+ if not self._future_division and node.op == '/':
+ for arg in (node.left, node.right):
+ if isinstance(arg, astroid.Const) and isinstance(arg.value, float):
+ break
+ else:
+ self.add_message('old-division', node=node)
+
+ @utils.check_messages('next-method-called',
+ 'dict-iter-method',
+ 'dict-view-method')
+ def visit_callfunc(self, node):
+ if not isinstance(node.func, astroid.Getattr):
+ return
+ if any([node.args, node.starargs, node.kwargs]):
+ return
+ if node.func.attrname == 'next':
+ self.add_message('next-method-called', node=node)
+ else:
+ if _check_dict_node(node.func.expr):
+ if node.func.attrname in ('iterkeys', 'itervalues', 'iteritems'):
+ self.add_message('dict-iter-method', node=node)
+ elif node.func.attrname in ('viewkeys', 'viewvalues', 'viewitems'):
+ self.add_message('dict-view-method', node=node)
+
+ @utils.check_messages('indexing-exception')
+ def visit_subscript(self, node):
+ """ Look for indexing exceptions. """
+ try:
+ for infered in node.value.infer():
+ if not isinstance(infered, astroid.Instance):
+ continue
+ if utils.inherit_from_std_ex(infered):
+ self.add_message('indexing-exception', node=node)
+ except astroid.InferenceError:
+ return
+
+ @utils.check_messages('unpacking-in-except')
+ def visit_excepthandler(self, node):
+ """Visit an except handler block and check for exception unpacking."""
+ if isinstance(node.name, (astroid.Tuple, astroid.List)):
+ self.add_message('unpacking-in-except', node=node)
+
+ @utils.check_messages('backtick')
+ def visit_backquote(self, node):
+ self.add_message('backtick', node=node)
+
+ @utils.check_messages('raising-string', 'old-raise-syntax')
+ def visit_raise(self, node):
+ """Visit a raise statement and check for raising
+ strings or old-raise-syntax.
+ """
+ if (node.exc is not None and
+ node.inst is not None and
+ node.tback is None):
+ self.add_message('old-raise-syntax', node=node)
+
+ # Ignore empty raise.
+ if node.exc is None:
+ return
+ expr = node.exc
+ if self._check_raise_value(node, expr):
+ return
+ else:
+ try:
+ value = next(astroid.unpack_infer(expr))
+ except astroid.InferenceError:
+ return
+ self._check_raise_value(node, value)
+
+ def _check_raise_value(self, node, expr):
+ if isinstance(expr, astroid.Const):
+ value = expr.value
+ if isinstance(value, str):
+ self.add_message('raising-string', node=node)
+ return True
+
+
+class Python3TokenChecker(checkers.BaseTokenChecker):
+ __implements__ = interfaces.ITokenChecker
+ name = 'python3'
+ enabled = False
+
+ msgs = {
+ 'E1606': ('Use of long suffix',
+ 'long-suffix',
+ 'Used when "l" or "L" is used to mark a long integer. '
+ 'This will not work in Python 3, since `int` and `long` '
+ 'types have merged.',
+ {'maxversion': (3, 0)}),
+ 'E1607': ('Use of the <> operator',
+ 'old-ne-operator',
+ 'Used when the deprecated "<>" operator is used instead '
+ 'of "!=". This is removed in Python 3.',
+ {'maxversion': (3, 0),
+ 'old_names': [('W0331', 'old-ne-operator')]}),
+ 'E1608': ('Use of old octal literal',
+ 'old-octal-literal',
+ 'Usen when encountering the old octal syntax, '
+ 'removed in Python 3. To use the new syntax, '
+ 'prepend 0o on the number.',
+ {'maxversion': (3, 0)}),
+ }
+
+ def process_tokens(self, tokens):
+ for idx, (tok_type, token, start, _, _) in enumerate(tokens):
+ if tok_type == tokenize.NUMBER:
+ if token.lower().endswith('l'):
+ # This has a different semantic than lowercase-l-suffix.
+ self.add_message('long-suffix', line=start[0])
+ elif _is_old_octal(token):
+ self.add_message('old-octal-literal', line=start[0])
+ if tokens[idx][1] == '<>':
+ self.add_message('old-ne-operator', line=tokens[idx][2][0])
+
+
+def register(linter):
+ linter.register_checker(Python3Checker(linter))
+ linter.register_checker(Python3TokenChecker(linter))
« no previous file with comments | « third_party/pylint/pylint/checkers/newstyle.py ('k') | third_party/pylint/pylint/checkers/raw_metrics.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698