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

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

706 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 sys 

13import token 

14from collections.abc import Callable, Generator 

15from io import StringIO 

16from tokenize import TokenInfo, generate_tokens 

17from typing import TYPE_CHECKING, Final, TypeVar, Union, cast, overload 

18 

19from astroid import nodes 

20from astroid._ast import ParserModule, get_parser_module, parse_function_type_comment 

21from astroid.const import IS_PYPY, PY38, PY39_PLUS, PY312_PLUS, Context 

22from astroid.manager import AstroidManager 

23from astroid.nodes import NodeNG 

24from astroid.nodes.node_classes import AssignName 

25from astroid.nodes.utils import Position 

26from astroid.typing import InferenceResult 

27 

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

29 "arguments": "Arguments", 

30 "comprehension": "Comprehension", 

31 "ListCompFor": "Comprehension", 

32 "GenExprFor": "Comprehension", 

33 "excepthandler": "ExceptHandler", 

34 "keyword": "Keyword", 

35 "match_case": "MatchCase", 

36} 

37 

38 

39T_Doc = TypeVar( 

40 "T_Doc", 

41 "ast.Module", 

42 "ast.ClassDef", 

43 Union["ast.FunctionDef", "ast.AsyncFunctionDef"], 

44) 

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

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

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

48NodesWithDocsType = Union[nodes.Module, nodes.ClassDef, nodes.FunctionDef] 

49 

50 

51# noinspection PyMethodMayBeStatic 

52class TreeRebuilder: 

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

54 

55 def __init__( 

56 self, 

57 manager: AstroidManager, 

58 parser_module: ParserModule | None = None, 

59 data: str | None = None, 

60 ) -> None: 

61 self._manager = manager 

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

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

64 self._import_from_nodes: list[nodes.ImportFrom] = [] 

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

66 self._visit_meths: dict[type[ast.AST], Callable[[ast.AST, NodeNG], NodeNG]] = {} 

67 

68 if parser_module is None: 

69 self._parser_module = get_parser_module() 

70 else: 

71 self._parser_module = parser_module 

72 

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

74 """Return the doc ast node.""" 

75 try: 

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

77 first_value = node.body[0].value 

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

79 first_value.value, str 

80 ): 

81 doc_ast_node = first_value 

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

83 # The ast parser of python < 3.8 sets col_offset of multi-line strings to -1 

84 # as it is unable to determine the value correctly. We reset this to None. 

85 if doc_ast_node.col_offset == -1: 

86 doc_ast_node.col_offset = None 

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 self._parser_module.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 # pylint: disable-next=unsubscriptable-object 

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

126 

127 start_token: TokenInfo | None = None 

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

129 if isinstance(parent, nodes.AsyncFunctionDef): 

130 search_token = "async" 

131 elif isinstance(parent, nodes.FunctionDef): 

132 search_token = "def" 

133 else: 

134 search_token = "class" 

135 

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 

153 return Position( 

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

155 col_offset=start_token.start[1], 

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

157 end_col_offset=t.end[1], 

158 ) 

159 

160 def _reset_end_lineno(self, newnode: nodes.NodeNG) -> None: 

161 """Reset end_lineno and end_col_offset attributes for PyPy 3.8. 

162 

163 For some nodes, these are either set to -1 or only partially assigned. 

164 To keep consistency across astroid and pylint, reset all. 

165 

166 This has been fixed in PyPy 3.9. 

167 For reference, an (incomplete) list of nodes with issues: 

168 - ClassDef - For 

169 - FunctionDef - While 

170 - Call - If 

171 - Decorators - Try 

172 - With - Assign 

173 """ 

174 newnode.end_lineno = None 

175 newnode.end_col_offset = None 

176 for child_node in newnode.get_children(): 

177 self._reset_end_lineno(child_node) 

178 

179 def visit_module( 

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

181 ) -> nodes.Module: 

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

183 

184 Note: Method not called by 'visit' 

185 """ 

186 node, doc_ast_node = self._get_doc(node) 

187 newnode = nodes.Module( 

188 name=modname, 

189 file=modpath, 

190 path=[modpath], 

191 package=package, 

192 ) 

193 newnode.postinit( 

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

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

196 ) 

197 if IS_PYPY and PY38: 

198 self._reset_end_lineno(newnode) 

199 return newnode 

200 

201 if TYPE_CHECKING: # noqa: C901 

202 

203 @overload 

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

205 

206 @overload 

207 def visit(self, node: ast.arguments, parent: NodeNG) -> nodes.Arguments: ... 

208 

209 @overload 

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

211 

212 @overload 

213 def visit( 

214 self, node: ast.AsyncFunctionDef, parent: NodeNG 

215 ) -> nodes.AsyncFunctionDef: ... 

216 

217 @overload 

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

219 

220 @overload 

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

222 

223 @overload 

224 def visit(self, node: ast.AsyncWith, parent: NodeNG) -> nodes.AsyncWith: ... 

225 

226 @overload 

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

228 

229 @overload 

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

231 

232 @overload 

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

234 

235 @overload 

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

237 

238 @overload 

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

240 

241 @overload 

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

243 

244 @overload 

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

246 

247 @overload 

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

249 

250 @overload 

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

252 

253 @overload 

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

255 

256 @overload 

257 def visit( 

258 self, node: ast.comprehension, parent: NodeNG 

259 ) -> nodes.Comprehension: ... 

260 

261 @overload 

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

263 

264 @overload 

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

266 

267 @overload 

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

269 

270 @overload 

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

272 

273 @overload 

274 def visit( 

275 self, node: ast.ExceptHandler, parent: NodeNG 

276 ) -> nodes.ExceptHandler: ... 

277 

278 @overload 

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

280 

281 @overload 

282 def visit(self, node: ast.ImportFrom, parent: NodeNG) -> nodes.ImportFrom: ... 

283 

284 @overload 

285 def visit(self, node: ast.FunctionDef, parent: NodeNG) -> nodes.FunctionDef: ... 

286 

287 @overload 

288 def visit( 

289 self, node: ast.GeneratorExp, parent: NodeNG 

290 ) -> nodes.GeneratorExp: ... 

291 

292 @overload 

293 def visit(self, node: ast.Attribute, parent: NodeNG) -> nodes.Attribute: ... 

294 

295 @overload 

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

297 

298 @overload 

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

300 

301 @overload 

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

303 

304 @overload 

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

306 

307 @overload 

308 def visit(self, node: ast.JoinedStr, parent: NodeNG) -> nodes.JoinedStr: ... 

309 

310 @overload 

311 def visit( 

312 self, node: ast.FormattedValue, parent: NodeNG 

313 ) -> nodes.FormattedValue: ... 

314 

315 @overload 

316 def visit(self, node: ast.NamedExpr, parent: NodeNG) -> nodes.NamedExpr: ... 

317 

318 if sys.version_info < (3, 9): 

319 # Not used in Python 3.9+ 

320 @overload 

321 def visit( 

322 self, node: ast.ExtSlice, parent: nodes.Subscript 

323 ) -> nodes.Tuple: ... 

324 

325 @overload 

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

327 

328 @overload 

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

330 

331 @overload 

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

333 

334 @overload 

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

336 

337 @overload 

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

339 

340 @overload 

341 def visit( 

342 self, node: ast.Name, parent: NodeNG 

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

344 

345 @overload 

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

347 

348 @overload 

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

350 

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

352 

353 @overload 

354 def visit(self, node: ast.ParamSpec, parent: NodeNG) -> nodes.ParamSpec: ... 

355 

356 @overload 

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

358 

359 @overload 

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

361 

362 @overload 

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

364 

365 @overload 

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

367 

368 @overload 

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

370 

371 @overload 

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

373 

374 @overload 

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

376 

377 @overload 

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

379 

380 @overload 

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

382 

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

384 

385 @overload 

386 def visit(self, node: ast.TryStar, parent: NodeNG) -> nodes.TryStar: ... 

387 

388 @overload 

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

390 

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

392 

393 @overload 

394 def visit(self, node: ast.TypeAlias, parent: NodeNG) -> nodes.TypeAlias: ... 

395 

396 @overload 

397 def visit(self, node: ast.TypeVar, parent: NodeNG) -> nodes.TypeVar: ... 

398 

399 @overload 

400 def visit( 

401 self, node: ast.TypeVarTuple, parent: NodeNG 

402 ) -> nodes.TypeVarTuple: ... 

403 

404 @overload 

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

406 

407 @overload 

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

409 

410 @overload 

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

412 

413 @overload 

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

415 

416 @overload 

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

418 

419 if sys.version_info >= (3, 10): 

420 

421 @overload 

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

423 

424 @overload 

425 def visit( 

426 self, node: ast.match_case, parent: NodeNG 

427 ) -> nodes.MatchCase: ... 

428 

429 @overload 

430 def visit( 

431 self, node: ast.MatchValue, parent: NodeNG 

432 ) -> nodes.MatchValue: ... 

433 

434 @overload 

435 def visit( 

436 self, node: ast.MatchSingleton, parent: NodeNG 

437 ) -> nodes.MatchSingleton: ... 

438 

439 @overload 

440 def visit( 

441 self, node: ast.MatchSequence, parent: NodeNG 

442 ) -> nodes.MatchSequence: ... 

443 

444 @overload 

445 def visit( 

446 self, node: ast.MatchMapping, parent: NodeNG 

447 ) -> nodes.MatchMapping: ... 

448 

449 @overload 

450 def visit( 

451 self, node: ast.MatchClass, parent: NodeNG 

452 ) -> nodes.MatchClass: ... 

453 

454 @overload 

455 def visit(self, node: ast.MatchStar, parent: NodeNG) -> nodes.MatchStar: ... 

456 

457 @overload 

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

459 

460 @overload 

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

462 

463 @overload 

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

465 

466 @overload 

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

468 

469 @overload 

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

471 

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

473 if node is None: 

474 return None 

475 cls = node.__class__ 

476 if cls in self._visit_meths: 

477 visit_method = self._visit_meths[cls] 

478 else: 

479 cls_name = cls.__name__ 

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

481 visit_method = getattr(self, visit_name) 

482 self._visit_meths[cls] = visit_method 

483 return visit_method(node, parent) 

484 

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

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

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

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

489 else: 

490 assert node.parent 

491 assert node.name 

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

493 

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

495 """Visit an arg node by returning a fresh AssName instance.""" 

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

497 

498 def visit_arguments(self, node: ast.arguments, parent: NodeNG) -> nodes.Arguments: 

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

500 vararg: str | None = None 

501 kwarg: str | None = None 

502 vararg_node = node.vararg 

503 kwarg_node = node.kwarg 

504 

505 newnode = nodes.Arguments( 

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

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

508 parent, 

509 ( 

510 AssignName( 

511 vararg_node.arg, 

512 vararg_node.lineno, 

513 vararg_node.col_offset, 

514 parent, 

515 end_lineno=vararg_node.end_lineno, 

516 end_col_offset=vararg_node.end_col_offset, 

517 ) 

518 if vararg_node 

519 else None 

520 ), 

521 ( 

522 AssignName( 

523 kwarg_node.arg, 

524 kwarg_node.lineno, 

525 kwarg_node.col_offset, 

526 parent, 

527 end_lineno=kwarg_node.end_lineno, 

528 end_col_offset=kwarg_node.end_col_offset, 

529 ) 

530 if kwarg_node 

531 else None 

532 ), 

533 ) 

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

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

536 varargannotation: NodeNG | None = None 

537 kwargannotation: NodeNG | None = None 

538 if node.vararg: 

539 vararg = node.vararg.arg 

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

541 if node.kwarg: 

542 kwarg = node.kwarg.arg 

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

544 

545 if PY38: 

546 # In Python 3.8 'end_lineno' and 'end_col_offset' 

547 # for 'kwonlyargs' don't include the annotation. 

548 for arg in node.kwonlyargs: 

549 if arg.annotation is not None: 

550 arg.end_lineno = arg.annotation.end_lineno 

551 arg.end_col_offset = arg.annotation.end_col_offset 

552 

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

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

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

556 kwonlyargs_annotations = [ 

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

558 ] 

559 

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

561 posonlyargs_annotations = [ 

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

563 ] 

564 type_comment_args = [ 

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

566 ] 

567 type_comment_kwonlyargs = [ 

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

569 ] 

570 type_comment_posonlyargs = [ 

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

572 ] 

573 

574 newnode.postinit( 

575 args=args, 

576 defaults=defaults, 

577 kwonlyargs=kwonlyargs, 

578 posonlyargs=posonlyargs, 

579 kw_defaults=kw_defaults, 

580 annotations=annotations, 

581 kwonlyargs_annotations=kwonlyargs_annotations, 

582 posonlyargs_annotations=posonlyargs_annotations, 

583 varargannotation=varargannotation, 

584 kwargannotation=kwargannotation, 

585 type_comment_args=type_comment_args, 

586 type_comment_kwonlyargs=type_comment_kwonlyargs, 

587 type_comment_posonlyargs=type_comment_posonlyargs, 

588 ) 

589 # save argument names in locals: 

590 assert newnode.parent 

591 if vararg: 

592 newnode.parent.set_local(vararg, newnode) 

593 if kwarg: 

594 newnode.parent.set_local(kwarg, newnode) 

595 return newnode 

596 

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

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

599 newnode = nodes.Assert( 

600 lineno=node.lineno, 

601 col_offset=node.col_offset, 

602 end_lineno=node.end_lineno, 

603 end_col_offset=node.end_col_offset, 

604 parent=parent, 

605 ) 

606 msg: NodeNG | None = None 

607 if node.msg: 

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

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

610 return newnode 

611 

612 def check_type_comment( 

613 self, 

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

615 parent: ( 

616 nodes.Assign 

617 | nodes.Arguments 

618 | nodes.For 

619 | nodes.AsyncFor 

620 | nodes.With 

621 | nodes.AsyncWith 

622 ), 

623 ) -> NodeNG | None: 

624 if not node.type_comment: 

625 return None 

626 

627 try: 

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

629 except SyntaxError: 

630 # Invalid type comment, just skip it. 

631 return None 

632 

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

634 # without any nodes in the body. 

635 if not type_comment_ast.body: 

636 return None 

637 

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

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

640 return None 

641 

642 return type_object.value 

643 

644 def check_function_type_comment( 

645 self, node: ast.FunctionDef | ast.AsyncFunctionDef, parent: NodeNG 

646 ) -> tuple[NodeNG | None, list[NodeNG]] | None: 

647 if not node.type_comment: 

648 return None 

649 

650 try: 

651 type_comment_ast = parse_function_type_comment(node.type_comment) 

652 except SyntaxError: 

653 # Invalid type comment, just skip it. 

654 return None 

655 

656 if not type_comment_ast: 

657 return None 

658 

659 returns: NodeNG | None = None 

660 argtypes: list[NodeNG] = [ 

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

662 ] 

663 if type_comment_ast.returns: 

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

665 

666 return returns, argtypes 

667 

668 def visit_asyncfunctiondef( 

669 self, node: ast.AsyncFunctionDef, parent: NodeNG 

670 ) -> nodes.AsyncFunctionDef: 

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

672 

673 def visit_asyncfor(self, node: ast.AsyncFor, parent: NodeNG) -> nodes.AsyncFor: 

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

675 

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

677 newnode = nodes.Await( 

678 lineno=node.lineno, 

679 col_offset=node.col_offset, 

680 end_lineno=node.end_lineno, 

681 end_col_offset=node.end_col_offset, 

682 parent=parent, 

683 ) 

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

685 return newnode 

686 

687 def visit_asyncwith(self, node: ast.AsyncWith, parent: NodeNG) -> nodes.AsyncWith: 

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

689 

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

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

692 newnode = nodes.Assign( 

693 lineno=node.lineno, 

694 col_offset=node.col_offset, 

695 end_lineno=node.end_lineno, 

696 end_col_offset=node.end_col_offset, 

697 parent=parent, 

698 ) 

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

700 newnode.postinit( 

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

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

703 type_annotation=type_annotation, 

704 ) 

705 return newnode 

706 

707 def visit_annassign(self, node: ast.AnnAssign, parent: NodeNG) -> nodes.AnnAssign: 

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

709 newnode = nodes.AnnAssign( 

710 lineno=node.lineno, 

711 col_offset=node.col_offset, 

712 end_lineno=node.end_lineno, 

713 end_col_offset=node.end_col_offset, 

714 parent=parent, 

715 ) 

716 newnode.postinit( 

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

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

719 simple=node.simple, 

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

721 ) 

722 return newnode 

723 

724 @overload 

725 def visit_assignname( 

726 self, node: ast.AST, parent: NodeNG, node_name: str 

727 ) -> nodes.AssignName: ... 

728 

729 @overload 

730 def visit_assignname( 

731 self, node: ast.AST, parent: NodeNG, node_name: None 

732 ) -> None: ... 

733 

734 def visit_assignname( 

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

736 ) -> nodes.AssignName | None: 

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

738 

739 Note: Method not called by 'visit' 

740 """ 

741 if node_name is None: 

742 return None 

743 newnode = nodes.AssignName( 

744 name=node_name, 

745 lineno=node.lineno, 

746 col_offset=node.col_offset, 

747 end_lineno=node.end_lineno, 

748 end_col_offset=node.end_col_offset, 

749 parent=parent, 

750 ) 

751 self._save_assignment(newnode) 

752 return newnode 

753 

754 def visit_augassign(self, node: ast.AugAssign, parent: NodeNG) -> nodes.AugAssign: 

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

756 newnode = nodes.AugAssign( 

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

758 lineno=node.lineno, 

759 col_offset=node.col_offset, 

760 end_lineno=node.end_lineno, 

761 end_col_offset=node.end_col_offset, 

762 parent=parent, 

763 ) 

764 newnode.postinit( 

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

766 ) 

767 return newnode 

768 

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

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

771 newnode = nodes.BinOp( 

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

773 lineno=node.lineno, 

774 col_offset=node.col_offset, 

775 end_lineno=node.end_lineno, 

776 end_col_offset=node.end_col_offset, 

777 parent=parent, 

778 ) 

779 newnode.postinit( 

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

781 ) 

782 return newnode 

783 

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

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

786 newnode = nodes.BoolOp( 

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

788 lineno=node.lineno, 

789 col_offset=node.col_offset, 

790 end_lineno=node.end_lineno, 

791 end_col_offset=node.end_col_offset, 

792 parent=parent, 

793 ) 

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

795 return newnode 

796 

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

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

799 return nodes.Break( 

800 lineno=node.lineno, 

801 col_offset=node.col_offset, 

802 end_lineno=node.end_lineno, 

803 end_col_offset=node.end_col_offset, 

804 parent=parent, 

805 ) 

806 

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

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

809 newnode = nodes.Call( 

810 lineno=node.lineno, 

811 col_offset=node.col_offset, 

812 end_lineno=node.end_lineno, 

813 end_col_offset=node.end_col_offset, 

814 parent=parent, 

815 ) 

816 newnode.postinit( 

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

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

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

820 ) 

821 return newnode 

822 

823 def visit_classdef( 

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

825 ) -> nodes.ClassDef: 

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

827 node, doc_ast_node = self._get_doc(node) 

828 newnode = nodes.ClassDef( 

829 name=node.name, 

830 lineno=node.lineno, 

831 col_offset=node.col_offset, 

832 end_lineno=node.end_lineno, 

833 end_col_offset=node.end_col_offset, 

834 parent=parent, 

835 ) 

836 metaclass = None 

837 for keyword in node.keywords: 

838 if keyword.arg == "metaclass": 

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

840 break 

841 decorators = self.visit_decorators(node, newnode) 

842 newnode.postinit( 

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

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

845 decorators, 

846 newstyle, 

847 metaclass, 

848 [ 

849 self.visit(kwd, newnode) 

850 for kwd in node.keywords 

851 if kwd.arg != "metaclass" 

852 ], 

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

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

855 type_params=( 

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

857 if PY312_PLUS 

858 else [] 

859 ), 

860 ) 

861 return newnode 

862 

863 def visit_continue(self, node: ast.Continue, parent: NodeNG) -> nodes.Continue: 

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

865 return nodes.Continue( 

866 lineno=node.lineno, 

867 col_offset=node.col_offset, 

868 end_lineno=node.end_lineno, 

869 end_col_offset=node.end_col_offset, 

870 parent=parent, 

871 ) 

872 

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

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

875 newnode = nodes.Compare( 

876 lineno=node.lineno, 

877 col_offset=node.col_offset, 

878 end_lineno=node.end_lineno, 

879 end_col_offset=node.end_col_offset, 

880 parent=parent, 

881 ) 

882 newnode.postinit( 

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

884 [ 

885 ( 

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

887 self.visit(expr, newnode), 

888 ) 

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

890 ], 

891 ) 

892 return newnode 

893 

894 def visit_comprehension( 

895 self, node: ast.comprehension, parent: NodeNG 

896 ) -> nodes.Comprehension: 

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

898 newnode = nodes.Comprehension( 

899 parent=parent, 

900 # Comprehension nodes don't have these attributes 

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

902 lineno=None, 

903 col_offset=None, 

904 end_lineno=None, 

905 end_col_offset=None, 

906 ) 

907 newnode.postinit( 

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

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

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

911 bool(node.is_async), 

912 ) 

913 return newnode 

914 

915 def visit_decorators( 

916 self, 

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

918 parent: NodeNG, 

919 ) -> nodes.Decorators | None: 

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

921 

922 Note: Method not called by 'visit' 

923 """ 

924 if not node.decorator_list: 

925 return None 

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

927 # parent is an astroid.nodes.FunctionDef node 

928 

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

930 lineno = node.decorator_list[0].lineno 

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

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

933 

934 newnode = nodes.Decorators( 

935 lineno=lineno, 

936 col_offset=node.col_offset, 

937 end_lineno=end_lineno, 

938 end_col_offset=end_col_offset, 

939 parent=parent, 

940 ) 

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

942 return newnode 

943 

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

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

946 newnode = nodes.Delete( 

947 lineno=node.lineno, 

948 col_offset=node.col_offset, 

949 end_lineno=node.end_lineno, 

950 end_col_offset=node.end_col_offset, 

951 parent=parent, 

952 ) 

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

954 return newnode 

955 

956 def _visit_dict_items( 

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

958 ) -> Generator[tuple[NodeNG, NodeNG], None, None]: 

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

960 rebuilt_key: NodeNG 

961 rebuilt_value = self.visit(value, newnode) 

962 if not key: 

963 # Extended unpacking 

964 rebuilt_key = nodes.DictUnpack( 

965 lineno=rebuilt_value.lineno, 

966 col_offset=rebuilt_value.col_offset, 

967 end_lineno=rebuilt_value.end_lineno, 

968 end_col_offset=rebuilt_value.end_col_offset, 

969 parent=parent, 

970 ) 

971 else: 

972 rebuilt_key = self.visit(key, newnode) 

973 yield rebuilt_key, rebuilt_value 

974 

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

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

977 newnode = nodes.Dict( 

978 lineno=node.lineno, 

979 col_offset=node.col_offset, 

980 end_lineno=node.end_lineno, 

981 end_col_offset=node.end_col_offset, 

982 parent=parent, 

983 ) 

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

985 self._visit_dict_items(node, parent, newnode) 

986 ) 

987 newnode.postinit(items) 

988 return newnode 

989 

990 def visit_dictcomp(self, node: ast.DictComp, parent: NodeNG) -> nodes.DictComp: 

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

992 newnode = nodes.DictComp( 

993 lineno=node.lineno, 

994 col_offset=node.col_offset, 

995 end_lineno=node.end_lineno, 

996 end_col_offset=node.end_col_offset, 

997 parent=parent, 

998 ) 

999 newnode.postinit( 

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

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

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

1003 ) 

1004 return newnode 

1005 

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

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

1008 newnode = nodes.Expr( 

1009 lineno=node.lineno, 

1010 col_offset=node.col_offset, 

1011 end_lineno=node.end_lineno, 

1012 end_col_offset=node.end_col_offset, 

1013 parent=parent, 

1014 ) 

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

1016 return newnode 

1017 

1018 def visit_excepthandler( 

1019 self, node: ast.ExceptHandler, parent: NodeNG 

1020 ) -> nodes.ExceptHandler: 

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

1022 newnode = nodes.ExceptHandler( 

1023 lineno=node.lineno, 

1024 col_offset=node.col_offset, 

1025 end_lineno=node.end_lineno, 

1026 end_col_offset=node.end_col_offset, 

1027 parent=parent, 

1028 ) 

1029 newnode.postinit( 

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

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

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

1033 ) 

1034 return newnode 

1035 

1036 @overload 

1037 def _visit_for( 

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

1039 ) -> nodes.For: ... 

1040 

1041 @overload 

1042 def _visit_for( 

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

1044 ) -> nodes.AsyncFor: ... 

1045 

1046 def _visit_for( 

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

1048 ) -> _ForT: 

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

1050 col_offset = node.col_offset 

1051 if IS_PYPY and not PY39_PLUS and isinstance(node, ast.AsyncFor) and self._data: 

1052 # pylint: disable-next=unsubscriptable-object 

1053 col_offset = self._data[node.lineno - 1].index("async") 

1054 

1055 newnode = cls( 

1056 lineno=node.lineno, 

1057 col_offset=col_offset, 

1058 end_lineno=node.end_lineno, 

1059 end_col_offset=node.end_col_offset, 

1060 parent=parent, 

1061 ) 

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

1063 newnode.postinit( 

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

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

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

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

1068 type_annotation=type_annotation, 

1069 ) 

1070 return newnode 

1071 

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

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

1074 

1075 def visit_importfrom( 

1076 self, node: ast.ImportFrom, parent: NodeNG 

1077 ) -> nodes.ImportFrom: 

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

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

1080 newnode = nodes.ImportFrom( 

1081 fromname=node.module or "", 

1082 names=names, 

1083 level=node.level or None, 

1084 lineno=node.lineno, 

1085 col_offset=node.col_offset, 

1086 end_lineno=node.end_lineno, 

1087 end_col_offset=node.end_col_offset, 

1088 parent=parent, 

1089 ) 

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

1091 self._import_from_nodes.append(newnode) 

1092 return newnode 

1093 

1094 @overload 

1095 def _visit_functiondef( 

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

1097 ) -> nodes.FunctionDef: ... 

1098 

1099 @overload 

1100 def _visit_functiondef( 

1101 self, 

1102 cls: type[nodes.AsyncFunctionDef], 

1103 node: ast.AsyncFunctionDef, 

1104 parent: NodeNG, 

1105 ) -> nodes.AsyncFunctionDef: ... 

1106 

1107 def _visit_functiondef( 

1108 self, 

1109 cls: type[_FunctionT], 

1110 node: ast.FunctionDef | ast.AsyncFunctionDef, 

1111 parent: NodeNG, 

1112 ) -> _FunctionT: 

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

1114 self._global_names.append({}) 

1115 node, doc_ast_node = self._get_doc(node) 

1116 

1117 lineno = node.lineno 

1118 if node.decorator_list: 

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

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

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

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

1123 # first decorator to maintain backward compatibility. 

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

1125 # the framework for *years*. 

1126 lineno = node.decorator_list[0].lineno 

1127 

1128 newnode = cls( 

1129 name=node.name, 

1130 lineno=lineno, 

1131 col_offset=node.col_offset, 

1132 end_lineno=node.end_lineno, 

1133 end_col_offset=node.end_col_offset, 

1134 parent=parent, 

1135 ) 

1136 decorators = self.visit_decorators(node, newnode) 

1137 returns: NodeNG | None 

1138 if node.returns: 

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

1140 else: 

1141 returns = None 

1142 

1143 type_comment_args = type_comment_returns = None 

1144 type_comment_annotation = self.check_function_type_comment(node, newnode) 

1145 if type_comment_annotation: 

1146 type_comment_returns, type_comment_args = type_comment_annotation 

1147 newnode.postinit( 

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

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

1150 decorators=decorators, 

1151 returns=returns, 

1152 type_comment_returns=type_comment_returns, 

1153 type_comment_args=type_comment_args, 

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

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

1156 type_params=( 

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

1158 if PY312_PLUS 

1159 else [] 

1160 ), 

1161 ) 

1162 self._global_names.pop() 

1163 return newnode 

1164 

1165 def visit_functiondef( 

1166 self, node: ast.FunctionDef, parent: NodeNG 

1167 ) -> nodes.FunctionDef: 

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

1169 

1170 def visit_generatorexp( 

1171 self, node: ast.GeneratorExp, parent: NodeNG 

1172 ) -> nodes.GeneratorExp: 

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

1174 newnode = nodes.GeneratorExp( 

1175 lineno=node.lineno, 

1176 col_offset=node.col_offset, 

1177 end_lineno=node.end_lineno, 

1178 end_col_offset=node.end_col_offset, 

1179 parent=parent, 

1180 ) 

1181 newnode.postinit( 

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

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

1184 ) 

1185 return newnode 

1186 

1187 def visit_attribute( 

1188 self, node: ast.Attribute, parent: NodeNG 

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

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

1191 context = self._get_context(node) 

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

1193 if context == Context.Del: 

1194 # FIXME : maybe we should reintroduce and visit_delattr ? 

1195 # for instance, deactivating assign_ctx 

1196 newnode = nodes.DelAttr( 

1197 attrname=node.attr, 

1198 lineno=node.lineno, 

1199 col_offset=node.col_offset, 

1200 end_lineno=node.end_lineno, 

1201 end_col_offset=node.end_col_offset, 

1202 parent=parent, 

1203 ) 

1204 elif context == Context.Store: 

1205 newnode = nodes.AssignAttr( 

1206 attrname=node.attr, 

1207 lineno=node.lineno, 

1208 col_offset=node.col_offset, 

1209 end_lineno=node.end_lineno, 

1210 end_col_offset=node.end_col_offset, 

1211 parent=parent, 

1212 ) 

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

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

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

1216 # doesn't support ParamSpec 

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

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

1219 else: 

1220 newnode = nodes.Attribute( 

1221 attrname=node.attr, 

1222 lineno=node.lineno, 

1223 col_offset=node.col_offset, 

1224 end_lineno=node.end_lineno, 

1225 end_col_offset=node.end_col_offset, 

1226 parent=parent, 

1227 ) 

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

1229 return newnode 

1230 

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

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

1233 newnode = nodes.Global( 

1234 names=node.names, 

1235 lineno=node.lineno, 

1236 col_offset=node.col_offset, 

1237 end_lineno=node.end_lineno, 

1238 end_col_offset=node.end_col_offset, 

1239 parent=parent, 

1240 ) 

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

1242 for name in node.names: 

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

1244 return newnode 

1245 

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

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

1248 newnode = nodes.If( 

1249 lineno=node.lineno, 

1250 col_offset=node.col_offset, 

1251 end_lineno=node.end_lineno, 

1252 end_col_offset=node.end_col_offset, 

1253 parent=parent, 

1254 ) 

1255 newnode.postinit( 

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

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

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

1259 ) 

1260 return newnode 

1261 

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

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

1264 newnode = nodes.IfExp( 

1265 lineno=node.lineno, 

1266 col_offset=node.col_offset, 

1267 end_lineno=node.end_lineno, 

1268 end_col_offset=node.end_col_offset, 

1269 parent=parent, 

1270 ) 

1271 newnode.postinit( 

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

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

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

1275 ) 

1276 return newnode 

1277 

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

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

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

1281 newnode = nodes.Import( 

1282 names=names, 

1283 lineno=node.lineno, 

1284 col_offset=node.col_offset, 

1285 end_lineno=node.end_lineno, 

1286 end_col_offset=node.end_col_offset, 

1287 parent=parent, 

1288 ) 

1289 # save import names in parent's locals: 

1290 for name, asname in newnode.names: 

1291 name = asname or name 

1292 parent.set_local(name.split(".")[0], newnode) 

1293 return newnode 

1294 

1295 def visit_joinedstr(self, node: ast.JoinedStr, parent: NodeNG) -> nodes.JoinedStr: 

1296 newnode = nodes.JoinedStr( 

1297 lineno=node.lineno, 

1298 col_offset=node.col_offset, 

1299 end_lineno=node.end_lineno, 

1300 end_col_offset=node.end_col_offset, 

1301 parent=parent, 

1302 ) 

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

1304 return newnode 

1305 

1306 def visit_formattedvalue( 

1307 self, node: ast.FormattedValue, parent: NodeNG 

1308 ) -> nodes.FormattedValue: 

1309 newnode = nodes.FormattedValue( 

1310 lineno=node.lineno, 

1311 col_offset=node.col_offset, 

1312 end_lineno=node.end_lineno, 

1313 end_col_offset=node.end_col_offset, 

1314 parent=parent, 

1315 ) 

1316 newnode.postinit( 

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

1318 conversion=node.conversion, 

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

1320 ) 

1321 return newnode 

1322 

1323 def visit_namedexpr(self, node: ast.NamedExpr, parent: NodeNG) -> nodes.NamedExpr: 

1324 newnode = nodes.NamedExpr( 

1325 lineno=node.lineno, 

1326 col_offset=node.col_offset, 

1327 end_lineno=node.end_lineno, 

1328 end_col_offset=node.end_col_offset, 

1329 parent=parent, 

1330 ) 

1331 newnode.postinit( 

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

1333 ) 

1334 return newnode 

1335 

1336 if sys.version_info < (3, 9): 

1337 # Not used in Python 3.9+. 

1338 def visit_extslice( 

1339 self, node: ast.ExtSlice, parent: nodes.Subscript 

1340 ) -> nodes.Tuple: 

1341 """Visit an ExtSlice node by returning a fresh instance of Tuple.""" 

1342 # ExtSlice doesn't have lineno or col_offset information 

1343 newnode = nodes.Tuple(ctx=Context.Load, parent=parent) 

1344 newnode.postinit([self.visit(dim, newnode) for dim in node.dims]) 

1345 return newnode 

1346 

1347 def visit_index(self, node: ast.Index, parent: nodes.Subscript) -> NodeNG: 

1348 """Visit a Index node by returning a fresh instance of NodeNG.""" 

1349 return self.visit(node.value, parent) 

1350 

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

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

1353 newnode = nodes.Keyword( 

1354 arg=node.arg, 

1355 # position attributes added in 3.9 

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

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

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

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

1360 parent=parent, 

1361 ) 

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

1363 return newnode 

1364 

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

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

1367 newnode = nodes.Lambda( 

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

1375 return newnode 

1376 

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

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

1379 context = self._get_context(node) 

1380 newnode = nodes.List( 

1381 ctx=context, 

1382 lineno=node.lineno, 

1383 col_offset=node.col_offset, 

1384 end_lineno=node.end_lineno, 

1385 end_col_offset=node.end_col_offset, 

1386 parent=parent, 

1387 ) 

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

1389 return newnode 

1390 

1391 def visit_listcomp(self, node: ast.ListComp, parent: NodeNG) -> nodes.ListComp: 

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

1393 newnode = nodes.ListComp( 

1394 lineno=node.lineno, 

1395 col_offset=node.col_offset, 

1396 end_lineno=node.end_lineno, 

1397 end_col_offset=node.end_col_offset, 

1398 parent=parent, 

1399 ) 

1400 newnode.postinit( 

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

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

1403 ) 

1404 return newnode 

1405 

1406 def visit_name( 

1407 self, node: ast.Name, parent: NodeNG 

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

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

1410 context = self._get_context(node) 

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

1412 if context == Context.Del: 

1413 newnode = nodes.DelName( 

1414 name=node.id, 

1415 lineno=node.lineno, 

1416 col_offset=node.col_offset, 

1417 end_lineno=node.end_lineno, 

1418 end_col_offset=node.end_col_offset, 

1419 parent=parent, 

1420 ) 

1421 elif context == Context.Store: 

1422 newnode = nodes.AssignName( 

1423 name=node.id, 

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 else: 

1431 newnode = nodes.Name( 

1432 name=node.id, 

1433 lineno=node.lineno, 

1434 col_offset=node.col_offset, 

1435 end_lineno=node.end_lineno, 

1436 end_col_offset=node.end_col_offset, 

1437 parent=parent, 

1438 ) 

1439 # XXX REMOVE me : 

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

1441 newnode = cast(Union[nodes.AssignName, nodes.DelName], newnode) 

1442 self._save_assignment(newnode) 

1443 return newnode 

1444 

1445 def visit_nonlocal(self, node: ast.Nonlocal, parent: NodeNG) -> nodes.Nonlocal: 

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

1447 return nodes.Nonlocal( 

1448 names=node.names, 

1449 lineno=node.lineno, 

1450 col_offset=node.col_offset, 

1451 end_lineno=node.end_lineno, 

1452 end_col_offset=node.end_col_offset, 

1453 parent=parent, 

1454 ) 

1455 

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

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

1458 return nodes.Const( 

1459 value=node.value, 

1460 kind=node.kind, 

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 

1468 def visit_paramspec(self, node: ast.ParamSpec, parent: NodeNG) -> nodes.ParamSpec: 

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

1470 newnode = nodes.ParamSpec( 

1471 lineno=node.lineno, 

1472 col_offset=node.col_offset, 

1473 end_lineno=node.end_lineno, 

1474 end_col_offset=node.end_col_offset, 

1475 parent=parent, 

1476 ) 

1477 # Add AssignName node for 'node.name' 

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

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

1480 return newnode 

1481 

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

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

1484 return nodes.Pass( 

1485 lineno=node.lineno, 

1486 col_offset=node.col_offset, 

1487 end_lineno=node.end_lineno, 

1488 end_col_offset=node.end_col_offset, 

1489 parent=parent, 

1490 ) 

1491 

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

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

1494 newnode = nodes.Raise( 

1495 lineno=node.lineno, 

1496 col_offset=node.col_offset, 

1497 end_lineno=node.end_lineno, 

1498 end_col_offset=node.end_col_offset, 

1499 parent=parent, 

1500 ) 

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

1502 newnode.postinit( 

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

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

1505 ) 

1506 return newnode 

1507 

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

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

1510 newnode = nodes.Return( 

1511 lineno=node.lineno, 

1512 col_offset=node.col_offset, 

1513 end_lineno=node.end_lineno, 

1514 end_col_offset=node.end_col_offset, 

1515 parent=parent, 

1516 ) 

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

1518 return newnode 

1519 

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

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

1522 newnode = nodes.Set( 

1523 lineno=node.lineno, 

1524 col_offset=node.col_offset, 

1525 end_lineno=node.end_lineno, 

1526 end_col_offset=node.end_col_offset, 

1527 parent=parent, 

1528 ) 

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

1530 return newnode 

1531 

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

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

1534 newnode = nodes.SetComp( 

1535 lineno=node.lineno, 

1536 col_offset=node.col_offset, 

1537 end_lineno=node.end_lineno, 

1538 end_col_offset=node.end_col_offset, 

1539 parent=parent, 

1540 ) 

1541 newnode.postinit( 

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

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

1544 ) 

1545 return newnode 

1546 

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

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

1549 newnode = nodes.Slice( 

1550 # position attributes added in 3.9 

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

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

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

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

1555 parent=parent, 

1556 ) 

1557 newnode.postinit( 

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

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

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

1561 ) 

1562 return newnode 

1563 

1564 def visit_subscript(self, node: ast.Subscript, parent: NodeNG) -> nodes.Subscript: 

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

1566 context = self._get_context(node) 

1567 newnode = nodes.Subscript( 

1568 ctx=context, 

1569 lineno=node.lineno, 

1570 col_offset=node.col_offset, 

1571 end_lineno=node.end_lineno, 

1572 end_col_offset=node.end_col_offset, 

1573 parent=parent, 

1574 ) 

1575 newnode.postinit( 

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

1577 ) 

1578 return newnode 

1579 

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

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

1582 context = self._get_context(node) 

1583 newnode = nodes.Starred( 

1584 ctx=context, 

1585 lineno=node.lineno, 

1586 col_offset=node.col_offset, 

1587 end_lineno=node.end_lineno, 

1588 end_col_offset=node.end_col_offset, 

1589 parent=parent, 

1590 ) 

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

1592 return newnode 

1593 

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

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

1596 newnode = nodes.Try( 

1597 lineno=node.lineno, 

1598 col_offset=node.col_offset, 

1599 end_lineno=node.end_lineno, 

1600 end_col_offset=node.end_col_offset, 

1601 parent=parent, 

1602 ) 

1603 newnode.postinit( 

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

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

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

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

1608 ) 

1609 return newnode 

1610 

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

1612 newnode = nodes.TryStar( 

1613 lineno=node.lineno, 

1614 col_offset=node.col_offset, 

1615 end_lineno=node.end_lineno, 

1616 end_col_offset=node.end_col_offset, 

1617 parent=parent, 

1618 ) 

1619 newnode.postinit( 

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

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

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

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

1624 ) 

1625 return newnode 

1626 

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

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

1629 context = self._get_context(node) 

1630 newnode = nodes.Tuple( 

1631 ctx=context, 

1632 lineno=node.lineno, 

1633 col_offset=node.col_offset, 

1634 end_lineno=node.end_lineno, 

1635 end_col_offset=node.end_col_offset, 

1636 parent=parent, 

1637 ) 

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

1639 return newnode 

1640 

1641 def visit_typealias(self, node: ast.TypeAlias, parent: NodeNG) -> nodes.TypeAlias: 

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

1643 newnode = nodes.TypeAlias( 

1644 lineno=node.lineno, 

1645 col_offset=node.col_offset, 

1646 end_lineno=node.end_lineno, 

1647 end_col_offset=node.end_col_offset, 

1648 parent=parent, 

1649 ) 

1650 newnode.postinit( 

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

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

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

1654 ) 

1655 return newnode 

1656 

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

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

1659 newnode = nodes.TypeVar( 

1660 lineno=node.lineno, 

1661 col_offset=node.col_offset, 

1662 end_lineno=node.end_lineno, 

1663 end_col_offset=node.end_col_offset, 

1664 parent=parent, 

1665 ) 

1666 # Add AssignName node for 'node.name' 

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

1668 newnode.postinit( 

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

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

1671 ) 

1672 return newnode 

1673 

1674 def visit_typevartuple( 

1675 self, node: ast.TypeVarTuple, parent: NodeNG 

1676 ) -> nodes.TypeVarTuple: 

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

1678 newnode = nodes.TypeVarTuple( 

1679 lineno=node.lineno, 

1680 col_offset=node.col_offset, 

1681 end_lineno=node.end_lineno, 

1682 end_col_offset=node.end_col_offset, 

1683 parent=parent, 

1684 ) 

1685 # Add AssignName node for 'node.name' 

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

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

1688 return newnode 

1689 

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

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

1692 newnode = nodes.UnaryOp( 

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

1694 lineno=node.lineno, 

1695 col_offset=node.col_offset, 

1696 end_lineno=node.end_lineno, 

1697 end_col_offset=node.end_col_offset, 

1698 parent=parent, 

1699 ) 

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

1701 return newnode 

1702 

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

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

1705 newnode = nodes.While( 

1706 lineno=node.lineno, 

1707 col_offset=node.col_offset, 

1708 end_lineno=node.end_lineno, 

1709 end_col_offset=node.end_col_offset, 

1710 parent=parent, 

1711 ) 

1712 newnode.postinit( 

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

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

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

1716 ) 

1717 return newnode 

1718 

1719 @overload 

1720 def _visit_with( 

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

1722 ) -> nodes.With: ... 

1723 

1724 @overload 

1725 def _visit_with( 

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

1727 ) -> nodes.AsyncWith: ... 

1728 

1729 def _visit_with( 

1730 self, 

1731 cls: type[_WithT], 

1732 node: ast.With | ast.AsyncWith, 

1733 parent: NodeNG, 

1734 ) -> _WithT: 

1735 col_offset = node.col_offset 

1736 if IS_PYPY and not PY39_PLUS and isinstance(node, ast.AsyncWith) and self._data: 

1737 # pylint: disable-next=unsubscriptable-object 

1738 col_offset = self._data[node.lineno - 1].index("async") 

1739 

1740 newnode = cls( 

1741 lineno=node.lineno, 

1742 col_offset=col_offset, 

1743 end_lineno=node.end_lineno, 

1744 end_col_offset=node.end_col_offset, 

1745 parent=parent, 

1746 ) 

1747 

1748 def visit_child(child: ast.withitem) -> tuple[NodeNG, NodeNG | None]: 

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

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

1751 return expr, var 

1752 

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

1754 newnode.postinit( 

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

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

1757 type_annotation=type_annotation, 

1758 ) 

1759 return newnode 

1760 

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

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

1763 

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

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

1766 newnode = nodes.Yield( 

1767 lineno=node.lineno, 

1768 col_offset=node.col_offset, 

1769 end_lineno=node.end_lineno, 

1770 end_col_offset=node.end_col_offset, 

1771 parent=parent, 

1772 ) 

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

1774 return newnode 

1775 

1776 def visit_yieldfrom(self, node: ast.YieldFrom, parent: NodeNG) -> NodeNG: 

1777 newnode = nodes.YieldFrom( 

1778 lineno=node.lineno, 

1779 col_offset=node.col_offset, 

1780 end_lineno=node.end_lineno, 

1781 end_col_offset=node.end_col_offset, 

1782 parent=parent, 

1783 ) 

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

1785 return newnode 

1786 

1787 if sys.version_info >= (3, 10): 

1788 

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

1790 newnode = nodes.Match( 

1791 lineno=node.lineno, 

1792 col_offset=node.col_offset, 

1793 end_lineno=node.end_lineno, 

1794 end_col_offset=node.end_col_offset, 

1795 parent=parent, 

1796 ) 

1797 newnode.postinit( 

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

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

1800 ) 

1801 return newnode 

1802 

1803 def visit_matchcase( 

1804 self, node: ast.match_case, parent: NodeNG 

1805 ) -> nodes.MatchCase: 

1806 newnode = nodes.MatchCase(parent=parent) 

1807 newnode.postinit( 

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

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

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

1811 ) 

1812 return newnode 

1813 

1814 def visit_matchvalue( 

1815 self, node: ast.MatchValue, parent: NodeNG 

1816 ) -> nodes.MatchValue: 

1817 newnode = nodes.MatchValue( 

1818 lineno=node.lineno, 

1819 col_offset=node.col_offset, 

1820 end_lineno=node.end_lineno, 

1821 end_col_offset=node.end_col_offset, 

1822 parent=parent, 

1823 ) 

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

1825 return newnode 

1826 

1827 def visit_matchsingleton( 

1828 self, node: ast.MatchSingleton, parent: NodeNG 

1829 ) -> nodes.MatchSingleton: 

1830 return nodes.MatchSingleton( 

1831 value=node.value, 

1832 lineno=node.lineno, 

1833 col_offset=node.col_offset, 

1834 end_lineno=node.end_lineno, 

1835 end_col_offset=node.end_col_offset, 

1836 parent=parent, 

1837 ) 

1838 

1839 def visit_matchsequence( 

1840 self, node: ast.MatchSequence, parent: NodeNG 

1841 ) -> nodes.MatchSequence: 

1842 newnode = nodes.MatchSequence( 

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( 

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

1851 ) 

1852 return newnode 

1853 

1854 def visit_matchmapping( 

1855 self, node: ast.MatchMapping, parent: NodeNG 

1856 ) -> nodes.MatchMapping: 

1857 newnode = nodes.MatchMapping( 

1858 lineno=node.lineno, 

1859 col_offset=node.col_offset, 

1860 end_lineno=node.end_lineno, 

1861 end_col_offset=node.end_col_offset, 

1862 parent=parent, 

1863 ) 

1864 # Add AssignName node for 'node.name' 

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

1866 newnode.postinit( 

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

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

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

1870 ) 

1871 return newnode 

1872 

1873 def visit_matchclass( 

1874 self, node: ast.MatchClass, parent: NodeNG 

1875 ) -> nodes.MatchClass: 

1876 newnode = nodes.MatchClass( 

1877 lineno=node.lineno, 

1878 col_offset=node.col_offset, 

1879 end_lineno=node.end_lineno, 

1880 end_col_offset=node.end_col_offset, 

1881 parent=parent, 

1882 ) 

1883 newnode.postinit( 

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

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

1886 kwd_attrs=node.kwd_attrs, 

1887 kwd_patterns=[ 

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

1889 ], 

1890 ) 

1891 return newnode 

1892 

1893 def visit_matchstar( 

1894 self, node: ast.MatchStar, parent: NodeNG 

1895 ) -> nodes.MatchStar: 

1896 newnode = nodes.MatchStar( 

1897 lineno=node.lineno, 

1898 col_offset=node.col_offset, 

1899 end_lineno=node.end_lineno, 

1900 end_col_offset=node.end_col_offset, 

1901 parent=parent, 

1902 ) 

1903 # Add AssignName node for 'node.name' 

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

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

1906 return newnode 

1907 

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

1909 newnode = nodes.MatchAs( 

1910 lineno=node.lineno, 

1911 col_offset=node.col_offset, 

1912 end_lineno=node.end_lineno, 

1913 end_col_offset=node.end_col_offset, 

1914 parent=parent, 

1915 ) 

1916 # Add AssignName node for 'node.name' 

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

1918 newnode.postinit( 

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

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

1921 ) 

1922 return newnode 

1923 

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

1925 newnode = nodes.MatchOr( 

1926 lineno=node.lineno, 

1927 col_offset=node.col_offset, 

1928 end_lineno=node.end_lineno, 

1929 end_col_offset=node.end_col_offset, 

1930 parent=parent, 

1931 ) 

1932 newnode.postinit( 

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

1934 ) 

1935 return newnode