This rule raise an issue if something other than None or a valid exception is provided as the cause of an exception chain.
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:
from keyword
try:
...
except OSError as e:
raise RuntimeError("Something went wrong") from e
__cause__ property
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.
Make sure the cause of a chain of exceptions is either None or a valid exception.
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.
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