Exemplo n.º 1
0
    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, ))
Exemplo n.º 2
0
    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.ClassDef):
            # 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.name not in self.builtin_exceptions:
            if has_known_bases(exc):
                self.add_message("catching-non-exception", node=handler.type, args=(exc.name,))
Exemplo n.º 3
0
 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.FunctionDef))):
         emit = True
         if not PY3K and isinstance(expr, astroid.Tuple) and expr.elts:
             # 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, astroid.Instance):
                 # pylint: disable=protected-access
                 inferred = inferred._proxied
             if (inferred is astroid.YES or
                     isinstance(inferred, astroid.ClassDef)
                     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.Call) and
               isinstance(expr.func, astroid.Name) and
               expr.func.name == 'NotImplemented')):
         self.add_message('notimplemented-raised', node=node)
     elif isinstance(expr, (astroid.Instance, astroid.ClassDef)):
         if isinstance(expr, astroid.Instance):
             # pylint: disable=protected-access
             expr = expr._proxied
         if (isinstance(expr, astroid.ClassDef) and
                 not inherit_from_std_ex(expr) and
                 has_known_bases(expr)):
             if expr.newstyle:
                 self.add_message('raising-non-exception', node=node)
             else:
                 self.add_message('nonstandard-exception', node=node)
         else:
             value_found = False
     else:
         value_found = False
     return value_found
Exemplo n.º 4
0
 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.FunctionDef))):
         emit = True
         if not PY3K and isinstance(expr, astroid.Tuple) and expr.elts:
             # 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, astroid.Instance):
                 # pylint: disable=protected-access
                 inferred = inferred._proxied
             if (inferred is astroid.YES
                     or isinstance(inferred, astroid.ClassDef)
                     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.Call)
                 and isinstance(expr.func, astroid.Name)
                 and expr.func.name == 'NotImplemented')):
         self.add_message('notimplemented-raised', node=node)
     elif isinstance(expr, (astroid.Instance, astroid.ClassDef)):
         if isinstance(expr, astroid.Instance):
             # pylint: disable=protected-access
             expr = expr._proxied
         if (isinstance(expr, astroid.ClassDef)
                 and not inherit_from_std_ex(expr)
                 and has_known_bases(expr)):
             if expr.newstyle:
                 self.add_message('raising-non-exception', node=node)
             else:
                 self.add_message('nonstandard-exception', node=node)
         else:
             value_found = False
     else:
         value_found = False
     return value_found
Exemplo n.º 5
0
 def visit_classdef(self, node: nodes.ClassDef) -> None:
     # TODO (Typing): This function can be called from visit_instance
     #  with the return type of instance._proxied (not typed right now)
     if not utils.inherit_from_std_ex(node) and utils.has_known_bases(node):
         if node.newstyle:
             self._checker.add_message("raising-non-exception",
                                       node=self._node)
Exemplo n.º 6
0
 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)
         else:
             self._checker.add_message('nonstandard-exception', node=self._node)
Exemplo n.º 7
0
 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)
         else:
             self._checker.add_message('nonstandard-exception', node=self._node)
Exemplo n.º 8
0
    def visit_tryexcept(self, node):
        """check for empty except"""
        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 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 astroid.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.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 == 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]
Exemplo n.º 9
0
 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 = next(node.cause.infer())
         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 = next(unpack_infer(expr))
         except astroid.InferenceError:
             return
         self._check_raise_value(node, value)
Exemplo n.º 10
0
    def _check_catching_non_exception(self, handler, exc, part):
        if isinstance(exc, nodes.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, nodes.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, nodes.Const) and exc.value is None:
                if (
                    isinstance(handler.type, nodes.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,)
                )
Exemplo n.º 11
0
    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 utils.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 utils.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]
Exemplo n.º 12
0
 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
Exemplo n.º 13
0
 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
Exemplo n.º 14
0
def possible_exc_types(node: nodes.NodeNG) -> set[nodes.ClassDef]:
    """Gets all the possible raised exception types for the given raise node.

    .. note::

        Caught exception types are ignored.

    :param node: The raise node to find exception types for.

    :returns: A list of exception types possibly raised by :param:`node`.
    """
    exceptions = []
    if isinstance(node.exc, nodes.Name):
        inferred = utils.safe_infer(node.exc)
        if inferred:
            exceptions = [inferred]
    elif node.exc is None:
        handler = node.parent
        while handler and not isinstance(handler, nodes.ExceptHandler):
            handler = handler.parent

        if handler and handler.type:
            try:
                for exception in astroid.unpack_infer(handler.type):
                    if exception is not astroid.Uninferable:
                        exceptions.append(exception)
            except astroid.InferenceError:
                pass
    else:
        target = _get_raise_target(node)
        if isinstance(target, nodes.ClassDef):
            exceptions = [target]
        elif isinstance(target, nodes.FunctionDef):
            for ret in target.nodes_of_class(nodes.Return):
                if ret.value is None:
                    continue
                if ret.frame(future=True) != target:
                    # return from inner function - ignore it
                    continue

                val = utils.safe_infer(ret.value)
                if val and utils.inherit_from_std_ex(val):
                    if isinstance(val, nodes.ClassDef):
                        exceptions.append(val)
                    elif isinstance(val, astroid.Instance):
                        exceptions.append(val.getattr("__class__")[0])

    try:
        return {
            exc
            for exc in exceptions
            if not utils.node_ignores_exception(node, exc.name)
        }
    except astroid.InferenceError:
        return set()
Exemplo n.º 15
0
def test_inherit_from_std_ex_recursive_definition():
    node = astroid.extract_node("""
      import datetime
      class First(datetime.datetime):
        pass
      class Second(datetime.datetime): #@
        pass
      datetime.datetime = First
      datetime.datetime = Second
      """)
    assert not utils.inherit_from_std_ex(node)
Exemplo n.º 16
0
 def visit_attribute(self, node):
     """ Look for accessing message on exceptions. """
     try:
         for infered in node.expr.infer():
             if not isinstance(infered, astroid.Instance):
                 continue
             if utils.inherit_from_std_ex(infered):
                 if node.attrname == 'message':
                     self.add_message('exception-message-attribute',
                                      node=node)
     except astroid.InferenceError:
         return
Exemplo n.º 17
0
def possible_exc_types(node):
    """
    Gets all of the possible raised exception types for the given raise node.

    .. note::

        Caught exception types are ignored.


    :param node: The raise node to find exception types for.
    :type node: astroid.node_classes.NodeNG

    :returns: A list of exception types possibly raised by :param:`node`.
    :rtype: set(str)
    """
    excs = []
    if isinstance(node.exc, astroid.Name):
        inferred = utils.safe_infer(node.exc)
        if inferred:
            excs = [inferred.name]
    elif (isinstance(node.exc, astroid.Call)
          and isinstance(node.exc.func, astroid.Name)):
        target = utils.safe_infer(node.exc.func)
        if isinstance(target, astroid.ClassDef):
            excs = [target.name]
        elif isinstance(target, astroid.FunctionDef):
            for ret in target.nodes_of_class(astroid.Return):
                if ret.frame() != target:
                    # return from inner function - ignore it
                    continue

                val = utils.safe_infer(ret.value)
                if (val and isinstance(val,
                                       (astroid.Instance, astroid.ClassDef))
                        and utils.inherit_from_std_ex(val)):
                    excs.append(val.name)
    elif node.exc is None:
        handler = node.parent
        while handler and not isinstance(handler, astroid.ExceptHandler):
            handler = handler.parent

        if handler and handler.type:
            inferred_excs = astroid.unpack_infer(handler.type)
            excs = (exc.name for exc in inferred_excs
                    if exc is not astroid.Uninferable)

    try:
        return {
            exc
            for exc in excs if not utils.node_ignores_exception(node, exc)
        }
    except astroid.InferenceError:
        return set()
Exemplo n.º 18
0
 def visit_attribute(self, node):
     """ Look for accessing message on exceptions. """
     try:
         for inferred in node.expr.infer():
             if (isinstance(inferred, astroid.Instance) and
                     utils.inherit_from_std_ex(inferred)):
                 if node.attrname == 'message':
                     self.add_message('exception-message-attribute', node=node)
             if isinstance(inferred, astroid.Module):
                 self._warn_if_deprecated(node, inferred.name, {node.attrname})
     except astroid.InferenceError:
         return
Exemplo n.º 19
0
    def visit_tryexcept(self, node: nodes.TryExcept) -> None:
        """check for empty except"""
        for handler in node.handlers:
            if handler.type is None:
                continue
            if isinstance(handler.type, astroid.BoolOp):
                continue
            try:
                excs = list(_annotated_unpack_infer(handler.type))
            except astroid.InferenceError:
                continue

            handled_in_clause: List[Tuple[Any, Any]] = []
            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

                if not isinstance(exc, astroid.ClassDef):
                    continue

                exc_ancestors = [
                    anc for anc in exc.ancestors()
                    if isinstance(anc, astroid.ClassDef)
                ]

                for prev_part, prev_exc in handled_in_clause:
                    prev_exc_ancestors = [
                        anc for anc in prev_exc.ancestors()
                        if isinstance(anc, astroid.ClassDef)
                    ]
                    if exc == prev_exc:
                        self.add_message(
                            "overlapping-except",
                            node=handler.type,
                            args=
                            f"{prev_part.as_string()} and {part.as_string()} are the same",
                        )
                    elif prev_exc in exc_ancestors or exc in prev_exc_ancestors:
                        ancestor = part if exc in prev_exc_ancestors else prev_part
                        descendant = part if prev_exc in exc_ancestors else prev_part
                        self.add_message(
                            "overlapping-except",
                            node=handler.type,
                            args=
                            f"{ancestor.as_string()} is an ancestor class of {descendant.as_string()}",
                        )
                handled_in_clause += [(part, exc)]
Exemplo n.º 20
0
    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 (astroid.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.ClassDef) and not inherit_from_std_ex(cause):
            self.add_message("bad-exception-context", node=node)
    def visit_tryexcept(self, node):
        """check for empty except"""
        for handler in node.handlers:
            if handler.type is None:
                continue
            if isinstance(handler.type, astroid.BoolOp):
                continue
            try:
                excs = list(_annotated_unpack_infer(handler.type))
            except astroid.InferenceError:
                continue

            handled_in_clause = []
            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

                if not isinstance(exc, astroid.ClassDef):
                    continue

                exc_ancestors = [
                    anc for anc in exc.ancestors() if isinstance(anc, astroid.ClassDef)
                ]

                for prev_part, prev_exc in handled_in_clause:
                    prev_exc_ancestors = [
                        anc
                        for anc in prev_exc.ancestors()
                        if isinstance(anc, astroid.ClassDef)
                    ]
                    if exc == prev_exc:
                        self.add_message(
                            "overlapping-except",
                            node=handler.type,
                            args="%s and %s are the same"
                            % (prev_part.as_string(), part.as_string()),
                        )
                    elif prev_exc in exc_ancestors or exc in prev_exc_ancestors:
                        ancestor = part if exc in prev_exc_ancestors else prev_part
                        descendant = part if prev_exc in exc_ancestors else prev_part
                        self.add_message(
                            "overlapping-except",
                            node=handler.type,
                            args="%s is an ancestor class of %s"
                            % (ancestor.as_string(), descendant.as_string()),
                        )
                handled_in_clause += [(part, exc)]
Exemplo n.º 22
0
def possible_exc_types(node):
    """
    Gets all of the possible raised exception types for the given raise node.

    .. note::

        Caught exception types are ignored.


    :param node: The raise node to find exception types for.
    :type node: astroid.node_classes.NodeNG

    :returns: A list of exception types possibly raised by :param:`node`.
    :rtype: list(str)
    """
    excs = []
    if isinstance(node.exc, astroid.Name):
        inferred = safe_infer(node.exc)
        if inferred:
            excs = [inferred.name]
    elif (isinstance(node.exc, astroid.Call) and
          isinstance(node.exc.func, astroid.Name)):
        target = safe_infer(node.exc.func)
        if isinstance(target, astroid.ClassDef):
            excs = [target.name]
        elif isinstance(target, astroid.FunctionDef):
            for ret in target.nodes_of_class(astroid.Return):
                if ret.frame() != target:
                    # return from inner function - ignore it
                    continue

                val = safe_infer(ret.value)
                if (val and isinstance(val, (astroid.Instance, astroid.ClassDef))
                        and inherit_from_std_ex(val)):
                    excs.append(val.name)
    elif node.exc is None:
        handler = node.parent
        while handler and not isinstance(handler, astroid.ExceptHandler):
            handler = handler.parent

        if handler and handler.type:
            inferred_excs = astroid.unpack_infer(handler.type)
            excs = (exc.name for exc in inferred_excs
                    if exc is not astroid.Uninferable)


    try:
        return set(exc for exc in excs if not node_ignores_exception(node, exc))
    except astroid.InferenceError:
        return ()
Exemplo n.º 23
0
 def visit_attribute(self, node):
     """ Look for accessing message on exceptions. """
     try:
         for inferred in node.expr.infer():
             if (isinstance(inferred, astroid.Instance)
                     and utils.inherit_from_std_ex(inferred)):
                 if node.attrname == 'message':
                     self.add_message('exception-message-attribute',
                                      node=node)
             if isinstance(inferred, astroid.Module):
                 self._warn_if_deprecated(node, inferred.name,
                                          {node.attrname})
     except astroid.InferenceError:
         return
Exemplo n.º 24
0
    def visit_tryexcept(self, node):
        """check for empty except"""
        for handler in node.handlers:
            if handler.type is None:
                continue
            if isinstance(handler.type, astroid.BoolOp):
                continue
            try:
                excs = list(_annotated_unpack_infer(handler.type))
            except astroid.InferenceError:
                continue

            handled_in_clause = []
            for part, exc in excs:
                if exc is astroid.YES:
                    continue
                if (isinstance(exc, astroid.Instance)
                        and utils.inherit_from_std_ex(exc)):
                    # pylint: disable=protected-access
                    exc = exc._proxied

                if not isinstance(exc, astroid.ClassDef):
                    continue

                exc_ancestors = [
                    anc for anc in exc.ancestors()
                    if isinstance(anc, astroid.ClassDef)
                ]

                for prev_part, prev_exc in handled_in_clause:
                    prev_exc_ancestors = [
                        anc for anc in prev_exc.ancestors()
                        if isinstance(anc, astroid.ClassDef)
                    ]
                    if exc == prev_exc:
                        self.add_message(
                            'overlapping-except',
                            node=handler.type,
                            args='%s and %s are the same' %
                            (prev_part.as_string(), part.as_string()))
                    elif (prev_exc in exc_ancestors
                          or exc in prev_exc_ancestors):
                        ancestor = part if exc in prev_exc_ancestors else prev_part
                        descendant = part if prev_exc in exc_ancestors else prev_part
                        self.add_message(
                            'overlapping-except',
                            node=handler.type,
                            args='%s is an ancestor class of %s' %
                            (ancestor.as_string(), descendant.as_string()))
                handled_in_clause += [(part, exc)]
Exemplo n.º 25
0
    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)
Exemplo n.º 26
0
    def _check_bad_exception_context(self, node: astroid.Raise) -> None:
        """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)
Exemplo n.º 27
0
    def visit_attribute(self, node):
        """Look for accessing message on exceptions. """
        message = 'message'
        try:
            for inferred in node.expr.infer():
                if (isinstance(inferred, astroid.Instance) and
                        utils.inherit_from_std_ex(inferred)):
                    if node.attrname == message:

                        # Exceptions with .message clearly defined are an exception
                        if message in inferred.instance_attrs:
                            continue
                        self.add_message('exception-message-attribute', node=node)
                if isinstance(inferred, astroid.Module):
                    self._warn_if_deprecated(node, inferred.name, {node.attrname},
                                             report_on_modules=False)
        except astroid.InferenceError:
            return
Exemplo n.º 28
0
    def visit_attribute(self, node):
        """Look for accessing message on exceptions. """
        message = 'message'
        try:
            for inferred in node.expr.infer():
                if (isinstance(inferred, astroid.Instance) and
                        utils.inherit_from_std_ex(inferred)):
                    if node.attrname == message:

                        # Exceptions with .message clearly defined are an exception
                        if message in inferred.instance_attrs:
                            continue
                        self.add_message('exception-message-attribute', node=node)
                if isinstance(inferred, astroid.Module):
                    self._warn_if_deprecated(node, inferred.name, {node.attrname},
                                             report_on_modules=False)
        except astroid.InferenceError:
            return
Exemplo n.º 29
0
 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 isinstance(value, str):
             self.add_message('raising-string', node=node)
         else:
             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)):
         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, astroid.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)
             else:
                 self.add_message(
                     'nonstandard-exception',
                     node=node,
                     confidence=INFERENCE
                     if has_known_bases(expr) else INFERENCE_FAILURE)
         else:
             value_found = False
     else:
         value_found = False
     return value_found
Exemplo n.º 30
0
 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 isinstance(value, str):
             # raising-string will be emitted from python3 porting checker.
             pass
         else:
             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)):
         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):
             expr = expr._proxied
         if (isinstance(expr, astroid.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)
             else:
                 self.add_message(
                     'nonstandard-exception', node=node,
                     confidence=INFERENCE if has_known_bases(expr) else INFERENCE_FAILURE)
         else:
             value_found = False
     else:
         value_found = False
     return value_found
Exemplo n.º 31
0
 def visit_classdef(self, node: nodes.ClassDef) -> None:
     if not utils.inherit_from_std_ex(node) and utils.has_known_bases(node):
         if node.newstyle:
             self._checker.add_message("raising-non-exception", node=self._node)
Exemplo n.º 32
0
 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)
Exemplo n.º 33
0
    def visit_tryexcept(self, node):
        """check for empty except"""
        exceptions_classes = []
        nb_handlers = len(node.handlers)
        for index, handler in enumerate(node.handlers):
            # `raise` as the first operator inside the except handler
            if utils.is_raising([handler.body[0]]):
                # flags when there is a bare raise
                if handler.body[0].exc is None:
                    self.add_message('try-except-raise', node=handler)
                else:
                    # not a bare raise
                    raise_type = None
                    if isinstance(handler.body[0].exc, astroid.Call):
                        raise_type = handler.body[0].exc.func

                    # flags only when the exception types of the handler
                    # and the raise statement match b/c we're raising the same
                    # type of exception that we're trying to handle. Example:
                    #
                    # except ValueError:
                    #   raise ValueError('some user friendly message')
                    if (isinstance(handler.type, astroid.Name)
                            and isinstance(raise_type, astroid.Name)
                            and raise_type.name == handler.type.name):
                        self.add_message('try-except-raise', node=handler)

            if handler.type is None:
                if not utils.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 utils.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]
Exemplo n.º 34
0
    def visit_tryexcept(self, node: nodes.TryExcept) -> None:
        """Check for empty except."""
        self._check_try_except_raise(node)
        exceptions_classes: list[Any] = []
        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, nodes.BoolOp):
                self.add_message("binary-op-exception",
                                 node=handler,
                                 args=handler.type.op)
            else:
                try:
                    exceptions = list(_annotated_unpack_infer(handler.type))
                except astroid.InferenceError:
                    continue

                for part, exception in exceptions:
                    if exception is astroid.Uninferable:
                        continue
                    if isinstance(exception, astroid.Instance
                                  ) and utils.inherit_from_std_ex(exception):
                        exception = exception._proxied

                    self._check_catching_non_exception(handler, exception,
                                                       part)

                    if not isinstance(exception, nodes.ClassDef):
                        continue

                    exc_ancestors = [
                        anc for anc in exception.ancestors()
                        if isinstance(anc, nodes.ClassDef)
                    ]

                    for previous_exc in exceptions_classes:
                        if previous_exc in exc_ancestors:
                            msg = f"{previous_exc.name} is an ancestor class of {exception.name}"
                            self.add_message("bad-except-order",
                                             node=handler.type,
                                             args=msg)
                    if (exception.name
                            in self.linter.config.overgeneral_exceptions and
                            exception.root().name == utils.EXCEPTIONS_MODULE
                            and not _is_raising(handler.body)):
                        self.add_message("broad-except",
                                         args=exception.name,
                                         node=handler.type)

                    if exception in exceptions_classes:
                        self.add_message("duplicate-except",
                                         args=exception.name,
                                         node=handler.type)

                exceptions_classes += [exc for _, exc in exceptions]
Exemplo n.º 35
0
    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):
                        exc = exc._proxied
                    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(), ))
                        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)

                    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, ))

                exceptions_classes += [exc for _, exc in excs]
Exemplo n.º 36
0
    def visit_tryexcept(self, node):
        """check for empty except"""
        exceptions_classes = []
        nb_handlers = len(node.handlers)
        for index, handler in enumerate(node.handlers):
            # `raise` as the first operator inside the except handler
            if utils.is_raising([handler.body[0]]):
                # flags when there is a bare raise
                if handler.body[0].exc is None:
                    self.add_message('try-except-raise', node=handler)
                else:
                    # not a bare raise
                    raise_type = None
                    if isinstance(handler.body[0].exc, astroid.Call):
                        raise_type = handler.body[0].exc.func

                    # flags only when the exception types of the handler
                    # and the raise statement match b/c we're raising the same
                    # type of exception that we're trying to handle. Example:
                    #
                    # except ValueError:
                    #   raise ValueError('some user friendly message')
                    if (isinstance(handler.type, astroid.Name)
                            and isinstance(raise_type, astroid.Name)
                            and raise_type.name == handler.type.name):
                        self.add_message('try-except-raise', node=handler)

            if handler.type is None:
                if not utils.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.YES:
                        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 utils.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]