Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/astroid/rebuilder.py: 61%

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

697 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 contains utilities for rebuilding an _ast tree in 

6order to get a single Astroid representation. 

7""" 

8 

9from __future__ import annotations 

10 

11import ast 

12import itertools 

13import sys 

14import token 

15from collections.abc import Callable, Collection, Generator 

16from io import StringIO 

17from tokenize import TokenError, TokenInfo, generate_tokens 

18from typing import TYPE_CHECKING, Final, TypeVar, cast, overload 

19 

20from astroid import nodes 

21from astroid._ast import ParserModule, get_parser_module, parse_function_type_comment 

22from astroid.const import PY312_PLUS, PY313_PLUS, Context 

23from astroid.nodes.utils import Position 

24from astroid.typing import InferenceResult 

25 

26if TYPE_CHECKING: 

27 from astroid.manager import AstroidManager 

28 

29 T_Doc = TypeVar( 

30 "T_Doc", 

31 ast.Module, 

32 ast.ClassDef, 

33 ast.FunctionDef | ast.AsyncFunctionDef, 

34 ) 

35 _FunctionT = TypeVar("_FunctionT", nodes.FunctionDef, nodes.AsyncFunctionDef) 

36 _ForT = TypeVar("_ForT", nodes.For, nodes.AsyncFor) 

37 _WithT = TypeVar("_WithT", nodes.With, nodes.AsyncWith) 

38 NodesWithDocsType = nodes.Module | nodes.ClassDef | nodes.FunctionDef 

39 

40 

41REDIRECT: Final[dict[str, str]] = { 

42 "arguments": "Arguments", 

43 "comprehension": "Comprehension", 

44 "ListCompFor": "Comprehension", 

45 "GenExprFor": "Comprehension", 

46 "excepthandler": "ExceptHandler", 

47 "keyword": "Keyword", 

48 "match_case": "MatchCase", 

49} 

50 

51 

52# noinspection PyMethodMayBeStatic 

53class TreeRebuilder: 

54 """Rebuilds the _ast tree to become an Astroid tree.""" 

55 

56 def __init__( 

57 self, 

58 manager: AstroidManager, 

59 parser_module: ParserModule | None = None, 

60 data: str | None = None, 

61 ) -> None: 

62 self._manager = manager 

63 self._data = data.split("\n") if data else None 

64 self._global_names: list[dict[str, list[nodes.Global]]] = [] 

65 self._import_from_nodes: list[tuple[nodes.ImportFrom, Collection[str]]] = [] 

66 self._delayed_assattr: list[nodes.AssignAttr] = [] 

67 self._visit_meths: dict[ 

68 type[ast.AST], Callable[[ast.AST, nodes.NodeNG], nodes.NodeNG] 

69 ] = {} 

70 

71 if parser_module is None: 

72 self._parser_module = get_parser_module() 

73 else: 

74 self._parser_module = parser_module 

75 

76 def _get_doc(self, node: T_Doc) -> tuple[T_Doc, ast.Constant | None]: 

77 """Return the doc ast node.""" 

78 try: 

79 if node.body and isinstance(node.body[0], ast.Expr): 

80 first_value = node.body[0].value 

81 if isinstance(first_value, ast.Constant) and isinstance( 

82 first_value.value, str 

83 ): 

84 doc_ast_node = first_value 

85 node.body = node.body[1:] 

86 return node, doc_ast_node 

87 except IndexError: 

88 pass # ast built from scratch 

89 return node, None 

90 

91 def _get_context( 

92 self, 

93 node: ( 

94 ast.Attribute 

95 | ast.List 

96 | ast.Name 

97 | ast.Subscript 

98 | ast.Starred 

99 | ast.Tuple 

100 ), 

101 ) -> Context: 

102 return self._parser_module.context_classes.get(type(node.ctx), Context.Load) 

103 

104 def _get_position_info( 

105 self, 

106 node: ast.ClassDef | ast.FunctionDef | ast.AsyncFunctionDef, 

107 parent: nodes.ClassDef | nodes.FunctionDef | nodes.AsyncFunctionDef, 

108 ) -> Position | None: 

109 """Return position information for ClassDef and FunctionDef nodes. 

110 

111 In contrast to AST positions, these only include the actual keyword(s) 

112 and the class / function name. 

113 

114 >>> @decorator 

115 >>> async def some_func(var: int) -> None: 

116 >>> ^^^^^^^^^^^^^^^^^^^ 

117 """ 

118 if not self._data: 

119 return None 

120 end_lineno = node.end_lineno 

121 if node.body: 

122 end_lineno = node.body[0].lineno 

123 data = "\n".join(self._data[node.lineno - 1 : end_lineno]) 

124 

125 start_token: TokenInfo | None = None 

126 keyword_tokens: tuple[int, ...] = (token.NAME,) 

127 if isinstance(parent, nodes.AsyncFunctionDef): 

128 search_token = "async" 

129 elif isinstance(parent, nodes.FunctionDef): 

130 search_token = "def" 

131 else: 

132 search_token = "class" 

133 

134 try: 

135 for t in generate_tokens(StringIO(data).readline): 

136 if ( 

137 start_token is not None 

138 and t.type == token.NAME 

139 and t.string == node.name 

140 ): 

141 break 

142 if t.type in keyword_tokens: 

143 if t.string == search_token: 

144 start_token = t 

145 continue 

146 if t.string in {"def"}: 

147 continue 

148 start_token = None 

149 else: 

150 return None 

151 except (TokenError, SyntaxError): 

152 # ``generate_tokens`` can raise on input it cannot tokenize, e.g. 

153 # ``TokenError`` for an unterminated bracket on Python < 3.12, or 

154 # ``IndentationError`` when ``\r``-terminated lines make the slice 

155 # of ``self._data`` (split on ``\n`` only) misaligned with the AST 

156 # line numbers; no position info then. 

157 return None 

158 

159 return Position( 

160 lineno=node.lineno + start_token.start[0] - 1, 

161 col_offset=start_token.start[1], 

162 end_lineno=node.lineno + t.end[0] - 1, 

163 end_col_offset=t.end[1], 

164 ) 

165 

166 def visit_module( 

167 self, node: ast.Module, modname: str, modpath: str, package: bool 

168 ) -> nodes.Module: 

169 """Visit a Module node by returning a fresh instance of it. 

170 

171 Note: Method not called by 'visit' 

172 """ 

173 node, doc_ast_node = self._get_doc(node) 

174 newnode = nodes.Module( 

175 name=modname, 

176 file=modpath, 

177 path=[modpath], 

178 package=package, 

179 ) 

180 newnode.postinit( 

181 [self.visit(child, newnode) for child in node.body], 

182 doc_node=self.visit(doc_ast_node, newnode), 

183 ) 

184 return newnode 

185 

186 if TYPE_CHECKING: # noqa: C901 

187 

188 @overload 

189 def visit(self, node: ast.arg, parent: nodes.NodeNG) -> nodes.AssignName: ... 

190 

191 @overload 

192 def visit( 

193 self, node: ast.arguments, parent: nodes.NodeNG 

194 ) -> nodes.Arguments: ... 

195 

196 @overload 

197 def visit(self, node: ast.Assert, parent: nodes.NodeNG) -> nodes.Assert: ... 

198 

199 @overload 

200 def visit( 

201 self, node: ast.AsyncFunctionDef, parent: nodes.NodeNG 

202 ) -> nodes.AsyncFunctionDef: ... 

203 

204 @overload 

205 def visit(self, node: ast.AsyncFor, parent: nodes.NodeNG) -> nodes.AsyncFor: ... 

206 

207 @overload 

208 def visit(self, node: ast.Await, parent: nodes.NodeNG) -> nodes.Await: ... 

209 

210 @overload 

211 def visit( 

212 self, node: ast.AsyncWith, parent: nodes.NodeNG 

213 ) -> nodes.AsyncWith: ... 

214 

215 @overload 

216 def visit(self, node: ast.Assign, parent: nodes.NodeNG) -> nodes.Assign: ... 

217 

218 @overload 

219 def visit( 

220 self, node: ast.AnnAssign, parent: nodes.NodeNG 

221 ) -> nodes.AnnAssign: ... 

222 

223 @overload 

224 def visit( 

225 self, node: ast.AugAssign, parent: nodes.NodeNG 

226 ) -> nodes.AugAssign: ... 

227 

228 @overload 

229 def visit(self, node: ast.BinOp, parent: nodes.NodeNG) -> nodes.BinOp: ... 

230 

231 @overload 

232 def visit(self, node: ast.BoolOp, parent: nodes.NodeNG) -> nodes.BoolOp: ... 

233 

234 @overload 

235 def visit(self, node: ast.Break, parent: nodes.NodeNG) -> nodes.Break: ... 

236 

237 @overload 

238 def visit(self, node: ast.Call, parent: nodes.NodeNG) -> nodes.Call: ... 

239 

240 @overload 

241 def visit(self, node: ast.ClassDef, parent: nodes.NodeNG) -> nodes.ClassDef: ... 

242 

243 @overload 

244 def visit(self, node: ast.Continue, parent: nodes.NodeNG) -> nodes.Continue: ... 

245 

246 @overload 

247 def visit(self, node: ast.Compare, parent: nodes.NodeNG) -> nodes.Compare: ... 

248 

249 @overload 

250 def visit( 

251 self, node: ast.comprehension, parent: nodes.NodeNG 

252 ) -> nodes.Comprehension: ... 

253 

254 @overload 

255 def visit(self, node: ast.Delete, parent: nodes.NodeNG) -> nodes.Delete: ... 

256 

257 @overload 

258 def visit(self, node: ast.Dict, parent: nodes.NodeNG) -> nodes.Dict: ... 

259 

260 @overload 

261 def visit(self, node: ast.DictComp, parent: nodes.NodeNG) -> nodes.DictComp: ... 

262 

263 @overload 

264 def visit(self, node: ast.Expr, parent: nodes.NodeNG) -> nodes.Expr: ... 

265 

266 @overload 

267 def visit( 

268 self, node: ast.ExceptHandler, parent: nodes.NodeNG 

269 ) -> nodes.ExceptHandler: ... 

270 

271 @overload 

272 def visit(self, node: ast.For, parent: nodes.NodeNG) -> nodes.For: ... 

273 

274 @overload 

275 def visit( 

276 self, node: ast.ImportFrom, parent: nodes.NodeNG 

277 ) -> nodes.ImportFrom: ... 

278 

279 @overload 

280 def visit( 

281 self, node: ast.FunctionDef, parent: nodes.NodeNG 

282 ) -> nodes.FunctionDef: ... 

283 

284 @overload 

285 def visit( 

286 self, node: ast.GeneratorExp, parent: nodes.NodeNG 

287 ) -> nodes.GeneratorExp: ... 

288 

289 @overload 

290 def visit( 

291 self, node: ast.Attribute, parent: nodes.NodeNG 

292 ) -> nodes.Attribute: ... 

293 

294 @overload 

295 def visit(self, node: ast.Global, parent: nodes.NodeNG) -> nodes.Global: ... 

296 

297 @overload 

298 def visit(self, node: ast.If, parent: nodes.NodeNG) -> nodes.If: ... 

299 

300 @overload 

301 def visit(self, node: ast.IfExp, parent: nodes.NodeNG) -> nodes.IfExp: ... 

302 

303 @overload 

304 def visit(self, node: ast.Import, parent: nodes.NodeNG) -> nodes.Import: ... 

305 

306 @overload 

307 def visit( 

308 self, node: ast.JoinedStr, parent: nodes.NodeNG 

309 ) -> nodes.JoinedStr: ... 

310 

311 @overload 

312 def visit( 

313 self, node: ast.FormattedValue, parent: nodes.NodeNG 

314 ) -> nodes.FormattedValue: ... 

315 

316 @overload 

317 def visit( 

318 self, node: ast.NamedExpr, parent: nodes.NodeNG 

319 ) -> nodes.NamedExpr: ... 

320 

321 @overload 

322 def visit(self, node: ast.keyword, parent: nodes.NodeNG) -> nodes.Keyword: ... 

323 

324 @overload 

325 def visit(self, node: ast.Lambda, parent: nodes.NodeNG) -> nodes.Lambda: ... 

326 

327 @overload 

328 def visit(self, node: ast.List, parent: nodes.NodeNG) -> nodes.List: ... 

329 

330 @overload 

331 def visit(self, node: ast.ListComp, parent: nodes.NodeNG) -> nodes.ListComp: ... 

332 

333 @overload 

334 def visit( 

335 self, node: ast.Name, parent: nodes.NodeNG 

336 ) -> nodes.Name | nodes.Const | nodes.AssignName | nodes.DelName: ... 

337 

338 @overload 

339 def visit(self, node: ast.Nonlocal, parent: nodes.NodeNG) -> nodes.Nonlocal: ... 

340 

341 @overload 

342 def visit(self, node: ast.Constant, parent: nodes.NodeNG) -> nodes.Const: ... 

343 

344 if sys.version_info >= (3, 12): 

345 

346 @overload 

347 def visit( 

348 self, node: ast.ParamSpec, parent: nodes.NodeNG 

349 ) -> nodes.ParamSpec: ... 

350 

351 @overload 

352 def visit(self, node: ast.Pass, parent: nodes.NodeNG) -> nodes.Pass: ... 

353 

354 @overload 

355 def visit(self, node: ast.Raise, parent: nodes.NodeNG) -> nodes.Raise: ... 

356 

357 @overload 

358 def visit(self, node: ast.Return, parent: nodes.NodeNG) -> nodes.Return: ... 

359 

360 @overload 

361 def visit(self, node: ast.Set, parent: nodes.NodeNG) -> nodes.Set: ... 

362 

363 @overload 

364 def visit(self, node: ast.SetComp, parent: nodes.NodeNG) -> nodes.SetComp: ... 

365 

366 @overload 

367 def visit(self, node: ast.Slice, parent: nodes.Subscript) -> nodes.Slice: ... 

368 

369 @overload 

370 def visit( 

371 self, node: ast.Subscript, parent: nodes.NodeNG 

372 ) -> nodes.Subscript: ... 

373 

374 @overload 

375 def visit(self, node: ast.Starred, parent: nodes.NodeNG) -> nodes.Starred: ... 

376 

377 @overload 

378 def visit(self, node: ast.Try, parent: nodes.NodeNG) -> nodes.Try: ... 

379 

380 if sys.version_info >= (3, 11): 

381 

382 @overload 

383 def visit( 

384 self, node: ast.TryStar, parent: nodes.NodeNG 

385 ) -> nodes.TryStar: ... 

386 

387 @overload 

388 def visit(self, node: ast.Tuple, parent: nodes.NodeNG) -> nodes.Tuple: ... 

389 

390 if sys.version_info >= (3, 12): 

391 

392 @overload 

393 def visit( 

394 self, node: ast.TypeAlias, parent: nodes.NodeNG 

395 ) -> nodes.TypeAlias: ... 

396 

397 @overload 

398 def visit( 

399 self, node: ast.TypeVar, parent: nodes.NodeNG 

400 ) -> nodes.TypeVar: ... 

401 

402 @overload 

403 def visit( 

404 self, node: ast.TypeVarTuple, parent: nodes.NodeNG 

405 ) -> nodes.TypeVarTuple: ... 

406 

407 @overload 

408 def visit(self, node: ast.UnaryOp, parent: nodes.NodeNG) -> nodes.UnaryOp: ... 

409 

410 @overload 

411 def visit(self, node: ast.While, parent: nodes.NodeNG) -> nodes.While: ... 

412 

413 @overload 

414 def visit(self, node: ast.With, parent: nodes.NodeNG) -> nodes.With: ... 

415 

416 @overload 

417 def visit(self, node: ast.Yield, parent: nodes.NodeNG) -> nodes.Yield: ... 

418 

419 @overload 

420 def visit( 

421 self, node: ast.YieldFrom, parent: nodes.NodeNG 

422 ) -> nodes.YieldFrom: ... 

423 

424 @overload 

425 def visit(self, node: ast.Match, parent: nodes.NodeNG) -> nodes.Match: ... 

426 

427 @overload 

428 def visit( 

429 self, node: ast.match_case, parent: nodes.NodeNG 

430 ) -> nodes.MatchCase: ... 

431 

432 @overload 

433 def visit( 

434 self, node: ast.MatchValue, parent: nodes.NodeNG 

435 ) -> nodes.MatchValue: ... 

436 

437 @overload 

438 def visit( 

439 self, node: ast.MatchSingleton, parent: nodes.NodeNG 

440 ) -> nodes.MatchSingleton: ... 

441 

442 @overload 

443 def visit( 

444 self, node: ast.MatchSequence, parent: nodes.NodeNG 

445 ) -> nodes.MatchSequence: ... 

446 

447 @overload 

448 def visit( 

449 self, node: ast.MatchMapping, parent: nodes.NodeNG 

450 ) -> nodes.MatchMapping: ... 

451 

452 @overload 

453 def visit( 

454 self, node: ast.MatchClass, parent: nodes.NodeNG 

455 ) -> nodes.MatchClass: ... 

456 

457 @overload 

458 def visit( 

459 self, node: ast.MatchStar, parent: nodes.NodeNG 

460 ) -> nodes.MatchStar: ... 

461 

462 @overload 

463 def visit(self, node: ast.MatchAs, parent: nodes.NodeNG) -> nodes.MatchAs: ... 

464 

465 @overload 

466 def visit(self, node: ast.MatchOr, parent: nodes.NodeNG) -> nodes.MatchOr: ... 

467 

468 @overload 

469 def visit(self, node: ast.pattern, parent: nodes.NodeNG) -> nodes.Pattern: ... 

470 

471 if sys.version_info >= (3, 14): 

472 

473 @overload 

474 def visit( 

475 self, node: ast.TemplateStr, parent: nodes.NodeNG 

476 ) -> nodes.TemplateStr: ... 

477 

478 @overload 

479 def visit( 

480 self, node: ast.Interpolation, parent: nodes.NodeNG 

481 ) -> nodes.Interpolation: ... 

482 

483 @overload 

484 def visit(self, node: ast.AST, parent: nodes.NodeNG) -> nodes.NodeNG: ... 

485 

486 @overload 

487 def visit(self, node: None, parent: nodes.NodeNG) -> None: ... 

488 

489 def visit(self, node: ast.AST | None, parent: nodes.NodeNG) -> nodes.NodeNG | None: 

490 if node is None: 

491 return None 

492 cls = node.__class__ 

493 if cls in self._visit_meths: 

494 visit_method = self._visit_meths[cls] 

495 else: 

496 cls_name = cls.__name__ 

497 visit_name = "visit_" + REDIRECT.get(cls_name, cls_name).lower() 

498 visit_method = getattr(self, visit_name) 

499 self._visit_meths[cls] = visit_method 

500 return visit_method(node, parent) 

501 

502 def _save_assignment(self, node: nodes.AssignName | nodes.DelName) -> None: 

503 """Save assignment situation since node.parent is not available yet.""" 

504 if self._global_names and node.name in self._global_names[-1]: 

505 node.root().set_local(node.name, node) 

506 else: 

507 assert node.parent 

508 assert node.name 

509 node.parent.set_local(node.name, node) 

510 

511 def visit_arg(self, node: ast.arg, parent: nodes.NodeNG) -> nodes.AssignName: 

512 """Visit an arg node by returning a fresh AssignName instance.""" 

513 return self.visit_assignname(node, parent, node.arg) 

514 

515 def visit_arguments( 

516 self, node: ast.arguments, parent: nodes.NodeNG 

517 ) -> nodes.Arguments: 

518 """Visit an Arguments node by returning a fresh instance of it.""" 

519 vararg: str | None = None 

520 kwarg: str | None = None 

521 vararg_node = node.vararg 

522 kwarg_node = node.kwarg 

523 

524 newnode = nodes.Arguments( 

525 node.vararg.arg if node.vararg else None, 

526 node.kwarg.arg if node.kwarg else None, 

527 parent, 

528 ( 

529 nodes.AssignName( 

530 vararg_node.arg, 

531 vararg_node.lineno, 

532 vararg_node.col_offset, 

533 parent, 

534 end_lineno=vararg_node.end_lineno, 

535 end_col_offset=vararg_node.end_col_offset, 

536 ) 

537 if vararg_node 

538 else None 

539 ), 

540 ( 

541 nodes.AssignName( 

542 kwarg_node.arg, 

543 kwarg_node.lineno, 

544 kwarg_node.col_offset, 

545 parent, 

546 end_lineno=kwarg_node.end_lineno, 

547 end_col_offset=kwarg_node.end_col_offset, 

548 ) 

549 if kwarg_node 

550 else None 

551 ), 

552 ) 

553 args = [self.visit(child, newnode) for child in node.args] 

554 defaults = [self.visit(child, newnode) for child in node.defaults] 

555 varargannotation: nodes.NodeNG | None = None 

556 kwargannotation: nodes.NodeNG | None = None 

557 if node.vararg: 

558 vararg = node.vararg.arg 

559 varargannotation = self.visit(node.vararg.annotation, newnode) 

560 if node.kwarg: 

561 kwarg = node.kwarg.arg 

562 kwargannotation = self.visit(node.kwarg.annotation, newnode) 

563 

564 kwonlyargs = [self.visit(child, newnode) for child in node.kwonlyargs] 

565 kw_defaults = [self.visit(child, newnode) for child in node.kw_defaults] 

566 annotations = [self.visit(arg.annotation, newnode) for arg in node.args] 

567 kwonlyargs_annotations = [ 

568 self.visit(arg.annotation, newnode) for arg in node.kwonlyargs 

569 ] 

570 

571 posonlyargs = [self.visit(child, newnode) for child in node.posonlyargs] 

572 posonlyargs_annotations = [ 

573 self.visit(arg.annotation, newnode) for arg in node.posonlyargs 

574 ] 

575 type_comment_args = [ 

576 self.check_type_comment(child, parent=newnode) for child in node.args 

577 ] 

578 type_comment_kwonlyargs = [ 

579 self.check_type_comment(child, parent=newnode) for child in node.kwonlyargs 

580 ] 

581 type_comment_posonlyargs = [ 

582 self.check_type_comment(child, parent=newnode) for child in node.posonlyargs 

583 ] 

584 

585 newnode.postinit( 

586 args=args, 

587 defaults=defaults, 

588 kwonlyargs=kwonlyargs, 

589 posonlyargs=posonlyargs, 

590 kw_defaults=kw_defaults, 

591 annotations=annotations, 

592 kwonlyargs_annotations=kwonlyargs_annotations, 

593 posonlyargs_annotations=posonlyargs_annotations, 

594 varargannotation=varargannotation, 

595 kwargannotation=kwargannotation, 

596 type_comment_args=type_comment_args, 

597 type_comment_kwonlyargs=type_comment_kwonlyargs, 

598 type_comment_posonlyargs=type_comment_posonlyargs, 

599 ) 

600 if start_end_lineno_pairs := [ 

601 (arg.lineno, arg.end_lineno) 

602 for arg in itertools.chain( 

603 node.args, node.posonlyargs, node.kwonlyargs, [node.vararg, node.kwarg] 

604 ) 

605 if arg 

606 ]: 

607 newnode.lineno = min(startend[0] for startend in start_end_lineno_pairs) 

608 newnode.end_lineno = max(startend[1] for startend in start_end_lineno_pairs) 

609 

610 # save argument names in locals: 

611 assert newnode.parent 

612 if vararg: 

613 newnode.parent.set_local(vararg, newnode) 

614 if kwarg: 

615 newnode.parent.set_local(kwarg, newnode) 

616 return newnode 

617 

618 def visit_assert(self, node: ast.Assert, parent: nodes.NodeNG) -> nodes.Assert: 

619 """Visit a Assert node by returning a fresh instance of it.""" 

620 newnode = nodes.Assert( 

621 lineno=node.lineno, 

622 col_offset=node.col_offset, 

623 end_lineno=node.end_lineno, 

624 end_col_offset=node.end_col_offset, 

625 parent=parent, 

626 ) 

627 msg: nodes.NodeNG | None = None 

628 if node.msg: 

629 msg = self.visit(node.msg, newnode) 

630 newnode.postinit(self.visit(node.test, newnode), msg) 

631 return newnode 

632 

633 def check_type_comment( 

634 self, 

635 node: ast.Assign | ast.arg | ast.For | ast.AsyncFor | ast.With | ast.AsyncWith, 

636 parent: ( 

637 nodes.Assign 

638 | nodes.Arguments 

639 | nodes.For 

640 | nodes.AsyncFor 

641 | nodes.With 

642 | nodes.AsyncWith 

643 ), 

644 ) -> nodes.NodeNG | None: 

645 if not node.type_comment: 

646 return None 

647 

648 try: 

649 type_comment_ast = self._parser_module.parse(node.type_comment) 

650 except (SyntaxError, ValueError, MemoryError, RecursionError): 

651 # Invalid type comment, just skip it. ``ast.parse`` may raise 

652 # ``MemoryError``/``RecursionError``/``ValueError`` on pathological 

653 # inputs (e.g. deeply nested braces produced by fuzzers). 

654 return None 

655 

656 # For '# type: # any comment' ast.parse returns a Module node, 

657 # without any nodes in the body. 

658 if not type_comment_ast.body: 

659 return None 

660 

661 type_object = self.visit(type_comment_ast.body[0], parent=parent) 

662 if not isinstance(type_object, nodes.Expr): 

663 return None 

664 

665 return type_object.value 

666 

667 def check_function_type_comment( 

668 self, node: ast.FunctionDef | ast.AsyncFunctionDef, parent: nodes.NodeNG 

669 ) -> tuple[nodes.NodeNG | None, list[nodes.NodeNG]] | None: 

670 if not node.type_comment: 

671 return None 

672 

673 try: 

674 type_comment_ast = parse_function_type_comment(node.type_comment) 

675 except (SyntaxError, ValueError, MemoryError, RecursionError): 

676 # Invalid type comment, just skip it. ``ast.parse`` may raise 

677 # ``MemoryError``/``RecursionError``/``ValueError`` on pathological 

678 # inputs (e.g. deeply nested braces produced by fuzzers). 

679 return None 

680 

681 if not type_comment_ast: 

682 return None 

683 

684 returns: nodes.NodeNG | None = None 

685 argtypes: list[nodes.NodeNG] = [ 

686 self.visit(elem, parent) for elem in (type_comment_ast.argtypes or []) 

687 ] 

688 if type_comment_ast.returns: 

689 returns = self.visit(type_comment_ast.returns, parent) 

690 

691 return returns, argtypes 

692 

693 def visit_asyncfunctiondef( 

694 self, node: ast.AsyncFunctionDef, parent: nodes.NodeNG 

695 ) -> nodes.AsyncFunctionDef: 

696 return self._visit_functiondef(nodes.AsyncFunctionDef, node, parent) 

697 

698 def visit_asyncfor( 

699 self, node: ast.AsyncFor, parent: nodes.NodeNG 

700 ) -> nodes.AsyncFor: 

701 return self._visit_for(nodes.AsyncFor, node, parent) 

702 

703 def visit_await(self, node: ast.Await, parent: nodes.NodeNG) -> nodes.Await: 

704 newnode = nodes.Await( 

705 lineno=node.lineno, 

706 col_offset=node.col_offset, 

707 end_lineno=node.end_lineno, 

708 end_col_offset=node.end_col_offset, 

709 parent=parent, 

710 ) 

711 newnode.postinit(value=self.visit(node.value, newnode)) 

712 return newnode 

713 

714 def visit_asyncwith( 

715 self, node: ast.AsyncWith, parent: nodes.NodeNG 

716 ) -> nodes.AsyncWith: 

717 return self._visit_with(nodes.AsyncWith, node, parent) 

718 

719 def visit_assign(self, node: ast.Assign, parent: nodes.NodeNG) -> nodes.Assign: 

720 """Visit a Assign node by returning a fresh instance of it.""" 

721 newnode = nodes.Assign( 

722 lineno=node.lineno, 

723 col_offset=node.col_offset, 

724 end_lineno=node.end_lineno, 

725 end_col_offset=node.end_col_offset, 

726 parent=parent, 

727 ) 

728 type_annotation = self.check_type_comment(node, parent=newnode) 

729 newnode.postinit( 

730 targets=[self.visit(child, newnode) for child in node.targets], 

731 value=self.visit(node.value, newnode), 

732 type_annotation=type_annotation, 

733 ) 

734 return newnode 

735 

736 def visit_annassign( 

737 self, node: ast.AnnAssign, parent: nodes.NodeNG 

738 ) -> nodes.AnnAssign: 

739 """Visit an AnnAssign node by returning a fresh instance of it.""" 

740 newnode = nodes.AnnAssign( 

741 lineno=node.lineno, 

742 col_offset=node.col_offset, 

743 end_lineno=node.end_lineno, 

744 end_col_offset=node.end_col_offset, 

745 parent=parent, 

746 ) 

747 newnode.postinit( 

748 target=self.visit(node.target, newnode), 

749 annotation=self.visit(node.annotation, newnode), 

750 simple=node.simple, 

751 value=self.visit(node.value, newnode), 

752 ) 

753 return newnode 

754 

755 @overload 

756 def visit_assignname( 

757 self, node: ast.AST, parent: nodes.NodeNG, node_name: str 

758 ) -> nodes.AssignName: ... 

759 

760 @overload 

761 def visit_assignname( 

762 self, node: ast.AST, parent: nodes.NodeNG, node_name: None 

763 ) -> None: ... 

764 

765 def visit_assignname( 

766 self, node: ast.AST, parent: nodes.NodeNG, node_name: str | None 

767 ) -> nodes.AssignName | None: 

768 """Visit a node and return a AssignName node. 

769 

770 Note: Method not called by 'visit' 

771 """ 

772 if node_name is None: 

773 return None 

774 newnode = nodes.AssignName( 

775 name=node_name, 

776 lineno=node.lineno, 

777 col_offset=node.col_offset, 

778 end_lineno=node.end_lineno, 

779 end_col_offset=node.end_col_offset, 

780 parent=parent, 

781 ) 

782 self._save_assignment(newnode) 

783 return newnode 

784 

785 def visit_augassign( 

786 self, node: ast.AugAssign, parent: nodes.NodeNG 

787 ) -> nodes.AugAssign: 

788 """Visit a AugAssign node by returning a fresh instance of it.""" 

789 newnode = nodes.AugAssign( 

790 op=self._parser_module.bin_op_classes[type(node.op)] + "=", 

791 lineno=node.lineno, 

792 col_offset=node.col_offset, 

793 end_lineno=node.end_lineno, 

794 end_col_offset=node.end_col_offset, 

795 parent=parent, 

796 ) 

797 newnode.postinit( 

798 self.visit(node.target, newnode), self.visit(node.value, newnode) 

799 ) 

800 return newnode 

801 

802 def visit_binop(self, node: ast.BinOp, parent: nodes.NodeNG) -> nodes.BinOp: 

803 """Visit a BinOp node by returning a fresh instance of it.""" 

804 newnode = nodes.BinOp( 

805 op=self._parser_module.bin_op_classes[type(node.op)], 

806 lineno=node.lineno, 

807 col_offset=node.col_offset, 

808 end_lineno=node.end_lineno, 

809 end_col_offset=node.end_col_offset, 

810 parent=parent, 

811 ) 

812 newnode.postinit( 

813 self.visit(node.left, newnode), self.visit(node.right, newnode) 

814 ) 

815 return newnode 

816 

817 def visit_boolop(self, node: ast.BoolOp, parent: nodes.NodeNG) -> nodes.BoolOp: 

818 """Visit a BoolOp node by returning a fresh instance of it.""" 

819 newnode = nodes.BoolOp( 

820 op=self._parser_module.bool_op_classes[type(node.op)], 

821 lineno=node.lineno, 

822 col_offset=node.col_offset, 

823 end_lineno=node.end_lineno, 

824 end_col_offset=node.end_col_offset, 

825 parent=parent, 

826 ) 

827 newnode.postinit([self.visit(child, newnode) for child in node.values]) 

828 return newnode 

829 

830 def visit_break(self, node: ast.Break, parent: nodes.NodeNG) -> nodes.Break: 

831 """Visit a Break node by returning a fresh instance of it.""" 

832 return nodes.Break( 

833 lineno=node.lineno, 

834 col_offset=node.col_offset, 

835 end_lineno=node.end_lineno, 

836 end_col_offset=node.end_col_offset, 

837 parent=parent, 

838 ) 

839 

840 def visit_call(self, node: ast.Call, parent: nodes.NodeNG) -> nodes.Call: 

841 """Visit a CallFunc node by returning a fresh instance of it.""" 

842 newnode = nodes.Call( 

843 lineno=node.lineno, 

844 col_offset=node.col_offset, 

845 end_lineno=node.end_lineno, 

846 end_col_offset=node.end_col_offset, 

847 parent=parent, 

848 ) 

849 newnode.postinit( 

850 func=self.visit(node.func, newnode), 

851 args=[self.visit(child, newnode) for child in node.args], 

852 keywords=[self.visit(child, newnode) for child in node.keywords], 

853 ) 

854 return newnode 

855 

856 def visit_classdef( 

857 self, node: ast.ClassDef, parent: nodes.NodeNG, newstyle: bool = True 

858 ) -> nodes.ClassDef: 

859 """Visit a ClassDef node to become astroid.""" 

860 node, doc_ast_node = self._get_doc(node) 

861 newnode = nodes.ClassDef( 

862 name=node.name, 

863 lineno=node.lineno, 

864 col_offset=node.col_offset, 

865 end_lineno=node.end_lineno, 

866 end_col_offset=node.end_col_offset, 

867 parent=parent, 

868 ) 

869 metaclass = None 

870 for keyword in node.keywords: 

871 if keyword.arg == "metaclass": 

872 metaclass = self.visit(keyword, newnode).value 

873 break 

874 decorators = self.visit_decorators(node, newnode) 

875 newnode.postinit( 

876 [self.visit(child, newnode) for child in node.bases], 

877 [self.visit(child, newnode) for child in node.body], 

878 decorators, 

879 newstyle, 

880 metaclass, 

881 [ 

882 self.visit(kwd, newnode) 

883 for kwd in node.keywords 

884 if kwd.arg != "metaclass" 

885 ], 

886 position=self._get_position_info(node, newnode), 

887 doc_node=self.visit(doc_ast_node, newnode), 

888 type_params=( 

889 [self.visit(param, newnode) for param in node.type_params] 

890 if PY312_PLUS 

891 else [] 

892 ), 

893 ) 

894 parent.set_local(newnode.name, newnode) 

895 return newnode 

896 

897 def visit_continue( 

898 self, node: ast.Continue, parent: nodes.NodeNG 

899 ) -> nodes.Continue: 

900 """Visit a Continue node by returning a fresh instance of it.""" 

901 return nodes.Continue( 

902 lineno=node.lineno, 

903 col_offset=node.col_offset, 

904 end_lineno=node.end_lineno, 

905 end_col_offset=node.end_col_offset, 

906 parent=parent, 

907 ) 

908 

909 def visit_compare(self, node: ast.Compare, parent: nodes.NodeNG) -> nodes.Compare: 

910 """Visit a Compare node by returning a fresh instance of it.""" 

911 newnode = nodes.Compare( 

912 lineno=node.lineno, 

913 col_offset=node.col_offset, 

914 end_lineno=node.end_lineno, 

915 end_col_offset=node.end_col_offset, 

916 parent=parent, 

917 ) 

918 newnode.postinit( 

919 self.visit(node.left, newnode), 

920 [ 

921 ( 

922 self._parser_module.cmp_op_classes[op.__class__], 

923 self.visit(expr, newnode), 

924 ) 

925 for (op, expr) in zip(node.ops, node.comparators) 

926 ], 

927 ) 

928 return newnode 

929 

930 def visit_comprehension( 

931 self, node: ast.comprehension, parent: nodes.NodeNG 

932 ) -> nodes.Comprehension: 

933 """Visit a Comprehension node by returning a fresh instance of it.""" 

934 newnode = nodes.Comprehension( 

935 parent=parent, 

936 # Comprehension nodes don't have these attributes 

937 # see https://docs.python.org/3/library/ast.html#abstract-grammar 

938 lineno=None, 

939 col_offset=None, 

940 end_lineno=None, 

941 end_col_offset=None, 

942 ) 

943 newnode.postinit( 

944 self.visit(node.target, newnode), 

945 self.visit(node.iter, newnode), 

946 [self.visit(child, newnode) for child in node.ifs], 

947 bool(node.is_async), 

948 ) 

949 return newnode 

950 

951 def visit_decorators( 

952 self, 

953 node: ast.ClassDef | ast.FunctionDef | ast.AsyncFunctionDef, 

954 parent: nodes.NodeNG, 

955 ) -> nodes.Decorators | None: 

956 """Visit a Decorators node by returning a fresh instance of it. 

957 

958 Note: Method not called by 'visit' 

959 """ 

960 if not node.decorator_list: 

961 return None 

962 # /!\ node is actually an _ast.FunctionDef node while 

963 # parent is an astroid.nodes.FunctionDef node 

964 

965 # Set the line number of the first decorator for Python 3.8+. 

966 lineno = node.decorator_list[0].lineno 

967 end_lineno = node.decorator_list[-1].end_lineno 

968 end_col_offset = node.decorator_list[-1].end_col_offset 

969 

970 newnode = nodes.Decorators( 

971 lineno=lineno, 

972 col_offset=node.col_offset, 

973 end_lineno=end_lineno, 

974 end_col_offset=end_col_offset, 

975 parent=parent, 

976 ) 

977 newnode.postinit([self.visit(child, newnode) for child in node.decorator_list]) 

978 return newnode 

979 

980 def visit_delete(self, node: ast.Delete, parent: nodes.NodeNG) -> nodes.Delete: 

981 """Visit a Delete node by returning a fresh instance of it.""" 

982 newnode = nodes.Delete( 

983 lineno=node.lineno, 

984 col_offset=node.col_offset, 

985 end_lineno=node.end_lineno, 

986 end_col_offset=node.end_col_offset, 

987 parent=parent, 

988 ) 

989 newnode.postinit([self.visit(child, newnode) for child in node.targets]) 

990 return newnode 

991 

992 def _visit_dict_items( 

993 self, node: ast.Dict, parent: nodes.NodeNG, newnode: nodes.Dict 

994 ) -> Generator[tuple[nodes.NodeNG, nodes.NodeNG]]: 

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

996 rebuilt_key: nodes.NodeNG 

997 rebuilt_value = self.visit(value, newnode) 

998 if not key: 

999 # Extended unpacking 

1000 rebuilt_key = nodes.DictUnpack( 

1001 lineno=rebuilt_value.lineno, 

1002 col_offset=rebuilt_value.col_offset, 

1003 end_lineno=rebuilt_value.end_lineno, 

1004 end_col_offset=rebuilt_value.end_col_offset, 

1005 parent=parent, 

1006 ) 

1007 else: 

1008 rebuilt_key = self.visit(key, newnode) 

1009 yield rebuilt_key, rebuilt_value 

1010 

1011 def visit_dict(self, node: ast.Dict, parent: nodes.NodeNG) -> nodes.Dict: 

1012 """Visit a Dict node by returning a fresh instance of it.""" 

1013 newnode = nodes.Dict( 

1014 lineno=node.lineno, 

1015 col_offset=node.col_offset, 

1016 end_lineno=node.end_lineno, 

1017 end_col_offset=node.end_col_offset, 

1018 parent=parent, 

1019 ) 

1020 items: list[tuple[InferenceResult, InferenceResult]] = list( 

1021 self._visit_dict_items(node, parent, newnode) 

1022 ) 

1023 newnode.postinit(items) 

1024 return newnode 

1025 

1026 def visit_dictcomp( 

1027 self, node: ast.DictComp, parent: nodes.NodeNG 

1028 ) -> nodes.DictComp: 

1029 """Visit a DictComp node by returning a fresh instance of it.""" 

1030 newnode = nodes.DictComp( 

1031 lineno=node.lineno, 

1032 col_offset=node.col_offset, 

1033 end_lineno=node.end_lineno, 

1034 end_col_offset=node.end_col_offset, 

1035 parent=parent, 

1036 ) 

1037 newnode.postinit( 

1038 self.visit(node.key, newnode), 

1039 self.visit(node.value, newnode), 

1040 [self.visit(child, newnode) for child in node.generators], 

1041 ) 

1042 return newnode 

1043 

1044 def visit_expr(self, node: ast.Expr, parent: nodes.NodeNG) -> nodes.Expr: 

1045 """Visit a Expr node by returning a fresh instance of it.""" 

1046 newnode = nodes.Expr( 

1047 lineno=node.lineno, 

1048 col_offset=node.col_offset, 

1049 end_lineno=node.end_lineno, 

1050 end_col_offset=node.end_col_offset, 

1051 parent=parent, 

1052 ) 

1053 newnode.postinit(self.visit(node.value, newnode)) 

1054 return newnode 

1055 

1056 def visit_excepthandler( 

1057 self, node: ast.ExceptHandler, parent: nodes.NodeNG 

1058 ) -> nodes.ExceptHandler: 

1059 """Visit an ExceptHandler node by returning a fresh instance of it.""" 

1060 newnode = nodes.ExceptHandler( 

1061 lineno=node.lineno, 

1062 col_offset=node.col_offset, 

1063 end_lineno=node.end_lineno, 

1064 end_col_offset=node.end_col_offset, 

1065 parent=parent, 

1066 ) 

1067 newnode.postinit( 

1068 self.visit(node.type, newnode), 

1069 self.visit_assignname(node, newnode, node.name), 

1070 [self.visit(child, newnode) for child in node.body], 

1071 ) 

1072 return newnode 

1073 

1074 @overload 

1075 def _visit_for( 

1076 self, cls: type[nodes.For], node: ast.For, parent: nodes.NodeNG 

1077 ) -> nodes.For: ... 

1078 

1079 @overload 

1080 def _visit_for( 

1081 self, cls: type[nodes.AsyncFor], node: ast.AsyncFor, parent: nodes.NodeNG 

1082 ) -> nodes.AsyncFor: ... 

1083 

1084 def _visit_for( 

1085 self, cls: type[_ForT], node: ast.For | ast.AsyncFor, parent: nodes.NodeNG 

1086 ) -> _ForT: 

1087 """Visit a For node by returning a fresh instance of it.""" 

1088 newnode = cls( 

1089 lineno=node.lineno, 

1090 col_offset=node.col_offset, 

1091 end_lineno=node.end_lineno, 

1092 end_col_offset=node.end_col_offset, 

1093 parent=parent, 

1094 ) 

1095 type_annotation = self.check_type_comment(node, parent=newnode) 

1096 newnode.postinit( 

1097 target=self.visit(node.target, newnode), 

1098 iter=self.visit(node.iter, newnode), 

1099 body=[self.visit(child, newnode) for child in node.body], 

1100 orelse=[self.visit(child, newnode) for child in node.orelse], 

1101 type_annotation=type_annotation, 

1102 ) 

1103 return newnode 

1104 

1105 def visit_for(self, node: ast.For, parent: nodes.NodeNG) -> nodes.For: 

1106 return self._visit_for(nodes.For, node, parent) 

1107 

1108 def visit_importfrom( 

1109 self, node: ast.ImportFrom, parent: nodes.NodeNG 

1110 ) -> nodes.ImportFrom: 

1111 """Visit an ImportFrom node by returning a fresh instance of it.""" 

1112 names = [(alias.name, alias.asname) for alias in node.names] 

1113 newnode = nodes.ImportFrom( 

1114 fromname=node.module or "", 

1115 names=names, 

1116 level=node.level or None, 

1117 lineno=node.lineno, 

1118 col_offset=node.col_offset, 

1119 end_lineno=node.end_lineno, 

1120 end_col_offset=node.end_col_offset, 

1121 parent=parent, 

1122 ) 

1123 # store From names to add them to locals after building 

1124 self._import_from_nodes.append( 

1125 (newnode, self._global_names[-1].keys() if self._global_names else ()) 

1126 ) 

1127 return newnode 

1128 

1129 @overload 

1130 def _visit_functiondef( 

1131 self, cls: type[nodes.FunctionDef], node: ast.FunctionDef, parent: nodes.NodeNG 

1132 ) -> nodes.FunctionDef: ... 

1133 

1134 @overload 

1135 def _visit_functiondef( 

1136 self, 

1137 cls: type[nodes.AsyncFunctionDef], 

1138 node: ast.AsyncFunctionDef, 

1139 parent: nodes.NodeNG, 

1140 ) -> nodes.AsyncFunctionDef: ... 

1141 

1142 def _visit_functiondef( 

1143 self, 

1144 cls: type[_FunctionT], 

1145 node: ast.FunctionDef | ast.AsyncFunctionDef, 

1146 parent: nodes.NodeNG, 

1147 ) -> _FunctionT: 

1148 """Visit an FunctionDef node to become astroid.""" 

1149 self._global_names.append({}) 

1150 node, doc_ast_node = self._get_doc(node) 

1151 

1152 lineno = node.lineno 

1153 if node.decorator_list: 

1154 # Python 3.8 sets the line number of a decorated function 

1155 # to be the actual line number of the function, but the 

1156 # previous versions expected the decorator's line number instead. 

1157 # We reset the function's line number to that of the 

1158 # first decorator to maintain backward compatibility. 

1159 # It's not ideal but this discrepancy was baked into 

1160 # the framework for *years*. 

1161 lineno = node.decorator_list[0].lineno 

1162 

1163 newnode = cls( 

1164 name=node.name, 

1165 lineno=lineno, 

1166 col_offset=node.col_offset, 

1167 end_lineno=node.end_lineno, 

1168 end_col_offset=node.end_col_offset, 

1169 parent=parent, 

1170 ) 

1171 decorators = self.visit_decorators(node, newnode) 

1172 returns: nodes.NodeNG | None 

1173 if node.returns: 

1174 returns = self.visit(node.returns, newnode) 

1175 else: 

1176 returns = None 

1177 

1178 type_comment_args = type_comment_returns = None 

1179 type_comment_annotation = self.check_function_type_comment(node, newnode) 

1180 if type_comment_annotation: 

1181 type_comment_returns, type_comment_args = type_comment_annotation 

1182 newnode.postinit( 

1183 args=self.visit(node.args, newnode), 

1184 body=[self.visit(child, newnode) for child in node.body], 

1185 decorators=decorators, 

1186 returns=returns, 

1187 type_comment_returns=type_comment_returns, 

1188 type_comment_args=type_comment_args, 

1189 position=self._get_position_info(node, newnode), 

1190 doc_node=self.visit(doc_ast_node, newnode), 

1191 type_params=( 

1192 [self.visit(param, newnode) for param in node.type_params] 

1193 if PY312_PLUS 

1194 else [] 

1195 ), 

1196 ) 

1197 self._global_names.pop() 

1198 parent.set_local(newnode.name, newnode) 

1199 return newnode 

1200 

1201 def visit_functiondef( 

1202 self, node: ast.FunctionDef, parent: nodes.NodeNG 

1203 ) -> nodes.FunctionDef: 

1204 return self._visit_functiondef(nodes.FunctionDef, node, parent) 

1205 

1206 def visit_generatorexp( 

1207 self, node: ast.GeneratorExp, parent: nodes.NodeNG 

1208 ) -> nodes.GeneratorExp: 

1209 """Visit a GeneratorExp node by returning a fresh instance of it.""" 

1210 newnode = nodes.GeneratorExp( 

1211 lineno=node.lineno, 

1212 col_offset=node.col_offset, 

1213 end_lineno=node.end_lineno, 

1214 end_col_offset=node.end_col_offset, 

1215 parent=parent, 

1216 ) 

1217 newnode.postinit( 

1218 self.visit(node.elt, newnode), 

1219 [self.visit(child, newnode) for child in node.generators], 

1220 ) 

1221 return newnode 

1222 

1223 def visit_attribute( 

1224 self, node: ast.Attribute, parent: nodes.NodeNG 

1225 ) -> nodes.Attribute | nodes.AssignAttr | nodes.DelAttr: 

1226 """Visit an Attribute node by returning a fresh instance of it.""" 

1227 context = self._get_context(node) 

1228 newnode: nodes.Attribute | nodes.AssignAttr | nodes.DelAttr 

1229 if context == Context.Del: 

1230 # FIXME : maybe we should reintroduce and visit_delattr ? 

1231 # for instance, deactivating assign_ctx 

1232 newnode = nodes.DelAttr( 

1233 attrname=node.attr, 

1234 lineno=node.lineno, 

1235 col_offset=node.col_offset, 

1236 end_lineno=node.end_lineno, 

1237 end_col_offset=node.end_col_offset, 

1238 parent=parent, 

1239 ) 

1240 elif context == Context.Store: 

1241 newnode = nodes.AssignAttr( 

1242 attrname=node.attr, 

1243 lineno=node.lineno, 

1244 col_offset=node.col_offset, 

1245 end_lineno=node.end_lineno, 

1246 end_col_offset=node.end_col_offset, 

1247 parent=parent, 

1248 ) 

1249 # Prohibit a local save if we are in an ExceptHandler. 

1250 if not isinstance(parent, nodes.ExceptHandler): 

1251 # mypy doesn't recognize that newnode has to be AssignAttr because it 

1252 # doesn't support ParamSpec 

1253 # See https://github.com/python/mypy/issues/8645 

1254 self._delayed_assattr.append(newnode) # type: ignore[arg-type] 

1255 else: 

1256 newnode = nodes.Attribute( 

1257 attrname=node.attr, 

1258 lineno=node.lineno, 

1259 col_offset=node.col_offset, 

1260 end_lineno=node.end_lineno, 

1261 end_col_offset=node.end_col_offset, 

1262 parent=parent, 

1263 ) 

1264 newnode.postinit(self.visit(node.value, newnode)) 

1265 return newnode 

1266 

1267 def visit_global(self, node: ast.Global, parent: nodes.NodeNG) -> nodes.Global: 

1268 """Visit a Global node to become astroid.""" 

1269 newnode = nodes.Global( 

1270 names=node.names, 

1271 lineno=node.lineno, 

1272 col_offset=node.col_offset, 

1273 end_lineno=node.end_lineno, 

1274 end_col_offset=node.end_col_offset, 

1275 parent=parent, 

1276 ) 

1277 if self._global_names: # global at the module level, no effect 

1278 for name in node.names: 

1279 self._global_names[-1].setdefault(name, []).append(newnode) 

1280 return newnode 

1281 

1282 def visit_if(self, node: ast.If, parent: nodes.NodeNG) -> nodes.If: 

1283 """Visit an If node by returning a fresh instance of it.""" 

1284 newnode = nodes.If( 

1285 lineno=node.lineno, 

1286 col_offset=node.col_offset, 

1287 end_lineno=node.end_lineno, 

1288 end_col_offset=node.end_col_offset, 

1289 parent=parent, 

1290 ) 

1291 newnode.postinit( 

1292 self.visit(node.test, newnode), 

1293 [self.visit(child, newnode) for child in node.body], 

1294 [self.visit(child, newnode) for child in node.orelse], 

1295 ) 

1296 return newnode 

1297 

1298 def visit_ifexp(self, node: ast.IfExp, parent: nodes.NodeNG) -> nodes.IfExp: 

1299 """Visit a IfExp node by returning a fresh instance of it.""" 

1300 newnode = nodes.IfExp( 

1301 lineno=node.lineno, 

1302 col_offset=node.col_offset, 

1303 end_lineno=node.end_lineno, 

1304 end_col_offset=node.end_col_offset, 

1305 parent=parent, 

1306 ) 

1307 newnode.postinit( 

1308 self.visit(node.test, newnode), 

1309 self.visit(node.body, newnode), 

1310 self.visit(node.orelse, newnode), 

1311 ) 

1312 return newnode 

1313 

1314 def visit_import(self, node: ast.Import, parent: nodes.NodeNG) -> nodes.Import: 

1315 """Visit a Import node by returning a fresh instance of it.""" 

1316 names = [(alias.name, alias.asname) for alias in node.names] 

1317 newnode = nodes.Import( 

1318 names=names, 

1319 lineno=node.lineno, 

1320 col_offset=node.col_offset, 

1321 end_lineno=node.end_lineno, 

1322 end_col_offset=node.end_col_offset, 

1323 parent=parent, 

1324 ) 

1325 # save import names in parent's locals: 

1326 for name, asname in newnode.names: 

1327 name = (asname or name).split(".")[0] 

1328 if self._global_names and name in self._global_names[-1]: 

1329 parent.root().set_local(name, newnode) 

1330 else: 

1331 parent.set_local(name, newnode) 

1332 return newnode 

1333 

1334 def visit_joinedstr( 

1335 self, node: ast.JoinedStr, parent: nodes.NodeNG 

1336 ) -> nodes.JoinedStr: 

1337 newnode = nodes.JoinedStr( 

1338 lineno=node.lineno, 

1339 col_offset=node.col_offset, 

1340 end_lineno=node.end_lineno, 

1341 end_col_offset=node.end_col_offset, 

1342 parent=parent, 

1343 ) 

1344 newnode.postinit([self.visit(child, newnode) for child in node.values]) 

1345 return newnode 

1346 

1347 def visit_formattedvalue( 

1348 self, node: ast.FormattedValue, parent: nodes.NodeNG 

1349 ) -> nodes.FormattedValue: 

1350 newnode = nodes.FormattedValue( 

1351 lineno=node.lineno, 

1352 col_offset=node.col_offset, 

1353 end_lineno=node.end_lineno, 

1354 end_col_offset=node.end_col_offset, 

1355 parent=parent, 

1356 ) 

1357 newnode.postinit( 

1358 value=self.visit(node.value, newnode), 

1359 conversion=node.conversion, 

1360 format_spec=self.visit(node.format_spec, newnode), 

1361 ) 

1362 return newnode 

1363 

1364 def visit_namedexpr( 

1365 self, node: ast.NamedExpr, parent: nodes.NodeNG 

1366 ) -> nodes.NamedExpr: 

1367 newnode = nodes.NamedExpr( 

1368 lineno=node.lineno, 

1369 col_offset=node.col_offset, 

1370 end_lineno=node.end_lineno, 

1371 end_col_offset=node.end_col_offset, 

1372 parent=parent, 

1373 ) 

1374 newnode.postinit( 

1375 self.visit(node.target, newnode), self.visit(node.value, newnode) 

1376 ) 

1377 return newnode 

1378 

1379 def visit_keyword(self, node: ast.keyword, parent: nodes.NodeNG) -> nodes.Keyword: 

1380 """Visit a Keyword node by returning a fresh instance of it.""" 

1381 newnode = nodes.Keyword( 

1382 arg=node.arg, 

1383 # position attributes added in 3.9 

1384 lineno=getattr(node, "lineno", None), 

1385 col_offset=getattr(node, "col_offset", None), 

1386 end_lineno=getattr(node, "end_lineno", None), 

1387 end_col_offset=getattr(node, "end_col_offset", None), 

1388 parent=parent, 

1389 ) 

1390 newnode.postinit(self.visit(node.value, newnode)) 

1391 return newnode 

1392 

1393 def visit_lambda(self, node: ast.Lambda, parent: nodes.NodeNG) -> nodes.Lambda: 

1394 """Visit a Lambda node by returning a fresh instance of it.""" 

1395 newnode = nodes.Lambda( 

1396 lineno=node.lineno, 

1397 col_offset=node.col_offset, 

1398 end_lineno=node.end_lineno, 

1399 end_col_offset=node.end_col_offset, 

1400 parent=parent, 

1401 ) 

1402 newnode.postinit(self.visit(node.args, newnode), self.visit(node.body, newnode)) 

1403 return newnode 

1404 

1405 def visit_list(self, node: ast.List, parent: nodes.NodeNG) -> nodes.List: 

1406 """Visit a List node by returning a fresh instance of it.""" 

1407 context = self._get_context(node) 

1408 newnode = nodes.List( 

1409 ctx=context, 

1410 lineno=node.lineno, 

1411 col_offset=node.col_offset, 

1412 end_lineno=node.end_lineno, 

1413 end_col_offset=node.end_col_offset, 

1414 parent=parent, 

1415 ) 

1416 newnode.postinit([self.visit(child, newnode) for child in node.elts]) 

1417 return newnode 

1418 

1419 def visit_listcomp( 

1420 self, node: ast.ListComp, parent: nodes.NodeNG 

1421 ) -> nodes.ListComp: 

1422 """Visit a ListComp node by returning a fresh instance of it.""" 

1423 newnode = nodes.ListComp( 

1424 lineno=node.lineno, 

1425 col_offset=node.col_offset, 

1426 end_lineno=node.end_lineno, 

1427 end_col_offset=node.end_col_offset, 

1428 parent=parent, 

1429 ) 

1430 newnode.postinit( 

1431 self.visit(node.elt, newnode), 

1432 [self.visit(child, newnode) for child in node.generators], 

1433 ) 

1434 return newnode 

1435 

1436 def visit_name( 

1437 self, node: ast.Name, parent: nodes.NodeNG 

1438 ) -> nodes.Name | nodes.AssignName | nodes.DelName: 

1439 """Visit a Name node by returning a fresh instance of it.""" 

1440 context = self._get_context(node) 

1441 newnode: nodes.Name | nodes.AssignName | nodes.DelName 

1442 if context == Context.Del: 

1443 newnode = nodes.DelName( 

1444 name=node.id, 

1445 lineno=node.lineno, 

1446 col_offset=node.col_offset, 

1447 end_lineno=node.end_lineno, 

1448 end_col_offset=node.end_col_offset, 

1449 parent=parent, 

1450 ) 

1451 elif context == Context.Store: 

1452 newnode = nodes.AssignName( 

1453 name=node.id, 

1454 lineno=node.lineno, 

1455 col_offset=node.col_offset, 

1456 end_lineno=node.end_lineno, 

1457 end_col_offset=node.end_col_offset, 

1458 parent=parent, 

1459 ) 

1460 else: 

1461 newnode = nodes.Name( 

1462 name=node.id, 

1463 lineno=node.lineno, 

1464 col_offset=node.col_offset, 

1465 end_lineno=node.end_lineno, 

1466 end_col_offset=node.end_col_offset, 

1467 parent=parent, 

1468 ) 

1469 # XXX REMOVE me : 

1470 if context in (Context.Del, Context.Store): # 'Aug' ?? 

1471 newnode = cast((nodes.AssignName | nodes.DelName), newnode) 

1472 self._save_assignment(newnode) 

1473 return newnode 

1474 

1475 def visit_nonlocal( 

1476 self, node: ast.Nonlocal, parent: nodes.NodeNG 

1477 ) -> nodes.Nonlocal: 

1478 """Visit a Nonlocal node and return a new instance of it.""" 

1479 return nodes.Nonlocal( 

1480 names=node.names, 

1481 lineno=node.lineno, 

1482 col_offset=node.col_offset, 

1483 end_lineno=node.end_lineno, 

1484 end_col_offset=node.end_col_offset, 

1485 parent=parent, 

1486 ) 

1487 

1488 def visit_constant(self, node: ast.Constant, parent: nodes.NodeNG) -> nodes.Const: 

1489 """Visit a Constant node by returning a fresh instance of Const.""" 

1490 return nodes.Const( 

1491 value=node.value, 

1492 kind=node.kind, 

1493 lineno=node.lineno, 

1494 col_offset=node.col_offset, 

1495 end_lineno=node.end_lineno, 

1496 end_col_offset=node.end_col_offset, 

1497 parent=parent, 

1498 ) 

1499 

1500 def visit_paramspec( 

1501 self, node: ast.ParamSpec, parent: nodes.NodeNG 

1502 ) -> nodes.ParamSpec: 

1503 """Visit a ParamSpec node by returning a fresh instance of it.""" 

1504 newnode = nodes.ParamSpec( 

1505 lineno=node.lineno, 

1506 col_offset=node.col_offset, 

1507 end_lineno=node.end_lineno, 

1508 end_col_offset=node.end_col_offset, 

1509 parent=parent, 

1510 ) 

1511 # Add AssignName node for 'node.name' 

1512 # https://bugs.python.org/issue43994 

1513 newnode.postinit( 

1514 name=self.visit_assignname(node, newnode, node.name), 

1515 default_value=( 

1516 self.visit(node.default_value, newnode) if PY313_PLUS else None 

1517 ), 

1518 ) 

1519 return newnode 

1520 

1521 def visit_pass(self, node: ast.Pass, parent: nodes.NodeNG) -> nodes.Pass: 

1522 """Visit a Pass node by returning a fresh instance of it.""" 

1523 return nodes.Pass( 

1524 lineno=node.lineno, 

1525 col_offset=node.col_offset, 

1526 end_lineno=node.end_lineno, 

1527 end_col_offset=node.end_col_offset, 

1528 parent=parent, 

1529 ) 

1530 

1531 def visit_raise(self, node: ast.Raise, parent: nodes.NodeNG) -> nodes.Raise: 

1532 """Visit a Raise node by returning a fresh instance of it.""" 

1533 newnode = nodes.Raise( 

1534 lineno=node.lineno, 

1535 col_offset=node.col_offset, 

1536 end_lineno=node.end_lineno, 

1537 end_col_offset=node.end_col_offset, 

1538 parent=parent, 

1539 ) 

1540 # no traceback; anyway it is not used in Pylint 

1541 newnode.postinit( 

1542 exc=self.visit(node.exc, newnode), 

1543 cause=self.visit(node.cause, newnode), 

1544 ) 

1545 return newnode 

1546 

1547 def visit_return(self, node: ast.Return, parent: nodes.NodeNG) -> nodes.Return: 

1548 """Visit a Return node by returning a fresh instance of it.""" 

1549 newnode = nodes.Return( 

1550 lineno=node.lineno, 

1551 col_offset=node.col_offset, 

1552 end_lineno=node.end_lineno, 

1553 end_col_offset=node.end_col_offset, 

1554 parent=parent, 

1555 ) 

1556 newnode.postinit(self.visit(node.value, newnode)) 

1557 return newnode 

1558 

1559 def visit_set(self, node: ast.Set, parent: nodes.NodeNG) -> nodes.Set: 

1560 """Visit a Set node by returning a fresh instance of it.""" 

1561 newnode = nodes.Set( 

1562 lineno=node.lineno, 

1563 col_offset=node.col_offset, 

1564 end_lineno=node.end_lineno, 

1565 end_col_offset=node.end_col_offset, 

1566 parent=parent, 

1567 ) 

1568 newnode.postinit([self.visit(child, newnode) for child in node.elts]) 

1569 return newnode 

1570 

1571 def visit_setcomp(self, node: ast.SetComp, parent: nodes.NodeNG) -> nodes.SetComp: 

1572 """Visit a SetComp node by returning a fresh instance of it.""" 

1573 newnode = nodes.SetComp( 

1574 lineno=node.lineno, 

1575 col_offset=node.col_offset, 

1576 end_lineno=node.end_lineno, 

1577 end_col_offset=node.end_col_offset, 

1578 parent=parent, 

1579 ) 

1580 newnode.postinit( 

1581 self.visit(node.elt, newnode), 

1582 [self.visit(child, newnode) for child in node.generators], 

1583 ) 

1584 return newnode 

1585 

1586 def visit_slice(self, node: ast.Slice, parent: nodes.Subscript) -> nodes.Slice: 

1587 """Visit a Slice node by returning a fresh instance of it.""" 

1588 newnode = nodes.Slice( 

1589 # position attributes added in 3.9 

1590 lineno=getattr(node, "lineno", None), 

1591 col_offset=getattr(node, "col_offset", None), 

1592 end_lineno=getattr(node, "end_lineno", None), 

1593 end_col_offset=getattr(node, "end_col_offset", None), 

1594 parent=parent, 

1595 ) 

1596 newnode.postinit( 

1597 lower=self.visit(node.lower, newnode), 

1598 upper=self.visit(node.upper, newnode), 

1599 step=self.visit(node.step, newnode), 

1600 ) 

1601 return newnode 

1602 

1603 def visit_subscript( 

1604 self, node: ast.Subscript, parent: nodes.NodeNG 

1605 ) -> nodes.Subscript: 

1606 """Visit a Subscript node by returning a fresh instance of it.""" 

1607 context = self._get_context(node) 

1608 newnode = nodes.Subscript( 

1609 ctx=context, 

1610 lineno=node.lineno, 

1611 col_offset=node.col_offset, 

1612 end_lineno=node.end_lineno, 

1613 end_col_offset=node.end_col_offset, 

1614 parent=parent, 

1615 ) 

1616 newnode.postinit( 

1617 self.visit(node.value, newnode), self.visit(node.slice, newnode) 

1618 ) 

1619 return newnode 

1620 

1621 def visit_starred(self, node: ast.Starred, parent: nodes.NodeNG) -> nodes.Starred: 

1622 """Visit a Starred node and return a new instance of it.""" 

1623 context = self._get_context(node) 

1624 newnode = nodes.Starred( 

1625 ctx=context, 

1626 lineno=node.lineno, 

1627 col_offset=node.col_offset, 

1628 end_lineno=node.end_lineno, 

1629 end_col_offset=node.end_col_offset, 

1630 parent=parent, 

1631 ) 

1632 newnode.postinit(self.visit(node.value, newnode)) 

1633 return newnode 

1634 

1635 def visit_try(self, node: ast.Try, parent: nodes.NodeNG) -> nodes.Try: 

1636 """Visit a Try node by returning a fresh instance of it""" 

1637 newnode = nodes.Try( 

1638 lineno=node.lineno, 

1639 col_offset=node.col_offset, 

1640 end_lineno=node.end_lineno, 

1641 end_col_offset=node.end_col_offset, 

1642 parent=parent, 

1643 ) 

1644 newnode.postinit( 

1645 body=[self.visit(child, newnode) for child in node.body], 

1646 handlers=[self.visit(child, newnode) for child in node.handlers], 

1647 orelse=[self.visit(child, newnode) for child in node.orelse], 

1648 finalbody=[self.visit(child, newnode) for child in node.finalbody], 

1649 ) 

1650 return newnode 

1651 

1652 def visit_trystar(self, node: ast.TryStar, parent: nodes.NodeNG) -> nodes.TryStar: 

1653 newnode = nodes.TryStar( 

1654 lineno=node.lineno, 

1655 col_offset=node.col_offset, 

1656 end_lineno=node.end_lineno, 

1657 end_col_offset=node.end_col_offset, 

1658 parent=parent, 

1659 ) 

1660 newnode.postinit( 

1661 body=[self.visit(n, newnode) for n in node.body], 

1662 handlers=[self.visit(n, newnode) for n in node.handlers], 

1663 orelse=[self.visit(n, newnode) for n in node.orelse], 

1664 finalbody=[self.visit(n, newnode) for n in node.finalbody], 

1665 ) 

1666 return newnode 

1667 

1668 def visit_tuple(self, node: ast.Tuple, parent: nodes.NodeNG) -> nodes.Tuple: 

1669 """Visit a Tuple node by returning a fresh instance of it.""" 

1670 context = self._get_context(node) 

1671 newnode = nodes.Tuple( 

1672 ctx=context, 

1673 lineno=node.lineno, 

1674 col_offset=node.col_offset, 

1675 end_lineno=node.end_lineno, 

1676 end_col_offset=node.end_col_offset, 

1677 parent=parent, 

1678 ) 

1679 newnode.postinit([self.visit(child, newnode) for child in node.elts]) 

1680 return newnode 

1681 

1682 def visit_typealias( 

1683 self, node: ast.TypeAlias, parent: nodes.NodeNG 

1684 ) -> nodes.TypeAlias: 

1685 """Visit a TypeAlias node by returning a fresh instance of it.""" 

1686 newnode = nodes.TypeAlias( 

1687 lineno=node.lineno, 

1688 col_offset=node.col_offset, 

1689 end_lineno=node.end_lineno, 

1690 end_col_offset=node.end_col_offset, 

1691 parent=parent, 

1692 ) 

1693 newnode.postinit( 

1694 name=self.visit(node.name, newnode), 

1695 type_params=[self.visit(p, newnode) for p in node.type_params], 

1696 value=self.visit(node.value, newnode), 

1697 ) 

1698 return newnode 

1699 

1700 def visit_typevar(self, node: ast.TypeVar, parent: nodes.NodeNG) -> nodes.TypeVar: 

1701 """Visit a TypeVar node by returning a fresh instance of it.""" 

1702 newnode = nodes.TypeVar( 

1703 lineno=node.lineno, 

1704 col_offset=node.col_offset, 

1705 end_lineno=node.end_lineno, 

1706 end_col_offset=node.end_col_offset, 

1707 parent=parent, 

1708 ) 

1709 # Add AssignName node for 'node.name' 

1710 # https://bugs.python.org/issue43994 

1711 newnode.postinit( 

1712 name=self.visit_assignname(node, newnode, node.name), 

1713 bound=self.visit(node.bound, newnode), 

1714 default_value=( 

1715 self.visit(node.default_value, newnode) if PY313_PLUS else None 

1716 ), 

1717 ) 

1718 return newnode 

1719 

1720 def visit_typevartuple( 

1721 self, node: ast.TypeVarTuple, parent: nodes.NodeNG 

1722 ) -> nodes.TypeVarTuple: 

1723 """Visit a TypeVarTuple node by returning a fresh instance of it.""" 

1724 newnode = nodes.TypeVarTuple( 

1725 lineno=node.lineno, 

1726 col_offset=node.col_offset, 

1727 end_lineno=node.end_lineno, 

1728 end_col_offset=node.end_col_offset, 

1729 parent=parent, 

1730 ) 

1731 # Add AssignName node for 'node.name' 

1732 # https://bugs.python.org/issue43994 

1733 newnode.postinit( 

1734 name=self.visit_assignname(node, newnode, node.name), 

1735 default_value=( 

1736 self.visit(node.default_value, newnode) if PY313_PLUS else None 

1737 ), 

1738 ) 

1739 return newnode 

1740 

1741 def visit_unaryop(self, node: ast.UnaryOp, parent: nodes.NodeNG) -> nodes.UnaryOp: 

1742 """Visit a UnaryOp node by returning a fresh instance of it.""" 

1743 newnode = nodes.UnaryOp( 

1744 op=self._parser_module.unary_op_classes[node.op.__class__], 

1745 lineno=node.lineno, 

1746 col_offset=node.col_offset, 

1747 end_lineno=node.end_lineno, 

1748 end_col_offset=node.end_col_offset, 

1749 parent=parent, 

1750 ) 

1751 newnode.postinit(self.visit(node.operand, newnode)) 

1752 return newnode 

1753 

1754 def visit_while(self, node: ast.While, parent: nodes.NodeNG) -> nodes.While: 

1755 """Visit a While node by returning a fresh instance of it.""" 

1756 newnode = nodes.While( 

1757 lineno=node.lineno, 

1758 col_offset=node.col_offset, 

1759 end_lineno=node.end_lineno, 

1760 end_col_offset=node.end_col_offset, 

1761 parent=parent, 

1762 ) 

1763 newnode.postinit( 

1764 self.visit(node.test, newnode), 

1765 [self.visit(child, newnode) for child in node.body], 

1766 [self.visit(child, newnode) for child in node.orelse], 

1767 ) 

1768 return newnode 

1769 

1770 @overload 

1771 def _visit_with( 

1772 self, cls: type[nodes.With], node: ast.With, parent: nodes.NodeNG 

1773 ) -> nodes.With: ... 

1774 

1775 @overload 

1776 def _visit_with( 

1777 self, cls: type[nodes.AsyncWith], node: ast.AsyncWith, parent: nodes.NodeNG 

1778 ) -> nodes.AsyncWith: ... 

1779 

1780 def _visit_with( 

1781 self, 

1782 cls: type[_WithT], 

1783 node: ast.With | ast.AsyncWith, 

1784 parent: nodes.NodeNG, 

1785 ) -> _WithT: 

1786 newnode = cls( 

1787 lineno=node.lineno, 

1788 col_offset=node.col_offset, 

1789 end_lineno=node.end_lineno, 

1790 end_col_offset=node.end_col_offset, 

1791 parent=parent, 

1792 ) 

1793 

1794 def visit_child( 

1795 child: ast.withitem, 

1796 ) -> tuple[nodes.NodeNG, nodes.NodeNG | None]: 

1797 expr = self.visit(child.context_expr, newnode) 

1798 var = self.visit(child.optional_vars, newnode) 

1799 return expr, var 

1800 

1801 type_annotation = self.check_type_comment(node, parent=newnode) 

1802 newnode.postinit( 

1803 items=[visit_child(child) for child in node.items], 

1804 body=[self.visit(child, newnode) for child in node.body], 

1805 type_annotation=type_annotation, 

1806 ) 

1807 return newnode 

1808 

1809 def visit_with(self, node: ast.With, parent: nodes.NodeNG) -> nodes.NodeNG: 

1810 return self._visit_with(nodes.With, node, parent) 

1811 

1812 def visit_yield(self, node: ast.Yield, parent: nodes.NodeNG) -> nodes.NodeNG: 

1813 """Visit a Yield node by returning a fresh instance of it.""" 

1814 newnode = nodes.Yield( 

1815 lineno=node.lineno, 

1816 col_offset=node.col_offset, 

1817 end_lineno=node.end_lineno, 

1818 end_col_offset=node.end_col_offset, 

1819 parent=parent, 

1820 ) 

1821 newnode.postinit(self.visit(node.value, newnode)) 

1822 return newnode 

1823 

1824 def visit_yieldfrom( 

1825 self, node: ast.YieldFrom, parent: nodes.NodeNG 

1826 ) -> nodes.NodeNG: 

1827 newnode = nodes.YieldFrom( 

1828 lineno=node.lineno, 

1829 col_offset=node.col_offset, 

1830 end_lineno=node.end_lineno, 

1831 end_col_offset=node.end_col_offset, 

1832 parent=parent, 

1833 ) 

1834 newnode.postinit(self.visit(node.value, newnode)) 

1835 return newnode 

1836 

1837 def visit_match(self, node: ast.Match, parent: nodes.NodeNG) -> nodes.Match: 

1838 newnode = nodes.Match( 

1839 lineno=node.lineno, 

1840 col_offset=node.col_offset, 

1841 end_lineno=node.end_lineno, 

1842 end_col_offset=node.end_col_offset, 

1843 parent=parent, 

1844 ) 

1845 newnode.postinit( 

1846 subject=self.visit(node.subject, newnode), 

1847 cases=[self.visit(case, newnode) for case in node.cases], 

1848 ) 

1849 return newnode 

1850 

1851 def visit_matchcase( 

1852 self, node: ast.match_case, parent: nodes.NodeNG 

1853 ) -> nodes.MatchCase: 

1854 newnode = nodes.MatchCase(parent=parent) 

1855 newnode.postinit( 

1856 pattern=self.visit(node.pattern, newnode), 

1857 guard=self.visit(node.guard, newnode), 

1858 body=[self.visit(child, newnode) for child in node.body], 

1859 ) 

1860 return newnode 

1861 

1862 def visit_matchvalue( 

1863 self, node: ast.MatchValue, parent: nodes.NodeNG 

1864 ) -> nodes.MatchValue: 

1865 newnode = nodes.MatchValue( 

1866 lineno=node.lineno, 

1867 col_offset=node.col_offset, 

1868 end_lineno=node.end_lineno, 

1869 end_col_offset=node.end_col_offset, 

1870 parent=parent, 

1871 ) 

1872 newnode.postinit(value=self.visit(node.value, newnode)) 

1873 return newnode 

1874 

1875 def visit_matchsingleton( 

1876 self, node: ast.MatchSingleton, parent: nodes.NodeNG 

1877 ) -> nodes.MatchSingleton: 

1878 return nodes.MatchSingleton( 

1879 value=node.value, 

1880 lineno=node.lineno, 

1881 col_offset=node.col_offset, 

1882 end_lineno=node.end_lineno, 

1883 end_col_offset=node.end_col_offset, 

1884 parent=parent, 

1885 ) 

1886 

1887 def visit_matchsequence( 

1888 self, node: ast.MatchSequence, parent: nodes.NodeNG 

1889 ) -> nodes.MatchSequence: 

1890 newnode = nodes.MatchSequence( 

1891 lineno=node.lineno, 

1892 col_offset=node.col_offset, 

1893 end_lineno=node.end_lineno, 

1894 end_col_offset=node.end_col_offset, 

1895 parent=parent, 

1896 ) 

1897 newnode.postinit( 

1898 patterns=[self.visit(pattern, newnode) for pattern in node.patterns] 

1899 ) 

1900 return newnode 

1901 

1902 def visit_matchmapping( 

1903 self, node: ast.MatchMapping, parent: nodes.NodeNG 

1904 ) -> nodes.MatchMapping: 

1905 newnode = nodes.MatchMapping( 

1906 lineno=node.lineno, 

1907 col_offset=node.col_offset, 

1908 end_lineno=node.end_lineno, 

1909 end_col_offset=node.end_col_offset, 

1910 parent=parent, 

1911 ) 

1912 # Add AssignName node for 'node.name' 

1913 # https://bugs.python.org/issue43994 

1914 newnode.postinit( 

1915 keys=[self.visit(child, newnode) for child in node.keys], 

1916 patterns=[self.visit(pattern, newnode) for pattern in node.patterns], 

1917 rest=self.visit_assignname(node, newnode, node.rest), 

1918 ) 

1919 return newnode 

1920 

1921 def visit_matchclass( 

1922 self, node: ast.MatchClass, parent: nodes.NodeNG 

1923 ) -> nodes.MatchClass: 

1924 newnode = nodes.MatchClass( 

1925 lineno=node.lineno, 

1926 col_offset=node.col_offset, 

1927 end_lineno=node.end_lineno, 

1928 end_col_offset=node.end_col_offset, 

1929 parent=parent, 

1930 ) 

1931 newnode.postinit( 

1932 cls=self.visit(node.cls, newnode), 

1933 patterns=[self.visit(pattern, newnode) for pattern in node.patterns], 

1934 kwd_attrs=node.kwd_attrs, 

1935 kwd_patterns=[ 

1936 self.visit(pattern, newnode) for pattern in node.kwd_patterns 

1937 ], 

1938 ) 

1939 return newnode 

1940 

1941 def visit_matchstar( 

1942 self, node: ast.MatchStar, parent: nodes.NodeNG 

1943 ) -> nodes.MatchStar: 

1944 newnode = nodes.MatchStar( 

1945 lineno=node.lineno, 

1946 col_offset=node.col_offset, 

1947 end_lineno=node.end_lineno, 

1948 end_col_offset=node.end_col_offset, 

1949 parent=parent, 

1950 ) 

1951 # Add AssignName node for 'node.name' 

1952 # https://bugs.python.org/issue43994 

1953 newnode.postinit(name=self.visit_assignname(node, newnode, node.name)) 

1954 return newnode 

1955 

1956 def visit_matchas(self, node: ast.MatchAs, parent: nodes.NodeNG) -> nodes.MatchAs: 

1957 newnode = nodes.MatchAs( 

1958 lineno=node.lineno, 

1959 col_offset=node.col_offset, 

1960 end_lineno=node.end_lineno, 

1961 end_col_offset=node.end_col_offset, 

1962 parent=parent, 

1963 ) 

1964 # Add AssignName node for 'node.name' 

1965 # https://bugs.python.org/issue43994 

1966 newnode.postinit( 

1967 pattern=self.visit(node.pattern, newnode), 

1968 name=self.visit_assignname(node, newnode, node.name), 

1969 ) 

1970 return newnode 

1971 

1972 def visit_matchor(self, node: ast.MatchOr, parent: nodes.NodeNG) -> nodes.MatchOr: 

1973 newnode = nodes.MatchOr( 

1974 lineno=node.lineno, 

1975 col_offset=node.col_offset, 

1976 end_lineno=node.end_lineno, 

1977 end_col_offset=node.end_col_offset, 

1978 parent=parent, 

1979 ) 

1980 newnode.postinit( 

1981 patterns=[self.visit(pattern, newnode) for pattern in node.patterns] 

1982 ) 

1983 return newnode 

1984 

1985 if sys.version_info >= (3, 14): 

1986 

1987 def visit_templatestr( 

1988 self, node: ast.TemplateStr, parent: nodes.NodeNG 

1989 ) -> nodes.TemplateStr: 

1990 newnode = nodes.TemplateStr( 

1991 lineno=node.lineno, 

1992 col_offset=node.col_offset, 

1993 end_lineno=node.end_lineno, 

1994 end_col_offset=node.end_col_offset, 

1995 parent=parent, 

1996 ) 

1997 newnode.postinit( 

1998 values=[self.visit(value, newnode) for value in node.values] 

1999 ) 

2000 return newnode 

2001 

2002 def visit_interpolation( 

2003 self, node: ast.Interpolation, parent: nodes.NodeNG 

2004 ) -> nodes.Interpolation: 

2005 newnode = nodes.Interpolation( 

2006 lineno=node.lineno, 

2007 col_offset=node.col_offset, 

2008 end_lineno=node.end_lineno, 

2009 end_col_offset=node.end_col_offset, 

2010 parent=parent, 

2011 ) 

2012 newnode.postinit( 

2013 value=self.visit(node.value, parent), 

2014 str=node.str, 

2015 conversion=node.conversion, 

2016 format_spec=self.visit(node.format_spec, parent), 

2017 ) 

2018 return newnode