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

Unified Diff: third_party/pylint/pylint/checkers/exceptions.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/design_analysis.py ('k') | third_party/pylint/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/pylint/checkers/exceptions.py
diff --git a/third_party/pylint/pylint/checkers/exceptions.py b/third_party/pylint/pylint/checkers/exceptions.py
new file mode 100644
index 0000000000000000000000000000000000000000..88a8f225e2e80304f8959fbcbe1a39a0aed02267
--- /dev/null
+++ b/third_party/pylint/pylint/checkers/exceptions.py
@@ -0,0 +1,332 @@
+# 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
+# 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.
+"""exceptions handling (raising, catching, exceptions classes) checker
+"""
+import sys
+
+import astroid
+from astroid import YES, Instance, unpack_infer, List, Tuple
+from logilab.common.compat import builtins
+
+from pylint.checkers import BaseChecker
+from pylint.checkers.utils import (
+ is_empty,
+ is_raising,
+ check_messages,
+ inherit_from_std_ex,
+ EXCEPTIONS_MODULE,
+ has_known_bases,
+ safe_infer)
+from pylint.interfaces import IAstroidChecker, INFERENCE, INFERENCE_FAILURE
+
+
+def _annotated_unpack_infer(stmt, context=None):
+ """
+ Recursively generate nodes inferred by the given statement.
+ If the inferred value is a list or a tuple, recurse on the elements.
+ Returns an iterator which yields tuples in the format
+ ('original node', 'infered node').
+ """
+ if isinstance(stmt, (List, Tuple)):
+ for elt in stmt.elts:
+ inferred = safe_infer(elt)
+ if inferred and inferred is not YES:
+ yield elt, inferred
+ return
+ for infered in stmt.infer(context):
+ if infered is YES:
+ continue
+ yield stmt, infered
+
+
+PY3K = sys.version_info >= (3, 0)
+OVERGENERAL_EXCEPTIONS = ('Exception',)
+BUILTINS_NAME = builtins.__name__
+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.'),
+ 'E0702': ('Raising %s while only classes or instances 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.'),
+ '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):"'),
+ }
+
+
+class ExceptionsChecker(BaseChecker):
+ """checks for
+ * excepts without exception filter
+ * type of raise argument : string, Exceptions, other values
+ """
+
+ __implements__ = IAstroidChecker
+
+ name = 'exceptions'
+ msgs = MSGS
+ priority = -4
+ options = (('overgeneral-exceptions',
+ {'default' : OVERGENERAL_EXCEPTIONS,
+ 'type' :'csv', 'metavar' : '<comma-separated class names>',
+ 'help' : 'Exceptions that will emit a warning '
+ 'when being caught. Defaults to "%s"' % (
+ ', '.join(OVERGENERAL_EXCEPTIONS),)}
+ ),
+ )
+
+ @check_messages('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:
+ self._check_bad_exception_context(node)
+
+ expr = node.exc
+ if self._check_raise_value(node, expr):
+ return
+ else:
+ try:
+ value = next(unpack_infer(expr))
+ except astroid.InferenceError:
+ return
+ self._check_raise_value(node, value)
+
+ def _check_bad_exception_context(self, node):
+ """Verify that the exception context is properly set.
+
+ An exception context can be only `None` or an exception.
+ """
+ cause = safe_infer(node.cause)
+ if cause in (YES, None):
+ 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)
+
+ def _check_raise_value(self, node, expr):
+ """check for bad values, string exception and class inheritance
+ """
+ value_found = True
+ if isinstance(expr, astroid.Const):
+ value = expr.value
+ if not isinstance(value, str):
+ # raising-string will be emitted from python3 porting checker.
+ self.add_message('raising-bad-type', node=node,
+ args=value.__class__.__name__)
+ elif ((isinstance(expr, astroid.Name) and
+ expr.name in ('None', 'True', 'False')) or
+ isinstance(expr, (astroid.List, astroid.Dict, astroid.Tuple,
+ astroid.Module, astroid.Function))):
+ emit = True
+ if not PY3K and isinstance(expr, astroid.Tuple):
+ # On Python 2, using the following is not an error:
+ # raise (ZeroDivisionError, None)
+ # raise (ZeroDivisionError, )
+ # What's left to do is to check that the first
+ # argument is indeed an exception.
+ # Verifying the other arguments is not
+ # the scope of this check.
+ first = expr.elts[0]
+ inferred = safe_infer(first)
+ if isinstance(inferred, Instance):
+ # pylint: disable=protected-access
+ inferred = inferred._proxied
+ if (inferred is YES or
+ isinstance(inferred, astroid.Class)
+ and inherit_from_std_ex(inferred)):
+ emit = False
+ if emit:
+ 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, (Instance, astroid.Class)):
+ if isinstance(expr, Instance):
+ # pylint: disable=protected-access
+ expr = expr._proxied
+ if (isinstance(expr, astroid.Class) and
+ not inherit_from_std_ex(expr)):
+ if expr.newstyle:
+ self.add_message('raising-non-exception', node=node)
+ else:
+ if has_known_bases(expr):
+ confidence = INFERENCE
+ else:
+ confidence = INFERENCE_FAILURE
+ self.add_message(
+ 'nonstandard-exception', node=node,
+ confidence=confidence)
+ else:
+ value_found = False
+ else:
+ value_found = False
+ return value_found
+
+ def _check_catching_non_exception(self, handler, exc, part):
+ if isinstance(exc, astroid.Tuple):
+ # Check if it is a tuple of exceptions.
+ inferred = [safe_infer(elt) for elt in exc.elts]
+ if any(node is astroid.YES for node in inferred):
+ # Don't emit if we don't know every component.
+ return
+ if all(node and inherit_from_std_ex(node)
+ for node in inferred):
+ return
+
+ if not isinstance(exc, astroid.Class):
+ # Don't emit the warning if the infered stmt
+ # is None, but the exception handler is something else,
+ # maybe it was redefined.
+ if (isinstance(exc, astroid.Const) and
+ exc.value is None):
+ if ((isinstance(handler.type, astroid.Const) and
+ handler.type.value is None) or
+ handler.type.parent_of(exc)):
+ # If the exception handler catches None or
+ # the exception component, which is None, is
+ # defined by the entire exception handler, then
+ # emit a warning.
+ self.add_message('catching-non-exception',
+ node=handler.type,
+ args=(part.as_string(), ))
+ else:
+ self.add_message('catching-non-exception',
+ node=handler.type,
+ args=(part.as_string(), ))
+ return
+ if (not inherit_from_std_ex(exc) and
+ exc.root().name != BUILTINS_NAME):
+ if has_known_bases(exc):
+ self.add_message('catching-non-exception',
+ node=handler.type,
+ args=(exc.name, ))
+
+ @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 handler.type is None:
+ if not is_raising(handler.body):
+ self.add_message('bare-except', node=handler)
+ # check if a "except:" is followed by some other
+ # except
+ if 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)
+ else:
+ try:
+ excs = list(_annotated_unpack_infer(handler.type))
+ except astroid.InferenceError:
+ continue
+ for part, exc in excs:
+ if exc is YES:
+ continue
+ if (isinstance(exc, astroid.Instance)
+ and inherit_from_std_ex(exc)):
+ # pylint: disable=protected-access
+ exc = exc._proxied
+
+ self._check_catching_non_exception(handler, exc, part)
+
+ if not isinstance(exc, astroid.Class):
+ continue
+
+ exc_ancestors = [anc for anc in exc.ancestors()
+ 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('bad-except-order',
+ 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)
+
+ exceptions_classes += [exc for _, exc in excs]
+
+
+def register(linter):
+ """required method to auto register this checker"""
+ linter.register_checker(ExceptionsChecker(linter))
« no previous file with comments | « third_party/pylint/pylint/checkers/design_analysis.py ('k') | third_party/pylint/pylint/checkers/format.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698