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