mirror of
https://github.com/python/cpython.git
synced 2025-11-24 12:20:42 +00:00
69 lines
2.6 KiB
Python
69 lines
2.6 KiB
Python
"""
|
|
Copy-parse of ast.dump, removing the `isinstance` checks. This is needed,
|
|
because testing pegen requires generating a C extension module, which contains
|
|
a copy of the symbols defined in Python-ast.c. Thus, the isinstance check would
|
|
always fail. We rely on string comparison of the base classes instead.
|
|
TODO: Remove the above-described hack.
|
|
"""
|
|
|
|
from typing import Any
|
|
|
|
|
|
def ast_dump(
|
|
node: Any,
|
|
annotate_fields: bool = True,
|
|
include_attributes: bool = False,
|
|
*,
|
|
indent: str | None = None,
|
|
) -> str:
|
|
def _format(node: Any, level: int = 0) -> tuple[str, bool]:
|
|
if indent is not None:
|
|
level += 1
|
|
prefix = "\n" + indent * level
|
|
sep = ",\n" + indent * level
|
|
else:
|
|
prefix = ""
|
|
sep = ", "
|
|
if any(cls.__name__ == "AST" for cls in node.__class__.__mro__):
|
|
cls = type(node)
|
|
args = []
|
|
allsimple = True
|
|
keywords = annotate_fields
|
|
for name in node._fields:
|
|
try:
|
|
value = getattr(node, name)
|
|
except AttributeError:
|
|
keywords = True
|
|
continue
|
|
if value is None and getattr(cls, name, ...) is None:
|
|
keywords = True
|
|
continue
|
|
value, simple = _format(value, level)
|
|
allsimple = allsimple and simple
|
|
if keywords:
|
|
args.append(f"{name}={value}")
|
|
else:
|
|
args.append(value)
|
|
if include_attributes and node._attributes:
|
|
for name in node._attributes:
|
|
try:
|
|
value = getattr(node, name)
|
|
except AttributeError:
|
|
continue
|
|
if value is None and getattr(cls, name, ...) is None:
|
|
continue
|
|
value, simple = _format(value, level)
|
|
allsimple = allsimple and simple
|
|
args.append(f"{name}={value}")
|
|
if allsimple and len(args) <= 3:
|
|
return "{}({})".format(node.__class__.__name__, ", ".join(args)), not args
|
|
return f"{node.__class__.__name__}({prefix}{sep.join(args)})", False
|
|
elif isinstance(node, list):
|
|
if not node:
|
|
return "[]", True
|
|
return f"[{prefix}{sep.join(_format(x, level)[0] for x in node)}]", False
|
|
return repr(node), True
|
|
|
|
if all(cls.__name__ != "AST" for cls in node.__class__.__mro__):
|
|
raise TypeError(f"expected AST, got {node.__class__.__name__!r}")
|
|
return _format(node)[0]
|