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

363 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-07 06:53 +0000

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 

9from collections.abc import Iterator 

10from typing import TYPE_CHECKING 

11 

12from astroid import nodes 

13 

14if TYPE_CHECKING: 

15 from astroid.nodes import Const 

16 from astroid.nodes.node_classes import ( 

17 Match, 

18 MatchAs, 

19 MatchCase, 

20 MatchClass, 

21 MatchMapping, 

22 MatchOr, 

23 MatchSequence, 

24 MatchSingleton, 

25 MatchStar, 

26 MatchValue, 

27 Unknown, 

28 ) 

29 

30# pylint: disable=unused-argument 

31 

32DOC_NEWLINE = "\0" 

33 

34 

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

36# noinspection PyUnusedLocal,PyMethodMayBeStatic 

37class AsStringVisitor: 

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

39 

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

41 self.indent: str = indent 

42 

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

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

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

46 

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

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

49 if not doc_node: 

50 return "" 

51 

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

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

54 ) 

55 

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

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

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

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

60 ) 

61 if not indent: 

62 return stmts_str 

63 

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

65 

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

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

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

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

70 

71 return child.accept(self) 

72 

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

74 """Wrap child if: 

75 - it has lower precedence 

76 - same precedence with position opposite to associativity direction 

77 """ 

78 node_precedence = node.op_precedence() 

79 child_precedence = child.op_precedence() 

80 

81 if node_precedence > child_precedence: 

82 # 3 * (4 + 5) 

83 return True 

84 

85 if ( 

86 node_precedence == child_precedence 

87 and is_left != node.op_left_associative() 

88 ): 

89 # 3 - (4 - 5) 

90 # (2**3)**4 

91 return True 

92 

93 return False 

94 

95 # visit_<node> methods ########################################### 

96 

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

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

99 

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

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

102 

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

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

105 

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

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

108 return node.format_args() 

109 

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

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

112 return self.visit_attribute(node) 

113 

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

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

116 if node.fail: 

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

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

119 

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

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

122 return node.name 

123 

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

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

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

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

128 

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

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

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

132 

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

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

135 

136 target = node.target.accept(self) 

137 annotation = node.annotation.accept(self) 

138 if node.value is None: 

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

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

141 

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

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

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

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

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

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

148 

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

150 

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

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

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

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

155 

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

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

158 return "break" 

159 

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

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

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

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

164 if node.keywords: 

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

166 else: 

167 keywords = [] 

168 

169 args.extend(keywords) 

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

171 

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

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

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

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

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

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

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

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

180 docs = self._docs_dedent(node.doc_node) 

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

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

183 ) 

184 

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

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

187 rhs_str = " ".join( 

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

189 for op, expr in node.ops 

190 ) 

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

192 

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

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

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

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

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

198 

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

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

201 if node.value is Ellipsis: 

202 return "..." 

203 return repr(node.value) 

204 

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

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

207 return "continue" 

208 

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

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

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

212 

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

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

215 return self.visit_attribute(node) 

216 

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

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

219 return node.name 

220 

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

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

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

224 

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

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

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

228 

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

230 for key, value in node.items: 

231 key = key.accept(self) 

232 value = value.accept(self) 

233 if key == "**": 

234 # It can only be a DictUnpack node. 

235 yield key + value 

236 else: 

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

238 

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

240 return "**" 

241 

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

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

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

245 node.key.accept(self), 

246 node.value.accept(self), 

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

248 ) 

249 

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

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

252 return node.value.accept(self) 

253 

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

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

256 return "" 

257 

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

259 n = "except" 

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

261 n = "except*" 

262 if node.type: 

263 if node.name: 

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

265 else: 

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

267 else: 

268 excs = f"{n}" 

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

270 

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

272 """return an Empty node as string""" 

273 return "" 

274 

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

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

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

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

279 ) 

280 if node.orelse: 

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

282 return fors 

283 

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

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

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

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

288 ) 

289 

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

291 string = "".join( 

292 # Use repr on the string literal parts 

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

294 # But strip the quotes off the ends 

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

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

297 # Literal braces must be doubled to escape them 

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

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

300 # or a FormattedValue 

301 if type(value).__name__ == "Const" else value.accept(self) 

302 for value in node.values 

303 ) 

304 

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

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

307 # using a triple quote is sometimes necessary 

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

309 if quote not in string: 

310 break 

311 

312 return "f" + quote + string + quote 

313 

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

315 result = node.value.accept(self) 

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

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

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

319 if node.format_spec: 

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

321 # We strip the f and quotes of the ends 

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

323 return "{%s}" % result 

324 

325 def handle_functiondef(self, node, keyword) -> str: 

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

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

328 docs = self._docs_dedent(node.doc_node) 

329 trailer = ":" 

330 if node.returns: 

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

332 trailer = return_annotation + ":" 

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

334 return def_format % ( 

335 decorate, 

336 keyword, 

337 node.name, 

338 node.args.accept(self), 

339 trailer, 

340 docs, 

341 self._stmt_list(node.body), 

342 ) 

343 

344 def visit_functiondef(self, node) -> str: 

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

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

347 

348 def visit_asyncfunctiondef(self, node) -> str: 

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

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

351 

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

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

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

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

356 ) 

357 

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

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

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

361 if left.isdigit(): 

362 left = f"({left})" 

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

364 

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

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

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

368 

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

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

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

372 if node.has_elif_block(): 

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

374 elif node.orelse: 

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

376 return "\n".join(ifs) 

377 

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

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

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

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

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

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

384 ) 

385 

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

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

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

389 

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

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

392 if node.arg is None: 

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

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

395 

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

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

398 args = node.args.accept(self) 

399 body = node.body.accept(self) 

400 if args: 

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

402 

403 return f"lambda: {body}" 

404 

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

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

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

408 

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

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

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

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

413 ) 

414 

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

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

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

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

419 

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

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

422 return node.name 

423 

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

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

426 target = node.target.accept(self) 

427 value = node.value.accept(self) 

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

429 

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

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

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

433 

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

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

436 return "pass" 

437 

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

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

440 if node.exc: 

441 if node.cause: 

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

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

444 return "raise" 

445 

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

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

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

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

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

451 

452 if node.value: 

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

454 

455 return "return" 

456 

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

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

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

460 

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

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

463 return "{{{} {}}}".format( 

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

465 ) 

466 

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

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

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

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

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

472 if step: 

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

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

475 

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

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

478 idx = node.slice 

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

480 idx = idx.value 

481 idxstr = idx.accept(self) 

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

483 # Remove parenthesis in tuple and extended slice. 

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

485 idxstr = idxstr[1:-1] 

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

487 

488 def visit_tryexcept(self, node) -> str: 

489 """return an astroid.TryExcept node as string""" 

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

491 for handler in node.handlers: 

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

493 if node.orelse: 

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

495 return "\n".join(trys) 

496 

497 def visit_tryfinally(self, node) -> str: 

498 """return an astroid.TryFinally node as string""" 

499 return "try:\n{}\nfinally:\n{}".format( 

500 self._stmt_list(node.body), self._stmt_list(node.finalbody) 

501 ) 

502 

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

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

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

506 for handler in node.handlers: 

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

508 if node.orelse: 

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

510 if node.finalbody: 

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

512 return "\n".join(trys) 

513 

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

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

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

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

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

519 

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

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

522 if node.op == "not": 

523 operator = "not " 

524 else: 

525 operator = node.op 

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

527 

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

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

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

531 if node.orelse: 

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

533 return whiles 

534 

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

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

537 items = ", ".join( 

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

539 for expr, v in node.items 

540 ) 

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

542 

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

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

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

546 expr = "yield" + yi_val 

547 if node.parent.is_statement: 

548 return expr 

549 

550 return f"({expr})" 

551 

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

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

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

555 expr = "yield from" + yi_val 

556 if node.parent.is_statement: 

557 return expr 

558 

559 return f"({expr})" 

560 

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

562 """return Starred node as string""" 

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

564 

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

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

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

568 

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

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

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

572 return ( 

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

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

575 ) 

576 

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

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

579 return node.value.accept(self) 

580 

581 @staticmethod 

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

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

584 return str(node.value) 

585 

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

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

588 if node.patterns is None: 

589 return "[]" 

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

591 

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

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

594 mapping_strings: list[str] = [] 

595 if node.keys and node.patterns: 

596 mapping_strings.extend( 

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

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

599 ) 

600 if node.rest: 

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

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

603 

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

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

606 if node.cls is None: 

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

608 class_strings: list[str] = [] 

609 if node.patterns: 

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

611 if node.kwd_attrs and node.kwd_patterns: 

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

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

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

615 

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

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

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

619 

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

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

622 # pylint: disable=import-outside-toplevel 

623 # Prevent circular dependency 

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

625 

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

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

628 return ( 

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

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

631 ) 

632 

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

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

635 if node.patterns is None: 

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

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

638 

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

640 

641 def visit_frozenset(self, node): 

642 return node.parent.accept(self) 

643 

644 def visit_super(self, node): 

645 return node.parent.accept(self) 

646 

647 def visit_uninferable(self, node): 

648 return str(node) 

649 

650 def visit_property(self, node): 

651 return node.function.accept(self) 

652 

653 def visit_evaluatedobject(self, node): 

654 return node.original.accept(self) 

655 

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

657 return str(node) 

658 

659 

660def _import_string(names) -> str: 

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

662 _names = [] 

663 for name, asname in names: 

664 if asname is not None: 

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

666 else: 

667 _names.append(name) 

668 return ", ".join(_names) 

669 

670 

671# This sets the default indent to 4 spaces. 

672to_code = AsStringVisitor(" ")