Skip to content

[unattended ai] fix(fixtures): clear stale finalizers when fixture setup fails before caching - #15026

Closed
okxint wants to merge 1 commit into
pytest-dev:mainfrom
okxint:fix/fixture-finalizers-after-failed-setup
Closed

okxint wants to merge 1 commit into
pytest-dev:mainfrom
okxint:fix/fixture-finalizers-after-failed-setup

Conversation

@okxint

@okxint okxint commented Sep 14, 2026

Copy link
Copy Markdown

Fixes #14775.

Problem

When -Werror turns a PytestRemovedIn10Warning into an error during fixture setup, FixtureDef.execute() exits without setting cached_result. The pytest_fixture_post_finalizer lambda that was just registered in self._finalizers stays there permanently — finish() is a no-op when cached_result is None (it guards with "already finished").

The next test that uses the same FixtureDef calls execute() again and hits:

assert not self._finalizers
AssertionError

This internal AssertionError masks the real error (the deprecation warning), making the second test's failure confusing.

Root cause

execute() for test_1:
  self._finalizers.append(pytest_fixture_post_finalizer)  # line 1281
  ihook.pytest_fixture_setup(...)  # RAISES — warning-as-error
  # cached_result never set; _finalizers = [<stale>]

execute() for test_2:
  assert not self._finalizers  # BOOM — stale entry from test_1

Fix

Clear self._finalizers at the top of the "fresh execution" path, before any new finalizers are registered. This is safe:

  • No previous setup ran → list is already empty, clear() is a no-op.
  • Previous setup succeededfinish() already cleared _finalizers.
  • Previous setup failed → stale entries are removed; fresh execution gets a clean slate.

Result

Both test_1 and test_2 now report PytestRemovedIn10Warning (the real error) instead of test_2 reporting an internal AssertionError.

Test

Added test_class_scoped_instance_method_werror_multiple_tests in testing/deprecated_test.py that reproduces the exact scenario from the issue and asserts no AssertionError appears.

… caching

When `pytest_fixture_setup` raises (e.g. because `-Werror` turns a
`PytestRemovedIn10Warning` into an error), `FixtureDef.execute()` exits
without setting `cached_result`.  This leaves whatever was already
appended to `self._finalizers` (the `pytest_fixture_post_finalizer`
lambda registered just before the call) sitting there permanently,
because `finish()` is a no-op when `cached_result is None`.

The next test that uses the same `FixtureDef` then calls `execute()`
again and hits:

    assert not self._finalizers

with an internal `AssertionError`, masking the real deprecation error.

Fix: clear `self._finalizers` at the start of the "fresh execution" path
in `execute()`, before registering new finalizers.  This is safe because:
- If no previous setup ran, the list is already empty.
- If a previous setup succeeded, `finish()` already cleared it.
- If a previous setup failed (our case), the stale entries are removed so
  the next execution gets a clean slate.

Fixes pytest-dev#14775
@RonnyPfannschmidt RonnyPfannschmidt changed the title fix(fixtures): clear stale finalizers when fixture setup fails before caching [unattended ai] fix(fixtures): clear stale finalizers when fixture setup fails before caching Sep 15, 2026
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.

Internal AssertionError after class scoped fixture warning

2 participants