{"id":"43eeafbc3e46c3fe","repo":"pytest-dev/pytest","slug":"error-evaluating-scope-callable-while-defining-f","errorCode":null,"errorMessage":"Error evaluating {scope_callable} while defining fixture '{fixture_name}'.\nExpected a function with the signature (*, fixture_name, config)","messagePattern":"Error evaluating (.+?) while defining fixture '(.+?)'\\.\nExpected a function with the signature \\(\\*, fixture_name, config\\)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/_pytest/fixtures.py","lineNumber":1098,"sourceCode":"        fail(\n            f\"fixture function has more than one 'yield':\\n\\n\"\n            f\"{Source(fixturefunc).indent()}\\n\"\n            f\"{fs}:{lineno + 1}\",\n            pytrace=False,\n        )\n\n\ndef _eval_scope_callable(\n    scope_callable: Callable[[str, Config], ScopeName],\n    fixture_name: str,\n    config: Config,\n) -> ScopeName:\n    try:\n        # Type ignored because there is no typing mechanism to specify\n        # keyword arguments, currently.\n        result = scope_callable(fixture_name=fixture_name, config=config)  # type: ignore[call-arg]\n    except Exception as e:\n        raise TypeError(\n            f\"Error evaluating {scope_callable} while defining fixture '{fixture_name}'.\\n\"\n            \"Expected a function with the signature (*, fixture_name, config)\"\n        ) from e\n    if not isinstance(result, str):\n        fail(\n            f\"Expected {scope_callable} to return a 'str' while defining fixture '{fixture_name}', but it returned:\\n\"\n            f\"{result!r}\",\n            pytrace=False,\n        )\n    return result\n\n\nclass FixtureDef(Generic[FixtureValue]):\n    \"\"\"A container for a fixture definition.\n\n    Note: At this time, only explicitly documented fields and methods are\n    considered public stable API.\n    \"\"\"","sourceCodeStart":1080,"sourceCodeEnd":1116,"githubUrl":"https://github.com/pytest-dev/pytest/blob/98b357f69e380da908740a212288d73b2ee06687/src/_pytest/fixtures.py#L1080-L1116","documentation":"Raised by `_eval_scope_callable` when the dynamic scope callable passed to `@pytest.fixture(scope=callable)` either raises or does not accept the required keyword-only signature `(*, fixture_name, config)`. pytest calls the callable at collection time to compute the scope string; any exception is wrapped in this TypeError pointing at the offending callable.","triggerScenarios":"Passing a scope function with the wrong signature, e.g. `def scope(fixture_name)` (missing `config`), or a function that raises (returns based on a missing config option). pytest invokes `scope(fixture_name=..., config=...)` with keyword args.","commonSituations":"Writing a dynamic-scope fixture that reads `config.getini(\"...\")` for an option that is not registered, or copying a signature from outdated docs. Using positional-only params.","solutions":["Define the callable as `def my_scope(*, fixture_name, config): ...` and return one of \"function\",\"class\",\"module\",\"package\",\"session\".","Make sure any config option you read inside the callable is registered via `pytest_addoption`/`addini`.","Catch/avoid exceptions inside the callable; return a safe default scope on edge cases."],"exampleFix":"// before\ndef scope(fixture_name):          # wrong signature\n    return \"session\"\n@pytest.fixture(scope=scope)\ndef x(): yield\n// after\ndef scope(*, fixture_name, config):\n    return \"session\" if config.getoption(\"--ci\") else \"function\"\n@pytest.fixture(scope=scope)\ndef x(): yield","handlingStrategy":"validation","validationCode":"import inspect\n\ndef check_scope_callable(fn):\n    sig = inspect.signature(fn)\n    params = [p for p in sig.parameters.values()]\n    has_var_kw = any(p.kind == inspect.Parameter.VAR_KEYWORD for p in params)\n    names = {p.name for p in params}\n    if not (\"fixture_name\" in names and \"config\" in names) and not has_var_kw:\n        raise TypeError(\"scope callable must accept (*, fixture_name, config)\")","typeGuard":"def is_valid_scope_callable(fn) -> bool:\n    import inspect\n    try:\n        sig = inspect.signature(fn)\n    except (TypeError, ValueError):\n        return False\n    names = set(sig.parameters)\n    return {\"fixture_name\", \"config\"}.issubset(names) or any(\n        p.kind == inspect.Parameter.VAR_KEYWORD for p in sig.parameters.values()\n    )","tryCatchPattern":null,"preventionTips":["Define dynamic scope callables as `def scope(*, fixture_name, config):`.","Register any config option the callable reads via pytest_addoption.","Return a valid scope string on every path."],"tags":["pytest","fixtures","dynamic-scope","signature","typeerror"],"analyzedSha":"98b357f69e380da908740a212288d73b2ee06687","analyzedAt":"2026-08-04T20:26:34.442Z","schemaVersion":2}