Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/genshi/template/astutil.py: 20%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

664 statements  

1# -*- coding: utf-8 -*- 

2# 

3# Copyright (C) 2008-2010 Edgewall Software 

4# All rights reserved. 

5# 

6# This software is licensed as described in the file COPYING, which 

7# you should have received as part of this distribution. The terms 

8# are also available at http://genshi.edgewall.org/wiki/License. 

9# 

10# This software consists of voluntary contributions made by many 

11# individuals. For the exact contribution history, see the revision 

12# history and logs, available at http://genshi.edgewall.org/log/. 

13 

14"""Support classes for generating code from abstract syntax trees.""" 

15 

16from genshi.compat import ast as _ast, _ast_Constant, IS_PYTHON2, isstring, \ 

17 _ast_Ellipsis, _ast_Ellipsis_value 

18 

19__docformat__ = 'restructuredtext en' 

20 

21def parse(source, mode): 

22 return compile(source, '', mode, _ast.PyCF_ONLY_AST) 

23 

24 

25class ASTCodeGenerator(object): 

26 """General purpose base class for AST transformations. 

27 

28 Every visitor method can be overridden to return an AST node that has been 

29 altered or replaced in some way. 

30 """ 

31 def __init__(self, tree): 

32 self.lines_info = [] 

33 self.line_info = None 

34 self.code = '' 

35 self.line = None 

36 self.last = None 

37 self.indent = 0 

38 self.blame_stack = [] 

39 self.visit(tree) 

40 if self.line.strip(): 

41 self.code += self.line + '\n' 

42 self.lines_info.append(self.line_info) 

43 self.line = None 

44 self.line_info = None 

45 

46 def _change_indent(self, delta): 

47 self.indent += delta 

48 

49 def _new_line(self): 

50 if self.line is not None: 

51 self.code += self.line + '\n' 

52 self.lines_info.append(self.line_info) 

53 self.line = ' '*4*self.indent 

54 if len(self.blame_stack) == 0: 

55 self.line_info = [] 

56 self.last = None 

57 else: 

58 self.line_info = [(0, self.blame_stack[-1],)] 

59 self.last = self.blame_stack[-1] 

60 

61 def _write(self, s): 

62 if len(s) == 0: 

63 return 

64 if len(self.blame_stack) == 0: 

65 if self.last is not None: 

66 self.last = None 

67 self.line_info.append((len(self.line), self.last)) 

68 else: 

69 if self.last != self.blame_stack[-1]: 

70 self.last = self.blame_stack[-1] 

71 self.line_info.append((len(self.line), self.last)) 

72 self.line += s 

73 

74 def visit(self, node): 

75 if node is None: 

76 return None 

77 if type(node) is tuple: 

78 return tuple([self.visit(n) for n in node]) 

79 try: 

80 self.blame_stack.append((node.lineno, node.col_offset,)) 

81 info = True 

82 except AttributeError: 

83 info = False 

84 if isinstance(node, (bool, bytes, float, int, str)): 

85 # something['foo'] just returns 'foo' as str in Python 3.9 while 

86 # Python 3.8 and earlier returned a Constant(). 

87 node = _ast_Constant(node) 

88 visitor = getattr(self, 'visit_%s' % node.__class__.__name__, None) 

89 if visitor is None: 

90 raise Exception('Unhandled node type %r' % type(node)) 

91 ret = visitor(node) 

92 if info: 

93 self.blame_stack.pop() 

94 return ret 

95 

96 def visit_Module(self, node): 

97 for n in node.body: 

98 self.visit(n) 

99 visit_Interactive = visit_Module 

100 visit_Suite = visit_Module 

101 

102 def visit_Expression(self, node): 

103 self._new_line() 

104 return self.visit(node.body) 

105 

106 # Python < 3.4 

107 # arguments = (expr* args, identifier? vararg, 

108 # identifier? kwarg, expr* defaults) 

109 # 

110 # Python >= 3.4 

111 # arguments = (arg* args, arg? vararg, arg* kwonlyargs, expr* kw_defaults, 

112 # arg? kwarg, expr* defaults) 

113 def visit_arguments(self, node): 

114 def write_possible_comma(): 

115 if _first[0]: 

116 _first[0] = False 

117 else: 

118 self._write(', ') 

119 _first = [True] 

120 

121 def write_args(args, defaults): 

122 no_default_count = len(args) - len(defaults) 

123 for i, arg in enumerate(args): 

124 write_possible_comma() 

125 self.visit(arg) 

126 default_idx = i - no_default_count 

127 if default_idx >= 0 and defaults[default_idx] is not None: 

128 self._write('=') 

129 self.visit(defaults[i - no_default_count]) 

130 

131 write_args(node.args, node.defaults) 

132 if getattr(node, 'vararg', None): 

133 write_possible_comma() 

134 self._write('*') 

135 if isstring(node.vararg): 

136 self._write(node.vararg) 

137 else: 

138 self.visit(node.vararg) 

139 if getattr(node, 'kwonlyargs', None): 

140 write_args(node.kwonlyargs, node.kw_defaults) 

141 if getattr(node, 'kwarg', None): 

142 write_possible_comma() 

143 self._write('**') 

144 if isstring(node.kwarg): 

145 self._write(node.kwarg) 

146 else: 

147 self.visit(node.kwarg) 

148 

149 if not IS_PYTHON2: 

150 # In Python 3 arguments get a special node 

151 def visit_arg(self, node): 

152 self._write(node.arg) 

153 

154 def visit_Starred(self, node): 

155 self._write('*') 

156 self.visit(node.value) 

157 

158 # FunctionDef(identifier name, arguments args, 

159 # stmt* body, expr* decorator_list) 

160 def visit_FunctionDef(self, node): 

161 decarators = () 

162 if hasattr(node, 'decorator_list'): 

163 decorators = getattr(node, 'decorator_list') 

164 else: # different name in earlier Python versions 

165 decorators = getattr(node, 'decorators', ()) 

166 for decorator in decorators: 

167 self._new_line() 

168 self._write('@') 

169 self.visit(decorator) 

170 self._new_line() 

171 self._write('def ' + node.name + '(') 

172 self.visit(node.args) 

173 self._write('):') 

174 self._change_indent(1) 

175 for statement in node.body: 

176 self.visit(statement) 

177 self._change_indent(-1) 

178 

179 # ClassDef(identifier name, expr* bases, stmt* body) 

180 def visit_ClassDef(self, node): 

181 self._new_line() 

182 self._write('class ' + node.name) 

183 if node.bases: 

184 self._write('(') 

185 self.visit(node.bases[0]) 

186 for base in node.bases[1:]: 

187 self._write(', ') 

188 self.visit(base) 

189 self._write(')') 

190 self._write(':') 

191 self._change_indent(1) 

192 for statement in node.body: 

193 self.visit(statement) 

194 self._change_indent(-1) 

195 

196 # Return(expr? value) 

197 def visit_Return(self, node): 

198 self._new_line() 

199 self._write('return') 

200 if getattr(node, 'value', None): 

201 self._write(' ') 

202 self.visit(node.value) 

203 

204 # Delete(expr* targets) 

205 def visit_Delete(self, node): 

206 self._new_line() 

207 self._write('del ') 

208 self.visit(node.targets[0]) 

209 for target in node.targets[1:]: 

210 self._write(', ') 

211 self.visit(target) 

212 

213 # Assign(expr* targets, expr value) 

214 def visit_Assign(self, node): 

215 self._new_line() 

216 for target in node.targets: 

217 self.visit(target) 

218 self._write(' = ') 

219 self.visit(node.value) 

220 

221 # AugAssign(expr target, operator op, expr value) 

222 def visit_AugAssign(self, node): 

223 self._new_line() 

224 self.visit(node.target) 

225 self._write(' ' + self.binary_operators[node.op.__class__] + '= ') 

226 self.visit(node.value) 

227 

228 # Print(expr? dest, expr* values, bool nl) 

229 def visit_Print(self, node): 

230 self._new_line() 

231 self._write('print') 

232 if getattr(node, 'dest', None): 

233 self._write(' >> ') 

234 self.visit(node.dest) 

235 if getattr(node, 'values', None): 

236 self._write(', ') 

237 else: 

238 self._write(' ') 

239 if getattr(node, 'values', None): 

240 self.visit(node.values[0]) 

241 for value in node.values[1:]: 

242 self._write(', ') 

243 self.visit(value) 

244 if not node.nl: 

245 self._write(',') 

246 

247 # For(expr target, expr iter, stmt* body, stmt* orelse) 

248 def visit_For(self, node): 

249 self._new_line() 

250 self._write('for ') 

251 self.visit(node.target) 

252 self._write(' in ') 

253 self.visit(node.iter) 

254 self._write(':') 

255 self._change_indent(1) 

256 for statement in node.body: 

257 self.visit(statement) 

258 self._change_indent(-1) 

259 if getattr(node, 'orelse', None): 

260 self._new_line() 

261 self._write('else:') 

262 self._change_indent(1) 

263 for statement in node.orelse: 

264 self.visit(statement) 

265 self._change_indent(-1) 

266 

267 # While(expr test, stmt* body, stmt* orelse) 

268 def visit_While(self, node): 

269 self._new_line() 

270 self._write('while ') 

271 self.visit(node.test) 

272 self._write(':') 

273 self._change_indent(1) 

274 for statement in node.body: 

275 self.visit(statement) 

276 self._change_indent(-1) 

277 if getattr(node, 'orelse', None): 

278 self._new_line() 

279 self._write('else:') 

280 self._change_indent(1) 

281 for statement in node.orelse: 

282 self.visit(statement) 

283 self._change_indent(-1) 

284 

285 # If(expr test, stmt* body, stmt* orelse) 

286 def visit_If(self, node): 

287 self._new_line() 

288 self._write('if ') 

289 self.visit(node.test) 

290 self._write(':') 

291 self._change_indent(1) 

292 for statement in node.body: 

293 self.visit(statement) 

294 self._change_indent(-1) 

295 if getattr(node, 'orelse', None): 

296 self._new_line() 

297 self._write('else:') 

298 self._change_indent(1) 

299 for statement in node.orelse: 

300 self.visit(statement) 

301 self._change_indent(-1) 

302 

303 # With(expr context_expr, expr? optional_vars, stmt* body) 

304 # With(withitem* items, stmt* body) in Python >= 3.3 

305 def visit_With(self, node): 

306 self._new_line() 

307 self._write('with ') 

308 items = getattr(node, 'items', None) 

309 first = True 

310 if items is None: 

311 items = [node] 

312 for item in items: 

313 if not first: 

314 self._write(', ') 

315 first = False 

316 self.visit(item.context_expr) 

317 if getattr(item, 'optional_vars', None): 

318 self._write(' as ') 

319 self.visit(item.optional_vars) 

320 self._write(':') 

321 self._change_indent(1) 

322 for statement in node.body: 

323 self.visit(statement) 

324 self._change_indent(-1) 

325 

326 # Raise(expr? type, expr? inst, expr? tback) 

327 def visit_Raise(self, node): 

328 self._new_line() 

329 self._write('raise') 

330 if IS_PYTHON2: 

331 if not node.type: 

332 return 

333 self._write(' ') 

334 self.visit(node.type) 

335 if not node.inst: 

336 return 

337 self._write(', ') 

338 self.visit(node.inst) 

339 if not node.tback: 

340 return 

341 self._write(', ') 

342 self.visit(node.tback) 

343 else: 

344 if not node.exc: 

345 return 

346 self._write(' ') 

347 self.visit(node.exc) 

348 if not node.cause: 

349 return 

350 self._write(' from ') 

351 self.visit(node.cause) 

352 

353 # TryExcept(stmt* body, excepthandler* handlers, stmt* orelse) 

354 def visit_TryExcept(self, node): 

355 self._new_line() 

356 self._write('try:') 

357 self._change_indent(1) 

358 for statement in node.body: 

359 self.visit(statement) 

360 self._change_indent(-1) 

361 if getattr(node, 'handlers', None): 

362 for handler in node.handlers: 

363 self.visit(handler) 

364 self._new_line() 

365 if getattr(node, 'orelse', None): 

366 self._write('else:') 

367 self._change_indent(1) 

368 for statement in node.orelse: 

369 self.visit(statement) 

370 self._change_indent(-1) 

371 

372 # excepthandler = (expr? type, expr? name, stmt* body) 

373 def visit_ExceptHandler(self, node): 

374 self._new_line() 

375 self._write('except') 

376 if getattr(node, 'type', None): 

377 self._write(' ') 

378 self.visit(node.type) 

379 if getattr(node, 'name', None): 

380 self._write(', ') 

381 self.visit(node.name) 

382 self._write(':') 

383 self._change_indent(1) 

384 for statement in node.body: 

385 self.visit(statement) 

386 self._change_indent(-1) 

387 visit_excepthandler = visit_ExceptHandler 

388 

389 # TryFinally(stmt* body, stmt* finalbody) 

390 def visit_TryFinally(self, node): 

391 self._new_line() 

392 self._write('try:') 

393 self._change_indent(1) 

394 for statement in node.body: 

395 self.visit(statement) 

396 self._change_indent(-1) 

397 

398 if getattr(node, 'finalbody', None): 

399 self._new_line() 

400 self._write('finally:') 

401 self._change_indent(1) 

402 for statement in node.finalbody: 

403 self.visit(statement) 

404 self._change_indent(-1) 

405 

406 # New in Py3.3 

407 # Try(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody) 

408 def visit_Try(self, node): 

409 self._new_line() 

410 self._write('try:') 

411 self._change_indent(1) 

412 for statement in node.body: 

413 self.visit(statement) 

414 self._change_indent(-1) 

415 if getattr(node, 'handlers', None): 

416 for handler in node.handlers: 

417 self.visit(handler) 

418 self._new_line() 

419 if getattr(node, 'orelse', None): 

420 self._write('else:') 

421 self._change_indent(1) 

422 for statement in node.orelse: 

423 self.visit(statement) 

424 self._change_indent(-1) 

425 if getattr(node, 'finalbody', None): 

426 self._new_line() 

427 self._write('finally:') 

428 self._change_indent(1) 

429 for statement in node.finalbody: 

430 self.visit(statement) 

431 self._change_indent(-1) 

432 

433 # Assert(expr test, expr? msg) 

434 def visit_Assert(self, node): 

435 self._new_line() 

436 self._write('assert ') 

437 self.visit(node.test) 

438 if getattr(node, 'msg', None): 

439 self._write(', ') 

440 self.visit(node.msg) 

441 

442 def visit_alias(self, node): 

443 self._write(node.name) 

444 if getattr(node, 'asname', None): 

445 self._write(' as ') 

446 self._write(node.asname) 

447 

448 # Import(alias* names) 

449 def visit_Import(self, node): 

450 self._new_line() 

451 self._write('import ') 

452 self.visit(node.names[0]) 

453 for name in node.names[1:]: 

454 self._write(', ') 

455 self.visit(name) 

456 

457 # ImportFrom(identifier module, alias* names, int? level) 

458 def visit_ImportFrom(self, node): 

459 self._new_line() 

460 self._write('from ') 

461 if node.level: 

462 self._write('.' * node.level) 

463 self._write(node.module) 

464 self._write(' import ') 

465 self.visit(node.names[0]) 

466 for name in node.names[1:]: 

467 self._write(', ') 

468 self.visit(name) 

469 

470 # Exec(expr body, expr? globals, expr? locals) 

471 def visit_Exec(self, node): 

472 self._new_line() 

473 self._write('exec ') 

474 self.visit(node.body) 

475 if not node.globals: 

476 return 

477 self._write(', ') 

478 self.visit(node.globals) 

479 if not node.locals: 

480 return 

481 self._write(', ') 

482 self.visit(node.locals) 

483 

484 # Global(identifier* names) 

485 def visit_Global(self, node): 

486 self._new_line() 

487 self._write('global ') 

488 self.visit(node.names[0]) 

489 for name in node.names[1:]: 

490 self._write(', ') 

491 self.visit(name) 

492 

493 # Expr(expr value) 

494 def visit_Expr(self, node): 

495 self._new_line() 

496 self.visit(node.value) 

497 

498 # Pass 

499 def visit_Pass(self, node): 

500 self._new_line() 

501 self._write('pass') 

502 

503 # Break 

504 def visit_Break(self, node): 

505 self._new_line() 

506 self._write('break') 

507 

508 # Continue 

509 def visit_Continue(self, node): 

510 self._new_line() 

511 self._write('continue') 

512 

513 ### EXPRESSIONS 

514 def with_parens(f): 

515 def _f(self, node): 

516 self._write('(') 

517 f(self, node) 

518 self._write(')') 

519 return _f 

520 

521 bool_operators = {_ast.And: 'and', _ast.Or: 'or'} 

522 

523 # BoolOp(boolop op, expr* values) 

524 @with_parens 

525 def visit_BoolOp(self, node): 

526 joiner = ' ' + self.bool_operators[node.op.__class__] + ' ' 

527 self.visit(node.values[0]) 

528 for value in node.values[1:]: 

529 self._write(joiner) 

530 self.visit(value) 

531 

532 binary_operators = { 

533 _ast.Add: '+', 

534 _ast.Sub: '-', 

535 _ast.Mult: '*', 

536 _ast.Div: '/', 

537 _ast.Mod: '%', 

538 _ast.Pow: '**', 

539 _ast.LShift: '<<', 

540 _ast.RShift: '>>', 

541 _ast.BitOr: '|', 

542 _ast.BitXor: '^', 

543 _ast.BitAnd: '&', 

544 _ast.FloorDiv: '//' 

545 } 

546 

547 # BinOp(expr left, operator op, expr right) 

548 @with_parens 

549 def visit_BinOp(self, node): 

550 self.visit(node.left) 

551 self._write(' ' + self.binary_operators[node.op.__class__] + ' ') 

552 self.visit(node.right) 

553 

554 unary_operators = { 

555 _ast.Invert: '~', 

556 _ast.Not: 'not', 

557 _ast.UAdd: '+', 

558 _ast.USub: '-', 

559 } 

560 

561 # UnaryOp(unaryop op, expr operand) 

562 def visit_UnaryOp(self, node): 

563 self._write(self.unary_operators[node.op.__class__] + ' ') 

564 self.visit(node.operand) 

565 

566 # Lambda(arguments args, expr body) 

567 @with_parens 

568 def visit_Lambda(self, node): 

569 self._write('lambda ') 

570 self.visit(node.args) 

571 self._write(': ') 

572 self.visit(node.body) 

573 

574 # IfExp(expr test, expr body, expr orelse) 

575 @with_parens 

576 def visit_IfExp(self, node): 

577 self.visit(node.body) 

578 self._write(' if ') 

579 self.visit(node.test) 

580 self._write(' else ') 

581 self.visit(node.orelse) 

582 

583 # Dict(expr* keys, expr* values) 

584 def visit_Dict(self, node): 

585 self._write('{') 

586 for key, value in zip(node.keys, node.values): 

587 self.visit(key) 

588 self._write(': ') 

589 self.visit(value) 

590 self._write(', ') 

591 self._write('}') 

592 

593 # ListComp(expr elt, comprehension* generators) 

594 def visit_ListComp(self, node): 

595 self._write('[') 

596 self.visit(node.elt) 

597 for generator in node.generators: 

598 # comprehension = (expr target, expr iter, expr* ifs) 

599 self._write(' for ') 

600 self.visit(generator.target) 

601 self._write(' in ') 

602 self.visit(generator.iter) 

603 for ifexpr in generator.ifs: 

604 self._write(' if ') 

605 self.visit(ifexpr) 

606 self._write(']') 

607 

608 # GeneratorExp(expr elt, comprehension* generators) 

609 def visit_GeneratorExp(self, node): 

610 self._write('(') 

611 self.visit(node.elt) 

612 for generator in node.generators: 

613 # comprehension = (expr target, expr iter, expr* ifs) 

614 self._write(' for ') 

615 self.visit(generator.target) 

616 self._write(' in ') 

617 self.visit(generator.iter) 

618 for ifexpr in generator.ifs: 

619 self._write(' if ') 

620 self.visit(ifexpr) 

621 self._write(')') 

622 

623 # Yield(expr? value) 

624 def visit_Yield(self, node): 

625 self._write('yield') 

626 if getattr(node, 'value', None): 

627 self._write(' ') 

628 self.visit(node.value) 

629 

630 comparision_operators = { 

631 _ast.Eq: '==', 

632 _ast.NotEq: '!=', 

633 _ast.Lt: '<', 

634 _ast.LtE: '<=', 

635 _ast.Gt: '>', 

636 _ast.GtE: '>=', 

637 _ast.Is: 'is', 

638 _ast.IsNot: 'is not', 

639 _ast.In: 'in', 

640 _ast.NotIn: 'not in', 

641 } 

642 

643 # Compare(expr left, cmpop* ops, expr* comparators) 

644 @with_parens 

645 def visit_Compare(self, node): 

646 self.visit(node.left) 

647 for op, comparator in zip(node.ops, node.comparators): 

648 self._write(' ' + self.comparision_operators[op.__class__] + ' ') 

649 self.visit(comparator) 

650 

651 # Call(expr func, expr* args, keyword* keywords, 

652 # expr? starargs, expr? kwargs) 

653 def visit_Call(self, node): 

654 self.visit(node.func) 

655 self._write('(') 

656 first = True 

657 for arg in node.args: 

658 if not first: 

659 self._write(', ') 

660 first = False 

661 self.visit(arg) 

662 

663 for keyword in node.keywords: 

664 if not first: 

665 self._write(', ') 

666 first = False 

667 if not keyword.arg: 

668 # Python 3.5+ star-star args 

669 self._write('**') 

670 else: 

671 # keyword = (identifier arg, expr value) 

672 self._write(keyword.arg) 

673 self._write('=') 

674 self.visit(keyword.value) 

675 if getattr(node, 'starargs', None): 

676 if not first: 

677 self._write(', ') 

678 first = False 

679 self._write('*') 

680 self.visit(node.starargs) 

681 

682 if getattr(node, 'kwargs', None): 

683 if not first: 

684 self._write(', ') 

685 first = False 

686 self._write('**') 

687 self.visit(node.kwargs) 

688 self._write(')') 

689 

690 # Repr(expr value) 

691 def visit_Repr(self, node): 

692 self._write('`') 

693 self.visit(node.value) 

694 self._write('`') 

695 

696 # Num(object n) 

697 def visit_Num(self, node): 

698 self._write(repr(node.n)) 

699 

700 # Str(string s) 

701 def visit_Str(self, node): 

702 self._write(repr(node.s)) 

703 

704 # Constant(object value) 

705 def visit_Constant(self, node): 

706 self._write(repr(node.value)) 

707 

708 if not IS_PYTHON2: 

709 # Bytes(bytes s) 

710 def visit_Bytes(self, node): 

711 self._write(repr(node.s)) 

712 

713 # Attribute(expr value, identifier attr, expr_context ctx) 

714 def visit_Attribute(self, node): 

715 self.visit(node.value) 

716 self._write('.') 

717 self._write(node.attr) 

718 

719 # Subscript(expr value, slice slice, expr_context ctx) 

720 def visit_Subscript(self, node): 

721 self.visit(node.value) 

722 self._write('[') 

723 def _process_slice(node): 

724 if ( 

725 isinstance(node, _ast_Ellipsis) 

726 and _ast_Ellipsis_value(node) == Ellipsis 

727 ): 

728 self._write('...') 

729 elif isinstance(node, _ast.Slice): 

730 if getattr(node, 'lower', 'None'): 

731 self.visit(node.lower) 

732 self._write(':') 

733 if getattr(node, 'upper', None): 

734 self.visit(node.upper) 

735 if getattr(node, 'step', None): 

736 self._write(':') 

737 self.visit(node.step) 

738 elif isinstance(node, _ast.Index): 

739 self.visit(node.value) 

740 elif isinstance(node, _ast.ExtSlice): 

741 self.visit(node.dims[0]) 

742 for dim in node.dims[1:]: 

743 self._write(', ') 

744 self.visit(dim) 

745 else: 

746 self.visit(node) 

747 _process_slice(node.slice) 

748 self._write(']') 

749 

750 # Name(identifier id, expr_context ctx) 

751 def visit_Name(self, node): 

752 self._write(node.id) 

753 

754 # NameConstant(singleton value) 

755 def visit_NameConstant(self, node): 

756 if node.value is None: 

757 self._write('None') 

758 elif node.value is True: 

759 self._write('True') 

760 elif node.value is False: 

761 self._write('False') 

762 else: 

763 raise Exception("Unknown NameConstant %r" % (node.value,)) 

764 

765 # List(expr* elts, expr_context ctx) 

766 def visit_List(self, node): 

767 self._write('[') 

768 for elt in node.elts: 

769 self.visit(elt) 

770 self._write(', ') 

771 self._write(']') 

772 

773 # Tuple(expr *elts, expr_context ctx) 

774 def visit_Tuple(self, node): 

775 self._write('(') 

776 for elt in node.elts: 

777 # In Python 3.9 simple types (which includes NoneType) are 

778 # represented by their value in "subscription" expressions. 

779 # However self.visit() returns None if elt is None leading to 

780 # invalid generated code. So we deal with the special case here. 

781 # Example code triggering this: value[None] 

782 self.visit(elt) if (elt is not None) else self._write('None') 

783 self._write(', ') 

784 self._write(')') 

785 

786 

787class ASTTransformer(object): 

788 """General purpose base class for AST transformations. 

789  

790 Every visitor method can be overridden to return an AST node that has been 

791 altered or replaced in some way. 

792 """ 

793 

794 def visit(self, node): 

795 if node is None: 

796 return None 

797 if type(node) is tuple: 

798 return tuple([self.visit(n) for n in node]) 

799 visitor = getattr(self, 'visit_%s' % node.__class__.__name__, None) 

800 if visitor is None: 

801 return node 

802 return visitor(node) 

803 

804 def _clone(self, node): 

805 clone = node.__class__() 

806 for name in getattr(clone, '_attributes', ()): 

807 try: 

808 setattr(clone, name, getattr(node, name)) 

809 except AttributeError: 

810 pass 

811 for name in clone._fields: 

812 try: 

813 value = getattr(node, name) 

814 except AttributeError: 

815 pass 

816 else: 

817 if value is None: 

818 pass 

819 elif isinstance(value, list): 

820 value = [self.visit(x) for x in value] 

821 elif isinstance(value, tuple): 

822 value = tuple(self.visit(x) for x in value) 

823 else: 

824 value = self.visit(value) 

825 setattr(clone, name, value) 

826 return clone 

827 

828 visit_Module = _clone 

829 visit_Interactive = _clone 

830 visit_Expression = _clone 

831 visit_Suite = _clone 

832 

833 visit_FunctionDef = _clone 

834 visit_ClassDef = _clone 

835 visit_Return = _clone 

836 visit_Delete = _clone 

837 visit_Assign = _clone 

838 visit_AugAssign = _clone 

839 visit_Print = _clone 

840 visit_For = _clone 

841 visit_While = _clone 

842 visit_If = _clone 

843 visit_With = _clone 

844 visit_Raise = _clone 

845 visit_TryExcept = _clone 

846 visit_TryFinally = _clone 

847 visit_Try = _clone 

848 visit_Assert = _clone 

849 visit_ExceptHandler = _clone 

850 

851 visit_Import = _clone 

852 visit_ImportFrom = _clone 

853 visit_Exec = _clone 

854 visit_Global = _clone 

855 visit_Expr = _clone 

856 # Pass, Break, Continue don't need to be copied 

857 

858 visit_BoolOp = _clone 

859 visit_BinOp = _clone 

860 visit_UnaryOp = _clone 

861 visit_Lambda = _clone 

862 visit_IfExp = _clone 

863 visit_Dict = _clone 

864 visit_ListComp = _clone 

865 visit_GeneratorExp = _clone 

866 visit_Yield = _clone 

867 visit_Compare = _clone 

868 visit_Call = _clone 

869 visit_Repr = _clone 

870 # Num, Str don't need to be copied 

871 

872 visit_Attribute = _clone 

873 visit_Subscript = _clone 

874 visit_Name = _clone 

875 visit_NameConstant = _clone 

876 visit_List = _clone 

877 visit_Tuple = _clone 

878 

879 visit_comprehension = _clone 

880 visit_excepthandler = _clone 

881 visit_arguments = _clone 

882 visit_keyword = _clone 

883 visit_alias = _clone 

884 

885 visit_Slice = _clone 

886 visit_ExtSlice = _clone 

887 visit_Index = _clone 

888 

889 del _clone