Skip to content

Restore higher-scoped teardown when a flaky condition is falsy - #351

Open
teddytennant wants to merge 1 commit into
pytest-dev:masterfrom
teddytennant:fix-falsy-condition-finalizer-leak
Open

Restore higher-scoped teardown when a flaky condition is falsy#351
teddytennant wants to merge 1 commit into
pytest-dev:masterfrom
teddytennant:fix-falsy-condition-finalizer-leak

Conversation

@teddytennant

Copy link
Copy Markdown
Contributor

pytest_runtest_teardown decides whether to suspend module, class and session finalizers using a gate that checks the rerun limit, the failure statuses and terminal errors. It never checks the flaky marker's condition, which _should_not_rerun does check.

So with a falsy condition on a failing test, teardown suspends the higher-scoped finalizers, the protocol then declines to rerun, _restore_suspended_finalizers is never reached, and that fixture's teardown never runs again for the rest of the session:

@pytest.fixture(scope="module", autouse=True)
def module_fixture():
    yield
    print("module teardown")

@pytest.mark.flaky(reruns=2, condition=False)
def test_fail():
    assert False

module teardown is not printed. With condition=True, or with no marker at all, it is. The damage is not local either, since suspended_finalizers is a module-level global: run that file alongside another and the first module's fixture stays un-torn-down past the end of its own module.

Adding the missing term to the gate is the whole fix. I also updated the comment above it, which enumerated the terms and was already one short.

Tests cover class, module and session scope, a string condition that evaluates falsy, and the cross-module case. Two are guards rather than reproductions: condition=True still reruns and still tears down exactly once, and a plain --reruns failure with no marker is unaffected.

Scope, so you do not have to ask. This fixes the condition gap only. Two related leaks are pre-existing and untouched. A terminal error raised in the teardown phase still leaks, because _terminal_errors["teardown"] is written from pytest_runtest_makereport after the teardown hook has already suspended, so it needs a hookwrapper rather than another gate term. And a call-phase failure consisting solely of failed subtests tears higher-scoped fixtures down prematurely on every attempt, which is the same drift in the opposite direction. Happy to take either as a follow-up if you want them.

@teddytennant
teddytennant force-pushed the fix-falsy-condition-finalizer-leak branch from a56b20c to 72c7004 Compare August 24, 2026 16:11
The teardown hook suspended module, class and session finalizers whenever
the rerun limit and failure statuses allowed it, but it never checked the
flaky marker's condition. With a falsy condition the protocol then
declined to rerun, nothing restored the finalizers, and higher-scoped
fixture teardown was skipped for the rest of the session.
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.

1 participant