Fixture markers

testsuite.fixture_markers lets plugins and tests attach typed metadata to fixture functions and later collect the fixtures that carry a given type and are visible to the current pytest request.

The helpers are framework-agnostic: they only depend on pytest fixture definitions. userver uses them for service dependencies and static config patches; other stacks can reuse the same marks for Postgres initializers, mock setup, and similar discovery.

Marking a fixture

Apply the mark to the original function, under @pytest.fixture:

import dataclasses

import pytest

from testsuite import fixture_markers


@dataclasses.dataclass(frozen=True)
class PgInitializer:
    order: int


def pg_init(*, order: int = 0):
    def decorator(function):
        return fixture_markers.mark(
            function,
            PgInitializer(order=order),
        )

    return decorator


@pytest.fixture
@pg_init()
def init_users(pgsql):
    pgsql['mydb'].execute('INSERT INTO users ...')


@pytest.fixture(name='init_orders')
@pg_init(order=1)
def _init_orders(pgsql):
    pgsql['mydb'].execute('INSERT INTO orders ...')

Querying marks

get_infos(request, info_type) returns a dict of fixture name to info for fixtures that:

  • are visible to request (plugin, ancestor conftest, this module, this class);

  • have a mark of info_type;

  • have a scope at least as wide as request.scope.

initializers = fixture_markers.get_infos(request, PgInitializer)
for name, _info in sorted(
    initializers.items(),
    key=lambda item: item[1].order,
):
    request.getfixturevalue(name)

Overriding a marked fixture

An override inherits the mark. get_infos looks at the definition pytest would call. When that definition has no mark of the requested type, the mark comes from the nearest overridden definition that has one. A mark on the override replaces the inherited value. An override cannot drop the mark.

# conftest.py

@pytest.fixture
@pg_init(order=1)
def init_users(pgsql):
    pgsql['mydb'].execute('INSERT INTO users ...')
# test_users.py

@pytest.fixture
def init_users(init_users, pgsql):
    init_users
    pgsql['mydb'].execute('INSERT INTO guests ...')

initializers = fixture_markers.get_infos(request, PgInitializer)
# {'init_users': PgInitializer(order=1)}

Utilities for attaching typed marks to pytest fixture functions and querying those marks during a test session.

Use mark() to store an info object on the original function. Use get_infos() to retrieve fixtures tagged with a particular info type among those visible to a request.

Marks are independent of @pytest.fixture: apply the mark to the original function, then wrap with @pytest.fixture.

testsuite.fixture_markers.get_infos(request: FixtureRequest, info_type: type[I], /) → dict[str, I][source]

Return marked fixtures of info_type that are visible to a request.

Walks fixture definitions known to pytest, keeps those applicable to the requesting test, and skips fixtures whose scope is narrower than request.scope.

The winning fixture definition is the one pytest would call. If it has no mark of info_type, the mark is inherited from the nearest overridden definition that has one. A mark on the winner replaces the inherited mark. There is no way to drop an inherited mark.

See Fixture markers for usage examples.

Parameters:
  • request – The pytest fixture request object.

  • info_type – The info class whose tagged fixtures you want to look up.

Returns:

dict[str, I] mapping each tagged fixture’s name to the info object that was passed to mark(). The dict is a fresh copy; mutating it has no effect on stored data.

testsuite.fixture_markers.mark(func: Callable[[...], object], info: object, /) → Callable[[...], object][source]

Attach info to the original function func.

Creates the marks dict if it is missing, otherwise updates it. The info type is the lookup key for get_infos(). Each type may be attached at most once.

func must be the original function, not a @pytest.fixture wrapper. Apply the mark under @pytest.fixture.

See Fixture markers for usage examples.

Parameters:
  • func – The original fixture function.

  • info – Metadata instance to store.

Returns:

func, unchanged.