Skip to content

error_later is silently dropped when a test wraps warnings.showwarning #15139

Closed as not planned

Description

@RonnyPfannschmidt

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

Follow-up to #15135, which adds the error_later warning filter action.

If a test replaces warnings.showwarning with a wrapper that forwards to the original, as numpy.testing.suppress_warnings does, a warning matching an error_later filter is shown as a plain warning and the test passes. -W error fails the same test.

import warnings

def test_it():
    orig = warnings.showwarning

    def fwd(*a, **k):
        orig(*a, **k)

    warnings.showwarning = fwd
    try:
        warnings.warn("w", UserWarning)
    finally:
        warnings.showwarning = orig
  • pytest -W error_later::UserWarning: 1 passed, 1 warning
  • pytest -W error::UserWarning: 1 failed

Real-world shape: numpy 2.4.1's suppress_warnings forwarding a UserWarning behaves the same. numpy deprecated suppress_warnings in 2.4, so the exposure is shrinking.

Cause

The stdlib decides whether an error_later filter applies: a probe object in the filter's module slot records a verdict when the filter wins. To avoid leaving a verdict behind for warnings that something else takes (pytest.warns, the test's own catch_warnings), the probe records only when the warning will be shown to pytest's recording directly. A forwarding wrapper puts itself in front of that recording, so the probe records nothing, and the warning reaches pytest without its verdict.

Possible fix (untested)

Record the verdict whenever the probe matches, keyed by module and message text. pytest's recording, or its showwarning wrapper, honours the verdict only if the text matches. A probe at the front of the filter list clears stale verdicts.

  • Cost: one string compare per recorded warning, plus one extra filter entry.
  • Residual risk: two warnings with identical text could be mismatched.

Activity

  1. fukalous commented on Oct 6, 2026

    @fukalous

    I opened RonnyPfannschmidt#142 against the feat/error-later branch from #15135. The patch preserves the verdict through forwarding warnings.showwarning wrappers, correlates it with the emitted message, and clears stale verdicts left by wrappers that discard warnings. It includes regressions for both forwarding and discarding wrappers and passes the full local pytest suite.

  2. RonnyPfannschmidt commented on Oct 6, 2026

    @RonnyPfannschmidt
    MemberAuthor

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

    Closing as outdated: error_later is not on main yet, so the fix went into #15135 itself instead of a follow-up (c6731f8). It uses a different mechanism from the one sketched here. The win probe leaves its verdict pending, and a wrapper around warnings._showwarnmsg makes it current for that one show call, so a hook that forwards the warning delivers it with its verdict, and a hook that discards it leaves nothing behind. Keying the verdict on the message text, as proposed above, was dropped because it still tags a later warning with the same text that a filter in front of error_later takes.

    The reproducer above and numpy 2.4.1's suppress_warnings now fail the test, as -W error does.

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

Metadata

Metadata

Labels

plugin: warningsrelated to the warnings builtin plugintype: bugproblem that needs to be addressed

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions