summaryrefslogtreecommitdiff
path: root/venv/Lib/site-packages/pylint/checkers/exceptions.py
diff options
context:
space:
mode:
Diffstat (limited to 'venv/Lib/site-packages/pylint/checkers/exceptions.py')
-rw-r--r--venv/Lib/site-packages/pylint/checkers/exceptions.py546
1 files changed, 0 insertions, 546 deletions
diff --git a/venv/Lib/site-packages/pylint/checkers/exceptions.py b/venv/Lib/site-packages/pylint/checkers/exceptions.py
deleted file mode 100644
index 360e1d1..0000000
--- a/venv/Lib/site-packages/pylint/checkers/exceptions.py
+++ /dev/null
@@ -1,546 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2006-2011, 2013-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
-# Copyright (c) 2011-2014 Google, Inc.
-# Copyright (c) 2012 Tim Hatch <tim@timhatch.com>
-# Copyright (c) 2013-2018 Claudiu Popa <pcmanticore@gmail.com>
-# Copyright (c) 2014 Brett Cannon <brett@python.org>
-# Copyright (c) 2014 Arun Persaud <arun@nubati.net>
-# Copyright (c) 2015 Rene Zhang <rz99@cornell.edu>
-# Copyright (c) 2015 Florian Bruhin <me@the-compiler.org>
-# Copyright (c) 2015 Steven Myint <hg@stevenmyint.com>
-# Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
-# Copyright (c) 2016 Erik <erik.eriksson@yahoo.com>
-# Copyright (c) 2016 Jakub Wilk <jwilk@jwilk.net>
-# Copyright (c) 2017 Łukasz Rogalski <rogalski.91@gmail.com>
-# Copyright (c) 2017 Martin von Gagern <gagern@google.com>
-# Copyright (c) 2018 Mike Frysinger <vapier@gmail.com>
-# Copyright (c) 2018 ssolanki <sushobhitsolanki@gmail.com>
-# Copyright (c) 2018 Alexander Todorov <atodorov@otb.bg>
-# Copyright (c) 2018 Ville Skyttä <ville.skytta@upcloud.com>
-
-# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
-
-"""Checks for various exception related errors."""
-import builtins
-import inspect
-import typing
-
-import astroid
-from astroid.node_classes import NodeNG
-
-from pylint import checkers, interfaces
-from pylint.checkers import utils
-
-
-def _builtin_exceptions():
- def predicate(obj):
- return isinstance(obj, type) and issubclass(obj, BaseException)
-
- members = inspect.getmembers(builtins, predicate)
- return {exc.__name__ for (_, exc) in members}
-
-
-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', 'inferred node').
- """
- if isinstance(stmt, (astroid.List, astroid.Tuple)):
- for elt in stmt.elts:
- inferred = utils.safe_infer(elt)
- if inferred and inferred is not astroid.Uninferable:
- yield elt, inferred
- return
- for inferred in stmt.infer(context):
- if inferred is astroid.Uninferable:
- continue
- yield stmt, inferred
-
-
-def _is_raising(body: typing.List) -> bool:
- """Return true if the given statement node raise an exception"""
- for node in body:
- if isinstance(node, astroid.Raise):
- return True
- return False
-
-
-OVERGENERAL_EXCEPTIONS = ("BaseException", "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 caught 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.",
- ),
- "E0704": (
- "The raise statement is not inside an except clause",
- "misplaced-bare-raise",
- "Used when a bare raise is not used inside an except clause. "
- "This generates an error, since there are no active exceptions "
- "to be reraised. An exception to this rule is represented by "
- "a bare raise inside a finally clause, which might work, as long "
- "as an exception is raised inside the try block, but it is "
- "nevertheless a code smell that must not be relied upon.",
- ),
- "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 Exception: %s",
- "catching-non-exception",
- "Used when a class which doesn't inherit from "
- "Exception 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.",
- ),
- "W0705": (
- "Catching previously caught exception type %s",
- "duplicate-except",
- "Used when an except catches a type that was already caught by "
- "a previous handler.",
- ),
- "W0706": (
- "The except handler raises immediately",
- "try-except-raise",
- "Used when an except handler uses raise as its first or only "
- "operator. This is useless because it raises back the exception "
- "immediately. Remove the raise operator or the entire "
- "try-except-raise block!",
- ),
- "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):"',
- ),
- "W0715": (
- "Exception arguments suggest string formatting might be intended",
- "raising-format-tuple",
- "Used when passing multiple arguments to an exception "
- "constructor, the first of them a string literal containing what "
- "appears to be placeholders intended for formatting",
- ),
- "W0716": (
- "Invalid exception operation. %s",
- "wrong-exception-operation",
- "Used when an operation is done against an exception, but the operation "
- "is not valid for the exception in question. Usually emitted when having "
- "binary operations between exceptions in except handlers.",
- ),
-}
-
-
-class BaseVisitor:
- """Base class for visitors defined in this module."""
-
- def __init__(self, checker, node):
- self._checker = checker
- self._node = node
-
- def visit(self, node):
- name = node.__class__.__name__.lower()
- dispatch_meth = getattr(self, "visit_" + name, None)
- if dispatch_meth:
- dispatch_meth(node)
- else:
- self.visit_default(node)
-
- def visit_default(self, node): # pylint: disable=unused-argument
- """Default implementation for all the nodes."""
-
-
-class ExceptionRaiseRefVisitor(BaseVisitor):
- """Visit references (anything that is not an AST leaf)."""
-
- def visit_name(self, name):
- if name.name == "NotImplemented":
- self._checker.add_message("notimplemented-raised", node=self._node)
-
- def visit_call(self, call):
- if isinstance(call.func, astroid.Name):
- self.visit_name(call.func)
- if (
- len(call.args) > 1
- and isinstance(call.args[0], astroid.Const)
- and isinstance(call.args[0].value, str)
- ):
- msg = call.args[0].value
- if "%" in msg or ("{" in msg and "}" in msg):
- self._checker.add_message("raising-format-tuple", node=self._node)
-
-
-class ExceptionRaiseLeafVisitor(BaseVisitor):
- """Visitor for handling leaf kinds of a raise value."""
-
- def visit_const(self, const):
- if not isinstance(const.value, str):
- # raising-string will be emitted from python3 porting checker.
- self._checker.add_message(
- "raising-bad-type", node=self._node, args=const.value.__class__.__name__
- )
-
- def visit_instance(self, instance):
- # pylint: disable=protected-access
- cls = instance._proxied
- self.visit_classdef(cls)
-
- # Exception instances have a particular class type
- visit_exceptioninstance = visit_instance
-
- def visit_classdef(self, cls):
- if not utils.inherit_from_std_ex(cls) and utils.has_known_bases(cls):
- if cls.newstyle:
- self._checker.add_message("raising-non-exception", node=self._node)
-
- def visit_tuple(self, _):
- self._checker.add_message("raising-bad-type", node=self._node, args="tuple")
-
- def visit_default(self, node):
- name = getattr(node, "name", node.__class__.__name__)
- self._checker.add_message("raising-bad-type", node=self._node, args=name)
-
-
-class ExceptionsChecker(checkers.BaseChecker):
- """Exception related checks."""
-
- __implements__ = interfaces.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),),
- },
- ),
- )
-
- def open(self):
- self._builtin_exceptions = _builtin_exceptions()
- super(ExceptionsChecker, self).open()
-
- @utils.check_messages(
- "misplaced-bare-raise",
- "raising-bad-type",
- "raising-non-exception",
- "notimplemented-raised",
- "bad-exception-context",
- "raising-format-tuple",
- )
- def visit_raise(self, node):
- if node.exc is None:
- self._check_misplaced_bare_raise(node)
- return
-
- if node.cause:
- self._check_bad_exception_context(node)
-
- expr = node.exc
- ExceptionRaiseRefVisitor(self, node).visit(expr)
-
- try:
- inferred_value = expr.inferred()[-1]
- except astroid.InferenceError:
- pass
- else:
- if inferred_value:
- ExceptionRaiseLeafVisitor(self, node).visit(inferred_value)
-
- def _check_misplaced_bare_raise(self, node):
- # Filter out if it's present in __exit__.
- scope = node.scope()
- if (
- isinstance(scope, astroid.FunctionDef)
- and scope.is_method()
- and scope.name == "__exit__"
- ):
- return
-
- current = node
- # Stop when a new scope is generated or when the raise
- # statement is found inside a TryFinally.
- ignores = (astroid.ExceptHandler, astroid.FunctionDef)
- while current and not isinstance(current.parent, ignores):
- current = current.parent
-
- expected = (astroid.ExceptHandler,)
- if not current or not isinstance(current.parent, expected):
- self.add_message("misplaced-bare-raise", node=node)
-
- 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 = utils.safe_infer(node.cause)
- if cause in (astroid.Uninferable, 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.ClassDef) and not utils.inherit_from_std_ex(
- cause
- ):
- self.add_message("bad-exception-context", node=node)
-
- def _check_catching_non_exception(self, handler, exc, part):
- if isinstance(exc, astroid.Tuple):
- # Check if it is a tuple of exceptions.
- inferred = [utils.safe_infer(elt) for elt in exc.elts]
- if any(node is astroid.Uninferable for node in inferred):
- # Don't emit if we don't know every component.
- return
- if all(
- node
- and (utils.inherit_from_std_ex(node) or not utils.has_known_bases(node))
- for node in inferred
- ):
- return
-
- if not isinstance(exc, astroid.ClassDef):
- # Don't emit the warning if the inferred 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 utils.inherit_from_std_ex(exc)
- and exc.name not in self._builtin_exceptions
- ):
- if utils.has_known_bases(exc):
- self.add_message(
- "catching-non-exception", node=handler.type, args=(exc.name,)
- )
-
- def _check_try_except_raise(self, node):
- def gather_exceptions_from_handler(
- handler
- ) -> typing.Optional[typing.List[NodeNG]]:
- exceptions = [] # type: typing.List[NodeNG]
- if handler.type:
- exceptions_in_handler = utils.safe_infer(handler.type)
- if isinstance(exceptions_in_handler, astroid.Tuple):
- exceptions = list(
- {
- exception
- for exception in exceptions_in_handler.elts
- if isinstance(exception, astroid.Name)
- }
- )
- elif exceptions_in_handler:
- exceptions = [exceptions_in_handler]
- else:
- # Break when we cannot infer anything reliably.
- return None
- return exceptions
-
- bare_raise = False
- handler_having_bare_raise = None
- excs_in_bare_handler = []
- for handler in node.handlers:
- if bare_raise:
- # check that subsequent handler is not parent of handler which had bare raise.
- # since utils.safe_infer can fail for bare except, check it before.
- # also break early if bare except is followed by bare except.
-
- excs_in_current_handler = gather_exceptions_from_handler(handler)
-
- if not excs_in_current_handler:
- bare_raise = False
- break
- if excs_in_bare_handler is None:
- # It can be `None` when the inference failed
- break
-
- for exc_in_current_handler in excs_in_current_handler:
- inferred_current = utils.safe_infer(exc_in_current_handler)
- if any(
- utils.is_subclass_of(
- utils.safe_infer(exc_in_bare_handler), inferred_current
- )
- for exc_in_bare_handler in excs_in_bare_handler
- ):
- bare_raise = False
- break
-
- # `raise` as the first operator inside the except handler
- if _is_raising([handler.body[0]]):
- # flags when there is a bare raise
- if handler.body[0].exc is None:
- bare_raise = True
- handler_having_bare_raise = handler
- excs_in_bare_handler = gather_exceptions_from_handler(handler)
- else:
- if bare_raise:
- self.add_message("try-except-raise", node=handler_having_bare_raise)
-
- @utils.check_messages("wrong-exception-operation")
- def visit_binop(self, node):
- if isinstance(node.parent, astroid.ExceptHandler):
- # except (V | A)
- suggestion = "Did you mean '(%s, %s)' instead?" % (
- node.left.as_string(),
- node.right.as_string(),
- )
- self.add_message("wrong-exception-operation", node=node, args=(suggestion,))
-
- @utils.check_messages("wrong-exception-operation")
- def visit_compare(self, node):
- if isinstance(node.parent, astroid.ExceptHandler):
- # except (V < A)
- suggestion = "Did you mean '(%s, %s)' instead?" % (
- node.left.as_string(),
- ", ".join(operand.as_string() for _, operand in node.ops),
- )
- self.add_message("wrong-exception-operation", node=node, args=(suggestion,))
-
- @utils.check_messages(
- "bare-except",
- "broad-except",
- "try-except-raise",
- "binary-op-exception",
- "bad-except-order",
- "catching-non-exception",
- "duplicate-except",
- )
- def visit_tryexcept(self, node):
- """check for empty except"""
- self._check_try_except_raise(node)
- exceptions_classes = []
- nb_handlers = len(node.handlers)
- for index, handler in enumerate(node.handlers):
- if handler.type is None:
- if not _is_raising(handler.body):
- self.add_message("bare-except", node=handler)
-
- # check if an "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 astroid.Uninferable:
- continue
- if isinstance(exc, astroid.Instance) and utils.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.ClassDef):
- continue
-
- exc_ancestors = [
- anc
- for anc in exc.ancestors()
- if isinstance(anc, astroid.ClassDef)
- ]
-
- 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 == utils.EXCEPTIONS_MODULE
- and not _is_raising(handler.body)
- ):
- self.add_message(
- "broad-except", args=exc.name, node=handler.type
- )
-
- if exc in exceptions_classes:
- self.add_message(
- "duplicate-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))