{"record":{"id":"122c9a5fe1b0fe1d","repo":"pytest-dev/pytest","slug":"function-definitions-are-not-supposed-to-be-run-as","errorCode":null,"errorMessage":"function definitions are not supposed to be run as tests","messagePattern":"function definitions are not supposed to be run as tests","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"src/_pytest/python.py","lineNumber":1833,"sourceCode":"        return excinfo.traceback\n\n    # TODO: Type ignored -- breaks Liskov Substitution.\n    def repr_failure(  # type: ignore[override]\n        self,\n        excinfo: ExceptionInfo[BaseException],\n    ) -> str | TerminalRepr:\n        style = self.config.getoption(\"tbstyle\", \"auto\")\n        if style == \"auto\":\n            style = \"long\"\n        return self._repr_failure_py(excinfo, style=style)\n\n\nclass FunctionDefinition(Function):\n    \"\"\"This class is a stop gap solution until we evolve to have actual function\n    definition nodes and manage to get rid of ``metafunc``.\"\"\"\n\n    def runtest(self) -> None:\n        raise RuntimeError(\"function definitions are not supposed to be run as tests\")\n\n    setup = runtest\n\n\ndef __getattr__(name: str) -> object:\n    if name == \"CallSpec2\":\n        warnings.warn(CALLSPEC2_RENAMED, stacklevel=2)\n        return CallSpec\n    raise AttributeError(f\"module {__name__!r} has no attribute {name!r}\")\n","sourceCodeStart":1815,"sourceCodeEnd":1843,"githubUrl":"https://github.com/pytest-dev/pytest/blob/0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc/src/_pytest/python.py#L1815-L1843","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Do not call runtest() on FunctionDefinition nodes; use Function items for execution.","Check isinstance(node, Function) and not FunctionDefinition before running.","Use the standard pytest_runtest_call hook pathway instead of invoking runtest directly."],"exampleFix":"// before\nfor node in session.items:\n    node.runtest()\n// after\nfor node in session.items:\n    if isinstance(node, FunctionDefinition):\n        continue\n    node.runtest()","handlingStrategy":"type-guard","validationCode":"from _pytest.python import Function, FunctionDefinition\nfor node in session.items:\n    if isinstance(node, FunctionDefinition):\n        continue\n    node.runtest()","typeGuard":"from _pytest.python import FunctionDefinition\ndef is_runnable_function(node) -> bool:\n    return not isinstance(node, FunctionDefinition)","tryCatchPattern":null,"preventionTips":["Skip FunctionDefinition nodes when iterating collection items.","Use the standard pytest_runtest_call hook for execution.","Do not call runtest() directly on definition nodes."],"tags":["function-definition","internal","collection","runtest"],"backgroundTag":null,"analyzedSha":"0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc","analyzedAt":"2026-08-11T20:52:36.969Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}