Skip to content

Derive ExceptionInfo strip text lazily from the exception - #15149

Open
RonnyPfannschmidt wants to merge 3 commits into
mainfrom
claude/project-thread-o2uoxy
Open

RonnyPfannschmidt wants to merge 3 commits into
mainfrom
claude/project-thread-o2uoxy

Conversation

@RonnyPfannschmidt

Copy link
Copy Markdown
Member

Requested by Ronny · project thread

🤖 Written by Claude Opus 5.5 via Claude Code for the pytest maintainers; I prompted it, it did the work, I read it.

Fixes #12175.

Before: exconly(tryshort=True) kept the AssertionError: prefix for a failing assert when the ExceptionInfo came from pytest.raises/RaisesGroup (for_later() + fill_unfilled()), or from unittest's addSubTest (direct construction). A failing assert inside TestCase.subTest therefore reported E AssertionError: assert 1 == 2 and SUBFAILED ... - AssertionError: assert 1 == 2, unlike a regular test.

After: every ExceptionInfo strips the prefix for rewritten asserts, so pytest.raises and unittest subtests match regular test output.

How

The strip text depends only on the exception value, so it is now derived on first use in exconly() (_get_striptext()) instead of being computed in from_exc_info(). _striptext=None means "derive"; an explicit exprinfo keeps its historical effect of disabling stripping. The exconly() docstring now says what the code actually does: only failing assert statements are shortened, an explicit AssertionError("message") keeps its type name.

Why this differs from #14206, #15089 and #15148

Those three PRs (all closed) extracted a _compute_striptext() helper and called it again from fill_unfilled(). That keeps the eager design, where every constructor has to remember to set the strip text:

  • It misses the direct ExceptionInfo(exc_info, _ispytest=True) construction in unittest.addSubTest, so the subtest crash line stays wrong. This PR covers that path and tests it in testing/test_subtests.py.
  • Any future construction path would hit the same bug again. Deriving lazily removes the state that can go missing.
  • None of them addressed the issue's own reproducer, raise AssertionError("message"). That case keeps its prefix on every path, including from_exception(), by design: pytest's failure output relies on only rewritten asserts being shortened. The real defect there is the docstring, which promised stripping for any AssertionError. This PR fixes the docstring rather than changing reporting behavior.

Checklist

  • Include new tests or update existing tests when applicable (both new tests fail on main).
  • Allow maintainers to push and squash when merging my commits.
  • Fixes #12175 in the description and commit.
  • If AI agents were used, they are credited in Co-authored-by commit trailers.
  • Changelog fragment changelog/12175.bugfix.rst.
  • AUTHORS: already listed.

Full suite passed locally on Python 3.13 (4637 passed), plus pre-commit on the changed files, including mypy.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RPVUqQy85BXtPFPctRc71n


Generated by Claude Code

ExceptionInfo only computed its "AssertionError: " strip text in
from_exc_info(). Instances created via for_later()/fill_unfilled()
(pytest.raises, RaisesGroup) or constructed directly (unittest
addSubTest) never got it, so exconly(tryshort=True) kept the prefix
for rewritten asserts.

The strip text is a pure function of the exception, so derive it on
first use instead of at construction. An explicit exprinfo keeps its
historical meaning of disabling stripping.

Also correct the exconly() docstring: only failing assert statements
are shortened, an explicit AssertionError("msg") keeps its type name.

Fixes #12175

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RPVUqQy85BXtPFPctRc71n
@RonnyPfannschmidt RonnyPfannschmidt self-assigned this Oct 7, 2026
@psf-chronographer psf-chronographer Bot added the bot:chronographer:provided (automation) changelog entry is part of PR label Oct 7, 2026
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RPVUqQy85BXtPFPctRc71n

RonnyPfannschmidt commented Oct 7, 2026 •

Copy link
Copy Markdown
Member Author

🤖 Written by Claude Opus 5.5 via Claude Code for the pytest maintainers; I prompted it, it did the work, I read it.

build (windows-py311) fails in testing/test_terminal.py::TestTerminal::test_console_output_style_times_slow_teardown_does_not_leak: assert 0.2548 < 0.1 on the first run and assert 0.1947 < 0.1 on the re-run. No other job fails.

Why I don't think this PR causes it: the diff only changes how ExceptionInfo.exconly(tryshort=True) strips the AssertionError: prefix, and nothing in that test raises. The test was added yesterday in #14670. It asserts that test_a2 takes under 100 ms. A leak of test_a1's 300 ms teardown would show up as at least 0.3 s, but the measured values are 0.19 to 0.25 s, so test_a2 itself was slow on the runner. A sequential local run on Linux shows test_a2 at about 0.3 ms.

What I can't explain yet is why it fails twice here while other PRs pass this job today. Possible fix, outside this PR's scope: assert dur_seconds < 0.3, which still catches the leak without depending on Windows runner speed.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot:chronographer:provided (automation) changelog entry is part of PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ExceptionInfo.for_later() wont add assertion strip text

2 participants