Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# This file is part of the lib3to6 project 

2# https://github.com/mbarkhau/lib3to6 

3# 

4# Copyright (c) 2019-2021 Manuel Barkhau (mbarkhau@gmail.com) - MIT License 

5# SPDX-License-Identifier: MIT 

6 

7import ast 

8import sys 

9import typing as typ 

10 

11from . import utils 

12from . import common 

13from . import fixer_base as fb 

14from .fixers_future import DivisionFutureFixer 

15from .fixers_future import GeneratorsFutureFixer 

16from .fixers_future import AnnotationsFutureFixer 

17from .fixers_future import NestedScopesFutureFixer 

18from .fixers_future import GeneratorStopFutureFixer 

19from .fixers_future import PrintFunctionFutureFixer 

20from .fixers_future import WithStatementFutureFixer 

21from .fixers_future import AbsoluteImportFutureFixer 

22from .fixers_future import UnicodeLiteralsFutureFixer 

23from .fixers_future import RemoveUnsupportedFuturesFixer 

24from .fixers_builtin_rename import UnichrToChrFixer 

25from .fixers_builtin_rename import UnicodeToStrFixer 

26from .fixers_builtin_rename import XrangeToRangeFixer 

27from .fixers_builtin_rename import RawInputToInputFixer 

28from .fixers_import_fallback import QueueImportFallbackFixer 

29from .fixers_import_fallback import DbmGnuImportFallbackFixer 

30from .fixers_import_fallback import PickleImportFallbackFixer 

31from .fixers_import_fallback import ThreadImportFallbackFixer 

32from .fixers_import_fallback import WinRegImportFallbackFixer 

33from .fixers_import_fallback import CopyRegImportFallbackFixer 

34from .fixers_import_fallback import ReprLibImportFallbackFixer 

35from .fixers_import_fallback import TkinterImportFallbackFixer 

36from .fixers_import_fallback import BuiltinsImportFallbackFixer 

37from .fixers_import_fallback import HtmlParserImportFallbackFixer 

38from .fixers_import_fallback import HttpClientImportFallbackFixer 

39from .fixers_import_fallback import TkinterDndImportFallbackFixer 

40from .fixers_import_fallback import TkinterTixImportFallbackFixer 

41from .fixers_import_fallback import TkinterTtkImportFallbackFixer 

42from .fixers_import_fallback import DummyThreadImportFallbackFixer 

43from .fixers_import_fallback import HttpCookiesImportFallbackFixer 

44from .fixers_import_fallback import TkinterFontImportFallbackFixer 

45from .fixers_import_fallback import UrllibErrorImportFallbackFixer 

46from .fixers_import_fallback import UrllibParseImportFallbackFixer 

47from .fixers_import_fallback import ConfigParserImportFallbackFixer 

48from .fixers_import_fallback import SocketServerImportFallbackFixer 

49from .fixers_import_fallback import XMLRPCClientImportFallbackFixer 

50from .fixers_import_fallback import XmlrpcServerImportFallbackFixer 

51from .fixers_import_fallback import EmailMimeBaseImportFallbackFixer 

52from .fixers_import_fallback import EmailMimeTextImportFallbackFixer 

53from .fixers_import_fallback import HttpCookiejarImportFallbackFixer 

54from .fixers_import_fallback import TkinterDialogImportFallbackFixer 

55from .fixers_import_fallback import UrllibRequestImportFallbackFixer 

56from .fixers_import_fallback import EmailMimeImageImportFallbackFixer 

57from .fixers_import_fallback import TkinterConstantsImportFallbackFixer 

58from .fixers_import_fallback import TkinterMessageboxImportFallbackFixer 

59from .fixers_import_fallback import UrllibRobotParserImportFallbackFixer 

60from .fixers_import_fallback import EmailMimeMultipartImportFallbackFixer 

61from .fixers_import_fallback import TkinterColorchooserImportFallbackFixer 

62from .fixers_import_fallback import TkinterCommonDialogImportFallbackFixer 

63from .fixers_import_fallback import TkinterScrolledTextImportFallbackFixer 

64from .fixers_import_fallback import EmailMimeNonmultipartImportFallbackFixer 

65from .fixers_unpacking_generalization import UnpackingGeneralizationsFixer 

66 

67AstStr = getattr(ast, 'Str', ast.Constant) 

68 

69 

70def is_const_node(node: ast.AST) -> bool: 

71 return node is None or any(isinstance(node, cntype) for cntype in common.ConstantNodeTypes) 

72 

73 

74Elt = typ.Union[ast.expr, ast.Name, ast.Constant, ast.Subscript] 

75Elts = typ.List[Elt] 

76 

77 

78AnnoNode = typ.Union[ast.arg, ast.AnnAssign, ast.FunctionDef] 

79 

80 

81class _FRAFContext: 

82 

83 local_classes: typ.Set[str] 

84 known_classes: typ.Set[str] 

85 

86 def __init__(self, local_classes: typ.Set[str]) -> None: 

87 self.local_classes = local_classes 

88 self.known_classes = set() 

89 

90 def is_forward_ref(self, name: str) -> bool: 

91 return name in self.local_classes and name not in self.known_classes 

92 

93 def update_index_elts(self, elts: Elts) -> None: 

94 # NOTE (mb 2020-07-19): We modify elts during iteration 

95 # pylint:disable=consider-using-enumerate 

96 for i in range(len(elts)): 

97 elt = elts[i] 

98 if is_const_node(elt) or isinstance(elt, ast.Attribute): 

99 continue 

100 

101 if isinstance(elt, ast.Name): 

102 if self.is_forward_ref(elt.id): 

103 elts[i] = ast.Constant(elt.id) 

104 elif isinstance(elt, ast.Subscript): 

105 self.update_subscript(elt) 

106 elif isinstance(elt, ast.List): 

107 self.update_index_elts(elt.elts) 

108 else: 

109 msg = f"Error fixing index element with forward ref of type {type(elt)}" 

110 raise common.FixerError(msg, elt) 

111 

112 def update_subscript(self, val: ast.Subscript) -> None: 

113 idx = val.slice 

114 if isinstance(idx, ast.Tuple): 

115 self.update_index_elts(idx.elts) 

116 elif isinstance(idx, ast.Index): 

117 self.update_index(idx) 

118 elif isinstance(idx, ast.Subscript): 

119 self.update_subscript(idx) 

120 elif isinstance(idx, ast.Name): 

121 if self.is_forward_ref(idx.id): 

122 val.slice = AstStr(idx.id) 

123 elif isinstance(idx, ast.Attribute): 

124 return 

125 elif isinstance(idx, ast.Constant): 

126 return 

127 else: 

128 msg = f"Error fixing annotation of forward ref with type {type(idx)}" 

129 raise common.FixerError(msg, idx) 

130 

131 def update_index(self, idx: ast.Index) -> None: 

132 val = idx.value 

133 if is_const_node(val) or isinstance(val, ast.Attribute): 

134 return 

135 

136 if isinstance(val, ast.Name): 

137 if self.is_forward_ref(val.id): 

138 idx.value = AstStr(val.id) 

139 elif isinstance(val, ast.Subscript): 

140 self.update_subscript(val) 

141 elif isinstance(val, (ast.Tuple, ast.List)): 

142 self.update_index_elts(val.elts) 

143 else: 

144 msg = f"Error fixing index with forward ref of type {type(val)}" 

145 raise common.FixerError(msg, val) 

146 

147 def update_annotation_refs(self, node: AnnoNode, attrname: str) -> None: 

148 anno = getattr(node, attrname) 

149 if is_const_node(anno) or isinstance(anno, ast.Attribute): 

150 return 

151 

152 if isinstance(anno, ast.Name): 

153 if self.is_forward_ref(anno.id): 

154 setattr(node, attrname, AstStr(anno.id)) 

155 elif isinstance(anno, ast.Subscript): 

156 self.update_subscript(anno) 

157 else: 

158 msg = f"Error fixing annotation of forward ref with type {type(anno)}" 

159 raise common.FixerError(msg, anno) 

160 

161 def remove_forward_references(self, node: ast.AST) -> None: 

162 for sub_node in ast.iter_child_nodes(node): 

163 if isinstance(sub_node, ast.FunctionDef): 

164 self.update_annotation_refs(sub_node, 'returns') 

165 

166 for arg in sub_node.args.args: 

167 self.update_annotation_refs(arg, 'annotation') 

168 for arg in sub_node.args.kwonlyargs: 

169 self.update_annotation_refs(arg, 'annotation') 

170 

171 kwarg = sub_node.args.kwarg 

172 if kwarg: 

173 self.update_annotation_refs(kwarg, 'annotation') 

174 vararg = sub_node.args.vararg 

175 if vararg: 

176 self.update_annotation_refs(vararg, 'annotation') 

177 elif isinstance(sub_node, ast.AnnAssign): 

178 self.update_annotation_refs(sub_node, 'annotation') 

179 

180 if hasattr(sub_node, 'body'): 

181 self.remove_forward_references(sub_node) 

182 

183 if isinstance(sub_node, ast.ClassDef): 

184 self.known_classes.add(sub_node.name) 

185 

186 

187class ForwardReferenceAnnotationsFixer(fb.FixerBase): 

188 

189 version_info = common.VersionInfo(apply_since="3.0", apply_until="3.6") 

190 

191 def apply_fix(self, ctx: common.BuildContext, tree: ast.Module) -> ast.Module: 

192 local_classes: typ.Set[str] = set() 

193 for node in ast.walk(tree): 

194 if isinstance(node, ast.ClassDef): 

195 local_classes.add(node.name) 

196 

197 fraf_ctx = _FRAFContext(local_classes) 

198 fraf_ctx.remove_forward_references(tree) 

199 return tree 

200 

201 

202class RemoveFunctionDefAnnotationsFixer(fb.FixerBase): 

203 

204 version_info = common.VersionInfo(apply_since="1.0", apply_until="2.7") 

205 

206 def apply_fix(self, ctx: common.BuildContext, tree: ast.Module) -> ast.Module: 

207 for node in ast.walk(tree): 

208 if isinstance(node, ast.FunctionDef): 

209 node.returns = None 

210 for arg in node.args.args: 

211 arg.annotation = None 

212 for arg in node.args.kwonlyargs: 

213 arg.annotation = None 

214 

215 if node.args.kwarg: 

216 node.args.kwarg.annotation = None 

217 if node.args.vararg: 

218 node.args.vararg.annotation = None 

219 

220 return tree 

221 

222 

223class RemoveAnnAssignFixer(fb.TransformerFixerBase): 

224 

225 version_info = common.VersionInfo(apply_since="1.0", apply_until="3.5") 

226 

227 @staticmethod 

228 def visit_AnnAssign(node: ast.AnnAssign) -> ast.Assign: 

229 tgt_node = node.target 

230 if isinstance(tgt_node, (ast.Name, ast.Attribute)): 

231 value: ast.expr 

232 if node.value is None: 

233 value = ast.NameConstant(value=None) 

234 else: 

235 value = node.value 

236 return ast.Assign(targets=[tgt_node], value=value) 

237 else: 

238 raise common.FixerError("Unexpected Node type", tgt_node) 

239 

240 

241class ShortToLongFormSuperFixer(fb.TransformerFixerBase): 

242 

243 version_info = common.VersionInfo(apply_since="2.2", apply_until="2.7") 

244 

245 @staticmethod 

246 def visit_ClassDef(node: ast.ClassDef) -> ast.ClassDef: 

247 for maybe_method in ast.walk(node): 

248 if not isinstance(maybe_method, ast.FunctionDef): 

249 continue 

250 

251 method : ast.FunctionDef = maybe_method 

252 method_args: ast.arguments = method.args 

253 if len(method_args.args) == 0: 

254 continue 

255 

256 self_arg: ast.arg = method_args.args[0] 

257 

258 for maybe_super_call in ast.walk(method): 

259 if not isinstance(maybe_super_call, ast.Call): 

260 continue 

261 

262 func_node = maybe_super_call.func 

263 if not (isinstance(func_node, ast.Name) and func_node.id == "super"): 

264 continue 

265 

266 super_call = maybe_super_call 

267 if len(super_call.args) > 0: 

268 continue 

269 

270 super_call.args = [ 

271 ast.Name(id=node.name , ctx=ast.Load()), 

272 ast.Name(id=self_arg.arg, ctx=ast.Load()), 

273 ] 

274 return node 

275 

276 

277class InlineKWOnlyArgsFixer(fb.TransformerFixerBase): 

278 

279 version_info = common.VersionInfo(apply_since="1.0", apply_until="2.99") 

280 

281 @staticmethod 

282 def visit_FunctionDef(node: ast.FunctionDef) -> ast.FunctionDef: 

283 if not node.args.kwonlyargs: 

284 return node 

285 

286 if node.args.kwarg: 

287 kw_name = node.args.kwarg.arg 

288 else: 

289 kw_name = "kwargs" 

290 node.args.kwarg = ast.arg(arg=kw_name, annotation=None) 

291 

292 kwonlyargs = reversed(node.args.kwonlyargs) 

293 kw_defaults = reversed(node.args.kw_defaults) 

294 for arg, default in zip(kwonlyargs, kw_defaults): 

295 arg_name = arg.arg 

296 node_value: ast.expr 

297 

298 # NOTE (mb 2018-06-03): Only use defaults for kwargs 

299 # if they are literals. Everything else would 

300 # change the semantics too much and so we should 

301 # raise an error. 

302 if default is None: 

303 node_value = ast.Subscript( 

304 value=ast.Name(id=kw_name, ctx=ast.Load()), 

305 slice=ast.Index(value=AstStr(s=arg_name)), 

306 ctx=ast.Load(), 

307 ) 

308 elif not isinstance(default, common.ConstantNodeTypes): 

309 msg = f"Keyword only arguments must be immutable. Found: {default} for {arg_name}" 

310 raise common.FixerError(msg, node) 

311 else: 

312 node_value = ast.Call( 

313 func=ast.Attribute( 

314 value=ast.Name(id=kw_name, ctx=ast.Load()), attr="get", ctx=ast.Load() 

315 ), 

316 args=[AstStr(s=arg_name), default], 

317 keywords=[], 

318 ) 

319 

320 new_node = ast.Assign( 

321 targets=[ast.Name(id=arg_name, ctx=ast.Store())], value=node_value 

322 ) 

323 

324 node.body.insert(0, new_node) 

325 

326 node.args.kwonlyargs = [] 

327 

328 return node 

329 

330 

331class NewStyleClassesFixer(fb.TransformerFixerBase): 

332 

333 version_info = common.VersionInfo(apply_since="2.0", apply_until="2.7") 

334 

335 def visit_ClassDef(self, node: ast.ClassDef) -> ast.ClassDef: 

336 self.generic_visit(node) 

337 if len(node.bases) == 0: 

338 node.bases.append(ast.Name(id="object", ctx=ast.Load())) 

339 return node 

340 

341 

342class ItertoolsBuiltinsFixer(fb.TransformerFixerBase): 

343 

344 version_info = common.VersionInfo( 

345 apply_since="2.3", # introduction of the itertools module 

346 apply_until="2.7", 

347 works_until="3.99", 

348 ) 

349 

350 # WARNING (mb 2018-06-09): This fix is very broad, and should 

351 # only be used in combination with a sanity check that the 

352 # builtin names are not being overridden. 

353 

354 def apply_fix(self, ctx: common.BuildContext, tree: ast.Module) -> ast.Module: 

355 new_tree = self.visit(tree) 

356 return typ.cast(ast.Module, new_tree) 

357 

358 def visit_Name(self, node: ast.Name) -> typ.Union[ast.Name, ast.Attribute]: 

359 if isinstance(node.ctx, ast.Load) and node.id in ("map", "zip", "filter"): 

360 self.required_imports.add(common.ImportDecl("itertools", None, None)) 

361 global_decl = f"{node.id} = getattr(itertools, 'i{node.id}', {node.id})" 

362 self.module_declarations.add(global_decl) 

363 

364 return node 

365 

366 

367class NamedTupleClassToAssignFixer(fb.TransformerFixerBase): 

368 

369 version_info = common.VersionInfo(apply_since="2.6", apply_until="3.4") 

370 

371 _typing_module_name : typ.Optional[str] 

372 _namedtuple_class_name: typ.Optional[str] 

373 

374 def __init__(self) -> None: 

375 self._typing_module_name = None 

376 self._namedtuple_class_name = None 

377 super().__init__() 

378 

379 def visit_ImportFrom(self, node: ast.ImportFrom) -> ast.ImportFrom: 

380 if node.module == 'typing': 

381 for alias in node.names: 

382 if alias.name == 'NamedTuple': 

383 if alias.asname is None: 

384 self._namedtuple_class_name = alias.name 

385 else: 

386 self._namedtuple_class_name = alias.asname 

387 

388 return node 

389 

390 def visit_Import(self, node: ast.Import) -> ast.Import: 

391 for alias in node.names: 

392 if alias.name == 'typing': 

393 if alias.asname is None: 

394 self._typing_module_name = alias.name 

395 else: 

396 self._typing_module_name = alias.asname 

397 return node 

398 

399 def visit_ClassDef(self, node: ast.ClassDef) -> typ.Union[ast.ClassDef, ast.Assign]: 

400 self.generic_visit(node) 

401 if len(node.bases) == 0: 

402 return node 

403 

404 if not (self._typing_module_name or self._namedtuple_class_name): 

405 # no import of typing.NamedTuple -> class cannot have it as one its bases 

406 return node 

407 

408 has_namedtuple_base = utils.has_base_class( 

409 node, self._typing_module_name, self._namedtuple_class_name or 'NamedTuple' 

410 ) 

411 if not has_namedtuple_base: 

412 return node 

413 

414 func: typ.Union[ast.Attribute, ast.Name] 

415 

416 if self._typing_module_name: 

417 func = ast.Attribute( 

418 value=ast.Name(id=self._typing_module_name, ctx=ast.Load()), 

419 attr="NamedTuple", 

420 ctx=ast.Load(), 

421 ) 

422 elif self._namedtuple_class_name: 

423 func = ast.Name(id=self._namedtuple_class_name, ctx=ast.Load()) 

424 else: 

425 raise RuntimeError("") 

426 

427 elts: typ.List[ast.Tuple] = [] 

428 

429 for assign in node.body: 

430 if not isinstance(assign, ast.AnnAssign): 

431 continue 

432 tgt = assign.target 

433 if not isinstance(tgt, ast.Name): 

434 continue 

435 

436 elts.append(ast.Tuple(elts=[AstStr(s=tgt.id), assign.annotation], ctx=ast.Load())) 

437 

438 return ast.Assign( 

439 targets=[ast.Name(id=node.name, ctx=ast.Store())], 

440 value=ast.Call( 

441 func=func, 

442 args=[AstStr(s=node.name), ast.List(elts=elts, ctx=ast.Load())], 

443 keywords=[], 

444 ), 

445 ) 

446 

447 

448if sys.version_info >= (3, 6): 

449 from .fixers_fstring import FStringToStrFormatFixer 

450else: 

451 FStringToStrFormatFixer = None 

452 

453 

454if sys.version_info >= (3, 8): 

455 from .fixers_namedexpr import NamedExprFixer 

456else: 

457 NamedExprFixer = None 

458 

459 

460__all__ = [ 

461 "AnnotationsFutureFixer", 

462 "GeneratorStopFutureFixer", 

463 "UnicodeLiteralsFutureFixer", 

464 "RemoveUnsupportedFuturesFixer", 

465 "PrintFunctionFutureFixer", 

466 "WithStatementFutureFixer", 

467 "AbsoluteImportFutureFixer", 

468 "DivisionFutureFixer", 

469 "GeneratorsFutureFixer", 

470 "NestedScopesFutureFixer", 

471 "ConfigParserImportFallbackFixer", 

472 "SocketServerImportFallbackFixer", 

473 "BuiltinsImportFallbackFixer", 

474 "QueueImportFallbackFixer", 

475 "CopyRegImportFallbackFixer", 

476 "WinRegImportFallbackFixer", 

477 "ReprLibImportFallbackFixer", 

478 "ThreadImportFallbackFixer", 

479 "DummyThreadImportFallbackFixer", 

480 "HttpCookiejarImportFallbackFixer", 

481 "UrllibParseImportFallbackFixer", 

482 "UrllibRequestImportFallbackFixer", 

483 "UrllibErrorImportFallbackFixer", 

484 "UrllibRobotParserImportFallbackFixer", 

485 "XMLRPCClientImportFallbackFixer", 

486 "XmlrpcServerImportFallbackFixer", 

487 "HtmlParserImportFallbackFixer", 

488 "HttpClientImportFallbackFixer", 

489 "HttpCookiesImportFallbackFixer", 

490 "PickleImportFallbackFixer", 

491 "DbmGnuImportFallbackFixer", 

492 "EmailMimeBaseImportFallbackFixer", 

493 "EmailMimeImageImportFallbackFixer", 

494 "EmailMimeMultipartImportFallbackFixer", 

495 "EmailMimeNonmultipartImportFallbackFixer", 

496 "EmailMimeTextImportFallbackFixer", 

497 "TkinterImportFallbackFixer", 

498 "TkinterDialogImportFallbackFixer", 

499 "TkinterScrolledTextImportFallbackFixer", 

500 "TkinterTixImportFallbackFixer", 

501 "TkinterTtkImportFallbackFixer", 

502 "TkinterConstantsImportFallbackFixer", 

503 "TkinterDndImportFallbackFixer", 

504 "TkinterColorchooserImportFallbackFixer", 

505 "TkinterCommonDialogImportFallbackFixer", 

506 "TkinterFontImportFallbackFixer", 

507 "TkinterMessageboxImportFallbackFixer", 

508 "XrangeToRangeFixer", 

509 "UnicodeToStrFixer", 

510 "UnichrToChrFixer", 

511 "RawInputToInputFixer", 

512 "RemoveFunctionDefAnnotationsFixer", 

513 "ForwardReferenceAnnotationsFixer", 

514 "RemoveAnnAssignFixer", 

515 "ShortToLongFormSuperFixer", 

516 "InlineKWOnlyArgsFixer", 

517 "NewStyleClassesFixer", 

518 "ItertoolsBuiltinsFixer", 

519 "UnpackingGeneralizationsFixer", 

520 "NamedTupleClassToAssignFixer", 

521 "FStringToStrFormatFixer", 

522 "NamedExprFixer", 

523 "UnpackingGeneralizationsFixer", 

524] 

525 

526# class GeneratorReturnToStopIterationExceptionFixer(fb.FixerBase): 

527# 

528# version_info = common.VersionInfo( 

529# apply_since="2.0", 

530# apply_until="3.3", 

531# ) 

532# 

533# def apply_fix(self, ctx: common.BuildContext, tree: ast.Module) -> ast.Module: 

534# return tree 

535# 

536# def visit_FunctionDef(self, node: ast.FunctionDef) -> ast.FunctionDef: 

537# # NOTE (mb 2018-06-15): What about a generator nested in a function definition? 

538# is_generator = any( 

539# isinstance(sub_node, (ast.Yield, ast.YieldFrom)) 

540# for sub_node in ast.walk(node) 

541# ) 

542# if not is_generator: 

543# return node 

544# 

545# for sub_node in ast.walk(node): 

546# pass 

547 

548 

549# YIELD_FROM_EQUIVALENT = """ 

550# _i = iter(EXPR) 

551# try: 

552# _y = next(_i) 

553# except StopIteration as _e: 

554# _r = _e.value 

555# else: 

556# while 1: 

557# try: 

558# _s = yield _y 

559# except GeneratorExit as _e: 

560# try: 

561# _m = _i.close 

562# except AttributeError: 

563# pass 

564# else: 

565# _m() 

566# raise _e 

567# except BaseException as _e: 

568# _x = sys.exc_info() 

569# try: 

570# _m = _i.throw 

571# except AttributeError: 

572# raise _e 

573# else: 

574# try: 

575# _y = _m(*_x) 

576# except StopIteration as _e: 

577# _r = _e.value 

578# break 

579# else: 

580# try: 

581# if _s is None: 

582# _y = next(_i) 

583# else: 

584# _y = _i.send(_s) 

585# except StopIteration as _e: 

586# _r = _e.value 

587# break 

588# RESULT = _r 

589# """in_len_body 

590 

591 

592# class YieldFromFixer(fb.FixerBase): 

593# # see https://www.python.org/dev/peps/pep-0380/ 

594# NOTE (mb 2018-06-14): We should definetly do the most simple case 

595# but maybe we can also detect the more complex cases involving 

596# send and return values and at least throw an error 

597 

598# class MetaclassFixer(fb.TransformerFixerBase): 

599# 

600# version_info = common.VersionInfo( 

601# apply_since="2.0", 

602# apply_until="2.7", 

603# ) 

604# 

605# def visit_ClassDef(self, node: ast.ClassDef) -> ast.ClassDef: 

606# # class Foo(metaclass=X): => class Foo(object):\n __metaclass__ = X 

607 

608 

609# class MatMulFixer(fb.TransformerFixerBase): 

610# 

611# version_info = common.VersionInfo( 

612# apply_since="2.0", 

613# apply_until="3.5", 

614# ) 

615# 

616# def visit_Binop(self, node: ast.BinOp) -> ast.Call: 

617# # replace a @ b with a.__matmul__(b) 

618 

619 

620# NOTE (mb 2018-06-24): I'm not gonna do it, but feel free to 

621# implement it if you feel like it. 

622# 

623# class DecoratorFixer(fb.FixerBase): 

624# """Replaces use of @decorators with function calls 

625# 

626# > @mydec1() 

627# > @mydec2 

628# > def myfn(): 

629# > pass 

630# < def myfn(): 

631# < pass 

632# < myfn = mydec2(myfn) 

633# < myfn = mydec1()(myfn) 

634# """ 

635# 

636# version_info = common.VersionInfo( 

637# apply_since="2.0", 

638# apply_until="2.4", 

639# ) 

640# 

641 

642# NOTE (mb 2018-06-24): I'm not gonna do it, but feel free to 

643# implement it if you feel like it. 

644# 

645# class WithStatementToTryExceptFixer(fb.FixerBase): 

646# """ 

647# > with expression as name: 

648# > name 

649# 

650# < import sys 

651# < __had_exception = False 

652# < __manager = expression 

653# < try: 

654# < name = manager.__enter__() 

655# < except: 

656# < __had_exception = True 

657# < ex_type, ex_value, traceback = sys.exc_info() 

658# < __manager.__exit__(ex_type, ex_value, traceback) 

659# < finally: 

660# < if not __had_exception: 

661# < __manager.__exit__(None, None, None) 

662# """ 

663# 

664# version_info = common.VersionInfo( 

665# apply_since="2.0", 

666# apply_until="2.4", 

667# ) 

668# 

669 

670# NOTE (mb 2018-06-25): I'm not gonna do it, but feel free to 

671# implement it if you feel like it. 

672# 

673# class ImplicitFormatIndexesFixer(fb.FixerBase): 

674# """Replaces use of @decorators with function calls 

675# 

676# > "first: {} second: {:>9}".format(0, 1) 

677# < "first: {0} second: {1:>9}".format(0, 1) 

678# """ 

679# 

680# version_info = common.VersionInfo( 

681# apply_since="2.6", 

682# apply_until="2.6", 

683# ) 

684#