Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/astroid/rebuilder.py: 18%
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
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
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
5"""This module contains utilities for rebuilding an _ast tree in
6order to get a single Astroid representation.
7"""
9from __future__ import annotations
11import ast
12import itertools
13import sys
14import token
15from collections.abc import Callable, Collection, Generator
16from io import StringIO
17from tokenize import TokenInfo, generate_tokens
18from typing import TYPE_CHECKING, Final, TypeVar, cast, overload
20from astroid import nodes
21from astroid._ast import ParserModule, get_parser_module, parse_function_type_comment
22from astroid.const import PY312_PLUS, PY313_PLUS, Context
23from astroid.nodes.utils import Position
24from astroid.typing import InferenceResult
26if TYPE_CHECKING:
27 from astroid.manager import AstroidManager
29 T_Doc = TypeVar(
30 "T_Doc",
31 ast.Module,
32 ast.ClassDef,
33 ast.FunctionDef | ast.AsyncFunctionDef,
34 )
35 _FunctionT = TypeVar("_FunctionT", nodes.FunctionDef, nodes.AsyncFunctionDef)
36 _ForT = TypeVar("_ForT", nodes.For, nodes.AsyncFor)
37 _WithT = TypeVar("_WithT", nodes.With, nodes.AsyncWith)
38 NodesWithDocsType = nodes.Module | nodes.ClassDef | nodes.FunctionDef
41REDIRECT: Final[dict[str, str]] = {
42 "arguments": "Arguments",
43 "comprehension": "Comprehension",
44 "ListCompFor": "Comprehension",
45 "GenExprFor": "Comprehension",
46 "excepthandler": "ExceptHandler",
47 "keyword": "Keyword",
48 "match_case": "MatchCase",
49}
52# noinspection PyMethodMayBeStatic
53class TreeRebuilder:
54 """Rebuilds the _ast tree to become an Astroid tree."""
56 def __init__(
57 self,
58 manager: AstroidManager,
59 parser_module: ParserModule | None = None,
60 data: str | None = None,
61 ) -> None:
62 self._manager = manager
63 self._data = data.split("\n") if data else None
64 self._global_names: list[dict[str, list[nodes.Global]]] = []
65 self._import_from_nodes: list[tuple[nodes.ImportFrom, Collection[str]]] = []
66 self._delayed_assattr: list[nodes.AssignAttr] = []
67 self._visit_meths: dict[
68 type[ast.AST], Callable[[ast.AST, nodes.NodeNG], nodes.NodeNG]
69 ] = {}
71 if parser_module is None:
72 self._parser_module = get_parser_module()
73 else:
74 self._parser_module = parser_module
76 def _get_doc(self, node: T_Doc) -> tuple[T_Doc, ast.Constant | None]:
77 """Return the doc ast node."""
78 try:
79 if node.body and isinstance(node.body[0], ast.Expr):
80 first_value = node.body[0].value
81 if isinstance(first_value, ast.Constant) and isinstance(
82 first_value.value, str
83 ):
84 doc_ast_node = first_value
85 node.body = node.body[1:]
86 return node, doc_ast_node
87 except IndexError:
88 pass # ast built from scratch
89 return node, None
91 def _get_context(
92 self,
93 node: (
94 ast.Attribute
95 | ast.List
96 | ast.Name
97 | ast.Subscript
98 | ast.Starred
99 | ast.Tuple
100 ),
101 ) -> Context:
102 return self._parser_module.context_classes.get(type(node.ctx), Context.Load)
104 def _get_position_info(
105 self,
106 node: ast.ClassDef | ast.FunctionDef | ast.AsyncFunctionDef,
107 parent: nodes.ClassDef | nodes.FunctionDef | nodes.AsyncFunctionDef,
108 ) -> Position | None:
109 """Return position information for ClassDef and FunctionDef nodes.
111 In contrast to AST positions, these only include the actual keyword(s)
112 and the class / function name.
114 >>> @decorator
115 >>> async def some_func(var: int) -> None:
116 >>> ^^^^^^^^^^^^^^^^^^^
117 """
118 if not self._data:
119 return None
120 end_lineno = node.end_lineno
121 if node.body:
122 end_lineno = node.body[0].lineno
123 # pylint: disable-next=unsubscriptable-object
124 data = "\n".join(self._data[node.lineno - 1 : end_lineno])
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"
135 for t in generate_tokens(StringIO(data).readline):
136 if (
137 start_token is not None
138 and t.type == token.NAME
139 and t.string == node.name
140 ):
141 break
142 if t.type in keyword_tokens:
143 if t.string == search_token:
144 start_token = t
145 continue
146 if t.string in {"def"}:
147 continue
148 start_token = None
149 else:
150 return None
152 return Position(
153 lineno=node.lineno + start_token.start[0] - 1,
154 col_offset=start_token.start[1],
155 end_lineno=node.lineno + t.end[0] - 1,
156 end_col_offset=t.end[1],
157 )
159 def visit_module(
160 self, node: ast.Module, modname: str, modpath: str, package: bool
161 ) -> nodes.Module:
162 """Visit a Module node by returning a fresh instance of it.
164 Note: Method not called by 'visit'
165 """
166 node, doc_ast_node = self._get_doc(node)
167 newnode = nodes.Module(
168 name=modname,
169 file=modpath,
170 path=[modpath],
171 package=package,
172 )
173 newnode.postinit(
174 [self.visit(child, newnode) for child in node.body],
175 doc_node=self.visit(doc_ast_node, newnode),
176 )
177 return newnode
179 if TYPE_CHECKING: # noqa: C901
181 @overload
182 def visit(self, node: ast.arg, parent: nodes.NodeNG) -> nodes.AssignName: ...
184 @overload
185 def visit(
186 self, node: ast.arguments, parent: nodes.NodeNG
187 ) -> nodes.Arguments: ...
189 @overload
190 def visit(self, node: ast.Assert, parent: nodes.NodeNG) -> nodes.Assert: ...
192 @overload
193 def visit(
194 self, node: ast.AsyncFunctionDef, parent: nodes.NodeNG
195 ) -> nodes.AsyncFunctionDef: ...
197 @overload
198 def visit(self, node: ast.AsyncFor, parent: nodes.NodeNG) -> nodes.AsyncFor: ...
200 @overload
201 def visit(self, node: ast.Await, parent: nodes.NodeNG) -> nodes.Await: ...
203 @overload
204 def visit(
205 self, node: ast.AsyncWith, parent: nodes.NodeNG
206 ) -> nodes.AsyncWith: ...
208 @overload
209 def visit(self, node: ast.Assign, parent: nodes.NodeNG) -> nodes.Assign: ...
211 @overload
212 def visit(
213 self, node: ast.AnnAssign, parent: nodes.NodeNG
214 ) -> nodes.AnnAssign: ...
216 @overload
217 def visit(
218 self, node: ast.AugAssign, parent: nodes.NodeNG
219 ) -> nodes.AugAssign: ...
221 @overload
222 def visit(self, node: ast.BinOp, parent: nodes.NodeNG) -> nodes.BinOp: ...
224 @overload
225 def visit(self, node: ast.BoolOp, parent: nodes.NodeNG) -> nodes.BoolOp: ...
227 @overload
228 def visit(self, node: ast.Break, parent: nodes.NodeNG) -> nodes.Break: ...
230 @overload
231 def visit(self, node: ast.Call, parent: nodes.NodeNG) -> nodes.Call: ...
233 @overload
234 def visit(self, node: ast.ClassDef, parent: nodes.NodeNG) -> nodes.ClassDef: ...
236 @overload
237 def visit(self, node: ast.Continue, parent: nodes.NodeNG) -> nodes.Continue: ...
239 @overload
240 def visit(self, node: ast.Compare, parent: nodes.NodeNG) -> nodes.Compare: ...
242 @overload
243 def visit(
244 self, node: ast.comprehension, parent: nodes.NodeNG
245 ) -> nodes.Comprehension: ...
247 @overload
248 def visit(self, node: ast.Delete, parent: nodes.NodeNG) -> nodes.Delete: ...
250 @overload
251 def visit(self, node: ast.Dict, parent: nodes.NodeNG) -> nodes.Dict: ...
253 @overload
254 def visit(self, node: ast.DictComp, parent: nodes.NodeNG) -> nodes.DictComp: ...
256 @overload
257 def visit(self, node: ast.Expr, parent: nodes.NodeNG) -> nodes.Expr: ...
259 @overload
260 def visit(
261 self, node: ast.ExceptHandler, parent: nodes.NodeNG
262 ) -> nodes.ExceptHandler: ...
264 @overload
265 def visit(self, node: ast.For, parent: nodes.NodeNG) -> nodes.For: ...
267 @overload
268 def visit(
269 self, node: ast.ImportFrom, parent: nodes.NodeNG
270 ) -> nodes.ImportFrom: ...
272 @overload
273 def visit(
274 self, node: ast.FunctionDef, parent: nodes.NodeNG
275 ) -> nodes.FunctionDef: ...
277 @overload
278 def visit(
279 self, node: ast.GeneratorExp, parent: nodes.NodeNG
280 ) -> nodes.GeneratorExp: ...
282 @overload
283 def visit(
284 self, node: ast.Attribute, parent: nodes.NodeNG
285 ) -> nodes.Attribute: ...
287 @overload
288 def visit(self, node: ast.Global, parent: nodes.NodeNG) -> nodes.Global: ...
290 @overload
291 def visit(self, node: ast.If, parent: nodes.NodeNG) -> nodes.If: ...
293 @overload
294 def visit(self, node: ast.IfExp, parent: nodes.NodeNG) -> nodes.IfExp: ...
296 @overload
297 def visit(self, node: ast.Import, parent: nodes.NodeNG) -> nodes.Import: ...
299 @overload
300 def visit(
301 self, node: ast.JoinedStr, parent: nodes.NodeNG
302 ) -> nodes.JoinedStr: ...
304 @overload
305 def visit(
306 self, node: ast.FormattedValue, parent: nodes.NodeNG
307 ) -> nodes.FormattedValue: ...
309 @overload
310 def visit(
311 self, node: ast.NamedExpr, parent: nodes.NodeNG
312 ) -> nodes.NamedExpr: ...
314 @overload
315 def visit(self, node: ast.keyword, parent: nodes.NodeNG) -> nodes.Keyword: ...
317 @overload
318 def visit(self, node: ast.Lambda, parent: nodes.NodeNG) -> nodes.Lambda: ...
320 @overload
321 def visit(self, node: ast.List, parent: nodes.NodeNG) -> nodes.List: ...
323 @overload
324 def visit(self, node: ast.ListComp, parent: nodes.NodeNG) -> nodes.ListComp: ...
326 @overload
327 def visit(
328 self, node: ast.Name, parent: nodes.NodeNG
329 ) -> nodes.Name | nodes.Const | nodes.AssignName | nodes.DelName: ...
331 @overload
332 def visit(self, node: ast.Nonlocal, parent: nodes.NodeNG) -> nodes.Nonlocal: ...
334 @overload
335 def visit(self, node: ast.Constant, parent: nodes.NodeNG) -> nodes.Const: ...
337 if sys.version_info >= (3, 12):
339 @overload
340 def visit(
341 self, node: ast.ParamSpec, parent: nodes.NodeNG
342 ) -> nodes.ParamSpec: ...
344 @overload
345 def visit(self, node: ast.Pass, parent: nodes.NodeNG) -> nodes.Pass: ...
347 @overload
348 def visit(self, node: ast.Raise, parent: nodes.NodeNG) -> nodes.Raise: ...
350 @overload
351 def visit(self, node: ast.Return, parent: nodes.NodeNG) -> nodes.Return: ...
353 @overload
354 def visit(self, node: ast.Set, parent: nodes.NodeNG) -> nodes.Set: ...
356 @overload
357 def visit(self, node: ast.SetComp, parent: nodes.NodeNG) -> nodes.SetComp: ...
359 @overload
360 def visit(self, node: ast.Slice, parent: nodes.Subscript) -> nodes.Slice: ...
362 @overload
363 def visit(
364 self, node: ast.Subscript, parent: nodes.NodeNG
365 ) -> nodes.Subscript: ...
367 @overload
368 def visit(self, node: ast.Starred, parent: nodes.NodeNG) -> nodes.Starred: ...
370 @overload
371 def visit(self, node: ast.Try, parent: nodes.NodeNG) -> nodes.Try: ...
373 if sys.version_info >= (3, 11):
375 @overload
376 def visit(
377 self, node: ast.TryStar, parent: nodes.NodeNG
378 ) -> nodes.TryStar: ...
380 @overload
381 def visit(self, node: ast.Tuple, parent: nodes.NodeNG) -> nodes.Tuple: ...
383 if sys.version_info >= (3, 12):
385 @overload
386 def visit(
387 self, node: ast.TypeAlias, parent: nodes.NodeNG
388 ) -> nodes.TypeAlias: ...
390 @overload
391 def visit(
392 self, node: ast.TypeVar, parent: nodes.NodeNG
393 ) -> nodes.TypeVar: ...
395 @overload
396 def visit(
397 self, node: ast.TypeVarTuple, parent: nodes.NodeNG
398 ) -> nodes.TypeVarTuple: ...
400 @overload
401 def visit(self, node: ast.UnaryOp, parent: nodes.NodeNG) -> nodes.UnaryOp: ...
403 @overload
404 def visit(self, node: ast.While, parent: nodes.NodeNG) -> nodes.While: ...
406 @overload
407 def visit(self, node: ast.With, parent: nodes.NodeNG) -> nodes.With: ...
409 @overload
410 def visit(self, node: ast.Yield, parent: nodes.NodeNG) -> nodes.Yield: ...
412 @overload
413 def visit(
414 self, node: ast.YieldFrom, parent: nodes.NodeNG
415 ) -> nodes.YieldFrom: ...
417 @overload
418 def visit(self, node: ast.Match, parent: nodes.NodeNG) -> nodes.Match: ...
420 @overload
421 def visit(
422 self, node: ast.match_case, parent: nodes.NodeNG
423 ) -> nodes.MatchCase: ...
425 @overload
426 def visit(
427 self, node: ast.MatchValue, parent: nodes.NodeNG
428 ) -> nodes.MatchValue: ...
430 @overload
431 def visit(
432 self, node: ast.MatchSingleton, parent: nodes.NodeNG
433 ) -> nodes.MatchSingleton: ...
435 @overload
436 def visit(
437 self, node: ast.MatchSequence, parent: nodes.NodeNG
438 ) -> nodes.MatchSequence: ...
440 @overload
441 def visit(
442 self, node: ast.MatchMapping, parent: nodes.NodeNG
443 ) -> nodes.MatchMapping: ...
445 @overload
446 def visit(
447 self, node: ast.MatchClass, parent: nodes.NodeNG
448 ) -> nodes.MatchClass: ...
450 @overload
451 def visit(
452 self, node: ast.MatchStar, parent: nodes.NodeNG
453 ) -> nodes.MatchStar: ...
455 @overload
456 def visit(self, node: ast.MatchAs, parent: nodes.NodeNG) -> nodes.MatchAs: ...
458 @overload
459 def visit(self, node: ast.MatchOr, parent: nodes.NodeNG) -> nodes.MatchOr: ...
461 @overload
462 def visit(self, node: ast.pattern, parent: nodes.NodeNG) -> nodes.Pattern: ...
464 if sys.version_info >= (3, 14):
466 @overload
467 def visit(
468 self, node: ast.TemplateStr, parent: nodes.NodeNG
469 ) -> nodes.TemplateStr: ...
471 @overload
472 def visit(
473 self, node: ast.Interpolation, parent: nodes.NodeNG
474 ) -> nodes.Interpolation: ...
476 @overload
477 def visit(self, node: ast.AST, parent: nodes.NodeNG) -> nodes.NodeNG: ...
479 @overload
480 def visit(self, node: None, parent: nodes.NodeNG) -> None: ...
482 def visit(self, node: ast.AST | None, parent: nodes.NodeNG) -> nodes.NodeNG | None:
483 if node is None:
484 return None
485 cls = node.__class__
486 if cls in self._visit_meths:
487 visit_method = self._visit_meths[cls]
488 else:
489 cls_name = cls.__name__
490 visit_name = "visit_" + REDIRECT.get(cls_name, cls_name).lower()
491 visit_method = getattr(self, visit_name)
492 self._visit_meths[cls] = visit_method
493 return visit_method(node, parent)
495 def _save_assignment(self, node: nodes.AssignName | nodes.DelName) -> None:
496 """Save assignment situation since node.parent is not available yet."""
497 if self._global_names and node.name in self._global_names[-1]:
498 node.root().set_local(node.name, node)
499 else:
500 assert node.parent
501 assert node.name
502 node.parent.set_local(node.name, node)
504 def visit_arg(self, node: ast.arg, parent: nodes.NodeNG) -> nodes.AssignName:
505 """Visit an arg node by returning a fresh AssignName instance."""
506 return self.visit_assignname(node, parent, node.arg)
508 def visit_arguments(
509 self, node: ast.arguments, parent: nodes.NodeNG
510 ) -> nodes.Arguments:
511 """Visit an Arguments node by returning a fresh instance of it."""
512 vararg: str | None = None
513 kwarg: str | None = None
514 vararg_node = node.vararg
515 kwarg_node = node.kwarg
517 newnode = nodes.Arguments(
518 node.vararg.arg if node.vararg else None,
519 node.kwarg.arg if node.kwarg else None,
520 parent,
521 (
522 nodes.AssignName(
523 vararg_node.arg,
524 vararg_node.lineno,
525 vararg_node.col_offset,
526 parent,
527 end_lineno=vararg_node.end_lineno,
528 end_col_offset=vararg_node.end_col_offset,
529 )
530 if vararg_node
531 else None
532 ),
533 (
534 nodes.AssignName(
535 kwarg_node.arg,
536 kwarg_node.lineno,
537 kwarg_node.col_offset,
538 parent,
539 end_lineno=kwarg_node.end_lineno,
540 end_col_offset=kwarg_node.end_col_offset,
541 )
542 if kwarg_node
543 else None
544 ),
545 )
546 args = [self.visit(child, newnode) for child in node.args]
547 defaults = [self.visit(child, newnode) for child in node.defaults]
548 varargannotation: nodes.NodeNG | None = None
549 kwargannotation: nodes.NodeNG | None = None
550 if node.vararg:
551 vararg = node.vararg.arg
552 varargannotation = self.visit(node.vararg.annotation, newnode)
553 if node.kwarg:
554 kwarg = node.kwarg.arg
555 kwargannotation = self.visit(node.kwarg.annotation, newnode)
557 kwonlyargs = [self.visit(child, newnode) for child in node.kwonlyargs]
558 kw_defaults = [self.visit(child, newnode) for child in node.kw_defaults]
559 annotations = [self.visit(arg.annotation, newnode) for arg in node.args]
560 kwonlyargs_annotations = [
561 self.visit(arg.annotation, newnode) for arg in node.kwonlyargs
562 ]
564 posonlyargs = [self.visit(child, newnode) for child in node.posonlyargs]
565 posonlyargs_annotations = [
566 self.visit(arg.annotation, newnode) for arg in node.posonlyargs
567 ]
568 type_comment_args = [
569 self.check_type_comment(child, parent=newnode) for child in node.args
570 ]
571 type_comment_kwonlyargs = [
572 self.check_type_comment(child, parent=newnode) for child in node.kwonlyargs
573 ]
574 type_comment_posonlyargs = [
575 self.check_type_comment(child, parent=newnode) for child in node.posonlyargs
576 ]
578 newnode.postinit(
579 args=args,
580 defaults=defaults,
581 kwonlyargs=kwonlyargs,
582 posonlyargs=posonlyargs,
583 kw_defaults=kw_defaults,
584 annotations=annotations,
585 kwonlyargs_annotations=kwonlyargs_annotations,
586 posonlyargs_annotations=posonlyargs_annotations,
587 varargannotation=varargannotation,
588 kwargannotation=kwargannotation,
589 type_comment_args=type_comment_args,
590 type_comment_kwonlyargs=type_comment_kwonlyargs,
591 type_comment_posonlyargs=type_comment_posonlyargs,
592 )
593 if start_end_lineno_pairs := [
594 (arg.lineno, arg.end_lineno)
595 for arg in itertools.chain(
596 node.args, node.posonlyargs, node.kwonlyargs, [node.vararg, node.kwarg]
597 )
598 if arg
599 ]:
600 newnode.lineno = min(startend[0] for startend in start_end_lineno_pairs)
601 newnode.end_lineno = max(startend[1] for startend in start_end_lineno_pairs)
603 # save argument names in locals:
604 assert newnode.parent
605 if vararg:
606 newnode.parent.set_local(vararg, newnode)
607 if kwarg:
608 newnode.parent.set_local(kwarg, newnode)
609 return newnode
611 def visit_assert(self, node: ast.Assert, parent: nodes.NodeNG) -> nodes.Assert:
612 """Visit a Assert node by returning a fresh instance of it."""
613 newnode = nodes.Assert(
614 lineno=node.lineno,
615 col_offset=node.col_offset,
616 end_lineno=node.end_lineno,
617 end_col_offset=node.end_col_offset,
618 parent=parent,
619 )
620 msg: nodes.NodeNG | None = None
621 if node.msg:
622 msg = self.visit(node.msg, newnode)
623 newnode.postinit(self.visit(node.test, newnode), msg)
624 return newnode
626 def check_type_comment(
627 self,
628 node: ast.Assign | ast.arg | ast.For | ast.AsyncFor | ast.With | ast.AsyncWith,
629 parent: (
630 nodes.Assign
631 | nodes.Arguments
632 | nodes.For
633 | nodes.AsyncFor
634 | nodes.With
635 | nodes.AsyncWith
636 ),
637 ) -> nodes.NodeNG | None:
638 if not node.type_comment:
639 return None
641 try:
642 type_comment_ast = self._parser_module.parse(node.type_comment)
643 except SyntaxError:
644 # Invalid type comment, just skip it.
645 return None
647 # For '# type: # any comment' ast.parse returns a Module node,
648 # without any nodes in the body.
649 if not type_comment_ast.body:
650 return None
652 type_object = self.visit(type_comment_ast.body[0], parent=parent)
653 if not isinstance(type_object, nodes.Expr):
654 return None
656 return type_object.value
658 def check_function_type_comment(
659 self, node: ast.FunctionDef | ast.AsyncFunctionDef, parent: nodes.NodeNG
660 ) -> tuple[nodes.NodeNG | None, list[nodes.NodeNG]] | None:
661 if not node.type_comment:
662 return None
664 try:
665 type_comment_ast = parse_function_type_comment(node.type_comment)
666 except SyntaxError:
667 # Invalid type comment, just skip it.
668 return None
670 if not type_comment_ast:
671 return None
673 returns: nodes.NodeNG | None = None
674 argtypes: list[nodes.NodeNG] = [
675 self.visit(elem, parent) for elem in (type_comment_ast.argtypes or [])
676 ]
677 if type_comment_ast.returns:
678 returns = self.visit(type_comment_ast.returns, parent)
680 return returns, argtypes
682 def visit_asyncfunctiondef(
683 self, node: ast.AsyncFunctionDef, parent: nodes.NodeNG
684 ) -> nodes.AsyncFunctionDef:
685 return self._visit_functiondef(nodes.AsyncFunctionDef, node, parent)
687 def visit_asyncfor(
688 self, node: ast.AsyncFor, parent: nodes.NodeNG
689 ) -> nodes.AsyncFor:
690 return self._visit_for(nodes.AsyncFor, node, parent)
692 def visit_await(self, node: ast.Await, parent: nodes.NodeNG) -> nodes.Await:
693 newnode = nodes.Await(
694 lineno=node.lineno,
695 col_offset=node.col_offset,
696 end_lineno=node.end_lineno,
697 end_col_offset=node.end_col_offset,
698 parent=parent,
699 )
700 newnode.postinit(value=self.visit(node.value, newnode))
701 return newnode
703 def visit_asyncwith(
704 self, node: ast.AsyncWith, parent: nodes.NodeNG
705 ) -> nodes.AsyncWith:
706 return self._visit_with(nodes.AsyncWith, node, parent)
708 def visit_assign(self, node: ast.Assign, parent: nodes.NodeNG) -> nodes.Assign:
709 """Visit a Assign node by returning a fresh instance of it."""
710 newnode = nodes.Assign(
711 lineno=node.lineno,
712 col_offset=node.col_offset,
713 end_lineno=node.end_lineno,
714 end_col_offset=node.end_col_offset,
715 parent=parent,
716 )
717 type_annotation = self.check_type_comment(node, parent=newnode)
718 newnode.postinit(
719 targets=[self.visit(child, newnode) for child in node.targets],
720 value=self.visit(node.value, newnode),
721 type_annotation=type_annotation,
722 )
723 return newnode
725 def visit_annassign(
726 self, node: ast.AnnAssign, parent: nodes.NodeNG
727 ) -> nodes.AnnAssign:
728 """Visit an AnnAssign node by returning a fresh instance of it."""
729 newnode = nodes.AnnAssign(
730 lineno=node.lineno,
731 col_offset=node.col_offset,
732 end_lineno=node.end_lineno,
733 end_col_offset=node.end_col_offset,
734 parent=parent,
735 )
736 newnode.postinit(
737 target=self.visit(node.target, newnode),
738 annotation=self.visit(node.annotation, newnode),
739 simple=node.simple,
740 value=self.visit(node.value, newnode),
741 )
742 return newnode
744 @overload
745 def visit_assignname(
746 self, node: ast.AST, parent: nodes.NodeNG, node_name: str
747 ) -> nodes.AssignName: ...
749 @overload
750 def visit_assignname(
751 self, node: ast.AST, parent: nodes.NodeNG, node_name: None
752 ) -> None: ...
754 def visit_assignname(
755 self, node: ast.AST, parent: nodes.NodeNG, node_name: str | None
756 ) -> nodes.AssignName | None:
757 """Visit a node and return a AssignName node.
759 Note: Method not called by 'visit'
760 """
761 if node_name is None:
762 return None
763 newnode = nodes.AssignName(
764 name=node_name,
765 lineno=node.lineno,
766 col_offset=node.col_offset,
767 end_lineno=node.end_lineno,
768 end_col_offset=node.end_col_offset,
769 parent=parent,
770 )
771 self._save_assignment(newnode)
772 return newnode
774 def visit_augassign(
775 self, node: ast.AugAssign, parent: nodes.NodeNG
776 ) -> nodes.AugAssign:
777 """Visit a AugAssign node by returning a fresh instance of it."""
778 newnode = nodes.AugAssign(
779 op=self._parser_module.bin_op_classes[type(node.op)] + "=",
780 lineno=node.lineno,
781 col_offset=node.col_offset,
782 end_lineno=node.end_lineno,
783 end_col_offset=node.end_col_offset,
784 parent=parent,
785 )
786 newnode.postinit(
787 self.visit(node.target, newnode), self.visit(node.value, newnode)
788 )
789 return newnode
791 def visit_binop(self, node: ast.BinOp, parent: nodes.NodeNG) -> nodes.BinOp:
792 """Visit a BinOp node by returning a fresh instance of it."""
793 newnode = nodes.BinOp(
794 op=self._parser_module.bin_op_classes[type(node.op)],
795 lineno=node.lineno,
796 col_offset=node.col_offset,
797 end_lineno=node.end_lineno,
798 end_col_offset=node.end_col_offset,
799 parent=parent,
800 )
801 newnode.postinit(
802 self.visit(node.left, newnode), self.visit(node.right, newnode)
803 )
804 return newnode
806 def visit_boolop(self, node: ast.BoolOp, parent: nodes.NodeNG) -> nodes.BoolOp:
807 """Visit a BoolOp node by returning a fresh instance of it."""
808 newnode = nodes.BoolOp(
809 op=self._parser_module.bool_op_classes[type(node.op)],
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([self.visit(child, newnode) for child in node.values])
817 return newnode
819 def visit_break(self, node: ast.Break, parent: nodes.NodeNG) -> nodes.Break:
820 """Visit a Break node by returning a fresh instance of it."""
821 return nodes.Break(
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 )
829 def visit_call(self, node: ast.Call, parent: nodes.NodeNG) -> nodes.Call:
830 """Visit a CallFunc node by returning a fresh instance of it."""
831 newnode = nodes.Call(
832 lineno=node.lineno,
833 col_offset=node.col_offset,
834 end_lineno=node.end_lineno,
835 end_col_offset=node.end_col_offset,
836 parent=parent,
837 )
838 newnode.postinit(
839 func=self.visit(node.func, newnode),
840 args=[self.visit(child, newnode) for child in node.args],
841 keywords=[self.visit(child, newnode) for child in node.keywords],
842 )
843 return newnode
845 def visit_classdef(
846 self, node: ast.ClassDef, parent: nodes.NodeNG, newstyle: bool = True
847 ) -> nodes.ClassDef:
848 """Visit a ClassDef node to become astroid."""
849 node, doc_ast_node = self._get_doc(node)
850 newnode = nodes.ClassDef(
851 name=node.name,
852 lineno=node.lineno,
853 col_offset=node.col_offset,
854 end_lineno=node.end_lineno,
855 end_col_offset=node.end_col_offset,
856 parent=parent,
857 )
858 metaclass = None
859 for keyword in node.keywords:
860 if keyword.arg == "metaclass":
861 metaclass = self.visit(keyword, newnode).value
862 break
863 decorators = self.visit_decorators(node, newnode)
864 newnode.postinit(
865 [self.visit(child, newnode) for child in node.bases],
866 [self.visit(child, newnode) for child in node.body],
867 decorators,
868 newstyle,
869 metaclass,
870 [
871 self.visit(kwd, newnode)
872 for kwd in node.keywords
873 if kwd.arg != "metaclass"
874 ],
875 position=self._get_position_info(node, newnode),
876 doc_node=self.visit(doc_ast_node, newnode),
877 type_params=(
878 [self.visit(param, newnode) for param in node.type_params]
879 if PY312_PLUS
880 else []
881 ),
882 )
883 parent.set_local(newnode.name, newnode)
884 return newnode
886 def visit_continue(
887 self, node: ast.Continue, parent: nodes.NodeNG
888 ) -> nodes.Continue:
889 """Visit a Continue node by returning a fresh instance of it."""
890 return nodes.Continue(
891 lineno=node.lineno,
892 col_offset=node.col_offset,
893 end_lineno=node.end_lineno,
894 end_col_offset=node.end_col_offset,
895 parent=parent,
896 )
898 def visit_compare(self, node: ast.Compare, parent: nodes.NodeNG) -> nodes.Compare:
899 """Visit a Compare node by returning a fresh instance of it."""
900 newnode = nodes.Compare(
901 lineno=node.lineno,
902 col_offset=node.col_offset,
903 end_lineno=node.end_lineno,
904 end_col_offset=node.end_col_offset,
905 parent=parent,
906 )
907 newnode.postinit(
908 self.visit(node.left, newnode),
909 [
910 (
911 self._parser_module.cmp_op_classes[op.__class__],
912 self.visit(expr, newnode),
913 )
914 for (op, expr) in zip(node.ops, node.comparators)
915 ],
916 )
917 return newnode
919 def visit_comprehension(
920 self, node: ast.comprehension, parent: nodes.NodeNG
921 ) -> nodes.Comprehension:
922 """Visit a Comprehension node by returning a fresh instance of it."""
923 newnode = nodes.Comprehension(
924 parent=parent,
925 # Comprehension nodes don't have these attributes
926 # see https://docs.python.org/3/library/ast.html#abstract-grammar
927 lineno=None,
928 col_offset=None,
929 end_lineno=None,
930 end_col_offset=None,
931 )
932 newnode.postinit(
933 self.visit(node.target, newnode),
934 self.visit(node.iter, newnode),
935 [self.visit(child, newnode) for child in node.ifs],
936 bool(node.is_async),
937 )
938 return newnode
940 def visit_decorators(
941 self,
942 node: ast.ClassDef | ast.FunctionDef | ast.AsyncFunctionDef,
943 parent: nodes.NodeNG,
944 ) -> nodes.Decorators | None:
945 """Visit a Decorators node by returning a fresh instance of it.
947 Note: Method not called by 'visit'
948 """
949 if not node.decorator_list:
950 return None
951 # /!\ node is actually an _ast.FunctionDef node while
952 # parent is an astroid.nodes.FunctionDef node
954 # Set the line number of the first decorator for Python 3.8+.
955 lineno = node.decorator_list[0].lineno
956 end_lineno = node.decorator_list[-1].end_lineno
957 end_col_offset = node.decorator_list[-1].end_col_offset
959 newnode = nodes.Decorators(
960 lineno=lineno,
961 col_offset=node.col_offset,
962 end_lineno=end_lineno,
963 end_col_offset=end_col_offset,
964 parent=parent,
965 )
966 newnode.postinit([self.visit(child, newnode) for child in node.decorator_list])
967 return newnode
969 def visit_delete(self, node: ast.Delete, parent: nodes.NodeNG) -> nodes.Delete:
970 """Visit a Delete node by returning a fresh instance of it."""
971 newnode = nodes.Delete(
972 lineno=node.lineno,
973 col_offset=node.col_offset,
974 end_lineno=node.end_lineno,
975 end_col_offset=node.end_col_offset,
976 parent=parent,
977 )
978 newnode.postinit([self.visit(child, newnode) for child in node.targets])
979 return newnode
981 def _visit_dict_items(
982 self, node: ast.Dict, parent: nodes.NodeNG, newnode: nodes.Dict
983 ) -> Generator[tuple[nodes.NodeNG, nodes.NodeNG]]:
984 for key, value in zip(node.keys, node.values):
985 rebuilt_key: nodes.NodeNG
986 rebuilt_value = self.visit(value, newnode)
987 if not key:
988 # Extended unpacking
989 rebuilt_key = nodes.DictUnpack(
990 lineno=rebuilt_value.lineno,
991 col_offset=rebuilt_value.col_offset,
992 end_lineno=rebuilt_value.end_lineno,
993 end_col_offset=rebuilt_value.end_col_offset,
994 parent=parent,
995 )
996 else:
997 rebuilt_key = self.visit(key, newnode)
998 yield rebuilt_key, rebuilt_value
1000 def visit_dict(self, node: ast.Dict, parent: nodes.NodeNG) -> nodes.Dict:
1001 """Visit a Dict node by returning a fresh instance of it."""
1002 newnode = nodes.Dict(
1003 lineno=node.lineno,
1004 col_offset=node.col_offset,
1005 end_lineno=node.end_lineno,
1006 end_col_offset=node.end_col_offset,
1007 parent=parent,
1008 )
1009 items: list[tuple[InferenceResult, InferenceResult]] = list(
1010 self._visit_dict_items(node, parent, newnode)
1011 )
1012 newnode.postinit(items)
1013 return newnode
1015 def visit_dictcomp(
1016 self, node: ast.DictComp, parent: nodes.NodeNG
1017 ) -> nodes.DictComp:
1018 """Visit a DictComp node by returning a fresh instance of it."""
1019 newnode = nodes.DictComp(
1020 lineno=node.lineno,
1021 col_offset=node.col_offset,
1022 end_lineno=node.end_lineno,
1023 end_col_offset=node.end_col_offset,
1024 parent=parent,
1025 )
1026 newnode.postinit(
1027 self.visit(node.key, newnode),
1028 self.visit(node.value, newnode),
1029 [self.visit(child, newnode) for child in node.generators],
1030 )
1031 return newnode
1033 def visit_expr(self, node: ast.Expr, parent: nodes.NodeNG) -> nodes.Expr:
1034 """Visit a Expr node by returning a fresh instance of it."""
1035 newnode = nodes.Expr(
1036 lineno=node.lineno,
1037 col_offset=node.col_offset,
1038 end_lineno=node.end_lineno,
1039 end_col_offset=node.end_col_offset,
1040 parent=parent,
1041 )
1042 newnode.postinit(self.visit(node.value, newnode))
1043 return newnode
1045 def visit_excepthandler(
1046 self, node: ast.ExceptHandler, parent: nodes.NodeNG
1047 ) -> nodes.ExceptHandler:
1048 """Visit an ExceptHandler node by returning a fresh instance of it."""
1049 newnode = nodes.ExceptHandler(
1050 lineno=node.lineno,
1051 col_offset=node.col_offset,
1052 end_lineno=node.end_lineno,
1053 end_col_offset=node.end_col_offset,
1054 parent=parent,
1055 )
1056 newnode.postinit(
1057 self.visit(node.type, newnode),
1058 self.visit_assignname(node, newnode, node.name),
1059 [self.visit(child, newnode) for child in node.body],
1060 )
1061 return newnode
1063 @overload
1064 def _visit_for(
1065 self, cls: type[nodes.For], node: ast.For, parent: nodes.NodeNG
1066 ) -> nodes.For: ...
1068 @overload
1069 def _visit_for(
1070 self, cls: type[nodes.AsyncFor], node: ast.AsyncFor, parent: nodes.NodeNG
1071 ) -> nodes.AsyncFor: ...
1073 def _visit_for(
1074 self, cls: type[_ForT], node: ast.For | ast.AsyncFor, parent: nodes.NodeNG
1075 ) -> _ForT:
1076 """Visit a For node by returning a fresh instance of it."""
1077 newnode = cls(
1078 lineno=node.lineno,
1079 col_offset=node.col_offset,
1080 end_lineno=node.end_lineno,
1081 end_col_offset=node.end_col_offset,
1082 parent=parent,
1083 )
1084 type_annotation = self.check_type_comment(node, parent=newnode)
1085 newnode.postinit(
1086 target=self.visit(node.target, newnode),
1087 iter=self.visit(node.iter, newnode),
1088 body=[self.visit(child, newnode) for child in node.body],
1089 orelse=[self.visit(child, newnode) for child in node.orelse],
1090 type_annotation=type_annotation,
1091 )
1092 return newnode
1094 def visit_for(self, node: ast.For, parent: nodes.NodeNG) -> nodes.For:
1095 return self._visit_for(nodes.For, node, parent)
1097 def visit_importfrom(
1098 self, node: ast.ImportFrom, parent: nodes.NodeNG
1099 ) -> nodes.ImportFrom:
1100 """Visit an ImportFrom node by returning a fresh instance of it."""
1101 names = [(alias.name, alias.asname) for alias in node.names]
1102 newnode = nodes.ImportFrom(
1103 fromname=node.module or "",
1104 names=names,
1105 level=node.level or None,
1106 lineno=node.lineno,
1107 col_offset=node.col_offset,
1108 end_lineno=node.end_lineno,
1109 end_col_offset=node.end_col_offset,
1110 parent=parent,
1111 )
1112 # store From names to add them to locals after building
1113 self._import_from_nodes.append(
1114 (newnode, self._global_names[-1].keys() if self._global_names else ())
1115 )
1116 return newnode
1118 @overload
1119 def _visit_functiondef(
1120 self, cls: type[nodes.FunctionDef], node: ast.FunctionDef, parent: nodes.NodeNG
1121 ) -> nodes.FunctionDef: ...
1123 @overload
1124 def _visit_functiondef(
1125 self,
1126 cls: type[nodes.AsyncFunctionDef],
1127 node: ast.AsyncFunctionDef,
1128 parent: nodes.NodeNG,
1129 ) -> nodes.AsyncFunctionDef: ...
1131 def _visit_functiondef(
1132 self,
1133 cls: type[_FunctionT],
1134 node: ast.FunctionDef | ast.AsyncFunctionDef,
1135 parent: nodes.NodeNG,
1136 ) -> _FunctionT:
1137 """Visit an FunctionDef node to become astroid."""
1138 self._global_names.append({})
1139 node, doc_ast_node = self._get_doc(node)
1141 lineno = node.lineno
1142 if node.decorator_list:
1143 # Python 3.8 sets the line number of a decorated function
1144 # to be the actual line number of the function, but the
1145 # previous versions expected the decorator's line number instead.
1146 # We reset the function's line number to that of the
1147 # first decorator to maintain backward compatibility.
1148 # It's not ideal but this discrepancy was baked into
1149 # the framework for *years*.
1150 lineno = node.decorator_list[0].lineno
1152 newnode = cls(
1153 name=node.name,
1154 lineno=lineno,
1155 col_offset=node.col_offset,
1156 end_lineno=node.end_lineno,
1157 end_col_offset=node.end_col_offset,
1158 parent=parent,
1159 )
1160 decorators = self.visit_decorators(node, newnode)
1161 returns: nodes.NodeNG | None
1162 if node.returns:
1163 returns = self.visit(node.returns, newnode)
1164 else:
1165 returns = None
1167 type_comment_args = type_comment_returns = None
1168 type_comment_annotation = self.check_function_type_comment(node, newnode)
1169 if type_comment_annotation:
1170 type_comment_returns, type_comment_args = type_comment_annotation
1171 newnode.postinit(
1172 args=self.visit(node.args, newnode),
1173 body=[self.visit(child, newnode) for child in node.body],
1174 decorators=decorators,
1175 returns=returns,
1176 type_comment_returns=type_comment_returns,
1177 type_comment_args=type_comment_args,
1178 position=self._get_position_info(node, newnode),
1179 doc_node=self.visit(doc_ast_node, newnode),
1180 type_params=(
1181 [self.visit(param, newnode) for param in node.type_params]
1182 if PY312_PLUS
1183 else []
1184 ),
1185 )
1186 self._global_names.pop()
1187 parent.set_local(newnode.name, newnode)
1188 return newnode
1190 def visit_functiondef(
1191 self, node: ast.FunctionDef, parent: nodes.NodeNG
1192 ) -> nodes.FunctionDef:
1193 return self._visit_functiondef(nodes.FunctionDef, node, parent)
1195 def visit_generatorexp(
1196 self, node: ast.GeneratorExp, parent: nodes.NodeNG
1197 ) -> nodes.GeneratorExp:
1198 """Visit a GeneratorExp node by returning a fresh instance of it."""
1199 newnode = nodes.GeneratorExp(
1200 lineno=node.lineno,
1201 col_offset=node.col_offset,
1202 end_lineno=node.end_lineno,
1203 end_col_offset=node.end_col_offset,
1204 parent=parent,
1205 )
1206 newnode.postinit(
1207 self.visit(node.elt, newnode),
1208 [self.visit(child, newnode) for child in node.generators],
1209 )
1210 return newnode
1212 def visit_attribute(
1213 self, node: ast.Attribute, parent: nodes.NodeNG
1214 ) -> nodes.Attribute | nodes.AssignAttr | nodes.DelAttr:
1215 """Visit an Attribute node by returning a fresh instance of it."""
1216 context = self._get_context(node)
1217 newnode: nodes.Attribute | nodes.AssignAttr | nodes.DelAttr
1218 if context == Context.Del:
1219 # FIXME : maybe we should reintroduce and visit_delattr ?
1220 # for instance, deactivating assign_ctx
1221 newnode = nodes.DelAttr(
1222 attrname=node.attr,
1223 lineno=node.lineno,
1224 col_offset=node.col_offset,
1225 end_lineno=node.end_lineno,
1226 end_col_offset=node.end_col_offset,
1227 parent=parent,
1228 )
1229 elif context == Context.Store:
1230 newnode = nodes.AssignAttr(
1231 attrname=node.attr,
1232 lineno=node.lineno,
1233 col_offset=node.col_offset,
1234 end_lineno=node.end_lineno,
1235 end_col_offset=node.end_col_offset,
1236 parent=parent,
1237 )
1238 # Prohibit a local save if we are in an ExceptHandler.
1239 if not isinstance(parent, nodes.ExceptHandler):
1240 # mypy doesn't recognize that newnode has to be AssignAttr because it
1241 # doesn't support ParamSpec
1242 # See https://github.com/python/mypy/issues/8645
1243 self._delayed_assattr.append(newnode) # type: ignore[arg-type]
1244 else:
1245 newnode = nodes.Attribute(
1246 attrname=node.attr,
1247 lineno=node.lineno,
1248 col_offset=node.col_offset,
1249 end_lineno=node.end_lineno,
1250 end_col_offset=node.end_col_offset,
1251 parent=parent,
1252 )
1253 newnode.postinit(self.visit(node.value, newnode))
1254 return newnode
1256 def visit_global(self, node: ast.Global, parent: nodes.NodeNG) -> nodes.Global:
1257 """Visit a Global node to become astroid."""
1258 newnode = nodes.Global(
1259 names=node.names,
1260 lineno=node.lineno,
1261 col_offset=node.col_offset,
1262 end_lineno=node.end_lineno,
1263 end_col_offset=node.end_col_offset,
1264 parent=parent,
1265 )
1266 if self._global_names: # global at the module level, no effect
1267 for name in node.names:
1268 self._global_names[-1].setdefault(name, []).append(newnode)
1269 return newnode
1271 def visit_if(self, node: ast.If, parent: nodes.NodeNG) -> nodes.If:
1272 """Visit an If node by returning a fresh instance of it."""
1273 newnode = nodes.If(
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(
1281 self.visit(node.test, newnode),
1282 [self.visit(child, newnode) for child in node.body],
1283 [self.visit(child, newnode) for child in node.orelse],
1284 )
1285 return newnode
1287 def visit_ifexp(self, node: ast.IfExp, parent: nodes.NodeNG) -> nodes.IfExp:
1288 """Visit a IfExp node by returning a fresh instance of it."""
1289 newnode = nodes.IfExp(
1290 lineno=node.lineno,
1291 col_offset=node.col_offset,
1292 end_lineno=node.end_lineno,
1293 end_col_offset=node.end_col_offset,
1294 parent=parent,
1295 )
1296 newnode.postinit(
1297 self.visit(node.test, newnode),
1298 self.visit(node.body, newnode),
1299 self.visit(node.orelse, newnode),
1300 )
1301 return newnode
1303 def visit_import(self, node: ast.Import, parent: nodes.NodeNG) -> nodes.Import:
1304 """Visit a Import node by returning a fresh instance of it."""
1305 names = [(alias.name, alias.asname) for alias in node.names]
1306 newnode = nodes.Import(
1307 names=names,
1308 lineno=node.lineno,
1309 col_offset=node.col_offset,
1310 end_lineno=node.end_lineno,
1311 end_col_offset=node.end_col_offset,
1312 parent=parent,
1313 )
1314 # save import names in parent's locals:
1315 for name, asname in newnode.names:
1316 name = (asname or name).split(".")[0]
1317 if self._global_names and name in self._global_names[-1]:
1318 parent.root().set_local(name, newnode)
1319 else:
1320 parent.set_local(name, newnode)
1321 return newnode
1323 def visit_joinedstr(
1324 self, node: ast.JoinedStr, parent: nodes.NodeNG
1325 ) -> nodes.JoinedStr:
1326 newnode = nodes.JoinedStr(
1327 lineno=node.lineno,
1328 col_offset=node.col_offset,
1329 end_lineno=node.end_lineno,
1330 end_col_offset=node.end_col_offset,
1331 parent=parent,
1332 )
1333 newnode.postinit([self.visit(child, newnode) for child in node.values])
1334 return newnode
1336 def visit_formattedvalue(
1337 self, node: ast.FormattedValue, parent: nodes.NodeNG
1338 ) -> nodes.FormattedValue:
1339 newnode = nodes.FormattedValue(
1340 lineno=node.lineno,
1341 col_offset=node.col_offset,
1342 end_lineno=node.end_lineno,
1343 end_col_offset=node.end_col_offset,
1344 parent=parent,
1345 )
1346 newnode.postinit(
1347 value=self.visit(node.value, newnode),
1348 conversion=node.conversion,
1349 format_spec=self.visit(node.format_spec, newnode),
1350 )
1351 return newnode
1353 def visit_namedexpr(
1354 self, node: ast.NamedExpr, parent: nodes.NodeNG
1355 ) -> nodes.NamedExpr:
1356 newnode = nodes.NamedExpr(
1357 lineno=node.lineno,
1358 col_offset=node.col_offset,
1359 end_lineno=node.end_lineno,
1360 end_col_offset=node.end_col_offset,
1361 parent=parent,
1362 )
1363 newnode.postinit(
1364 self.visit(node.target, newnode), self.visit(node.value, newnode)
1365 )
1366 return newnode
1368 def visit_keyword(self, node: ast.keyword, parent: nodes.NodeNG) -> nodes.Keyword:
1369 """Visit a Keyword node by returning a fresh instance of it."""
1370 newnode = nodes.Keyword(
1371 arg=node.arg,
1372 # position attributes added in 3.9
1373 lineno=getattr(node, "lineno", None),
1374 col_offset=getattr(node, "col_offset", None),
1375 end_lineno=getattr(node, "end_lineno", None),
1376 end_col_offset=getattr(node, "end_col_offset", None),
1377 parent=parent,
1378 )
1379 newnode.postinit(self.visit(node.value, newnode))
1380 return newnode
1382 def visit_lambda(self, node: ast.Lambda, parent: nodes.NodeNG) -> nodes.Lambda:
1383 """Visit a Lambda node by returning a fresh instance of it."""
1384 newnode = nodes.Lambda(
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(self.visit(node.args, newnode), self.visit(node.body, newnode))
1392 return newnode
1394 def visit_list(self, node: ast.List, parent: nodes.NodeNG) -> nodes.List:
1395 """Visit a List node by returning a fresh instance of it."""
1396 context = self._get_context(node)
1397 newnode = nodes.List(
1398 ctx=context,
1399 lineno=node.lineno,
1400 col_offset=node.col_offset,
1401 end_lineno=node.end_lineno,
1402 end_col_offset=node.end_col_offset,
1403 parent=parent,
1404 )
1405 newnode.postinit([self.visit(child, newnode) for child in node.elts])
1406 return newnode
1408 def visit_listcomp(
1409 self, node: ast.ListComp, parent: nodes.NodeNG
1410 ) -> nodes.ListComp:
1411 """Visit a ListComp node by returning a fresh instance of it."""
1412 newnode = nodes.ListComp(
1413 lineno=node.lineno,
1414 col_offset=node.col_offset,
1415 end_lineno=node.end_lineno,
1416 end_col_offset=node.end_col_offset,
1417 parent=parent,
1418 )
1419 newnode.postinit(
1420 self.visit(node.elt, newnode),
1421 [self.visit(child, newnode) for child in node.generators],
1422 )
1423 return newnode
1425 def visit_name(
1426 self, node: ast.Name, parent: nodes.NodeNG
1427 ) -> nodes.Name | nodes.AssignName | nodes.DelName:
1428 """Visit a Name node by returning a fresh instance of it."""
1429 context = self._get_context(node)
1430 newnode: nodes.Name | nodes.AssignName | nodes.DelName
1431 if context == Context.Del:
1432 newnode = nodes.DelName(
1433 name=node.id,
1434 lineno=node.lineno,
1435 col_offset=node.col_offset,
1436 end_lineno=node.end_lineno,
1437 end_col_offset=node.end_col_offset,
1438 parent=parent,
1439 )
1440 elif context == Context.Store:
1441 newnode = nodes.AssignName(
1442 name=node.id,
1443 lineno=node.lineno,
1444 col_offset=node.col_offset,
1445 end_lineno=node.end_lineno,
1446 end_col_offset=node.end_col_offset,
1447 parent=parent,
1448 )
1449 else:
1450 newnode = nodes.Name(
1451 name=node.id,
1452 lineno=node.lineno,
1453 col_offset=node.col_offset,
1454 end_lineno=node.end_lineno,
1455 end_col_offset=node.end_col_offset,
1456 parent=parent,
1457 )
1458 # XXX REMOVE me :
1459 if context in (Context.Del, Context.Store): # 'Aug' ??
1460 newnode = cast((nodes.AssignName | nodes.DelName), newnode)
1461 self._save_assignment(newnode)
1462 return newnode
1464 def visit_nonlocal(
1465 self, node: ast.Nonlocal, parent: nodes.NodeNG
1466 ) -> nodes.Nonlocal:
1467 """Visit a Nonlocal node and return a new instance of it."""
1468 return nodes.Nonlocal(
1469 names=node.names,
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 )
1477 def visit_constant(self, node: ast.Constant, parent: nodes.NodeNG) -> nodes.Const:
1478 """Visit a Constant node by returning a fresh instance of Const."""
1479 return nodes.Const(
1480 value=node.value,
1481 kind=node.kind,
1482 lineno=node.lineno,
1483 col_offset=node.col_offset,
1484 end_lineno=node.end_lineno,
1485 end_col_offset=node.end_col_offset,
1486 parent=parent,
1487 )
1489 def visit_paramspec(
1490 self, node: ast.ParamSpec, parent: nodes.NodeNG
1491 ) -> nodes.ParamSpec:
1492 """Visit a ParamSpec node by returning a fresh instance of it."""
1493 newnode = nodes.ParamSpec(
1494 lineno=node.lineno,
1495 col_offset=node.col_offset,
1496 end_lineno=node.end_lineno,
1497 end_col_offset=node.end_col_offset,
1498 parent=parent,
1499 )
1500 # Add AssignName node for 'node.name'
1501 # https://bugs.python.org/issue43994
1502 newnode.postinit(
1503 name=self.visit_assignname(node, newnode, node.name),
1504 default_value=(
1505 self.visit(node.default_value, newnode) if PY313_PLUS else None
1506 ),
1507 )
1508 return newnode
1510 def visit_pass(self, node: ast.Pass, parent: nodes.NodeNG) -> nodes.Pass:
1511 """Visit a Pass node by returning a fresh instance of it."""
1512 return nodes.Pass(
1513 lineno=node.lineno,
1514 col_offset=node.col_offset,
1515 end_lineno=node.end_lineno,
1516 end_col_offset=node.end_col_offset,
1517 parent=parent,
1518 )
1520 def visit_raise(self, node: ast.Raise, parent: nodes.NodeNG) -> nodes.Raise:
1521 """Visit a Raise node by returning a fresh instance of it."""
1522 newnode = nodes.Raise(
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 # no traceback; anyway it is not used in Pylint
1530 newnode.postinit(
1531 exc=self.visit(node.exc, newnode),
1532 cause=self.visit(node.cause, newnode),
1533 )
1534 return newnode
1536 def visit_return(self, node: ast.Return, parent: nodes.NodeNG) -> nodes.Return:
1537 """Visit a Return node by returning a fresh instance of it."""
1538 newnode = nodes.Return(
1539 lineno=node.lineno,
1540 col_offset=node.col_offset,
1541 end_lineno=node.end_lineno,
1542 end_col_offset=node.end_col_offset,
1543 parent=parent,
1544 )
1545 newnode.postinit(self.visit(node.value, newnode))
1546 return newnode
1548 def visit_set(self, node: ast.Set, parent: nodes.NodeNG) -> nodes.Set:
1549 """Visit a Set node by returning a fresh instance of it."""
1550 newnode = nodes.Set(
1551 lineno=node.lineno,
1552 col_offset=node.col_offset,
1553 end_lineno=node.end_lineno,
1554 end_col_offset=node.end_col_offset,
1555 parent=parent,
1556 )
1557 newnode.postinit([self.visit(child, newnode) for child in node.elts])
1558 return newnode
1560 def visit_setcomp(self, node: ast.SetComp, parent: nodes.NodeNG) -> nodes.SetComp:
1561 """Visit a SetComp node by returning a fresh instance of it."""
1562 newnode = nodes.SetComp(
1563 lineno=node.lineno,
1564 col_offset=node.col_offset,
1565 end_lineno=node.end_lineno,
1566 end_col_offset=node.end_col_offset,
1567 parent=parent,
1568 )
1569 newnode.postinit(
1570 self.visit(node.elt, newnode),
1571 [self.visit(child, newnode) for child in node.generators],
1572 )
1573 return newnode
1575 def visit_slice(self, node: ast.Slice, parent: nodes.Subscript) -> nodes.Slice:
1576 """Visit a Slice node by returning a fresh instance of it."""
1577 newnode = nodes.Slice(
1578 # position attributes added in 3.9
1579 lineno=getattr(node, "lineno", None),
1580 col_offset=getattr(node, "col_offset", None),
1581 end_lineno=getattr(node, "end_lineno", None),
1582 end_col_offset=getattr(node, "end_col_offset", None),
1583 parent=parent,
1584 )
1585 newnode.postinit(
1586 lower=self.visit(node.lower, newnode),
1587 upper=self.visit(node.upper, newnode),
1588 step=self.visit(node.step, newnode),
1589 )
1590 return newnode
1592 def visit_subscript(
1593 self, node: ast.Subscript, parent: nodes.NodeNG
1594 ) -> nodes.Subscript:
1595 """Visit a Subscript node by returning a fresh instance of it."""
1596 context = self._get_context(node)
1597 newnode = nodes.Subscript(
1598 ctx=context,
1599 lineno=node.lineno,
1600 col_offset=node.col_offset,
1601 end_lineno=node.end_lineno,
1602 end_col_offset=node.end_col_offset,
1603 parent=parent,
1604 )
1605 newnode.postinit(
1606 self.visit(node.value, newnode), self.visit(node.slice, newnode)
1607 )
1608 return newnode
1610 def visit_starred(self, node: ast.Starred, parent: nodes.NodeNG) -> nodes.Starred:
1611 """Visit a Starred node and return a new instance of it."""
1612 context = self._get_context(node)
1613 newnode = nodes.Starred(
1614 ctx=context,
1615 lineno=node.lineno,
1616 col_offset=node.col_offset,
1617 end_lineno=node.end_lineno,
1618 end_col_offset=node.end_col_offset,
1619 parent=parent,
1620 )
1621 newnode.postinit(self.visit(node.value, newnode))
1622 return newnode
1624 def visit_try(self, node: ast.Try, parent: nodes.NodeNG) -> nodes.Try:
1625 """Visit a Try node by returning a fresh instance of it"""
1626 newnode = nodes.Try(
1627 lineno=node.lineno,
1628 col_offset=node.col_offset,
1629 end_lineno=node.end_lineno,
1630 end_col_offset=node.end_col_offset,
1631 parent=parent,
1632 )
1633 newnode.postinit(
1634 body=[self.visit(child, newnode) for child in node.body],
1635 handlers=[self.visit(child, newnode) for child in node.handlers],
1636 orelse=[self.visit(child, newnode) for child in node.orelse],
1637 finalbody=[self.visit(child, newnode) for child in node.finalbody],
1638 )
1639 return newnode
1641 def visit_trystar(self, node: ast.TryStar, parent: nodes.NodeNG) -> nodes.TryStar:
1642 newnode = nodes.TryStar(
1643 lineno=node.lineno,
1644 col_offset=node.col_offset,
1645 end_lineno=node.end_lineno,
1646 end_col_offset=node.end_col_offset,
1647 parent=parent,
1648 )
1649 newnode.postinit(
1650 body=[self.visit(n, newnode) for n in node.body],
1651 handlers=[self.visit(n, newnode) for n in node.handlers],
1652 orelse=[self.visit(n, newnode) for n in node.orelse],
1653 finalbody=[self.visit(n, newnode) for n in node.finalbody],
1654 )
1655 return newnode
1657 def visit_tuple(self, node: ast.Tuple, parent: nodes.NodeNG) -> nodes.Tuple:
1658 """Visit a Tuple node by returning a fresh instance of it."""
1659 context = self._get_context(node)
1660 newnode = nodes.Tuple(
1661 ctx=context,
1662 lineno=node.lineno,
1663 col_offset=node.col_offset,
1664 end_lineno=node.end_lineno,
1665 end_col_offset=node.end_col_offset,
1666 parent=parent,
1667 )
1668 newnode.postinit([self.visit(child, newnode) for child in node.elts])
1669 return newnode
1671 def visit_typealias(
1672 self, node: ast.TypeAlias, parent: nodes.NodeNG
1673 ) -> nodes.TypeAlias:
1674 """Visit a TypeAlias node by returning a fresh instance of it."""
1675 newnode = nodes.TypeAlias(
1676 lineno=node.lineno,
1677 col_offset=node.col_offset,
1678 end_lineno=node.end_lineno,
1679 end_col_offset=node.end_col_offset,
1680 parent=parent,
1681 )
1682 newnode.postinit(
1683 name=self.visit(node.name, newnode),
1684 type_params=[self.visit(p, newnode) for p in node.type_params],
1685 value=self.visit(node.value, newnode),
1686 )
1687 return newnode
1689 def visit_typevar(self, node: ast.TypeVar, parent: nodes.NodeNG) -> nodes.TypeVar:
1690 """Visit a TypeVar node by returning a fresh instance of it."""
1691 newnode = nodes.TypeVar(
1692 lineno=node.lineno,
1693 col_offset=node.col_offset,
1694 end_lineno=node.end_lineno,
1695 end_col_offset=node.end_col_offset,
1696 parent=parent,
1697 )
1698 # Add AssignName node for 'node.name'
1699 # https://bugs.python.org/issue43994
1700 newnode.postinit(
1701 name=self.visit_assignname(node, newnode, node.name),
1702 bound=self.visit(node.bound, newnode),
1703 default_value=(
1704 self.visit(node.default_value, newnode) if PY313_PLUS else None
1705 ),
1706 )
1707 return newnode
1709 def visit_typevartuple(
1710 self, node: ast.TypeVarTuple, parent: nodes.NodeNG
1711 ) -> nodes.TypeVarTuple:
1712 """Visit a TypeVarTuple node by returning a fresh instance of it."""
1713 newnode = nodes.TypeVarTuple(
1714 lineno=node.lineno,
1715 col_offset=node.col_offset,
1716 end_lineno=node.end_lineno,
1717 end_col_offset=node.end_col_offset,
1718 parent=parent,
1719 )
1720 # Add AssignName node for 'node.name'
1721 # https://bugs.python.org/issue43994
1722 newnode.postinit(
1723 name=self.visit_assignname(node, newnode, node.name),
1724 default_value=(
1725 self.visit(node.default_value, newnode) if PY313_PLUS else None
1726 ),
1727 )
1728 return newnode
1730 def visit_unaryop(self, node: ast.UnaryOp, parent: nodes.NodeNG) -> nodes.UnaryOp:
1731 """Visit a UnaryOp node by returning a fresh instance of it."""
1732 newnode = nodes.UnaryOp(
1733 op=self._parser_module.unary_op_classes[node.op.__class__],
1734 lineno=node.lineno,
1735 col_offset=node.col_offset,
1736 end_lineno=node.end_lineno,
1737 end_col_offset=node.end_col_offset,
1738 parent=parent,
1739 )
1740 newnode.postinit(self.visit(node.operand, newnode))
1741 return newnode
1743 def visit_while(self, node: ast.While, parent: nodes.NodeNG) -> nodes.While:
1744 """Visit a While node by returning a fresh instance of it."""
1745 newnode = nodes.While(
1746 lineno=node.lineno,
1747 col_offset=node.col_offset,
1748 end_lineno=node.end_lineno,
1749 end_col_offset=node.end_col_offset,
1750 parent=parent,
1751 )
1752 newnode.postinit(
1753 self.visit(node.test, newnode),
1754 [self.visit(child, newnode) for child in node.body],
1755 [self.visit(child, newnode) for child in node.orelse],
1756 )
1757 return newnode
1759 @overload
1760 def _visit_with(
1761 self, cls: type[nodes.With], node: ast.With, parent: nodes.NodeNG
1762 ) -> nodes.With: ...
1764 @overload
1765 def _visit_with(
1766 self, cls: type[nodes.AsyncWith], node: ast.AsyncWith, parent: nodes.NodeNG
1767 ) -> nodes.AsyncWith: ...
1769 def _visit_with(
1770 self,
1771 cls: type[_WithT],
1772 node: ast.With | ast.AsyncWith,
1773 parent: nodes.NodeNG,
1774 ) -> _WithT:
1775 newnode = cls(
1776 lineno=node.lineno,
1777 col_offset=node.col_offset,
1778 end_lineno=node.end_lineno,
1779 end_col_offset=node.end_col_offset,
1780 parent=parent,
1781 )
1783 def visit_child(
1784 child: ast.withitem,
1785 ) -> tuple[nodes.NodeNG, nodes.NodeNG | None]:
1786 expr = self.visit(child.context_expr, newnode)
1787 var = self.visit(child.optional_vars, newnode)
1788 return expr, var
1790 type_annotation = self.check_type_comment(node, parent=newnode)
1791 newnode.postinit(
1792 items=[visit_child(child) for child in node.items],
1793 body=[self.visit(child, newnode) for child in node.body],
1794 type_annotation=type_annotation,
1795 )
1796 return newnode
1798 def visit_with(self, node: ast.With, parent: nodes.NodeNG) -> nodes.NodeNG:
1799 return self._visit_with(nodes.With, node, parent)
1801 def visit_yield(self, node: ast.Yield, parent: nodes.NodeNG) -> nodes.NodeNG:
1802 """Visit a Yield node by returning a fresh instance of it."""
1803 newnode = nodes.Yield(
1804 lineno=node.lineno,
1805 col_offset=node.col_offset,
1806 end_lineno=node.end_lineno,
1807 end_col_offset=node.end_col_offset,
1808 parent=parent,
1809 )
1810 newnode.postinit(self.visit(node.value, newnode))
1811 return newnode
1813 def visit_yieldfrom(
1814 self, node: ast.YieldFrom, parent: nodes.NodeNG
1815 ) -> nodes.NodeNG:
1816 newnode = nodes.YieldFrom(
1817 lineno=node.lineno,
1818 col_offset=node.col_offset,
1819 end_lineno=node.end_lineno,
1820 end_col_offset=node.end_col_offset,
1821 parent=parent,
1822 )
1823 newnode.postinit(self.visit(node.value, newnode))
1824 return newnode
1826 def visit_match(self, node: ast.Match, parent: nodes.NodeNG) -> nodes.Match:
1827 newnode = nodes.Match(
1828 lineno=node.lineno,
1829 col_offset=node.col_offset,
1830 end_lineno=node.end_lineno,
1831 end_col_offset=node.end_col_offset,
1832 parent=parent,
1833 )
1834 newnode.postinit(
1835 subject=self.visit(node.subject, newnode),
1836 cases=[self.visit(case, newnode) for case in node.cases],
1837 )
1838 return newnode
1840 def visit_matchcase(
1841 self, node: ast.match_case, parent: nodes.NodeNG
1842 ) -> nodes.MatchCase:
1843 newnode = nodes.MatchCase(parent=parent)
1844 newnode.postinit(
1845 pattern=self.visit(node.pattern, newnode),
1846 guard=self.visit(node.guard, newnode),
1847 body=[self.visit(child, newnode) for child in node.body],
1848 )
1849 return newnode
1851 def visit_matchvalue(
1852 self, node: ast.MatchValue, parent: nodes.NodeNG
1853 ) -> nodes.MatchValue:
1854 newnode = nodes.MatchValue(
1855 lineno=node.lineno,
1856 col_offset=node.col_offset,
1857 end_lineno=node.end_lineno,
1858 end_col_offset=node.end_col_offset,
1859 parent=parent,
1860 )
1861 newnode.postinit(value=self.visit(node.value, newnode))
1862 return newnode
1864 def visit_matchsingleton(
1865 self, node: ast.MatchSingleton, parent: nodes.NodeNG
1866 ) -> nodes.MatchSingleton:
1867 return nodes.MatchSingleton(
1868 value=node.value,
1869 lineno=node.lineno,
1870 col_offset=node.col_offset,
1871 end_lineno=node.end_lineno,
1872 end_col_offset=node.end_col_offset,
1873 parent=parent,
1874 )
1876 def visit_matchsequence(
1877 self, node: ast.MatchSequence, parent: nodes.NodeNG
1878 ) -> nodes.MatchSequence:
1879 newnode = nodes.MatchSequence(
1880 lineno=node.lineno,
1881 col_offset=node.col_offset,
1882 end_lineno=node.end_lineno,
1883 end_col_offset=node.end_col_offset,
1884 parent=parent,
1885 )
1886 newnode.postinit(
1887 patterns=[self.visit(pattern, newnode) for pattern in node.patterns]
1888 )
1889 return newnode
1891 def visit_matchmapping(
1892 self, node: ast.MatchMapping, parent: nodes.NodeNG
1893 ) -> nodes.MatchMapping:
1894 newnode = nodes.MatchMapping(
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 # Add AssignName node for 'node.name'
1902 # https://bugs.python.org/issue43994
1903 newnode.postinit(
1904 keys=[self.visit(child, newnode) for child in node.keys],
1905 patterns=[self.visit(pattern, newnode) for pattern in node.patterns],
1906 rest=self.visit_assignname(node, newnode, node.rest),
1907 )
1908 return newnode
1910 def visit_matchclass(
1911 self, node: ast.MatchClass, parent: nodes.NodeNG
1912 ) -> nodes.MatchClass:
1913 newnode = nodes.MatchClass(
1914 lineno=node.lineno,
1915 col_offset=node.col_offset,
1916 end_lineno=node.end_lineno,
1917 end_col_offset=node.end_col_offset,
1918 parent=parent,
1919 )
1920 newnode.postinit(
1921 cls=self.visit(node.cls, newnode),
1922 patterns=[self.visit(pattern, newnode) for pattern in node.patterns],
1923 kwd_attrs=node.kwd_attrs,
1924 kwd_patterns=[
1925 self.visit(pattern, newnode) for pattern in node.kwd_patterns
1926 ],
1927 )
1928 return newnode
1930 def visit_matchstar(
1931 self, node: ast.MatchStar, parent: nodes.NodeNG
1932 ) -> nodes.MatchStar:
1933 newnode = nodes.MatchStar(
1934 lineno=node.lineno,
1935 col_offset=node.col_offset,
1936 end_lineno=node.end_lineno,
1937 end_col_offset=node.end_col_offset,
1938 parent=parent,
1939 )
1940 # Add AssignName node for 'node.name'
1941 # https://bugs.python.org/issue43994
1942 newnode.postinit(name=self.visit_assignname(node, newnode, node.name))
1943 return newnode
1945 def visit_matchas(self, node: ast.MatchAs, parent: nodes.NodeNG) -> nodes.MatchAs:
1946 newnode = nodes.MatchAs(
1947 lineno=node.lineno,
1948 col_offset=node.col_offset,
1949 end_lineno=node.end_lineno,
1950 end_col_offset=node.end_col_offset,
1951 parent=parent,
1952 )
1953 # Add AssignName node for 'node.name'
1954 # https://bugs.python.org/issue43994
1955 newnode.postinit(
1956 pattern=self.visit(node.pattern, newnode),
1957 name=self.visit_assignname(node, newnode, node.name),
1958 )
1959 return newnode
1961 def visit_matchor(self, node: ast.MatchOr, parent: nodes.NodeNG) -> nodes.MatchOr:
1962 newnode = nodes.MatchOr(
1963 lineno=node.lineno,
1964 col_offset=node.col_offset,
1965 end_lineno=node.end_lineno,
1966 end_col_offset=node.end_col_offset,
1967 parent=parent,
1968 )
1969 newnode.postinit(
1970 patterns=[self.visit(pattern, newnode) for pattern in node.patterns]
1971 )
1972 return newnode
1974 if sys.version_info >= (3, 14):
1976 def visit_templatestr(
1977 self, node: ast.TemplateStr, parent: nodes.NodeNG
1978 ) -> nodes.TemplateStr:
1979 newnode = nodes.TemplateStr(
1980 lineno=node.lineno,
1981 col_offset=node.col_offset,
1982 end_lineno=node.end_lineno,
1983 end_col_offset=node.end_col_offset,
1984 parent=parent,
1985 )
1986 newnode.postinit(
1987 values=[self.visit(value, newnode) for value in node.values]
1988 )
1989 return newnode
1991 def visit_interpolation(
1992 self, node: ast.Interpolation, parent: nodes.NodeNG
1993 ) -> nodes.Interpolation:
1994 newnode = nodes.Interpolation(
1995 lineno=node.lineno,
1996 col_offset=node.col_offset,
1997 end_lineno=node.end_lineno,
1998 end_col_offset=node.end_col_offset,
1999 parent=parent,
2000 )
2001 newnode.postinit(
2002 value=self.visit(node.value, parent),
2003 str=node.str,
2004 conversion=node.conversion,
2005 format_spec=self.visit(node.format_spec, parent),
2006 )
2007 return newnode