Skip to content

Commit 8177525

Browse files
authored
Update ast.py from 3.13.5 (#6006)
1 parent 4e0c1aa commit 8177525

File tree

9 files changed

+4468
-3280
lines changed

9 files changed

+4468
-3280
lines changed

Lib/ast.py

Lines changed: 78 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,24 @@
11
"""
2-
ast
3-
~~~
4-
5-
The `ast` module helps Python applications to process trees of the Python
6-
abstract syntax grammar. The abstract syntax itself might change with
7-
each Python release; this module helps to find out programmatically what
8-
the current grammar looks like and allows modifications of it.
9-
10-
An abstract syntax tree can be generated by passing `ast.PyCF_ONLY_AST` as
11-
a flag to the `compile()` builtin function or by using the `parse()`
12-
function from this module. The result will be a tree of objects whose
13-
classes all inherit from `ast.AST`.
14-
15-
A modified abstract syntax tree can be compiled into a Python code object
16-
using the built-in `compile()` function.
17-
18-
Additionally various helper functions are provided that make working with
19-
the trees simpler. The main intention of the helper functions and this
20-
module in general is to provide an easy to use interface for libraries
21-
that work tightly with the python syntax (template engines for example).
22-
23-
24-
:copyright: Copyright 2008 by Armin Ronacher.
25-
:license: Python License.
2+
The `ast` module helps Python applications to process trees of the Python
3+
abstract syntax grammar. The abstract syntax itself might change with
4+
each Python release; this module helps to find out programmatically what
5+
the current grammar looks like and allows modifications of it.
6+
7+
An abstract syntax tree can be generated by passing `ast.PyCF_ONLY_AST` as
8+
a flag to the `compile()` builtin function or by using the `parse()`
9+
function from this module. The result will be a tree of objects whose
10+
classes all inherit from `ast.AST`.
11+
12+
A modified abstract syntax tree can be compiled into a Python code object
13+
using the built-in `compile()` function.
14+
15+
Additionally various helper functions are provided that make working with
16+
the trees simpler. The main intention of the helper functions and this
17+
module in general is to provide an easy to use interface for libraries
18+
that work tightly with the python syntax (template engines for example).
19+
20+
:copyright: Copyright 2008 by Armin Ronacher.
21+
:license: Python License.
2622
"""
2723
import sys
2824
import re
@@ -32,13 +28,15 @@
3228

3329

3430
def parse(source, filename='<unknown>', mode='exec', *,
35-
type_comments=False, feature_version=None):
31+
type_comments=False, feature_version=None, optimize=-1):
3632
"""
3733
Parse the source into an AST node.
3834
Equivalent to compile(source, filename, mode, PyCF_ONLY_AST).
3935
Pass type_comments=True to get back type comments where the syntax allows.
4036
"""
4137
flags = PyCF_ONLY_AST
38+
if optimize > 0:
39+
flags |= PyCF_OPTIMIZED_AST
4240
if type_comments:
4341
flags |= PyCF_TYPE_COMMENTS
4442
if feature_version is None:
@@ -50,7 +48,7 @@ def parse(source, filename='<unknown>', mode='exec', *,
5048
feature_version = minor
5149
# Else it should be an int giving the minor version for 3.x.
5250
return compile(source, filename, mode, flags,
53-
_feature_version=feature_version)
51+
_feature_version=feature_version, optimize=optimize)
5452

5553

5654
def literal_eval(node_or_string):
@@ -112,7 +110,11 @@ def _convert(node):
112110
return _convert(node_or_string)
113111

114112

115-
def dump(node, annotate_fields=True, include_attributes=False, *, indent=None):
113+
def dump(
114+
node, annotate_fields=True, include_attributes=False,
115+
*,
116+
indent=None, show_empty=False,
117+
):
116118
"""
117119
Return a formatted dump of the tree in node. This is mainly useful for
118120
debugging purposes. If annotate_fields is true (by default),
@@ -123,6 +125,8 @@ def dump(node, annotate_fields=True, include_attributes=False, *, indent=None):
123125
include_attributes can be set to true. If indent is a non-negative
124126
integer or string, then the tree will be pretty-printed with that indent
125127
level. None (the default) selects the single line representation.
128+
If show_empty is False, then empty lists and fields that are None
129+
will be omitted from the output for better readability.
126130
"""
127131
def _format(node, level=0):
128132
if indent is not None:
@@ -135,6 +139,7 @@ def _format(node, level=0):
135139
if isinstance(node, AST):
136140
cls = type(node)
137141
args = []
142+
args_buffer = []
138143
allsimple = True
139144
keywords = annotate_fields
140145
for name in node._fields:
@@ -146,6 +151,16 @@ def _format(node, level=0):
146151
if value is None and getattr(cls, name, ...) is None:
147152
keywords = True
148153
continue
154+
if not show_empty:
155+
if value == []:
156+
field_type = cls._field_types.get(name, object)
157+
if getattr(field_type, '__origin__', ...) is list:
158+
if not keywords:
159+
args_buffer.append(repr(value))
160+
continue
161+
if not keywords:
162+
args.extend(args_buffer)
163+
args_buffer = []
149164
value, simple = _format(value, level)
150165
allsimple = allsimple and simple
151166
if keywords:
@@ -726,12 +741,11 @@ class _Unparser(NodeVisitor):
726741
output source code for the abstract syntax; original formatting
727742
is disregarded."""
728743

729-
def __init__(self, *, _avoid_backslashes=False):
744+
def __init__(self):
730745
self._source = []
731746
self._precedences = {}
732747
self._type_ignores = {}
733748
self._indent = 0
734-
self._avoid_backslashes = _avoid_backslashes
735749
self._in_try_star = False
736750

737751
def interleave(self, inter, f, seq):
@@ -1104,12 +1118,21 @@ def visit_TypeVar(self, node):
11041118
if node.bound:
11051119
self.write(": ")
11061120
self.traverse(node.bound)
1121+
if node.default_value:
1122+
self.write(" = ")
1123+
self.traverse(node.default_value)
11071124

11081125
def visit_TypeVarTuple(self, node):
11091126
self.write("*" + node.name)
1127+
if node.default_value:
1128+
self.write(" = ")
1129+
self.traverse(node.default_value)
11101130

11111131
def visit_ParamSpec(self, node):
11121132
self.write("**" + node.name)
1133+
if node.default_value:
1134+
self.write(" = ")
1135+
self.traverse(node.default_value)
11131136

11141137
def visit_TypeAlias(self, node):
11151138
self.fill("type ")
@@ -1246,9 +1269,14 @@ def visit_JoinedStr(self, node):
12461269
fallback_to_repr = True
12471270
break
12481271
quote_types = new_quote_types
1249-
elif "\n" in value:
1250-
quote_types = [q for q in quote_types if q in _MULTI_QUOTES]
1251-
assert quote_types
1272+
else:
1273+
if "\n" in value:
1274+
quote_types = [q for q in quote_types if q in _MULTI_QUOTES]
1275+
assert quote_types
1276+
1277+
new_quote_types = [q for q in quote_types if q not in value]
1278+
if new_quote_types:
1279+
quote_types = new_quote_types
12521280
new_fstring_parts.append(value)
12531281

12541282
if fallback_to_repr:
@@ -1268,13 +1296,19 @@ def visit_JoinedStr(self, node):
12681296
quote_type = quote_types[0]
12691297
self.write(f"{quote_type}{value}{quote_type}")
12701298

1271-
def _write_fstring_inner(self, node):
1299+
def _write_fstring_inner(self, node, is_format_spec=False):
12721300
if isinstance(node, JoinedStr):
12731301
# for both the f-string itself, and format_spec
12741302
for value in node.values:
1275-
self._write_fstring_inner(value)
1303+
self._write_fstring_inner(value, is_format_spec=is_format_spec)
12761304
elif isinstance(node, Constant) and isinstance(node.value, str):
12771305
value = node.value.replace("{", "{{").replace("}", "}}")
1306+
1307+
if is_format_spec:
1308+
value = value.replace("\\", "\\\\")
1309+
value = value.replace("'", "\\'")
1310+
value = value.replace('"', '\\"')
1311+
value = value.replace("\n", "\\n")
12781312
self.write(value)
12791313
elif isinstance(node, FormattedValue):
12801314
self.visit_FormattedValue(node)
@@ -1297,7 +1331,7 @@ def unparse_inner(inner):
12971331
self.write(f"!{chr(node.conversion)}")
12981332
if node.format_spec:
12991333
self.write(":")
1300-
self._write_fstring_inner(node.format_spec)
1334+
self._write_fstring_inner(node.format_spec, is_format_spec=True)
13011335

13021336
def visit_Name(self, node):
13031337
self.write(node.id)
@@ -1317,8 +1351,6 @@ def _write_constant(self, value):
13171351
.replace("inf", _INFSTR)
13181352
.replace("nan", f"({_INFSTR}-{_INFSTR})")
13191353
)
1320-
elif self._avoid_backslashes and isinstance(value, str):
1321-
self._write_str_avoiding_backslashes(value)
13221354
else:
13231355
self.write(repr(value))
13241356

@@ -1805,8 +1837,7 @@ def main():
18051837
import argparse
18061838

18071839
parser = argparse.ArgumentParser(prog='python -m ast')
1808-
parser.add_argument('infile', type=argparse.FileType(mode='rb'), nargs='?',
1809-
default='-',
1840+
parser.add_argument('infile', nargs='?', default='-',
18101841
help='the file to parse; defaults to stdin')
18111842
parser.add_argument('-m', '--mode', default='exec',
18121843
choices=('exec', 'single', 'eval', 'func_type'),
@@ -1820,9 +1851,14 @@ def main():
18201851
help='indentation of nodes (number of spaces)')
18211852
args = parser.parse_args()
18221853

1823-
with args.infile as infile:
1824-
source = infile.read()
1825-
tree = parse(source, args.infile.name, args.mode, type_comments=args.no_type_comments)
1854+
if args.infile == '-':
1855+
name = '<stdin>'
1856+
source = sys.stdin.buffer.read()
1857+
else:
1858+
name = args.infile
1859+
with open(args.infile, 'rb') as infile:
1860+
source = infile.read()
1861+
tree = parse(source, name, args.mode, type_comments=args.no_type_comments)
18261862
print(dump(tree, include_attributes=args.include_attributes, indent=args.indent))
18271863

18281864
if __name__ == '__main__':

0 commit comments

Comments
 (0)