python-minifier 2.11.2__py2-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- python_minifier/__init__.py +269 -0
- python_minifier/__init__.pyi +37 -0
- python_minifier/__main__.py +332 -0
- python_minifier/ast_compare.py +104 -0
- python_minifier/ast_compat.py +40 -0
- python_minifier/ast_printer.py +130 -0
- python_minifier/expression_printer.py +753 -0
- python_minifier/f_string.py +446 -0
- python_minifier/ministring.py +179 -0
- python_minifier/module_printer.py +862 -0
- python_minifier/py.typed +0 -0
- python_minifier/rename/__init__.py +6 -0
- python_minifier/rename/bind_names.py +192 -0
- python_minifier/rename/binding.py +495 -0
- python_minifier/rename/mapper.py +175 -0
- python_minifier/rename/name_generator.py +51 -0
- python_minifier/rename/rename_literals.py +249 -0
- python_minifier/rename/renamer.py +230 -0
- python_minifier/rename/resolve_names.py +106 -0
- python_minifier/rename/util.py +203 -0
- python_minifier/token_printer.py +299 -0
- python_minifier/transforms/__init__.py +0 -0
- python_minifier/transforms/combine_imports.py +76 -0
- python_minifier/transforms/constant_folding.py +114 -0
- python_minifier/transforms/remove_annotations.py +130 -0
- python_minifier/transforms/remove_annotations_options.py +35 -0
- python_minifier/transforms/remove_annotations_options.pyi +17 -0
- python_minifier/transforms/remove_asserts.py +26 -0
- python_minifier/transforms/remove_debug.py +53 -0
- python_minifier/transforms/remove_exception_brackets.py +124 -0
- python_minifier/transforms/remove_explicit_return_none.py +38 -0
- python_minifier/transforms/remove_literal_statements.py +61 -0
- python_minifier/transforms/remove_object_base.py +24 -0
- python_minifier/transforms/remove_pass.py +26 -0
- python_minifier/transforms/remove_posargs.py +13 -0
- python_minifier/transforms/suite_transformer.py +196 -0
- python_minifier/util.py +48 -0
- python_minifier-2.11.2.dist-info/LICENSE +21 -0
- python_minifier-2.11.2.dist-info/METADATA +177 -0
- python_minifier-2.11.2.dist-info/RECORD +44 -0
- python_minifier-2.11.2.dist-info/WHEEL +5 -0
- python_minifier-2.11.2.dist-info/entry_points.txt +3 -0
- python_minifier-2.11.2.dist-info/top_level.txt +1 -0
- python_minifier-2.11.2.dist-info/zip-safe +1 -0
|
@@ -0,0 +1,862 @@
|
|
|
1
|
+
import python_minifier.ast_compat as ast
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from .expression_printer import ExpressionPrinter
|
|
5
|
+
from .token_printer import Delimiter
|
|
6
|
+
from .util import is_ast_node
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ModulePrinter(ExpressionPrinter):
|
|
10
|
+
"""
|
|
11
|
+
Builds the smallest possible exact representation of an ast
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def __init__(self, indent_char='\t'):
|
|
15
|
+
super(ModulePrinter, self).__init__()
|
|
16
|
+
self.indent_char = indent_char
|
|
17
|
+
|
|
18
|
+
def __call__(self, module):
|
|
19
|
+
"""
|
|
20
|
+
Generate the source code for an AST
|
|
21
|
+
|
|
22
|
+
:param module: The Module to generate code for
|
|
23
|
+
:type module: ast.Module
|
|
24
|
+
:rtype: str
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
assert isinstance(module, ast.Module)
|
|
29
|
+
|
|
30
|
+
self.visit_Module(module)
|
|
31
|
+
return str(self.printer).rstrip('\n' + self.indent_char + ';')
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def code(self):
|
|
35
|
+
return str(self.printer).rstrip('\n' + self.indent_char + ';')
|
|
36
|
+
|
|
37
|
+
# region Simple Statements
|
|
38
|
+
|
|
39
|
+
def visit_Exec(self, node):
|
|
40
|
+
assert isinstance(node, ast.Exec)
|
|
41
|
+
|
|
42
|
+
self.printer.keyword('exec')
|
|
43
|
+
self._expression(node.body)
|
|
44
|
+
|
|
45
|
+
if node.globals:
|
|
46
|
+
self.printer.keyword('in')
|
|
47
|
+
self._expression(node.globals)
|
|
48
|
+
|
|
49
|
+
if node.locals:
|
|
50
|
+
self.printer.delimiter(',')
|
|
51
|
+
self._expression(node.locals)
|
|
52
|
+
|
|
53
|
+
self.printer.end_statement()
|
|
54
|
+
|
|
55
|
+
def visit_Expr(self, node):
|
|
56
|
+
assert isinstance(node, ast.Expr)
|
|
57
|
+
|
|
58
|
+
if is_ast_node(node.value, (ast.Yield, 'YieldFrom')):
|
|
59
|
+
self._yield_expr(node.value)
|
|
60
|
+
else:
|
|
61
|
+
self._testlist(node.value)
|
|
62
|
+
|
|
63
|
+
self.printer.end_statement()
|
|
64
|
+
|
|
65
|
+
def visit_Assert(self, node):
|
|
66
|
+
assert isinstance(node, ast.Assert)
|
|
67
|
+
|
|
68
|
+
self.printer.keyword('assert')
|
|
69
|
+
self._expression(node.test)
|
|
70
|
+
|
|
71
|
+
if node.msg:
|
|
72
|
+
self.printer.delimiter(',')
|
|
73
|
+
self._expression(node.msg)
|
|
74
|
+
|
|
75
|
+
self.printer.end_statement()
|
|
76
|
+
|
|
77
|
+
def visit_Assign(self, node):
|
|
78
|
+
assert isinstance(node, ast.Assign)
|
|
79
|
+
|
|
80
|
+
for target_node in node.targets:
|
|
81
|
+
self._testlist(target_node)
|
|
82
|
+
self.printer.delimiter('=')
|
|
83
|
+
|
|
84
|
+
# Yield nodes that are the sole node on the right hand side of an assignment do not need parens
|
|
85
|
+
if is_ast_node(node.value, (ast.Yield, 'YieldFrom')):
|
|
86
|
+
self._yield_expr(node.value)
|
|
87
|
+
else:
|
|
88
|
+
self._testlist(node.value)
|
|
89
|
+
|
|
90
|
+
self.printer.end_statement()
|
|
91
|
+
|
|
92
|
+
def visit_AugAssign(self, node):
|
|
93
|
+
assert isinstance(node, ast.AugAssign)
|
|
94
|
+
|
|
95
|
+
self._testlist(node.target)
|
|
96
|
+
self.visit(node.op)
|
|
97
|
+
self.printer.delimiter('=')
|
|
98
|
+
|
|
99
|
+
# Yield nodes that are the sole node on the right hand side of an assignment do not need parens
|
|
100
|
+
if is_ast_node(node.value, (ast.Yield, 'YieldFrom')):
|
|
101
|
+
self._yield_expr(node.value)
|
|
102
|
+
else:
|
|
103
|
+
self._testlist(node.value)
|
|
104
|
+
|
|
105
|
+
self.printer.end_statement()
|
|
106
|
+
|
|
107
|
+
def visit_AnnAssign(self, node):
|
|
108
|
+
assert isinstance(node, ast.AnnAssign)
|
|
109
|
+
|
|
110
|
+
if node.simple:
|
|
111
|
+
self.visit(node.target)
|
|
112
|
+
else:
|
|
113
|
+
self.printer.delimiter('(')
|
|
114
|
+
self._expression(node.target)
|
|
115
|
+
self.printer.delimiter(')')
|
|
116
|
+
|
|
117
|
+
if node.annotation:
|
|
118
|
+
self.printer.delimiter(':')
|
|
119
|
+
self._expression(node.annotation)
|
|
120
|
+
|
|
121
|
+
if node.value:
|
|
122
|
+
self.printer.delimiter('=')
|
|
123
|
+
|
|
124
|
+
self._expression(node.value)
|
|
125
|
+
|
|
126
|
+
self.printer.end_statement()
|
|
127
|
+
|
|
128
|
+
def visit_Pass(self, node):
|
|
129
|
+
assert isinstance(node, ast.Pass)
|
|
130
|
+
|
|
131
|
+
self.printer.keyword('pass')
|
|
132
|
+
self.printer.end_statement()
|
|
133
|
+
|
|
134
|
+
def visit_Delete(self, node):
|
|
135
|
+
assert isinstance(node, ast.Delete)
|
|
136
|
+
|
|
137
|
+
self.printer.keyword('del')
|
|
138
|
+
self._exprlist(node.targets)
|
|
139
|
+
self.printer.end_statement()
|
|
140
|
+
|
|
141
|
+
def visit_Return(self, node):
|
|
142
|
+
assert isinstance(node, ast.Return)
|
|
143
|
+
|
|
144
|
+
self.printer.keyword('return')
|
|
145
|
+
if isinstance(node.value, ast.Tuple):
|
|
146
|
+
if sys.version_info < (3, 8) and [n for n in node.value.elts if is_ast_node(n, 'Starred')]:
|
|
147
|
+
self.printer.delimiter('(')
|
|
148
|
+
self._testlist(node.value)
|
|
149
|
+
self.printer.delimiter(')')
|
|
150
|
+
else:
|
|
151
|
+
self._testlist(node.value)
|
|
152
|
+
elif node.value is not None:
|
|
153
|
+
self._testlist(node.value)
|
|
154
|
+
self.printer.end_statement()
|
|
155
|
+
|
|
156
|
+
def visit_Print(self, node):
|
|
157
|
+
assert isinstance(node, ast.Print)
|
|
158
|
+
|
|
159
|
+
self.printer.keyword('print')
|
|
160
|
+
|
|
161
|
+
delimiter = Delimiter(self.printer)
|
|
162
|
+
|
|
163
|
+
if node.dest:
|
|
164
|
+
delimiter.new_item()
|
|
165
|
+
self.printer.operator('>>')
|
|
166
|
+
self._expression(node.dest)
|
|
167
|
+
|
|
168
|
+
for v in node.values:
|
|
169
|
+
delimiter.new_item()
|
|
170
|
+
self._expression(v)
|
|
171
|
+
|
|
172
|
+
if not node.nl:
|
|
173
|
+
self.printer.delimiter(',')
|
|
174
|
+
|
|
175
|
+
self.printer.end_statement()
|
|
176
|
+
|
|
177
|
+
def visit_Yield(self, node):
|
|
178
|
+
assert isinstance(node, ast.Yield)
|
|
179
|
+
|
|
180
|
+
self._yield_expr(node)
|
|
181
|
+
self.printer.end_statement()
|
|
182
|
+
|
|
183
|
+
def visit_YieldFrom(self, node):
|
|
184
|
+
assert isinstance(node, ast.YieldFrom)
|
|
185
|
+
|
|
186
|
+
self._yield_expr(node)
|
|
187
|
+
self.printer.end_statement()
|
|
188
|
+
|
|
189
|
+
def visit_Raise(self, node):
|
|
190
|
+
assert isinstance(node, ast.Raise)
|
|
191
|
+
|
|
192
|
+
self.printer.keyword('raise')
|
|
193
|
+
|
|
194
|
+
if hasattr(node, 'type'):
|
|
195
|
+
# Python2 raise node
|
|
196
|
+
|
|
197
|
+
if node.type:
|
|
198
|
+
self._expression(node.type)
|
|
199
|
+
if node.inst:
|
|
200
|
+
self.printer.delimiter(',')
|
|
201
|
+
self._expression(node.inst)
|
|
202
|
+
if node.tback:
|
|
203
|
+
self.printer.delimiter(',')
|
|
204
|
+
self._expression(node.tback)
|
|
205
|
+
|
|
206
|
+
else:
|
|
207
|
+
# Python3
|
|
208
|
+
|
|
209
|
+
if node.exc:
|
|
210
|
+
self._expression(node.exc)
|
|
211
|
+
|
|
212
|
+
if node.cause:
|
|
213
|
+
self.printer.keyword('from')
|
|
214
|
+
self._expression(node.cause)
|
|
215
|
+
|
|
216
|
+
self.printer.end_statement()
|
|
217
|
+
|
|
218
|
+
def visit_Break(self, node):
|
|
219
|
+
assert isinstance(node, ast.Break)
|
|
220
|
+
|
|
221
|
+
self.printer.keyword('break')
|
|
222
|
+
self.printer.end_statement()
|
|
223
|
+
|
|
224
|
+
def visit_Continue(self, node):
|
|
225
|
+
assert isinstance(node, ast.Continue)
|
|
226
|
+
|
|
227
|
+
self.printer.keyword('continue')
|
|
228
|
+
self.printer.end_statement()
|
|
229
|
+
|
|
230
|
+
def visit_Import(self, node):
|
|
231
|
+
assert isinstance(node, ast.Import)
|
|
232
|
+
|
|
233
|
+
self.printer.keyword('import')
|
|
234
|
+
|
|
235
|
+
delimiter = Delimiter(self.printer)
|
|
236
|
+
for n in node.names:
|
|
237
|
+
delimiter.new_item()
|
|
238
|
+
self.visit_alias(n)
|
|
239
|
+
|
|
240
|
+
self.printer.end_statement()
|
|
241
|
+
|
|
242
|
+
def visit_ImportFrom(self, node):
|
|
243
|
+
assert isinstance(node, ast.ImportFrom)
|
|
244
|
+
|
|
245
|
+
self.printer.keyword('from')
|
|
246
|
+
for i in range(node.level):
|
|
247
|
+
self.printer.delimiter('.')
|
|
248
|
+
if node.module is not None:
|
|
249
|
+
self.printer.identifier(node.module)
|
|
250
|
+
|
|
251
|
+
self.printer.keyword('import')
|
|
252
|
+
|
|
253
|
+
delimiter = Delimiter(self.printer)
|
|
254
|
+
for n in node.names:
|
|
255
|
+
delimiter.new_item()
|
|
256
|
+
|
|
257
|
+
if node.module == '__future__' and n.name == 'unicode_literals':
|
|
258
|
+
self.printer.unicode_literals = True
|
|
259
|
+
|
|
260
|
+
if n.name == '*':
|
|
261
|
+
self.printer.operator('*')
|
|
262
|
+
else:
|
|
263
|
+
self.visit_alias(n)
|
|
264
|
+
|
|
265
|
+
self.printer.end_statement()
|
|
266
|
+
|
|
267
|
+
def visit_alias(self, node):
|
|
268
|
+
assert isinstance(node, ast.alias)
|
|
269
|
+
|
|
270
|
+
self.printer.identifier(node.name)
|
|
271
|
+
|
|
272
|
+
if node.asname:
|
|
273
|
+
self.printer.keyword('as')
|
|
274
|
+
self.printer.identifier(node.asname)
|
|
275
|
+
|
|
276
|
+
def visit_Global(self, node):
|
|
277
|
+
assert isinstance(node, ast.Global)
|
|
278
|
+
|
|
279
|
+
self.printer.keyword('global')
|
|
280
|
+
delimiter = Delimiter(self.printer)
|
|
281
|
+
for n in node.names:
|
|
282
|
+
delimiter.new_item()
|
|
283
|
+
self.printer.identifier(n)
|
|
284
|
+
|
|
285
|
+
self.printer.end_statement()
|
|
286
|
+
|
|
287
|
+
def visit_Nonlocal(self, node):
|
|
288
|
+
assert isinstance(node, ast.Nonlocal)
|
|
289
|
+
|
|
290
|
+
self.printer.keyword('nonlocal')
|
|
291
|
+
delimiter = Delimiter(self.printer)
|
|
292
|
+
for n in node.names:
|
|
293
|
+
delimiter.new_item()
|
|
294
|
+
self.printer.identifier(n)
|
|
295
|
+
|
|
296
|
+
self.printer.end_statement()
|
|
297
|
+
|
|
298
|
+
# endregion
|
|
299
|
+
|
|
300
|
+
# region Compound Statements
|
|
301
|
+
|
|
302
|
+
def visit_If(self, node, el=False):
|
|
303
|
+
assert isinstance(node, ast.If)
|
|
304
|
+
|
|
305
|
+
self.printer.newline()
|
|
306
|
+
|
|
307
|
+
if el:
|
|
308
|
+
self.printer.keyword('elif')
|
|
309
|
+
else:
|
|
310
|
+
self.printer.keyword('if')
|
|
311
|
+
|
|
312
|
+
self._expression(node.test)
|
|
313
|
+
self.printer.delimiter(':')
|
|
314
|
+
|
|
315
|
+
self._suite(node.body)
|
|
316
|
+
|
|
317
|
+
if node.orelse:
|
|
318
|
+
if len(node.orelse) == 1 and isinstance(node.orelse[0], ast.If):
|
|
319
|
+
# elif
|
|
320
|
+
self.visit_If(node.orelse[0], el=True)
|
|
321
|
+
self.printer.newline()
|
|
322
|
+
else:
|
|
323
|
+
# an else block
|
|
324
|
+
self.printer.keyword('else')
|
|
325
|
+
self.printer.delimiter(':')
|
|
326
|
+
self._suite(node.orelse)
|
|
327
|
+
|
|
328
|
+
def visit_For(self, node, is_async=False):
|
|
329
|
+
assert isinstance(node, ast.For) or (hasattr(ast, 'AsyncFor') and isinstance(node, ast.AsyncFor))
|
|
330
|
+
|
|
331
|
+
self.printer.newline()
|
|
332
|
+
|
|
333
|
+
if is_async:
|
|
334
|
+
self.printer.keyword('async')
|
|
335
|
+
|
|
336
|
+
self.printer.keyword('for')
|
|
337
|
+
self._exprlist([node.target])
|
|
338
|
+
self.printer.keyword('in')
|
|
339
|
+
self._expression(node.iter)
|
|
340
|
+
self.printer.delimiter(':')
|
|
341
|
+
|
|
342
|
+
self._suite(node.body)
|
|
343
|
+
|
|
344
|
+
if node.orelse:
|
|
345
|
+
self.printer.newline()
|
|
346
|
+
self.printer.keyword('else')
|
|
347
|
+
self.printer.delimiter(':')
|
|
348
|
+
self._suite(node.orelse)
|
|
349
|
+
|
|
350
|
+
def visit_While(self, node):
|
|
351
|
+
assert isinstance(node, ast.While)
|
|
352
|
+
|
|
353
|
+
self.printer.newline()
|
|
354
|
+
self.printer.keyword('while')
|
|
355
|
+
self._expression(node.test)
|
|
356
|
+
self.printer.delimiter(':')
|
|
357
|
+
self._suite(node.body)
|
|
358
|
+
|
|
359
|
+
if node.orelse:
|
|
360
|
+
self.printer.keyword('else')
|
|
361
|
+
self.printer.delimiter(':')
|
|
362
|
+
self._suite(node.orelse)
|
|
363
|
+
|
|
364
|
+
def visit_Try(self, node, star=False):
|
|
365
|
+
assert is_ast_node(node, (ast.Try, 'TryStar'))
|
|
366
|
+
|
|
367
|
+
self.printer.newline()
|
|
368
|
+
self.printer.keyword('try')
|
|
369
|
+
self.printer.delimiter(':')
|
|
370
|
+
self._suite(node.body)
|
|
371
|
+
|
|
372
|
+
[self.visit_ExceptHandler(n, star) for n in node.handlers]
|
|
373
|
+
|
|
374
|
+
if node.orelse:
|
|
375
|
+
self.printer.keyword('else')
|
|
376
|
+
self.printer.delimiter(':')
|
|
377
|
+
self._suite(node.orelse)
|
|
378
|
+
|
|
379
|
+
if node.finalbody:
|
|
380
|
+
self.printer.keyword('finally')
|
|
381
|
+
self.printer.delimiter(':')
|
|
382
|
+
self._suite(node.finalbody)
|
|
383
|
+
|
|
384
|
+
def visit_TryStar(self, node):
|
|
385
|
+
assert isinstance(node, ast.TryStar)
|
|
386
|
+
self.visit_Try(node, star=True)
|
|
387
|
+
|
|
388
|
+
def visit_TryFinally(self, node):
|
|
389
|
+
assert isinstance(node, ast.TryFinally)
|
|
390
|
+
|
|
391
|
+
if len(node.body) == 1 and isinstance(node.body[0], ast.TryExcept):
|
|
392
|
+
self.visit_TryExcept(node.body[0])
|
|
393
|
+
else:
|
|
394
|
+
self.printer.newline()
|
|
395
|
+
self.printer.keyword('try')
|
|
396
|
+
self.printer.delimiter(':')
|
|
397
|
+
self._suite(node.body)
|
|
398
|
+
|
|
399
|
+
if node.finalbody:
|
|
400
|
+
self.printer.keyword('finally')
|
|
401
|
+
self.printer.delimiter(':')
|
|
402
|
+
self._suite(node.finalbody)
|
|
403
|
+
|
|
404
|
+
def visit_TryExcept(self, node):
|
|
405
|
+
assert isinstance(node, ast.TryExcept)
|
|
406
|
+
|
|
407
|
+
self.printer.newline()
|
|
408
|
+
self.printer.keyword('try')
|
|
409
|
+
self.printer.delimiter(':')
|
|
410
|
+
self._suite(node.body)
|
|
411
|
+
|
|
412
|
+
[self.visit_ExceptHandler(n) for n in node.handlers]
|
|
413
|
+
|
|
414
|
+
if node.orelse:
|
|
415
|
+
self.printer.keyword('else')
|
|
416
|
+
self.printer.delimiter(':')
|
|
417
|
+
self._suite(node.orelse)
|
|
418
|
+
|
|
419
|
+
def visit_ExceptHandler(self, node, star=False):
|
|
420
|
+
assert isinstance(node, ast.ExceptHandler)
|
|
421
|
+
|
|
422
|
+
self.printer.keyword('except')
|
|
423
|
+
|
|
424
|
+
if star:
|
|
425
|
+
self.printer.operator('*')
|
|
426
|
+
|
|
427
|
+
if node.type is not None:
|
|
428
|
+
self._expression(node.type)
|
|
429
|
+
|
|
430
|
+
if node.name is not None:
|
|
431
|
+
self.printer.keyword('as')
|
|
432
|
+
|
|
433
|
+
if isinstance(node.name, str):
|
|
434
|
+
self.printer.identifier(node.name)
|
|
435
|
+
else:
|
|
436
|
+
self._expression(node.name)
|
|
437
|
+
|
|
438
|
+
self.printer.delimiter(':')
|
|
439
|
+
|
|
440
|
+
self._suite(node.body)
|
|
441
|
+
|
|
442
|
+
def visit_With(self, node, is_async=False):
|
|
443
|
+
assert is_ast_node(node, (ast.With, 'AsyncWith'))
|
|
444
|
+
|
|
445
|
+
self.printer.newline()
|
|
446
|
+
|
|
447
|
+
if is_async:
|
|
448
|
+
self.printer.keyword('async')
|
|
449
|
+
|
|
450
|
+
self.printer.keyword('with')
|
|
451
|
+
|
|
452
|
+
delimiter = Delimiter(self.printer)
|
|
453
|
+
if hasattr(node, 'items'):
|
|
454
|
+
for item in node.items:
|
|
455
|
+
delimiter.new_item()
|
|
456
|
+
|
|
457
|
+
if self.precedence(item.context_expr) != 0 and self.precedence(item.context_expr) <= self.precedence(
|
|
458
|
+
node
|
|
459
|
+
):
|
|
460
|
+
self.printer.delimiter('(')
|
|
461
|
+
self.visit_withitem(item)
|
|
462
|
+
self.printer.delimiter(')')
|
|
463
|
+
else:
|
|
464
|
+
self.visit_withitem(item)
|
|
465
|
+
else:
|
|
466
|
+
self.visit_withitem(node)
|
|
467
|
+
|
|
468
|
+
self.printer.delimiter(':')
|
|
469
|
+
self._suite(node.body)
|
|
470
|
+
|
|
471
|
+
def visit_withitem(self, node):
|
|
472
|
+
assert is_ast_node(node, ('withitem', ast.With))
|
|
473
|
+
|
|
474
|
+
self._expression(node.context_expr)
|
|
475
|
+
|
|
476
|
+
if node.optional_vars is not None:
|
|
477
|
+
self.printer.keyword('as')
|
|
478
|
+
self._expression(node.optional_vars)
|
|
479
|
+
|
|
480
|
+
def visit_FunctionDef(self, node, is_async=False):
|
|
481
|
+
assert is_ast_node(node, (ast.FunctionDef, 'AsyncFunctionDef'))
|
|
482
|
+
|
|
483
|
+
self.printer.newline()
|
|
484
|
+
|
|
485
|
+
for d in node.decorator_list:
|
|
486
|
+
self.printer.operator('@')
|
|
487
|
+
self._expression(d)
|
|
488
|
+
self.printer.newline()
|
|
489
|
+
|
|
490
|
+
if is_async:
|
|
491
|
+
self.printer.keyword('async')
|
|
492
|
+
|
|
493
|
+
self.printer.keyword('def')
|
|
494
|
+
self.printer.identifier(node.name)
|
|
495
|
+
|
|
496
|
+
if hasattr(node, 'type_params') and node.type_params:
|
|
497
|
+
self.printer.delimiter('[')
|
|
498
|
+
delimiter = Delimiter(self.printer)
|
|
499
|
+
for type_param in node.type_params:
|
|
500
|
+
delimiter.new_item()
|
|
501
|
+
self.visit(type_param)
|
|
502
|
+
self.printer.delimiter(']')
|
|
503
|
+
|
|
504
|
+
self.printer.delimiter('(')
|
|
505
|
+
self.visit_arguments(node.args)
|
|
506
|
+
self.printer.delimiter(')')
|
|
507
|
+
|
|
508
|
+
if hasattr(node, 'returns') and node.returns is not None:
|
|
509
|
+
self.printer.delimiter('->')
|
|
510
|
+
self._expression(node.returns)
|
|
511
|
+
self.printer.delimiter(':')
|
|
512
|
+
else:
|
|
513
|
+
self.printer.delimiter(':')
|
|
514
|
+
|
|
515
|
+
if hasattr(node, 'docstring') and node.docstring is not None:
|
|
516
|
+
self._suite([ast.Expr(value=ast.Str(s=node.docstring))] + node.body)
|
|
517
|
+
else:
|
|
518
|
+
self._suite(node.body)
|
|
519
|
+
|
|
520
|
+
def visit_ClassDef(self, node):
|
|
521
|
+
assert isinstance(node, ast.ClassDef)
|
|
522
|
+
|
|
523
|
+
self.printer.newline()
|
|
524
|
+
|
|
525
|
+
for d in node.decorator_list:
|
|
526
|
+
self.printer.operator('@')
|
|
527
|
+
self._expression(d)
|
|
528
|
+
self.printer.newline()
|
|
529
|
+
|
|
530
|
+
self.printer.keyword('class')
|
|
531
|
+
self.printer.identifier(node.name)
|
|
532
|
+
|
|
533
|
+
if hasattr(node, 'type_params') and node.type_params:
|
|
534
|
+
self.printer.delimiter('[')
|
|
535
|
+
delimiter = Delimiter(self.printer)
|
|
536
|
+
for type_param in node.type_params:
|
|
537
|
+
delimiter.new_item()
|
|
538
|
+
self.visit(type_param)
|
|
539
|
+
self.printer.delimiter(']')
|
|
540
|
+
|
|
541
|
+
with Delimiter(self.printer, add_parens=True) as delimiter:
|
|
542
|
+
|
|
543
|
+
for b in node.bases:
|
|
544
|
+
delimiter.new_item()
|
|
545
|
+
self._expression(b)
|
|
546
|
+
|
|
547
|
+
if hasattr(node, 'starargs') and node.starargs is not None:
|
|
548
|
+
delimiter.new_item()
|
|
549
|
+
self.printer.operator('*')
|
|
550
|
+
self._expression(node.starargs)
|
|
551
|
+
|
|
552
|
+
if hasattr(node, 'keywords'):
|
|
553
|
+
for kw in node.keywords:
|
|
554
|
+
delimiter.new_item()
|
|
555
|
+
self.visit_keyword(kw)
|
|
556
|
+
|
|
557
|
+
if hasattr(node, 'kwargs') and node.kwargs is not None:
|
|
558
|
+
delimiter.new_item()
|
|
559
|
+
self.printer.operator('**')
|
|
560
|
+
self.visit(node.kwargs)
|
|
561
|
+
|
|
562
|
+
self.printer.delimiter(':')
|
|
563
|
+
|
|
564
|
+
if hasattr(node, 'docstring') and node.docstring is not None:
|
|
565
|
+
self._suite([ast.Expr(value=ast.Str(s=node.docstring))] + node.body)
|
|
566
|
+
else:
|
|
567
|
+
self._suite(node.body)
|
|
568
|
+
|
|
569
|
+
# endregion
|
|
570
|
+
|
|
571
|
+
# region Pattern Matching
|
|
572
|
+
|
|
573
|
+
def pattern(self, pattern_node):
|
|
574
|
+
assert isinstance(pattern_node, (ast.MatchValue, ast.MatchAs, ast.MatchStar, ast.MatchOr, ast.MatchSingleton, ast.MatchClass, ast.MatchSequence, ast.MatchMapping))
|
|
575
|
+
self.visit(pattern_node)
|
|
576
|
+
|
|
577
|
+
def visit_Match(self, node):
|
|
578
|
+
assert isinstance(node, ast.Match)
|
|
579
|
+
|
|
580
|
+
self.printer.newline()
|
|
581
|
+
|
|
582
|
+
self.printer.keyword('match')
|
|
583
|
+
|
|
584
|
+
self._expression(node.subject)
|
|
585
|
+
|
|
586
|
+
self.printer.delimiter(':')
|
|
587
|
+
|
|
588
|
+
self._suite(node.cases)
|
|
589
|
+
|
|
590
|
+
def visit_match_case(self, node):
|
|
591
|
+
assert isinstance(node, ast.match_case)
|
|
592
|
+
self.printer.keyword('case')
|
|
593
|
+
|
|
594
|
+
if isinstance(node.pattern, ast.MatchSequence):
|
|
595
|
+
self.visit_MatchSequence(node.pattern, open=True)
|
|
596
|
+
else:
|
|
597
|
+
self.pattern(node.pattern)
|
|
598
|
+
|
|
599
|
+
if node.guard is not None:
|
|
600
|
+
self.printer.keyword('if')
|
|
601
|
+
self.visit(node.guard)
|
|
602
|
+
|
|
603
|
+
self.printer.delimiter(':')
|
|
604
|
+
self._suite(node.body)
|
|
605
|
+
|
|
606
|
+
def visit_MatchValue(self, node):
|
|
607
|
+
assert isinstance(node, ast.MatchValue)
|
|
608
|
+
self.visit(node.value)
|
|
609
|
+
|
|
610
|
+
def visit_MatchSingleton(self, node):
|
|
611
|
+
assert isinstance(node, ast.MatchSingleton)
|
|
612
|
+
|
|
613
|
+
self.printer.identifier(repr(node.value))
|
|
614
|
+
|
|
615
|
+
def visit_MatchStar(self, node):
|
|
616
|
+
assert isinstance(node, ast.MatchStar)
|
|
617
|
+
|
|
618
|
+
self.printer.operator('*')
|
|
619
|
+
|
|
620
|
+
if node.name is None:
|
|
621
|
+
self.printer.identifier('_')
|
|
622
|
+
else:
|
|
623
|
+
self.printer.identifier(node.name)
|
|
624
|
+
|
|
625
|
+
def visit_MatchSequence(self, node, open=False):
|
|
626
|
+
assert isinstance(node, ast.MatchSequence)
|
|
627
|
+
|
|
628
|
+
if len(node.patterns) < 2 or not open:
|
|
629
|
+
self.printer.delimiter('[')
|
|
630
|
+
|
|
631
|
+
delimiter = Delimiter(self.printer)
|
|
632
|
+
for pattern in node.patterns:
|
|
633
|
+
delimiter.new_item()
|
|
634
|
+
self.pattern(pattern)
|
|
635
|
+
|
|
636
|
+
if len(node.patterns) < 2 or not open:
|
|
637
|
+
self.printer.delimiter(']')
|
|
638
|
+
|
|
639
|
+
def visit_MatchMapping(self, node):
|
|
640
|
+
self.printer.delimiter('{')
|
|
641
|
+
|
|
642
|
+
delimiter = Delimiter(self.printer)
|
|
643
|
+
for k, p in zip(node.keys, node.patterns):
|
|
644
|
+
delimiter.new_item()
|
|
645
|
+
|
|
646
|
+
self._expression(k)
|
|
647
|
+
self.printer.delimiter(':')
|
|
648
|
+
|
|
649
|
+
self.pattern(p)
|
|
650
|
+
|
|
651
|
+
if node.rest is not None:
|
|
652
|
+
delimiter.new_item()
|
|
653
|
+
|
|
654
|
+
self.printer.operator('**')
|
|
655
|
+
self.printer.identifier(node.rest)
|
|
656
|
+
|
|
657
|
+
self.printer.delimiter('}')
|
|
658
|
+
|
|
659
|
+
def visit_MatchClass(self, node):
|
|
660
|
+
assert isinstance(node, ast.MatchClass)
|
|
661
|
+
|
|
662
|
+
self.visit(node.cls)
|
|
663
|
+
self.printer.delimiter('(')
|
|
664
|
+
|
|
665
|
+
delimiter = Delimiter(self.printer)
|
|
666
|
+
for pattern in node.patterns:
|
|
667
|
+
delimiter.new_item()
|
|
668
|
+
self.pattern(pattern)
|
|
669
|
+
|
|
670
|
+
for kwd, pattern in zip(node.kwd_attrs, node.kwd_patterns):
|
|
671
|
+
delimiter.new_item()
|
|
672
|
+
|
|
673
|
+
self.printer.identifier(kwd)
|
|
674
|
+
self.printer.delimiter('=')
|
|
675
|
+
|
|
676
|
+
self.pattern(pattern)
|
|
677
|
+
|
|
678
|
+
self.printer.delimiter(')')
|
|
679
|
+
|
|
680
|
+
def visit_MatchAs(self, node):
|
|
681
|
+
assert isinstance(node, ast.MatchAs)
|
|
682
|
+
|
|
683
|
+
if node.pattern is not None:
|
|
684
|
+
if isinstance(node.pattern, ast.MatchAs):
|
|
685
|
+
self.printer.delimiter('(')
|
|
686
|
+
self.pattern(node.pattern)
|
|
687
|
+
self.printer.delimiter(')')
|
|
688
|
+
else:
|
|
689
|
+
self.pattern(node.pattern)
|
|
690
|
+
|
|
691
|
+
self.printer.keyword('as')
|
|
692
|
+
|
|
693
|
+
if node.name is None:
|
|
694
|
+
self.printer.identifier('_')
|
|
695
|
+
else:
|
|
696
|
+
self.printer.identifier(node.name)
|
|
697
|
+
|
|
698
|
+
def visit_MatchOr(self, node):
|
|
699
|
+
assert isinstance(node, ast.MatchOr)
|
|
700
|
+
|
|
701
|
+
delimiter = Delimiter(self.printer, delimiter='|')
|
|
702
|
+
for pattern in node.patterns:
|
|
703
|
+
delimiter.new_item()
|
|
704
|
+
|
|
705
|
+
if isinstance(pattern, (ast.MatchAs, ast.MatchOr)):
|
|
706
|
+
self.printer.delimiter('(')
|
|
707
|
+
self.pattern(pattern)
|
|
708
|
+
self.printer.delimiter(')')
|
|
709
|
+
else:
|
|
710
|
+
self.pattern(pattern)
|
|
711
|
+
|
|
712
|
+
# endregion
|
|
713
|
+
|
|
714
|
+
# region async and await
|
|
715
|
+
|
|
716
|
+
def visit_AsyncFunctionDef(self, node):
|
|
717
|
+
assert isinstance(node, ast.AsyncFunctionDef)
|
|
718
|
+
self.visit_FunctionDef(node, is_async=True)
|
|
719
|
+
|
|
720
|
+
def visit_AsyncFor(self, node):
|
|
721
|
+
assert isinstance(node, ast.AsyncFor)
|
|
722
|
+
self.visit_For(node, is_async=True)
|
|
723
|
+
|
|
724
|
+
def visit_AsyncWith(self, node):
|
|
725
|
+
assert isinstance(node, ast.AsyncWith)
|
|
726
|
+
self.visit_With(node, is_async=True)
|
|
727
|
+
|
|
728
|
+
# endregion
|
|
729
|
+
|
|
730
|
+
# region Generic Types
|
|
731
|
+
def visit_TypeAlias(self, node):
|
|
732
|
+
assert isinstance(node, ast.TypeAlias)
|
|
733
|
+
self.printer.keyword('type')
|
|
734
|
+
self.visit_Name(node.name)
|
|
735
|
+
|
|
736
|
+
if hasattr(node, 'type_params') and node.type_params:
|
|
737
|
+
self.printer.delimiter('[')
|
|
738
|
+
delimiter = Delimiter(self.printer)
|
|
739
|
+
for param in node.type_params:
|
|
740
|
+
delimiter.new_item()
|
|
741
|
+
self.visit(param)
|
|
742
|
+
self.printer.delimiter(']')
|
|
743
|
+
|
|
744
|
+
self.printer.delimiter('=')
|
|
745
|
+
self._expression(node.value)
|
|
746
|
+
self.printer.end_statement()
|
|
747
|
+
|
|
748
|
+
def visit_TypeVar(self, node):
|
|
749
|
+
assert isinstance(node, ast.TypeVar)
|
|
750
|
+
assert isinstance(node.name, str)
|
|
751
|
+
self.printer.identifier(node.name)
|
|
752
|
+
|
|
753
|
+
if node.bound:
|
|
754
|
+
self.printer.delimiter(':')
|
|
755
|
+
self._expression(node.bound)
|
|
756
|
+
|
|
757
|
+
if hasattr(node, 'default_value') and node.default_value is not None:
|
|
758
|
+
self.printer.delimiter('=')
|
|
759
|
+
self._expression(node.default_value)
|
|
760
|
+
|
|
761
|
+
def visit_TypeVarTuple(self, node):
|
|
762
|
+
assert isinstance(node, ast.TypeVarTuple)
|
|
763
|
+
self.printer.operator('*')
|
|
764
|
+
self.printer.identifier(node.name)
|
|
765
|
+
|
|
766
|
+
if hasattr(node, 'default_value') and node.default_value is not None:
|
|
767
|
+
self.printer.delimiter('=')
|
|
768
|
+
self._expression(node.default_value)
|
|
769
|
+
|
|
770
|
+
def visit_ParamSpec(self, node):
|
|
771
|
+
assert isinstance(node, ast.ParamSpec)
|
|
772
|
+
self.printer.operator('*')
|
|
773
|
+
self.printer.operator('*')
|
|
774
|
+
self.printer.identifier(node.name)
|
|
775
|
+
|
|
776
|
+
if hasattr(node, 'default_value') and node.default_value is not None:
|
|
777
|
+
self.printer.delimiter('=')
|
|
778
|
+
self._expression(node.default_value)
|
|
779
|
+
|
|
780
|
+
# endregion
|
|
781
|
+
|
|
782
|
+
def visit_Module(self, node):
|
|
783
|
+
if hasattr(node, 'docstring') and node.docstring is not None:
|
|
784
|
+
# Python 3.6 added a docstring field! Really useful for every use case except this one...
|
|
785
|
+
# Put the docstring back into the body
|
|
786
|
+
self._suite_body([ast.Expr(value=ast.Str(s=node.docstring))] + node.body)
|
|
787
|
+
else:
|
|
788
|
+
self._suite_body(node.body)
|
|
789
|
+
|
|
790
|
+
def _suite(self, node_list):
|
|
791
|
+
|
|
792
|
+
compound_statements = [
|
|
793
|
+
'For',
|
|
794
|
+
'While',
|
|
795
|
+
'Try',
|
|
796
|
+
'TryStar',
|
|
797
|
+
'If',
|
|
798
|
+
'With',
|
|
799
|
+
'ClassDef',
|
|
800
|
+
'TryFinally',
|
|
801
|
+
'TryExcept',
|
|
802
|
+
'FunctionDef',
|
|
803
|
+
'AsyncFunctionDef',
|
|
804
|
+
'AsyncFor',
|
|
805
|
+
'AsyncWith',
|
|
806
|
+
'Match',
|
|
807
|
+
'match_case'
|
|
808
|
+
]
|
|
809
|
+
|
|
810
|
+
if [node for node in node_list if node.__class__.__name__ in compound_statements]:
|
|
811
|
+
self.printer.enter_block()
|
|
812
|
+
self._suite_body(node_list)
|
|
813
|
+
self.printer.leave_block()
|
|
814
|
+
else:
|
|
815
|
+
self.printer.indent += 1
|
|
816
|
+
self._suite_body(node_list)
|
|
817
|
+
self.printer.indent -= 1
|
|
818
|
+
self.printer.newline()
|
|
819
|
+
|
|
820
|
+
def _suite_body(self, node_list):
|
|
821
|
+
|
|
822
|
+
statements = {
|
|
823
|
+
'Assign': self.visit_Assign,
|
|
824
|
+
'AnnAssign': self.visit_AnnAssign,
|
|
825
|
+
'AugAssign': self.visit_AugAssign,
|
|
826
|
+
'Expr': self.visit_Expr,
|
|
827
|
+
'Delete': self.visit_Delete,
|
|
828
|
+
'Pass': self.visit_Pass,
|
|
829
|
+
'Import': self.visit_Import,
|
|
830
|
+
'ImportFrom': self.visit_ImportFrom,
|
|
831
|
+
'Global': self.visit_Global,
|
|
832
|
+
'Nonlocal': self.visit_Nonlocal,
|
|
833
|
+
'Assert': self.visit_Assert,
|
|
834
|
+
'Break': self.visit_Break,
|
|
835
|
+
'Continue': self.visit_Continue,
|
|
836
|
+
'Return': self.visit_Return,
|
|
837
|
+
'Raise': self.visit_Raise,
|
|
838
|
+
'Yield': self.visit_Yield,
|
|
839
|
+
'YieldFrom': self.visit_YieldFrom,
|
|
840
|
+
'For': self.visit_For,
|
|
841
|
+
'While': self.visit_While,
|
|
842
|
+
'Try': self.visit_Try,
|
|
843
|
+
'TryStar': self.visit_TryStar,
|
|
844
|
+
'If': self.visit_If,
|
|
845
|
+
'With': self.visit_With,
|
|
846
|
+
'ClassDef': self.visit_ClassDef,
|
|
847
|
+
'FunctionDef': self.visit_FunctionDef,
|
|
848
|
+
'AsyncFunctionDef': self.visit_AsyncFunctionDef,
|
|
849
|
+
'AsyncFor': self.visit_AsyncFor,
|
|
850
|
+
'AsyncWith': self.visit_AsyncWith,
|
|
851
|
+
'TryFinally': self.visit_TryFinally,
|
|
852
|
+
'TryExcept': self.visit_TryExcept,
|
|
853
|
+
'Print': self.visit_Print,
|
|
854
|
+
'Exec': self.visit_Exec,
|
|
855
|
+
'Match': self.visit_Match,
|
|
856
|
+
'match_case': self.visit_match_case,
|
|
857
|
+
'TypeAlias': self.visit_TypeAlias
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
for node in node_list:
|
|
861
|
+
statements[node.__class__.__name__](node)
|
|
862
|
+
|