funcarg_compare.rst

Overview

This file is a detailed explanatory document focused on the evolution of pytest's *funcarg* mechanism into the modern *fixture* system introduced in pytest version 2.3. It serves as a historical and technical guide for pytest users and plugin authors who are familiar with older pytest versions and want to understand the reasons and benefits behind the fixture redesign.

The document contrasts the limitations of the old `pytest_funcarg__` factory style with the new `@pytest.fixture` decorator approach, elaborates on scoping and parametrization improvements, and discusses how these changes address common testing challenges. It also covers autouse fixtures and fixture discovery enhancements introduced in pytest-2.3, along with compatibility notes to assist migration from older pytest versions.

This file is primarily educational and is intended to be read within the pytest documentation to provide context and rationale for the fixture system design decisions.


Detailed Explanation

Historical Context and Purpose

Prior to pytest-2.3, pytest used a *funcarg* mechanism to provide test function arguments (resources needed during testing). This was done using special factory functions named with a prefix `pytest_funcarg__`. These factories created resources on demand but had limitations in scoping, parametrization, and reusability.

The file explains these shortcomings and demonstrates how pytest-2.3 introduced *fixtures* with the `@pytest.fixture` decorator to replace funcargs, simplifying resource management and enabling powerful features such as scoped resource lifetimes, direct parametrization, and autouse fixtures.


Key Sections and Concepts

1. Shortcomings of the previous pytest_funcarg__ mechanism

Example of old style funcarg:
# content of conftest.py
class Database:
    def __init__(self):
        print("database instance created")

    def destroy(self):
        print("database instance destroyed")

def pytest_funcarg__db(request):
    return request.cached_setup(
        setup=Database, teardown=lambda db: db.destroy, scope="session"
    )

2. Direct scoping of fixture/funcarg factories

The new `@pytest.fixture` decorator allows declaring the scope of a fixture directly, making caching and setup/teardown automatic and transparent.

Example of scoped fixture:
@pytest.fixture(scope="session")
def db(request):
    db = Database()
    request.addfinalizer(db.destroy)  # teardown at session end
    return db

3. Direct parametrization of funcarg resource factories

Fixtures can be parametrized using the `params` argument in the decorator. Each parameter value results in a separate fixture instance and test invocation.

Example of parametrized fixture:
@pytest.fixture(params=["mysql", "pg"])
def db(request):
    if request.param == "mysql":
        db = MySQL()
    elif request.param == "pg":
        db = PG()
    request.addfinalizer(db.destroy)
    return db

4. No pytest_funcarg__ prefix when using @fixture decorator


5. Solving per-session setup / autouse fixtures


6. Fixture discovery at collection time


7. Conclusion and compatibility notes


Usage Examples

@pytest.fixture(scope="session")
def db(request):
    db = Database()
    request.addfinalizer(db.destroy)
    return db

def test_query(db):
    assert db.query("SELECT 1") == 1
@pytest.fixture(params=["sqlite", "postgres"])
def db(request):
    if request.param == "sqlite":
        db = SQLiteDB()
    else:
        db = PostgresDB()
    request.addfinalizer(db.close)
    return db

def test_db_connection(db):
    assert db.is_connected()

Implementation Details


Interactions with Other System Components


Mermaid Diagram

flowchart TD
    A[Old funcarg mechanism] -->|Uses| B[pytest_funcarg__NAME factories]
    B -->|Manual caching| C[request.cached_setup()]
    C -->|Complex scoping and teardown| D[Limitations]

    E[pytest-2.3 Fixture system]
    E -->|@pytest.fixture decorator| F[Fixture function]
    F -->|Defines scope and params| G[Automatic resource caching]
    G -->|Uses| H[request.addfinalizer()]
    F -->|Can be parametrized| I[request.param]
    I -->|Generates multiple test runs| J[Parametrized test invocations]
    E -->|Supports| K[autouse fixtures]
    K -->|Automatic setup/teardown| L[Improved global resource management]

    D -->|Addressed by| E

Summary

This documentation file is an in-depth, historical, and technical explanation of the transition from pytest’s older funcarg system to the modern fixture system introduced in pytest-2.3. It explains key concepts such as scoping, parametrization, autouse fixtures, and fixture discovery, illustrating how these innovations resolve earlier limitations and improve test resource management. The file is intended for pytest users with some experience who want to understand the rationale behind fixture design and migrate legacy code accordingly.


**End of funcarg_compare.rst documentation**