This rule raises an issue when a @pytest.fixture uses request.addfinalizer(…) for teardown instead of a yield
fixture.
In Python, this refers to fixtures that call request.addfinalizer(…) and return a resource instead of yielding it and running
teardown after the yield.
Pytest fixtures can clean up either with a sequential yield (setup before yield, teardown after) or with callback-based
request.addfinalizer(…). The sequential style is clearer for ordinary fixtures: setup, provide the value, then tear down in one linear
flow.
Registering teardown with request.addfinalizer while returning the resource scatters setup and cleanup:
@pytest.fixture
def with_finalizer(request):
resource = open_resource()
request.addfinalizer(resource.close)
return resource
Prefer yielding the resource and running cleanup after the test:
@pytest.fixture
def with_finalizer():
resource = open_resource()
yield resource
resource.close()
request.addfinalizer remains appropriate for the factory-as-fixture pattern, where teardown must be registered inside a nested factory
that creates resources on demand.
addfinalizer-based teardown is harder to follow than a linear yield fixture, which slows reviews and increases the chance of
mismatched setup and cleanup.
Replace request.addfinalizer teardown with a yield fixture: yield the resource, then run cleanup after the test.
import pytest
@pytest.fixture
def with_finalizer(request):
resource = open_resource()
request.addfinalizer(resource.close) # Noncompliant
return resource
import pytest
@pytest.fixture
def with_finalizer():
resource = open_resource()
yield resource
resource.close()