summaryrefslogtreecommitdiff
path: root/Lib/ast.py
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2019-09-09 19:33:13 +0300
committerGitHub <noreply@github.com>2019-09-09 19:33:13 +0300
commit850573b836d5b82d1a1ebe75a635aaa0a3dff997 (patch)
treeeb7aa5da66e0dfa0520104fac656ae93f3a12a34 /Lib/ast.py
parent92709a263e9cec0bc646ccc1ea051fc528800d8d (diff)
downloadcpython-git-850573b836d5b82d1a1ebe75a635aaa0a3dff997.tar.gz
bpo-37995: Add an option to ast.dump() to produce a multiline output. (GH-15631)
Diffstat (limited to 'Lib/ast.py')
-rw-r--r--Lib/ast.py45
1 files changed, 34 insertions, 11 deletions
diff --git a/Lib/ast.py b/Lib/ast.py
index 5ab023f6c3..498484f198 100644
--- a/Lib/ast.py
+++ b/Lib/ast.py
@@ -96,7 +96,7 @@ def literal_eval(node_or_string):
return _convert(node_or_string)
-def dump(node, annotate_fields=True, include_attributes=False):
+def dump(node, annotate_fields=True, include_attributes=False, *, indent=None):
"""
Return a formatted dump of the tree in node. This is mainly useful for
debugging purposes. If annotate_fields is true (by default),
@@ -104,11 +104,21 @@ def dump(node, annotate_fields=True, include_attributes=False):
If annotate_fields is false, the result string will be more compact by
omitting unambiguous field names. Attributes such as line
numbers and column offsets are not dumped by default. If this is wanted,
- include_attributes can be set to true.
+ include_attributes can be set to true. If indent is a non-negative
+ integer or string, then the tree will be pretty-printed with that indent
+ level. None (the default) selects the single line representation.
"""
- def _format(node):
+ def _format(node, level=0):
+ if indent is not None:
+ level += 1
+ prefix = '\n' + indent * level
+ sep = ',\n' + indent * level
+ else:
+ prefix = ''
+ sep = ', '
if isinstance(node, AST):
args = []
+ allsimple = True
keywords = annotate_fields
for field in node._fields:
try:
@@ -116,23 +126,36 @@ def dump(node, annotate_fields=True, include_attributes=False):
except AttributeError:
keywords = True
else:
+ value, simple = _format(value, level)
+ allsimple = allsimple and simple
if keywords:
- args.append('%s=%s' % (field, _format(value)))
+ args.append('%s=%s' % (field, value))
else:
- args.append(_format(value))
+ args.append(value)
if include_attributes and node._attributes:
- for a in node._attributes:
+ for attr in node._attributes:
try:
- args.append('%s=%s' % (a, _format(getattr(node, a))))
+ value = getattr(node, attr)
except AttributeError:
pass
- return '%s(%s)' % (node.__class__.__name__, ', '.join(args))
+ else:
+ value, simple = _format(value, level)
+ allsimple = allsimple and simple
+ args.append('%s=%s' % (attr, value))
+ if allsimple and len(args) <= 3:
+ return '%s(%s)' % (node.__class__.__name__, ', '.join(args)), not args
+ return '%s(%s%s)' % (node.__class__.__name__, prefix, sep.join(args)), False
elif isinstance(node, list):
- return '[%s]' % ', '.join(_format(x) for x in node)
- return repr(node)
+ if not node:
+ return '[]', True
+ return '[%s%s]' % (prefix, sep.join(_format(x, level)[0] for x in node)), False
+ return repr(node), True
+
if not isinstance(node, AST):
raise TypeError('expected AST, got %r' % node.__class__.__name__)
- return _format(node)
+ if indent is not None and not isinstance(indent, str):
+ indent = ' ' * indent
+ return _format(node)[0]
def copy_location(new_node, old_node):