Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 097eae5

Browse files
[3.8] bpo-37950: Fix ast.dump() when call with incompletely initialized node. (GH-15510) (GH-15582)
(cherry picked from commit e64f948)
1 parent 38d311d commit 097eae5

File tree

4 files changed

+59
-19
lines changed

4 files changed

+59
-19
lines changed

Doc/library/ast.rst

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -322,11 +322,12 @@ and classes for traversing abstract syntax trees:
322322
.. function:: dump(node, annotate_fields=True, include_attributes=False)
323323

324324
Return a formatted dump of the tree in *node*. This is mainly useful for
325-
debugging purposes. The returned string will show the names and the values
326-
for fields. This makes the code impossible to evaluate, so if evaluation is
327-
wanted *annotate_fields* must be set to ``False``. Attributes such as line
325+
debugging purposes. If *annotate_fields* is true (by default),
326+
the returned string will show the names and the values for fields.
327+
If *annotate_fields* is false, the result string will be more compact by
328+
omitting unambiguous field names. Attributes such as line
328329
numbers and column offsets are not dumped by default. If this is wanted,
329-
*include_attributes* can be set to ``True``.
330+
*include_attributes* can be set to true.
330331

331332
.. seealso::
332333

Lib/ast.py

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -98,26 +98,35 @@ def _convert(node):
9898

9999
def dump(node, annotate_fields=True, include_attributes=False):
100100
"""
101-
Return a formatted dump of the tree in *node*. This is mainly useful for
102-
debugging purposes. The returned string will show the names and the values
103-
for fields. This makes the code impossible to evaluate, so if evaluation is
104-
wanted *annotate_fields* must be set to False. Attributes such as line
101+
Return a formatted dump of the tree in node. This is mainly useful for
102+
debugging purposes. If annotate_fields is true (by default),
103+
the returned string will show the names and the values for fields.
104+
If annotate_fields is false, the result string will be more compact by
105+
omitting unambiguous field names. Attributes such as line
105106
numbers and column offsets are not dumped by default. If this is wanted,
106-
*include_attributes* can be set to True.
107+
include_attributes can be set to true.
107108
"""
108109
def _format(node):
109110
if isinstance(node, AST):
110-
fields = [(a, _format(b)) for a, b in iter_fields(node)]
111-
rv = '%s(%s' % (node.__class__.__name__, ', '.join(
112-
('%s=%s' % field for field in fields)
113-
if annotate_fields else
114-
(b for a, b in fields)
115-
))
111+
args = []
112+
keywords = annotate_fields
113+
for field in node._fields:
114+
try:
115+
value = getattr(node, field)
116+
except AttributeError:
117+
keywords = True
118+
else:
119+
if keywords:
120+
args.append('%s=%s' % (field, _format(value)))
121+
else:
122+
args.append(_format(value))
116123
if include_attributes and node._attributes:
117-
rv += fields and ', ' or ' '
118-
rv += ', '.join('%s=%s' % (a, _format(getattr(node, a)))
119-
for a in node._attributes)
120-
return rv + ')'
124+
for a in node._attributes:
125+
try:
126+
args.append('%s=%s' % (a, _format(getattr(node, a))))
127+
except AttributeError:
128+
pass
129+
return '%s(%s)' % (node.__class__.__name__, ', '.join(args))
121130
elif isinstance(node, list):
122131
return '[%s]' % ', '.join(_format(x) for x in node)
123132
return repr(node)

Lib/test/test_ast.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,35 @@ def test_dump(self):
645645
"lineno=1, col_offset=0, end_lineno=1, end_col_offset=24)], type_ignores=[])"
646646
)
647647

648+
def test_dump_incomplete(self):
649+
node = ast.Raise(lineno=3, col_offset=4)
650+
self.assertEqual(ast.dump(node),
651+
"Raise()"
652+
)
653+
self.assertEqual(ast.dump(node, include_attributes=True),
654+
"Raise(lineno=3, col_offset=4)"
655+
)
656+
node = ast.Raise(exc=ast.Name(id='e', ctx=ast.Load()), lineno=3, col_offset=4)
657+
self.assertEqual(ast.dump(node),
658+
"Raise(exc=Name(id='e', ctx=Load()))"
659+
)
660+
self.assertEqual(ast.dump(node, annotate_fields=False),
661+
"Raise(Name('e', Load()))"
662+
)
663+
self.assertEqual(ast.dump(node, include_attributes=True),
664+
"Raise(exc=Name(id='e', ctx=Load()), lineno=3, col_offset=4)"
665+
)
666+
self.assertEqual(ast.dump(node, annotate_fields=False, include_attributes=True),
667+
"Raise(Name('e', Load()), lineno=3, col_offset=4)"
668+
)
669+
node = ast.Raise(cause=ast.Name(id='e', ctx=ast.Load()))
670+
self.assertEqual(ast.dump(node),
671+
"Raise(cause=Name(id='e', ctx=Load()))"
672+
)
673+
self.assertEqual(ast.dump(node, annotate_fields=False),
674+
"Raise(cause=Name('e', Load()))"
675+
)
676+
648677
def test_copy_location(self):
649678
src = ast.parse('1 + 1', mode='eval')
650679
src.body.right = ast.copy_location(ast.Num(2), src.body.right)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix :func:`ast.dump` when call with incompletely initialized node.

0 commit comments

Comments
 (0)