This rule raise an issue if something other than None or a valid exception is provided as the cause of an exception chain.

Why is this an issue?

Exception chaining enables users to see if an exception is the direct consequence of another exception (see PEP-3134). This is useful to propagate the original context of the error.

Exceptions are chained using either of the following syntax:

try:
    ...
except OSError as e:
    raise RuntimeError("Something went wrong") from e
try:
    ...
except OSError as e:
    new_exception = RuntimeError("Something went wrong")
    new_exception.__cause__ = e
    raise new_exception

It is also possible to erase a chaining by setting new_exception.__cause__ = None or using raise new_exception from None (see PEP-409).

Chaining will fail and raise a TypeError if something other than None or a valid exception, i.e. an instance or a subclass of BaseException, is provided.

How to fix it

Make sure the cause of a chain of exceptions is either None or a valid exception.

Code examples

Noncompliant code example

class A:
    pass

try:
    raise ValueError("orig")
except ValueError as e:
    new_exc = TypeError("new")
    new_exc.__cause__ = A()  # Noncompliant: A is not a subclass of BaseException.
    raise new_exc

try:
    raise ValueError("orig")
except ValueError as e:
    raise TypeError("new") from "test"  # Noncompliant: "test" is not a valid exception.

Compliant solution

try:
    raise ValueError("orig")
except ValueError as e:
    new_exc = TypeError("new")
    new_exc.__cause__ = None  # Ok
    raise new_exc

try:
    raise ValueError("orig")
except ValueError as e:
    new_exc = TypeError("new")
    new_exc.__cause__ = e  # Ok
    raise new_exc

try:
    raise ValueError("orig")
except ValueError as e:
    raise TypeError("new") from None  # Ok

try:
    raise ValueError("orig")
except ValueError as e:
    raise TypeError("new") from e  # Ok

Resources

Documentation

Standards