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 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 data = "\n".join(self._data[node.lineno - 1 : end_lineno])
125 start_token: TokenInfo | None = None
126 keyword_tokens: tuple[int, ...] = (token.NAME,)
127 if isinstance(parent, nodes.AsyncFunctionDef):
128 search_token = "async"
129 elif isinstance(parent, nodes.FunctionDef):
130 search_token = "def"
131 else:
132 search_token = "class"
134 try:
135 for t in generate_tokens(StringIO(data).readline):
136 if (
137 start_token is not None
138 and t.type == token.NAME
139 and t.string == node.name
140 ):
141 break
142 if t.type in keyword_tokens:
143 if t.string == search_token:
144 start_token = t
145 continue
146 if t.string in {"def"}:
147 continue
148 start_token = None
149 else:
150 return None
151 except (TokenError, SyntaxError):
152 # ``generate_tokens`` can raise on input it cannot tokenize, e.g.
153 # ``TokenError`` for an unterminated bracket on Python < 3.12, or
154 # ``IndentationError`` when ``\r``-terminated lines make the slice
155 # of ``self._data`` (split on ``\n`` only) misaligned with the AST
156 # line numbers; no position info then.
157 return None
159 return Position(
160 lineno=node.lineno + start_token.start[0] - 1,
161 col_offset=start_token.start[1],
162 end_lineno=node.lineno + t.end[0] - 1,
163 end_col_offset=t.end[1],
164 )
166 def visit_module(
167 self, node: ast.Module, modname: str, modpath: str, package: bool
168 ) -> nodes.Module:
169 """Visit a Module node by returning a fresh instance of it.
171 Note: Method not called by 'visit'
172 """
173 node, doc_ast_node = self._get_doc(node)
174 newnode = nodes.Module(
175 name=modname,
176 file=modpath,
177 path=[modpath],
178 package=package,
179 )
180 newnode.postinit(
181 [self.visit(child, newnode) for child in node.body],
182 doc_node=self.visit(doc_ast_node, newnode),
183 )
184 return newnode
186 if TYPE_CHECKING: # noqa: C901
188 @overload
189 def visit(self, node: ast.arg, parent: nodes.NodeNG) -> nodes.AssignName: ...
191 @overload
192 def visit(
193 self, node: ast.arguments, parent: nodes.NodeNG
194 ) -> nodes.Arguments: ...
196 @overload
197 def visit(self, node: ast.Assert, parent: nodes.NodeNG) -> nodes.Assert: ...
199 @overload
200 def visit(
201 self, node: ast.AsyncFunctionDef, parent: nodes.NodeNG
202 ) -> nodes.AsyncFunctionDef: ...
204 @overload
205 def visit(self, node: ast.AsyncFor, parent: nodes.NodeNG) -> nodes.AsyncFor: ...
207 @overload
208 def visit(self, node: ast.Await, parent: nodes.NodeNG) -> nodes.Await: ...
210 @overload
211 def visit(
212 self, node: ast.AsyncWith, parent: nodes.NodeNG
213 ) -> nodes.AsyncWith: ...
215 @overload
216 def visit(self, node: ast.Assign, parent: nodes.NodeNG) -> nodes.Assign: ...
218 @overload
219 def visit(
220 self, node: ast.AnnAssign, parent: nodes.NodeNG
221 ) -> nodes.AnnAssign: ...
223 @overload
224 def visit(
225 self, node: ast.AugAssign, parent: nodes.NodeNG
226 ) -> nodes.AugAssign: ...
228 @overload
229 def visit(self, node: ast.BinOp, parent: nodes.NodeNG) -> nodes.BinOp: ...
231 @overload
232 def visit(self, node: ast.BoolOp, parent: nodes.NodeNG) -> nodes.BoolOp: ...
234 @overload
235 def visit(self, node: ast.Break, parent: nodes.NodeNG) -> nodes.Break: ...
237 @overload
238 def visit(self, node: ast.Call, parent: nodes.NodeNG) -> nodes.Call: ...
240 @overload
241 def visit(self, node: ast.ClassDef, parent: nodes.NodeNG) -> nodes.ClassDef: ...
243 @overload
244 def visit(self, node: ast.Continue, parent: nodes.NodeNG) -> nodes.Continue: ...
246 @overload
247 def visit(self, node: ast.Compare, parent: nodes.NodeNG) -> nodes.Compare: ...
249 @overload
250 def visit(
251 self, node: ast.comprehension, parent: nodes.NodeNG
252 ) -> nodes.Comprehension: ...
254 @overload
255 def visit(self, node: ast.Delete, parent: nodes.NodeNG) -> nodes.Delete: ...
257 @overload
258 def visit(self, node: ast.Dict, parent: nodes.NodeNG) -> nodes.Dict: ...
260 @overload
261 def visit(self, node: ast.DictComp, parent: nodes.NodeNG) -> nodes.DictComp: ...
263 @overload
264 def visit(self, node: ast.Expr, parent: nodes.NodeNG) -> nodes.Expr: ...
266 @overload
267 def visit(
268 self, node: ast.ExceptHandler, parent: nodes.NodeNG
269 ) -> nodes.ExceptHandler: ...
271 @overload
272 def visit(self, node: ast.For, parent: nodes.NodeNG) -> nodes.For: ...
274 @overload
275 def visit(
276 self, node: ast.ImportFrom, parent: nodes.NodeNG
277 ) -> nodes.ImportFrom: ...
279 @overload
280 def visit(
281 self, node: ast.FunctionDef, parent: nodes.NodeNG
282 ) -> nodes.FunctionDef: ...
284 @overload
285 def visit(
286 self, node: ast.GeneratorExp, parent: nodes.NodeNG
287 ) -> nodes.GeneratorExp: ...
289 @overload
290 def visit(
291 self, node: ast.Attribute, parent: nodes.NodeNG
292 ) -> nodes.Attribute: ...
294 @overload
295 def visit(self, node: ast.Global, parent: nodes.NodeNG) -> nodes.Global: ...
297 @overload
298 def visit(self, node: ast.If, parent: nodes.NodeNG) -> nodes.If: ...
300 @overload
301 def visit(self, node: ast.IfExp, parent: nodes.NodeNG) -> nodes.IfExp: ...
303 @overload
304 def visit(self, node: ast.Import, parent: nodes.NodeNG) -> nodes.Import: ...
306 @overload
307 def visit(
308 self, node: ast.JoinedStr, parent: nodes.NodeNG
309 ) -> nodes.JoinedStr: ...
311 @overload
312 def visit(
313 self, node: ast.FormattedValue, parent: nodes.NodeNG
314 ) -> nodes.FormattedValue: ...
316 @overload
317 def visit(
318 self, node: ast.NamedExpr, parent: nodes.NodeNG
319 ) -> nodes.NamedExpr: ...
321 @overload
322 def visit(self, node: ast.keyword, parent: nodes.NodeNG) -> nodes.Keyword: ...
324 @overload
325 def visit(self, node: ast.Lambda, parent: nodes.NodeNG) -> nodes.Lambda: ...
327 @overload
328 def visit(self, node: ast.List, parent: nodes.NodeNG) -> nodes.List: ...
330 @overload
331 def visit(self, node: ast.ListComp, parent: nodes.NodeNG) -> nodes.ListComp: ...
333 @overload
334 def visit(
335 self, node: ast.Name, parent: nodes.NodeNG
336 ) -> nodes.Name | nodes.Const | nodes.AssignName | nodes.DelName: ...
338 @overload
339 def visit(self, node: ast.Nonlocal, parent: nodes.NodeNG) -> nodes.Nonlocal: ...
341 @overload
342 def visit(self, node: ast.Constant, parent: nodes.NodeNG) -> nodes.Const: ...
344 if sys.version_info >= (3, 12):
346 @overload
347 def visit(
348 self, node: ast.ParamSpec, parent: nodes.NodeNG
349 ) -> nodes.ParamSpec: ...
351 @overload
352 def visit(self, node: ast.Pass, parent: nodes.NodeNG) -> nodes.Pass: ...
354 @overload
355 def visit(self, node: ast.Raise, parent: nodes.NodeNG) -> nodes.Raise: ...
357 @overload
358 def visit(self, node: ast.Return, parent: nodes.NodeNG) -> nodes.Return: ...
360 @overload
361 def visit(self, node: ast.Set, parent: nodes.NodeNG) -> nodes.Set: ...
363 @overload
364 def visit(self, node: ast.SetComp, parent: nodes.NodeNG) -> nodes.SetComp: ...
366 @overload
367 def visit(self, node: ast.Slice, parent: nodes.Subscript) -> nodes.Slice: ...
369 @overload
370 def visit(
371 self, node: ast.Subscript, parent: nodes.NodeNG
372 ) -> nodes.Subscript: ...
374 @overload
375 def visit(self, node: ast.Starred, parent: nodes.NodeNG) -> nodes.Starred: ...
377 @overload
378 def visit(self, node: ast.Try, parent: nodes.NodeNG) -> nodes.Try: ...
380 if sys.version_info >= (3, 11):
382 @overload
383 def visit(
384 self, node: ast.TryStar, parent: nodes.NodeNG
385 ) -> nodes.TryStar: ...
387 @overload
388 def visit(self, node: ast.Tuple, parent: nodes.NodeNG) -> nodes.Tuple: ...
390 if sys.version_info >= (3, 12):
392 @overload
393 def visit(
394 self, node: ast.TypeAlias, parent: nodes.NodeNG
395 ) -> nodes.TypeAlias: ...
397 @overload
398 def visit(
399 self, node: ast.TypeVar, parent: nodes.NodeNG
400 ) -> nodes.TypeVar: ...
402 @overload
403 def visit(
404 self, node: ast.TypeVarTuple, parent: nodes.NodeNG
405 ) -> nodes.TypeVarTuple: ...
407 @overload
408 def visit(self, node: ast.UnaryOp, parent: nodes.NodeNG) -> nodes.UnaryOp: ...
410 @overload
411 def visit(self, node: ast.While, parent: nodes.NodeNG) -> nodes.While: ...
413 @overload
414 def visit(self, node: ast.With, parent: nodes.NodeNG) -> nodes.With: ...
416 @overload
417 def visit(self, node: ast.Yield, parent: nodes.NodeNG) -> nodes.Yield: ...
419 @overload
420 def visit(
421 self, node: ast.YieldFrom, parent: nodes.NodeNG
422 ) -> nodes.YieldFrom: ...
424 @overload
425 def visit(self, node: ast.Match, parent: nodes.NodeNG) -> nodes.Match: ...
427 @overload
428 def visit(
429 self, node: ast.match_case, parent: nodes.NodeNG
430 ) -> nodes.MatchCase: ...
432 @overload
433 def visit(
434 self, node: ast.MatchValue, parent: nodes.NodeNG
435 ) -> nodes.MatchValue: ...
437 @overload
438 def visit(
439 self, node: ast.MatchSingleton, parent: nodes.NodeNG
440 ) -> nodes.MatchSingleton: ...
442 @overload
443 def visit(
444 self, node: ast.MatchSequence, parent: nodes.NodeNG
445 ) -> nodes.MatchSequence: ...
447 @overload
448 def visit(
449 self, node: ast.MatchMapping, parent: nodes.NodeNG
450 ) -> nodes.MatchMapping: ...
452 @overload
453 def visit(
454 self, node: ast.MatchClass, parent: nodes.NodeNG
455 ) -> nodes.MatchClass: ...
457 @overload
458 def visit(
459 self, node: ast.MatchStar, parent: nodes.NodeNG
460 ) -> nodes.MatchStar: ...
462 @overload
463 def visit(self, node: ast.MatchAs, parent: nodes.NodeNG) -> nodes.MatchAs: ...
465 @overload
466 def visit(self, node: ast.MatchOr, parent: nodes.NodeNG) -> nodes.MatchOr: ...
468 @overload
469 def visit(self, node: ast.pattern, parent: nodes.NodeNG) -> nodes.Pattern: ...
471 if sys.version_info >= (3, 14):
473 @overload
474 def visit(
475 self, node: ast.TemplateStr, parent: nodes.NodeNG
476 ) -> nodes.TemplateStr: ...
478 @overload
479 def visit(
480 self, node: ast.Interpolation, parent: nodes.NodeNG
481 ) -> nodes.Interpolation: ...
483 @overload
484 def visit(self, node: ast.AST, parent: nodes.NodeNG) -> nodes.NodeNG: ...
486 @overload
487 def visit(self, node: None, parent: nodes.NodeNG) -> None: ...
489 def visit(self, node: ast.AST | None, parent: nodes.NodeNG) -> nodes.NodeNG | None:
490 if node is None:
491 return None
492 cls = node.__class__
493 if cls in self._visit_meths:
494 visit_method = self._visit_meths[cls]
495 else:
496 cls_name = cls.__name__
497 visit_name = "visit_" + REDIRECT.get(cls_name, cls_name).lower()
498 visit_method = getattr(self, visit_name)
499 self._visit_meths[cls] = visit_method
500 return visit_method(node, parent)
502 def _save_assignment(self, node: nodes.AssignName | nodes.DelName) -> None:
503 """Save assignment situation since node.parent is not available yet."""
504 if self._global_names and node.name in self._global_names[-1]:
505 node.root().set_local(node.name, node)
506 else:
507 assert node.parent
508 assert node.name
509 node.parent.set_local(node.name, node)
511 def visit_arg(self, node: ast.arg, parent: nodes.NodeNG) -> nodes.AssignName:
512 """Visit an arg node by returning a fresh AssignName instance."""
513 return self.visit_assignname(node, parent, node.arg)
515 def visit_arguments(
516 self, node: ast.arguments, parent: nodes.NodeNG
517 ) -> nodes.Arguments:
518 """Visit an Arguments node by returning a fresh instance of it."""
519 vararg: str | None = None
520 kwarg: str | None = None
521 vararg_node = node.vararg
522 kwarg_node = node.kwarg
524 newnode = nodes.Arguments(
525 node.vararg.arg if node.vararg else None,
526 node.kwarg.arg if node.kwarg else None,
527 parent,
528 (
529 nodes.AssignName(
530 vararg_node.arg,
531 vararg_node.lineno,
532 vararg_node.col_offset,
533 parent,
534 end_lineno=vararg_node.end_lineno,
535 end_col_offset=vararg_node.end_col_offset,
536 )
537 if vararg_node
538 else None
539 ),
540 (
541 nodes.AssignName(
542 kwarg_node.arg,
543 kwarg_node.lineno,
544 kwarg_node.col_offset,
545 parent,
546 end_lineno=kwarg_node.end_lineno,
547 end_col_offset=kwarg_node.end_col_offset,
548 )
549 if kwarg_node
550 else None
551 ),
552 )
553 args = [self.visit(child, newnode) for child in node.args]
554 defaults = [self.visit(child, newnode) for child in node.defaults]
555 varargannotation: nodes.NodeNG | None = None
556 kwargannotation: nodes.NodeNG | None = None
557 if node.vararg:
558 vararg = node.vararg.arg
559 varargannotation = self.visit(node.vararg.annotation, newnode)
560 if node.kwarg:
561 kwarg = node.kwarg.arg
562 kwargannotation = self.visit(node.kwarg.annotation, newnode)
564 kwonlyargs = [self.visit(child, newnode) for child in node.kwonlyargs]
565 kw_defaults = [self.visit(child, newnode) for child in node.kw_defaults]
566 annotations = [self.visit(arg.annotation, newnode) for arg in node.args]
567 kwonlyargs_annotations = [
568 self.visit(arg.annotation, newnode) for arg in node.kwonlyargs
569 ]
571 posonlyargs = [self.visit(child, newnode) for child in node.posonlyargs]
572 posonlyargs_annotations = [
573 self.visit(arg.annotation, newnode) for arg in node.posonlyargs
574 ]
575 type_comment_args = [
576 self.check_type_comment(child, parent=newnode) for child in node.args
577 ]
578 type_comment_kwonlyargs = [
579 self.check_type_comment(child, parent=newnode) for child in node.kwonlyargs
580 ]
581 type_comment_posonlyargs = [
582 self.check_type_comment(child, parent=newnode) for child in node.posonlyargs
583 ]
585 newnode.postinit(
586 args=args,
587 defaults=defaults,
588 kwonlyargs=kwonlyargs,
589 posonlyargs=posonlyargs,
590 kw_defaults=kw_defaults,
591 annotations=annotations,
592 kwonlyargs_annotations=kwonlyargs_annotations,
593 posonlyargs_annotations=posonlyargs_annotations,
594 varargannotation=varargannotation,
595 kwargannotation=kwargannotation,
596 type_comment_args=type_comment_args,
597 type_comment_kwonlyargs=type_comment_kwonlyargs,
598 type_comment_posonlyargs=type_comment_posonlyargs,
599 )
600 if start_end_lineno_pairs := [
601 (arg.lineno, arg.end_lineno)
602 for arg in itertools.chain(
603 node.args, node.posonlyargs, node.kwonlyargs, [node.vararg, node.kwarg]
604 )
605 if arg
606 ]:
607 newnode.lineno = min(startend[0] for startend in start_end_lineno_pairs)
608 newnode.end_lineno = max(startend[1] for startend in start_end_lineno_pairs)
610 # save argument names in locals:
611 assert newnode.parent
612 if vararg:
613 newnode.parent.set_local(vararg, newnode)
614 if kwarg:
615 newnode.parent.set_local(kwarg, newnode)
616 return newnode
618 def visit_assert(self, node: ast.Assert, parent: nodes.NodeNG) -> nodes.Assert:
619 """Visit a Assert node by returning a fresh instance of it."""
620 newnode = nodes.Assert(
621 lineno=node.lineno,
622 col_offset=node.col_offset,
623 end_lineno=node.end_lineno,
624 end_col_offset=node.end_col_offset,
625 parent=parent,
626 )
627 msg: nodes.NodeNG | None = None
628 if node.msg:
629 msg = self.visit(node.msg, newnode)
630 newnode.postinit(self.visit(node.test, newnode), msg)
631 return newnode
633 def check_type_comment(
634 self,
635 node: ast.Assign | ast.arg | ast.For | ast.AsyncFor | ast.With | ast.AsyncWith,
636 parent: (
637 nodes.Assign
638 | nodes.Arguments
639 | nodes.For
640 | nodes.AsyncFor
641 | nodes.With
642 | nodes.AsyncWith
643 ),
644 ) -> nodes.NodeNG | None:
645 if not node.type_comment:
646 return None
648 try:
649 type_comment_ast = self._parser_module.parse(node.type_comment)
650 except (SyntaxError, ValueError, MemoryError, RecursionError):
651 # Invalid type comment, just skip it. ``ast.parse`` may raise
652 # ``MemoryError``/``RecursionError``/``ValueError`` on pathological
653 # inputs (e.g. deeply nested braces produced by fuzzers).
654 return None
656 # For '# type: # any comment' ast.parse returns a Module node,
657 # without any nodes in the body.
658 if not type_comment_ast.body:
659 return None
661 type_object = self.visit(type_comment_ast.body[0], parent=parent)
662 if not isinstance(type_object, nodes.Expr):
663 return None
665 return type_object.value
667 def check_function_type_comment(
668 self, node: ast.FunctionDef | ast.AsyncFunctionDef, parent: nodes.NodeNG
669 ) -> tuple[nodes.NodeNG | None, list[nodes.NodeNG]] | None:
670 if not node.type_comment:
671 return None
673 try:
674 type_comment_ast = parse_function_type_comment(node.type_comment)
675 except (SyntaxError, ValueError, MemoryError, RecursionError):
676 # Invalid type comment, just skip it. ``ast.parse`` may raise
677 # ``MemoryError``/``RecursionError``/``ValueError`` on pathological
678 # inputs (e.g. deeply nested braces produced by fuzzers).
679 return None
681 if not type_comment_ast:
682 return None
684 returns: nodes.NodeNG | None = None
685 argtypes: list[nodes.NodeNG] = [
686 self.visit(elem, parent) for elem in (type_comment_ast.argtypes or [])
687 ]
688 if type_comment_ast.returns:
689 returns = self.visit(type_comment_ast.returns, parent)
691 return returns, argtypes
693 def visit_asyncfunctiondef(
694 self, node: ast.AsyncFunctionDef, parent: nodes.NodeNG
695 ) -> nodes.AsyncFunctionDef:
696 return self._visit_functiondef(nodes.AsyncFunctionDef, node, parent)
698 def visit_asyncfor(
699 self, node: ast.AsyncFor, parent: nodes.NodeNG
700 ) -> nodes.AsyncFor:
701 return self._visit_for(nodes.AsyncFor, node, parent)
703 def visit_await(self, node: ast.Await, parent: nodes.NodeNG) -> nodes.Await:
704 newnode = nodes.Await(
705 lineno=node.lineno,
706 col_offset=node.col_offset,
707 end_lineno=node.end_lineno,
708 end_col_offset=node.end_col_offset,
709 parent=parent,
710 )
711 newnode.postinit(value=self.visit(node.value, newnode))
712 return newnode
714 def visit_asyncwith(
715 self, node: ast.AsyncWith, parent: nodes.NodeNG
716 ) -> nodes.AsyncWith:
717 return self._visit_with(nodes.AsyncWith, node, parent)
719 def visit_assign(self, node: ast.Assign, parent: nodes.NodeNG) -> nodes.Assign:
720 """Visit a Assign node by returning a fresh instance of it."""
721 newnode = nodes.Assign(
722 lineno=node.lineno,
723 col_offset=node.col_offset,
724 end_lineno=node.end_lineno,
725 end_col_offset=node.end_col_offset,
726 parent=parent,
727 )
728 type_annotation = self.check_type_comment(node, parent=newnode)
729 newnode.postinit(
730 targets=[self.visit(child, newnode) for child in node.targets],
731 value=self.visit(node.value, newnode),
732 type_annotation=type_annotation,
733 )
734 return newnode
736 def visit_annassign(
737 self, node: ast.AnnAssign, parent: nodes.NodeNG
738 ) -> nodes.AnnAssign:
739 """Visit an AnnAssign node by returning a fresh instance of it."""
740 newnode = nodes.AnnAssign(
741 lineno=node.lineno,
742 col_offset=node.col_offset,
743 end_lineno=node.end_lineno,
744 end_col_offset=node.end_col_offset,
745 parent=parent,
746 )
747 newnode.postinit(
748 target=self.visit(node.target, newnode),
749 annotation=self.visit(node.annotation, newnode),
750 simple=node.simple,
751 value=self.visit(node.value, newnode),
752 )
753 return newnode
755 @overload
756 def visit_assignname(
757 self, node: ast.AST, parent: nodes.NodeNG, node_name: str
758 ) -> nodes.AssignName: ...
760 @overload
761 def visit_assignname(
762 self, node: ast.AST, parent: nodes.NodeNG, node_name: None
763 ) -> None: ...
765 def visit_assignname(
766 self, node: ast.AST, parent: nodes.NodeNG, node_name: str | None
767 ) -> nodes.AssignName | None:
768 """Visit a node and return a AssignName node.
770 Note: Method not called by 'visit'
771 """
772 if node_name is None:
773 return None
774 newnode = nodes.AssignName(
775 name=node_name,
776 lineno=node.lineno,
777 col_offset=node.col_offset,
778 end_lineno=node.end_lineno,
779 end_col_offset=node.end_col_offset,
780 parent=parent,
781 )
782 self._save_assignment(newnode)
783 return newnode
785 def visit_augassign(
786 self, node: ast.AugAssign, parent: nodes.NodeNG
787 ) -> nodes.AugAssign:
788 """Visit a AugAssign node by returning a fresh instance of it."""
789 newnode = nodes.AugAssign(
790 op=self._parser_module.bin_op_classes[type(node.op)] + "=",
791 lineno=node.lineno,
792 col_offset=node.col_offset,
793 end_lineno=node.end_lineno,
794 end_col_offset=node.end_col_offset,
795 parent=parent,
796 )
797 newnode.postinit(
798 self.visit(node.target, newnode), self.visit(node.value, newnode)
799 )
800 return newnode
802 def visit_binop(self, node: ast.BinOp, parent: nodes.NodeNG) -> nodes.BinOp:
803 """Visit a BinOp node by returning a fresh instance of it."""
804 newnode = nodes.BinOp(
805 op=self._parser_module.bin_op_classes[type(node.op)],
806 lineno=node.lineno,
807 col_offset=node.col_offset,
808 end_lineno=node.end_lineno,
809 end_col_offset=node.end_col_offset,
810 parent=parent,
811 )
812 newnode.postinit(
813 self.visit(node.left, newnode), self.visit(node.right, newnode)
814 )
815 return newnode
817 def visit_boolop(self, node: ast.BoolOp, parent: nodes.NodeNG) -> nodes.BoolOp:
818 """Visit a BoolOp node by returning a fresh instance of it."""
819 newnode = nodes.BoolOp(
820 op=self._parser_module.bool_op_classes[type(node.op)],
821 lineno=node.lineno,
822 col_offset=node.col_offset,
823 end_lineno=node.end_lineno,
824 end_col_offset=node.end_col_offset,
825 parent=parent,
826 )
827 newnode.postinit([self.visit(child, newnode) for child in node.values])
828 return newnode
830 def visit_break(self, node: ast.Break, parent: nodes.NodeNG) -> nodes.Break:
831 """Visit a Break node by returning a fresh instance of it."""
832 return nodes.Break(
833 lineno=node.lineno,
834 col_offset=node.col_offset,
835 end_lineno=node.end_lineno,
836 end_col_offset=node.end_col_offset,
837 parent=parent,
838 )
840 def visit_call(self, node: ast.Call, parent: nodes.NodeNG) -> nodes.Call:
841 """Visit a CallFunc node by returning a fresh instance of it."""
842 newnode = nodes.Call(
843 lineno=node.lineno,
844 col_offset=node.col_offset,
845 end_lineno=node.end_lineno,
846 end_col_offset=node.end_col_offset,
847 parent=parent,
848 )
849 newnode.postinit(
850 func=self.visit(node.func, newnode),
851 args=[self.visit(child, newnode) for child in node.args],
852 keywords=[self.visit(child, newnode) for child in node.keywords],
853 )
854 return newnode
856 def visit_classdef(
857 self, node: ast.ClassDef, parent: nodes.NodeNG, newstyle: bool = True
858 ) -> nodes.ClassDef:
859 """Visit a ClassDef node to become astroid."""
860 node, doc_ast_node = self._get_doc(node)
861 newnode = nodes.ClassDef(
862 name=node.name,
863 lineno=node.lineno,
864 col_offset=node.col_offset,
865 end_lineno=node.end_lineno,
866 end_col_offset=node.end_col_offset,
867 parent=parent,
868 )
869 metaclass = None
870 for keyword in node.keywords:
871 if keyword.arg == "metaclass":
872 metaclass = self.visit(keyword, newnode).value
873 break
874 decorators = self.visit_decorators(node, newnode)
875 newnode.postinit(
876 [self.visit(child, newnode) for child in node.bases],
877 [self.visit(child, newnode) for child in node.body],
878 decorators,
879 newstyle,
880 metaclass,
881 [
882 self.visit(kwd, newnode)
883 for kwd in node.keywords
884 if kwd.arg != "metaclass"
885 ],
886 position=self._get_position_info(node, newnode),
887 doc_node=self.visit(doc_ast_node, newnode),
888 type_params=(
889 [self.visit(param, newnode) for param in node.type_params]
890 if PY312_PLUS
891 else []
892 ),
893 )
894 parent.set_local(newnode.name, newnode)
895 return newnode
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 self._parser_module.cmp_op_classes[op.__class__],
923 self.visit(expr, newnode),
924 )
925 for (op, expr) in zip(node.ops, node.comparators)
926 ],
927 )
928 return newnode
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 # Set the line number of the first decorator for Python 3.8+.
966 lineno = node.decorator_list[0].lineno
967 end_lineno = node.decorator_list[-1].end_lineno
968 end_col_offset = node.decorator_list[-1].end_col_offset
970 newnode = nodes.Decorators(
971 lineno=lineno,
972 col_offset=node.col_offset,
973 end_lineno=end_lineno,
974 end_col_offset=end_col_offset,
975 parent=parent,
976 )
977 newnode.postinit([self.visit(child, newnode) for child in node.decorator_list])
978 return newnode
980 def visit_delete(self, node: ast.Delete, parent: nodes.NodeNG) -> nodes.Delete:
981 """Visit a Delete node by returning a fresh instance of it."""
982 newnode = nodes.Delete(
983 lineno=node.lineno,
984 col_offset=node.col_offset,
985 end_lineno=node.end_lineno,
986 end_col_offset=node.end_col_offset,
987 parent=parent,
988 )
989 newnode.postinit([self.visit(child, newnode) for child in node.targets])
990 return newnode
992 def _visit_dict_items(
993 self, node: ast.Dict, parent: nodes.NodeNG, newnode: nodes.Dict
994 ) -> Generator[tuple[nodes.NodeNG, nodes.NodeNG]]:
995 for key, value in zip(node.keys, node.values):
996 rebuilt_key: nodes.NodeNG
997 rebuilt_value = self.visit(value, newnode)
998 if not key:
999 # Extended unpacking
1000 rebuilt_key = nodes.DictUnpack(
1001 lineno=rebuilt_value.lineno,
1002 col_offset=rebuilt_value.col_offset,
1003 end_lineno=rebuilt_value.end_lineno,
1004 end_col_offset=rebuilt_value.end_col_offset,
1005 parent=parent,
1006 )
1007 else:
1008 rebuilt_key = self.visit(key, newnode)
1009 yield rebuilt_key, rebuilt_value
1011 def visit_dict(self, node: ast.Dict, parent: nodes.NodeNG) -> nodes.Dict:
1012 """Visit a Dict node by returning a fresh instance of it."""
1013 newnode = nodes.Dict(
1014 lineno=node.lineno,
1015 col_offset=node.col_offset,
1016 end_lineno=node.end_lineno,
1017 end_col_offset=node.end_col_offset,
1018 parent=parent,
1019 )
1020 items: list[tuple[InferenceResult, InferenceResult]] = list(
1021 self._visit_dict_items(node, parent, newnode)
1022 )
1023 newnode.postinit(items)
1024 return newnode
1026 def visit_dictcomp(
1027 self, node: ast.DictComp, parent: nodes.NodeNG
1028 ) -> nodes.DictComp:
1029 """Visit a DictComp node by returning a fresh instance of it."""
1030 newnode = nodes.DictComp(
1031 lineno=node.lineno,
1032 col_offset=node.col_offset,
1033 end_lineno=node.end_lineno,
1034 end_col_offset=node.end_col_offset,
1035 parent=parent,
1036 )
1037 newnode.postinit(
1038 self.visit(node.key, newnode),
1039 self.visit(node.value, newnode),
1040 [self.visit(child, newnode) for child in node.generators],
1041 )
1042 return newnode
1044 def visit_expr(self, node: ast.Expr, parent: nodes.NodeNG) -> nodes.Expr:
1045 """Visit a Expr node by returning a fresh instance of it."""
1046 newnode = nodes.Expr(
1047 lineno=node.lineno,
1048 col_offset=node.col_offset,
1049 end_lineno=node.end_lineno,
1050 end_col_offset=node.end_col_offset,
1051 parent=parent,
1052 )
1053 newnode.postinit(self.visit(node.value, newnode))
1054 return newnode
1056 def visit_excepthandler(
1057 self, node: ast.ExceptHandler, parent: nodes.NodeNG
1058 ) -> nodes.ExceptHandler:
1059 """Visit an ExceptHandler node by returning a fresh instance of it."""
1060 newnode = nodes.ExceptHandler(
1061 lineno=node.lineno,
1062 col_offset=node.col_offset,
1063 end_lineno=node.end_lineno,
1064 end_col_offset=node.end_col_offset,
1065 parent=parent,
1066 )
1067 newnode.postinit(
1068 self.visit(node.type, newnode),
1069 self.visit_assignname(node, newnode, node.name),
1070 [self.visit(child, newnode) for child in node.body],
1071 )
1072 return newnode
1074 @overload
1075 def _visit_for(
1076 self, cls: type[nodes.For], node: ast.For, parent: nodes.NodeNG
1077 ) -> nodes.For: ...
1079 @overload
1080 def _visit_for(
1081 self, cls: type[nodes.AsyncFor], node: ast.AsyncFor, parent: nodes.NodeNG
1082 ) -> nodes.AsyncFor: ...
1084 def _visit_for(
1085 self, cls: type[_ForT], node: ast.For | ast.AsyncFor, parent: nodes.NodeNG
1086 ) -> _ForT:
1087 """Visit a For node by returning a fresh instance of it."""
1088 newnode = cls(
1089 lineno=node.lineno,
1090 col_offset=node.col_offset,
1091 end_lineno=node.end_lineno,
1092 end_col_offset=node.end_col_offset,
1093 parent=parent,
1094 )
1095 type_annotation = self.check_type_comment(node, parent=newnode)
1096 newnode.postinit(
1097 target=self.visit(node.target, newnode),
1098 iter=self.visit(node.iter, newnode),
1099 body=[self.visit(child, newnode) for child in node.body],
1100 orelse=[self.visit(child, newnode) for child in node.orelse],
1101 type_annotation=type_annotation,
1102 )
1103 return newnode
1105 def visit_for(self, node: ast.For, parent: nodes.NodeNG) -> nodes.For:
1106 return self._visit_for(nodes.For, node, parent)
1108 def visit_importfrom(
1109 self, node: ast.ImportFrom, parent: nodes.NodeNG
1110 ) -> nodes.ImportFrom:
1111 """Visit an ImportFrom node by returning a fresh instance of it."""
1112 names = [(alias.name, alias.asname) for alias in node.names]
1113 newnode = nodes.ImportFrom(
1114 fromname=node.module or "",
1115 names=names,
1116 level=node.level or None,
1117 lineno=node.lineno,
1118 col_offset=node.col_offset,
1119 end_lineno=node.end_lineno,
1120 end_col_offset=node.end_col_offset,
1121 parent=parent,
1122 )
1123 # store From names to add them to locals after building
1124 self._import_from_nodes.append(
1125 (newnode, self._global_names[-1].keys() if self._global_names else ())
1126 )
1127 return newnode
1129 @overload
1130 def _visit_functiondef(
1131 self, cls: type[nodes.FunctionDef], node: ast.FunctionDef, parent: nodes.NodeNG
1132 ) -> nodes.FunctionDef: ...
1134 @overload
1135 def _visit_functiondef(
1136 self,
1137 cls: type[nodes.AsyncFunctionDef],
1138 node: ast.AsyncFunctionDef,
1139 parent: nodes.NodeNG,
1140 ) -> nodes.AsyncFunctionDef: ...
1142 def _visit_functiondef(
1143 self,
1144 cls: type[_FunctionT],
1145 node: ast.FunctionDef | ast.AsyncFunctionDef,
1146 parent: nodes.NodeNG,
1147 ) -> _FunctionT:
1148 """Visit an FunctionDef node to become astroid."""
1149 self._global_names.append({})
1150 node, doc_ast_node = self._get_doc(node)
1152 lineno = node.lineno
1153 if node.decorator_list:
1154 # Python 3.8 sets the line number of a decorated function
1155 # to be the actual line number of the function, but the
1156 # previous versions expected the decorator's line number instead.
1157 # We reset the function's line number to that of the
1158 # first decorator to maintain backward compatibility.
1159 # It's not ideal but this discrepancy was baked into
1160 # the framework for *years*.
1161 lineno = node.decorator_list[0].lineno
1163 newnode = cls(
1164 name=node.name,
1165 lineno=lineno,
1166 col_offset=node.col_offset,
1167 end_lineno=node.end_lineno,
1168 end_col_offset=node.end_col_offset,
1169 parent=parent,
1170 )
1171 decorators = self.visit_decorators(node, newnode)
1172 returns: nodes.NodeNG | None
1173 if node.returns:
1174 returns = self.visit(node.returns, newnode)
1175 else:
1176 returns = None
1178 type_comment_args = type_comment_returns = None
1179 type_comment_annotation = self.check_function_type_comment(node, newnode)
1180 if type_comment_annotation:
1181 type_comment_returns, type_comment_args = type_comment_annotation
1182 newnode.postinit(
1183 args=self.visit(node.args, newnode),
1184 body=[self.visit(child, newnode) for child in node.body],
1185 decorators=decorators,
1186 returns=returns,
1187 type_comment_returns=type_comment_returns,
1188 type_comment_args=type_comment_args,
1189 position=self._get_position_info(node, newnode),
1190 doc_node=self.visit(doc_ast_node, newnode),
1191 type_params=(
1192 [self.visit(param, newnode) for param in node.type_params]
1193 if PY312_PLUS
1194 else []
1195 ),
1196 )
1197 self._global_names.pop()
1198 parent.set_local(newnode.name, newnode)
1199 return newnode
1201 def visit_functiondef(
1202 self, node: ast.FunctionDef, parent: nodes.NodeNG
1203 ) -> nodes.FunctionDef:
1204 return self._visit_functiondef(nodes.FunctionDef, node, parent)
1206 def visit_generatorexp(
1207 self, node: ast.GeneratorExp, parent: nodes.NodeNG
1208 ) -> nodes.GeneratorExp:
1209 """Visit a GeneratorExp node by returning a fresh instance of it."""
1210 newnode = nodes.GeneratorExp(
1211 lineno=node.lineno,
1212 col_offset=node.col_offset,
1213 end_lineno=node.end_lineno,
1214 end_col_offset=node.end_col_offset,
1215 parent=parent,
1216 )
1217 newnode.postinit(
1218 self.visit(node.elt, newnode),
1219 [self.visit(child, newnode) for child in node.generators],
1220 )
1221 return newnode
1223 def visit_attribute(
1224 self, node: ast.Attribute, parent: nodes.NodeNG
1225 ) -> nodes.Attribute | nodes.AssignAttr | nodes.DelAttr:
1226 """Visit an Attribute node by returning a fresh instance of it."""
1227 context = self._get_context(node)
1228 newnode: nodes.Attribute | nodes.AssignAttr | nodes.DelAttr
1229 if context == Context.Del:
1230 # FIXME : maybe we should reintroduce and visit_delattr ?
1231 # for instance, deactivating assign_ctx
1232 newnode = nodes.DelAttr(
1233 attrname=node.attr,
1234 lineno=node.lineno,
1235 col_offset=node.col_offset,
1236 end_lineno=node.end_lineno,
1237 end_col_offset=node.end_col_offset,
1238 parent=parent,
1239 )
1240 elif context == Context.Store:
1241 newnode = nodes.AssignAttr(
1242 attrname=node.attr,
1243 lineno=node.lineno,
1244 col_offset=node.col_offset,
1245 end_lineno=node.end_lineno,
1246 end_col_offset=node.end_col_offset,
1247 parent=parent,
1248 )
1249 # Prohibit a local save if we are in an ExceptHandler.
1250 if not isinstance(parent, nodes.ExceptHandler):
1251 # mypy doesn't recognize that newnode has to be AssignAttr because it
1252 # doesn't support ParamSpec
1253 # See https://github.com/python/mypy/issues/8645
1254 self._delayed_assattr.append(newnode) # type: ignore[arg-type]
1255 else:
1256 newnode = nodes.Attribute(
1257 attrname=node.attr,
1258 lineno=node.lineno,
1259 col_offset=node.col_offset,
1260 end_lineno=node.end_lineno,
1261 end_col_offset=node.end_col_offset,
1262 parent=parent,
1263 )
1264 newnode.postinit(self.visit(node.value, newnode))
1265 return newnode
1267 def visit_global(self, node: ast.Global, parent: nodes.NodeNG) -> nodes.Global:
1268 """Visit a Global node to become astroid."""
1269 newnode = nodes.Global(
1270 names=node.names,
1271 lineno=node.lineno,
1272 col_offset=node.col_offset,
1273 end_lineno=node.end_lineno,
1274 end_col_offset=node.end_col_offset,
1275 parent=parent,
1276 )
1277 if self._global_names: # global at the module level, no effect
1278 for name in node.names:
1279 self._global_names[-1].setdefault(name, []).append(newnode)
1280 return newnode
1282 def visit_if(self, node: ast.If, parent: nodes.NodeNG) -> nodes.If:
1283 """Visit an If node by returning a fresh instance of it."""
1284 newnode = nodes.If(
1285 lineno=node.lineno,
1286 col_offset=node.col_offset,
1287 end_lineno=node.end_lineno,
1288 end_col_offset=node.end_col_offset,
1289 parent=parent,
1290 )
1291 newnode.postinit(
1292 self.visit(node.test, newnode),
1293 [self.visit(child, newnode) for child in node.body],
1294 [self.visit(child, newnode) for child in node.orelse],
1295 )
1296 return newnode
1298 def visit_ifexp(self, node: ast.IfExp, parent: nodes.NodeNG) -> nodes.IfExp:
1299 """Visit a IfExp node by returning a fresh instance of it."""
1300 newnode = nodes.IfExp(
1301 lineno=node.lineno,
1302 col_offset=node.col_offset,
1303 end_lineno=node.end_lineno,
1304 end_col_offset=node.end_col_offset,
1305 parent=parent,
1306 )
1307 newnode.postinit(
1308 self.visit(node.test, newnode),
1309 self.visit(node.body, newnode),
1310 self.visit(node.orelse, newnode),
1311 )
1312 return newnode
1314 def visit_import(self, node: ast.Import, parent: nodes.NodeNG) -> nodes.Import:
1315 """Visit a Import node by returning a fresh instance of it."""
1316 names = [(alias.name, alias.asname) for alias in node.names]
1317 newnode = nodes.Import(
1318 names=names,
1319 lineno=node.lineno,
1320 col_offset=node.col_offset,
1321 end_lineno=node.end_lineno,
1322 end_col_offset=node.end_col_offset,
1323 parent=parent,
1324 )
1325 # save import names in parent's locals:
1326 for name, asname in newnode.names:
1327 name = (asname or name).split(".")[0]
1328 if self._global_names and name in self._global_names[-1]:
1329 parent.root().set_local(name, newnode)
1330 else:
1331 parent.set_local(name, newnode)
1332 return newnode
1334 def visit_joinedstr(
1335 self, node: ast.JoinedStr, parent: nodes.NodeNG
1336 ) -> nodes.JoinedStr:
1337 newnode = nodes.JoinedStr(
1338 lineno=node.lineno,
1339 col_offset=node.col_offset,
1340 end_lineno=node.end_lineno,
1341 end_col_offset=node.end_col_offset,
1342 parent=parent,
1343 )
1344 newnode.postinit([self.visit(child, newnode) for child in node.values])
1345 return newnode
1347 def visit_formattedvalue(
1348 self, node: ast.FormattedValue, parent: nodes.NodeNG
1349 ) -> nodes.FormattedValue:
1350 newnode = nodes.FormattedValue(
1351 lineno=node.lineno,
1352 col_offset=node.col_offset,
1353 end_lineno=node.end_lineno,
1354 end_col_offset=node.end_col_offset,
1355 parent=parent,
1356 )
1357 newnode.postinit(
1358 value=self.visit(node.value, newnode),
1359 conversion=node.conversion,
1360 format_spec=self.visit(node.format_spec, newnode),
1361 )
1362 return newnode
1364 def visit_namedexpr(
1365 self, node: ast.NamedExpr, parent: nodes.NodeNG
1366 ) -> nodes.NamedExpr:
1367 newnode = nodes.NamedExpr(
1368 lineno=node.lineno,
1369 col_offset=node.col_offset,
1370 end_lineno=node.end_lineno,
1371 end_col_offset=node.end_col_offset,
1372 parent=parent,
1373 )
1374 newnode.postinit(
1375 self.visit(node.target, newnode), self.visit(node.value, newnode)
1376 )
1377 return newnode
1379 def visit_keyword(self, node: ast.keyword, parent: nodes.NodeNG) -> nodes.Keyword:
1380 """Visit a Keyword node by returning a fresh instance of it."""
1381 newnode = nodes.Keyword(
1382 arg=node.arg,
1383 # position attributes added in 3.9
1384 lineno=getattr(node, "lineno", None),
1385 col_offset=getattr(node, "col_offset", None),
1386 end_lineno=getattr(node, "end_lineno", None),
1387 end_col_offset=getattr(node, "end_col_offset", None),
1388 parent=parent,
1389 )
1390 newnode.postinit(self.visit(node.value, newnode))
1391 return newnode
1393 def visit_lambda(self, node: ast.Lambda, parent: nodes.NodeNG) -> nodes.Lambda:
1394 """Visit a Lambda node by returning a fresh instance of it."""
1395 newnode = nodes.Lambda(
1396 lineno=node.lineno,
1397 col_offset=node.col_offset,
1398 end_lineno=node.end_lineno,
1399 end_col_offset=node.end_col_offset,
1400 parent=parent,
1401 )
1402 newnode.postinit(self.visit(node.args, newnode), self.visit(node.body, newnode))
1403 return newnode
1405 def visit_list(self, node: ast.List, parent: nodes.NodeNG) -> nodes.List:
1406 """Visit a List node by returning a fresh instance of it."""
1407 context = self._get_context(node)
1408 newnode = nodes.List(
1409 ctx=context,
1410 lineno=node.lineno,
1411 col_offset=node.col_offset,
1412 end_lineno=node.end_lineno,
1413 end_col_offset=node.end_col_offset,
1414 parent=parent,
1415 )
1416 newnode.postinit([self.visit(child, newnode) for child in node.elts])
1417 return newnode
1419 def visit_listcomp(
1420 self, node: ast.ListComp, parent: nodes.NodeNG
1421 ) -> nodes.ListComp:
1422 """Visit a ListComp node by returning a fresh instance of it."""
1423 newnode = nodes.ListComp(
1424 lineno=node.lineno,
1425 col_offset=node.col_offset,
1426 end_lineno=node.end_lineno,
1427 end_col_offset=node.end_col_offset,
1428 parent=parent,
1429 )
1430 newnode.postinit(
1431 self.visit(node.elt, newnode),
1432 [self.visit(child, newnode) for child in node.generators],
1433 )
1434 return newnode
1436 def visit_name(
1437 self, node: ast.Name, parent: nodes.NodeNG
1438 ) -> nodes.Name | nodes.AssignName | nodes.DelName:
1439 """Visit a Name node by returning a fresh instance of it."""
1440 context = self._get_context(node)
1441 newnode: nodes.Name | nodes.AssignName | nodes.DelName
1442 if context == Context.Del:
1443 newnode = nodes.DelName(
1444 name=node.id,
1445 lineno=node.lineno,
1446 col_offset=node.col_offset,
1447 end_lineno=node.end_lineno,
1448 end_col_offset=node.end_col_offset,
1449 parent=parent,
1450 )
1451 elif context == Context.Store:
1452 newnode = nodes.AssignName(
1453 name=node.id,
1454 lineno=node.lineno,
1455 col_offset=node.col_offset,
1456 end_lineno=node.end_lineno,
1457 end_col_offset=node.end_col_offset,
1458 parent=parent,
1459 )
1460 else:
1461 newnode = nodes.Name(
1462 name=node.id,
1463 lineno=node.lineno,
1464 col_offset=node.col_offset,
1465 end_lineno=node.end_lineno,
1466 end_col_offset=node.end_col_offset,
1467 parent=parent,
1468 )
1469 # XXX REMOVE me :
1470 if context in (Context.Del, Context.Store): # 'Aug' ??
1471 newnode = cast((nodes.AssignName | nodes.DelName), newnode)
1472 self._save_assignment(newnode)
1473 return newnode
1475 def visit_nonlocal(
1476 self, node: ast.Nonlocal, parent: nodes.NodeNG
1477 ) -> nodes.Nonlocal:
1478 """Visit a Nonlocal node and return a new instance of it."""
1479 return nodes.Nonlocal(
1480 names=node.names,
1481 lineno=node.lineno,
1482 col_offset=node.col_offset,
1483 end_lineno=node.end_lineno,
1484 end_col_offset=node.end_col_offset,
1485 parent=parent,
1486 )
1488 def visit_constant(self, node: ast.Constant, parent: nodes.NodeNG) -> nodes.Const:
1489 """Visit a Constant node by returning a fresh instance of Const."""
1490 return nodes.Const(
1491 value=node.value,
1492 kind=node.kind,
1493 lineno=node.lineno,
1494 col_offset=node.col_offset,
1495 end_lineno=node.end_lineno,
1496 end_col_offset=node.end_col_offset,
1497 parent=parent,
1498 )
1500 def visit_paramspec(
1501 self, node: ast.ParamSpec, parent: nodes.NodeNG
1502 ) -> nodes.ParamSpec:
1503 """Visit a ParamSpec node by returning a fresh instance of it."""
1504 newnode = nodes.ParamSpec(
1505 lineno=node.lineno,
1506 col_offset=node.col_offset,
1507 end_lineno=node.end_lineno,
1508 end_col_offset=node.end_col_offset,
1509 parent=parent,
1510 )
1511 # Add AssignName node for 'node.name'
1512 # https://bugs.python.org/issue43994
1513 newnode.postinit(
1514 name=self.visit_assignname(node, newnode, node.name),
1515 default_value=(
1516 self.visit(node.default_value, newnode) if PY313_PLUS else None
1517 ),
1518 )
1519 return newnode
1521 def visit_pass(self, node: ast.Pass, parent: nodes.NodeNG) -> nodes.Pass:
1522 """Visit a Pass node by returning a fresh instance of it."""
1523 return nodes.Pass(
1524 lineno=node.lineno,
1525 col_offset=node.col_offset,
1526 end_lineno=node.end_lineno,
1527 end_col_offset=node.end_col_offset,
1528 parent=parent,
1529 )
1531 def visit_raise(self, node: ast.Raise, parent: nodes.NodeNG) -> nodes.Raise:
1532 """Visit a Raise node by returning a fresh instance of it."""
1533 newnode = nodes.Raise(
1534 lineno=node.lineno,
1535 col_offset=node.col_offset,
1536 end_lineno=node.end_lineno,
1537 end_col_offset=node.end_col_offset,
1538 parent=parent,
1539 )
1540 # no traceback; anyway it is not used in Pylint
1541 newnode.postinit(
1542 exc=self.visit(node.exc, newnode),
1543 cause=self.visit(node.cause, newnode),
1544 )
1545 return newnode
1547 def visit_return(self, node: ast.Return, parent: nodes.NodeNG) -> nodes.Return:
1548 """Visit a Return node by returning a fresh instance of it."""
1549 newnode = nodes.Return(
1550 lineno=node.lineno,
1551 col_offset=node.col_offset,
1552 end_lineno=node.end_lineno,
1553 end_col_offset=node.end_col_offset,
1554 parent=parent,
1555 )
1556 newnode.postinit(self.visit(node.value, newnode))
1557 return newnode
1559 def visit_set(self, node: ast.Set, parent: nodes.NodeNG) -> nodes.Set:
1560 """Visit a Set node by returning a fresh instance of it."""
1561 newnode = nodes.Set(
1562 lineno=node.lineno,
1563 col_offset=node.col_offset,
1564 end_lineno=node.end_lineno,
1565 end_col_offset=node.end_col_offset,
1566 parent=parent,
1567 )
1568 newnode.postinit([self.visit(child, newnode) for child in node.elts])
1569 return newnode
1571 def visit_setcomp(self, node: ast.SetComp, parent: nodes.NodeNG) -> nodes.SetComp:
1572 """Visit a SetComp node by returning a fresh instance of it."""
1573 newnode = nodes.SetComp(
1574 lineno=node.lineno,
1575 col_offset=node.col_offset,
1576 end_lineno=node.end_lineno,
1577 end_col_offset=node.end_col_offset,
1578 parent=parent,
1579 )
1580 newnode.postinit(
1581 self.visit(node.elt, newnode),
1582 [self.visit(child, newnode) for child in node.generators],
1583 )
1584 return newnode
1586 def visit_slice(self, node: ast.Slice, parent: nodes.Subscript) -> nodes.Slice:
1587 """Visit a Slice node by returning a fresh instance of it."""
1588 newnode = nodes.Slice(
1589 # position attributes added in 3.9
1590 lineno=getattr(node, "lineno", None),
1591 col_offset=getattr(node, "col_offset", None),
1592 end_lineno=getattr(node, "end_lineno", None),
1593 end_col_offset=getattr(node, "end_col_offset", None),
1594 parent=parent,
1595 )
1596 newnode.postinit(
1597 lower=self.visit(node.lower, newnode),
1598 upper=self.visit(node.upper, newnode),
1599 step=self.visit(node.step, newnode),
1600 )
1601 return newnode
1603 def visit_subscript(
1604 self, node: ast.Subscript, parent: nodes.NodeNG
1605 ) -> nodes.Subscript:
1606 """Visit a Subscript node by returning a fresh instance of it."""
1607 context = self._get_context(node)
1608 newnode = nodes.Subscript(
1609 ctx=context,
1610 lineno=node.lineno,
1611 col_offset=node.col_offset,
1612 end_lineno=node.end_lineno,
1613 end_col_offset=node.end_col_offset,
1614 parent=parent,
1615 )
1616 newnode.postinit(
1617 self.visit(node.value, newnode), self.visit(node.slice, newnode)
1618 )
1619 return newnode
1621 def visit_starred(self, node: ast.Starred, parent: nodes.NodeNG) -> nodes.Starred:
1622 """Visit a Starred node and return a new instance of it."""
1623 context = self._get_context(node)
1624 newnode = nodes.Starred(
1625 ctx=context,
1626 lineno=node.lineno,
1627 col_offset=node.col_offset,
1628 end_lineno=node.end_lineno,
1629 end_col_offset=node.end_col_offset,
1630 parent=parent,
1631 )
1632 newnode.postinit(self.visit(node.value, newnode))
1633 return newnode
1635 def visit_try(self, node: ast.Try, parent: nodes.NodeNG) -> nodes.Try:
1636 """Visit a Try node by returning a fresh instance of it"""
1637 newnode = nodes.Try(
1638 lineno=node.lineno,
1639 col_offset=node.col_offset,
1640 end_lineno=node.end_lineno,
1641 end_col_offset=node.end_col_offset,
1642 parent=parent,
1643 )
1644 newnode.postinit(
1645 body=[self.visit(child, newnode) for child in node.body],
1646 handlers=[self.visit(child, newnode) for child in node.handlers],
1647 orelse=[self.visit(child, newnode) for child in node.orelse],
1648 finalbody=[self.visit(child, newnode) for child in node.finalbody],
1649 )
1650 return newnode
1652 def visit_trystar(self, node: ast.TryStar, parent: nodes.NodeNG) -> nodes.TryStar:
1653 newnode = nodes.TryStar(
1654 lineno=node.lineno,
1655 col_offset=node.col_offset,
1656 end_lineno=node.end_lineno,
1657 end_col_offset=node.end_col_offset,
1658 parent=parent,
1659 )
1660 newnode.postinit(
1661 body=[self.visit(n, newnode) for n in node.body],
1662 handlers=[self.visit(n, newnode) for n in node.handlers],
1663 orelse=[self.visit(n, newnode) for n in node.orelse],
1664 finalbody=[self.visit(n, newnode) for n in node.finalbody],
1665 )
1666 return newnode
1668 def visit_tuple(self, node: ast.Tuple, parent: nodes.NodeNG) -> nodes.Tuple:
1669 """Visit a Tuple node by returning a fresh instance of it."""
1670 context = self._get_context(node)
1671 newnode = nodes.Tuple(
1672 ctx=context,
1673 lineno=node.lineno,
1674 col_offset=node.col_offset,
1675 end_lineno=node.end_lineno,
1676 end_col_offset=node.end_col_offset,
1677 parent=parent,
1678 )
1679 newnode.postinit([self.visit(child, newnode) for child in node.elts])
1680 return newnode
1682 def visit_typealias(
1683 self, node: ast.TypeAlias, parent: nodes.NodeNG
1684 ) -> nodes.TypeAlias:
1685 """Visit a TypeAlias node by returning a fresh instance of it."""
1686 newnode = nodes.TypeAlias(
1687 lineno=node.lineno,
1688 col_offset=node.col_offset,
1689 end_lineno=node.end_lineno,
1690 end_col_offset=node.end_col_offset,
1691 parent=parent,
1692 )
1693 newnode.postinit(
1694 name=self.visit(node.name, newnode),
1695 type_params=[self.visit(p, newnode) for p in node.type_params],
1696 value=self.visit(node.value, newnode),
1697 )
1698 return newnode
1700 def visit_typevar(self, node: ast.TypeVar, parent: nodes.NodeNG) -> nodes.TypeVar:
1701 """Visit a TypeVar node by returning a fresh instance of it."""
1702 newnode = nodes.TypeVar(
1703 lineno=node.lineno,
1704 col_offset=node.col_offset,
1705 end_lineno=node.end_lineno,
1706 end_col_offset=node.end_col_offset,
1707 parent=parent,
1708 )
1709 # Add AssignName node for 'node.name'
1710 # https://bugs.python.org/issue43994
1711 newnode.postinit(
1712 name=self.visit_assignname(node, newnode, node.name),
1713 bound=self.visit(node.bound, newnode),
1714 default_value=(
1715 self.visit(node.default_value, newnode) if PY313_PLUS else None
1716 ),
1717 )
1718 return newnode
1720 def visit_typevartuple(
1721 self, node: ast.TypeVarTuple, parent: nodes.NodeNG
1722 ) -> nodes.TypeVarTuple:
1723 """Visit a TypeVarTuple node by returning a fresh instance of it."""
1724 newnode = nodes.TypeVarTuple(
1725 lineno=node.lineno,
1726 col_offset=node.col_offset,
1727 end_lineno=node.end_lineno,
1728 end_col_offset=node.end_col_offset,
1729 parent=parent,
1730 )
1731 # Add AssignName node for 'node.name'
1732 # https://bugs.python.org/issue43994
1733 newnode.postinit(
1734 name=self.visit_assignname(node, newnode, node.name),
1735 default_value=(
1736 self.visit(node.default_value, newnode) if PY313_PLUS else None
1737 ),
1738 )
1739 return newnode
1741 def visit_unaryop(self, node: ast.UnaryOp, parent: nodes.NodeNG) -> nodes.UnaryOp:
1742 """Visit a UnaryOp node by returning a fresh instance of it."""
1743 newnode = nodes.UnaryOp(
1744 op=self._parser_module.unary_op_classes[node.op.__class__],
1745 lineno=node.lineno,
1746 col_offset=node.col_offset,
1747 end_lineno=node.end_lineno,
1748 end_col_offset=node.end_col_offset,
1749 parent=parent,
1750 )
1751 newnode.postinit(self.visit(node.operand, newnode))
1752 return newnode
1754 def visit_while(self, node: ast.While, parent: nodes.NodeNG) -> nodes.While:
1755 """Visit a While node by returning a fresh instance of it."""
1756 newnode = nodes.While(
1757 lineno=node.lineno,
1758 col_offset=node.col_offset,
1759 end_lineno=node.end_lineno,
1760 end_col_offset=node.end_col_offset,
1761 parent=parent,
1762 )
1763 newnode.postinit(
1764 self.visit(node.test, newnode),
1765 [self.visit(child, newnode) for child in node.body],
1766 [self.visit(child, newnode) for child in node.orelse],
1767 )
1768 return newnode
1770 @overload
1771 def _visit_with(
1772 self, cls: type[nodes.With], node: ast.With, parent: nodes.NodeNG
1773 ) -> nodes.With: ...
1775 @overload
1776 def _visit_with(
1777 self, cls: type[nodes.AsyncWith], node: ast.AsyncWith, parent: nodes.NodeNG
1778 ) -> nodes.AsyncWith: ...
1780 def _visit_with(
1781 self,
1782 cls: type[_WithT],
1783 node: ast.With | ast.AsyncWith,
1784 parent: nodes.NodeNG,
1785 ) -> _WithT:
1786 newnode = cls(
1787 lineno=node.lineno,
1788 col_offset=node.col_offset,
1789 end_lineno=node.end_lineno,
1790 end_col_offset=node.end_col_offset,
1791 parent=parent,
1792 )
1794 def visit_child(
1795 child: ast.withitem,
1796 ) -> tuple[nodes.NodeNG, nodes.NodeNG | None]:
1797 expr = self.visit(child.context_expr, newnode)
1798 var = self.visit(child.optional_vars, newnode)
1799 return expr, var
1801 type_annotation = self.check_type_comment(node, parent=newnode)
1802 newnode.postinit(
1803 items=[visit_child(child) for child in node.items],
1804 body=[self.visit(child, newnode) for child in node.body],
1805 type_annotation=type_annotation,
1806 )
1807 return newnode
1809 def visit_with(self, node: ast.With, parent: nodes.NodeNG) -> nodes.NodeNG:
1810 return self._visit_with(nodes.With, node, parent)
1812 def visit_yield(self, node: ast.Yield, parent: nodes.NodeNG) -> nodes.NodeNG:
1813 """Visit a Yield node by returning a fresh instance of it."""
1814 newnode = nodes.Yield(
1815 lineno=node.lineno,
1816 col_offset=node.col_offset,
1817 end_lineno=node.end_lineno,
1818 end_col_offset=node.end_col_offset,
1819 parent=parent,
1820 )
1821 newnode.postinit(self.visit(node.value, newnode))
1822 return newnode
1824 def visit_yieldfrom(
1825 self, node: ast.YieldFrom, parent: nodes.NodeNG
1826 ) -> nodes.NodeNG:
1827 newnode = nodes.YieldFrom(
1828 lineno=node.lineno,
1829 col_offset=node.col_offset,
1830 end_lineno=node.end_lineno,
1831 end_col_offset=node.end_col_offset,
1832 parent=parent,
1833 )
1834 newnode.postinit(self.visit(node.value, newnode))
1835 return newnode
1837 def visit_match(self, node: ast.Match, parent: nodes.NodeNG) -> nodes.Match:
1838 newnode = nodes.Match(
1839 lineno=node.lineno,
1840 col_offset=node.col_offset,
1841 end_lineno=node.end_lineno,
1842 end_col_offset=node.end_col_offset,
1843 parent=parent,
1844 )
1845 newnode.postinit(
1846 subject=self.visit(node.subject, newnode),
1847 cases=[self.visit(case, newnode) for case in node.cases],
1848 )
1849 return newnode
1851 def visit_matchcase(
1852 self, node: ast.match_case, parent: nodes.NodeNG
1853 ) -> nodes.MatchCase:
1854 newnode = nodes.MatchCase(parent=parent)
1855 newnode.postinit(
1856 pattern=self.visit(node.pattern, newnode),
1857 guard=self.visit(node.guard, newnode),
1858 body=[self.visit(child, newnode) for child in node.body],
1859 )
1860 return newnode
1862 def visit_matchvalue(
1863 self, node: ast.MatchValue, parent: nodes.NodeNG
1864 ) -> nodes.MatchValue:
1865 newnode = nodes.MatchValue(
1866 lineno=node.lineno,
1867 col_offset=node.col_offset,
1868 end_lineno=node.end_lineno,
1869 end_col_offset=node.end_col_offset,
1870 parent=parent,
1871 )
1872 newnode.postinit(value=self.visit(node.value, newnode))
1873 return newnode
1875 def visit_matchsingleton(
1876 self, node: ast.MatchSingleton, parent: nodes.NodeNG
1877 ) -> nodes.MatchSingleton:
1878 return nodes.MatchSingleton(
1879 value=node.value,
1880 lineno=node.lineno,
1881 col_offset=node.col_offset,
1882 end_lineno=node.end_lineno,
1883 end_col_offset=node.end_col_offset,
1884 parent=parent,
1885 )
1887 def visit_matchsequence(
1888 self, node: ast.MatchSequence, parent: nodes.NodeNG
1889 ) -> nodes.MatchSequence:
1890 newnode = nodes.MatchSequence(
1891 lineno=node.lineno,
1892 col_offset=node.col_offset,
1893 end_lineno=node.end_lineno,
1894 end_col_offset=node.end_col_offset,
1895 parent=parent,
1896 )
1897 newnode.postinit(
1898 patterns=[self.visit(pattern, newnode) for pattern in node.patterns]
1899 )
1900 return newnode
1902 def visit_matchmapping(
1903 self, node: ast.MatchMapping, parent: nodes.NodeNG
1904 ) -> nodes.MatchMapping:
1905 newnode = nodes.MatchMapping(
1906 lineno=node.lineno,
1907 col_offset=node.col_offset,
1908 end_lineno=node.end_lineno,
1909 end_col_offset=node.end_col_offset,
1910 parent=parent,
1911 )
1912 # Add AssignName node for 'node.name'
1913 # https://bugs.python.org/issue43994
1914 newnode.postinit(
1915 keys=[self.visit(child, newnode) for child in node.keys],
1916 patterns=[self.visit(pattern, newnode) for pattern in node.patterns],
1917 rest=self.visit_assignname(node, newnode, node.rest),
1918 )
1919 return newnode
1921 def visit_matchclass(
1922 self, node: ast.MatchClass, parent: nodes.NodeNG
1923 ) -> nodes.MatchClass:
1924 newnode = nodes.MatchClass(
1925 lineno=node.lineno,
1926 col_offset=node.col_offset,
1927 end_lineno=node.end_lineno,
1928 end_col_offset=node.end_col_offset,
1929 parent=parent,
1930 )
1931 newnode.postinit(
1932 cls=self.visit(node.cls, newnode),
1933 patterns=[self.visit(pattern, newnode) for pattern in node.patterns],
1934 kwd_attrs=node.kwd_attrs,
1935 kwd_patterns=[
1936 self.visit(pattern, newnode) for pattern in node.kwd_patterns
1937 ],
1938 )
1939 return newnode
1941 def visit_matchstar(
1942 self, node: ast.MatchStar, parent: nodes.NodeNG
1943 ) -> nodes.MatchStar:
1944 newnode = nodes.MatchStar(
1945 lineno=node.lineno,
1946 col_offset=node.col_offset,
1947 end_lineno=node.end_lineno,
1948 end_col_offset=node.end_col_offset,
1949 parent=parent,
1950 )
1951 # Add AssignName node for 'node.name'
1952 # https://bugs.python.org/issue43994
1953 newnode.postinit(name=self.visit_assignname(node, newnode, node.name))
1954 return newnode
1956 def visit_matchas(self, node: ast.MatchAs, parent: nodes.NodeNG) -> nodes.MatchAs:
1957 newnode = nodes.MatchAs(
1958 lineno=node.lineno,
1959 col_offset=node.col_offset,
1960 end_lineno=node.end_lineno,
1961 end_col_offset=node.end_col_offset,
1962 parent=parent,
1963 )
1964 # Add AssignName node for 'node.name'
1965 # https://bugs.python.org/issue43994
1966 newnode.postinit(
1967 pattern=self.visit(node.pattern, newnode),
1968 name=self.visit_assignname(node, newnode, node.name),
1969 )
1970 return newnode
1972 def visit_matchor(self, node: ast.MatchOr, parent: nodes.NodeNG) -> nodes.MatchOr:
1973 newnode = nodes.MatchOr(
1974 lineno=node.lineno,
1975 col_offset=node.col_offset,
1976 end_lineno=node.end_lineno,
1977 end_col_offset=node.end_col_offset,
1978 parent=parent,
1979 )
1980 newnode.postinit(
1981 patterns=[self.visit(pattern, newnode) for pattern in node.patterns]
1982 )
1983 return newnode
1985 if sys.version_info >= (3, 14):
1987 def visit_templatestr(
1988 self, node: ast.TemplateStr, parent: nodes.NodeNG
1989 ) -> nodes.TemplateStr:
1990 newnode = nodes.TemplateStr(
1991 lineno=node.lineno,
1992 col_offset=node.col_offset,
1993 end_lineno=node.end_lineno,
1994 end_col_offset=node.end_col_offset,
1995 parent=parent,
1996 )
1997 newnode.postinit(
1998 values=[self.visit(value, newnode) for value in node.values]
1999 )
2000 return newnode
2002 def visit_interpolation(
2003 self, node: ast.Interpolation, parent: nodes.NodeNG
2004 ) -> nodes.Interpolation:
2005 newnode = nodes.Interpolation(
2006 lineno=node.lineno,
2007 col_offset=node.col_offset,
2008 end_lineno=node.end_lineno,
2009 end_col_offset=node.end_col_offset,
2010 parent=parent,
2011 )
2012 newnode.postinit(
2013 value=self.visit(node.value, parent),
2014 str=node.str,
2015 conversion=node.conversion,
2016 format_spec=self.visit(node.format_spec, parent),
2017 )
2018 return newnode