pytest-dev / pytest-dev/pytest

`--tb` affects `longrepr` construction, so plugins cannot suppress traceback display without losing traceback data

Open
#14,720 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
14.5k
Forks
3.4k
Avg merge
2d 9h
Merged PRs (30d)
35

Description

A reporting plugin that wants to render its own compact traceback has to stop pytest printing the standard one. The obvious way is --tb=no. But --tb is consulted when the representation is built, not only when it is displayed, so this also removes the data the plugin wanted to read.

Reproduced on 9.1.1 and 8.4.2.

# test_repro.py
def inner(): raise ValueError("boom")
def middle(): inner()
def test_a(): middle()
# conftest.py
def pytest_runtest_logreport(report):
    if report.failed:
        rt = getattr(report.longrepr, "reprtraceback", None)
        entries = getattr(rt, "reprentries", []) if rt else []
        located = [e for e in entries if getattr(e, "reprfileloc", None) is not None]
        print(f"entries={len(entries)} located={len(located)} "
              f"len(str(longrepr))={len(str(report.longrepr))}")
--tb=long    entries=3  located=3  len(str(longrepr))=441
--tb=short   entries=3  located=3  len(str(longrepr))=290
--tb=line    entries=3  located=0  len(str(longrepr))=20
--tb=no      entries=3  located=0  len(str(longrepr))=20

The entry count survives, but reprfileloc is None under line and no, so the file and line of every frame are gone. A plugin reading reprtraceback to build its own summary sees three anonymous entries.

The result is that a plugin must choose between pytest printing a traceback it does not want, and having no traceback data to work with.

We hit this in a reporting plugin and shipped a version that silently lost all frame information: setting --tb=no in pytest_configure looked like a clean way to suppress output, and the summaries kept rendering, just without any of the frames they were supposed to summarise. The workaround is to leave --tb alone and suppress the rendering through some other mechanism, which works, but which mechanism is available is not obvious.

This may well be intentional — not building what will not be shown is a reasonable optimisation. If so, it would be worth documenting, since the flag reads as purely presentational. If not, separating "what representation to build" from "what to display" would let plugins summarise tracebacks without either fighting the terminal reporter or losing the data.

Happy to work on a patch if there is a direction the team would prefer.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the test_repro.py and conftest.py reproduction with each --tb value, focusing on pytest_runtest_logreport and report.longrepr. Trace where reprtraceback and reprentries are built and how the terminal output is rendered. Done should preserve usable frame locations for plugins while retaining the intended traceback display behavior, or document the deliberate limitation and supported workaround.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
cli, testing
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.