Index: third_party/pylint/checkers/exceptions.py |
diff --git a/third_party/pylint/checkers/exceptions.py b/third_party/pylint/checkers/exceptions.py |
index 94186eba72f14c31a38013f27a4ae2d7c241006d..08f4334c382480ca98688bc951a2642aee3f1b01 100644 |
--- a/third_party/pylint/checkers/exceptions.py |
+++ b/third_party/pylint/checkers/exceptions.py |
@@ -1,4 +1,4 @@ |
-# Copyright (c) 2003-2013 LOGILAB S.A. (Paris, FRANCE). |
+# Copyright (c) 2003-2007 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,107 +11,53 @@ |
# |
# 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. |
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
"""exceptions handling (raising, catching, exceptions classes) checker |
""" |
import sys |
from logilab.common.compat import builtins |
BUILTINS_NAME = builtins.__name__ |
-import astroid |
-from astroid import YES, Instance, unpack_infer |
+from logilab import astng |
+from logilab.astng import YES, Instance, unpack_infer |
from pylint.checkers import BaseChecker |
-from pylint.checkers.utils import is_empty, is_raising, check_messages |
-from pylint.interfaces import IAstroidChecker |
+from pylint.checkers.utils import is_empty, is_raising |
+from pylint.interfaces import IASTNGChecker |
-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)', |
- '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.'), |
+ '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.'), |
'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.', |
- {'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)}), |
+ inherit from the builtin "Exception" class.'), |
} |
@@ -121,12 +67,12 @@ else: |
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__ = IAstroidChecker |
+ |
+ __implements__ = IASTNGChecker |
name = 'exceptions' |
msgs = MSGS |
@@ -137,39 +83,21 @@ class ExceptionsChecker(BaseChecker): |
'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 |
else: |
try: |
value = unpack_infer(expr).next() |
- except astroid.InferenceError: |
+ except astng.InferenceError: |
return |
self._check_raise_value(node, value) |
@@ -177,115 +105,78 @@ class ExceptionsChecker(BaseChecker): |
"""check for bad values, string exception and class inheritance |
""" |
value_found = True |
- if isinstance(expr, astroid.Const): |
+ if isinstance(expr, astng.Const): |
value = expr.value |
if isinstance(value, str): |
- self.add_message('raising-string', node=node) |
+ self.add_message('W0701', node=node) |
else: |
- self.add_message('raising-bad-type', node=node, |
+ self.add_message('E0702', node=node, |
args=value.__class__.__name__) |
- elif (isinstance(expr, astroid.Name) and \ |
+ elif (isinstance(expr, astng.Name) and \ |
expr.name in ('None', 'True', 'False')) or \ |
- 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)): |
+ 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)): |
if isinstance(expr, Instance): |
expr = expr._proxied |
- if (isinstance(expr, astroid.Class) and |
+ if (isinstance(expr, astng.Class) and |
not inherit_from_std_ex(expr) and |
expr.root().name != BUILTINS_NAME): |
if expr.newstyle: |
- self.add_message('raising-non-exception', node=node) |
+ self.add_message('E0710', node=node) |
else: |
- self.add_message('nonstandard-exception', node=node) |
+ self.add_message('W0710', node=node) |
else: |
value_found = False |
else: |
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 = [] |
nb_handlers = len(node.handlers) |
for index, handler in enumerate(node.handlers): |
# single except doing nothing but "pass" without else clause |
- if is_empty(handler.body) and not node.orelse: |
- self.add_message('pointless-except', node=handler.type or handler.body[0]) |
+ 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 handler.type is None: |
- if not is_raising(handler.body): |
- self.add_message('bare-except', node=handler) |
+ if nb_handlers == 1 and not is_raising(handler.body): |
+ self.add_message('W0702', node=handler) |
# check if a "except:" is followed by some other |
# except |
- if index < (nb_handlers - 1): |
+ elif index < (nb_handlers - 1): |
msg = 'empty except clause should always appear last' |
- 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) |
+ self.add_message('E0701', node=node, args=msg) |
else: |
try: |
excs = list(unpack_infer(handler.type)) |
- except astroid.InferenceError: |
+ except astng.InferenceError: |
continue |
for exc in excs: |
- # XXX skip other non class nodes |
- if exc is YES or not isinstance(exc, astroid.Class): |
+ # XXX skip other non class nodes |
+ if exc is YES or not isinstance(exc, astng.Class): |
continue |
exc_ancestors = [anc for anc in exc.ancestors() |
- if isinstance(anc, astroid.Class)] |
+ if isinstance(anc, astng.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('bad-except-order', node=handler.type, args=msg) |
+ self.add_message('E0701', node=handler.type, args=msg) |
if (exc.name in self.config.overgeneral_exceptions |
- 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, )) |
- |
+ 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) |
exceptions_classes += excs |