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

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

Issue 739393004: Revert "Revert "pylint: upgrade to 1.3.1"" (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools/
Patch Set: Created 6 years, 1 month 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/checkers/design_analysis.py ('k') | third_party/pylint/checkers/format.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/pylint/checkers/exceptions.py
===================================================================
--- third_party/pylint/checkers/exceptions.py (revision 293047)
+++ third_party/pylint/checkers/exceptions.py (working copy)
@@ -1,4 +1,4 @@
-# Copyright (c) 2003-2007 LOGILAB S.A. (Paris, FRANCE).
+# Copyright (c) 2003-2013 LOGILAB S.A. (Paris, FRANCE).
# http://www.logilab.fr/ -- mailto:contact@logilab.fr
# 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
@@ -11,7 +11,7 @@
#
# 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.,
-# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""exceptions handling (raising, catching, exceptions classes) checker
"""
import sys
@@ -18,46 +18,100 @@
from logilab.common.compat import builtins
BUILTINS_NAME = builtins.__name__
-from logilab import astng
-from logilab.astng import YES, Instance, unpack_infer
+import astroid
+from astroid import YES, Instance, unpack_infer
from pylint.checkers import BaseChecker
-from pylint.checkers.utils import is_empty, is_raising
-from pylint.interfaces import IASTNGChecker
+from pylint.checkers.utils import is_empty, is_raising, check_messages
+from pylint.interfaces import IAstroidChecker
+def infer_bases(klass):
+ """ Fully infer the bases of the klass node.
+ This doesn't use .ancestors(), because we need
+ the non-inferable nodes (YES nodes),
+ which can't be retrieved from .ancestors()
+ """
+ for base in klass.bases:
+ try:
+ inferit = base.infer().next()
+ except astroid.InferenceError:
+ continue
+ if inferit is YES:
+ yield inferit
+ else:
+ for base in infer_bases(inferit):
+ yield base
+
+PY3K = sys.version_info >= (3, 0)
OVERGENERAL_EXCEPTIONS = ('Exception',)
MSGS = {
- 'E0701': (
- 'Bad except clauses order (%s)',
- 'Used when except clauses are not in the correct order (from the \
- more specific to the more generic). If you don\'t fix the order, \
- some exceptions may not be catched by the most specific handler.'),
+ 'E0701': ('Bad except clauses order (%s)',
+ 'bad-except-order',
+ 'Used when except clauses are not in the correct order (from the '
+ 'more specific to the more generic). If you don\'t fix the order, '
+ 'some exceptions may not be catched by the most specific handler.'),
'E0702': ('Raising %s while only classes, instances or string are allowed',
+ 'raising-bad-type',
'Used when something which is neither a class, an instance or a \
string is raised (i.e. a `TypeError` will be raised).'),
+ 'E0703': ('Exception context set to something which is not an '
+ 'exception, nor None',
+ 'bad-exception-context',
+ 'Used when using the syntax "raise ... from ...", '
+ 'where the exception context is not an exception, '
+ 'nor None.',
+ {'minversion': (3, 0)}),
'E0710': ('Raising a new style class which doesn\'t inherit from BaseException',
+ 'raising-non-exception',
'Used when a new style class which doesn\'t inherit from \
BaseException is raised.'),
'E0711': ('NotImplemented raised - should raise NotImplementedError',
+ 'notimplemented-raised',
'Used when NotImplemented is raised instead of \
NotImplementedError'),
-
+ 'E0712': ('Catching an exception which doesn\'t inherit from BaseException: %s',
+ 'catching-non-exception',
+ 'Used when a class which doesn\'t inherit from \
+ BaseException is used as an exception in an except clause.'),
+
'W0701': ('Raising a string exception',
+ 'raising-string',
'Used when a string exception is raised.'),
'W0702': ('No exception type(s) specified',
+ 'bare-except',
'Used when an except clause doesn\'t specify exceptions type to \
catch.'),
'W0703': ('Catching too general exception %s',
+ 'broad-except',
'Used when an except catches a too general exception, \
possibly burying unrelated errors.'),
'W0704': ('Except doesn\'t do anything',
+ 'pointless-except',
'Used when an except clause does nothing but "pass" and there is\
no "else" clause.'),
'W0710': ('Exception doesn\'t inherit from standard "Exception" class',
+ 'nonstandard-exception',
'Used when a custom exception class is raised but doesn\'t \
- inherit from the builtin "Exception" class.'),
+ inherit from the builtin "Exception" class.',
+ {'maxversion': (3, 0)}),
+ 'W0711': ('Exception to catch is the result of a binary "%s" operation',
+ 'binary-op-exception',
+ 'Used when the exception to catch is of the form \
+ "except A or B:". If intending to catch multiple, \
+ rewrite as "except (A, B):"'),
+ 'W0712': ('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)}),
+ 'W0713': ('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)}),
}
@@ -67,13 +121,13 @@
EXCEPTIONS_MODULE = "builtins"
class ExceptionsChecker(BaseChecker):
- """checks for
- * excepts without exception filter
+ """checks for
+ * excepts without exception filter
* type of raise argument : string, Exceptions, other values
"""
-
- __implements__ = IASTNGChecker
+ __implements__ = IAstroidChecker
+
name = 'exceptions'
msgs = MSGS
priority = -4
@@ -83,14 +137,32 @@
'help' : 'Exceptions that will emit a warning '
'when being caught. Defaults to "%s"' % (
', '.join(OVERGENERAL_EXCEPTIONS),)}
- ),
- )
+ ),
+ )
+ @check_messages('raising-string', 'nonstandard-exception', 'raising-bad-type',
+ 'raising-non-exception', 'notimplemented-raised', 'bad-exception-context')
def visit_raise(self, node):
"""visit raise possibly inferring value"""
# ignore empty raise
if node.exc is None:
return
+ if PY3K and node.cause:
+ try:
+ cause = node.cause.infer().next()
+ except astroid.InferenceError:
+ pass
+ else:
+ if cause is YES:
+ return
+ if isinstance(cause, astroid.Const):
+ if cause.value is not None:
+ self.add_message('bad-exception-context',
+ node=node)
+ elif (not isinstance(cause, astroid.Class) and
+ not inherit_from_std_ex(cause)):
+ self.add_message('bad-exception-context',
+ node=node)
expr = node.exc
if self._check_raise_value(node, expr):
return
@@ -97,7 +169,7 @@
else:
try:
value = unpack_infer(expr).next()
- except astng.InferenceError:
+ except astroid.InferenceError:
return
self._check_raise_value(node, value)
@@ -105,35 +177,35 @@
"""check for bad values, string exception and class inheritance
"""
value_found = True
- if isinstance(expr, astng.Const):
+ if isinstance(expr, astroid.Const):
value = expr.value
if isinstance(value, str):
- self.add_message('W0701', node=node)
+ self.add_message('raising-string', node=node)
else:
- self.add_message('E0702', node=node,
+ self.add_message('raising-bad-type', node=node,
args=value.__class__.__name__)
- elif (isinstance(expr, astng.Name) and \
+ elif (isinstance(expr, astroid.Name) and \
expr.name in ('None', 'True', 'False')) or \
- isinstance(expr, (astng.List, astng.Dict, astng.Tuple,
- astng.Module, astng.Function)):
- self.add_message('E0702', node=node, args=expr.name)
- elif ( (isinstance(expr, astng.Name) and expr.name == 'NotImplemented')
- or (isinstance(expr, astng.CallFunc) and
- isinstance(expr.func, astng.Name) and
- expr.func.name == 'NotImplemented') ):
- self.add_message('E0711', node=node)
- elif isinstance(expr, astng.BinOp) and expr.op == '%':
- self.add_message('W0701', node=node)
- elif isinstance(expr, (Instance, astng.Class)):
+ isinstance(expr, (astroid.List, astroid.Dict, astroid.Tuple,
+ astroid.Module, astroid.Function)):
+ self.add_message('raising-bad-type', node=node, args=expr.name)
+ elif ((isinstance(expr, astroid.Name) and expr.name == 'NotImplemented')
+ or (isinstance(expr, astroid.CallFunc) and
+ isinstance(expr.func, astroid.Name) and
+ expr.func.name == 'NotImplemented')):
+ self.add_message('notimplemented-raised', node=node)
+ elif isinstance(expr, astroid.BinOp) and expr.op == '%':
+ self.add_message('raising-string', node=node)
+ elif isinstance(expr, (Instance, astroid.Class)):
if isinstance(expr, Instance):
expr = expr._proxied
- if (isinstance(expr, astng.Class) and
+ if (isinstance(expr, astroid.Class) and
not inherit_from_std_ex(expr) and
expr.root().name != BUILTINS_NAME):
if expr.newstyle:
- self.add_message('E0710', node=node)
+ self.add_message('raising-non-exception', node=node)
else:
- self.add_message('W0710', node=node)
+ self.add_message('nonstandard-exception', node=node)
else:
value_found = False
else:
@@ -140,7 +212,27 @@
value_found = False
return value_found
+ @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)
+ @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 inherit_from_std_ex(infered):
+ self.add_message('indexing-exception', node=node)
+ except astroid.InferenceError:
+ return
+
+ @check_messages('bare-except', 'broad-except', 'pointless-except',
+ 'binary-op-exception', 'bad-except-order',
+ 'catching-non-exception')
def visit_tryexcept(self, node):
"""check for empty except"""
exceptions_classes = []
@@ -147,36 +239,53 @@
nb_handlers = len(node.handlers)
for index, handler in enumerate(node.handlers):
# single except doing nothing but "pass" without else clause
- if nb_handlers == 1 and is_empty(handler.body) and not node.orelse:
- self.add_message('W0704', node=handler.type or handler.body[0])
+ if is_empty(handler.body) and not node.orelse:
+ self.add_message('pointless-except', node=handler.type or handler.body[0])
if handler.type is None:
- if nb_handlers == 1 and not is_raising(handler.body):
- self.add_message('W0702', node=handler)
+ if not is_raising(handler.body):
+ self.add_message('bare-except', node=handler)
# check if a "except:" is followed by some other
# except
- elif index < (nb_handlers - 1):
+ if index < (nb_handlers - 1):
msg = 'empty except clause should always appear last'
- self.add_message('E0701', node=node, args=msg)
+ self.add_message('bad-except-order', node=node, args=msg)
+
+ elif isinstance(handler.type, astroid.BoolOp):
+ self.add_message('binary-op-exception', node=handler, args=handler.type.op)
else:
try:
excs = list(unpack_infer(handler.type))
- except astng.InferenceError:
+ except astroid.InferenceError:
continue
for exc in excs:
- # XXX skip other non class nodes
- if exc is YES or not isinstance(exc, astng.Class):
+ # XXX skip other non class nodes
+ if exc is YES or not isinstance(exc, astroid.Class):
continue
exc_ancestors = [anc for anc in exc.ancestors()
- if isinstance(anc, astng.Class)]
+ if isinstance(anc, astroid.Class)]
for previous_exc in exceptions_classes:
if previous_exc in exc_ancestors:
msg = '%s is an ancestor class of %s' % (
previous_exc.name, exc.name)
- self.add_message('E0701', node=handler.type, args=msg)
+ self.add_message('bad-except-order', node=handler.type, args=msg)
if (exc.name in self.config.overgeneral_exceptions
- and exc.root().name == EXCEPTIONS_MODULE
- and nb_handlers == 1 and not is_raising(handler.body)):
- self.add_message('W0703', args=exc.name, node=handler.type)
+ and exc.root().name == EXCEPTIONS_MODULE
+ and not is_raising(handler.body)):
+ self.add_message('broad-except', args=exc.name, node=handler.type)
+
+ if (not inherit_from_std_ex(exc) and
+ exc.root().name != BUILTINS_NAME):
+ # try to see if the exception is based on a C based
+ # exception, by infering all the base classes and
+ # looking for inference errors
+ bases = infer_bases(exc)
+ fully_infered = all(inferit is not YES
+ for inferit in bases)
+ if fully_infered:
+ self.add_message('catching-non-exception',
+ node=handler.type,
+ args=(exc.name, ))
+
exceptions_classes += excs
« no previous file with comments | « third_party/pylint/checkers/design_analysis.py ('k') | third_party/pylint/checkers/format.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698