Skip to content

Add rerun_if() to request a rerun from inside a test - #382

Open
LouisDeconinck wants to merge 2 commits into
pytest-dev:masterfrom
LouisDeconinck:issue-58-rerun-if
Open

LouisDeconinck wants to merge 2 commits into
pytest-dev:masterfrom
LouisDeconinck:issue-58-rerun-if

Conversation

@LouisDeconinck

@LouisDeconinck LouisDeconinck commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Adds rerun_if(condition, reason=None) and the RerunRequest exception: inside a test, rerun_if(...) aborts the current attempt and retries while the test still has reruns (@pytest.mark.flaky(reruns=N) or --reruns)
  • Covers the hypothesis.assume()-style use case from the issue; combining with only_rerun=[RerunRequest] restricts reruns to exactly the requested condition rather than any failure
  • Without a rerun budget the request is a normal test failure

Closes #58

Test plan

  • rerun_if inside a flaky test reruns and passes
  • only_rerun=[RerunRequest] does not rerun other failures
  • No rerun budget → normal failure

LouisDeconinck and others added 2 commits September 17, 2026 21:47
Expose a RerunRequest exception and a rerun_if(condition, reason) helper
that discards the current attempt and retries while the test still has
reruns left. Combined with only_rerun=[RerunRequest], tests can restrict
reruns to exactly the known-bad generated-data case instead of any
failure.

Closes pytest-dev#58.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>

@icemac icemac left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

— Comment created by Claude

Automated review: 6 inline findings.

)


class RerunRequest(Exception):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

— Comment created by Claude

RerunRequest subclasses Exception, so any except Exception: (or pytest.raises(Exception)) between rerun_if() and the test function swallows it. If a test helper or fixture wraps the call like that, no rerun is requested and the test keeps running with the bad data it was trying to reject. pytest's own skip/fail outcomes subclass BaseException for this reason. Consider deriving from BaseException; only_rerun=[RerunRequest] still matches because of the isinstance check.

this condition and not on other failures.
"""
if condition:
raise RerunRequest(reason or "rerun requested from test")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

— Comment created by Claude

rerun_if() only raises a normal exception, so a request can still be turned into a hard failure:

  • a global or ini filter like --only-rerun ConnectionError (or only_rerun = ... in ini) does not match RerunRequest: ..., so the test fails without being rerun;
  • a broad --rerun-except regex can block it too;
  • so can a marker condition= that evaluates to false.

This contradicts "request a rerun". A more general fix: have _should_hard_fail_on_error treat RerunRequest as always rerunnable when the test has reruns left. Users would then not need to add only_rerun=[RerunRequest] themselves.

Comment thread README.rst


To request a re-run from *inside* a test -- for example when generated data
happens to hit a known-bad case, similar to ``hypothesis.assume()`` -- use

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

— Comment created by Claude

The hypothesis.assume() comparison is misleading. Inside a @given test, Hypothesis treats RerunRequest as a failure: it shrinks the input, saves the failing example to its database and replays it first on the next attempt. Each rerun then hits the same input again, so the reruns cannot succeed and only add shrinking time. Please mention this, or drop the analogy.


@pytest.mark.flaky(reruns=2, only_rerun=[RerunRequest])
def test_fail():
rerun_if(False)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

— Comment created by Claude

This test never raises RerunRequest (rerun_if(False)), so it would also pass if RerunRequest never matched only_rerun. The main README example (only_rerun=[RerunRequest] plus rerun_if(True) on the first attempt, which should then rerun) has no test. Neither does the global --reruns path that the docs describe.

failure. Combine with ``only_rerun=[RerunRequest]`` to rerun *only* on
this condition and not on other failures.
"""
if condition:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

— Comment created by Claude

Minor: reason or "rerun requested from test" replaces any falsy reason, so an explicit reason="" cannot be passed through. "rerun requested from test" if reason is None else reason matches the None default exactly.

"""Raised by :func:`rerun_if` to discard an attempt and request a rerun."""


def rerun_if(condition, reason=None):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

— Comment created by Claude

Cleanup: the new class and function sit between RERUNS_DELAY_BACKOFF_FACTOR_DESC and ONLY_RERUN_DESC, splitting the block of option description constants. Moving them below the constants or near the other public helpers keeps that block together.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature request: rerun test if condition is not met (similar to hypothesis.assume())

2 participants