Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/astroid/nodes/as_string.py: 70%

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

379 statements  

1# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html 

2# For details: https://github.com/pylint-dev/astroid/blob/main/LICENSE 

3# Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt 

4 

5"""This module renders Astroid nodes as string""" 

6 

7from __future__ import annotations 

8 

9import warnings 

10from collections.abc import Iterator 

11from typing import TYPE_CHECKING 

12 

13from astroid import nodes 

14 

15if TYPE_CHECKING: 

16 from astroid import objects 

17 from astroid.nodes import Const 

18 from astroid.nodes.node_classes import ( 

19 Match, 

20 MatchAs, 

21 MatchCase, 

22 MatchClass, 

23 MatchMapping, 

24 MatchOr, 

25 MatchSequence, 

26 MatchSingleton, 

27 MatchStar, 

28 MatchValue, 

29 Unknown, 

30 ) 

31 

32# pylint: disable=unused-argument 

33 

34DOC_NEWLINE = "\0" 

35 

36 

37# Visitor pattern require argument all the time and is not better with staticmethod 

38# noinspection PyUnusedLocal,PyMethodMayBeStatic 

39class AsStringVisitor: 

40 """Visitor to render an Astroid node as a valid python code string""" 

41 

42 def __init__(self, indent: str = " "): 

43 self.indent: str = indent 

44 

45 def __call__(self, node) -> str: 

46 """Makes this visitor behave as a simple function""" 

47 return node.accept(self).replace(DOC_NEWLINE, "\n") 

48 

49 def _docs_dedent(self, doc_node: Const | None) -> str: 

50 """Stop newlines in docs being indented by self._stmt_list""" 

51 if not doc_node: 

52 return "" 

53 

54 return '\n{}"""{}"""'.format( 

55 self.indent, doc_node.value.replace("\n", DOC_NEWLINE) 

56 ) 

57 

58 def _stmt_list(self, stmts: list, indent: bool = True) -> str: 

59 """return a list of nodes to string""" 

60 stmts_str: str = "\n".join( 

61 nstr for nstr in [n.accept(self) for n in stmts] if nstr 

62 ) 

63 if not indent: 

64 return stmts_str 

65 

66 return self.indent + stmts_str.replace("\n", "\n" + self.indent) 

67 

68 def _precedence_parens(self, node, child, is_left: bool = True) -> str: 

69 """Wrap child in parens only if required to keep same semantics""" 

70 if self._should_wrap(node, child, is_left): 

71 return f"({child.accept(self)})" 

72 

73 return child.accept(self) 

74 

75 def _should_wrap(self, node, child, is_left: bool) -> bool: 

76 """Wrap child if: 

77 - it has lower precedence 

78 - same precedence with position opposite to associativity direction 

79 """ 

80 node_precedence = node.op_precedence() 

81 child_precedence = child.op_precedence() 

82 

83 if node_precedence > child_precedence: 

84 # 3 * (4 + 5) 

85 return True 

86 

87 if ( 

88 node_precedence == child_precedence 

89 and is_left != node.op_left_associative() 

90 ): 

91 # 3 - (4 - 5) 

92 # (2**3)**4 

93 return True 

94 

95 return False 

96 

97 # visit_<node> methods ########################################### 

98 

99 def visit_await(self, node) -> str: 

100 return f"await {node.value.accept(self)}" 

101 

102 def visit_asyncwith(self, node) -> str: 

103 return f"async {self.visit_with(node)}" 

104 

105 def visit_asyncfor(self, node) -> str: 

106 return f"async {self.visit_for(node)}" 

107 

108 def visit_arguments(self, node) -> str: 

109 """return an astroid.Function node as string""" 

110 return node.format_args() 

111 

112 def visit_assignattr(self, node) -> str: 

113 """return an astroid.AssAttr node as string""" 

114 return self.visit_attribute(node) 

115 

116 def visit_assert(self, node) -> str: 

117 """return an astroid.Assert node as string""" 

118 if node.fail: 

119 return f"assert {node.test.accept(self)}, {node.fail.accept(self)}" 

120 return f"assert {node.test.accept(self)}" 

121 

122 def visit_assignname(self, node) -> str: 

123 """return an astroid.AssName node as string""" 

124 return node.name 

125 

126 def visit_assign(self, node) -> str: 

127 """return an astroid.Assign node as string""" 

128 lhs = " = ".join(n.accept(self) for n in node.targets) 

129 return f"{lhs} = {node.value.accept(self)}" 

130 

131 def visit_augassign(self, node) -> str: 

132 """return an astroid.AugAssign node as string""" 

133 return f"{node.target.accept(self)} {node.op} {node.value.accept(self)}" 

134 

135 def visit_annassign(self, node) -> str: 

136 """Return an astroid.AugAssign node as string""" 

137 

138 target = node.target.accept(self) 

139 annotation = node.annotation.accept(self) 

140 if node.value is None: 

141 return f"{target}: {annotation}" 

142 return f"{target}: {annotation} = {node.value.accept(self)}" 

143 

144 def visit_binop(self, node) -> str: 

145 """return an astroid.BinOp node as string""" 

146 left = self._precedence_parens(node, node.left) 

147 right = self._precedence_parens(node, node.right, is_left=False) 

148 if node.op == "**": 

149 return f"{left}{node.op}{right}" 

150 

151 return f"{left} {node.op} {right}" 

152 

153 def visit_boolop(self, node) -> str: 

154 """return an astroid.BoolOp node as string""" 

155 values = [f"{self._precedence_parens(node, n)}" for n in node.values] 

156 return (f" {node.op} ").join(values) 

157 

158 def visit_break(self, node) -> str: 

159 """return an astroid.Break node as string""" 

160 return "break" 

161 

162 def visit_call(self, node) -> str: 

163 """return an astroid.Call node as string""" 

164 expr_str = self._precedence_parens(node, node.func) 

165 args = [arg.accept(self) for arg in node.args] 

166 if node.keywords: 

167 keywords = [kwarg.accept(self) for kwarg in node.keywords] 

168 else: 

169 keywords = [] 

170 

171 args.extend(keywords) 

172 return f"{expr_str}({', '.join(args)})" 

173 

174 def visit_classdef(self, node) -> str: 

175 """return an astroid.ClassDef node as string""" 

176 decorate = node.decorators.accept(self) if node.decorators else "" 

177 args = [n.accept(self) for n in node.bases] 

178 if node._metaclass and not node.has_metaclass_hack(): 

179 args.append("metaclass=" + node._metaclass.accept(self)) 

180 args += [n.accept(self) for n in node.keywords] 

181 args_str = f"({', '.join(args)})" if args else "" 

182 docs = self._docs_dedent(node.doc_node) 

183 # TODO: handle type_params 

184 return "\n\n{}class {}{}:{}\n{}\n".format( 

185 decorate, node.name, args_str, docs, self._stmt_list(node.body) 

186 ) 

187 

188 def visit_compare(self, node) -> str: 

189 """return an astroid.Compare node as string""" 

190 rhs_str = " ".join( 

191 f"{op} {self._precedence_parens(node, expr, is_left=False)}" 

192 for op, expr in node.ops 

193 ) 

194 return f"{self._precedence_parens(node, node.left)} {rhs_str}" 

195 

196 def visit_comprehension(self, node) -> str: 

197 """return an astroid.Comprehension node as string""" 

198 ifs = "".join(f" if {n.accept(self)}" for n in node.ifs) 

199 generated = f"for {node.target.accept(self)} in {node.iter.accept(self)}{ifs}" 

200 return f"{'async ' if node.is_async else ''}{generated}" 

201 

202 def visit_const(self, node) -> str: 

203 """return an astroid.Const node as string""" 

204 if node.value is Ellipsis: 

205 return "..." 

206 return repr(node.value) 

207 

208 def visit_continue(self, node) -> str: 

209 """return an astroid.Continue node as string""" 

210 return "continue" 

211 

212 def visit_delete(self, node) -> str: # XXX check if correct 

213 """return an astroid.Delete node as string""" 

214 return f"del {', '.join(child.accept(self) for child in node.targets)}" 

215 

216 def visit_delattr(self, node) -> str: 

217 """return an astroid.DelAttr node as string""" 

218 return self.visit_attribute(node) 

219 

220 def visit_delname(self, node) -> str: 

221 """return an astroid.DelName node as string""" 

222 return node.name 

223 

224 def visit_decorators(self, node) -> str: 

225 """return an astroid.Decorators node as string""" 

226 return "@%s\n" % "\n@".join(item.accept(self) for item in node.nodes) 

227 

228 def visit_dict(self, node) -> str: 

229 """return an astroid.Dict node as string""" 

230 return "{%s}" % ", ".join(self._visit_dict(node)) 

231 

232 def _visit_dict(self, node) -> Iterator[str]: 

233 for key, value in node.items: 

234 key = key.accept(self) 

235 value = value.accept(self) 

236 if key == "**": 

237 # It can only be a DictUnpack node. 

238 yield key + value 

239 else: 

240 yield f"{key}: {value}" 

241 

242 def visit_dictunpack(self, node) -> str: 

243 return "**" 

244 

245 def visit_dictcomp(self, node) -> str: 

246 """return an astroid.DictComp node as string""" 

247 return "{{{}: {} {}}}".format( 

248 node.key.accept(self), 

249 node.value.accept(self), 

250 " ".join(n.accept(self) for n in node.generators), 

251 ) 

252 

253 def visit_expr(self, node) -> str: 

254 """return an astroid.Discard node as string""" 

255 return node.value.accept(self) 

256 

257 def visit_emptynode(self, node) -> str: 

258 """dummy method for visiting an Empty node""" 

259 return "" 

260 

261 def visit_excepthandler(self, node) -> str: 

262 n = "except" 

263 if isinstance(getattr(node, "parent", None), nodes.TryStar): 

264 n = "except*" 

265 if node.type: 

266 if node.name: 

267 excs = f"{n} {node.type.accept(self)} as {node.name.accept(self)}" 

268 else: 

269 excs = f"{n} {node.type.accept(self)}" 

270 else: 

271 excs = f"{n}" 

272 return f"{excs}:\n{self._stmt_list(node.body)}" 

273 

274 def visit_empty(self, node) -> str: 

275 """return an Empty node as string""" 

276 return "" 

277 

278 def visit_for(self, node) -> str: 

279 """return an astroid.For node as string""" 

280 fors = "for {} in {}:\n{}".format( 

281 node.target.accept(self), node.iter.accept(self), self._stmt_list(node.body) 

282 ) 

283 if node.orelse: 

284 fors = f"{fors}\nelse:\n{self._stmt_list(node.orelse)}" 

285 return fors 

286 

287 def visit_importfrom(self, node) -> str: 

288 """return an astroid.ImportFrom node as string""" 

289 return "from {} import {}".format( 

290 "." * (node.level or 0) + node.modname, _import_string(node.names) 

291 ) 

292 

293 def visit_joinedstr(self, node) -> str: 

294 string = "".join( 

295 # Use repr on the string literal parts 

296 # to get proper escapes, e.g. \n, \\, \" 

297 # But strip the quotes off the ends 

298 # (they will always be one character: ' or ") 

299 ( 

300 repr(value.value)[1:-1] 

301 # Literal braces must be doubled to escape them 

302 .replace("{", "{{").replace("}", "}}") 

303 # Each value in values is either a string literal (Const) 

304 # or a FormattedValue 

305 if type(value).__name__ == "Const" 

306 else value.accept(self) 

307 ) 

308 for value in node.values 

309 ) 

310 

311 # Try to find surrounding quotes that don't appear at all in the string. 

312 # Because the formatted values inside {} can't contain backslash (\) 

313 # using a triple quote is sometimes necessary 

314 for quote in ("'", '"', '"""', "'''"): 

315 if quote not in string: 

316 break 

317 

318 return "f" + quote + string + quote 

319 

320 def visit_formattedvalue(self, node) -> str: 

321 result = node.value.accept(self) 

322 if node.conversion and node.conversion >= 0: 

323 # e.g. if node.conversion == 114: result += "!r" 

324 result += "!" + chr(node.conversion) 

325 if node.format_spec: 

326 # The format spec is itself a JoinedString, i.e. an f-string 

327 # We strip the f and quotes of the ends 

328 result += ":" + node.format_spec.accept(self)[2:-1] 

329 return "{%s}" % result 

330 

331 def handle_functiondef(self, node: nodes.FunctionDef, keyword: str) -> str: 

332 """return a (possibly async) function definition node as string""" 

333 decorate = node.decorators.accept(self) if node.decorators else "" 

334 docs = self._docs_dedent(node.doc_node) 

335 trailer = ":" 

336 if node.returns: 

337 return_annotation = " -> " + node.returns.as_string() 

338 trailer = return_annotation + ":" 

339 # TODO: handle type_params 

340 def_format = "\n%s%s %s(%s)%s%s\n%s" 

341 return def_format % ( 

342 decorate, 

343 keyword, 

344 node.name, 

345 node.args.accept(self), 

346 trailer, 

347 docs, 

348 self._stmt_list(node.body), 

349 ) 

350 

351 def visit_functiondef(self, node: nodes.FunctionDef) -> str: 

352 """return an astroid.FunctionDef node as string""" 

353 return self.handle_functiondef(node, "def") 

354 

355 def visit_asyncfunctiondef(self, node: nodes.AsyncFunctionDef) -> str: 

356 """return an astroid.AsyncFunction node as string""" 

357 return self.handle_functiondef(node, "async def") 

358 

359 def visit_generatorexp(self, node) -> str: 

360 """return an astroid.GeneratorExp node as string""" 

361 return "({} {})".format( 

362 node.elt.accept(self), " ".join(n.accept(self) for n in node.generators) 

363 ) 

364 

365 def visit_attribute(self, node) -> str: 

366 """return an astroid.Getattr node as string""" 

367 try: 

368 left = self._precedence_parens(node, node.expr) 

369 except RecursionError: 

370 warnings.warn( 

371 "Recursion limit exhausted; defaulting to adding parentheses.", 

372 UserWarning, 

373 stacklevel=2, 

374 ) 

375 left = f"({node.expr.accept(self)})" 

376 if left.isdigit(): 

377 left = f"({left})" 

378 return f"{left}.{node.attrname}" 

379 

380 def visit_global(self, node) -> str: 

381 """return an astroid.Global node as string""" 

382 return f"global {', '.join(node.names)}" 

383 

384 def visit_if(self, node) -> str: 

385 """return an astroid.If node as string""" 

386 ifs = [f"if {node.test.accept(self)}:\n{self._stmt_list(node.body)}"] 

387 if node.has_elif_block(): 

388 ifs.append(f"el{self._stmt_list(node.orelse, indent=False)}") 

389 elif node.orelse: 

390 ifs.append(f"else:\n{self._stmt_list(node.orelse)}") 

391 return "\n".join(ifs) 

392 

393 def visit_ifexp(self, node) -> str: 

394 """return an astroid.IfExp node as string""" 

395 return "{} if {} else {}".format( 

396 self._precedence_parens(node, node.body, is_left=True), 

397 self._precedence_parens(node, node.test, is_left=True), 

398 self._precedence_parens(node, node.orelse, is_left=False), 

399 ) 

400 

401 def visit_import(self, node) -> str: 

402 """return an astroid.Import node as string""" 

403 return f"import {_import_string(node.names)}" 

404 

405 def visit_keyword(self, node) -> str: 

406 """return an astroid.Keyword node as string""" 

407 if node.arg is None: 

408 return f"**{node.value.accept(self)}" 

409 return f"{node.arg}={node.value.accept(self)}" 

410 

411 def visit_lambda(self, node) -> str: 

412 """return an astroid.Lambda node as string""" 

413 args = node.args.accept(self) 

414 body = node.body.accept(self) 

415 if args: 

416 return f"lambda {args}: {body}" 

417 

418 return f"lambda: {body}" 

419 

420 def visit_list(self, node) -> str: 

421 """return an astroid.List node as string""" 

422 return f"[{', '.join(child.accept(self) for child in node.elts)}]" 

423 

424 def visit_listcomp(self, node) -> str: 

425 """return an astroid.ListComp node as string""" 

426 return "[{} {}]".format( 

427 node.elt.accept(self), " ".join(n.accept(self) for n in node.generators) 

428 ) 

429 

430 def visit_module(self, node) -> str: 

431 """return an astroid.Module node as string""" 

432 docs = f'"""{node.doc_node.value}"""\n\n' if node.doc_node else "" 

433 return docs + "\n".join(n.accept(self) for n in node.body) + "\n\n" 

434 

435 def visit_name(self, node) -> str: 

436 """return an astroid.Name node as string""" 

437 return node.name 

438 

439 def visit_namedexpr(self, node) -> str: 

440 """Return an assignment expression node as string""" 

441 target = node.target.accept(self) 

442 value = node.value.accept(self) 

443 return f"{target} := {value}" 

444 

445 def visit_nonlocal(self, node) -> str: 

446 """return an astroid.Nonlocal node as string""" 

447 return f"nonlocal {', '.join(node.names)}" 

448 

449 def visit_paramspec(self, node: nodes.ParamSpec) -> str: 

450 """return an astroid.ParamSpec node as string""" 

451 return node.name.accept(self) 

452 

453 def visit_pass(self, node) -> str: 

454 """return an astroid.Pass node as string""" 

455 return "pass" 

456 

457 def visit_partialfunction(self, node: objects.PartialFunction) -> str: 

458 """Return an objects.PartialFunction as string.""" 

459 return self.visit_functiondef(node) 

460 

461 def visit_raise(self, node) -> str: 

462 """return an astroid.Raise node as string""" 

463 if node.exc: 

464 if node.cause: 

465 return f"raise {node.exc.accept(self)} from {node.cause.accept(self)}" 

466 return f"raise {node.exc.accept(self)}" 

467 return "raise" 

468 

469 def visit_return(self, node) -> str: 

470 """return an astroid.Return node as string""" 

471 if node.is_tuple_return() and len(node.value.elts) > 1: 

472 elts = [child.accept(self) for child in node.value.elts] 

473 return f"return {', '.join(elts)}" 

474 

475 if node.value: 

476 return f"return {node.value.accept(self)}" 

477 

478 return "return" 

479 

480 def visit_set(self, node) -> str: 

481 """return an astroid.Set node as string""" 

482 return "{%s}" % ", ".join(child.accept(self) for child in node.elts) 

483 

484 def visit_setcomp(self, node) -> str: 

485 """return an astroid.SetComp node as string""" 

486 return "{{{} {}}}".format( 

487 node.elt.accept(self), " ".join(n.accept(self) for n in node.generators) 

488 ) 

489 

490 def visit_slice(self, node) -> str: 

491 """return an astroid.Slice node as string""" 

492 lower = node.lower.accept(self) if node.lower else "" 

493 upper = node.upper.accept(self) if node.upper else "" 

494 step = node.step.accept(self) if node.step else "" 

495 if step: 

496 return f"{lower}:{upper}:{step}" 

497 return f"{lower}:{upper}" 

498 

499 def visit_subscript(self, node) -> str: 

500 """return an astroid.Subscript node as string""" 

501 idx = node.slice 

502 if idx.__class__.__name__.lower() == "index": 

503 idx = idx.value 

504 idxstr = idx.accept(self) 

505 if idx.__class__.__name__.lower() == "tuple" and idx.elts: 

506 # Remove parenthesis in tuple and extended slice. 

507 # a[(::1, 1:)] is not valid syntax. 

508 idxstr = idxstr[1:-1] 

509 return f"{self._precedence_parens(node, node.value)}[{idxstr}]" 

510 

511 def visit_try(self, node) -> str: 

512 """return an astroid.Try node as string""" 

513 trys = [f"try:\n{self._stmt_list(node.body)}"] 

514 for handler in node.handlers: 

515 trys.append(handler.accept(self)) 

516 if node.orelse: 

517 trys.append(f"else:\n{self._stmt_list(node.orelse)}") 

518 if node.finalbody: 

519 trys.append(f"finally:\n{self._stmt_list(node.finalbody)}") 

520 return "\n".join(trys) 

521 

522 def visit_trystar(self, node) -> str: 

523 """return an astroid.TryStar node as string""" 

524 trys = [f"try:\n{self._stmt_list(node.body)}"] 

525 for handler in node.handlers: 

526 trys.append(handler.accept(self)) 

527 if node.orelse: 

528 trys.append(f"else:\n{self._stmt_list(node.orelse)}") 

529 if node.finalbody: 

530 trys.append(f"finally:\n{self._stmt_list(node.finalbody)}") 

531 return "\n".join(trys) 

532 

533 def visit_tuple(self, node) -> str: 

534 """return an astroid.Tuple node as string""" 

535 if len(node.elts) == 1: 

536 return f"({node.elts[0].accept(self)}, )" 

537 return f"({', '.join(child.accept(self) for child in node.elts)})" 

538 

539 def visit_typealias(self, node: nodes.TypeAlias) -> str: 

540 """return an astroid.TypeAlias node as string""" 

541 return node.name.accept(self) if node.name else "_" 

542 

543 def visit_typevar(self, node: nodes.TypeVar) -> str: 

544 """return an astroid.TypeVar node as string""" 

545 return node.name.accept(self) if node.name else "_" 

546 

547 def visit_typevartuple(self, node: nodes.TypeVarTuple) -> str: 

548 """return an astroid.TypeVarTuple node as string""" 

549 return "*" + node.name.accept(self) if node.name else "" 

550 

551 def visit_unaryop(self, node) -> str: 

552 """return an astroid.UnaryOp node as string""" 

553 if node.op == "not": 

554 operator = "not " 

555 else: 

556 operator = node.op 

557 return f"{operator}{self._precedence_parens(node, node.operand)}" 

558 

559 def visit_while(self, node) -> str: 

560 """return an astroid.While node as string""" 

561 whiles = f"while {node.test.accept(self)}:\n{self._stmt_list(node.body)}" 

562 if node.orelse: 

563 whiles = f"{whiles}\nelse:\n{self._stmt_list(node.orelse)}" 

564 return whiles 

565 

566 def visit_with(self, node) -> str: # 'with' without 'as' is possible 

567 """return an astroid.With node as string""" 

568 items = ", ".join( 

569 f"{expr.accept(self)}" + (v and f" as {v.accept(self)}" or "") 

570 for expr, v in node.items 

571 ) 

572 return f"with {items}:\n{self._stmt_list(node.body)}" 

573 

574 def visit_yield(self, node) -> str: 

575 """yield an ast.Yield node as string""" 

576 yi_val = (" " + node.value.accept(self)) if node.value else "" 

577 expr = "yield" + yi_val 

578 if node.parent.is_statement: 

579 return expr 

580 

581 return f"({expr})" 

582 

583 def visit_yieldfrom(self, node) -> str: 

584 """Return an astroid.YieldFrom node as string.""" 

585 yi_val = (" " + node.value.accept(self)) if node.value else "" 

586 expr = "yield from" + yi_val 

587 if node.parent.is_statement: 

588 return expr 

589 

590 return f"({expr})" 

591 

592 def visit_starred(self, node) -> str: 

593 """return Starred node as string""" 

594 return "*" + node.value.accept(self) 

595 

596 def visit_match(self, node: Match) -> str: 

597 """Return an astroid.Match node as string.""" 

598 return f"match {node.subject.accept(self)}:\n{self._stmt_list(node.cases)}" 

599 

600 def visit_matchcase(self, node: MatchCase) -> str: 

601 """Return an astroid.MatchCase node as string.""" 

602 guard_str = f" if {node.guard.accept(self)}" if node.guard else "" 

603 return ( 

604 f"case {node.pattern.accept(self)}{guard_str}:\n" 

605 f"{self._stmt_list(node.body)}" 

606 ) 

607 

608 def visit_matchvalue(self, node: MatchValue) -> str: 

609 """Return an astroid.MatchValue node as string.""" 

610 return node.value.accept(self) 

611 

612 @staticmethod 

613 def visit_matchsingleton(node: MatchSingleton) -> str: 

614 """Return an astroid.MatchSingleton node as string.""" 

615 return str(node.value) 

616 

617 def visit_matchsequence(self, node: MatchSequence) -> str: 

618 """Return an astroid.MatchSequence node as string.""" 

619 if node.patterns is None: 

620 return "[]" 

621 return f"[{', '.join(p.accept(self) for p in node.patterns)}]" 

622 

623 def visit_matchmapping(self, node: MatchMapping) -> str: 

624 """Return an astroid.MatchMapping node as string.""" 

625 mapping_strings: list[str] = [] 

626 if node.keys and node.patterns: 

627 mapping_strings.extend( 

628 f"{key.accept(self)}: {p.accept(self)}" 

629 for key, p in zip(node.keys, node.patterns) 

630 ) 

631 if node.rest: 

632 mapping_strings.append(f"**{node.rest.accept(self)}") 

633 return f"{'{'}{', '.join(mapping_strings)}{'}'}" 

634 

635 def visit_matchclass(self, node: MatchClass) -> str: 

636 """Return an astroid.MatchClass node as string.""" 

637 if node.cls is None: 

638 raise AssertionError(f"{node} does not have a 'cls' node") 

639 class_strings: list[str] = [] 

640 if node.patterns: 

641 class_strings.extend(p.accept(self) for p in node.patterns) 

642 if node.kwd_attrs and node.kwd_patterns: 

643 for attr, pattern in zip(node.kwd_attrs, node.kwd_patterns): 

644 class_strings.append(f"{attr}={pattern.accept(self)}") 

645 return f"{node.cls.accept(self)}({', '.join(class_strings)})" 

646 

647 def visit_matchstar(self, node: MatchStar) -> str: 

648 """Return an astroid.MatchStar node as string.""" 

649 return f"*{node.name.accept(self) if node.name else '_'}" 

650 

651 def visit_matchas(self, node: MatchAs) -> str: 

652 """Return an astroid.MatchAs node as string.""" 

653 # pylint: disable=import-outside-toplevel 

654 # Prevent circular dependency 

655 from astroid.nodes.node_classes import MatchClass, MatchMapping, MatchSequence 

656 

657 if isinstance(node.parent, (MatchSequence, MatchMapping, MatchClass)): 

658 return node.name.accept(self) if node.name else "_" 

659 return ( 

660 f"{node.pattern.accept(self) if node.pattern else '_'}" 

661 f"{f' as {node.name.accept(self)}' if node.name else ''}" 

662 ) 

663 

664 def visit_matchor(self, node: MatchOr) -> str: 

665 """Return an astroid.MatchOr node as string.""" 

666 if node.patterns is None: 

667 raise AssertionError(f"{node} does not have pattern nodes") 

668 return " | ".join(p.accept(self) for p in node.patterns) 

669 

670 # These aren't for real AST nodes, but for inference objects. 

671 

672 def visit_frozenset(self, node): 

673 return node.parent.accept(self) 

674 

675 def visit_super(self, node): 

676 return node.parent.accept(self) 

677 

678 def visit_uninferable(self, node): 

679 return str(node) 

680 

681 def visit_property(self, node): 

682 return node.function.accept(self) 

683 

684 def visit_evaluatedobject(self, node): 

685 return node.original.accept(self) 

686 

687 def visit_unknown(self, node: Unknown) -> str: 

688 return str(node) 

689 

690 

691def _import_string(names) -> str: 

692 """return a list of (name, asname) formatted as a string""" 

693 _names = [] 

694 for name, asname in names: 

695 if asname is not None: 

696 _names.append(f"{name} as {asname}") 

697 else: 

698 _names.append(name) 

699 return ", ".join(_names) 

700 

701 

702# This sets the default indent to 4 spaces. 

703to_code = AsStringVisitor(" ")