[Python-checkins] bpo-36287: Make ast.dump() not output optional fields and attributes with default values. (GH-18843)

Serhiy Storchaka webhook-mailer at python.org
Mon Mar 9 18:07:55 EDT 2020


https://github.com/python/cpython/commit/b7e9525f9c7ef02a1d2ad8253afdeb733b0951d4
commit: b7e9525f9c7ef02a1d2ad8253afdeb733b0951d4
branch: master
author: Serhiy Storchaka <storchaka at gmail.com>
committer: GitHub <noreply at github.com>
date: 2020年03月10日T00:07:47+02:00
summary:
bpo-36287: Make ast.dump() not output optional fields and attributes with default values. (GH-18843)
The default values for optional fields and attributes of AST nodes are now set
as class attributes (e.g. Constant.kind is set to None).
files:
A Misc/NEWS.d/next/Library/2020-03-08-09-53-55.bpo-36287.mxr5m8.rst
M Doc/library/ast.rst
M Lib/ast.py
M Lib/test/test_ast.py
M Parser/asdl_c.py
M Python/Python-ast.c
diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst
index 01735643dbb9b..a11f8b9894076 100644
--- a/Doc/library/ast.rst
+++ b/Doc/library/ast.rst
@@ -141,7 +141,7 @@ Literals
 
 >>> print(ast.dump(ast.parse('123', mode='eval'), indent=4))
 Expression(
- body=Constant(value=123, kind=None))
+ body=Constant(value=123))
 
 
 .. class:: FormattedValue(value, conversion, format_spec)
@@ -175,12 +175,11 @@ Literals
 Expression(
 body=JoinedStr(
 values=[
- Constant(value='sin(', kind=None),
+ Constant(value='sin('),
 FormattedValue(
 value=Name(id='a', ctx=Load()),
- conversion=-1,
- format_spec=None),
- Constant(value=') is ', kind=None),
+ conversion=-1),
+ Constant(value=') is '),
 FormattedValue(
 value=Call(
 func=Name(id='sin', ctx=Load()),
@@ -190,7 +189,7 @@ Literals
 conversion=-1,
 format_spec=JoinedStr(
 values=[
- Constant(value='.3', kind=None)]))]))
+ Constant(value='.3')]))]))
 
 
 .. class:: List(elts, ctx)
@@ -206,17 +205,17 @@ Literals
 Expression(
 body=List(
 elts=[
- Constant(value=1, kind=None),
- Constant(value=2, kind=None),
- Constant(value=3, kind=None)],
+ Constant(value=1),
+ Constant(value=2),
+ Constant(value=3)],
 ctx=Load()))
 >>> print(ast.dump(ast.parse('(1, 2, 3)', mode='eval'), indent=4))
 Expression(
 body=Tuple(
 elts=[
- Constant(value=1, kind=None),
- Constant(value=2, kind=None),
- Constant(value=3, kind=None)],
+ Constant(value=1),
+ Constant(value=2),
+ Constant(value=3)],
 ctx=Load()))
 
 
@@ -230,9 +229,9 @@ Literals
 Expression(
 body=Set(
 elts=[
- Constant(value=1, kind=None),
- Constant(value=2, kind=None),
- Constant(value=3, kind=None)]))
+ Constant(value=1),
+ Constant(value=2),
+ Constant(value=3)]))
 
 
 .. class:: Dict(keys, values)
@@ -251,10 +250,10 @@ Literals
 Expression(
 body=Dict(
 keys=[
- Constant(value='a', kind=None),
+ Constant(value='a'),
 None],
 values=[
- Constant(value=1, kind=None),
+ Constant(value=1),
 Name(id='d', ctx=Load())]))
 
 
@@ -290,8 +289,7 @@ Variables
 Assign(
 targets=[
 Name(id='a', ctx=Store())],
- value=Constant(value=1, kind=None),
- type_comment=None)],
+ value=Constant(value=1))],
 type_ignores=[])
 
 >>> print(ast.dump(ast.parse('del a'), indent=4))
@@ -323,8 +321,7 @@ Variables
 value=Name(id='b', ctx=Store()),
 ctx=Store())],
 ctx=Store())],
- value=Name(id='it', ctx=Load()),
- type_comment=None)],
+ value=Name(id='it', ctx=Load()))],
 type_ignores=[])
 
 
@@ -442,13 +439,13 @@ Expressions
 >>> print(ast.dump(ast.parse('1 <= a < 10', mode='eval'), indent=4))
 Expression(
 body=Compare(
- left=Constant(value=1, kind=None),
+ left=Constant(value=1),
 ops=[
 LtE(),
 Lt()],
 comparators=[
 Name(id='a', ctx=Load()),
- Constant(value=10, kind=None)]))
+ Constant(value=10)]))
 
 
 .. class:: Eq
@@ -493,7 +490,6 @@ Expressions
 arg='b',
 value=Name(id='c', ctx=Load())),
 keyword(
- arg=None,
 value=Name(id='e', ctx=Load()))]))
 
 
@@ -548,7 +544,7 @@ Expressions
 Expression(
 body=NamedExpr(
 target=Name(id='x', ctx=Store()),
- value=Constant(value=4, kind=None)))
+ value=Constant(value=4)))
 
 
 Subscripting
@@ -573,7 +569,7 @@ Subscripting
 body=Subscript(
 value=Name(id='l', ctx=Load()),
 slice=Index(
- value=Constant(value=1, kind=None)),
+ value=Constant(value=1)),
 ctx=Load()))
 
 
@@ -588,9 +584,8 @@ Subscripting
 body=Subscript(
 value=Name(id='l', ctx=Load()),
 slice=Slice(
- lower=Constant(value=1, kind=None),
- upper=Constant(value=2, kind=None),
- step=None),
+ lower=Constant(value=1),
+ upper=Constant(value=2)),
 ctx=Load()))
 
 
@@ -608,11 +603,10 @@ Subscripting
 slice=ExtSlice(
 dims=[
 Slice(
- lower=Constant(value=1, kind=None),
- upper=Constant(value=2, kind=None),
- step=None),
+ lower=Constant(value=1),
+ upper=Constant(value=2)),
 Index(
- value=Constant(value=3, kind=None))]),
+ value=Constant(value=3))]),
 ctx=Load()))
 
 
@@ -649,7 +643,7 @@ Comprehensions
 value=BinOp(
 left=Name(id='x', ctx=Load()),
 op=Pow(),
- right=Constant(value=2, kind=None)),
+ right=Constant(value=2)),
 generators=[
 comprehension(
 target=Name(id='x', ctx=Store()),
@@ -708,7 +702,7 @@ Comprehensions
 elt=BinOp(
 left=Name(id='n', ctx=Load()),
 op=Pow(),
- right=Constant(value=2, kind=None)),
+ right=Constant(value=2)),
 generators=[
 comprehension(
 target=Name(id='n', ctx=Store()),
@@ -719,13 +713,13 @@ Comprehensions
 ops=[
 Gt()],
 comparators=[
- Constant(value=5, kind=None)]),
+ Constant(value=5)]),
 Compare(
 left=Name(id='n', ctx=Load()),
 ops=[
 Lt()],
 comparators=[
- Constant(value=10, kind=None)])],
+ Constant(value=10)])],
 is_async=0)]))
 
 >>> print(ast.dump(ast.parse('[i async for i in soc]', mode='eval'),
@@ -764,8 +758,7 @@ Statements
 targets=[
 Name(id='a', ctx=Store()),
 Name(id='b', ctx=Store())],
- value=Constant(value=1, kind=None),
- type_comment=None)],
+ value=Constant(value=1))],
 type_ignores=[])
 
 >>> print(ast.dump(ast.parse('a,b = c'), indent=4)) # Unpacking
@@ -778,8 +771,7 @@ Statements
 Name(id='a', ctx=Store()),
 Name(id='b', ctx=Store())],
 ctx=Store())],
- value=Name(id='c', ctx=Load()),
- type_comment=None)],
+ value=Name(id='c', ctx=Load()))],
 type_ignores=[])
 
 
@@ -800,7 +792,6 @@ Statements
 AnnAssign(
 target=Name(id='c', ctx=Store()),
 annotation=Name(id='int', ctx=Load()),
- value=None,
 simple=1)],
 type_ignores=[])
 
@@ -810,7 +801,7 @@ Statements
 AnnAssign(
 target=Name(id='a', ctx=Store()),
 annotation=Name(id='int', ctx=Load()),
- value=Constant(value=1, kind=None),
+ value=Constant(value=1),
 simple=0)],
 type_ignores=[])
 
@@ -823,7 +814,6 @@ Statements
 attr='b',
 ctx=Store()),
 annotation=Name(id='int', ctx=Load()),
- value=None,
 simple=0)],
 type_ignores=[])
 
@@ -834,10 +824,9 @@ Statements
 target=Subscript(
 value=Name(id='a', ctx=Load()),
 slice=Index(
- value=Constant(value=1, kind=None)),
+ value=Constant(value=1)),
 ctx=Store()),
 annotation=Name(id='int', ctx=Load()),
- value=None,
 simple=0)],
 type_ignores=[])
 
@@ -860,7 +849,7 @@ Statements
 AugAssign(
 target=Name(id='x', ctx=Store()),
 op=Add(),
- value=Constant(value=2, kind=None))],
+ value=Constant(value=2))],
 type_ignores=[])
 
 
@@ -945,9 +934,9 @@ Imports
 body=[
 Import(
 names=[
- alias(name='x', asname=None),
- alias(name='y', asname=None),
- alias(name='z', asname=None)])],
+ alias(name='x'),
+ alias(name='y'),
+ alias(name='z')])],
 type_ignores=[])
 
 
@@ -966,9 +955,9 @@ Imports
 ImportFrom(
 module='y',
 names=[
- alias(name='x', asname=None),
- alias(name='y', asname=None),
- alias(name='z', asname=None)],
+ alias(name='x'),
+ alias(name='y'),
+ alias(name='z')],
 level=0)],
 type_ignores=[])
 
@@ -987,7 +976,7 @@ Imports
 module='foo.bar',
 names=[
 alias(name='a', asname='b'),
- alias(name='c', asname=None)],
+ alias(name='c')],
 level=2)],
 type_ignores=[])
 
@@ -1023,16 +1012,16 @@ Control flow
 test=Name(id='x', ctx=Load()),
 body=[
 Expr(
- value=Constant(value=Ellipsis, kind=None))],
+ value=Constant(value=Ellipsis))],
 orelse=[
 If(
 test=Name(id='y', ctx=Load()),
 body=[
 Expr(
- value=Constant(value=Ellipsis, kind=None))],
+ value=Constant(value=Ellipsis))],
 orelse=[
 Expr(
- value=Constant(value=Ellipsis, kind=None))])])],
+ value=Constant(value=Ellipsis))])])],
 type_ignores=[])
 
 
@@ -1063,11 +1052,10 @@ Control flow
 iter=Name(id='y', ctx=Load()),
 body=[
 Expr(
- value=Constant(value=Ellipsis, kind=None))],
+ value=Constant(value=Ellipsis))],
 orelse=[
 Expr(
- value=Constant(value=Ellipsis, kind=None))],
- type_comment=None)],
+ value=Constant(value=Ellipsis))])],
 type_ignores=[])
 
 
@@ -1090,10 +1078,10 @@ Control flow
 test=Name(id='x', ctx=Load()),
 body=[
 Expr(
- value=Constant(value=Ellipsis, kind=None))],
+ value=Constant(value=Ellipsis))],
 orelse=[
 Expr(
- value=Constant(value=Ellipsis, kind=None))])],
+ value=Constant(value=Ellipsis))])],
 type_ignores=[])
 
 
@@ -1124,13 +1112,12 @@ Control flow
 ops=[
 Gt()],
 comparators=[
- Constant(value=5, kind=None)]),
+ Constant(value=5)]),
 body=[
 Break()],
 orelse=[
 Continue()])],
- orelse=[],
- type_comment=None)],
+ orelse=[])],
 type_ignores=[])
 
 
@@ -1158,26 +1145,25 @@ Control flow
 Try(
 body=[
 Expr(
- value=Constant(value=Ellipsis, kind=None))],
+ value=Constant(value=Ellipsis))],
 handlers=[
 ExceptHandler(
 type=Name(id='Exception', ctx=Load()),
- name=None,
 body=[
 Expr(
- value=Constant(value=Ellipsis, kind=None))]),
+ value=Constant(value=Ellipsis))]),
 ExceptHandler(
 type=Name(id='OtherException', ctx=Load()),
 name='e',
 body=[
 Expr(
- value=Constant(value=Ellipsis, kind=None))])],
+ value=Constant(value=Ellipsis))])],
 orelse=[
 Expr(
- value=Constant(value=Ellipsis, kind=None))],
+ value=Constant(value=Ellipsis))],
 finalbody=[
 Expr(
- value=Constant(value=Ellipsis, kind=None))])],
+ value=Constant(value=Ellipsis))])],
 type_ignores=[])
 
 
@@ -1204,11 +1190,10 @@ Control flow
 value=BinOp(
 left=Name(id='a', ctx=Load()),
 op=Add(),
- right=Constant(value=1, kind=None)))],
+ right=Constant(value=1)))],
 handlers=[
 ExceptHandler(
 type=Name(id='TypeError', ctx=Load()),
- name=None,
 body=[
 Pass()])],
 orelse=[],
@@ -1256,8 +1241,7 @@ Control flow
 args=[
 Name(id='b', ctx=Load()),
 Name(id='d', ctx=Load())],
- keywords=[]))],
- type_comment=None)],
+ keywords=[]))])],
 type_ignores=[])
 
 
@@ -1295,14 +1279,12 @@ Function and class definitions
 args=arguments(
 posonlyargs=[],
 args=[
- arg(arg='x', annotation=None, type_comment=None),
- arg(arg='y', annotation=None, type_comment=None)],
- vararg=None,
+ arg(arg='x'),
+ arg(arg='y')],
 kwonlyargs=[],
 kw_defaults=[],
- kwarg=None,
 defaults=[]),
- body=Constant(value=Ellipsis, kind=None)))],
+ body=Constant(value=Ellipsis)))],
 type_ignores=[])
 
 
@@ -1347,28 +1329,26 @@ Function and class definitions
 args=[
 arg(
 arg='a',
- annotation=Constant(value='annotation', kind=None),
- type_comment=None),
- arg(arg='b', annotation=None, type_comment=None),
- arg(arg='c', annotation=None, type_comment=None)],
- vararg=arg(arg='d', annotation=None, type_comment=None),
+ annotation=Constant(value='annotation')),
+ arg(arg='b'),
+ arg(arg='c')],
+ vararg=arg(arg='d'),
 kwonlyargs=[
- arg(arg='e', annotation=None, type_comment=None),
- arg(arg='f', annotation=None, type_comment=None)],
+ arg(arg='e'),
+ arg(arg='f')],
 kw_defaults=[
 None,
- Constant(value=3, kind=None)],
- kwarg=arg(arg='g', annotation=None, type_comment=None),
+ Constant(value=3)],
+ kwarg=arg(arg='g'),
 defaults=[
- Constant(value=1, kind=None),
- Constant(value=2, kind=None)]),
+ Constant(value=1),
+ Constant(value=2)]),
 body=[
 Pass()],
 decorator_list=[
 Name(id='decorator1', ctx=Load()),
 Name(id='decorator2', ctx=Load())],
- returns=Constant(value='return annotation', kind=None),
- type_comment=None)],
+ returns=Constant(value='return annotation'))],
 type_ignores=[])
 
 
@@ -1382,7 +1362,7 @@ Function and class definitions
 Module(
 body=[
 Return(
- value=Constant(value=4, kind=None))],
+ value=Constant(value=4))],
 type_ignores=[])
 
 
@@ -1508,10 +1488,8 @@ Async and await
 args=arguments(
 posonlyargs=[],
 args=[],
- vararg=None,
 kwonlyargs=[],
 kw_defaults=[],
- kwarg=None,
 defaults=[]),
 body=[
 Expr(
@@ -1520,9 +1498,7 @@ Async and await
 func=Name(id='other_func', ctx=Load()),
 args=[],
 keywords=[])))],
- decorator_list=[],
- returns=None,
- type_comment=None)],
+ decorator_list=[])],
 type_ignores=[])
 
 
diff --git a/Lib/ast.py b/Lib/ast.py
index 9a3d3806eb8ca..0bce4a49dc77a 100644
--- a/Lib/ast.py
+++ b/Lib/ast.py
@@ -123,31 +123,36 @@ def _format(node, level=0):
 prefix = ''
 sep = ', '
 if isinstance(node, AST):
+ cls = type(node)
 args = []
 allsimple = True
 keywords = annotate_fields
- for field in node._fields:
+ for name in node._fields:
 try:
- value = getattr(node, field)
+ 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('%s=%s' % (name, value))
 else:
- value, simple = _format(value, level)
- allsimple = allsimple and simple
- if keywords:
- args.append('%s=%s' % (field, value))
- else:
- args.append(value)
+ args.append(value)
 if include_attributes and node._attributes:
- for attr in node._attributes:
+ for name in node._attributes:
 try:
- value = getattr(node, attr)
+ value = getattr(node, name)
 except AttributeError:
- pass
- else:
- value, simple = _format(value, level)
- allsimple = allsimple and simple
- args.append('%s=%s' % (attr, value))
+ continue
+ if value is None and getattr(cls, name, ...) is None:
+ continue
+ value, simple = _format(value, level)
+ allsimple = allsimple and simple
+ args.append('%s=%s' % (name, 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
@@ -170,9 +175,10 @@ def copy_location(new_node, old_node):
 attributes) from *old_node* to *new_node* if possible, and return *new_node*.
 """
 for attr in 'lineno', 'col_offset', 'end_lineno', 'end_col_offset':
- if attr in old_node._attributes and attr in new_node._attributes \
- and hasattr(old_node, attr):
- setattr(new_node, attr, getattr(old_node, attr))
+ if attr in old_node._attributes and attr in new_node._attributes:
+ value = getattr(old_node, attr, None)
+ if value is not None:
+ setattr(new_node, attr, value)
 return new_node
 
 
@@ -191,7 +197,7 @@ def _fix(node, lineno, col_offset, end_lineno, end_col_offset):
 else:
 lineno = node.lineno
 if 'end_lineno' in node._attributes:
- if not hasattr(node, 'end_lineno'):
+ if getattr(node, 'end_lineno', None) is None:
 node.end_lineno = end_lineno
 else:
 end_lineno = node.end_lineno
@@ -201,7 +207,7 @@ def _fix(node, lineno, col_offset, end_lineno, end_col_offset):
 else:
 col_offset = node.col_offset
 if 'end_col_offset' in node._attributes:
- if not hasattr(node, 'end_col_offset'):
+ if getattr(node, 'end_col_offset', None) is None:
 node.end_col_offset = end_col_offset
 else:
 end_col_offset = node.end_col_offset
diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py
index e78848537d47a..c1e9f00281115 100644
--- a/Lib/test/test_ast.py
+++ b/Lib/test/test_ast.py
@@ -353,9 +353,11 @@ def test_arguments(self):
 'kw_defaults', 'kwarg', 'defaults'))
 
 with self.assertRaises(AttributeError):
- x.vararg
+ x.args
+ self.assertIsNone(x.vararg)
 
 x = ast.arguments(*range(1, 8))
+ self.assertEqual(x.args, 2)
 self.assertEqual(x.vararg, 3)
 
 def test_field_attr_writable(self):
@@ -650,18 +652,18 @@ def test_dump(self):
 node = ast.parse('spam(eggs, "and cheese")')
 self.assertEqual(ast.dump(node),
 "Module(body=[Expr(value=Call(func=Name(id='spam', ctx=Load()), "
- "args=[Name(id='eggs', ctx=Load()), Constant(value='and cheese', kind=None)], "
+ "args=[Name(id='eggs', ctx=Load()), Constant(value='and cheese')], "
 "keywords=[]))], type_ignores=[])"
 )
 self.assertEqual(ast.dump(node, annotate_fields=False),
 "Module([Expr(Call(Name('spam', Load()), [Name('eggs', Load()), "
- "Constant('and cheese', None)], []))], [])"
+ "Constant('and cheese')], []))], [])"
 )
 self.assertEqual(ast.dump(node, include_attributes=True),
 "Module(body=[Expr(value=Call(func=Name(id='spam', ctx=Load(), "
 "lineno=1, col_offset=0, end_lineno=1, end_col_offset=4), "
 "args=[Name(id='eggs', ctx=Load(), lineno=1, col_offset=5, "
- "end_lineno=1, end_col_offset=9), Constant(value='and cheese', kind=None, "
+ "end_lineno=1, end_col_offset=9), Constant(value='and cheese', "
 "lineno=1, col_offset=11, end_lineno=1, end_col_offset=23)], keywords=[], "
 "lineno=1, col_offset=0, end_lineno=1, end_col_offset=24), "
 "lineno=1, col_offset=0, end_lineno=1, end_col_offset=24)], type_ignores=[])"
@@ -677,7 +679,7 @@ def test_dump_indent(self):
 func=Name(id='spam', ctx=Load()),
 args=[
 Name(id='eggs', ctx=Load()),
- Constant(value='and cheese', kind=None)],
+ Constant(value='and cheese')],
 keywords=[]))],
 type_ignores=[])""")
 self.assertEqual(ast.dump(node, annotate_fields=False, indent='\t'), """\
@@ -688,7 +690,7 @@ def test_dump_indent(self):
 \t\t\t\tName('spam', Load()),
 \t\t\t\t[
 \t\t\t\t\tName('eggs', Load()),
-\t\t\t\t\tConstant('and cheese', None)],
+\t\t\t\t\tConstant('and cheese')],
 \t\t\t\t[]))],
 \t[])""")
 self.assertEqual(ast.dump(node, include_attributes=True, indent=3), """\
@@ -713,7 +715,6 @@ def test_dump_indent(self):
 end_col_offset=9),
 Constant(
 value='and cheese',
- kind=None,
 lineno=1,
 col_offset=11,
 end_lineno=1,
@@ -762,7 +763,7 @@ def test_copy_location(self):
 src = ast.parse('1 + 1', mode='eval')
 src.body.right = ast.copy_location(ast.Num(2), src.body.right)
 self.assertEqual(ast.dump(src, include_attributes=True),
- 'Expression(body=BinOp(left=Constant(value=1, kind=None, lineno=1, col_offset=0, '
+ 'Expression(body=BinOp(left=Constant(value=1, lineno=1, col_offset=0, '
 'end_lineno=1, end_col_offset=1), op=Add(), right=Constant(value=2, '
 'lineno=1, col_offset=4, end_lineno=1, end_col_offset=5), lineno=1, '
 'col_offset=0, end_lineno=1, end_col_offset=5))'
@@ -777,7 +778,7 @@ def test_fix_missing_locations(self):
 self.assertEqual(ast.dump(src, include_attributes=True),
 "Module(body=[Expr(value=Call(func=Name(id='write', ctx=Load(), "
 "lineno=1, col_offset=0, end_lineno=1, end_col_offset=5), "
- "args=[Constant(value='spam', kind=None, lineno=1, col_offset=6, end_lineno=1, "
+ "args=[Constant(value='spam', lineno=1, col_offset=6, end_lineno=1, "
 "end_col_offset=12)], keywords=[], lineno=1, col_offset=0, end_lineno=1, "
 "end_col_offset=13), lineno=1, col_offset=0, end_lineno=1, "
 "end_col_offset=13), Expr(value=Call(func=Name(id='spam', ctx=Load(), "
@@ -792,8 +793,8 @@ def test_increment_lineno(self):
 src = ast.parse('1 + 1', mode='eval')
 self.assertEqual(ast.increment_lineno(src, n=3), src)
 self.assertEqual(ast.dump(src, include_attributes=True),
- 'Expression(body=BinOp(left=Constant(value=1, kind=None, lineno=4, col_offset=0, '
- 'end_lineno=4, end_col_offset=1), op=Add(), right=Constant(value=1, kind=None, '
+ 'Expression(body=BinOp(left=Constant(value=1, lineno=4, col_offset=0, '
+ 'end_lineno=4, end_col_offset=1), op=Add(), right=Constant(value=1, '
 'lineno=4, col_offset=4, end_lineno=4, end_col_offset=5), lineno=4, '
 'col_offset=0, end_lineno=4, end_col_offset=5))'
 )
@@ -801,8 +802,8 @@ def test_increment_lineno(self):
 src = ast.parse('1 + 1', mode='eval')
 self.assertEqual(ast.increment_lineno(src.body, n=3), src.body)
 self.assertEqual(ast.dump(src, include_attributes=True),
- 'Expression(body=BinOp(left=Constant(value=1, kind=None, lineno=4, col_offset=0, '
- 'end_lineno=4, end_col_offset=1), op=Add(), right=Constant(value=1, kind=None, '
+ 'Expression(body=BinOp(left=Constant(value=1, lineno=4, col_offset=0, '
+ 'end_lineno=4, end_col_offset=1), op=Add(), right=Constant(value=1, '
 'lineno=4, col_offset=4, end_lineno=4, end_col_offset=5), lineno=4, '
 'col_offset=0, end_lineno=4, end_col_offset=5))'
 )
@@ -821,7 +822,7 @@ def test_iter_child_nodes(self):
 self.assertEqual(next(iterator).value, 23)
 self.assertEqual(next(iterator).value, 42)
 self.assertEqual(ast.dump(next(iterator)),
- "keyword(arg='eggs', value=Constant(value='leek', kind=None))"
+ "keyword(arg='eggs', value=Constant(value='leek'))"
 )
 
 def test_get_docstring(self):
diff --git a/Misc/NEWS.d/next/Library/2020-03-08-09-53-55.bpo-36287.mxr5m8.rst b/Misc/NEWS.d/next/Library/2020-03-08-09-53-55.bpo-36287.mxr5m8.rst
new file mode 100644
index 0000000000000..b7bef3cdf4912
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2020-03-08-09-53-55.bpo-36287.mxr5m8.rst
@@ -0,0 +1,4 @@
+:func:`ast.dump()` no longer outputs optional fields and attributes with
+default values. The default values for optional fields and attributes of
+AST nodes are now set as class attributes (e.g. ``Constant.kind`` is set
+to ``None``).
diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py
index e81506cc9a62d..016c12ddf1497 100755
--- a/Parser/asdl_c.py
+++ b/Parser/asdl_c.py
@@ -957,6 +957,8 @@ def visitProduct(self, prod, name):
 (name, name, len(prod.attributes)), 1)
 else:
 self.emit("if (!add_attributes(state->%s_type, NULL, 0)) return 0;" % name, 1)
+ self.emit_defaults(name, prod.fields, 1)
+ self.emit_defaults(name, prod.attributes, 1)
 
 def visitSum(self, sum, name):
 self.emit('state->%s_type = make_type("%s", state->AST_type, NULL, 0);' %
@@ -968,6 +970,7 @@ def visitSum(self, sum, name):
 (name, name, len(sum.attributes)), 1)
 else:
 self.emit("if (!add_attributes(state->%s_type, NULL, 0)) return 0;" % name, 1)
+ self.emit_defaults(name, sum.attributes, 1)
 simple = is_simple(sum)
 for t in sum.types:
 self.visitConstructor(t, name, simple)
@@ -981,12 +984,20 @@ def visitConstructor(self, cons, name, simple):
 (cons.name, cons.name, name, fields, len(cons.fields)), 1)
 self.emit("if (!state->%s_type) return 0;" % cons.name, 1)
 self.emit_type("%s_type" % cons.name)
+ self.emit_defaults(cons.name, cons.fields, 1)
 if simple:
 self.emit("state->%s_singleton = PyType_GenericNew((PyTypeObject *)"
 "state->%s_type, NULL, NULL);" %
 (cons.name, cons.name), 1)
 self.emit("if (!state->%s_singleton) return 0;" % cons.name, 1)
 
+ def emit_defaults(self, name, fields, depth):
+ for field in fields:
+ if field.opt:
+ self.emit('if (PyObject_SetAttr(state->%s_type, state->%s, Py_None) == -1)' %
+ (name, field.name), depth)
+ self.emit("return 0;", depth+1)
+
 
 class ASTModuleVisitor(PickleVisitor):
 
diff --git a/Python/Python-ast.c b/Python/Python-ast.c
index 2784c427d72dc..47c88b6741771 100644
--- a/Python/Python-ast.c
+++ b/Python/Python-ast.c
@@ -1439,58 +1439,102 @@ static int init_types(void)
 state->stmt_type = make_type("stmt", state->AST_type, NULL, 0);
 if (!state->stmt_type) return 0;
 if (!add_attributes(state->stmt_type, stmt_attributes, 4)) return 0;
+ if (PyObject_SetAttr(state->stmt_type, state->end_lineno, Py_None) == -1)
+ return 0;
+ if (PyObject_SetAttr(state->stmt_type, state->end_col_offset, Py_None) ==
+ -1)
+ return 0;
 state->FunctionDef_type = make_type("FunctionDef", state->stmt_type,
 FunctionDef_fields, 6);
 if (!state->FunctionDef_type) return 0;
+ if (PyObject_SetAttr(state->FunctionDef_type, state->returns, Py_None) ==
+ -1)
+ return 0;
+ if (PyObject_SetAttr(state->FunctionDef_type, state->type_comment, Py_None)
+ == -1)
+ return 0;
 state->AsyncFunctionDef_type = make_type("AsyncFunctionDef",
 state->stmt_type,
 AsyncFunctionDef_fields, 6);
 if (!state->AsyncFunctionDef_type) return 0;
+ if (PyObject_SetAttr(state->AsyncFunctionDef_type, state->returns, Py_None)
+ == -1)
+ return 0;
+ if (PyObject_SetAttr(state->AsyncFunctionDef_type, state->type_comment,
+ Py_None) == -1)
+ return 0;
 state->ClassDef_type = make_type("ClassDef", state->stmt_type,
 ClassDef_fields, 5);
 if (!state->ClassDef_type) return 0;
 state->Return_type = make_type("Return", state->stmt_type, Return_fields,
 1);
 if (!state->Return_type) return 0;
+ if (PyObject_SetAttr(state->Return_type, state->value, Py_None) == -1)
+ return 0;
 state->Delete_type = make_type("Delete", state->stmt_type, Delete_fields,
 1);
 if (!state->Delete_type) return 0;
 state->Assign_type = make_type("Assign", state->stmt_type, Assign_fields,
 3);
 if (!state->Assign_type) return 0;
+ if (PyObject_SetAttr(state->Assign_type, state->type_comment, Py_None) ==
+ -1)
+ return 0;
 state->AugAssign_type = make_type("AugAssign", state->stmt_type,
 AugAssign_fields, 3);
 if (!state->AugAssign_type) return 0;
 state->AnnAssign_type = make_type("AnnAssign", state->stmt_type,
 AnnAssign_fields, 4);
 if (!state->AnnAssign_type) return 0;
+ if (PyObject_SetAttr(state->AnnAssign_type, state->value, Py_None) == -1)
+ return 0;
 state->For_type = make_type("For", state->stmt_type, For_fields, 5);
 if (!state->For_type) return 0;
+ if (PyObject_SetAttr(state->For_type, state->type_comment, Py_None) == -1)
+ return 0;
 state->AsyncFor_type = make_type("AsyncFor", state->stmt_type,
 AsyncFor_fields, 5);
 if (!state->AsyncFor_type) return 0;
+ if (PyObject_SetAttr(state->AsyncFor_type, state->type_comment, Py_None) ==
+ -1)
+ return 0;
 state->While_type = make_type("While", state->stmt_type, While_fields, 3);
 if (!state->While_type) return 0;
 state->If_type = make_type("If", state->stmt_type, If_fields, 3);
 if (!state->If_type) return 0;
 state->With_type = make_type("With", state->stmt_type, With_fields, 3);
 if (!state->With_type) return 0;
+ if (PyObject_SetAttr(state->With_type, state->type_comment, Py_None) == -1)
+ return 0;
 state->AsyncWith_type = make_type("AsyncWith", state->stmt_type,
 AsyncWith_fields, 3);
 if (!state->AsyncWith_type) return 0;
+ if (PyObject_SetAttr(state->AsyncWith_type, state->type_comment, Py_None)
+ == -1)
+ return 0;
 state->Raise_type = make_type("Raise", state->stmt_type, Raise_fields, 2);
 if (!state->Raise_type) return 0;
+ if (PyObject_SetAttr(state->Raise_type, state->exc, Py_None) == -1)
+ return 0;
+ if (PyObject_SetAttr(state->Raise_type, state->cause, Py_None) == -1)
+ return 0;
 state->Try_type = make_type("Try", state->stmt_type, Try_fields, 4);
 if (!state->Try_type) return 0;
 state->Assert_type = make_type("Assert", state->stmt_type, Assert_fields,
 2);
 if (!state->Assert_type) return 0;
+ if (PyObject_SetAttr(state->Assert_type, state->msg, Py_None) == -1)
+ return 0;
 state->Import_type = make_type("Import", state->stmt_type, Import_fields,
 1);
 if (!state->Import_type) return 0;
 state->ImportFrom_type = make_type("ImportFrom", state->stmt_type,
 ImportFrom_fields, 3);
 if (!state->ImportFrom_type) return 0;
+ if (PyObject_SetAttr(state->ImportFrom_type, state->module, Py_None) == -1)
+ return 0;
+ if (PyObject_SetAttr(state->ImportFrom_type, state->level, Py_None) == -1)
+ return 0;
 state->Global_type = make_type("Global", state->stmt_type, Global_fields,
 1);
 if (!state->Global_type) return 0;
@@ -1508,6 +1552,11 @@ static int init_types(void)
 state->expr_type = make_type("expr", state->AST_type, NULL, 0);
 if (!state->expr_type) return 0;
 if (!add_attributes(state->expr_type, expr_attributes, 4)) return 0;
+ if (PyObject_SetAttr(state->expr_type, state->end_lineno, Py_None) == -1)
+ return 0;
+ if (PyObject_SetAttr(state->expr_type, state->end_col_offset, Py_None) ==
+ -1)
+ return 0;
 state->BoolOp_type = make_type("BoolOp", state->expr_type, BoolOp_fields,
 2);
 if (!state->BoolOp_type) return 0;
@@ -1544,6 +1593,8 @@ static int init_types(void)
 if (!state->Await_type) return 0;
 state->Yield_type = make_type("Yield", state->expr_type, Yield_fields, 1);
 if (!state->Yield_type) return 0;
+ if (PyObject_SetAttr(state->Yield_type, state->value, Py_None) == -1)
+ return 0;
 state->YieldFrom_type = make_type("YieldFrom", state->expr_type,
 YieldFrom_fields, 1);
 if (!state->YieldFrom_type) return 0;
@@ -1555,12 +1606,20 @@ static int init_types(void)
 state->FormattedValue_type = make_type("FormattedValue", state->expr_type,
 FormattedValue_fields, 3);
 if (!state->FormattedValue_type) return 0;
+ if (PyObject_SetAttr(state->FormattedValue_type, state->conversion,
+ Py_None) == -1)
+ return 0;
+ if (PyObject_SetAttr(state->FormattedValue_type, state->format_spec,
+ Py_None) == -1)
+ return 0;
 state->JoinedStr_type = make_type("JoinedStr", state->expr_type,
 JoinedStr_fields, 1);
 if (!state->JoinedStr_type) return 0;
 state->Constant_type = make_type("Constant", state->expr_type,
 Constant_fields, 2);
 if (!state->Constant_type) return 0;
+ if (PyObject_SetAttr(state->Constant_type, state->kind, Py_None) == -1)
+ return 0;
 state->Attribute_type = make_type("Attribute", state->expr_type,
 Attribute_fields, 3);
 if (!state->Attribute_type) return 0;
@@ -1619,6 +1678,12 @@ static int init_types(void)
 if (!add_attributes(state->slice_type, NULL, 0)) return 0;
 state->Slice_type = make_type("Slice", state->slice_type, Slice_fields, 3);
 if (!state->Slice_type) return 0;
+ if (PyObject_SetAttr(state->Slice_type, state->lower, Py_None) == -1)
+ return 0;
+ if (PyObject_SetAttr(state->Slice_type, state->upper, Py_None) == -1)
+ return 0;
+ if (PyObject_SetAttr(state->Slice_type, state->step, Py_None) == -1)
+ return 0;
 state->ExtSlice_type = make_type("ExtSlice", state->slice_type,
 ExtSlice_fields, 1);
 if (!state->ExtSlice_type) return 0;
@@ -1797,28 +1862,57 @@ static int init_types(void)
 if (!state->excepthandler_type) return 0;
 if (!add_attributes(state->excepthandler_type, excepthandler_attributes,
 4)) return 0;
+ if (PyObject_SetAttr(state->excepthandler_type, state->end_lineno, Py_None)
+ == -1)
+ return 0;
+ if (PyObject_SetAttr(state->excepthandler_type, state->end_col_offset,
+ Py_None) == -1)
+ return 0;
 state->ExceptHandler_type = make_type("ExceptHandler",
 state->excepthandler_type,
 ExceptHandler_fields, 3);
 if (!state->ExceptHandler_type) return 0;
+ if (PyObject_SetAttr(state->ExceptHandler_type, state->type, Py_None) == -1)
+ return 0;
+ if (PyObject_SetAttr(state->ExceptHandler_type, state->name, Py_None) == -1)
+ return 0;
 state->arguments_type = make_type("arguments", state->AST_type,
 arguments_fields, 7);
 if (!state->arguments_type) return 0;
 if (!add_attributes(state->arguments_type, NULL, 0)) return 0;
+ if (PyObject_SetAttr(state->arguments_type, state->vararg, Py_None) == -1)
+ return 0;
+ if (PyObject_SetAttr(state->arguments_type, state->kwarg, Py_None) == -1)
+ return 0;
 state->arg_type = make_type("arg", state->AST_type, arg_fields, 3);
 if (!state->arg_type) return 0;
 if (!add_attributes(state->arg_type, arg_attributes, 4)) return 0;
+ if (PyObject_SetAttr(state->arg_type, state->annotation, Py_None) == -1)
+ return 0;
+ if (PyObject_SetAttr(state->arg_type, state->type_comment, Py_None) == -1)
+ return 0;
+ if (PyObject_SetAttr(state->arg_type, state->end_lineno, Py_None) == -1)
+ return 0;
+ if (PyObject_SetAttr(state->arg_type, state->end_col_offset, Py_None) == -1)
+ return 0;
 state->keyword_type = make_type("keyword", state->AST_type, keyword_fields,
 2);
 if (!state->keyword_type) return 0;
 if (!add_attributes(state->keyword_type, NULL, 0)) return 0;
+ if (PyObject_SetAttr(state->keyword_type, state->arg, Py_None) == -1)
+ return 0;
 state->alias_type = make_type("alias", state->AST_type, alias_fields, 2);
 if (!state->alias_type) return 0;
 if (!add_attributes(state->alias_type, NULL, 0)) return 0;
+ if (PyObject_SetAttr(state->alias_type, state->asname, Py_None) == -1)
+ return 0;
 state->withitem_type = make_type("withitem", state->AST_type,
 withitem_fields, 2);
 if (!state->withitem_type) return 0;
 if (!add_attributes(state->withitem_type, NULL, 0)) return 0;
+ if (PyObject_SetAttr(state->withitem_type, state->optional_vars, Py_None)
+ == -1)
+ return 0;
 state->type_ignore_type = make_type("type_ignore", state->AST_type, NULL,
 0);
 if (!state->type_ignore_type) return 0;


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /