Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/astunparse/unparser.py: 15%

718 statements  

« prev     ^ index     » next       coverage.py v7.4.0, created at 2024-01-03 07:57 +0000

1"Usage: unparse.py <path to source file>" 

2from __future__ import print_function, unicode_literals 

3import six 

4import sys 

5import ast 

6import os 

7import tokenize 

8from six import StringIO 

9 

10# Large float and imaginary literals get turned into infinities in the AST. 

11# We unparse those infinities to INFSTR. 

12INFSTR = "1e" + repr(sys.float_info.max_10_exp + 1) 

13 

14def 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 

27class 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 _NamedExpr(self, tree): 

93 self.write("(") 

94 self.dispatch(tree.target) 

95 self.write(" := ") 

96 self.dispatch(tree.value) 

97 self.write(")") 

98 

99 def _Import(self, t): 

100 self.fill("import ") 

101 interleave(lambda: self.write(", "), self.dispatch, t.names) 

102 

103 def _ImportFrom(self, t): 

104 # A from __future__ import may affect unparsing, so record it. 

105 if t.module and t.module == '__future__': 

106 self.future_imports.extend(n.name for n in t.names) 

107 

108 self.fill("from ") 

109 self.write("." * t.level) 

110 if t.module: 

111 self.write(t.module) 

112 self.write(" import ") 

113 interleave(lambda: self.write(", "), self.dispatch, t.names) 

114 

115 def _Assign(self, t): 

116 self.fill() 

117 for target in t.targets: 

118 self.dispatch(target) 

119 self.write(" = ") 

120 self.dispatch(t.value) 

121 

122 def _AugAssign(self, t): 

123 self.fill() 

124 self.dispatch(t.target) 

125 self.write(" "+self.binop[t.op.__class__.__name__]+"= ") 

126 self.dispatch(t.value) 

127 

128 def _AnnAssign(self, t): 

129 self.fill() 

130 if not t.simple and isinstance(t.target, ast.Name): 

131 self.write('(') 

132 self.dispatch(t.target) 

133 if not t.simple and isinstance(t.target, ast.Name): 

134 self.write(')') 

135 self.write(": ") 

136 self.dispatch(t.annotation) 

137 if t.value: 

138 self.write(" = ") 

139 self.dispatch(t.value) 

140 

141 def _Return(self, t): 

142 self.fill("return") 

143 if t.value: 

144 self.write(" ") 

145 self.dispatch(t.value) 

146 

147 def _Pass(self, t): 

148 self.fill("pass") 

149 

150 def _Break(self, t): 

151 self.fill("break") 

152 

153 def _Continue(self, t): 

154 self.fill("continue") 

155 

156 def _Delete(self, t): 

157 self.fill("del ") 

158 interleave(lambda: self.write(", "), self.dispatch, t.targets) 

159 

160 def _Assert(self, t): 

161 self.fill("assert ") 

162 self.dispatch(t.test) 

163 if t.msg: 

164 self.write(", ") 

165 self.dispatch(t.msg) 

166 

167 def _Exec(self, t): 

168 self.fill("exec ") 

169 self.dispatch(t.body) 

170 if t.globals: 

171 self.write(" in ") 

172 self.dispatch(t.globals) 

173 if t.locals: 

174 self.write(", ") 

175 self.dispatch(t.locals) 

176 

177 def _Print(self, t): 

178 self.fill("print ") 

179 do_comma = False 

180 if t.dest: 

181 self.write(">>") 

182 self.dispatch(t.dest) 

183 do_comma = True 

184 for e in t.values: 

185 if do_comma:self.write(", ") 

186 else:do_comma=True 

187 self.dispatch(e) 

188 if not t.nl: 

189 self.write(",") 

190 

191 def _Global(self, t): 

192 self.fill("global ") 

193 interleave(lambda: self.write(", "), self.write, t.names) 

194 

195 def _Nonlocal(self, t): 

196 self.fill("nonlocal ") 

197 interleave(lambda: self.write(", "), self.write, t.names) 

198 

199 def _Await(self, t): 

200 self.write("(") 

201 self.write("await") 

202 if t.value: 

203 self.write(" ") 

204 self.dispatch(t.value) 

205 self.write(")") 

206 

207 def _Yield(self, t): 

208 self.write("(") 

209 self.write("yield") 

210 if t.value: 

211 self.write(" ") 

212 self.dispatch(t.value) 

213 self.write(")") 

214 

215 def _YieldFrom(self, t): 

216 self.write("(") 

217 self.write("yield from") 

218 if t.value: 

219 self.write(" ") 

220 self.dispatch(t.value) 

221 self.write(")") 

222 

223 def _Raise(self, t): 

224 self.fill("raise") 

225 if six.PY3: 

226 if not t.exc: 

227 assert not t.cause 

228 return 

229 self.write(" ") 

230 self.dispatch(t.exc) 

231 if t.cause: 

232 self.write(" from ") 

233 self.dispatch(t.cause) 

234 else: 

235 self.write(" ") 

236 if t.type: 

237 self.dispatch(t.type) 

238 if t.inst: 

239 self.write(", ") 

240 self.dispatch(t.inst) 

241 if t.tback: 

242 self.write(", ") 

243 self.dispatch(t.tback) 

244 

245 def _Try(self, t): 

246 self.fill("try") 

247 self.enter() 

248 self.dispatch(t.body) 

249 self.leave() 

250 for ex in t.handlers: 

251 self.dispatch(ex) 

252 if t.orelse: 

253 self.fill("else") 

254 self.enter() 

255 self.dispatch(t.orelse) 

256 self.leave() 

257 if t.finalbody: 

258 self.fill("finally") 

259 self.enter() 

260 self.dispatch(t.finalbody) 

261 self.leave() 

262 

263 def _TryExcept(self, t): 

264 self.fill("try") 

265 self.enter() 

266 self.dispatch(t.body) 

267 self.leave() 

268 

269 for ex in t.handlers: 

270 self.dispatch(ex) 

271 if t.orelse: 

272 self.fill("else") 

273 self.enter() 

274 self.dispatch(t.orelse) 

275 self.leave() 

276 

277 def _TryFinally(self, t): 

278 if len(t.body) == 1 and isinstance(t.body[0], ast.TryExcept): 

279 # try-except-finally 

280 self.dispatch(t.body) 

281 else: 

282 self.fill("try") 

283 self.enter() 

284 self.dispatch(t.body) 

285 self.leave() 

286 

287 self.fill("finally") 

288 self.enter() 

289 self.dispatch(t.finalbody) 

290 self.leave() 

291 

292 def _ExceptHandler(self, t): 

293 self.fill("except") 

294 if t.type: 

295 self.write(" ") 

296 self.dispatch(t.type) 

297 if t.name: 

298 self.write(" as ") 

299 if six.PY3: 

300 self.write(t.name) 

301 else: 

302 self.dispatch(t.name) 

303 self.enter() 

304 self.dispatch(t.body) 

305 self.leave() 

306 

307 def _ClassDef(self, t): 

308 self.write("\n") 

309 for deco in t.decorator_list: 

310 self.fill("@") 

311 self.dispatch(deco) 

312 self.fill("class "+t.name) 

313 if six.PY3: 

314 self.write("(") 

315 comma = False 

316 for e in t.bases: 

317 if comma: self.write(", ") 

318 else: comma = True 

319 self.dispatch(e) 

320 for e in t.keywords: 

321 if comma: self.write(", ") 

322 else: comma = True 

323 self.dispatch(e) 

324 if sys.version_info[:2] < (3, 5): 

325 if t.starargs: 

326 if comma: self.write(", ") 

327 else: comma = True 

328 self.write("*") 

329 self.dispatch(t.starargs) 

330 if t.kwargs: 

331 if comma: self.write(", ") 

332 else: comma = True 

333 self.write("**") 

334 self.dispatch(t.kwargs) 

335 self.write(")") 

336 elif t.bases: 

337 self.write("(") 

338 for a in t.bases: 

339 self.dispatch(a) 

340 self.write(", ") 

341 self.write(")") 

342 self.enter() 

343 self.dispatch(t.body) 

344 self.leave() 

345 

346 def _FunctionDef(self, t): 

347 self.__FunctionDef_helper(t, "def") 

348 

349 def _AsyncFunctionDef(self, t): 

350 self.__FunctionDef_helper(t, "async def") 

351 

352 def __FunctionDef_helper(self, t, fill_suffix): 

353 self.write("\n") 

354 for deco in t.decorator_list: 

355 self.fill("@") 

356 self.dispatch(deco) 

357 def_str = fill_suffix+" "+t.name + "(" 

358 self.fill(def_str) 

359 self.dispatch(t.args) 

360 self.write(")") 

361 if getattr(t, "returns", False): 

362 self.write(" -> ") 

363 self.dispatch(t.returns) 

364 self.enter() 

365 self.dispatch(t.body) 

366 self.leave() 

367 

368 def _For(self, t): 

369 self.__For_helper("for ", t) 

370 

371 def _AsyncFor(self, t): 

372 self.__For_helper("async for ", t) 

373 

374 def __For_helper(self, fill, t): 

375 self.fill(fill) 

376 self.dispatch(t.target) 

377 self.write(" in ") 

378 self.dispatch(t.iter) 

379 self.enter() 

380 self.dispatch(t.body) 

381 self.leave() 

382 if t.orelse: 

383 self.fill("else") 

384 self.enter() 

385 self.dispatch(t.orelse) 

386 self.leave() 

387 

388 def _If(self, t): 

389 self.fill("if ") 

390 self.dispatch(t.test) 

391 self.enter() 

392 self.dispatch(t.body) 

393 self.leave() 

394 # collapse nested ifs into equivalent elifs. 

395 while (t.orelse and len(t.orelse) == 1 and 

396 isinstance(t.orelse[0], ast.If)): 

397 t = t.orelse[0] 

398 self.fill("elif ") 

399 self.dispatch(t.test) 

400 self.enter() 

401 self.dispatch(t.body) 

402 self.leave() 

403 # final else 

404 if t.orelse: 

405 self.fill("else") 

406 self.enter() 

407 self.dispatch(t.orelse) 

408 self.leave() 

409 

410 def _While(self, t): 

411 self.fill("while ") 

412 self.dispatch(t.test) 

413 self.enter() 

414 self.dispatch(t.body) 

415 self.leave() 

416 if t.orelse: 

417 self.fill("else") 

418 self.enter() 

419 self.dispatch(t.orelse) 

420 self.leave() 

421 

422 def _generic_With(self, t, async_=False): 

423 self.fill("async with " if async_ else "with ") 

424 if hasattr(t, 'items'): 

425 interleave(lambda: self.write(", "), self.dispatch, t.items) 

426 else: 

427 self.dispatch(t.context_expr) 

428 if t.optional_vars: 

429 self.write(" as ") 

430 self.dispatch(t.optional_vars) 

431 self.enter() 

432 self.dispatch(t.body) 

433 self.leave() 

434 

435 def _With(self, t): 

436 self._generic_With(t) 

437 

438 def _AsyncWith(self, t): 

439 self._generic_With(t, async_=True) 

440 

441 # expr 

442 def _Bytes(self, t): 

443 self.write(repr(t.s)) 

444 

445 def _Str(self, tree): 

446 if six.PY3: 

447 self.write(repr(tree.s)) 

448 else: 

449 # if from __future__ import unicode_literals is in effect, 

450 # then we want to output string literals using a 'b' prefix 

451 # and unicode literals with no prefix. 

452 if "unicode_literals" not in self.future_imports: 

453 self.write(repr(tree.s)) 

454 elif isinstance(tree.s, str): 

455 self.write("b" + repr(tree.s)) 

456 elif isinstance(tree.s, unicode): 

457 self.write(repr(tree.s).lstrip("u")) 

458 else: 

459 assert False, "shouldn't get here" 

460 

461 def _JoinedStr(self, t): 

462 # JoinedStr(expr* values) 

463 self.write("f") 

464 string = StringIO() 

465 self._fstring_JoinedStr(t, string.write) 

466 # Deviation from `unparse.py`: Try to find an unused quote. 

467 # This change is made to handle _very_ complex f-strings. 

468 v = string.getvalue() 

469 if '\n' in v or '\r' in v: 

470 quote_types = ["'''", '"""'] 

471 else: 

472 quote_types = ["'", '"', '"""', "'''"] 

473 for quote_type in quote_types: 

474 if quote_type not in v: 

475 v = "{quote_type}{v}{quote_type}".format(quote_type=quote_type, v=v) 

476 break 

477 else: 

478 v = repr(v) 

479 self.write(v) 

480 

481 def _FormattedValue(self, t): 

482 # FormattedValue(expr value, int? conversion, expr? format_spec) 

483 self.write("f") 

484 string = StringIO() 

485 self._fstring_JoinedStr(t, string.write) 

486 self.write(repr(string.getvalue())) 

487 

488 def _fstring_JoinedStr(self, t, write): 

489 for value in t.values: 

490 meth = getattr(self, "_fstring_" + type(value).__name__) 

491 meth(value, write) 

492 

493 def _fstring_Str(self, t, write): 

494 value = t.s.replace("{", "{{").replace("}", "}}") 

495 write(value) 

496 

497 def _fstring_Constant(self, t, write): 

498 assert isinstance(t.value, str) 

499 value = t.value.replace("{", "{{").replace("}", "}}") 

500 write(value) 

501 

502 def _fstring_FormattedValue(self, t, write): 

503 write("{") 

504 expr = StringIO() 

505 Unparser(t.value, expr) 

506 expr = expr.getvalue().rstrip("\n") 

507 if expr.startswith("{"): 

508 write(" ") # Separate pair of opening brackets as "{ {" 

509 write(expr) 

510 if t.conversion != -1: 

511 conversion = chr(t.conversion) 

512 assert conversion in "sra" 

513 write("!{conversion}".format(conversion=conversion)) 

514 if t.format_spec: 

515 write(":") 

516 meth = getattr(self, "_fstring_" + type(t.format_spec).__name__) 

517 meth(t.format_spec, write) 

518 write("}") 

519 

520 def _Name(self, t): 

521 self.write(t.id) 

522 

523 def _NameConstant(self, t): 

524 self.write(repr(t.value)) 

525 

526 def _Repr(self, t): 

527 self.write("`") 

528 self.dispatch(t.value) 

529 self.write("`") 

530 

531 def _write_constant(self, value): 

532 if isinstance(value, (float, complex)): 

533 # Substitute overflowing decimal literal for AST infinities. 

534 self.write(repr(value).replace("inf", INFSTR)) 

535 else: 

536 self.write(repr(value)) 

537 

538 def _Constant(self, t): 

539 value = t.value 

540 if isinstance(value, tuple): 

541 self.write("(") 

542 if len(value) == 1: 

543 self._write_constant(value[0]) 

544 self.write(",") 

545 else: 

546 interleave(lambda: self.write(", "), self._write_constant, value) 

547 self.write(")") 

548 elif value is Ellipsis: # instead of `...` for Py2 compatibility 

549 self.write("...") 

550 else: 

551 if t.kind == "u": 

552 self.write("u") 

553 self._write_constant(t.value) 

554 

555 def _Num(self, t): 

556 repr_n = repr(t.n) 

557 if six.PY3: 

558 self.write(repr_n.replace("inf", INFSTR)) 

559 else: 

560 # Parenthesize negative numbers, to avoid turning (-1)**2 into -1**2. 

561 if repr_n.startswith("-"): 

562 self.write("(") 

563 if "inf" in repr_n and repr_n.endswith("*j"): 

564 repr_n = repr_n.replace("*j", "j") 

565 # Substitute overflowing decimal literal for AST infinities. 

566 self.write(repr_n.replace("inf", INFSTR)) 

567 if repr_n.startswith("-"): 

568 self.write(")") 

569 

570 def _List(self, t): 

571 self.write("[") 

572 interleave(lambda: self.write(", "), self.dispatch, t.elts) 

573 self.write("]") 

574 

575 def _ListComp(self, t): 

576 self.write("[") 

577 self.dispatch(t.elt) 

578 for gen in t.generators: 

579 self.dispatch(gen) 

580 self.write("]") 

581 

582 def _GeneratorExp(self, t): 

583 self.write("(") 

584 self.dispatch(t.elt) 

585 for gen in t.generators: 

586 self.dispatch(gen) 

587 self.write(")") 

588 

589 def _SetComp(self, t): 

590 self.write("{") 

591 self.dispatch(t.elt) 

592 for gen in t.generators: 

593 self.dispatch(gen) 

594 self.write("}") 

595 

596 def _DictComp(self, t): 

597 self.write("{") 

598 self.dispatch(t.key) 

599 self.write(": ") 

600 self.dispatch(t.value) 

601 for gen in t.generators: 

602 self.dispatch(gen) 

603 self.write("}") 

604 

605 def _comprehension(self, t): 

606 if getattr(t, 'is_async', False): 

607 self.write(" async for ") 

608 else: 

609 self.write(" for ") 

610 self.dispatch(t.target) 

611 self.write(" in ") 

612 self.dispatch(t.iter) 

613 for if_clause in t.ifs: 

614 self.write(" if ") 

615 self.dispatch(if_clause) 

616 

617 def _IfExp(self, t): 

618 self.write("(") 

619 self.dispatch(t.body) 

620 self.write(" if ") 

621 self.dispatch(t.test) 

622 self.write(" else ") 

623 self.dispatch(t.orelse) 

624 self.write(")") 

625 

626 def _Set(self, t): 

627 assert(t.elts) # should be at least one element 

628 self.write("{") 

629 interleave(lambda: self.write(", "), self.dispatch, t.elts) 

630 self.write("}") 

631 

632 def _Dict(self, t): 

633 self.write("{") 

634 def write_key_value_pair(k, v): 

635 self.dispatch(k) 

636 self.write(": ") 

637 self.dispatch(v) 

638 

639 def write_item(item): 

640 k, v = item 

641 if k is None: 

642 # for dictionary unpacking operator in dicts {**{'y': 2}} 

643 # see PEP 448 for details 

644 self.write("**") 

645 self.dispatch(v) 

646 else: 

647 write_key_value_pair(k, v) 

648 interleave(lambda: self.write(", "), write_item, zip(t.keys, t.values)) 

649 self.write("}") 

650 

651 def _Tuple(self, t): 

652 self.write("(") 

653 if len(t.elts) == 1: 

654 elt = t.elts[0] 

655 self.dispatch(elt) 

656 self.write(",") 

657 else: 

658 interleave(lambda: self.write(", "), self.dispatch, t.elts) 

659 self.write(")") 

660 

661 unop = {"Invert":"~", "Not": "not", "UAdd":"+", "USub":"-"} 

662 def _UnaryOp(self, t): 

663 self.write("(") 

664 self.write(self.unop[t.op.__class__.__name__]) 

665 self.write(" ") 

666 if six.PY2 and isinstance(t.op, ast.USub) and isinstance(t.operand, ast.Num): 

667 # If we're applying unary minus to a number, parenthesize the number. 

668 # This is necessary: -2147483648 is different from -(2147483648) on 

669 # a 32-bit machine (the first is an int, the second a long), and 

670 # -7j is different from -(7j). (The first has real part 0.0, the second 

671 # has real part -0.0.) 

672 self.write("(") 

673 self.dispatch(t.operand) 

674 self.write(")") 

675 else: 

676 self.dispatch(t.operand) 

677 self.write(")") 

678 

679 binop = { "Add":"+", "Sub":"-", "Mult":"*", "MatMult":"@", "Div":"/", "Mod":"%", 

680 "LShift":"<<", "RShift":">>", "BitOr":"|", "BitXor":"^", "BitAnd":"&", 

681 "FloorDiv":"//", "Pow": "**"} 

682 def _BinOp(self, t): 

683 self.write("(") 

684 self.dispatch(t.left) 

685 self.write(" " + self.binop[t.op.__class__.__name__] + " ") 

686 self.dispatch(t.right) 

687 self.write(")") 

688 

689 cmpops = {"Eq":"==", "NotEq":"!=", "Lt":"<", "LtE":"<=", "Gt":">", "GtE":">=", 

690 "Is":"is", "IsNot":"is not", "In":"in", "NotIn":"not in"} 

691 def _Compare(self, t): 

692 self.write("(") 

693 self.dispatch(t.left) 

694 for o, e in zip(t.ops, t.comparators): 

695 self.write(" " + self.cmpops[o.__class__.__name__] + " ") 

696 self.dispatch(e) 

697 self.write(")") 

698 

699 boolops = {ast.And: 'and', ast.Or: 'or'} 

700 def _BoolOp(self, t): 

701 self.write("(") 

702 s = " %s " % self.boolops[t.op.__class__] 

703 interleave(lambda: self.write(s), self.dispatch, t.values) 

704 self.write(")") 

705 

706 def _Attribute(self,t): 

707 self.dispatch(t.value) 

708 # Special case: 3.__abs__() is a syntax error, so if t.value 

709 # is an integer literal then we need to either parenthesize 

710 # it or add an extra space to get 3 .__abs__(). 

711 if isinstance(t.value, getattr(ast, 'Constant', getattr(ast, 'Num', None))) and isinstance(t.value.n, int): 

712 self.write(" ") 

713 self.write(".") 

714 self.write(t.attr) 

715 

716 def _Call(self, t): 

717 self.dispatch(t.func) 

718 self.write("(") 

719 comma = False 

720 for e in t.args: 

721 if comma: self.write(", ") 

722 else: comma = True 

723 self.dispatch(e) 

724 for e in t.keywords: 

725 if comma: self.write(", ") 

726 else: comma = True 

727 self.dispatch(e) 

728 if sys.version_info[:2] < (3, 5): 

729 if t.starargs: 

730 if comma: self.write(", ") 

731 else: comma = True 

732 self.write("*") 

733 self.dispatch(t.starargs) 

734 if t.kwargs: 

735 if comma: self.write(", ") 

736 else: comma = True 

737 self.write("**") 

738 self.dispatch(t.kwargs) 

739 self.write(")") 

740 

741 def _Subscript(self, t): 

742 self.dispatch(t.value) 

743 self.write("[") 

744 self.dispatch(t.slice) 

745 self.write("]") 

746 

747 def _Starred(self, t): 

748 self.write("*") 

749 self.dispatch(t.value) 

750 

751 # slice 

752 def _Ellipsis(self, t): 

753 self.write("...") 

754 

755 def _Index(self, t): 

756 self.dispatch(t.value) 

757 

758 def _Slice(self, t): 

759 if t.lower: 

760 self.dispatch(t.lower) 

761 self.write(":") 

762 if t.upper: 

763 self.dispatch(t.upper) 

764 if t.step: 

765 self.write(":") 

766 self.dispatch(t.step) 

767 

768 def _ExtSlice(self, t): 

769 interleave(lambda: self.write(', '), self.dispatch, t.dims) 

770 

771 # argument 

772 def _arg(self, t): 

773 self.write(t.arg) 

774 if t.annotation: 

775 self.write(": ") 

776 self.dispatch(t.annotation) 

777 

778 # others 

779 def _arguments(self, t): 

780 first = True 

781 # normal arguments 

782 all_args = getattr(t, 'posonlyargs', []) + t.args 

783 defaults = [None] * (len(all_args) - len(t.defaults)) + t.defaults 

784 for index, elements in enumerate(zip(all_args, defaults), 1): 

785 a, d = elements 

786 if first:first = False 

787 else: self.write(", ") 

788 self.dispatch(a) 

789 if d: 

790 self.write("=") 

791 self.dispatch(d) 

792 if index == len(getattr(t, 'posonlyargs', ())): 

793 self.write(", /") 

794 

795 # varargs, or bare '*' if no varargs but keyword-only arguments present 

796 if t.vararg or getattr(t, "kwonlyargs", False): 

797 if first:first = False 

798 else: self.write(", ") 

799 self.write("*") 

800 if t.vararg: 

801 if hasattr(t.vararg, 'arg'): 

802 self.write(t.vararg.arg) 

803 if t.vararg.annotation: 

804 self.write(": ") 

805 self.dispatch(t.vararg.annotation) 

806 else: 

807 self.write(t.vararg) 

808 if getattr(t, 'varargannotation', None): 

809 self.write(": ") 

810 self.dispatch(t.varargannotation) 

811 

812 # keyword-only arguments 

813 if getattr(t, "kwonlyargs", False): 

814 for a, d in zip(t.kwonlyargs, t.kw_defaults): 

815 if first:first = False 

816 else: self.write(", ") 

817 self.dispatch(a), 

818 if d: 

819 self.write("=") 

820 self.dispatch(d) 

821 

822 # kwargs 

823 if t.kwarg: 

824 if first:first = False 

825 else: self.write(", ") 

826 if hasattr(t.kwarg, 'arg'): 

827 self.write("**"+t.kwarg.arg) 

828 if t.kwarg.annotation: 

829 self.write(": ") 

830 self.dispatch(t.kwarg.annotation) 

831 else: 

832 self.write("**"+t.kwarg) 

833 if getattr(t, 'kwargannotation', None): 

834 self.write(": ") 

835 self.dispatch(t.kwargannotation) 

836 

837 def _keyword(self, t): 

838 if t.arg is None: 

839 # starting from Python 3.5 this denotes a kwargs part of the invocation 

840 self.write("**") 

841 else: 

842 self.write(t.arg) 

843 self.write("=") 

844 self.dispatch(t.value) 

845 

846 def _Lambda(self, t): 

847 self.write("(") 

848 self.write("lambda ") 

849 self.dispatch(t.args) 

850 self.write(": ") 

851 self.dispatch(t.body) 

852 self.write(")") 

853 

854 def _alias(self, t): 

855 self.write(t.name) 

856 if t.asname: 

857 self.write(" as "+t.asname) 

858 

859 def _withitem(self, t): 

860 self.dispatch(t.context_expr) 

861 if t.optional_vars: 

862 self.write(" as ") 

863 self.dispatch(t.optional_vars) 

864 

865def roundtrip(filename, output=sys.stdout): 

866 if six.PY3: 

867 with open(filename, "rb") as pyfile: 

868 encoding = tokenize.detect_encoding(pyfile.readline)[0] 

869 with open(filename, "r", encoding=encoding) as pyfile: 

870 source = pyfile.read() 

871 else: 

872 with open(filename, "r") as pyfile: 

873 source = pyfile.read() 

874 tree = compile(source, filename, "exec", ast.PyCF_ONLY_AST, dont_inherit=True) 

875 Unparser(tree, output) 

876 

877 

878 

879def testdir(a): 

880 try: 

881 names = [n for n in os.listdir(a) if n.endswith('.py')] 

882 except OSError: 

883 print("Directory not readable: %s" % a, file=sys.stderr) 

884 else: 

885 for n in names: 

886 fullname = os.path.join(a, n) 

887 if os.path.isfile(fullname): 

888 output = StringIO() 

889 print('Testing %s' % fullname) 

890 try: 

891 roundtrip(fullname, output) 

892 except Exception as e: 

893 print(' Failed to compile, exception is %s' % repr(e)) 

894 elif os.path.isdir(fullname): 

895 testdir(fullname) 

896 

897def main(args): 

898 if args[0] == '--testdir': 

899 for a in args[1:]: 

900 testdir(a) 

901 else: 

902 for a in args: 

903 roundtrip(a) 

904 

905if __name__=='__main__': 

906 main(sys.argv[1:])