Skip to content

Support PEP-415's Exception.__suppress_context__ #2631

Closed
@jmoldow

Description

@jmoldow
  • 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions