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.

Why is this an issue?

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.

What is the potential impact?

addfinalizer-based teardown is harder to follow than a linear yield fixture, which slows reviews and increases the chance of mismatched setup and cleanup.

How to fix it

Replace request.addfinalizer teardown with a yield fixture: yield the resource, then run cleanup after the test.

Code examples

Noncompliant code example

import pytest

@pytest.fixture
def with_finalizer(request):
    resource = open_resource()
    request.addfinalizer(resource.close)  # Noncompliant
    return resource

Compliant solution

import pytest

@pytest.fixture
def with_finalizer():
    resource = open_resource()
    yield resource
    resource.close()

Resources

Documentation

Related rules