python/cpython · error · AttributeError
module 'ast' has no attribute {attr!r}
Error message
module 'ast' has no attribute {attr!r} What it means
ast's module-level __getattr__ serves the deprecated node classes removed from the main namespace (Index, ExtSlice, Suite, AugLoad, AugStore, Param, and peers kept in _deprecated). A lookup that misses _deprecated entirely raises AttributeError; names present in the mapping emit a DeprecationWarning (removal targeted for 3.21) and return the shim class. This pattern replaced the old hard ImportError after these classes were made subclasses of their replacements.
Source
Thrown at Lib/ast.py:733
print(dump(tree, include_attributes=args.include_attributes,
color=can_colorize(file=sys.stdout),
indent=args.indent, show_empty=args.show_empty))
_deprecated = {
'slice': globals().pop("slice"),
'Index': globals().pop("Index"),
'ExtSlice': globals().pop("ExtSlice"),
'Suite': globals().pop("Suite"),
'AugLoad': globals().pop("AugLoad"),
'AugStore': globals().pop("AugStore"),
'Param': globals().pop("Param")
}
def __getattr__(attr):
try:
val = _deprecated[attr]
except KeyError:
raise AttributeError(f"module 'ast' has no attribute {attr!r}") from None
warnings._deprecated(f"ast.{attr}", remove=(3, 21))
return val
if __name__ == '__main__':
main()
View on GitHub (pinned to bc6749cc3b)
Solutions
- Replace deprecated classes: use the wrapped node directly (e.g. x instead of ast.Index(x) for subscripts; ast.Tuple for ExtSlice; plain Load/Store for AugLoad/AugStore; drop ast.Param in favor of plain arg).
- Pin or upgrade the tooling — many codemod libraries (e.g. libcst, astroid) already shipped 3.9+ fixes.
- For dynamic lookups use getattr(ast, name, None) and check sys.version_info before touching removed names.
Example fix
# before slc = ast.Index(value=ast.Name(id='i')) # deprecation + removal in 3.21 # after slc = ast.Name(id='i', ctx=ast.Load()) # bare expression as index (3.9+)
Defensive patterns
Strategy: type-guard
Validate before calling
DEPRECATED_AST = {'Index', 'ExtSlice', 'Suite', 'AugLoad', 'AugStore', 'Param'}
def ast_attr(name, default=None):
if name in DEPRECATED_AST:
return default # do not touch the deprecation shims
return getattr(ast, name, default) Type guard
def ast_has(name) -> bool:
"""True only for non-deprecated attributes."""
import warnings
DEPRECATED = {'Index', 'ExtSlice', 'Suite', 'AugLoad', 'AugStore', 'Param'}
return name not in DEPRECATED and hasattr(ast, name) Try / catch
try:
cls = getattr(ast, name)
except AttributeError:
raise RuntimeError(
f'ast.{name} does not exist on Python {sys.version.split()[0]}; '
f'use 3.9+ node classes') from None Prevention
- Target modern node classes: bare expressions instead of Index, Tuple instead of ExtSlice, plain Load/Store contexts.
- Use getattr(ast, name, None) plus sys.version_info checks in cross-version codemods.
- Run tests with -W error::DeprecationWarning to catch ast deprecations before removal.
When it happens
Trigger: ast.Index / ast.ExtSlice / ast.Suite / ast.AugLoad / ast.AugStore / ast.Param accessed directly (deprecation path); any other misspelled or nonexistent ast name such as ast.AstParser raising the AttributeError; getattr(ast, name) probes in version-adaptive code.
Common situations: Old AST-rewriting tools (codemods, macros, optimizers) written before 3.9 when Index/SExtSlice were real node classes; code that constructs ast.Index(value) while targeting multiple Python versions; hasattr-based feature detection against ast.
Related errors
- module 'collections.abc' has no attribute {attr!r}
- module {__name__!r} has no attribute {name!r}
- Node can't use cause without an exception.
- Unexpected node inside JoinedStr, {node!r}
- %r object attribute '__dict__' is read-only
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/04c59be28c01f626.
Report an issue: GitHub.