pytest-dev/pytest · error · TypeError

Error evaluating while defining fixture ' '. Expected a…

Error message

Error evaluating {scope_callable} while defining fixture '{fixture_name}'.
Expected a function with the signature (*, fixture_name, config)

What it means

_eval_scope_callable (fixtures.py:1098) invokes a dynamic scope function passed via @pytest.fixture(scope=callable). If calling it raises ANY Exception, pytest wraps that as TypeError with guidance that the callable must accept keyword-only 'fixture_name' and 'config'. This is strictly a signature/implementation problem in the user-supplied scope function.

Solutions

  1. Define the scope callable exactly as def my_scope(*, fixture_name, config): ... returning a scope string.
  2. Ensure the function returns one of 'function','class','module','package','session'.
  3. Catch/handle any internal errors inside the callable so it does not propagate.
  4. Verify config option names exist (config.getoption) before accessing them inside the callable.

Example fix

// before
@pytest.fixture(scope=lambda name: 'session' if name == 'db' else 'function')
def db(): ...
// after
def _scope(*, fixture_name, config):
    return 'session' if fixture_name == 'db' else 'function'

@pytest.fixture(scope=_scope)
def db(): ...
Defensive patterns

Strategy: type-guard

Validate before calling

import inspect
def assert_scope_callable(fn):
    sig = inspect.signature(fn)
    params = {p.name: p.kind for p in sig.parameters.values()}
    assert {'fixture_name','config'} <= set(params), 'scope callable must take fixture_name and config'
    assert all(k == inspect.Parameter.KEYWORD_ONLY for k in params.values()), 'use keyword-only params'

Type guard

import inspect
from typing import Callable
def is_valid_scope_callable(fn) -> bool:
    try:
        sig = inspect.signature(fn)
    except (TypeError, ValueError):
        return False
    names = set(sig.parameters)
    return {'fixture_name','config'} <= names

Prevention

When it happens

Trigger: Passing scope=<function> whose signature is not (*, fixture_name, config), e.g. def scope(name): ...; the callable raising internally (e.g. config.getoption on a missing option); a lambda that ignores required kwargs.

Common situations: Trying to make scope depend on configuration but writing the wrong parameter names; using positional params instead of keyword-only; raising inside the scope function due to a typo or missing config option; copying a scope callable from an older pytest version with a different signature contract.

Related errors


AI-assisted analysis of pytest-dev/pytest@0d6fbdeffa (2026-08-11). Data as JSON: /api/errors/43eeafbc3e46c3fe. Report an issue: GitHub.

Appendix: source

Thrown at src/_pytest/fixtures.py:1098

        fail(
            f"fixture function has more than one 'yield':\n\n"
            f"{Source(fixturefunc).indent()}\n"
            f"{fs}:{lineno + 1}",
            pytrace=False,
        )


def _eval_scope_callable(
    scope_callable: Callable[[str, Config], ScopeName],
    fixture_name: str,
    config: Config,
) -> ScopeName:
    try:
        # Type ignored because there is no typing mechanism to specify
        # keyword arguments, currently.
        result = scope_callable(fixture_name=fixture_name, config=config)  # type: ignore[call-arg]
    except Exception as e:
        raise TypeError(
            f"Error evaluating {scope_callable} while defining fixture '{fixture_name}'.\n"
            "Expected a function with the signature (*, fixture_name, config)"
        ) from e
    if not isinstance(result, str):
        fail(
            f"Expected {scope_callable} to return a 'str' while defining fixture '{fixture_name}', but it returned:\n"
            f"{result!r}",
            pytrace=False,
        )
    return result


class FixtureDef(Generic[FixtureValue]):
    """A container for a fixture definition.

    Note: At this time, only explicitly documented fields and methods are
    considered public stable API.
    """

View on GitHub (pinned to 0d6fbdeffa)