Exception chaining enables users to see if an exception was triggered by another exception (see PEP-3134). Exceptions are chained using either of the following syntax:

* raise NewException() from chained_exception

* new_exception.__cause__ = chained_exception

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

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

Noncompliant Code Example

class A:
    pass

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

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

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

See

* PEP 3134 – Exception Chaining and Embedded Tracebacks

* PEP 409 – Suppressing exception context

* PEP 352 - Required Superclass for Exceptions

* Python documentation - Built-in Exceptions