1# Copyright (c) 2009-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr> 2# Copyright (c) 2013-2020 Claudiu Popa <pcmanticore@gmail.com> 3# Copyright (c) 2013-2014 Google, Inc. 4# Copyright (c) 2014 Alexander Presnyakov <flagist0@gmail.com> 5# Copyright (c) 2014 Eevee (Alex Munroe) <amunroe@yelp.com> 6# Copyright (c) 2015-2016 Ceridwen <ceridwenv@gmail.com> 7# Copyright (c) 2016-2017 Derek Gustafson <degustaf@gmail.com> 8# Copyright (c) 2016 Jared Garst <jgarst@users.noreply.github.com> 9# Copyright (c) 2017 Hugo <hugovk@users.noreply.github.com> 10# Copyright (c) 2017 Łukasz Rogalski <rogalski.91@gmail.com> 11# Copyright (c) 2017 rr- <rr-@sakuya.pl> 12# Copyright (c) 2018-2019 Ville Skyttä <ville.skytta@iki.fi> 13# Copyright (c) 2018 Tomas Gavenciak <gavento@ucw.cz> 14# Copyright (c) 2018 Serhiy Storchaka <storchaka@gmail.com> 15# Copyright (c) 2018 Nick Drozd <nicholasdrozd@gmail.com> 16# Copyright (c) 2018 Bryce Guinta <bryce.paul.guinta@gmail.com> 17# Copyright (c) 2019-2021 Ashley Whetter <ashley@awhetter.co.uk> 18# Copyright (c) 2019 Hugo van Kemenade <hugovk@users.noreply.github.com> 19# Copyright (c) 2019 Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> 20# Copyright (c) 2021 Marc Mueller <30130371+cdce8p@users.noreply.github.com> 21# Copyright (c) 2021 Daniël van Noord <13665637+DanielNoord@users.noreply.github.com> 22# Copyright (c) 2021 Pierre Sassoulas <pierre.sassoulas@gmail.com> 23# Copyright (c) 2021 Federico Bond <federicobond@gmail.com> 24# Copyright (c) 2021 hippo91 <guillaume.peillex@gmail.com> 25 26# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html 27# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE 28 29"""this module contains utilities for rebuilding an _ast tree in 30order to get a single Astroid representation 31""" 32 33import sys 34from typing import ( 35 TYPE_CHECKING, 36 Callable, 37 Dict, 38 Generator, 39 List, 40 Optional, 41 Tuple, 42 Type, 43 TypeVar, 44 Union, 45 cast, 46 overload, 47) 48 49from astroid import nodes 50from astroid._ast import ParserModule, get_parser_module, parse_function_type_comment 51from astroid.const import PY37_PLUS, PY38, PY38_PLUS, Context 52from astroid.manager import AstroidManager 53from astroid.nodes import NodeNG 54 55if sys.version_info >= (3, 8): 56 from typing import Final 57else: 58 from typing_extensions import Final 59 60if TYPE_CHECKING: 61 import ast 62 63 64REDIRECT: Final[Dict[str, str]] = { 65 "arguments": "Arguments", 66 "comprehension": "Comprehension", 67 "ListCompFor": "Comprehension", 68 "GenExprFor": "Comprehension", 69 "excepthandler": "ExceptHandler", 70 "keyword": "Keyword", 71 "match_case": "MatchCase", 72} 73 74 75T_Doc = TypeVar( 76 "T_Doc", 77 "ast.Module", 78 "ast.ClassDef", 79 Union["ast.FunctionDef", "ast.AsyncFunctionDef"], 80) 81T_Function = TypeVar("T_Function", nodes.FunctionDef, nodes.AsyncFunctionDef) 82T_For = TypeVar("T_For", nodes.For, nodes.AsyncFor) 83T_With = TypeVar("T_With", nodes.With, nodes.AsyncWith) 84 85 86# noinspection PyMethodMayBeStatic 87class TreeRebuilder: 88 """Rebuilds the _ast tree to become an Astroid tree""" 89 90 def __init__( 91 self, manager: AstroidManager, parser_module: Optional[ParserModule] = None 92 ): 93 self._manager = manager 94 self._global_names: List[Dict[str, List[nodes.Global]]] = [] 95 self._import_from_nodes: List[nodes.ImportFrom] = [] 96 self._delayed_assattr: List[nodes.AssignAttr] = [] 97 self._visit_meths: Dict[ 98 Type["ast.AST"], Callable[["ast.AST", NodeNG], NodeNG] 99 ] = {} 100 101 if parser_module is None: 102 self._parser_module = get_parser_module() 103 else: 104 self._parser_module = parser_module 105 self._module = self._parser_module.module 106 107 def _get_doc(self, node: T_Doc) -> Tuple[T_Doc, Optional[str]]: 108 try: 109 if PY37_PLUS and hasattr(node, "docstring"): 110 doc = node.docstring 111 return node, doc 112 if node.body and isinstance(node.body[0], self._module.Expr): 113 114 first_value = node.body[0].value 115 if isinstance(first_value, self._module.Str) or ( 116 PY38_PLUS 117 and isinstance(first_value, self._module.Constant) 118 and isinstance(first_value.value, str) 119 ): 120 doc = first_value.value if PY38_PLUS else first_value.s 121 node.body = node.body[1:] 122 return node, doc 123 except IndexError: 124 pass # ast built from scratch 125 return node, None 126 127 def _get_context( 128 self, 129 node: Union[ 130 "ast.Attribute", 131 "ast.List", 132 "ast.Name", 133 "ast.Subscript", 134 "ast.Starred", 135 "ast.Tuple", 136 ], 137 ) -> Context: 138 return self._parser_module.context_classes.get(type(node.ctx), Context.Load) 139 140 def visit_module( 141 self, node: "ast.Module", modname: str, modpath: str, package: bool 142 ) -> nodes.Module: 143 """visit a Module node by returning a fresh instance of it 144 145 Note: Method not called by 'visit' 146 """ 147 node, doc = self._get_doc(node) 148 newnode = nodes.Module( 149 name=modname, 150 doc=doc, 151 file=modpath, 152 path=[modpath], 153 package=package, 154 parent=None, 155 ) 156 newnode.postinit([self.visit(child, newnode) for child in node.body]) 157 return newnode 158 159 if sys.version_info >= (3, 10): 160 161 @overload 162 def visit(self, node: "ast.arg", parent: NodeNG) -> nodes.AssignName: 163 ... 164 165 @overload 166 def visit(self, node: "ast.arguments", parent: NodeNG) -> nodes.Arguments: 167 ... 168 169 @overload 170 def visit(self, node: "ast.Assert", parent: NodeNG) -> nodes.Assert: 171 ... 172 173 @overload 174 def visit( 175 self, node: "ast.AsyncFunctionDef", parent: NodeNG 176 ) -> nodes.AsyncFunctionDef: 177 ... 178 179 @overload 180 def visit(self, node: "ast.AsyncFor", parent: NodeNG) -> nodes.AsyncFor: 181 ... 182 183 @overload 184 def visit(self, node: "ast.Await", parent: NodeNG) -> nodes.Await: 185 ... 186 187 @overload 188 def visit(self, node: "ast.AsyncWith", parent: NodeNG) -> nodes.AsyncWith: 189 ... 190 191 @overload 192 def visit(self, node: "ast.Assign", parent: NodeNG) -> nodes.Assign: 193 ... 194 195 @overload 196 def visit(self, node: "ast.AnnAssign", parent: NodeNG) -> nodes.AnnAssign: 197 ... 198 199 @overload 200 def visit(self, node: "ast.AugAssign", parent: NodeNG) -> nodes.AugAssign: 201 ... 202 203 @overload 204 def visit(self, node: "ast.BinOp", parent: NodeNG) -> nodes.BinOp: 205 ... 206 207 @overload 208 def visit(self, node: "ast.BoolOp", parent: NodeNG) -> nodes.BoolOp: 209 ... 210 211 @overload 212 def visit(self, node: "ast.Break", parent: NodeNG) -> nodes.Break: 213 ... 214 215 @overload 216 def visit(self, node: "ast.Call", parent: NodeNG) -> nodes.Call: 217 ... 218 219 @overload 220 def visit(self, node: "ast.ClassDef", parent: NodeNG) -> nodes.ClassDef: 221 ... 222 223 @overload 224 def visit(self, node: "ast.Continue", parent: NodeNG) -> nodes.Continue: 225 ... 226 227 @overload 228 def visit(self, node: "ast.Compare", parent: NodeNG) -> nodes.Compare: 229 ... 230 231 @overload 232 def visit( 233 self, node: "ast.comprehension", parent: NodeNG 234 ) -> nodes.Comprehension: 235 ... 236 237 @overload 238 def visit(self, node: "ast.Delete", parent: NodeNG) -> nodes.Delete: 239 ... 240 241 @overload 242 def visit(self, node: "ast.Dict", parent: NodeNG) -> nodes.Dict: 243 ... 244 245 @overload 246 def visit(self, node: "ast.DictComp", parent: NodeNG) -> nodes.DictComp: 247 ... 248 249 @overload 250 def visit(self, node: "ast.Expr", parent: NodeNG) -> nodes.Expr: 251 ... 252 253 # Not used in Python 3.8+ 254 @overload 255 def visit(self, node: "ast.Ellipsis", parent: NodeNG) -> nodes.Const: 256 ... 257 258 @overload 259 def visit( 260 self, node: "ast.ExceptHandler", parent: NodeNG 261 ) -> nodes.ExceptHandler: 262 ... 263 264 # Not used in Python 3.9+ 265 @overload 266 def visit(self, node: "ast.ExtSlice", parent: nodes.Subscript) -> nodes.Tuple: 267 ... 268 269 @overload 270 def visit(self, node: "ast.For", parent: NodeNG) -> nodes.For: 271 ... 272 273 @overload 274 def visit(self, node: "ast.ImportFrom", parent: NodeNG) -> nodes.ImportFrom: 275 ... 276 277 @overload 278 def visit(self, node: "ast.FunctionDef", parent: NodeNG) -> nodes.FunctionDef: 279 ... 280 281 @overload 282 def visit(self, node: "ast.GeneratorExp", parent: NodeNG) -> nodes.GeneratorExp: 283 ... 284 285 @overload 286 def visit(self, node: "ast.Attribute", parent: NodeNG) -> nodes.Attribute: 287 ... 288 289 @overload 290 def visit(self, node: "ast.Global", parent: NodeNG) -> nodes.Global: 291 ... 292 293 @overload 294 def visit(self, node: "ast.If", parent: NodeNG) -> nodes.If: 295 ... 296 297 @overload 298 def visit(self, node: "ast.IfExp", parent: NodeNG) -> nodes.IfExp: 299 ... 300 301 @overload 302 def visit(self, node: "ast.Import", parent: NodeNG) -> nodes.Import: 303 ... 304 305 @overload 306 def visit(self, node: "ast.JoinedStr", parent: NodeNG) -> nodes.JoinedStr: 307 ... 308 309 @overload 310 def visit( 311 self, node: "ast.FormattedValue", parent: NodeNG 312 ) -> nodes.FormattedValue: 313 ... 314 315 @overload 316 def visit(self, node: "ast.NamedExpr", parent: NodeNG) -> nodes.NamedExpr: 317 ... 318 319 # Not used in Python 3.9+ 320 @overload 321 def visit(self, node: "ast.Index", parent: nodes.Subscript) -> NodeNG: 322 ... 323 324 @overload 325 def visit(self, node: "ast.keyword", parent: NodeNG) -> nodes.Keyword: 326 ... 327 328 @overload 329 def visit(self, node: "ast.Lambda", parent: NodeNG) -> nodes.Lambda: 330 ... 331 332 @overload 333 def visit(self, node: "ast.List", parent: NodeNG) -> nodes.List: 334 ... 335 336 @overload 337 def visit(self, node: "ast.ListComp", parent: NodeNG) -> nodes.ListComp: 338 ... 339 340 @overload 341 def visit( 342 self, node: "ast.Name", parent: NodeNG 343 ) -> Union[nodes.Name, nodes.Const, nodes.AssignName, nodes.DelName]: 344 ... 345 346 # Not used in Python 3.8+ 347 @overload 348 def visit(self, node: "ast.NameConstant", parent: NodeNG) -> nodes.Const: 349 ... 350 351 @overload 352 def visit(self, node: "ast.Nonlocal", parent: NodeNG) -> nodes.Nonlocal: 353 ... 354 355 # Not used in Python 3.8+ 356 @overload 357 def visit(self, node: "ast.Str", parent: NodeNG) -> nodes.Const: 358 ... 359 360 # Not used in Python 3.8+ 361 @overload 362 def visit(self, node: "ast.Bytes", parent: NodeNG) -> nodes.Const: 363 ... 364 365 # Not used in Python 3.8+ 366 @overload 367 def visit(self, node: "ast.Num", parent: NodeNG) -> nodes.Const: 368 ... 369 370 @overload 371 def visit(self, node: "ast.Constant", parent: NodeNG) -> nodes.Const: 372 ... 373 374 @overload 375 def visit(self, node: "ast.Pass", parent: NodeNG) -> nodes.Pass: 376 ... 377 378 @overload 379 def visit(self, node: "ast.Raise", parent: NodeNG) -> nodes.Raise: 380 ... 381 382 @overload 383 def visit(self, node: "ast.Return", parent: NodeNG) -> nodes.Return: 384 ... 385 386 @overload 387 def visit(self, node: "ast.Set", parent: NodeNG) -> nodes.Set: 388 ... 389 390 @overload 391 def visit(self, node: "ast.SetComp", parent: NodeNG) -> nodes.SetComp: 392 ... 393 394 @overload 395 def visit(self, node: "ast.Slice", parent: nodes.Subscript) -> nodes.Slice: 396 ... 397 398 @overload 399 def visit(self, node: "ast.Subscript", parent: NodeNG) -> nodes.Subscript: 400 ... 401 402 @overload 403 def visit(self, node: "ast.Starred", parent: NodeNG) -> nodes.Starred: 404 ... 405 406 @overload 407 def visit( 408 self, node: "ast.Try", parent: NodeNG 409 ) -> Union[nodes.TryExcept, nodes.TryFinally]: 410 ... 411 412 @overload 413 def visit(self, node: "ast.Tuple", parent: NodeNG) -> nodes.Tuple: 414 ... 415 416 @overload 417 def visit(self, node: "ast.UnaryOp", parent: NodeNG) -> nodes.UnaryOp: 418 ... 419 420 @overload 421 def visit(self, node: "ast.While", parent: NodeNG) -> nodes.While: 422 ... 423 424 @overload 425 def visit(self, node: "ast.With", parent: NodeNG) -> nodes.With: 426 ... 427 428 @overload 429 def visit(self, node: "ast.Yield", parent: NodeNG) -> nodes.Yield: 430 ... 431 432 @overload 433 def visit(self, node: "ast.YieldFrom", parent: NodeNG) -> nodes.YieldFrom: 434 ... 435 436 @overload 437 def visit(self, node: "ast.Match", parent: NodeNG) -> nodes.Match: 438 ... 439 440 @overload 441 def visit(self, node: "ast.match_case", parent: NodeNG) -> nodes.MatchCase: 442 ... 443 444 @overload 445 def visit(self, node: "ast.MatchValue", parent: NodeNG) -> nodes.MatchValue: 446 ... 447 448 @overload 449 def visit( 450 self, node: "ast.MatchSingleton", parent: NodeNG 451 ) -> nodes.MatchSingleton: 452 ... 453 454 @overload 455 def visit( 456 self, node: "ast.MatchSequence", parent: NodeNG 457 ) -> nodes.MatchSequence: 458 ... 459 460 @overload 461 def visit(self, node: "ast.MatchMapping", parent: NodeNG) -> nodes.MatchMapping: 462 ... 463 464 @overload 465 def visit(self, node: "ast.MatchClass", parent: NodeNG) -> nodes.MatchClass: 466 ... 467 468 @overload 469 def visit(self, node: "ast.MatchStar", parent: NodeNG) -> nodes.MatchStar: 470 ... 471 472 @overload 473 def visit(self, node: "ast.MatchAs", parent: NodeNG) -> nodes.MatchAs: 474 ... 475 476 @overload 477 def visit(self, node: "ast.MatchOr", parent: NodeNG) -> nodes.MatchOr: 478 ... 479 480 @overload 481 def visit(self, node: "ast.pattern", parent: NodeNG) -> nodes.Pattern: 482 ... 483 484 @overload 485 def visit(self, node: "ast.AST", parent: NodeNG) -> NodeNG: 486 ... 487 488 @overload 489 def visit(self, node: None, parent: NodeNG) -> None: 490 ... 491 492 def visit(self, node: Optional["ast.AST"], parent: NodeNG) -> Optional[NodeNG]: 493 if node is None: 494 return None 495 cls = node.__class__ 496 if cls in self._visit_meths: 497 visit_method = self._visit_meths[cls] 498 else: 499 cls_name = cls.__name__ 500 visit_name = "visit_" + REDIRECT.get(cls_name, cls_name).lower() 501 visit_method = getattr(self, visit_name) 502 self._visit_meths[cls] = visit_method 503 return visit_method(node, parent) 504 505 else: 506 507 @overload 508 def visit(self, node: "ast.arg", parent: NodeNG) -> nodes.AssignName: 509 ... 510 511 @overload 512 def visit(self, node: "ast.arguments", parent: NodeNG) -> nodes.Arguments: 513 ... 514 515 @overload 516 def visit(self, node: "ast.Assert", parent: NodeNG) -> nodes.Assert: 517 ... 518 519 @overload 520 def visit( 521 self, node: "ast.AsyncFunctionDef", parent: NodeNG 522 ) -> nodes.AsyncFunctionDef: 523 ... 524 525 @overload 526 def visit(self, node: "ast.AsyncFor", parent: NodeNG) -> nodes.AsyncFor: 527 ... 528 529 @overload 530 def visit(self, node: "ast.Await", parent: NodeNG) -> nodes.Await: 531 ... 532 533 @overload 534 def visit(self, node: "ast.AsyncWith", parent: NodeNG) -> nodes.AsyncWith: 535 ... 536 537 @overload 538 def visit(self, node: "ast.Assign", parent: NodeNG) -> nodes.Assign: 539 ... 540 541 @overload 542 def visit(self, node: "ast.AnnAssign", parent: NodeNG) -> nodes.AnnAssign: 543 ... 544 545 @overload 546 def visit(self, node: "ast.AugAssign", parent: NodeNG) -> nodes.AugAssign: 547 ... 548 549 @overload 550 def visit(self, node: "ast.BinOp", parent: NodeNG) -> nodes.BinOp: 551 ... 552 553 @overload 554 def visit(self, node: "ast.BoolOp", parent: NodeNG) -> nodes.BoolOp: 555 ... 556 557 @overload 558 def visit(self, node: "ast.Break", parent: NodeNG) -> nodes.Break: 559 ... 560 561 @overload 562 def visit(self, node: "ast.Call", parent: NodeNG) -> nodes.Call: 563 ... 564 565 @overload 566 def visit(self, node: "ast.ClassDef", parent: NodeNG) -> nodes.ClassDef: 567 ... 568 569 @overload 570 def visit(self, node: "ast.Continue", parent: NodeNG) -> nodes.Continue: 571 ... 572 573 @overload 574 def visit(self, node: "ast.Compare", parent: NodeNG) -> nodes.Compare: 575 ... 576 577 @overload 578 def visit( 579 self, node: "ast.comprehension", parent: NodeNG 580 ) -> nodes.Comprehension: 581 ... 582 583 @overload 584 def visit(self, node: "ast.Delete", parent: NodeNG) -> nodes.Delete: 585 ... 586 587 @overload 588 def visit(self, node: "ast.Dict", parent: NodeNG) -> nodes.Dict: 589 ... 590 591 @overload 592 def visit(self, node: "ast.DictComp", parent: NodeNG) -> nodes.DictComp: 593 ... 594 595 @overload 596 def visit(self, node: "ast.Expr", parent: NodeNG) -> nodes.Expr: 597 ... 598 599 # Not used in Python 3.8+ 600 @overload 601 def visit(self, node: "ast.Ellipsis", parent: NodeNG) -> nodes.Const: 602 ... 603 604 @overload 605 def visit( 606 self, node: "ast.ExceptHandler", parent: NodeNG 607 ) -> nodes.ExceptHandler: 608 ... 609 610 # Not used in Python 3.9+ 611 @overload 612 def visit(self, node: "ast.ExtSlice", parent: nodes.Subscript) -> nodes.Tuple: 613 ... 614 615 @overload 616 def visit(self, node: "ast.For", parent: NodeNG) -> nodes.For: 617 ... 618 619 @overload 620 def visit(self, node: "ast.ImportFrom", parent: NodeNG) -> nodes.ImportFrom: 621 ... 622 623 @overload 624 def visit(self, node: "ast.FunctionDef", parent: NodeNG) -> nodes.FunctionDef: 625 ... 626 627 @overload 628 def visit(self, node: "ast.GeneratorExp", parent: NodeNG) -> nodes.GeneratorExp: 629 ... 630 631 @overload 632 def visit(self, node: "ast.Attribute", parent: NodeNG) -> nodes.Attribute: 633 ... 634 635 @overload 636 def visit(self, node: "ast.Global", parent: NodeNG) -> nodes.Global: 637 ... 638 639 @overload 640 def visit(self, node: "ast.If", parent: NodeNG) -> nodes.If: 641 ... 642 643 @overload 644 def visit(self, node: "ast.IfExp", parent: NodeNG) -> nodes.IfExp: 645 ... 646 647 @overload 648 def visit(self, node: "ast.Import", parent: NodeNG) -> nodes.Import: 649 ... 650 651 @overload 652 def visit(self, node: "ast.JoinedStr", parent: NodeNG) -> nodes.JoinedStr: 653 ... 654 655 @overload 656 def visit( 657 self, node: "ast.FormattedValue", parent: NodeNG 658 ) -> nodes.FormattedValue: 659 ... 660 661 @overload 662 def visit(self, node: "ast.NamedExpr", parent: NodeNG) -> nodes.NamedExpr: 663 ... 664 665 # Not used in Python 3.9+ 666 @overload 667 def visit(self, node: "ast.Index", parent: nodes.Subscript) -> NodeNG: 668 ... 669 670 @overload 671 def visit(self, node: "ast.keyword", parent: NodeNG) -> nodes.Keyword: 672 ... 673 674 @overload 675 def visit(self, node: "ast.Lambda", parent: NodeNG) -> nodes.Lambda: 676 ... 677 678 @overload 679 def visit(self, node: "ast.List", parent: NodeNG) -> nodes.List: 680 ... 681 682 @overload 683 def visit(self, node: "ast.ListComp", parent: NodeNG) -> nodes.ListComp: 684 ... 685 686 @overload 687 def visit( 688 self, node: "ast.Name", parent: NodeNG 689 ) -> Union[nodes.Name, nodes.Const, nodes.AssignName, nodes.DelName]: 690 ... 691 692 # Not used in Python 3.8+ 693 @overload 694 def visit(self, node: "ast.NameConstant", parent: NodeNG) -> nodes.Const: 695 ... 696 697 @overload 698 def visit(self, node: "ast.Nonlocal", parent: NodeNG) -> nodes.Nonlocal: 699 ... 700 701 # Not used in Python 3.8+ 702 @overload 703 def visit(self, node: "ast.Str", parent: NodeNG) -> nodes.Const: 704 ... 705 706 # Not used in Python 3.8+ 707 @overload 708 def visit(self, node: "ast.Bytes", parent: NodeNG) -> nodes.Const: 709 ... 710 711 # Not used in Python 3.8+ 712 @overload 713 def visit(self, node: "ast.Num", parent: NodeNG) -> nodes.Const: 714 ... 715 716 @overload 717 def visit(self, node: "ast.Constant", parent: NodeNG) -> nodes.Const: 718 ... 719 720 @overload 721 def visit(self, node: "ast.Pass", parent: NodeNG) -> nodes.Pass: 722 ... 723 724 @overload 725 def visit(self, node: "ast.Raise", parent: NodeNG) -> nodes.Raise: 726 ... 727 728 @overload 729 def visit(self, node: "ast.Return", parent: NodeNG) -> nodes.Return: 730 ... 731 732 @overload 733 def visit(self, node: "ast.Set", parent: NodeNG) -> nodes.Set: 734 ... 735 736 @overload 737 def visit(self, node: "ast.SetComp", parent: NodeNG) -> nodes.SetComp: 738 ... 739 740 @overload 741 def visit(self, node: "ast.Slice", parent: nodes.Subscript) -> nodes.Slice: 742 ... 743 744 @overload 745 def visit(self, node: "ast.Subscript", parent: NodeNG) -> nodes.Subscript: 746 ... 747 748 @overload 749 def visit(self, node: "ast.Starred", parent: NodeNG) -> nodes.Starred: 750 ... 751 752 @overload 753 def visit( 754 self, node: "ast.Try", parent: NodeNG 755 ) -> Union[nodes.TryExcept, nodes.TryFinally]: 756 ... 757 758 @overload 759 def visit(self, node: "ast.Tuple", parent: NodeNG) -> nodes.Tuple: 760 ... 761 762 @overload 763 def visit(self, node: "ast.UnaryOp", parent: NodeNG) -> nodes.UnaryOp: 764 ... 765 766 @overload 767 def visit(self, node: "ast.While", parent: NodeNG) -> nodes.While: 768 ... 769 770 @overload 771 def visit(self, node: "ast.With", parent: NodeNG) -> nodes.With: 772 ... 773 774 @overload 775 def visit(self, node: "ast.Yield", parent: NodeNG) -> nodes.Yield: 776 ... 777 778 @overload 779 def visit(self, node: "ast.YieldFrom", parent: NodeNG) -> nodes.YieldFrom: 780 ... 781 782 @overload 783 def visit(self, node: "ast.AST", parent: NodeNG) -> NodeNG: 784 ... 785 786 @overload 787 def visit(self, node: None, parent: NodeNG) -> None: 788 ... 789 790 def visit(self, node: Optional["ast.AST"], parent: NodeNG) -> Optional[NodeNG]: 791 if node is None: 792 return None 793 cls = node.__class__ 794 if cls in self._visit_meths: 795 visit_method = self._visit_meths[cls] 796 else: 797 cls_name = cls.__name__ 798 visit_name = "visit_" + REDIRECT.get(cls_name, cls_name).lower() 799 visit_method = getattr(self, visit_name) 800 self._visit_meths[cls] = visit_method 801 return visit_method(node, parent) 802 803 def _save_assignment(self, node: Union[nodes.AssignName, nodes.DelName]) -> None: 804 """save assignment situation since node.parent is not available yet""" 805 if self._global_names and node.name in self._global_names[-1]: 806 node.root().set_local(node.name, node) 807 else: 808 node.parent.set_local(node.name, node) 809 810 def visit_arg(self, node: "ast.arg", parent: NodeNG) -> nodes.AssignName: 811 """visit an arg node by returning a fresh AssName instance""" 812 return self.visit_assignname(node, parent, node.arg) 813 814 def visit_arguments(self, node: "ast.arguments", parent: NodeNG) -> nodes.Arguments: 815 """visit an Arguments node by returning a fresh instance of it""" 816 vararg: Optional[str] = None 817 kwarg: Optional[str] = None 818 newnode = nodes.Arguments( 819 node.vararg.arg if node.vararg else None, 820 node.kwarg.arg if node.kwarg else None, 821 parent, 822 ) 823 args = [self.visit(child, newnode) for child in node.args] 824 defaults = [self.visit(child, newnode) for child in node.defaults] 825 varargannotation: Optional[NodeNG] = None 826 kwargannotation: Optional[NodeNG] = None 827 posonlyargs: List[nodes.AssignName] = [] 828 if node.vararg: 829 vararg = node.vararg.arg 830 varargannotation = self.visit(node.vararg.annotation, newnode) 831 if node.kwarg: 832 kwarg = node.kwarg.arg 833 kwargannotation = self.visit(node.kwarg.annotation, newnode) 834 835 if PY38: 836 # In Python 3.8 'end_lineno' and 'end_col_offset' 837 # for 'kwonlyargs' don't include the annotation. 838 for arg in node.kwonlyargs: 839 if arg.annotation is not None: 840 arg.end_lineno = arg.annotation.end_lineno 841 arg.end_col_offset = arg.annotation.end_col_offset 842 843 kwonlyargs = [self.visit(child, newnode) for child in node.kwonlyargs] 844 kw_defaults = [self.visit(child, newnode) for child in node.kw_defaults] 845 annotations = [self.visit(arg.annotation, newnode) for arg in node.args] 846 kwonlyargs_annotations = [ 847 self.visit(arg.annotation, newnode) for arg in node.kwonlyargs 848 ] 849 850 posonlyargs_annotations: List[Optional[NodeNG]] = [] 851 if PY38_PLUS: 852 posonlyargs = [self.visit(child, newnode) for child in node.posonlyargs] 853 posonlyargs_annotations = [ 854 self.visit(arg.annotation, newnode) for arg in node.posonlyargs 855 ] 856 type_comment_args = [ 857 self.check_type_comment(child, parent=newnode) for child in node.args 858 ] 859 type_comment_kwonlyargs = [ 860 self.check_type_comment(child, parent=newnode) for child in node.kwonlyargs 861 ] 862 type_comment_posonlyargs: List[Optional[NodeNG]] = [] 863 if PY38_PLUS: 864 type_comment_posonlyargs = [ 865 self.check_type_comment(child, parent=newnode) 866 for child in node.posonlyargs 867 ] 868 869 newnode.postinit( 870 args=args, 871 defaults=defaults, 872 kwonlyargs=kwonlyargs, 873 posonlyargs=posonlyargs, 874 kw_defaults=kw_defaults, 875 annotations=annotations, 876 kwonlyargs_annotations=kwonlyargs_annotations, 877 posonlyargs_annotations=posonlyargs_annotations, 878 varargannotation=varargannotation, 879 kwargannotation=kwargannotation, 880 type_comment_args=type_comment_args, 881 type_comment_kwonlyargs=type_comment_kwonlyargs, 882 type_comment_posonlyargs=type_comment_posonlyargs, 883 ) 884 # save argument names in locals: 885 if vararg: 886 newnode.parent.set_local(vararg, newnode) 887 if kwarg: 888 newnode.parent.set_local(kwarg, newnode) 889 return newnode 890 891 def visit_assert(self, node: "ast.Assert", parent: NodeNG) -> nodes.Assert: 892 """visit a Assert node by returning a fresh instance of it""" 893 if sys.version_info >= (3, 8): 894 newnode = nodes.Assert( 895 lineno=node.lineno, 896 col_offset=node.col_offset, 897 end_lineno=node.end_lineno, 898 end_col_offset=node.end_col_offset, 899 parent=parent, 900 ) 901 else: 902 newnode = nodes.Assert(node.lineno, node.col_offset, parent) 903 msg: Optional[NodeNG] = None 904 if node.msg: 905 msg = self.visit(node.msg, newnode) 906 newnode.postinit(self.visit(node.test, newnode), msg) 907 return newnode 908 909 def check_type_comment( 910 self, 911 node: Union[ 912 "ast.Assign", 913 "ast.arg", 914 "ast.For", 915 "ast.AsyncFor", 916 "ast.With", 917 "ast.AsyncWith", 918 ], 919 parent: Union[ 920 nodes.Assign, 921 nodes.Arguments, 922 nodes.For, 923 nodes.AsyncFor, 924 nodes.With, 925 nodes.AsyncWith, 926 ], 927 ) -> Optional[NodeNG]: 928 type_comment = getattr(node, "type_comment", None) # Added in Python 3.8 929 if not type_comment: 930 return None 931 932 try: 933 type_comment_ast = self._parser_module.parse(type_comment) 934 except SyntaxError: 935 # Invalid type comment, just skip it. 936 return None 937 938 type_object = self.visit(type_comment_ast.body[0], parent=parent) 939 if not isinstance(type_object, nodes.Expr): 940 return None 941 942 return type_object.value 943 944 def check_function_type_comment( 945 self, node: Union["ast.FunctionDef", "ast.AsyncFunctionDef"], parent: NodeNG 946 ) -> Optional[Tuple[Optional[NodeNG], List[NodeNG]]]: 947 type_comment = getattr(node, "type_comment", None) # Added in Python 3.8 948 if not type_comment: 949 return None 950 951 try: 952 type_comment_ast = parse_function_type_comment(type_comment) 953 except SyntaxError: 954 # Invalid type comment, just skip it. 955 return None 956 957 returns: Optional[NodeNG] = None 958 argtypes: List[NodeNG] = [ 959 self.visit(elem, parent) for elem in (type_comment_ast.argtypes or []) 960 ] 961 if type_comment_ast.returns: 962 returns = self.visit(type_comment_ast.returns, parent) 963 964 return returns, argtypes 965 966 def visit_asyncfunctiondef( 967 self, node: "ast.AsyncFunctionDef", parent: NodeNG 968 ) -> nodes.AsyncFunctionDef: 969 return self._visit_functiondef(nodes.AsyncFunctionDef, node, parent) 970 971 def visit_asyncfor(self, node: "ast.AsyncFor", parent: NodeNG) -> nodes.AsyncFor: 972 return self._visit_for(nodes.AsyncFor, node, parent) 973 974 def visit_await(self, node: "ast.Await", parent: NodeNG) -> nodes.Await: 975 if sys.version_info >= (3, 8): 976 newnode = nodes.Await( 977 lineno=node.lineno, 978 col_offset=node.col_offset, 979 end_lineno=node.end_lineno, 980 end_col_offset=node.end_col_offset, 981 parent=parent, 982 ) 983 else: 984 newnode = nodes.Await(node.lineno, node.col_offset, parent) 985 newnode.postinit(value=self.visit(node.value, newnode)) 986 return newnode 987 988 def visit_asyncwith(self, node: "ast.AsyncWith", parent: NodeNG) -> nodes.AsyncWith: 989 return self._visit_with(nodes.AsyncWith, node, parent) 990 991 def visit_assign(self, node: "ast.Assign", parent: NodeNG) -> nodes.Assign: 992 """visit a Assign node by returning a fresh instance of it""" 993 if sys.version_info >= (3, 8): 994 newnode = nodes.Assign( 995 lineno=node.lineno, 996 col_offset=node.col_offset, 997 end_lineno=node.end_lineno, 998 end_col_offset=node.end_col_offset, 999 parent=parent, 1000 ) 1001 else: 1002 newnode = nodes.Assign(node.lineno, node.col_offset, parent) 1003 type_annotation = self.check_type_comment(node, parent=newnode) 1004 newnode.postinit( 1005 targets=[self.visit(child, newnode) for child in node.targets], 1006 value=self.visit(node.value, newnode), 1007 type_annotation=type_annotation, 1008 ) 1009 return newnode 1010 1011 def visit_annassign(self, node: "ast.AnnAssign", parent: NodeNG) -> nodes.AnnAssign: 1012 """visit an AnnAssign node by returning a fresh instance of it""" 1013 if sys.version_info >= (3, 8): 1014 newnode = nodes.AnnAssign( 1015 lineno=node.lineno, 1016 col_offset=node.col_offset, 1017 end_lineno=node.end_lineno, 1018 end_col_offset=node.end_col_offset, 1019 parent=parent, 1020 ) 1021 else: 1022 newnode = nodes.AnnAssign(node.lineno, node.col_offset, parent) 1023 newnode.postinit( 1024 target=self.visit(node.target, newnode), 1025 annotation=self.visit(node.annotation, newnode), 1026 simple=node.simple, 1027 value=self.visit(node.value, newnode), 1028 ) 1029 return newnode 1030 1031 @overload 1032 def visit_assignname( 1033 self, node: "ast.AST", parent: NodeNG, node_name: str 1034 ) -> nodes.AssignName: 1035 ... 1036 1037 @overload 1038 def visit_assignname( 1039 self, node: "ast.AST", parent: NodeNG, node_name: None 1040 ) -> None: 1041 ... 1042 1043 def visit_assignname( 1044 self, node: "ast.AST", parent: NodeNG, node_name: Optional[str] 1045 ) -> Optional[nodes.AssignName]: 1046 """visit a node and return a AssignName node 1047 1048 Note: Method not called by 'visit' 1049 """ 1050 if node_name is None: 1051 return None 1052 if sys.version_info >= (3, 8): 1053 newnode = nodes.AssignName( 1054 name=node_name, 1055 lineno=node.lineno, 1056 col_offset=node.col_offset, 1057 end_lineno=node.end_lineno, 1058 end_col_offset=node.end_col_offset, 1059 parent=parent, 1060 ) 1061 else: 1062 newnode = nodes.AssignName( 1063 node_name, 1064 node.lineno, 1065 node.col_offset, 1066 parent, 1067 ) 1068 self._save_assignment(newnode) 1069 return newnode 1070 1071 def visit_augassign(self, node: "ast.AugAssign", parent: NodeNG) -> nodes.AugAssign: 1072 """visit a AugAssign node by returning a fresh instance of it""" 1073 if sys.version_info >= (3, 8): 1074 newnode = nodes.AugAssign( 1075 op=self._parser_module.bin_op_classes[type(node.op)] + "=", 1076 lineno=node.lineno, 1077 col_offset=node.col_offset, 1078 end_lineno=node.end_lineno, 1079 end_col_offset=node.end_col_offset, 1080 parent=parent, 1081 ) 1082 else: 1083 newnode = nodes.AugAssign( 1084 self._parser_module.bin_op_classes[type(node.op)] + "=", 1085 node.lineno, 1086 node.col_offset, 1087 parent, 1088 ) 1089 newnode.postinit( 1090 self.visit(node.target, newnode), self.visit(node.value, newnode) 1091 ) 1092 return newnode 1093 1094 def visit_binop(self, node: "ast.BinOp", parent: NodeNG) -> nodes.BinOp: 1095 """visit a BinOp node by returning a fresh instance of it""" 1096 if sys.version_info >= (3, 8): 1097 newnode = nodes.BinOp( 1098 op=self._parser_module.bin_op_classes[type(node.op)], 1099 lineno=node.lineno, 1100 col_offset=node.col_offset, 1101 end_lineno=node.end_lineno, 1102 end_col_offset=node.end_col_offset, 1103 parent=parent, 1104 ) 1105 else: 1106 newnode = nodes.BinOp( 1107 self._parser_module.bin_op_classes[type(node.op)], 1108 node.lineno, 1109 node.col_offset, 1110 parent, 1111 ) 1112 newnode.postinit( 1113 self.visit(node.left, newnode), self.visit(node.right, newnode) 1114 ) 1115 return newnode 1116 1117 def visit_boolop(self, node: "ast.BoolOp", parent: NodeNG) -> nodes.BoolOp: 1118 """visit a BoolOp node by returning a fresh instance of it""" 1119 if sys.version_info >= (3, 8): 1120 newnode = nodes.BoolOp( 1121 op=self._parser_module.bool_op_classes[type(node.op)], 1122 lineno=node.lineno, 1123 col_offset=node.col_offset, 1124 end_lineno=node.end_lineno, 1125 end_col_offset=node.end_col_offset, 1126 parent=parent, 1127 ) 1128 else: 1129 newnode = nodes.BoolOp( 1130 self._parser_module.bool_op_classes[type(node.op)], 1131 node.lineno, 1132 node.col_offset, 1133 parent, 1134 ) 1135 newnode.postinit([self.visit(child, newnode) for child in node.values]) 1136 return newnode 1137 1138 def visit_break(self, node: "ast.Break", parent: NodeNG) -> nodes.Break: 1139 """visit a Break node by returning a fresh instance of it""" 1140 if sys.version_info >= (3, 8): 1141 return nodes.Break( 1142 lineno=node.lineno, 1143 col_offset=node.col_offset, 1144 end_lineno=node.end_lineno, 1145 end_col_offset=node.end_col_offset, 1146 parent=parent, 1147 ) 1148 return nodes.Break(node.lineno, node.col_offset, parent) 1149 1150 def visit_call(self, node: "ast.Call", parent: NodeNG) -> nodes.Call: 1151 """visit a CallFunc node by returning a fresh instance of it""" 1152 if sys.version_info >= (3, 8): 1153 newnode = nodes.Call( 1154 lineno=node.lineno, 1155 col_offset=node.col_offset, 1156 end_lineno=node.end_lineno, 1157 end_col_offset=node.end_col_offset, 1158 parent=parent, 1159 ) 1160 else: 1161 newnode = nodes.Call(node.lineno, node.col_offset, parent) 1162 newnode.postinit( 1163 func=self.visit(node.func, newnode), 1164 args=[self.visit(child, newnode) for child in node.args], 1165 keywords=[self.visit(child, newnode) for child in node.keywords], 1166 ) 1167 return newnode 1168 1169 def visit_classdef( 1170 self, node: "ast.ClassDef", parent: NodeNG, newstyle: bool = True 1171 ) -> nodes.ClassDef: 1172 """visit a ClassDef node to become astroid""" 1173 node, doc = self._get_doc(node) 1174 if sys.version_info >= (3, 8): 1175 newnode = nodes.ClassDef( 1176 name=node.name, 1177 doc=doc, 1178 lineno=node.lineno, 1179 col_offset=node.col_offset, 1180 end_lineno=node.end_lineno, 1181 end_col_offset=node.end_col_offset, 1182 parent=parent, 1183 ) 1184 else: 1185 newnode = nodes.ClassDef( 1186 node.name, doc, node.lineno, node.col_offset, parent 1187 ) 1188 metaclass = None 1189 for keyword in node.keywords: 1190 if keyword.arg == "metaclass": 1191 metaclass = self.visit(keyword, newnode).value 1192 break 1193 decorators = self.visit_decorators(node, newnode) 1194 newnode.postinit( 1195 [self.visit(child, newnode) for child in node.bases], 1196 [self.visit(child, newnode) for child in node.body], 1197 decorators, 1198 newstyle, 1199 metaclass, 1200 [ 1201 self.visit(kwd, newnode) 1202 for kwd in node.keywords 1203 if kwd.arg != "metaclass" 1204 ], 1205 ) 1206 return newnode 1207 1208 def visit_continue(self, node: "ast.Continue", parent: NodeNG) -> nodes.Continue: 1209 """visit a Continue node by returning a fresh instance of it""" 1210 if sys.version_info >= (3, 8): 1211 return nodes.Continue( 1212 lineno=node.lineno, 1213 col_offset=node.col_offset, 1214 end_lineno=node.end_lineno, 1215 end_col_offset=node.end_col_offset, 1216 parent=parent, 1217 ) 1218 return nodes.Continue(node.lineno, node.col_offset, parent) 1219 1220 def visit_compare(self, node: "ast.Compare", parent: NodeNG) -> nodes.Compare: 1221 """visit a Compare node by returning a fresh instance of it""" 1222 if sys.version_info >= (3, 8): 1223 newnode = nodes.Compare( 1224 lineno=node.lineno, 1225 col_offset=node.col_offset, 1226 end_lineno=node.end_lineno, 1227 end_col_offset=node.end_col_offset, 1228 parent=parent, 1229 ) 1230 else: 1231 newnode = nodes.Compare(node.lineno, node.col_offset, parent) 1232 newnode.postinit( 1233 self.visit(node.left, newnode), 1234 [ 1235 ( 1236 self._parser_module.cmp_op_classes[op.__class__], 1237 self.visit(expr, newnode), 1238 ) 1239 for (op, expr) in zip(node.ops, node.comparators) 1240 ], 1241 ) 1242 return newnode 1243 1244 def visit_comprehension( 1245 self, node: "ast.comprehension", parent: NodeNG 1246 ) -> nodes.Comprehension: 1247 """visit a Comprehension node by returning a fresh instance of it""" 1248 newnode = nodes.Comprehension(parent) 1249 newnode.postinit( 1250 self.visit(node.target, newnode), 1251 self.visit(node.iter, newnode), 1252 [self.visit(child, newnode) for child in node.ifs], 1253 bool(node.is_async), 1254 ) 1255 return newnode 1256 1257 def visit_decorators( 1258 self, 1259 node: Union["ast.ClassDef", "ast.FunctionDef", "ast.AsyncFunctionDef"], 1260 parent: NodeNG, 1261 ) -> Optional[nodes.Decorators]: 1262 """visit a Decorators node by returning a fresh instance of it 1263 1264 Note: Method not called by 'visit' 1265 """ 1266 if not node.decorator_list: 1267 return None 1268 # /!\ node is actually an _ast.FunctionDef node while 1269 # parent is an astroid.nodes.FunctionDef node 1270 if sys.version_info >= (3, 8): 1271 # Set the line number of the first decorator for Python 3.8+. 1272 lineno = node.decorator_list[0].lineno 1273 end_lineno = node.decorator_list[-1].end_lineno 1274 end_col_offset = node.decorator_list[-1].end_col_offset 1275 else: 1276 lineno = node.lineno 1277 end_lineno = None 1278 end_col_offset = None 1279 newnode = nodes.Decorators( 1280 lineno=lineno, 1281 col_offset=node.col_offset, 1282 end_lineno=end_lineno, 1283 end_col_offset=end_col_offset, 1284 parent=parent, 1285 ) 1286 newnode.postinit([self.visit(child, newnode) for child in node.decorator_list]) 1287 return newnode 1288 1289 def visit_delete(self, node: "ast.Delete", parent: NodeNG) -> nodes.Delete: 1290 """visit a Delete node by returning a fresh instance of it""" 1291 if sys.version_info >= (3, 8): 1292 newnode = nodes.Delete( 1293 lineno=node.lineno, 1294 col_offset=node.col_offset, 1295 end_lineno=node.end_lineno, 1296 end_col_offset=node.end_col_offset, 1297 parent=parent, 1298 ) 1299 else: 1300 newnode = nodes.Delete(node.lineno, node.col_offset, parent) 1301 newnode.postinit([self.visit(child, newnode) for child in node.targets]) 1302 return newnode 1303 1304 def _visit_dict_items( 1305 self, node: "ast.Dict", parent: NodeNG, newnode: nodes.Dict 1306 ) -> Generator[Tuple[NodeNG, NodeNG], None, None]: 1307 for key, value in zip(node.keys, node.values): 1308 rebuilt_key: NodeNG 1309 rebuilt_value = self.visit(value, newnode) 1310 if not key: 1311 # Extended unpacking 1312 if sys.version_info >= (3, 8): 1313 rebuilt_key = nodes.DictUnpack( 1314 lineno=rebuilt_value.lineno, 1315 col_offset=rebuilt_value.col_offset, 1316 end_lineno=rebuilt_value.end_lineno, 1317 end_col_offset=rebuilt_value.end_col_offset, 1318 parent=parent, 1319 ) 1320 else: 1321 rebuilt_key = nodes.DictUnpack( 1322 rebuilt_value.lineno, rebuilt_value.col_offset, parent 1323 ) 1324 else: 1325 rebuilt_key = self.visit(key, newnode) 1326 yield rebuilt_key, rebuilt_value 1327 1328 def visit_dict(self, node: "ast.Dict", parent: NodeNG) -> nodes.Dict: 1329 """visit a Dict node by returning a fresh instance of it""" 1330 if sys.version_info >= (3, 8): 1331 newnode = nodes.Dict( 1332 lineno=node.lineno, 1333 col_offset=node.col_offset, 1334 end_lineno=node.end_lineno, 1335 end_col_offset=node.end_col_offset, 1336 parent=parent, 1337 ) 1338 else: 1339 newnode = nodes.Dict(node.lineno, node.col_offset, parent) 1340 items = list(self._visit_dict_items(node, parent, newnode)) 1341 newnode.postinit(items) 1342 return newnode 1343 1344 def visit_dictcomp(self, node: "ast.DictComp", parent: NodeNG) -> nodes.DictComp: 1345 """visit a DictComp node by returning a fresh instance of it""" 1346 if sys.version_info >= (3, 8): 1347 newnode = nodes.DictComp( 1348 lineno=node.lineno, 1349 col_offset=node.col_offset, 1350 end_lineno=node.end_lineno, 1351 end_col_offset=node.end_col_offset, 1352 parent=parent, 1353 ) 1354 else: 1355 newnode = nodes.DictComp(node.lineno, node.col_offset, parent) 1356 newnode.postinit( 1357 self.visit(node.key, newnode), 1358 self.visit(node.value, newnode), 1359 [self.visit(child, newnode) for child in node.generators], 1360 ) 1361 return newnode 1362 1363 def visit_expr(self, node: "ast.Expr", parent: NodeNG) -> nodes.Expr: 1364 """visit a Expr node by returning a fresh instance of it""" 1365 if sys.version_info >= (3, 8): 1366 newnode = nodes.Expr( 1367 lineno=node.lineno, 1368 col_offset=node.col_offset, 1369 end_lineno=node.end_lineno, 1370 end_col_offset=node.end_col_offset, 1371 parent=parent, 1372 ) 1373 else: 1374 newnode = nodes.Expr(node.lineno, node.col_offset, parent) 1375 newnode.postinit(self.visit(node.value, newnode)) 1376 return newnode 1377 1378 # Not used in Python 3.8+. 1379 def visit_ellipsis(self, node: "ast.Ellipsis", parent: NodeNG) -> nodes.Const: 1380 """visit an Ellipsis node by returning a fresh instance of Const""" 1381 return nodes.Const( 1382 value=Ellipsis, 1383 lineno=node.lineno, 1384 col_offset=node.col_offset, 1385 parent=parent, 1386 ) 1387 1388 def visit_excepthandler( 1389 self, node: "ast.ExceptHandler", parent: NodeNG 1390 ) -> nodes.ExceptHandler: 1391 """visit an ExceptHandler node by returning a fresh instance of it""" 1392 if sys.version_info >= (3, 8): 1393 newnode = nodes.ExceptHandler( 1394 lineno=node.lineno, 1395 col_offset=node.col_offset, 1396 end_lineno=node.end_lineno, 1397 end_col_offset=node.end_col_offset, 1398 parent=parent, 1399 ) 1400 else: 1401 newnode = nodes.ExceptHandler(node.lineno, node.col_offset, parent) 1402 newnode.postinit( 1403 self.visit(node.type, newnode), 1404 self.visit_assignname(node, newnode, node.name), 1405 [self.visit(child, newnode) for child in node.body], 1406 ) 1407 return newnode 1408 1409 # Not used in Python 3.9+. 1410 def visit_extslice( 1411 self, node: "ast.ExtSlice", parent: nodes.Subscript 1412 ) -> nodes.Tuple: 1413 """visit an ExtSlice node by returning a fresh instance of Tuple""" 1414 # ExtSlice doesn't have lineno or col_offset information 1415 newnode = nodes.Tuple(ctx=Context.Load, parent=parent) 1416 newnode.postinit([self.visit(dim, newnode) for dim in node.dims]) # type: ignore[attr-defined] 1417 return newnode 1418 1419 @overload 1420 def _visit_for( 1421 self, cls: Type[nodes.For], node: "ast.For", parent: NodeNG 1422 ) -> nodes.For: 1423 ... 1424 1425 @overload 1426 def _visit_for( 1427 self, cls: Type[nodes.AsyncFor], node: "ast.AsyncFor", parent: NodeNG 1428 ) -> nodes.AsyncFor: 1429 ... 1430 1431 def _visit_for( 1432 self, cls: Type[T_For], node: Union["ast.For", "ast.AsyncFor"], parent: NodeNG 1433 ) -> T_For: 1434 """visit a For node by returning a fresh instance of it""" 1435 if sys.version_info >= (3, 8): 1436 newnode = cls( 1437 lineno=node.lineno, 1438 col_offset=node.col_offset, 1439 end_lineno=node.end_lineno, 1440 end_col_offset=node.end_col_offset, 1441 parent=parent, 1442 ) 1443 else: 1444 newnode = cls(node.lineno, node.col_offset, parent) 1445 type_annotation = self.check_type_comment(node, parent=newnode) 1446 newnode.postinit( 1447 target=self.visit(node.target, newnode), 1448 iter=self.visit(node.iter, newnode), 1449 body=[self.visit(child, newnode) for child in node.body], 1450 orelse=[self.visit(child, newnode) for child in node.orelse], 1451 type_annotation=type_annotation, 1452 ) 1453 return newnode 1454 1455 def visit_for(self, node: "ast.For", parent: NodeNG) -> nodes.For: 1456 return self._visit_for(nodes.For, node, parent) 1457 1458 def visit_importfrom( 1459 self, node: "ast.ImportFrom", parent: NodeNG 1460 ) -> nodes.ImportFrom: 1461 """visit an ImportFrom node by returning a fresh instance of it""" 1462 names = [(alias.name, alias.asname) for alias in node.names] 1463 if sys.version_info >= (3, 8): 1464 newnode = nodes.ImportFrom( 1465 fromname=node.module or "", 1466 names=names, 1467 level=node.level or None, 1468 lineno=node.lineno, 1469 col_offset=node.col_offset, 1470 end_lineno=node.end_lineno, 1471 end_col_offset=node.end_col_offset, 1472 parent=parent, 1473 ) 1474 else: 1475 newnode = nodes.ImportFrom( 1476 node.module or "", 1477 names, 1478 node.level or None, 1479 node.lineno, 1480 node.col_offset, 1481 parent, 1482 ) 1483 # store From names to add them to locals after building 1484 self._import_from_nodes.append(newnode) 1485 return newnode 1486 1487 @overload 1488 def _visit_functiondef( 1489 self, cls: Type[nodes.FunctionDef], node: "ast.FunctionDef", parent: NodeNG 1490 ) -> nodes.FunctionDef: 1491 ... 1492 1493 @overload 1494 def _visit_functiondef( 1495 self, 1496 cls: Type[nodes.AsyncFunctionDef], 1497 node: "ast.AsyncFunctionDef", 1498 parent: NodeNG, 1499 ) -> nodes.AsyncFunctionDef: 1500 ... 1501 1502 def _visit_functiondef( 1503 self, 1504 cls: Type[T_Function], 1505 node: Union["ast.FunctionDef", "ast.AsyncFunctionDef"], 1506 parent: NodeNG, 1507 ) -> T_Function: 1508 """visit an FunctionDef node to become astroid""" 1509 self._global_names.append({}) 1510 node, doc = self._get_doc(node) 1511 1512 lineno = node.lineno 1513 if PY38_PLUS and node.decorator_list: 1514 # Python 3.8 sets the line number of a decorated function 1515 # to be the actual line number of the function, but the 1516 # previous versions expected the decorator's line number instead. 1517 # We reset the function's line number to that of the 1518 # first decorator to maintain backward compatibility. 1519 # It's not ideal but this discrepancy was baked into 1520 # the framework for *years*. 1521 lineno = node.decorator_list[0].lineno 1522 1523 if sys.version_info >= (3, 8): 1524 newnode = cls( 1525 name=node.name, 1526 doc=doc, 1527 lineno=lineno, 1528 col_offset=node.col_offset, 1529 end_lineno=node.end_lineno, 1530 end_col_offset=node.end_col_offset, 1531 parent=parent, 1532 ) 1533 else: 1534 newnode = cls(node.name, doc, lineno, node.col_offset, parent) 1535 decorators = self.visit_decorators(node, newnode) 1536 returns: Optional[NodeNG] 1537 if node.returns: 1538 returns = self.visit(node.returns, newnode) 1539 else: 1540 returns = None 1541 1542 type_comment_args = type_comment_returns = None 1543 type_comment_annotation = self.check_function_type_comment(node, newnode) 1544 if type_comment_annotation: 1545 type_comment_returns, type_comment_args = type_comment_annotation 1546 newnode.postinit( 1547 args=self.visit(node.args, newnode), 1548 body=[self.visit(child, newnode) for child in node.body], 1549 decorators=decorators, 1550 returns=returns, 1551 type_comment_returns=type_comment_returns, 1552 type_comment_args=type_comment_args, 1553 ) 1554 self._global_names.pop() 1555 return newnode 1556 1557 def visit_functiondef( 1558 self, node: "ast.FunctionDef", parent: NodeNG 1559 ) -> nodes.FunctionDef: 1560 return self._visit_functiondef(nodes.FunctionDef, node, parent) 1561 1562 def visit_generatorexp( 1563 self, node: "ast.GeneratorExp", parent: NodeNG 1564 ) -> nodes.GeneratorExp: 1565 """visit a GeneratorExp node by returning a fresh instance of it""" 1566 if sys.version_info >= (3, 8): 1567 newnode = nodes.GeneratorExp( 1568 lineno=node.lineno, 1569 col_offset=node.col_offset, 1570 end_lineno=node.end_lineno, 1571 end_col_offset=node.end_col_offset, 1572 parent=parent, 1573 ) 1574 else: 1575 newnode = nodes.GeneratorExp(node.lineno, node.col_offset, parent) 1576 newnode.postinit( 1577 self.visit(node.elt, newnode), 1578 [self.visit(child, newnode) for child in node.generators], 1579 ) 1580 return newnode 1581 1582 def visit_attribute( 1583 self, node: "ast.Attribute", parent: NodeNG 1584 ) -> Union[nodes.Attribute, nodes.AssignAttr, nodes.DelAttr]: 1585 """visit an Attribute node by returning a fresh instance of it""" 1586 context = self._get_context(node) 1587 newnode: Union[nodes.Attribute, nodes.AssignAttr, nodes.DelAttr] 1588 if context == Context.Del: 1589 # FIXME : maybe we should reintroduce and visit_delattr ? 1590 # for instance, deactivating assign_ctx 1591 if sys.version_info >= (3, 8): 1592 newnode = nodes.DelAttr( 1593 attrname=node.attr, 1594 lineno=node.lineno, 1595 col_offset=node.col_offset, 1596 end_lineno=node.end_lineno, 1597 end_col_offset=node.end_col_offset, 1598 parent=parent, 1599 ) 1600 else: 1601 newnode = nodes.DelAttr(node.attr, node.lineno, node.col_offset, parent) 1602 elif context == Context.Store: 1603 if sys.version_info >= (3, 8): 1604 newnode = nodes.AssignAttr( 1605 attrname=node.attr, 1606 lineno=node.lineno, 1607 col_offset=node.col_offset, 1608 end_lineno=node.end_lineno, 1609 end_col_offset=node.end_col_offset, 1610 parent=parent, 1611 ) 1612 else: 1613 newnode = nodes.AssignAttr( 1614 node.attr, node.lineno, node.col_offset, parent 1615 ) 1616 # Prohibit a local save if we are in an ExceptHandler. 1617 if not isinstance(parent, nodes.ExceptHandler): 1618 self._delayed_assattr.append(newnode) 1619 else: 1620 # pylint: disable-next=else-if-used 1621 # Preserve symmetry with other cases 1622 if sys.version_info >= (3, 8): 1623 newnode = nodes.Attribute( 1624 attrname=node.attr, 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 else: 1632 newnode = nodes.Attribute( 1633 node.attr, node.lineno, node.col_offset, parent 1634 ) 1635 newnode.postinit(self.visit(node.value, newnode)) 1636 return newnode 1637 1638 def visit_global(self, node: "ast.Global", parent: NodeNG) -> nodes.Global: 1639 """visit a Global node to become astroid""" 1640 if sys.version_info >= (3, 8): 1641 newnode = nodes.Global( 1642 names=node.names, 1643 lineno=node.lineno, 1644 col_offset=node.col_offset, 1645 end_lineno=node.end_lineno, 1646 end_col_offset=node.end_col_offset, 1647 parent=parent, 1648 ) 1649 else: 1650 newnode = nodes.Global( 1651 node.names, 1652 node.lineno, 1653 node.col_offset, 1654 parent, 1655 ) 1656 if self._global_names: # global at the module level, no effect 1657 for name in node.names: 1658 self._global_names[-1].setdefault(name, []).append(newnode) 1659 return newnode 1660 1661 def visit_if(self, node: "ast.If", parent: NodeNG) -> nodes.If: 1662 """visit an If node by returning a fresh instance of it""" 1663 if sys.version_info >= (3, 8): 1664 newnode = nodes.If( 1665 lineno=node.lineno, 1666 col_offset=node.col_offset, 1667 end_lineno=node.end_lineno, 1668 end_col_offset=node.end_col_offset, 1669 parent=parent, 1670 ) 1671 else: 1672 newnode = nodes.If(node.lineno, node.col_offset, parent) 1673 newnode.postinit( 1674 self.visit(node.test, newnode), 1675 [self.visit(child, newnode) for child in node.body], 1676 [self.visit(child, newnode) for child in node.orelse], 1677 ) 1678 return newnode 1679 1680 def visit_ifexp(self, node: "ast.IfExp", parent: NodeNG) -> nodes.IfExp: 1681 """visit a IfExp node by returning a fresh instance of it""" 1682 if sys.version_info >= (3, 8): 1683 newnode = nodes.IfExp( 1684 lineno=node.lineno, 1685 col_offset=node.col_offset, 1686 end_lineno=node.end_lineno, 1687 end_col_offset=node.end_col_offset, 1688 parent=parent, 1689 ) 1690 else: 1691 newnode = nodes.IfExp(node.lineno, node.col_offset, parent) 1692 newnode.postinit( 1693 self.visit(node.test, newnode), 1694 self.visit(node.body, newnode), 1695 self.visit(node.orelse, newnode), 1696 ) 1697 return newnode 1698 1699 def visit_import(self, node: "ast.Import", parent: NodeNG) -> nodes.Import: 1700 """visit a Import node by returning a fresh instance of it""" 1701 names = [(alias.name, alias.asname) for alias in node.names] 1702 if sys.version_info >= (3, 8): 1703 newnode = nodes.Import( 1704 names=names, 1705 lineno=node.lineno, 1706 col_offset=node.col_offset, 1707 end_lineno=node.end_lineno, 1708 end_col_offset=node.end_col_offset, 1709 parent=parent, 1710 ) 1711 else: 1712 newnode = nodes.Import( 1713 names, 1714 node.lineno, 1715 node.col_offset, 1716 parent, 1717 ) 1718 # save import names in parent's locals: 1719 for (name, asname) in newnode.names: 1720 name = asname or name 1721 parent.set_local(name.split(".")[0], newnode) 1722 return newnode 1723 1724 def visit_joinedstr(self, node: "ast.JoinedStr", parent: NodeNG) -> nodes.JoinedStr: 1725 if sys.version_info >= (3, 8): 1726 newnode = nodes.JoinedStr( 1727 lineno=node.lineno, 1728 col_offset=node.col_offset, 1729 end_lineno=node.end_lineno, 1730 end_col_offset=node.end_col_offset, 1731 parent=parent, 1732 ) 1733 else: 1734 newnode = nodes.JoinedStr(node.lineno, node.col_offset, parent) 1735 newnode.postinit([self.visit(child, newnode) for child in node.values]) 1736 return newnode 1737 1738 def visit_formattedvalue( 1739 self, node: "ast.FormattedValue", parent: NodeNG 1740 ) -> nodes.FormattedValue: 1741 if sys.version_info >= (3, 8): 1742 newnode = nodes.FormattedValue( 1743 lineno=node.lineno, 1744 col_offset=node.col_offset, 1745 end_lineno=node.end_lineno, 1746 end_col_offset=node.end_col_offset, 1747 parent=parent, 1748 ) 1749 else: 1750 newnode = nodes.FormattedValue(node.lineno, node.col_offset, parent) 1751 newnode.postinit( 1752 self.visit(node.value, newnode), 1753 node.conversion, 1754 self.visit(node.format_spec, newnode), 1755 ) 1756 return newnode 1757 1758 def visit_namedexpr(self, node: "ast.NamedExpr", parent: NodeNG) -> nodes.NamedExpr: 1759 if sys.version_info >= (3, 8): 1760 newnode = nodes.NamedExpr( 1761 lineno=node.lineno, 1762 col_offset=node.col_offset, 1763 end_lineno=node.end_lineno, 1764 end_col_offset=node.end_col_offset, 1765 parent=parent, 1766 ) 1767 else: 1768 newnode = nodes.NamedExpr(node.lineno, node.col_offset, parent) 1769 newnode.postinit( 1770 self.visit(node.target, newnode), self.visit(node.value, newnode) 1771 ) 1772 return newnode 1773 1774 # Not used in Python 3.9+. 1775 def visit_index(self, node: "ast.Index", parent: nodes.Subscript) -> NodeNG: 1776 """visit a Index node by returning a fresh instance of NodeNG""" 1777 return self.visit(node.value, parent) # type: ignore[attr-defined] 1778 1779 def visit_keyword(self, node: "ast.keyword", parent: NodeNG) -> nodes.Keyword: 1780 """visit a Keyword node by returning a fresh instance of it""" 1781 if sys.version_info >= (3, 9): 1782 newnode = nodes.Keyword( 1783 arg=node.arg, 1784 lineno=node.lineno, 1785 col_offset=node.col_offset, 1786 end_lineno=node.end_lineno, 1787 end_col_offset=node.end_col_offset, 1788 parent=parent, 1789 ) 1790 else: 1791 newnode = nodes.Keyword(node.arg, parent=parent) 1792 newnode.postinit(self.visit(node.value, newnode)) 1793 return newnode 1794 1795 def visit_lambda(self, node: "ast.Lambda", parent: NodeNG) -> nodes.Lambda: 1796 """visit a Lambda node by returning a fresh instance of it""" 1797 if sys.version_info >= (3, 8): 1798 newnode = nodes.Lambda( 1799 lineno=node.lineno, 1800 col_offset=node.col_offset, 1801 end_lineno=node.end_lineno, 1802 end_col_offset=node.end_col_offset, 1803 parent=parent, 1804 ) 1805 else: 1806 newnode = nodes.Lambda(node.lineno, node.col_offset, parent) 1807 newnode.postinit(self.visit(node.args, newnode), self.visit(node.body, newnode)) 1808 return newnode 1809 1810 def visit_list(self, node: "ast.List", parent: NodeNG) -> nodes.List: 1811 """visit a List node by returning a fresh instance of it""" 1812 context = self._get_context(node) 1813 if sys.version_info >= (3, 8): 1814 newnode = nodes.List( 1815 ctx=context, 1816 lineno=node.lineno, 1817 col_offset=node.col_offset, 1818 end_lineno=node.end_lineno, 1819 end_col_offset=node.end_col_offset, 1820 parent=parent, 1821 ) 1822 else: 1823 newnode = nodes.List( 1824 ctx=context, 1825 lineno=node.lineno, 1826 col_offset=node.col_offset, 1827 parent=parent, 1828 ) 1829 newnode.postinit([self.visit(child, newnode) for child in node.elts]) 1830 return newnode 1831 1832 def visit_listcomp(self, node: "ast.ListComp", parent: NodeNG) -> nodes.ListComp: 1833 """visit a ListComp node by returning a fresh instance of it""" 1834 if sys.version_info >= (3, 8): 1835 newnode = nodes.ListComp( 1836 lineno=node.lineno, 1837 col_offset=node.col_offset, 1838 end_lineno=node.end_lineno, 1839 end_col_offset=node.end_col_offset, 1840 parent=parent, 1841 ) 1842 else: 1843 newnode = nodes.ListComp(node.lineno, node.col_offset, parent) 1844 newnode.postinit( 1845 self.visit(node.elt, newnode), 1846 [self.visit(child, newnode) for child in node.generators], 1847 ) 1848 return newnode 1849 1850 def visit_name( 1851 self, node: "ast.Name", parent: NodeNG 1852 ) -> Union[nodes.Name, nodes.AssignName, nodes.DelName]: 1853 """visit a Name node by returning a fresh instance of it""" 1854 context = self._get_context(node) 1855 newnode: Union[nodes.Name, nodes.AssignName, nodes.DelName] 1856 if context == Context.Del: 1857 if sys.version_info >= (3, 8): 1858 newnode = nodes.DelName( 1859 name=node.id, 1860 lineno=node.lineno, 1861 col_offset=node.col_offset, 1862 end_lineno=node.end_lineno, 1863 end_col_offset=node.end_col_offset, 1864 parent=parent, 1865 ) 1866 else: 1867 newnode = nodes.DelName(node.id, node.lineno, node.col_offset, parent) 1868 elif context == Context.Store: 1869 if sys.version_info >= (3, 8): 1870 newnode = nodes.AssignName( 1871 name=node.id, 1872 lineno=node.lineno, 1873 col_offset=node.col_offset, 1874 end_lineno=node.end_lineno, 1875 end_col_offset=node.end_col_offset, 1876 parent=parent, 1877 ) 1878 else: 1879 newnode = nodes.AssignName( 1880 node.id, node.lineno, node.col_offset, parent 1881 ) 1882 else: 1883 # pylint: disable-next=else-if-used 1884 # Preserve symmetry with other cases 1885 if sys.version_info >= (3, 8): 1886 newnode = nodes.Name( 1887 name=node.id, 1888 lineno=node.lineno, 1889 col_offset=node.col_offset, 1890 end_lineno=node.end_lineno, 1891 end_col_offset=node.end_col_offset, 1892 parent=parent, 1893 ) 1894 else: 1895 newnode = nodes.Name(node.id, node.lineno, node.col_offset, parent) 1896 # XXX REMOVE me : 1897 if context in (Context.Del, Context.Store): # 'Aug' ?? 1898 newnode = cast(Union[nodes.AssignName, nodes.DelName], newnode) 1899 self._save_assignment(newnode) 1900 return newnode 1901 1902 # Not used in Python 3.8+. 1903 def visit_nameconstant( 1904 self, node: "ast.NameConstant", parent: NodeNG 1905 ) -> nodes.Const: 1906 # For singleton values True / False / None 1907 return nodes.Const( 1908 node.value, 1909 node.lineno, 1910 node.col_offset, 1911 parent, 1912 ) 1913 1914 def visit_nonlocal(self, node: "ast.Nonlocal", parent: NodeNG) -> nodes.Nonlocal: 1915 """visit a Nonlocal node and return a new instance of it""" 1916 if sys.version_info >= (3, 8): 1917 return nodes.Nonlocal( 1918 names=node.names, 1919 lineno=node.lineno, 1920 col_offset=node.col_offset, 1921 end_lineno=node.end_lineno, 1922 end_col_offset=node.end_col_offset, 1923 parent=parent, 1924 ) 1925 return nodes.Nonlocal( 1926 node.names, 1927 node.lineno, 1928 node.col_offset, 1929 parent, 1930 ) 1931 1932 def visit_constant(self, node: "ast.Constant", parent: NodeNG) -> nodes.Const: 1933 """visit a Constant node by returning a fresh instance of Const""" 1934 if sys.version_info >= (3, 8): 1935 return nodes.Const( 1936 value=node.value, 1937 kind=node.kind, 1938 lineno=node.lineno, 1939 col_offset=node.col_offset, 1940 end_lineno=node.end_lineno, 1941 end_col_offset=node.end_col_offset, 1942 parent=parent, 1943 ) 1944 return nodes.Const( 1945 node.value, 1946 node.lineno, 1947 node.col_offset, 1948 parent, 1949 node.kind, 1950 ) 1951 1952 # Not used in Python 3.8+. 1953 def visit_str( 1954 self, node: Union["ast.Str", "ast.Bytes"], parent: NodeNG 1955 ) -> nodes.Const: 1956 """visit a String/Bytes node by returning a fresh instance of Const""" 1957 return nodes.Const( 1958 node.s, 1959 node.lineno, 1960 node.col_offset, 1961 parent, 1962 ) 1963 1964 # Not used in Python 3.8+ 1965 visit_bytes = visit_str 1966 1967 # Not used in Python 3.8+. 1968 def visit_num(self, node: "ast.Num", parent: NodeNG) -> nodes.Const: 1969 """visit a Num node by returning a fresh instance of Const""" 1970 return nodes.Const( 1971 node.n, 1972 node.lineno, 1973 node.col_offset, 1974 parent, 1975 ) 1976 1977 def visit_pass(self, node: "ast.Pass", parent: NodeNG) -> nodes.Pass: 1978 """visit a Pass node by returning a fresh instance of it""" 1979 if sys.version_info >= (3, 8): 1980 return nodes.Pass( 1981 lineno=node.lineno, 1982 col_offset=node.col_offset, 1983 end_lineno=node.end_lineno, 1984 end_col_offset=node.end_col_offset, 1985 parent=parent, 1986 ) 1987 return nodes.Pass(node.lineno, node.col_offset, parent) 1988 1989 def visit_raise(self, node: "ast.Raise", parent: NodeNG) -> nodes.Raise: 1990 """visit a Raise node by returning a fresh instance of it""" 1991 if sys.version_info >= (3, 8): 1992 newnode = nodes.Raise( 1993 lineno=node.lineno, 1994 col_offset=node.col_offset, 1995 end_lineno=node.end_lineno, 1996 end_col_offset=node.end_col_offset, 1997 parent=parent, 1998 ) 1999 else: 2000 newnode = nodes.Raise(node.lineno, node.col_offset, parent) 2001 # no traceback; anyway it is not used in Pylint 2002 newnode.postinit( 2003 exc=self.visit(node.exc, newnode), 2004 cause=self.visit(node.cause, newnode), 2005 ) 2006 return newnode 2007 2008 def visit_return(self, node: "ast.Return", parent: NodeNG) -> nodes.Return: 2009 """visit a Return node by returning a fresh instance of it""" 2010 if sys.version_info >= (3, 8): 2011 newnode = nodes.Return( 2012 lineno=node.lineno, 2013 col_offset=node.col_offset, 2014 end_lineno=node.end_lineno, 2015 end_col_offset=node.end_col_offset, 2016 parent=parent, 2017 ) 2018 else: 2019 newnode = nodes.Return(node.lineno, node.col_offset, parent) 2020 if node.value is not None: 2021 newnode.postinit(self.visit(node.value, newnode)) 2022 return newnode 2023 2024 def visit_set(self, node: "ast.Set", parent: NodeNG) -> nodes.Set: 2025 """visit a Set node by returning a fresh instance of it""" 2026 if sys.version_info >= (3, 8): 2027 newnode = nodes.Set( 2028 lineno=node.lineno, 2029 col_offset=node.col_offset, 2030 end_lineno=node.end_lineno, 2031 end_col_offset=node.end_col_offset, 2032 parent=parent, 2033 ) 2034 else: 2035 newnode = nodes.Set(node.lineno, node.col_offset, parent) 2036 newnode.postinit([self.visit(child, newnode) for child in node.elts]) 2037 return newnode 2038 2039 def visit_setcomp(self, node: "ast.SetComp", parent: NodeNG) -> nodes.SetComp: 2040 """visit a SetComp node by returning a fresh instance of it""" 2041 if sys.version_info >= (3, 8): 2042 newnode = nodes.SetComp( 2043 lineno=node.lineno, 2044 col_offset=node.col_offset, 2045 end_lineno=node.end_lineno, 2046 end_col_offset=node.end_col_offset, 2047 parent=parent, 2048 ) 2049 else: 2050 newnode = nodes.SetComp(node.lineno, node.col_offset, parent) 2051 newnode.postinit( 2052 self.visit(node.elt, newnode), 2053 [self.visit(child, newnode) for child in node.generators], 2054 ) 2055 return newnode 2056 2057 def visit_slice(self, node: "ast.Slice", parent: nodes.Subscript) -> nodes.Slice: 2058 """visit a Slice node by returning a fresh instance of it""" 2059 if sys.version_info >= (3, 9): 2060 newnode = nodes.Slice( 2061 lineno=node.lineno, 2062 col_offset=node.col_offset, 2063 end_lineno=node.end_lineno, 2064 end_col_offset=node.end_col_offset, 2065 parent=parent, 2066 ) 2067 else: 2068 newnode = nodes.Slice(parent=parent) 2069 newnode.postinit( 2070 lower=self.visit(node.lower, newnode), 2071 upper=self.visit(node.upper, newnode), 2072 step=self.visit(node.step, newnode), 2073 ) 2074 return newnode 2075 2076 def visit_subscript(self, node: "ast.Subscript", parent: NodeNG) -> nodes.Subscript: 2077 """visit a Subscript node by returning a fresh instance of it""" 2078 context = self._get_context(node) 2079 if sys.version_info >= (3, 8): 2080 newnode = nodes.Subscript( 2081 ctx=context, 2082 lineno=node.lineno, 2083 col_offset=node.col_offset, 2084 end_lineno=node.end_lineno, 2085 end_col_offset=node.end_col_offset, 2086 parent=parent, 2087 ) 2088 else: 2089 newnode = nodes.Subscript( 2090 ctx=context, 2091 lineno=node.lineno, 2092 col_offset=node.col_offset, 2093 parent=parent, 2094 ) 2095 newnode.postinit( 2096 self.visit(node.value, newnode), self.visit(node.slice, newnode) 2097 ) 2098 return newnode 2099 2100 def visit_starred(self, node: "ast.Starred", parent: NodeNG) -> nodes.Starred: 2101 """visit a Starred node and return a new instance of it""" 2102 context = self._get_context(node) 2103 if sys.version_info >= (3, 8): 2104 newnode = nodes.Starred( 2105 ctx=context, 2106 lineno=node.lineno, 2107 col_offset=node.col_offset, 2108 end_lineno=node.end_lineno, 2109 end_col_offset=node.end_col_offset, 2110 parent=parent, 2111 ) 2112 else: 2113 newnode = nodes.Starred( 2114 ctx=context, 2115 lineno=node.lineno, 2116 col_offset=node.col_offset, 2117 parent=parent, 2118 ) 2119 newnode.postinit(self.visit(node.value, newnode)) 2120 return newnode 2121 2122 def visit_tryexcept(self, node: "ast.Try", parent: NodeNG) -> nodes.TryExcept: 2123 """visit a TryExcept node by returning a fresh instance of it""" 2124 if sys.version_info >= (3, 8): 2125 newnode = nodes.TryExcept( 2126 lineno=node.lineno, 2127 col_offset=node.col_offset, 2128 end_lineno=node.end_lineno, 2129 end_col_offset=node.end_col_offset, 2130 parent=parent, 2131 ) 2132 else: 2133 newnode = nodes.TryExcept(node.lineno, node.col_offset, parent) 2134 newnode.postinit( 2135 [self.visit(child, newnode) for child in node.body], 2136 [self.visit(child, newnode) for child in node.handlers], 2137 [self.visit(child, newnode) for child in node.orelse], 2138 ) 2139 return newnode 2140 2141 def visit_try( 2142 self, node: "ast.Try", parent: NodeNG 2143 ) -> Union[nodes.TryExcept, nodes.TryFinally, None]: 2144 # python 3.3 introduce a new Try node replacing 2145 # TryFinally/TryExcept nodes 2146 if node.finalbody: 2147 if sys.version_info >= (3, 8): 2148 newnode = nodes.TryFinally( 2149 lineno=node.lineno, 2150 col_offset=node.col_offset, 2151 end_lineno=node.end_lineno, 2152 end_col_offset=node.end_col_offset, 2153 parent=parent, 2154 ) 2155 else: 2156 newnode = nodes.TryFinally(node.lineno, node.col_offset, parent) 2157 body: Union[List[nodes.TryExcept], List[NodeNG]] 2158 if node.handlers: 2159 body = [self.visit_tryexcept(node, newnode)] 2160 else: 2161 body = [self.visit(child, newnode) for child in node.body] 2162 newnode.postinit(body, [self.visit(n, newnode) for n in node.finalbody]) 2163 return newnode 2164 if node.handlers: 2165 return self.visit_tryexcept(node, parent) 2166 return None 2167 2168 def visit_tryfinally(self, node: "ast.Try", parent: NodeNG) -> nodes.TryFinally: 2169 """visit a TryFinally node by returning a fresh instance of it""" 2170 if sys.version_info >= (3, 8): 2171 newnode = nodes.TryFinally( 2172 lineno=node.lineno, 2173 col_offset=node.col_offset, 2174 end_lineno=node.end_lineno, 2175 end_col_offset=node.end_col_offset, 2176 parent=parent, 2177 ) 2178 else: 2179 newnode = nodes.TryFinally(node.lineno, node.col_offset, parent) 2180 newnode.postinit( 2181 [self.visit(child, newnode) for child in node.body], 2182 [self.visit(n, newnode) for n in node.finalbody], 2183 ) 2184 return newnode 2185 2186 def visit_tuple(self, node: "ast.Tuple", parent: NodeNG) -> nodes.Tuple: 2187 """visit a Tuple node by returning a fresh instance of it""" 2188 context = self._get_context(node) 2189 if sys.version_info >= (3, 8): 2190 newnode = nodes.Tuple( 2191 ctx=context, 2192 lineno=node.lineno, 2193 col_offset=node.col_offset, 2194 end_lineno=node.end_lineno, 2195 end_col_offset=node.end_col_offset, 2196 parent=parent, 2197 ) 2198 else: 2199 newnode = nodes.Tuple( 2200 ctx=context, 2201 lineno=node.lineno, 2202 col_offset=node.col_offset, 2203 parent=parent, 2204 ) 2205 newnode.postinit([self.visit(child, newnode) for child in node.elts]) 2206 return newnode 2207 2208 def visit_unaryop(self, node: "ast.UnaryOp", parent: NodeNG) -> nodes.UnaryOp: 2209 """visit a UnaryOp node by returning a fresh instance of it""" 2210 if sys.version_info >= (3, 8): 2211 newnode = nodes.UnaryOp( 2212 op=self._parser_module.unary_op_classes[node.op.__class__], 2213 lineno=node.lineno, 2214 col_offset=node.col_offset, 2215 end_lineno=node.end_lineno, 2216 end_col_offset=node.end_col_offset, 2217 parent=parent, 2218 ) 2219 else: 2220 newnode = nodes.UnaryOp( 2221 self._parser_module.unary_op_classes[node.op.__class__], 2222 node.lineno, 2223 node.col_offset, 2224 parent, 2225 ) 2226 newnode.postinit(self.visit(node.operand, newnode)) 2227 return newnode 2228 2229 def visit_while(self, node: "ast.While", parent: NodeNG) -> nodes.While: 2230 """visit a While node by returning a fresh instance of it""" 2231 if sys.version_info >= (3, 8): 2232 newnode = nodes.While( 2233 lineno=node.lineno, 2234 col_offset=node.col_offset, 2235 end_lineno=node.end_lineno, 2236 end_col_offset=node.end_col_offset, 2237 parent=parent, 2238 ) 2239 else: 2240 newnode = nodes.While(node.lineno, node.col_offset, parent) 2241 newnode.postinit( 2242 self.visit(node.test, newnode), 2243 [self.visit(child, newnode) for child in node.body], 2244 [self.visit(child, newnode) for child in node.orelse], 2245 ) 2246 return newnode 2247 2248 @overload 2249 def _visit_with( 2250 self, cls: Type[nodes.With], node: "ast.With", parent: NodeNG 2251 ) -> nodes.With: 2252 ... 2253 2254 @overload 2255 def _visit_with( 2256 self, cls: Type[nodes.AsyncWith], node: "ast.AsyncWith", parent: NodeNG 2257 ) -> nodes.AsyncWith: 2258 ... 2259 2260 def _visit_with( 2261 self, 2262 cls: Type[T_With], 2263 node: Union["ast.With", "ast.AsyncWith"], 2264 parent: NodeNG, 2265 ) -> T_With: 2266 if sys.version_info >= (3, 8): 2267 newnode = cls( 2268 lineno=node.lineno, 2269 col_offset=node.col_offset, 2270 end_lineno=node.end_lineno, 2271 end_col_offset=node.end_col_offset, 2272 parent=parent, 2273 ) 2274 else: 2275 newnode = cls(node.lineno, node.col_offset, parent) 2276 2277 def visit_child(child: "ast.withitem") -> Tuple[NodeNG, Optional[NodeNG]]: 2278 expr = self.visit(child.context_expr, newnode) 2279 var = self.visit(child.optional_vars, newnode) 2280 return expr, var 2281 2282 type_annotation = self.check_type_comment(node, parent=newnode) 2283 newnode.postinit( 2284 items=[visit_child(child) for child in node.items], 2285 body=[self.visit(child, newnode) for child in node.body], 2286 type_annotation=type_annotation, 2287 ) 2288 return newnode 2289 2290 def visit_with(self, node: "ast.With", parent: NodeNG) -> NodeNG: 2291 return self._visit_with(nodes.With, node, parent) 2292 2293 def visit_yield(self, node: "ast.Yield", parent: NodeNG) -> NodeNG: 2294 """visit a Yield node by returning a fresh instance of it""" 2295 if sys.version_info >= (3, 8): 2296 newnode = nodes.Yield( 2297 lineno=node.lineno, 2298 col_offset=node.col_offset, 2299 end_lineno=node.end_lineno, 2300 end_col_offset=node.end_col_offset, 2301 parent=parent, 2302 ) 2303 else: 2304 newnode = nodes.Yield(node.lineno, node.col_offset, parent) 2305 if node.value is not None: 2306 newnode.postinit(self.visit(node.value, newnode)) 2307 return newnode 2308 2309 def visit_yieldfrom(self, node: "ast.YieldFrom", parent: NodeNG) -> NodeNG: 2310 if sys.version_info >= (3, 8): 2311 newnode = nodes.YieldFrom( 2312 lineno=node.lineno, 2313 col_offset=node.col_offset, 2314 end_lineno=node.end_lineno, 2315 end_col_offset=node.end_col_offset, 2316 parent=parent, 2317 ) 2318 else: 2319 newnode = nodes.YieldFrom(node.lineno, node.col_offset, parent) 2320 if node.value is not None: 2321 newnode.postinit(self.visit(node.value, newnode)) 2322 return newnode 2323 2324 if sys.version_info >= (3, 10): 2325 2326 def visit_match(self, node: "ast.Match", parent: NodeNG) -> nodes.Match: 2327 newnode = nodes.Match( 2328 lineno=node.lineno, 2329 col_offset=node.col_offset, 2330 end_lineno=node.end_lineno, 2331 end_col_offset=node.end_col_offset, 2332 parent=parent, 2333 ) 2334 newnode.postinit( 2335 subject=self.visit(node.subject, newnode), 2336 cases=[self.visit(case, newnode) for case in node.cases], 2337 ) 2338 return newnode 2339 2340 def visit_matchcase( 2341 self, node: "ast.match_case", parent: NodeNG 2342 ) -> nodes.MatchCase: 2343 newnode = nodes.MatchCase(parent=parent) 2344 newnode.postinit( 2345 pattern=self.visit(node.pattern, newnode), 2346 guard=self.visit(node.guard, newnode), 2347 body=[self.visit(child, newnode) for child in node.body], 2348 ) 2349 return newnode 2350 2351 def visit_matchvalue( 2352 self, node: "ast.MatchValue", parent: NodeNG 2353 ) -> nodes.MatchValue: 2354 newnode = nodes.MatchValue( 2355 lineno=node.lineno, 2356 col_offset=node.col_offset, 2357 end_lineno=node.end_lineno, 2358 end_col_offset=node.end_col_offset, 2359 parent=parent, 2360 ) 2361 newnode.postinit(value=self.visit(node.value, newnode)) 2362 return newnode 2363 2364 def visit_matchsingleton( 2365 self, node: "ast.MatchSingleton", parent: NodeNG 2366 ) -> nodes.MatchSingleton: 2367 return nodes.MatchSingleton( 2368 value=node.value, 2369 lineno=node.lineno, 2370 col_offset=node.col_offset, 2371 end_lineno=node.end_lineno, 2372 end_col_offset=node.end_col_offset, 2373 parent=parent, 2374 ) 2375 2376 def visit_matchsequence( 2377 self, node: "ast.MatchSequence", parent: NodeNG 2378 ) -> nodes.MatchSequence: 2379 newnode = nodes.MatchSequence( 2380 lineno=node.lineno, 2381 col_offset=node.col_offset, 2382 end_lineno=node.end_lineno, 2383 end_col_offset=node.end_col_offset, 2384 parent=parent, 2385 ) 2386 newnode.postinit( 2387 patterns=[self.visit(pattern, newnode) for pattern in node.patterns] 2388 ) 2389 return newnode 2390 2391 def visit_matchmapping( 2392 self, node: "ast.MatchMapping", parent: NodeNG 2393 ) -> nodes.MatchMapping: 2394 newnode = nodes.MatchMapping( 2395 lineno=node.lineno, 2396 col_offset=node.col_offset, 2397 end_lineno=node.end_lineno, 2398 end_col_offset=node.end_col_offset, 2399 parent=parent, 2400 ) 2401 # Add AssignName node for 'node.name' 2402 # https://bugs.python.org/issue43994 2403 newnode.postinit( 2404 keys=[self.visit(child, newnode) for child in node.keys], 2405 patterns=[self.visit(pattern, newnode) for pattern in node.patterns], 2406 rest=self.visit_assignname(node, newnode, node.rest), 2407 ) 2408 return newnode 2409 2410 def visit_matchclass( 2411 self, node: "ast.MatchClass", parent: NodeNG 2412 ) -> nodes.MatchClass: 2413 newnode = nodes.MatchClass( 2414 lineno=node.lineno, 2415 col_offset=node.col_offset, 2416 end_lineno=node.end_lineno, 2417 end_col_offset=node.end_col_offset, 2418 parent=parent, 2419 ) 2420 newnode.postinit( 2421 cls=self.visit(node.cls, newnode), 2422 patterns=[self.visit(pattern, newnode) for pattern in node.patterns], 2423 kwd_attrs=node.kwd_attrs, 2424 kwd_patterns=[ 2425 self.visit(pattern, newnode) for pattern in node.kwd_patterns 2426 ], 2427 ) 2428 return newnode 2429 2430 def visit_matchstar( 2431 self, node: "ast.MatchStar", parent: NodeNG 2432 ) -> nodes.MatchStar: 2433 newnode = nodes.MatchStar( 2434 lineno=node.lineno, 2435 col_offset=node.col_offset, 2436 end_lineno=node.end_lineno, 2437 end_col_offset=node.end_col_offset, 2438 parent=parent, 2439 ) 2440 # Add AssignName node for 'node.name' 2441 # https://bugs.python.org/issue43994 2442 newnode.postinit(name=self.visit_assignname(node, newnode, node.name)) 2443 return newnode 2444 2445 def visit_matchas(self, node: "ast.MatchAs", parent: NodeNG) -> nodes.MatchAs: 2446 newnode = nodes.MatchAs( 2447 lineno=node.lineno, 2448 col_offset=node.col_offset, 2449 end_lineno=node.end_lineno, 2450 end_col_offset=node.end_col_offset, 2451 parent=parent, 2452 ) 2453 # Add AssignName node for 'node.name' 2454 # https://bugs.python.org/issue43994 2455 newnode.postinit( 2456 pattern=self.visit(node.pattern, newnode), 2457 name=self.visit_assignname(node, newnode, node.name), 2458 ) 2459 return newnode 2460 2461 def visit_matchor(self, node: "ast.MatchOr", parent: NodeNG) -> nodes.MatchOr: 2462 newnode = nodes.MatchOr( 2463 lineno=node.lineno, 2464 col_offset=node.col_offset, 2465 end_lineno=node.end_lineno, 2466 end_col_offset=node.end_col_offset, 2467 parent=parent, 2468 ) 2469 newnode.postinit( 2470 patterns=[self.visit(pattern, newnode) for pattern in node.patterns] 2471 ) 2472 return newnode 2473