OLD | NEW |
(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:]) |
OLD | NEW |