pytest-dev/pytest · warning · AttributeError
module has no attribute
Error message
module {__name__!r} has no attribute {name!r} What it means
Thrown by the module-level __getattr__ in _pytest/python.py for any attribute access not special-cased. Currently only 'CallSpec2' is special-cased (deprecated alias); everything else falls through to this generic AttributeError.
Solutions
- Import the name from the public pytest namespace instead of _pytest.python.
- Check the pytest version's source for the correct name; it may have been renamed.
- Avoid relying on private _pytest.* modules in external plugins.
Example fix
// before from _pytest.python import CallSpec2 # deprecated, will warn // after from _pytest.python import CallSpec
Defensive patterns
Strategy: validation
Validate before calling
import importlib
mod = importlib.import_module('_pytest.python')
if not hasattr(mod, name):
raise AttributeError(f'_pytest.python has no {name!r}; check for renames') Type guard
def module_has_attr(module, name: str) -> bool:
return hasattr(module, name) Prevention
- Import from the public pytest package, not _pytest.python internals.
- Check pytest source/changelog for renamed private names.
- Avoid depending on private modules in external plugins.
When it happens
Trigger: Doing from _pytest.python import SomeName where SomeName doesn't exist; accessing _pytest.python.CallSpec2 (deprecated warning then redirect, but other names error); typos in internal imports by plugins.
Common situations: Plugins reaching into _pytest.python internals; renamed/removed private names across pytest versions; IDE auto-import suggestions for non-existent names.
Related errors
- Expected a float string for option
- Expected an int string for option
- function definitions are not supposed to be run as tests
- is the lower-most scope
- is the upper-most scope
AI-assisted analysis of pytest-dev/pytest@0d6fbdeffa (2026-08-11).
Data as JSON: /api/errors/5ebbfd321fedd03c.
Report an issue: GitHub.
Appendix: source
Thrown at src/_pytest/python.py:1842
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)