Description
- Include a detailed description of the bug or suggestion
PEP-415 states that exception.__context__
should be suppressed in traceback outputs, if exception.__suppress_context__
is True
.
If a raise exception from None
is caught by pytest, pytest should not chain the context in the test report.
The current algorithm in _pytest._code.code.FormattedExcinfo
is:
if e.__cause__ is not None:
# Code to chain the cause.
elif e.__context__ is not None:
# Code to chain the context.
which means that pytest always chains the exception, assuming that e.__context__
hasn't been set to None
.
By comparison, the algorithm in traceback.TracebackException
is:
if e.__cause__ is not None:
# Code to chain the cause.
elif (e.__context__ is not None and not e.__suppress_context__):
# Code to chain the context.
Exception.__suppress_context__
is available in all of the versions of Python 3 that are supported by pytest, so it is trivial to add support for this feature.
- Minimal example if possible
Here's a test that has a raise exception from None
in it:
def test_raise_from_none():
try:
raise ValueError()
except Exception:
raise AttributeError() from None
This is the test output (with the chained exception traceback) that results when running against the pytest feature branch (commit 768edde):
_____________________________________________________ test_raise_from_none _____________________________________________________
def test_raise_from_none():
try:
> raise ValueError()
E ValueError
testing/code/test_excinfo.py:1257: ValueError
During handling of the above exception, another exception occurred:
def test_raise_from_none():
try:
raise ValueError()
except Exception:
> raise AttributeError() from None
E AttributeError
testing/code/test_excinfo.py:1259: AttributeError
But running the same code in a terminal produces this shorter, non-chained traceback:
AttributeError Traceback (most recent call last)
<ipython-input-51-e2e3809c49fb> in <module>()
----> 1 test_raise_from_none()
<ipython-input-50-d651befdf00e> in test_raise_from_none()
3 raise ValueError()
4 except Exception:
----> 5 raise AttributeError() from None
6
AttributeError:
And this is what the pytest output should look like:
_____________________________________________________ test_raise_from_none _____________________________________________________
def test_raise_from_none():
try:
raise ValueError()
except Exception:
> raise AttributeError() from None
E AttributeError
testing/code/test_excinfo.py:1259: AttributeError