Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(672)

Side by Side Diff: recipe_engine/third_party/astunparse/unparser.py

Issue 2387763003: Add initial postprocess unit test thingy. (Closed)
Patch Set: Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 "Usage: unparse.py <path to source file>"
2 from __future__ import print_function, unicode_literals
3 import six
4 import sys
5 import ast
6 import os
7 import tokenize
8 from six import StringIO
9
10 # Large float and imaginary literals get turned into infinities in the AST.
11 # We unparse those infinities to INFSTR.
12 INFSTR = "1e" + repr(sys.float_info.max_10_exp + 1)
13
14 def interleave(inter, f, seq):
15 """Call f on each item in seq, calling inter() in between.
16 """
17 seq = iter(seq)
18 try:
19 f(next(seq))
20 except StopIteration:
21 pass
22 else:
23 for x in seq:
24 inter()
25 f(x)
26
27 class Unparser:
28 """Methods in this class recursively traverse an AST and
29 output source code for the abstract syntax; original formatting
30 is disregarded. """
31
32 def __init__(self, tree, file=sys.stdout):
33 """Unparser(tree, file=sys.stdout) -> None.
34 Print the source for tree to file."""
35 self.f = file
36 self.future_imports = []
37 self._indent = 0
38 self.dispatch(tree)
39 print("", file=self.f)
40 self.f.flush()
41
42 def fill(self, text = ""):
43 "Indent a piece of text, according to the current indentation level"
44 self.f.write("\n"+" "*self._indent + text)
45
46 def write(self, text):
47 "Append a piece of text to the current line."
48 self.f.write(six.text_type(text))
49
50 def enter(self):
51 "Print ':', and increase the indentation."
52 self.write(":")
53 self._indent += 1
54
55 def leave(self):
56 "Decrease the indentation level."
57 self._indent -= 1
58
59 def dispatch(self, tree):
60 "Dispatcher function, dispatching tree type T to method _T."
61 if isinstance(tree, list):
62 for t in tree:
63 self.dispatch(t)
64 return
65 meth = getattr(self, "_"+tree.__class__.__name__)
66 meth(tree)
67
68
69 ############### Unparsing methods ######################
70 # There should be one method per concrete grammar type #
71 # Constructors should be grouped by sum type. Ideally, #
72 # this would follow the order in the grammar, but #
73 # currently doesn't. #
74 ########################################################
75
76 def _Module(self, tree):
77 for stmt in tree.body:
78 self.dispatch(stmt)
79
80 def _Interactive(self, tree):
81 for stmt in tree.body:
82 self.dispatch(stmt)
83
84 def _Expression(self, tree):
85 self.dispatch(tree.body)
86
87 # stmt
88 def _Expr(self, tree):
89 self.fill()
90 self.dispatch(tree.value)
91
92 def _Import(self, t):
93 self.fill("import ")
94 interleave(lambda: self.write(", "), self.dispatch, t.names)
95
96 def _ImportFrom(self, t):
97 # A from __future__ import may affect unparsing, so record it.
98 if t.module and t.module == '__future__':
99 self.future_imports.extend(n.name for n in t.names)
100
101 self.fill("from ")
102 self.write("." * t.level)
103 if t.module:
104 self.write(t.module)
105 self.write(" import ")
106 interleave(lambda: self.write(", "), self.dispatch, t.names)
107
108 def _Assign(self, t):
109 self.fill()
110 for target in t.targets:
111 self.dispatch(target)
112 self.write(" = ")
113 self.dispatch(t.value)
114
115 def _AugAssign(self, t):
116 self.fill()
117 self.dispatch(t.target)
118 self.write(" "+self.binop[t.op.__class__.__name__]+"= ")
119 self.dispatch(t.value)
120
121 def _Return(self, t):
122 self.fill("return")
123 if t.value:
124 self.write(" ")
125 self.dispatch(t.value)
126
127 def _Pass(self, t):
128 self.fill("pass")
129
130 def _Break(self, t):
131 self.fill("break")
132
133 def _Continue(self, t):
134 self.fill("continue")
135
136 def _Delete(self, t):
137 self.fill("del ")
138 interleave(lambda: self.write(", "), self.dispatch, t.targets)
139
140 def _Assert(self, t):
141 self.fill("assert ")
142 self.dispatch(t.test)
143 if t.msg:
144 self.write(", ")
145 self.dispatch(t.msg)
146
147 def _Exec(self, t):
148 self.fill("exec ")
149 self.dispatch(t.body)
150 if t.globals:
151 self.write(" in ")
152 self.dispatch(t.globals)
153 if t.locals:
154 self.write(", ")
155 self.dispatch(t.locals)
156
157 def _Print(self, t):
158 self.fill("print ")
159 do_comma = False
160 if t.dest:
161 self.write(">>")
162 self.dispatch(t.dest)
163 do_comma = True
164 for e in t.values:
165 if do_comma:self.write(", ")
166 else:do_comma=True
167 self.dispatch(e)
168 if not t.nl:
169 self.write(",")
170
171 def _Global(self, t):
172 self.fill("global ")
173 interleave(lambda: self.write(", "), self.write, t.names)
174
175 def _Nonlocal(self, t):
176 self.fill("nonlocal ")
177 interleave(lambda: self.write(", "), self.write, t.names)
178
179 def _Yield(self, t):
180 self.write("(")
181 self.write("yield")
182 if t.value:
183 self.write(" ")
184 self.dispatch(t.value)
185 self.write(")")
186
187 def _YieldFrom(self, t):
188 self.write("(")
189 self.write("yield from")
190 if t.value:
191 self.write(" ")
192 self.dispatch(t.value)
193 self.write(")")
194
195 def _Raise(self, t):
196 self.fill("raise")
197 if six.PY3:
198 if not t.exc:
199 assert not t.cause
200 return
201 self.write(" ")
202 self.dispatch(t.exc)
203 if t.cause:
204 self.write(" from ")
205 self.dispatch(t.cause)
206 else:
207 self.write(" ")
208 if t.type:
209 self.dispatch(t.type)
210 if t.inst:
211 self.write(", ")
212 self.dispatch(t.inst)
213 if t.tback:
214 self.write(", ")
215 self.dispatch(t.tback)
216
217 def _Try(self, t):
218 self.fill("try")
219 self.enter()
220 self.dispatch(t.body)
221 self.leave()
222 for ex in t.handlers:
223 self.dispatch(ex)
224 if t.orelse:
225 self.fill("else")
226 self.enter()
227 self.dispatch(t.orelse)
228 self.leave()
229 if t.finalbody:
230 self.fill("finally")
231 self.enter()
232 self.dispatch(t.finalbody)
233 self.leave()
234
235 def _TryExcept(self, t):
236 self.fill("try")
237 self.enter()
238 self.dispatch(t.body)
239 self.leave()
240
241 for ex in t.handlers:
242 self.dispatch(ex)
243 if t.orelse:
244 self.fill("else")
245 self.enter()
246 self.dispatch(t.orelse)
247 self.leave()
248
249 def _TryFinally(self, t):
250 if len(t.body) == 1 and isinstance(t.body[0], ast.TryExcept):
251 # try-except-finally
252 self.dispatch(t.body)
253 else:
254 self.fill("try")
255 self.enter()
256 self.dispatch(t.body)
257 self.leave()
258
259 self.fill("finally")
260 self.enter()
261 self.dispatch(t.finalbody)
262 self.leave()
263
264 def _ExceptHandler(self, t):
265 self.fill("except")
266 if t.type:
267 self.write(" ")
268 self.dispatch(t.type)
269 if t.name:
270 self.write(" as ")
271 if six.PY3:
272 self.write(t.name)
273 else:
274 self.dispatch(t.name)
275 self.enter()
276 self.dispatch(t.body)
277 self.leave()
278
279 def _ClassDef(self, t):
280 self.write("\n")
281 for deco in t.decorator_list:
282 self.fill("@")
283 self.dispatch(deco)
284 self.fill("class "+t.name)
285 if six.PY3:
286 self.write("(")
287 comma = False
288 for e in t.bases:
289 if comma: self.write(", ")
290 else: comma = True
291 self.dispatch(e)
292 for e in t.keywords:
293 if comma: self.write(", ")
294 else: comma = True
295 self.dispatch(e)
296 if sys.version_info[:2] < (3, 5):
297 if t.starargs:
298 if comma: self.write(", ")
299 else: comma = True
300 self.write("*")
301 self.dispatch(t.starargs)
302 if t.kwargs:
303 if comma: self.write(", ")
304 else: comma = True
305 self.write("**")
306 self.dispatch(t.kwargs)
307 self.write(")")
308 elif t.bases:
309 self.write("(")
310 for a in t.bases:
311 self.dispatch(a)
312 self.write(", ")
313 self.write(")")
314 self.enter()
315 self.dispatch(t.body)
316 self.leave()
317
318 def _generic_FunctionDef(self, t, async=False):
319 self.write("\n")
320 for deco in t.decorator_list:
321 self.fill("@")
322 self.dispatch(deco)
323 self.fill(("async " if async else "") + "def " + t.name + "(")
324 self.dispatch(t.args)
325 self.write(")")
326 if getattr(t, "returns", False):
327 self.write(" -> ")
328 self.dispatch(t.returns)
329 self.enter()
330 self.dispatch(t.body)
331 self.leave()
332
333 def _FunctionDef(self, t):
334 self._generic_FunctionDef(t)
335
336 def _AsyncFunctionDef(self, t):
337 self._generic_FunctionDef(t, async=True)
338
339 def _generic_For(self, t, async=False):
340 self.fill("async for " if async else "for ")
341 self.dispatch(t.target)
342 self.write(" in ")
343 self.dispatch(t.iter)
344 self.enter()
345 self.dispatch(t.body)
346 self.leave()
347 if t.orelse:
348 self.fill("else")
349 self.enter()
350 self.dispatch(t.orelse)
351 self.leave()
352
353 def _For(self, t):
354 self._generic_For(t)
355
356 def _AsyncFor(self, t):
357 self._generic_For(t, async=True)
358
359 def _If(self, t):
360 self.fill("if ")
361 self.dispatch(t.test)
362 self.enter()
363 self.dispatch(t.body)
364 self.leave()
365 # collapse nested ifs into equivalent elifs.
366 while (t.orelse and len(t.orelse) == 1 and
367 isinstance(t.orelse[0], ast.If)):
368 t = t.orelse[0]
369 self.fill("elif ")
370 self.dispatch(t.test)
371 self.enter()
372 self.dispatch(t.body)
373 self.leave()
374 # final else
375 if t.orelse:
376 self.fill("else")
377 self.enter()
378 self.dispatch(t.orelse)
379 self.leave()
380
381 def _While(self, t):
382 self.fill("while ")
383 self.dispatch(t.test)
384 self.enter()
385 self.dispatch(t.body)
386 self.leave()
387 if t.orelse:
388 self.fill("else")
389 self.enter()
390 self.dispatch(t.orelse)
391 self.leave()
392
393 def _generic_With(self, t, async=False):
394 self.fill("async with " if async else "with ")
395 if hasattr(t, 'items'):
396 interleave(lambda: self.write(", "), self.dispatch, t.items)
397 else:
398 self.dispatch(t.context_expr)
399 if t.optional_vars:
400 self.write(" as ")
401 self.dispatch(t.optional_vars)
402 self.enter()
403 self.dispatch(t.body)
404 self.leave()
405
406 def _With(self, t):
407 self._generic_With(t)
408
409 def _AsyncWith(self, t):
410 self._generic_With(t, async=True)
411
412 # expr
413 def _Bytes(self, t):
414 self.write(repr(t.s))
415
416 def _Str(self, tree):
417 if six.PY3:
418 self.write(repr(tree.s))
419 else:
420 # if from __future__ import unicode_literals is in effect,
421 # then we want to output string literals using a 'b' prefix
422 # and unicode literals with no prefix.
423 if "unicode_literals" not in self.future_imports:
424 self.write(repr(tree.s))
425 elif isinstance(tree.s, str):
426 self.write("b" + repr(tree.s))
427 elif isinstance(tree.s, unicode):
428 self.write(repr(tree.s).lstrip("u"))
429 else:
430 assert False, "shouldn't get here"
431
432 def _Name(self, t):
433 self.write(t.id)
434
435 def _NameConstant(self, t):
436 self.write(repr(t.value))
437
438 def _Repr(self, t):
439 self.write("`")
440 self.dispatch(t.value)
441 self.write("`")
442
443 def _Num(self, t):
444 repr_n = repr(t.n)
445 if six.PY3:
446 self.write(repr_n.replace("inf", INFSTR))
447 else:
448 # Parenthesize negative numbers, to avoid turning (-1)**2 into -1**2 .
449 if repr_n.startswith("-"):
450 self.write("(")
451 if "inf" in repr_n and repr_n.endswith("*j"):
452 repr_n = repr_n.replace("*j", "j")
453 # Substitute overflowing decimal literal for AST infinities.
454 self.write(repr_n.replace("inf", INFSTR))
455 if repr_n.startswith("-"):
456 self.write(")")
457
458 def _List(self, t):
459 self.write("[")
460 interleave(lambda: self.write(", "), self.dispatch, t.elts)
461 self.write("]")
462
463 def _ListComp(self, t):
464 self.write("[")
465 self.dispatch(t.elt)
466 for gen in t.generators:
467 self.dispatch(gen)
468 self.write("]")
469
470 def _GeneratorExp(self, t):
471 self.write("(")
472 self.dispatch(t.elt)
473 for gen in t.generators:
474 self.dispatch(gen)
475 self.write(")")
476
477 def _SetComp(self, t):
478 self.write("{")
479 self.dispatch(t.elt)
480 for gen in t.generators:
481 self.dispatch(gen)
482 self.write("}")
483
484 def _DictComp(self, t):
485 self.write("{")
486 self.dispatch(t.key)
487 self.write(": ")
488 self.dispatch(t.value)
489 for gen in t.generators:
490 self.dispatch(gen)
491 self.write("}")
492
493 def _comprehension(self, t):
494 self.write(" for ")
495 self.dispatch(t.target)
496 self.write(" in ")
497 self.dispatch(t.iter)
498 for if_clause in t.ifs:
499 self.write(" if ")
500 self.dispatch(if_clause)
501
502 def _IfExp(self, t):
503 self.write("(")
504 self.dispatch(t.body)
505 self.write(" if ")
506 self.dispatch(t.test)
507 self.write(" else ")
508 self.dispatch(t.orelse)
509 self.write(")")
510
511 def _Set(self, t):
512 assert(t.elts) # should be at least one element
513 self.write("{")
514 interleave(lambda: self.write(", "), self.dispatch, t.elts)
515 self.write("}")
516
517 def _Dict(self, t):
518 self.write("{")
519 def write_pair(pair):
520 (k, v) = pair
521 self.dispatch(k)
522 self.write(": ")
523 self.dispatch(v)
524 interleave(lambda: self.write(", "), write_pair, zip(t.keys, t.values))
525 self.write("}")
526
527 def _Tuple(self, t):
528 self.write("(")
529 if len(t.elts) == 1:
530 (elt,) = t.elts
531 self.dispatch(elt)
532 self.write(",")
533 else:
534 interleave(lambda: self.write(", "), self.dispatch, t.elts)
535 self.write(")")
536
537 unop = {"Invert":"~", "Not": "not", "UAdd":"+", "USub":"-"}
538 def _UnaryOp(self, t):
539 self.write("(")
540 self.write(self.unop[t.op.__class__.__name__])
541 self.write(" ")
542 if six.PY2 and isinstance(t.op, ast.USub) and isinstance(t.operand, ast. Num):
543 # If we're applying unary minus to a number, parenthesize the number .
544 # This is necessary: -2147483648 is different from -(2147483648) on
545 # a 32-bit machine (the first is an int, the second a long), and
546 # -7j is different from -(7j). (The first has real part 0.0, the se cond
547 # has real part -0.0.)
548 self.write("(")
549 self.dispatch(t.operand)
550 self.write(")")
551 else:
552 self.dispatch(t.operand)
553 self.write(")")
554
555 binop = { "Add":"+", "Sub":"-", "Mult":"*", "Div":"/", "Mod":"%",
556 "LShift":"<<", "RShift":">>", "BitOr":"|", "BitXor":"^", "Bi tAnd":"&",
557 "FloorDiv":"//", "Pow": "**",
558 "MatMult":"@"}
559 def _BinOp(self, t):
560 self.write("(")
561 self.dispatch(t.left)
562 self.write(" " + self.binop[t.op.__class__.__name__] + " ")
563 self.dispatch(t.right)
564 self.write(")")
565
566 cmpops = {"Eq":"==", "NotEq":"!=", "Lt":"<", "LtE":"<=", "Gt":">", "GtE":">= ",
567 "Is":"is", "IsNot":"is not", "In":"in", "NotIn":"not in" }
568 def _Compare(self, t):
569 self.write("(")
570 self.dispatch(t.left)
571 for o, e in zip(t.ops, t.comparators):
572 self.write(" " + self.cmpops[o.__class__.__name__] + " ")
573 self.dispatch(e)
574 self.write(")")
575
576 boolops = {ast.And: 'and', ast.Or: 'or'}
577 def _BoolOp(self, t):
578 self.write("(")
579 s = " %s " % self.boolops[t.op.__class__]
580 interleave(lambda: self.write(s), self.dispatch, t.values)
581 self.write(")")
582
583 def _Attribute(self,t):
584 self.dispatch(t.value)
585 # Special case: 3.__abs__() is a syntax error, so if t.value
586 # is an integer literal then we need to either parenthesize
587 # it or add an extra space to get 3 .__abs__().
588 if isinstance(t.value, ast.Num) and isinstance(t.value.n, int):
589 self.write(" ")
590 self.write(".")
591 self.write(t.attr)
592
593 def _Call(self, t):
594 self.dispatch(t.func)
595 self.write("(")
596 comma = False
597 for e in t.args:
598 if comma: self.write(", ")
599 else: comma = True
600 self.dispatch(e)
601 for e in t.keywords:
602 if comma: self.write(", ")
603 else: comma = True
604 self.dispatch(e)
605 if sys.version_info[:2] < (3, 5):
606 if t.starargs:
607 if comma: self.write(", ")
608 else: comma = True
609 self.write("*")
610 self.dispatch(t.starargs)
611 if t.kwargs:
612 if comma: self.write(", ")
613 else: comma = True
614 self.write("**")
615 self.dispatch(t.kwargs)
616 self.write(")")
617
618 def _Subscript(self, t):
619 self.dispatch(t.value)
620 self.write("[")
621 self.dispatch(t.slice)
622 self.write("]")
623
624 def _Starred(self, t):
625 self.write("*")
626 self.dispatch(t.value)
627
628 # slice
629 def _Ellipsis(self, t):
630 self.write("...")
631
632 def _Index(self, t):
633 self.dispatch(t.value)
634
635 def _Slice(self, t):
636 if t.lower:
637 self.dispatch(t.lower)
638 self.write(":")
639 if t.upper:
640 self.dispatch(t.upper)
641 if t.step:
642 self.write(":")
643 self.dispatch(t.step)
644
645 def _ExtSlice(self, t):
646 interleave(lambda: self.write(', '), self.dispatch, t.dims)
647
648 # argument
649 def _arg(self, t):
650 self.write(t.arg)
651 if t.annotation:
652 self.write(": ")
653 self.dispatch(t.annotation)
654
655 # others
656 def _arguments(self, t):
657 first = True
658 # normal arguments
659 defaults = [None] * (len(t.args) - len(t.defaults)) + t.defaults
660 for a,d in zip(t.args, defaults):
661 if first:first = False
662 else: self.write(", ")
663 self.dispatch(a)
664 if d:
665 self.write("=")
666 self.dispatch(d)
667
668 # varargs, or bare '*' if no varargs but keyword-only arguments present
669 if t.vararg or getattr(t, "kwonlyargs", False):
670 if first: first = False
671 else: self.write(", ")
672 self.write("*")
673 if t.vararg:
674 if hasattr(t.vararg, 'arg'):
675 self.write(t.vararg.arg)
676 if t.vararg.annotation:
677 self.write(": ")
678 self.dispatch(t.vararg.annotation)
679 else:
680 self.write(t.vararg)
681 if getattr(t, 'varargannotation', None):
682 self.write(": ")
683 self.dispatch(t.varargannotation)
684
685 # keyword-only arguments
686 if getattr(t, "kwonlyargs", False):
687 for a, d in zip(t.kwonlyargs, t.kw_defaults):
688 if first:first = False
689 else: self.write(", ")
690 self.dispatch(a),
691 if d:
692 self.write("=")
693 self.dispatch(d)
694
695 # kwargs
696 if t.kwarg:
697 if first:first = False
698 else: self.write(", ")
699 if hasattr(t.kwarg, 'arg'):
700 self.write("**"+t.kwarg.arg)
701 if t.kwarg.annotation:
702 self.write(": ")
703 self.dispatch(t.kwarg.annotation)
704 else:
705 self.write("**"+t.kwarg)
706 if getattr(t, 'kwargannotation', None):
707 self.write(": ")
708 self.dispatch(t.kwargannotation)
709
710 def _keyword(self, t):
711 if t.arg is None:
712 # starting from Python 3.5 this denotes a kwargs part of the invocat ion
713 self.write("**")
714 else:
715 self.write(t.arg)
716 self.write("=")
717 self.dispatch(t.value)
718
719 def _Lambda(self, t):
720 self.write("(")
721 self.write("lambda ")
722 self.dispatch(t.args)
723 self.write(": ")
724 self.dispatch(t.body)
725 self.write(")")
726
727 def _alias(self, t):
728 self.write(t.name)
729 if t.asname:
730 self.write(" as "+t.asname)
731
732 def _withitem(self, t):
733 self.dispatch(t.context_expr)
734 if t.optional_vars:
735 self.write(" as ")
736 self.dispatch(t.optional_vars)
737
738 def _Await(self, t):
739 self.write("(")
740 self.write("await")
741 if t.value:
742 self.write(" ")
743 self.dispatch(t.value)
744 self.write(")")
745
746 def roundtrip(filename, output=sys.stdout):
747 if six.PY3:
748 with open(filename, "rb") as pyfile:
749 encoding = tokenize.detect_encoding(pyfile.readline)[0]
750 with open(filename, "r", encoding=encoding) as pyfile:
751 source = pyfile.read()
752 else:
753 with open(filename, "r") as pyfile:
754 source = pyfile.read()
755 tree = compile(source, filename, "exec", ast.PyCF_ONLY_AST, dont_inherit=Tru e)
756 Unparser(tree, output)
757
758
759
760 def testdir(a):
761 try:
762 names = [n for n in os.listdir(a) if n.endswith('.py')]
763 except OSError:
764 print("Directory not readable: %s" % a, file=sys.stderr)
765 else:
766 for n in names:
767 fullname = os.path.join(a, n)
768 if os.path.isfile(fullname):
769 output = StringIO()
770 print('Testing %s' % fullname)
771 try:
772 roundtrip(fullname, output)
773 except Exception as e:
774 print(' Failed to compile, exception is %s' % repr(e))
775 elif os.path.isdir(fullname):
776 testdir(fullname)
777
778 def main(args):
779 if args[0] == '--testdir':
780 for a in args[1:]:
781 testdir(a)
782 else:
783 for a in args:
784 roundtrip(a)
785
786 if __name__=='__main__':
787 main(sys.argv[1:])
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698