pytest-dev/pytest · error · RuntimeError

function definitions are not supposed to be run as tests

Error message

function definitions are not supposed to be run as tests

What it means

Thrown by FunctionDefinition.runtest() (and setup, which aliases runtest). FunctionDefinition represents a function collected as a definition node (e.g. for metafunc inspection) that is not meant to be executed as a test. Attempting to run it indicates a collection/handler mismatch.

Solutions

  1. Do not call runtest() on FunctionDefinition nodes; use Function items for execution.
  2. Check isinstance(node, Function) and not FunctionDefinition before running.
  3. Use the standard pytest_runtest_call hook pathway instead of invoking runtest directly.

Example fix

// before
for node in session.items:
    node.runtest()
// after
for node in session.items:
    if isinstance(node, FunctionDefinition):
        continue
    node.runtest()
Defensive patterns

Strategy: type-guard

Validate before calling

from _pytest.python import Function, FunctionDefinition
for node in session.items:
    if isinstance(node, FunctionDefinition):
        continue
    node.runtest()

Type guard

from _pytest.python import FunctionDefinition
def is_runnable_function(node) -> bool:
    return not isinstance(node, FunctionDefinition)

Prevention

When it happens

Trigger: A plugin or hook calling node.runtest() on a FunctionDefinition node directly; a custom item subclass that delegates to FunctionDefinition; misuse of the internal stop-gap API.

Common situations: Writing pytest plugins that walk the collection tree and invoke runtest; test frameworks built on pytest internals; version differences where Function vs FunctionDefinition handling changed.

Related errors


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

Appendix: source

Thrown at src/_pytest/python.py:1833

        return excinfo.traceback

    # TODO: Type ignored -- breaks Liskov Substitution.
    def repr_failure(  # type: ignore[override]
        self,
        excinfo: ExceptionInfo[BaseException],
    ) -> str | TerminalRepr:
        style = self.config.getoption("tbstyle", "auto")
        if style == "auto":
            style = "long"
        return self._repr_failure_py(excinfo, style=style)


class FunctionDefinition(Function):
    """This class is a stop gap solution until we evolve to have actual function
    definition nodes and manage to get rid of ``metafunc``."""

    def runtest(self) -> None:
        raise RuntimeError("function definitions are not supposed to be run as tests")

    setup = runtest


def __getattr__(name: str) -> object:
    if name == "CallSpec2":
        warnings.warn(CALLSPEC2_RENAMED, stacklevel=2)
        return CallSpec
    raise AttributeError(f"module {__name__!r} has no attribute {name!r}")

View on GitHub (pinned to 0d6fbdeffa)