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

699 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 ( 

22 BIN_OP_CLASSES, 

23 BOOL_OP_CLASSES, 

24 CMP_OP_CLASSES, 

25 CONTEXT_CLASSES, 

26 UNARY_OP_CLASSES, 

27 parse_function_type_comment, 

28) 

29from astroid.const import PY312_PLUS, PY313_PLUS, Context 

30from astroid.nodes.utils import Position 

31from astroid.typing import InferenceResult 

32 

33if TYPE_CHECKING: 

34 from astroid.manager import AstroidManager 

35 

36 T_Doc = TypeVar( 

37 "T_Doc", 

38 ast.Module, 

39 ast.ClassDef, 

40 ast.FunctionDef | ast.AsyncFunctionDef, 

41 ) 

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

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

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

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

46 

47 

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

49 "arguments": "Arguments", 

50 "comprehension": "Comprehension", 

51 "ListCompFor": "Comprehension", 

52 "GenExprFor": "Comprehension", 

53 "excepthandler": "ExceptHandler", 

54 "keyword": "Keyword", 

55 "match_case": "MatchCase", 

56} 

57 

58 

59# noinspection PyMethodMayBeStatic 

60class TreeRebuilder: 

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

62 

63 def __init__( 

64 self, 

65 manager: AstroidManager, 

66 data: str | None = None, 

67 ) -> None: 

68 self._manager = manager 

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

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

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

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

73 self._visit_meths: dict[ 

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

75 ] = {} 

76 

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

78 """Return the doc ast node.""" 

79 try: 

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

81 first_value = node.body[0].value 

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

83 first_value.value, str 

84 ): 

85 doc_ast_node = first_value 

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

87 return node, doc_ast_node 

88 except IndexError: 

89 pass # ast built from scratch 

90 return node, None 

91 

92 def _get_context( 

93 self, 

94 node: ( 

95 ast.Attribute 

96 | ast.List 

97 | ast.Name 

98 | ast.Subscript 

99 | ast.Starred 

100 | ast.Tuple 

101 ), 

102 ) -> Context: 

103 return CONTEXT_CLASSES.get(type(node.ctx), Context.Load) 

104 

105 def _get_position_info( 

106 self, 

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

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

109 ) -> Position | None: 

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

111 

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

113 and the class / function name. 

114 

115 >>> @decorator 

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

117 >>> ^^^^^^^^^^^^^^^^^^^ 

118 """ 

119 if not self._data: 

120 return None 

121 end_lineno = node.end_lineno 

122 if node.body: 

123 end_lineno = node.body[0].lineno 

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

125 

126 start_token: TokenInfo | None = None 

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

128 if isinstance(parent, nodes.AsyncFunctionDef): 

129 search_token = "async" 

130 elif isinstance(parent, nodes.FunctionDef): 

131 search_token = "def" 

132 else: 

133 search_token = "class" 

134 

135 try: 

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

137 if ( 

138 start_token is not None 

139 and t.type == token.NAME 

140 and t.string == node.name 

141 ): 

142 break 

143 if t.type in keyword_tokens: 

144 if t.string == search_token: 

145 start_token = t 

146 continue 

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

148 continue 

149 start_token = None 

150 else: 

151 return None 

152 except (TokenError, SyntaxError): 

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

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

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

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

157 # line numbers; no position info then. 

158 return None 

159 

160 return Position( 

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

162 col_offset=start_token.start[1], 

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

164 end_col_offset=t.end[1], 

165 ) 

166 

167 def visit_module( 

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

169 ) -> nodes.Module: 

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

171 

172 Note: Method not called by 'visit' 

173 """ 

174 node, doc_ast_node = self._get_doc(node) 

175 newnode = nodes.Module( 

176 name=modname, 

177 file=modpath, 

178 path=[modpath], 

179 package=package, 

180 ) 

181 newnode.postinit( 

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

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

184 ) 

185 return newnode 

186 

187 if TYPE_CHECKING: # noqa: C901 

188 

189 @overload 

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

191 

192 @overload 

193 def visit( 

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

195 ) -> nodes.Arguments: ... 

196 

197 @overload 

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

199 

200 @overload 

201 def visit( 

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

203 ) -> nodes.AsyncFunctionDef: ... 

204 

205 @overload 

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

207 

208 @overload 

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

210 

211 @overload 

212 def visit( 

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

214 ) -> nodes.AsyncWith: ... 

215 

216 @overload 

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

218 

219 @overload 

220 def visit( 

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

222 ) -> nodes.AnnAssign: ... 

223 

224 @overload 

225 def visit( 

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

227 ) -> nodes.AugAssign: ... 

228 

229 @overload 

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

231 

232 @overload 

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

234 

235 @overload 

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

237 

238 @overload 

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

240 

241 @overload 

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

243 

244 @overload 

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

246 

247 @overload 

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

249 

250 @overload 

251 def visit( 

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

253 ) -> nodes.Comprehension: ... 

254 

255 @overload 

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

257 

258 @overload 

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

260 

261 @overload 

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

263 

264 @overload 

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

266 

267 @overload 

268 def visit( 

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

270 ) -> nodes.ExceptHandler: ... 

271 

272 @overload 

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

274 

275 @overload 

276 def visit( 

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

278 ) -> nodes.ImportFrom: ... 

279 

280 @overload 

281 def visit( 

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

283 ) -> nodes.FunctionDef: ... 

284 

285 @overload 

286 def visit( 

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

288 ) -> nodes.GeneratorExp: ... 

289 

290 @overload 

291 def visit( 

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

293 ) -> nodes.Attribute: ... 

294 

295 @overload 

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

297 

298 @overload 

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

300 

301 @overload 

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

303 

304 @overload 

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

306 

307 @overload 

308 def visit( 

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

310 ) -> nodes.JoinedStr: ... 

311 

312 @overload 

313 def visit( 

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

315 ) -> nodes.FormattedValue: ... 

316 

317 @overload 

318 def visit( 

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

320 ) -> nodes.NamedExpr: ... 

321 

322 @overload 

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

324 

325 @overload 

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

327 

328 @overload 

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

330 

331 @overload 

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

333 

334 @overload 

335 def visit( 

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

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

338 

339 @overload 

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

341 

342 @overload 

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

344 

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

346 

347 @overload 

348 def visit( 

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

350 ) -> nodes.ParamSpec: ... 

351 

352 @overload 

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

354 

355 @overload 

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

357 

358 @overload 

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

360 

361 @overload 

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

363 

364 @overload 

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

366 

367 @overload 

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

369 

370 @overload 

371 def visit( 

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

373 ) -> nodes.Subscript: ... 

374 

375 @overload 

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

377 

378 @overload 

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

380 

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

382 

383 @overload 

384 def visit( 

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

386 ) -> nodes.TryStar: ... 

387 

388 @overload 

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

390 

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

392 

393 @overload 

394 def visit( 

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

396 ) -> nodes.TypeAlias: ... 

397 

398 @overload 

399 def visit( 

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

401 ) -> nodes.TypeVar: ... 

402 

403 @overload 

404 def visit( 

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

406 ) -> nodes.TypeVarTuple: ... 

407 

408 @overload 

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

410 

411 @overload 

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

413 

414 @overload 

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

416 

417 @overload 

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

419 

420 @overload 

421 def visit( 

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

423 ) -> nodes.YieldFrom: ... 

424 

425 @overload 

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

427 

428 @overload 

429 def visit( 

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

431 ) -> nodes.MatchCase: ... 

432 

433 @overload 

434 def visit( 

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

436 ) -> nodes.MatchValue: ... 

437 

438 @overload 

439 def visit( 

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

441 ) -> nodes.MatchSingleton: ... 

442 

443 @overload 

444 def visit( 

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

446 ) -> nodes.MatchSequence: ... 

447 

448 @overload 

449 def visit( 

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

451 ) -> nodes.MatchMapping: ... 

452 

453 @overload 

454 def visit( 

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

456 ) -> nodes.MatchClass: ... 

457 

458 @overload 

459 def visit( 

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

461 ) -> nodes.MatchStar: ... 

462 

463 @overload 

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

465 

466 @overload 

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

468 

469 @overload 

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

471 

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

473 

474 @overload 

475 def visit( 

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

477 ) -> nodes.TemplateStr: ... 

478 

479 @overload 

480 def visit( 

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

482 ) -> nodes.Interpolation: ... 

483 

484 @overload 

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

486 

487 @overload 

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

489 

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

491 if node is None: 

492 return None 

493 cls = node.__class__ 

494 if cls in self._visit_meths: 

495 visit_method = self._visit_meths[cls] 

496 else: 

497 cls_name = cls.__name__ 

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

499 visit_method = getattr(self, visit_name) 

500 self._visit_meths[cls] = visit_method 

501 return visit_method(node, parent) 

502 

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

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

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

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

507 else: 

508 assert node.parent 

509 assert node.name 

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

511 

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

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

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

515 

516 def visit_arguments( 

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

518 ) -> nodes.Arguments: 

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

520 vararg: str | None = None 

521 kwarg: str | None = None 

522 vararg_node = node.vararg 

523 kwarg_node = node.kwarg 

524 

525 newnode = nodes.Arguments( 

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

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

528 parent, 

529 ( 

530 nodes.AssignName( 

531 vararg_node.arg, 

532 vararg_node.lineno, 

533 vararg_node.col_offset, 

534 parent, 

535 end_lineno=vararg_node.end_lineno, 

536 end_col_offset=vararg_node.end_col_offset, 

537 ) 

538 if vararg_node 

539 else None 

540 ), 

541 ( 

542 nodes.AssignName( 

543 kwarg_node.arg, 

544 kwarg_node.lineno, 

545 kwarg_node.col_offset, 

546 parent, 

547 end_lineno=kwarg_node.end_lineno, 

548 end_col_offset=kwarg_node.end_col_offset, 

549 ) 

550 if kwarg_node 

551 else None 

552 ), 

553 ) 

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

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

556 varargannotation: nodes.NodeNG | None = None 

557 kwargannotation: nodes.NodeNG | None = None 

558 if node.vararg: 

559 vararg = node.vararg.arg 

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

561 if node.kwarg: 

562 kwarg = node.kwarg.arg 

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

564 

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

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

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

568 kwonlyargs_annotations = [ 

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

570 ] 

571 

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

573 posonlyargs_annotations = [ 

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

575 ] 

576 type_comment_args = [ 

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

578 ] 

579 type_comment_kwonlyargs = [ 

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

581 ] 

582 type_comment_posonlyargs = [ 

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

584 ] 

585 

586 newnode.postinit( 

587 args=args, 

588 defaults=defaults, 

589 kwonlyargs=kwonlyargs, 

590 posonlyargs=posonlyargs, 

591 kw_defaults=kw_defaults, 

592 annotations=annotations, 

593 kwonlyargs_annotations=kwonlyargs_annotations, 

594 posonlyargs_annotations=posonlyargs_annotations, 

595 varargannotation=varargannotation, 

596 kwargannotation=kwargannotation, 

597 type_comment_args=type_comment_args, 

598 type_comment_kwonlyargs=type_comment_kwonlyargs, 

599 type_comment_posonlyargs=type_comment_posonlyargs, 

600 ) 

601 if start_end_lineno_pairs := [ 

602 (arg.lineno, arg.end_lineno) 

603 for arg in itertools.chain( 

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

605 ) 

606 if arg 

607 ]: 

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

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

610 

611 # save argument names in locals: 

612 assert newnode.parent 

613 if vararg: 

614 newnode.parent.set_local(vararg, newnode) 

615 if kwarg: 

616 newnode.parent.set_local(kwarg, newnode) 

617 return newnode 

618 

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

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

621 newnode = nodes.Assert( 

622 lineno=node.lineno, 

623 col_offset=node.col_offset, 

624 end_lineno=node.end_lineno, 

625 end_col_offset=node.end_col_offset, 

626 parent=parent, 

627 ) 

628 msg: nodes.NodeNG | None = None 

629 if node.msg: 

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

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

632 return newnode 

633 

634 def check_type_comment( 

635 self, 

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

637 parent: ( 

638 nodes.Assign 

639 | nodes.Arguments 

640 | nodes.For 

641 | nodes.AsyncFor 

642 | nodes.With 

643 | nodes.AsyncWith 

644 ), 

645 ) -> nodes.NodeNG | None: 

646 if not node.type_comment: 

647 return None 

648 

649 try: 

650 type_comment_ast = ast.parse(node.type_comment, type_comments=True) 

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

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

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

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

655 return None 

656 

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

658 # without any nodes in the body. 

659 if not type_comment_ast.body: 

660 return None 

661 

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

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

664 return None 

665 

666 return type_object.value 

667 

668 def check_function_type_comment( 

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

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

671 if not node.type_comment: 

672 return None 

673 

674 try: 

675 type_comment_ast = parse_function_type_comment(node.type_comment) 

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

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

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

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

680 return None 

681 

682 if not type_comment_ast: 

683 return None 

684 

685 returns: nodes.NodeNG | None = None 

686 argtypes: list[nodes.NodeNG] = [ 

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

688 ] 

689 if type_comment_ast.returns: 

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

691 

692 return returns, argtypes 

693 

694 def visit_asyncfunctiondef( 

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

696 ) -> nodes.AsyncFunctionDef: 

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

698 

699 def visit_asyncfor( 

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

701 ) -> nodes.AsyncFor: 

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

703 

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

705 newnode = nodes.Await( 

706 lineno=node.lineno, 

707 col_offset=node.col_offset, 

708 end_lineno=node.end_lineno, 

709 end_col_offset=node.end_col_offset, 

710 parent=parent, 

711 ) 

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

713 return newnode 

714 

715 def visit_asyncwith( 

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

717 ) -> nodes.AsyncWith: 

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

719 

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

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

722 newnode = nodes.Assign( 

723 lineno=node.lineno, 

724 col_offset=node.col_offset, 

725 end_lineno=node.end_lineno, 

726 end_col_offset=node.end_col_offset, 

727 parent=parent, 

728 ) 

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

730 newnode.postinit( 

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

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

733 type_annotation=type_annotation, 

734 ) 

735 return newnode 

736 

737 def visit_annassign( 

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

739 ) -> nodes.AnnAssign: 

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

741 newnode = nodes.AnnAssign( 

742 lineno=node.lineno, 

743 col_offset=node.col_offset, 

744 end_lineno=node.end_lineno, 

745 end_col_offset=node.end_col_offset, 

746 parent=parent, 

747 ) 

748 newnode.postinit( 

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

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

751 simple=node.simple, 

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

753 ) 

754 return newnode 

755 

756 @overload 

757 def visit_assignname( 

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

759 ) -> nodes.AssignName: ... 

760 

761 @overload 

762 def visit_assignname( 

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

764 ) -> None: ... 

765 

766 def visit_assignname( 

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

768 ) -> nodes.AssignName | None: 

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

770 

771 Note: Method not called by 'visit' 

772 """ 

773 if node_name is None: 

774 return None 

775 newnode = nodes.AssignName( 

776 name=node_name, 

777 lineno=node.lineno, 

778 col_offset=node.col_offset, 

779 end_lineno=node.end_lineno, 

780 end_col_offset=node.end_col_offset, 

781 parent=parent, 

782 ) 

783 self._save_assignment(newnode) 

784 return newnode 

785 

786 def visit_augassign( 

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

788 ) -> nodes.AugAssign: 

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

790 newnode = nodes.AugAssign( 

791 op=BIN_OP_CLASSES[type(node.op)] + "=", 

792 lineno=node.lineno, 

793 col_offset=node.col_offset, 

794 end_lineno=node.end_lineno, 

795 end_col_offset=node.end_col_offset, 

796 parent=parent, 

797 ) 

798 newnode.postinit( 

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

800 ) 

801 return newnode 

802 

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

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

805 newnode = nodes.BinOp( 

806 op=BIN_OP_CLASSES[type(node.op)], 

807 lineno=node.lineno, 

808 col_offset=node.col_offset, 

809 end_lineno=node.end_lineno, 

810 end_col_offset=node.end_col_offset, 

811 parent=parent, 

812 ) 

813 newnode.postinit( 

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

815 ) 

816 return newnode 

817 

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

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

820 newnode = nodes.BoolOp( 

821 op=BOOL_OP_CLASSES[type(node.op)], 

822 lineno=node.lineno, 

823 col_offset=node.col_offset, 

824 end_lineno=node.end_lineno, 

825 end_col_offset=node.end_col_offset, 

826 parent=parent, 

827 ) 

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

829 return newnode 

830 

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

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

833 return nodes.Break( 

834 lineno=node.lineno, 

835 col_offset=node.col_offset, 

836 end_lineno=node.end_lineno, 

837 end_col_offset=node.end_col_offset, 

838 parent=parent, 

839 ) 

840 

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

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

843 newnode = nodes.Call( 

844 lineno=node.lineno, 

845 col_offset=node.col_offset, 

846 end_lineno=node.end_lineno, 

847 end_col_offset=node.end_col_offset, 

848 parent=parent, 

849 ) 

850 newnode.postinit( 

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

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

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

854 ) 

855 return newnode 

856 

857 def visit_classdef( 

858 self, node: ast.ClassDef, parent: nodes.NodeNG 

859 ) -> nodes.ClassDef: 

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

861 node, doc_ast_node = self._get_doc(node) 

862 newnode = nodes.ClassDef( 

863 name=node.name, 

864 lineno=node.lineno, 

865 col_offset=node.col_offset, 

866 end_lineno=node.end_lineno, 

867 end_col_offset=node.end_col_offset, 

868 parent=parent, 

869 ) 

870 metaclass = None 

871 for keyword in node.keywords: 

872 if keyword.arg == "metaclass": 

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

874 break 

875 decorators = self.visit_decorators(node, newnode) 

876 newnode.postinit( 

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

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

879 decorators, 

880 metaclass=metaclass, 

881 keywords=[ 

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 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 lineno = node.decorator_list[0].lineno 

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

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

968 

969 newnode = nodes.Decorators( 

970 lineno=lineno, 

971 col_offset=node.col_offset, 

972 end_lineno=end_lineno, 

973 end_col_offset=end_col_offset, 

974 parent=parent, 

975 ) 

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

977 return newnode 

978 

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

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

981 newnode = nodes.Delete( 

982 lineno=node.lineno, 

983 col_offset=node.col_offset, 

984 end_lineno=node.end_lineno, 

985 end_col_offset=node.end_col_offset, 

986 parent=parent, 

987 ) 

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

989 return newnode 

990 

991 def _visit_dict_items( 

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

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

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

995 rebuilt_key: nodes.NodeNG 

996 rebuilt_value = self.visit(value, newnode) 

997 if not key: 

998 # Extended unpacking 

999 rebuilt_key = nodes.DictUnpack( 

1000 lineno=rebuilt_value.lineno, 

1001 col_offset=rebuilt_value.col_offset, 

1002 end_lineno=rebuilt_value.end_lineno, 

1003 end_col_offset=rebuilt_value.end_col_offset, 

1004 parent=parent, 

1005 ) 

1006 else: 

1007 rebuilt_key = self.visit(key, newnode) 

1008 yield rebuilt_key, rebuilt_value 

1009 

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

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

1012 newnode = nodes.Dict( 

1013 lineno=node.lineno, 

1014 col_offset=node.col_offset, 

1015 end_lineno=node.end_lineno, 

1016 end_col_offset=node.end_col_offset, 

1017 parent=parent, 

1018 ) 

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

1020 self._visit_dict_items(node, parent, newnode) 

1021 ) 

1022 newnode.postinit(items) 

1023 return newnode 

1024 

1025 def visit_dictcomp( 

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

1027 ) -> nodes.DictComp: 

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

1029 newnode = nodes.DictComp( 

1030 lineno=node.lineno, 

1031 col_offset=node.col_offset, 

1032 end_lineno=node.end_lineno, 

1033 end_col_offset=node.end_col_offset, 

1034 parent=parent, 

1035 ) 

1036 key: nodes.NodeNG 

1037 if node.value is None: 

1038 # PEP 798 dict-comprehension unpacking, e.g. ``{**d for d in dicts}``. 

1039 # CPython stores the unpacked mapping in ``key`` and leaves 

1040 # ``value`` as ``None``. Mirror the ``ast.Dict`` representation of 

1041 # ``{**d}``: a ``DictUnpack`` key together with the real value. 

1042 value = self.visit(node.key, newnode) 

1043 key = nodes.DictUnpack( 

1044 lineno=value.lineno, 

1045 col_offset=value.col_offset, 

1046 end_lineno=value.end_lineno, 

1047 end_col_offset=value.end_col_offset, 

1048 parent=newnode, 

1049 ) 

1050 else: 

1051 key = self.visit(node.key, newnode) 

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

1053 newnode.postinit( 

1054 key, 

1055 value, 

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

1057 ) 

1058 return newnode 

1059 

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

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

1062 newnode = nodes.Expr( 

1063 lineno=node.lineno, 

1064 col_offset=node.col_offset, 

1065 end_lineno=node.end_lineno, 

1066 end_col_offset=node.end_col_offset, 

1067 parent=parent, 

1068 ) 

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

1070 return newnode 

1071 

1072 def visit_excepthandler( 

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

1074 ) -> nodes.ExceptHandler: 

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

1076 newnode = nodes.ExceptHandler( 

1077 lineno=node.lineno, 

1078 col_offset=node.col_offset, 

1079 end_lineno=node.end_lineno, 

1080 end_col_offset=node.end_col_offset, 

1081 parent=parent, 

1082 ) 

1083 newnode.postinit( 

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

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

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

1087 ) 

1088 return newnode 

1089 

1090 @overload 

1091 def _visit_for( 

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

1093 ) -> nodes.For: ... 

1094 

1095 @overload 

1096 def _visit_for( 

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

1098 ) -> nodes.AsyncFor: ... 

1099 

1100 def _visit_for( 

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

1102 ) -> _ForT: 

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

1104 newnode = cls( 

1105 lineno=node.lineno, 

1106 col_offset=node.col_offset, 

1107 end_lineno=node.end_lineno, 

1108 end_col_offset=node.end_col_offset, 

1109 parent=parent, 

1110 ) 

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

1112 newnode.postinit( 

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

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

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

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

1117 type_annotation=type_annotation, 

1118 ) 

1119 return newnode 

1120 

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

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

1123 

1124 def visit_importfrom( 

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

1126 ) -> nodes.ImportFrom: 

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

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

1129 newnode = nodes.ImportFrom( 

1130 fromname=node.module or "", 

1131 names=names, 

1132 level=node.level or None, 

1133 lineno=node.lineno, 

1134 col_offset=node.col_offset, 

1135 end_lineno=node.end_lineno, 

1136 end_col_offset=node.end_col_offset, 

1137 parent=parent, 

1138 is_lazy=node.is_lazy if sys.version_info >= (3, 15) else 0, 

1139 ) 

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

1141 self._import_from_nodes.append( 

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

1143 ) 

1144 return newnode 

1145 

1146 @overload 

1147 def _visit_functiondef( 

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

1149 ) -> nodes.FunctionDef: ... 

1150 

1151 @overload 

1152 def _visit_functiondef( 

1153 self, 

1154 cls: type[nodes.AsyncFunctionDef], 

1155 node: ast.AsyncFunctionDef, 

1156 parent: nodes.NodeNG, 

1157 ) -> nodes.AsyncFunctionDef: ... 

1158 

1159 def _visit_functiondef( 

1160 self, 

1161 cls: type[_FunctionT], 

1162 node: ast.FunctionDef | ast.AsyncFunctionDef, 

1163 parent: nodes.NodeNG, 

1164 ) -> _FunctionT: 

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

1166 self._global_names.append({}) 

1167 node, doc_ast_node = self._get_doc(node) 

1168 

1169 lineno = node.lineno 

1170 if node.decorator_list: 

1171 # The ast parser of python < 3.8 incorrectly set the line number of 

1172 # a decorated function to the line of its first decorator. 

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

1174 # first decorator to maintain backward compatibility. 

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

1176 # the framework for *years*. 

1177 lineno = node.decorator_list[0].lineno 

1178 

1179 newnode = cls( 

1180 name=node.name, 

1181 lineno=lineno, 

1182 col_offset=node.col_offset, 

1183 end_lineno=node.end_lineno, 

1184 end_col_offset=node.end_col_offset, 

1185 parent=parent, 

1186 ) 

1187 decorators = self.visit_decorators(node, newnode) 

1188 returns: nodes.NodeNG | None 

1189 if node.returns: 

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

1191 else: 

1192 returns = None 

1193 

1194 type_comment_args = type_comment_returns = None 

1195 type_comment_annotation = self.check_function_type_comment(node, newnode) 

1196 if type_comment_annotation: 

1197 type_comment_returns, type_comment_args = type_comment_annotation 

1198 newnode.postinit( 

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

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

1201 decorators=decorators, 

1202 returns=returns, 

1203 type_comment_returns=type_comment_returns, 

1204 type_comment_args=type_comment_args, 

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

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

1207 type_params=( 

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

1209 if PY312_PLUS 

1210 else [] 

1211 ), 

1212 ) 

1213 self._global_names.pop() 

1214 parent.set_local(newnode.name, newnode) 

1215 return newnode 

1216 

1217 def visit_functiondef( 

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

1219 ) -> nodes.FunctionDef: 

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

1221 

1222 def visit_generatorexp( 

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

1224 ) -> nodes.GeneratorExp: 

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

1226 newnode = nodes.GeneratorExp( 

1227 lineno=node.lineno, 

1228 col_offset=node.col_offset, 

1229 end_lineno=node.end_lineno, 

1230 end_col_offset=node.end_col_offset, 

1231 parent=parent, 

1232 ) 

1233 newnode.postinit( 

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

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

1236 ) 

1237 return newnode 

1238 

1239 def visit_attribute( 

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

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

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

1243 context = self._get_context(node) 

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

1245 if context == Context.Del: 

1246 # FIXME : maybe we should reintroduce and visit_delattr ? 

1247 # for instance, deactivating assign_ctx 

1248 newnode = nodes.DelAttr( 

1249 attrname=node.attr, 

1250 lineno=node.lineno, 

1251 col_offset=node.col_offset, 

1252 end_lineno=node.end_lineno, 

1253 end_col_offset=node.end_col_offset, 

1254 parent=parent, 

1255 ) 

1256 elif context == Context.Store: 

1257 newnode = nodes.AssignAttr( 

1258 attrname=node.attr, 

1259 lineno=node.lineno, 

1260 col_offset=node.col_offset, 

1261 end_lineno=node.end_lineno, 

1262 end_col_offset=node.end_col_offset, 

1263 parent=parent, 

1264 ) 

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

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

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

1268 # doesn't support ParamSpec 

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

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

1271 else: 

1272 newnode = nodes.Attribute( 

1273 attrname=node.attr, 

1274 lineno=node.lineno, 

1275 col_offset=node.col_offset, 

1276 end_lineno=node.end_lineno, 

1277 end_col_offset=node.end_col_offset, 

1278 parent=parent, 

1279 ) 

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

1281 return newnode 

1282 

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

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

1285 newnode = nodes.Global( 

1286 names=node.names, 

1287 lineno=node.lineno, 

1288 col_offset=node.col_offset, 

1289 end_lineno=node.end_lineno, 

1290 end_col_offset=node.end_col_offset, 

1291 parent=parent, 

1292 ) 

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

1294 for name in node.names: 

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

1296 return newnode 

1297 

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

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

1300 newnode = nodes.If( 

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(child, newnode) for child in node.body], 

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

1311 ) 

1312 return newnode 

1313 

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

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

1316 newnode = nodes.IfExp( 

1317 lineno=node.lineno, 

1318 col_offset=node.col_offset, 

1319 end_lineno=node.end_lineno, 

1320 end_col_offset=node.end_col_offset, 

1321 parent=parent, 

1322 ) 

1323 newnode.postinit( 

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

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

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

1327 ) 

1328 return newnode 

1329 

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

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

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

1333 newnode = nodes.Import( 

1334 names=names, 

1335 lineno=node.lineno, 

1336 col_offset=node.col_offset, 

1337 end_lineno=node.end_lineno, 

1338 end_col_offset=node.end_col_offset, 

1339 parent=parent, 

1340 is_lazy=node.is_lazy if sys.version_info >= (3, 15) else 0, 

1341 ) 

1342 # save import names in parent's locals: 

1343 for name, asname in newnode.names: 

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

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

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

1347 else: 

1348 parent.set_local(name, newnode) 

1349 return newnode 

1350 

1351 def visit_joinedstr( 

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

1353 ) -> nodes.JoinedStr: 

1354 newnode = nodes.JoinedStr( 

1355 lineno=node.lineno, 

1356 col_offset=node.col_offset, 

1357 end_lineno=node.end_lineno, 

1358 end_col_offset=node.end_col_offset, 

1359 parent=parent, 

1360 ) 

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

1362 return newnode 

1363 

1364 def visit_formattedvalue( 

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

1366 ) -> nodes.FormattedValue: 

1367 newnode = nodes.FormattedValue( 

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 value=self.visit(node.value, newnode), 

1376 conversion=node.conversion, 

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

1378 ) 

1379 return newnode 

1380 

1381 def visit_namedexpr( 

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

1383 ) -> nodes.NamedExpr: 

1384 newnode = nodes.NamedExpr( 

1385 lineno=node.lineno, 

1386 col_offset=node.col_offset, 

1387 end_lineno=node.end_lineno, 

1388 end_col_offset=node.end_col_offset, 

1389 parent=parent, 

1390 ) 

1391 newnode.postinit( 

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

1393 ) 

1394 return newnode 

1395 

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

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

1398 newnode = nodes.Keyword( 

1399 arg=node.arg, 

1400 lineno=node.lineno, 

1401 col_offset=node.col_offset, 

1402 end_lineno=node.end_lineno, 

1403 end_col_offset=node.end_col_offset, 

1404 parent=parent, 

1405 ) 

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

1407 return newnode 

1408 

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

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

1411 newnode = nodes.Lambda( 

1412 lineno=node.lineno, 

1413 col_offset=node.col_offset, 

1414 end_lineno=node.end_lineno, 

1415 end_col_offset=node.end_col_offset, 

1416 parent=parent, 

1417 ) 

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

1419 return newnode 

1420 

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

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

1423 context = self._get_context(node) 

1424 newnode = nodes.List( 

1425 ctx=context, 

1426 lineno=node.lineno, 

1427 col_offset=node.col_offset, 

1428 end_lineno=node.end_lineno, 

1429 end_col_offset=node.end_col_offset, 

1430 parent=parent, 

1431 ) 

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

1433 return newnode 

1434 

1435 def visit_listcomp( 

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

1437 ) -> nodes.ListComp: 

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

1439 newnode = nodes.ListComp( 

1440 lineno=node.lineno, 

1441 col_offset=node.col_offset, 

1442 end_lineno=node.end_lineno, 

1443 end_col_offset=node.end_col_offset, 

1444 parent=parent, 

1445 ) 

1446 newnode.postinit( 

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

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

1449 ) 

1450 return newnode 

1451 

1452 def visit_name( 

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

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

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

1456 context = self._get_context(node) 

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

1458 if context == Context.Del: 

1459 newnode = nodes.DelName( 

1460 name=node.id, 

1461 lineno=node.lineno, 

1462 col_offset=node.col_offset, 

1463 end_lineno=node.end_lineno, 

1464 end_col_offset=node.end_col_offset, 

1465 parent=parent, 

1466 ) 

1467 elif context == Context.Store: 

1468 newnode = nodes.AssignName( 

1469 name=node.id, 

1470 lineno=node.lineno, 

1471 col_offset=node.col_offset, 

1472 end_lineno=node.end_lineno, 

1473 end_col_offset=node.end_col_offset, 

1474 parent=parent, 

1475 ) 

1476 else: 

1477 newnode = nodes.Name( 

1478 name=node.id, 

1479 lineno=node.lineno, 

1480 col_offset=node.col_offset, 

1481 end_lineno=node.end_lineno, 

1482 end_col_offset=node.end_col_offset, 

1483 parent=parent, 

1484 ) 

1485 # XXX REMOVE me : 

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

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

1488 self._save_assignment(newnode) 

1489 return newnode 

1490 

1491 def visit_nonlocal( 

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

1493 ) -> nodes.Nonlocal: 

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

1495 return nodes.Nonlocal( 

1496 names=node.names, 

1497 lineno=node.lineno, 

1498 col_offset=node.col_offset, 

1499 end_lineno=node.end_lineno, 

1500 end_col_offset=node.end_col_offset, 

1501 parent=parent, 

1502 ) 

1503 

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

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

1506 return nodes.Const( 

1507 value=node.value, 

1508 kind=node.kind, 

1509 lineno=node.lineno, 

1510 col_offset=node.col_offset, 

1511 end_lineno=node.end_lineno, 

1512 end_col_offset=node.end_col_offset, 

1513 parent=parent, 

1514 ) 

1515 

1516 def visit_paramspec( 

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

1518 ) -> nodes.ParamSpec: 

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

1520 newnode = nodes.ParamSpec( 

1521 lineno=node.lineno, 

1522 col_offset=node.col_offset, 

1523 end_lineno=node.end_lineno, 

1524 end_col_offset=node.end_col_offset, 

1525 parent=parent, 

1526 ) 

1527 # Add AssignName node for 'node.name' 

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

1529 newnode.postinit( 

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

1531 default_value=( 

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

1533 ), 

1534 ) 

1535 return newnode 

1536 

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

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

1539 return nodes.Pass( 

1540 lineno=node.lineno, 

1541 col_offset=node.col_offset, 

1542 end_lineno=node.end_lineno, 

1543 end_col_offset=node.end_col_offset, 

1544 parent=parent, 

1545 ) 

1546 

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

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

1549 newnode = nodes.Raise( 

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 # no traceback; anyway it is not used in Pylint 

1557 newnode.postinit( 

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

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

1560 ) 

1561 return newnode 

1562 

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

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

1565 newnode = nodes.Return( 

1566 lineno=node.lineno, 

1567 col_offset=node.col_offset, 

1568 end_lineno=node.end_lineno, 

1569 end_col_offset=node.end_col_offset, 

1570 parent=parent, 

1571 ) 

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

1573 return newnode 

1574 

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

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

1577 newnode = nodes.Set( 

1578 lineno=node.lineno, 

1579 col_offset=node.col_offset, 

1580 end_lineno=node.end_lineno, 

1581 end_col_offset=node.end_col_offset, 

1582 parent=parent, 

1583 ) 

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

1585 return newnode 

1586 

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

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

1589 newnode = nodes.SetComp( 

1590 lineno=node.lineno, 

1591 col_offset=node.col_offset, 

1592 end_lineno=node.end_lineno, 

1593 end_col_offset=node.end_col_offset, 

1594 parent=parent, 

1595 ) 

1596 newnode.postinit( 

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

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

1599 ) 

1600 return newnode 

1601 

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

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

1604 newnode = nodes.Slice( 

1605 lineno=node.lineno, 

1606 col_offset=node.col_offset, 

1607 end_lineno=node.end_lineno, 

1608 end_col_offset=node.end_col_offset, 

1609 parent=parent, 

1610 ) 

1611 newnode.postinit( 

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

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

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

1615 ) 

1616 return newnode 

1617 

1618 def visit_subscript( 

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

1620 ) -> nodes.Subscript: 

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

1622 context = self._get_context(node) 

1623 newnode = nodes.Subscript( 

1624 ctx=context, 

1625 lineno=node.lineno, 

1626 col_offset=node.col_offset, 

1627 end_lineno=node.end_lineno, 

1628 end_col_offset=node.end_col_offset, 

1629 parent=parent, 

1630 ) 

1631 newnode.postinit( 

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

1633 ) 

1634 return newnode 

1635 

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

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

1638 context = self._get_context(node) 

1639 newnode = nodes.Starred( 

1640 ctx=context, 

1641 lineno=node.lineno, 

1642 col_offset=node.col_offset, 

1643 end_lineno=node.end_lineno, 

1644 end_col_offset=node.end_col_offset, 

1645 parent=parent, 

1646 ) 

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

1648 return newnode 

1649 

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

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

1652 newnode = nodes.Try( 

1653 lineno=node.lineno, 

1654 col_offset=node.col_offset, 

1655 end_lineno=node.end_lineno, 

1656 end_col_offset=node.end_col_offset, 

1657 parent=parent, 

1658 ) 

1659 newnode.postinit( 

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

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

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

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

1664 ) 

1665 return newnode 

1666 

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

1668 newnode = nodes.TryStar( 

1669 lineno=node.lineno, 

1670 col_offset=node.col_offset, 

1671 end_lineno=node.end_lineno, 

1672 end_col_offset=node.end_col_offset, 

1673 parent=parent, 

1674 ) 

1675 newnode.postinit( 

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

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

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

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

1680 ) 

1681 return newnode 

1682 

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

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

1685 context = self._get_context(node) 

1686 newnode = nodes.Tuple( 

1687 ctx=context, 

1688 lineno=node.lineno, 

1689 col_offset=node.col_offset, 

1690 end_lineno=node.end_lineno, 

1691 end_col_offset=node.end_col_offset, 

1692 parent=parent, 

1693 ) 

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

1695 return newnode 

1696 

1697 def visit_typealias( 

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

1699 ) -> nodes.TypeAlias: 

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

1701 newnode = nodes.TypeAlias( 

1702 lineno=node.lineno, 

1703 col_offset=node.col_offset, 

1704 end_lineno=node.end_lineno, 

1705 end_col_offset=node.end_col_offset, 

1706 parent=parent, 

1707 ) 

1708 newnode.postinit( 

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

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

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

1712 ) 

1713 return newnode 

1714 

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

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

1717 newnode = nodes.TypeVar( 

1718 lineno=node.lineno, 

1719 col_offset=node.col_offset, 

1720 end_lineno=node.end_lineno, 

1721 end_col_offset=node.end_col_offset, 

1722 parent=parent, 

1723 ) 

1724 # Add AssignName node for 'node.name' 

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

1726 newnode.postinit( 

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

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

1729 default_value=( 

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

1731 ), 

1732 ) 

1733 return newnode 

1734 

1735 def visit_typevartuple( 

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

1737 ) -> nodes.TypeVarTuple: 

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

1739 newnode = nodes.TypeVarTuple( 

1740 lineno=node.lineno, 

1741 col_offset=node.col_offset, 

1742 end_lineno=node.end_lineno, 

1743 end_col_offset=node.end_col_offset, 

1744 parent=parent, 

1745 ) 

1746 # Add AssignName node for 'node.name' 

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

1748 newnode.postinit( 

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

1750 default_value=( 

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

1752 ), 

1753 ) 

1754 return newnode 

1755 

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

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

1758 newnode = nodes.UnaryOp( 

1759 op=UNARY_OP_CLASSES[node.op.__class__], 

1760 lineno=node.lineno, 

1761 col_offset=node.col_offset, 

1762 end_lineno=node.end_lineno, 

1763 end_col_offset=node.end_col_offset, 

1764 parent=parent, 

1765 ) 

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

1767 return newnode 

1768 

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

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

1771 newnode = nodes.While( 

1772 lineno=node.lineno, 

1773 col_offset=node.col_offset, 

1774 end_lineno=node.end_lineno, 

1775 end_col_offset=node.end_col_offset, 

1776 parent=parent, 

1777 ) 

1778 newnode.postinit( 

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

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

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

1782 ) 

1783 return newnode 

1784 

1785 @overload 

1786 def _visit_with( 

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

1788 ) -> nodes.With: ... 

1789 

1790 @overload 

1791 def _visit_with( 

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

1793 ) -> nodes.AsyncWith: ... 

1794 

1795 def _visit_with( 

1796 self, 

1797 cls: type[_WithT], 

1798 node: ast.With | ast.AsyncWith, 

1799 parent: nodes.NodeNG, 

1800 ) -> _WithT: 

1801 newnode = cls( 

1802 lineno=node.lineno, 

1803 col_offset=node.col_offset, 

1804 end_lineno=node.end_lineno, 

1805 end_col_offset=node.end_col_offset, 

1806 parent=parent, 

1807 ) 

1808 

1809 def visit_child( 

1810 child: ast.withitem, 

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

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

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

1814 return expr, var 

1815 

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

1817 newnode.postinit( 

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

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

1820 type_annotation=type_annotation, 

1821 ) 

1822 return newnode 

1823 

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

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

1826 

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

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

1829 newnode = nodes.Yield( 

1830 lineno=node.lineno, 

1831 col_offset=node.col_offset, 

1832 end_lineno=node.end_lineno, 

1833 end_col_offset=node.end_col_offset, 

1834 parent=parent, 

1835 ) 

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

1837 return newnode 

1838 

1839 def visit_yieldfrom( 

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

1841 ) -> nodes.NodeNG: 

1842 newnode = nodes.YieldFrom( 

1843 lineno=node.lineno, 

1844 col_offset=node.col_offset, 

1845 end_lineno=node.end_lineno, 

1846 end_col_offset=node.end_col_offset, 

1847 parent=parent, 

1848 ) 

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

1850 return newnode 

1851 

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

1853 newnode = nodes.Match( 

1854 lineno=node.lineno, 

1855 col_offset=node.col_offset, 

1856 end_lineno=node.end_lineno, 

1857 end_col_offset=node.end_col_offset, 

1858 parent=parent, 

1859 ) 

1860 newnode.postinit( 

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

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

1863 ) 

1864 return newnode 

1865 

1866 def visit_matchcase( 

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

1868 ) -> nodes.MatchCase: 

1869 newnode = nodes.MatchCase(parent=parent) 

1870 newnode.postinit( 

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

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

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

1874 ) 

1875 return newnode 

1876 

1877 def visit_matchvalue( 

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

1879 ) -> nodes.MatchValue: 

1880 newnode = nodes.MatchValue( 

1881 lineno=node.lineno, 

1882 col_offset=node.col_offset, 

1883 end_lineno=node.end_lineno, 

1884 end_col_offset=node.end_col_offset, 

1885 parent=parent, 

1886 ) 

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

1888 return newnode 

1889 

1890 def visit_matchsingleton( 

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

1892 ) -> nodes.MatchSingleton: 

1893 return nodes.MatchSingleton( 

1894 value=node.value, 

1895 lineno=node.lineno, 

1896 col_offset=node.col_offset, 

1897 end_lineno=node.end_lineno, 

1898 end_col_offset=node.end_col_offset, 

1899 parent=parent, 

1900 ) 

1901 

1902 def visit_matchsequence( 

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

1904 ) -> nodes.MatchSequence: 

1905 newnode = nodes.MatchSequence( 

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 newnode.postinit( 

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

1914 ) 

1915 return newnode 

1916 

1917 def visit_matchmapping( 

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

1919 ) -> nodes.MatchMapping: 

1920 newnode = nodes.MatchMapping( 

1921 lineno=node.lineno, 

1922 col_offset=node.col_offset, 

1923 end_lineno=node.end_lineno, 

1924 end_col_offset=node.end_col_offset, 

1925 parent=parent, 

1926 ) 

1927 # Add AssignName node for 'node.name' 

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

1929 newnode.postinit( 

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

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

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

1933 ) 

1934 return newnode 

1935 

1936 def visit_matchclass( 

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

1938 ) -> nodes.MatchClass: 

1939 newnode = nodes.MatchClass( 

1940 lineno=node.lineno, 

1941 col_offset=node.col_offset, 

1942 end_lineno=node.end_lineno, 

1943 end_col_offset=node.end_col_offset, 

1944 parent=parent, 

1945 ) 

1946 newnode.postinit( 

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

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

1949 kwd_attrs=node.kwd_attrs, 

1950 kwd_patterns=[ 

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

1952 ], 

1953 ) 

1954 return newnode 

1955 

1956 def visit_matchstar( 

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

1958 ) -> nodes.MatchStar: 

1959 newnode = nodes.MatchStar( 

1960 lineno=node.lineno, 

1961 col_offset=node.col_offset, 

1962 end_lineno=node.end_lineno, 

1963 end_col_offset=node.end_col_offset, 

1964 parent=parent, 

1965 ) 

1966 # Add AssignName node for 'node.name' 

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

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

1969 return newnode 

1970 

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

1972 newnode = nodes.MatchAs( 

1973 lineno=node.lineno, 

1974 col_offset=node.col_offset, 

1975 end_lineno=node.end_lineno, 

1976 end_col_offset=node.end_col_offset, 

1977 parent=parent, 

1978 ) 

1979 # Add AssignName node for 'node.name' 

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

1981 newnode.postinit( 

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

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

1984 ) 

1985 return newnode 

1986 

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

1988 newnode = nodes.MatchOr( 

1989 lineno=node.lineno, 

1990 col_offset=node.col_offset, 

1991 end_lineno=node.end_lineno, 

1992 end_col_offset=node.end_col_offset, 

1993 parent=parent, 

1994 ) 

1995 newnode.postinit( 

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

1997 ) 

1998 return newnode 

1999 

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

2001 

2002 def visit_templatestr( 

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

2004 ) -> nodes.TemplateStr: 

2005 newnode = nodes.TemplateStr( 

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 values=[self.visit(value, newnode) for value in node.values] 

2014 ) 

2015 return newnode 

2016 

2017 def visit_interpolation( 

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

2019 ) -> nodes.Interpolation: 

2020 newnode = nodes.Interpolation( 

2021 lineno=node.lineno, 

2022 col_offset=node.col_offset, 

2023 end_lineno=node.end_lineno, 

2024 end_col_offset=node.end_col_offset, 

2025 parent=parent, 

2026 ) 

2027 newnode.postinit( 

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

2029 str=node.str, 

2030 conversion=node.conversion, 

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

2032 ) 

2033 return newnode