1import pprint 2import sys 3import typing 4import warnings 5from functools import singledispatch as _singledispatch 6from typing import ( 7 TYPE_CHECKING, 8 ClassVar, 9 Iterator, 10 List, 11 Optional, 12 Tuple, 13 Type, 14 TypeVar, 15 Union, 16 cast, 17 overload, 18) 19 20from astroid import decorators, util 21from astroid.exceptions import ( 22 AstroidError, 23 InferenceError, 24 ParentMissingError, 25 StatementMissing, 26 UseInferenceDefault, 27) 28from astroid.manager import AstroidManager 29from astroid.nodes.as_string import AsStringVisitor 30from astroid.nodes.const import OP_PRECEDENCE 31 32if TYPE_CHECKING: 33 from astroid import nodes 34 35 if sys.version_info >= (3, 6, 2): 36 # To be fixed with https://github.com/PyCQA/pylint/pull/5316 37 from typing import NoReturn # pylint: disable=unused-import 38 else: 39 from typing_extensions import NoReturn 40 41if sys.version_info >= (3, 8): 42 from typing import Literal 43else: 44 from typing_extensions import Literal 45 46 47# Types for 'NodeNG.nodes_of_class()' 48T_Nodes = TypeVar("T_Nodes", bound="NodeNG") 49T_Nodes2 = TypeVar("T_Nodes2", bound="NodeNG") 50T_Nodes3 = TypeVar("T_Nodes3", bound="NodeNG") 51SkipKlassT = Union[None, Type["NodeNG"], Tuple[Type["NodeNG"], ...]] 52 53 54class NodeNG: 55 """A node of the new Abstract Syntax Tree (AST). 56 57 This is the base class for all Astroid node classes. 58 """ 59 60 is_statement: ClassVar[bool] = False 61 """Whether this node indicates a statement.""" 62 optional_assign: ClassVar[ 63 bool 64 ] = False # True for For (and for Comprehension if py <3.0) 65 """Whether this node optionally assigns a variable. 66 67 This is for loop assignments because loop won't necessarily perform an 68 assignment if the loop has no iterations. 69 This is also the case from comprehensions in Python 2. 70 """ 71 is_function: ClassVar[bool] = False # True for FunctionDef nodes 72 """Whether this node indicates a function.""" 73 is_lambda: ClassVar[bool] = False 74 75 # Attributes below are set by the builder module or by raw factories 76 _astroid_fields: ClassVar[typing.Tuple[str, ...]] = () 77 """Node attributes that contain child nodes. 78 79 This is redefined in most concrete classes. 80 """ 81 _other_fields: ClassVar[typing.Tuple[str, ...]] = () 82 """Node attributes that do not contain child nodes.""" 83 _other_other_fields: ClassVar[typing.Tuple[str, ...]] = () 84 """Attributes that contain AST-dependent fields.""" 85 # instance specific inference function infer(node, context) 86 _explicit_inference = None 87 88 def __init__( 89 self, 90 lineno: Optional[int] = None, 91 col_offset: Optional[int] = None, 92 parent: Optional["NodeNG"] = None, 93 *, 94 end_lineno: Optional[int] = None, 95 end_col_offset: Optional[int] = None, 96 ) -> None: 97 """ 98 :param lineno: The line that this node appears on in the source code. 99 100 :param col_offset: The column that this node appears on in the 101 source code. 102 103 :param parent: The parent node in the syntax tree. 104 105 :param end_lineno: The last line this node appears on in the source code. 106 107 :param end_col_offset: The end column this node appears on in the 108 source code. Note: This is after the last symbol. 109 """ 110 self.lineno: Optional[int] = lineno 111 """The line that this node appears on in the source code.""" 112 113 self.col_offset: Optional[int] = col_offset 114 """The column that this node appears on in the source code.""" 115 116 self.parent: Optional["NodeNG"] = parent 117 """The parent node in the syntax tree.""" 118 119 self.end_lineno: Optional[int] = end_lineno 120 """The last line this node appears on in the source code.""" 121 122 self.end_col_offset: Optional[int] = end_col_offset 123 """The end column this node appears on in the source code. 124 Note: This is after the last symbol. 125 """ 126 127 def infer(self, context=None, **kwargs): 128 """Get a generator of the inferred values. 129 130 This is the main entry point to the inference system. 131 132 .. seealso:: :ref:`inference` 133 134 If the instance has some explicit inference function set, it will be 135 called instead of the default interface. 136 137 :returns: The inferred values. 138 :rtype: iterable 139 """ 140 if context is not None: 141 context = context.extra_context.get(self, context) 142 if self._explicit_inference is not None: 143 # explicit_inference is not bound, give it self explicitly 144 try: 145 # pylint: disable=not-callable 146 results = list(self._explicit_inference(self, context, **kwargs)) 147 if context is not None: 148 context.nodes_inferred += len(results) 149 yield from results 150 return 151 except UseInferenceDefault: 152 pass 153 154 if not context: 155 # nodes_inferred? 156 yield from self._infer(context, **kwargs) 157 return 158 159 key = (self, context.lookupname, context.callcontext, context.boundnode) 160 if key in context.inferred: 161 yield from context.inferred[key] 162 return 163 164 generator = self._infer(context, **kwargs) 165 results = [] 166 167 # Limit inference amount to help with performance issues with 168 # exponentially exploding possible results. 169 limit = AstroidManager().max_inferable_values 170 for i, result in enumerate(generator): 171 if i >= limit or (context.nodes_inferred > context.max_inferred): 172 yield util.Uninferable 173 break 174 results.append(result) 175 yield result 176 context.nodes_inferred += 1 177 178 # Cache generated results for subsequent inferences of the 179 # same node using the same context 180 context.inferred[key] = tuple(results) 181 return 182 183 def _repr_name(self): 184 """Get a name for nice representation. 185 186 This is either :attr:`name`, :attr:`attrname`, or the empty string. 187 188 :returns: The nice name. 189 :rtype: str 190 """ 191 if all(name not in self._astroid_fields for name in ("name", "attrname")): 192 return getattr(self, "name", "") or getattr(self, "attrname", "") 193 return "" 194 195 def __str__(self): 196 rname = self._repr_name() 197 cname = type(self).__name__ 198 if rname: 199 string = "%(cname)s.%(rname)s(%(fields)s)" 200 alignment = len(cname) + len(rname) + 2 201 else: 202 string = "%(cname)s(%(fields)s)" 203 alignment = len(cname) + 1 204 result = [] 205 for field in self._other_fields + self._astroid_fields: 206 value = getattr(self, field) 207 width = 80 - len(field) - alignment 208 lines = pprint.pformat(value, indent=2, width=width).splitlines(True) 209 210 inner = [lines[0]] 211 for line in lines[1:]: 212 inner.append(" " * alignment + line) 213 result.append(f"{field}={''.join(inner)}") 214 215 return string % { 216 "cname": cname, 217 "rname": rname, 218 "fields": (",\n" + " " * alignment).join(result), 219 } 220 221 def __repr__(self): 222 rname = self._repr_name() 223 if rname: 224 string = "<%(cname)s.%(rname)s l.%(lineno)s at 0x%(id)x>" 225 else: 226 string = "<%(cname)s l.%(lineno)s at 0x%(id)x>" 227 return string % { 228 "cname": type(self).__name__, 229 "rname": rname, 230 "lineno": self.fromlineno, 231 "id": id(self), 232 } 233 234 def accept(self, visitor): 235 """Visit this node using the given visitor.""" 236 func = getattr(visitor, "visit_" + self.__class__.__name__.lower()) 237 return func(self) 238 239 def get_children(self) -> Iterator["NodeNG"]: 240 """Get the child nodes below this node.""" 241 for field in self._astroid_fields: 242 attr = getattr(self, field) 243 if attr is None: 244 continue 245 if isinstance(attr, (list, tuple)): 246 yield from attr 247 else: 248 yield attr 249 yield from () 250 251 def last_child(self) -> Optional["NodeNG"]: 252 """An optimized version of list(get_children())[-1]""" 253 for field in self._astroid_fields[::-1]: 254 attr = getattr(self, field) 255 if not attr: # None or empty listy / tuple 256 continue 257 if isinstance(attr, (list, tuple)): 258 return attr[-1] 259 return attr 260 return None 261 262 def node_ancestors(self) -> Iterator["NodeNG"]: 263 """Yield parent, grandparent, etc until there are no more.""" 264 parent = self.parent 265 while parent is not None: 266 yield parent 267 parent = parent.parent 268 269 def parent_of(self, node): 270 """Check if this node is the parent of the given node. 271 272 :param node: The node to check if it is the child. 273 :type node: NodeNG 274 275 :returns: True if this node is the parent of the given node, 276 False otherwise. 277 :rtype: bool 278 """ 279 for parent in node.node_ancestors(): 280 if self is parent: 281 return True 282 return False 283 284 @overload 285 def statement( 286 self, *, future: Literal[None] = ... 287 ) -> Union["nodes.Statement", "nodes.Module"]: 288 ... 289 290 @overload 291 def statement(self, *, future: Literal[True]) -> "nodes.Statement": 292 ... 293 294 def statement( 295 self, *, future: Literal[None, True] = None 296 ) -> Union["nodes.Statement", "nodes.Module", "NoReturn"]: 297 """The first parent node, including self, marked as statement node. 298 299 TODO: Deprecate the future parameter and only raise StatementMissing and return 300 nodes.Statement 301 302 :raises AttributeError: If self has no parent attribute 303 :raises StatementMissing: If self has no parent attribute and future is True 304 """ 305 if self.is_statement: 306 return cast("nodes.Statement", self) 307 if not self.parent: 308 if future: 309 raise StatementMissing(target=self) 310 warnings.warn( 311 "In astroid 3.0.0 NodeNG.statement() will return either a nodes.Statement " 312 "or raise a StatementMissing exception. AttributeError will no longer be raised. " 313 "This behaviour can already be triggered " 314 "by passing 'future=True' to a statement() call.", 315 DeprecationWarning, 316 ) 317 raise AttributeError(f"{self} object has no attribute 'parent'") 318 return self.parent.statement(future=future) 319 320 def frame( 321 self, 322 ) -> Union["nodes.FunctionDef", "nodes.Module", "nodes.ClassDef", "nodes.Lambda"]: 323 """The first parent frame node. 324 325 A frame node is a :class:`Module`, :class:`FunctionDef`, 326 :class:`ClassDef` or :class:`Lambda`. 327 328 :returns: The first parent frame node. 329 """ 330 return self.parent.frame() 331 332 def scope(self) -> "nodes.LocalsDictNodeNG": 333 """The first parent node defining a new scope. 334 These can be Module, FunctionDef, ClassDef, Lambda, or GeneratorExp nodes. 335 336 :returns: The first parent scope node. 337 """ 338 if not self.parent: 339 raise ParentMissingError(target=self) 340 return self.parent.scope() 341 342 def root(self): 343 """Return the root node of the syntax tree. 344 345 :returns: The root node. 346 :rtype: Module 347 """ 348 if self.parent: 349 return self.parent.root() 350 return self 351 352 def child_sequence(self, child): 353 """Search for the sequence that contains this child. 354 355 :param child: The child node to search sequences for. 356 :type child: NodeNG 357 358 :returns: The sequence containing the given child node. 359 :rtype: iterable(NodeNG) 360 361 :raises AstroidError: If no sequence could be found that contains 362 the given child. 363 """ 364 for field in self._astroid_fields: 365 node_or_sequence = getattr(self, field) 366 if node_or_sequence is child: 367 return [node_or_sequence] 368 # /!\ compiler.ast Nodes have an __iter__ walking over child nodes 369 if ( 370 isinstance(node_or_sequence, (tuple, list)) 371 and child in node_or_sequence 372 ): 373 return node_or_sequence 374 375 msg = "Could not find %s in %s's children" 376 raise AstroidError(msg % (repr(child), repr(self))) 377 378 def locate_child(self, child): 379 """Find the field of this node that contains the given child. 380 381 :param child: The child node to search fields for. 382 :type child: NodeNG 383 384 :returns: A tuple of the name of the field that contains the child, 385 and the sequence or node that contains the child node. 386 :rtype: tuple(str, iterable(NodeNG) or NodeNG) 387 388 :raises AstroidError: If no field could be found that contains 389 the given child. 390 """ 391 for field in self._astroid_fields: 392 node_or_sequence = getattr(self, field) 393 # /!\ compiler.ast Nodes have an __iter__ walking over child nodes 394 if child is node_or_sequence: 395 return field, child 396 if ( 397 isinstance(node_or_sequence, (tuple, list)) 398 and child in node_or_sequence 399 ): 400 return field, node_or_sequence 401 msg = "Could not find %s in %s's children" 402 raise AstroidError(msg % (repr(child), repr(self))) 403 404 # FIXME : should we merge child_sequence and locate_child ? locate_child 405 # is only used in are_exclusive, child_sequence one time in pylint. 406 407 def next_sibling(self): 408 """The next sibling statement node. 409 410 :returns: The next sibling statement node. 411 :rtype: NodeNG or None 412 """ 413 return self.parent.next_sibling() 414 415 def previous_sibling(self): 416 """The previous sibling statement. 417 418 :returns: The previous sibling statement node. 419 :rtype: NodeNG or None 420 """ 421 return self.parent.previous_sibling() 422 423 # these are lazy because they're relatively expensive to compute for every 424 # single node, and they rarely get looked at 425 426 @decorators.cachedproperty 427 def fromlineno(self) -> Optional[int]: 428 """The first line that this node appears on in the source code.""" 429 if self.lineno is None: 430 return self._fixed_source_line() 431 return self.lineno 432 433 @decorators.cachedproperty 434 def tolineno(self) -> Optional[int]: 435 """The last line that this node appears on in the source code.""" 436 if not self._astroid_fields: 437 # can't have children 438 last_child = None 439 else: 440 last_child = self.last_child() 441 if last_child is None: 442 return self.fromlineno 443 return last_child.tolineno 444 445 def _fixed_source_line(self) -> Optional[int]: 446 """Attempt to find the line that this node appears on. 447 448 We need this method since not all nodes have :attr:`lineno` set. 449 """ 450 line = self.lineno 451 _node: Optional[NodeNG] = self 452 try: 453 while line is None: 454 _node = next(_node.get_children()) 455 line = _node.lineno 456 except StopIteration: 457 _node = self.parent 458 while _node and line is None: 459 line = _node.lineno 460 _node = _node.parent 461 return line 462 463 def block_range(self, lineno): 464 """Get a range from the given line number to where this node ends. 465 466 :param lineno: The line number to start the range at. 467 :type lineno: int 468 469 :returns: The range of line numbers that this node belongs to, 470 starting at the given line number. 471 :rtype: tuple(int, int or None) 472 """ 473 return lineno, self.tolineno 474 475 def set_local(self, name, stmt): 476 """Define that the given name is declared in the given statement node. 477 478 This definition is stored on the parent scope node. 479 480 .. seealso:: :meth:`scope` 481 482 :param name: The name that is being defined. 483 :type name: str 484 485 :param stmt: The statement that defines the given name. 486 :type stmt: NodeNG 487 """ 488 self.parent.set_local(name, stmt) 489 490 @overload 491 def nodes_of_class( 492 self, 493 klass: Type[T_Nodes], 494 skip_klass: SkipKlassT = None, 495 ) -> Iterator[T_Nodes]: 496 ... 497 498 @overload 499 def nodes_of_class( 500 self, 501 klass: Tuple[Type[T_Nodes], Type[T_Nodes2]], 502 skip_klass: SkipKlassT = None, 503 ) -> Union[Iterator[T_Nodes], Iterator[T_Nodes2]]: 504 ... 505 506 @overload 507 def nodes_of_class( 508 self, 509 klass: Tuple[Type[T_Nodes], Type[T_Nodes2], Type[T_Nodes3]], 510 skip_klass: SkipKlassT = None, 511 ) -> Union[Iterator[T_Nodes], Iterator[T_Nodes2], Iterator[T_Nodes3]]: 512 ... 513 514 @overload 515 def nodes_of_class( 516 self, 517 klass: Tuple[Type[T_Nodes], ...], 518 skip_klass: SkipKlassT = None, 519 ) -> Iterator[T_Nodes]: 520 ... 521 522 def nodes_of_class( # type: ignore[misc] # mypy doesn't correctly recognize the overloads 523 self, 524 klass: Union[ 525 Type[T_Nodes], 526 Tuple[Type[T_Nodes], Type[T_Nodes2]], 527 Tuple[Type[T_Nodes], Type[T_Nodes2], Type[T_Nodes3]], 528 Tuple[Type[T_Nodes], ...], 529 ], 530 skip_klass: SkipKlassT = None, 531 ) -> Union[Iterator[T_Nodes], Iterator[T_Nodes2], Iterator[T_Nodes3]]: 532 """Get the nodes (including this one or below) of the given types. 533 534 :param klass: The types of node to search for. 535 536 :param skip_klass: The types of node to ignore. This is useful to ignore 537 subclasses of :attr:`klass`. 538 539 :returns: The node of the given types. 540 """ 541 if isinstance(self, klass): 542 yield self 543 544 if skip_klass is None: 545 for child_node in self.get_children(): 546 yield from child_node.nodes_of_class(klass, skip_klass) 547 548 return 549 550 for child_node in self.get_children(): 551 if isinstance(child_node, skip_klass): 552 continue 553 yield from child_node.nodes_of_class(klass, skip_klass) 554 555 @decorators.cached 556 def _get_assign_nodes(self): 557 return [] 558 559 def _get_name_nodes(self): 560 for child_node in self.get_children(): 561 yield from child_node._get_name_nodes() 562 563 def _get_return_nodes_skip_functions(self): 564 yield from () 565 566 def _get_yield_nodes_skip_lambdas(self): 567 yield from () 568 569 def _infer_name(self, frame, name): 570 # overridden for ImportFrom, Import, Global, TryExcept and Arguments 571 pass 572 573 def _infer(self, context=None): 574 """we don't know how to resolve a statement by default""" 575 # this method is overridden by most concrete classes 576 raise InferenceError( 577 "No inference function for {node!r}.", node=self, context=context 578 ) 579 580 def inferred(self): 581 """Get a list of the inferred values. 582 583 .. seealso:: :ref:`inference` 584 585 :returns: The inferred values. 586 :rtype: list 587 """ 588 return list(self.infer()) 589 590 def instantiate_class(self): 591 """Instantiate an instance of the defined class. 592 593 .. note:: 594 595 On anything other than a :class:`ClassDef` this will return self. 596 597 :returns: An instance of the defined class. 598 :rtype: object 599 """ 600 return self 601 602 def has_base(self, node): 603 """Check if this node inherits from the given type. 604 605 :param node: The node defining the base to look for. 606 Usually this is a :class:`Name` node. 607 :type node: NodeNG 608 """ 609 return False 610 611 def callable(self): 612 """Whether this node defines something that is callable. 613 614 :returns: True if this defines something that is callable, 615 False otherwise. 616 :rtype: bool 617 """ 618 return False 619 620 def eq(self, value): 621 return False 622 623 def as_string(self) -> str: 624 """Get the source code that this node represents.""" 625 return AsStringVisitor()(self) 626 627 def repr_tree( 628 self, 629 ids=False, 630 include_linenos=False, 631 ast_state=False, 632 indent=" ", 633 max_depth=0, 634 max_width=80, 635 ) -> str: 636 """Get a string representation of the AST from this node. 637 638 :param ids: If true, includes the ids with the node type names. 639 :type ids: bool 640 641 :param include_linenos: If true, includes the line numbers and 642 column offsets. 643 :type include_linenos: bool 644 645 :param ast_state: If true, includes information derived from 646 the whole AST like local and global variables. 647 :type ast_state: bool 648 649 :param indent: A string to use to indent the output string. 650 :type indent: str 651 652 :param max_depth: If set to a positive integer, won't return 653 nodes deeper than max_depth in the string. 654 :type max_depth: int 655 656 :param max_width: Attempt to format the output string to stay 657 within this number of characters, but can exceed it under some 658 circumstances. Only positive integer values are valid, the default is 80. 659 :type max_width: int 660 661 :returns: The string representation of the AST. 662 :rtype: str 663 """ 664 665 @_singledispatch 666 def _repr_tree(node, result, done, cur_indent="", depth=1): 667 """Outputs a representation of a non-tuple/list, non-node that's 668 contained within an AST, including strings. 669 """ 670 lines = pprint.pformat( 671 node, width=max(max_width - len(cur_indent), 1) 672 ).splitlines(True) 673 result.append(lines[0]) 674 result.extend([cur_indent + line for line in lines[1:]]) 675 return len(lines) != 1 676 677 # pylint: disable=unused-variable,useless-suppression; doesn't understand singledispatch 678 @_repr_tree.register(tuple) 679 @_repr_tree.register(list) 680 def _repr_seq(node, result, done, cur_indent="", depth=1): 681 """Outputs a representation of a sequence that's contained within an AST.""" 682 cur_indent += indent 683 result.append("[") 684 if not node: 685 broken = False 686 elif len(node) == 1: 687 broken = _repr_tree(node[0], result, done, cur_indent, depth) 688 elif len(node) == 2: 689 broken = _repr_tree(node[0], result, done, cur_indent, depth) 690 if not broken: 691 result.append(", ") 692 else: 693 result.append(",\n") 694 result.append(cur_indent) 695 broken = _repr_tree(node[1], result, done, cur_indent, depth) or broken 696 else: 697 result.append("\n") 698 result.append(cur_indent) 699 for child in node[:-1]: 700 _repr_tree(child, result, done, cur_indent, depth) 701 result.append(",\n") 702 result.append(cur_indent) 703 _repr_tree(node[-1], result, done, cur_indent, depth) 704 broken = True 705 result.append("]") 706 return broken 707 708 # pylint: disable=unused-variable,useless-suppression; doesn't understand singledispatch 709 @_repr_tree.register(NodeNG) 710 def _repr_node(node, result, done, cur_indent="", depth=1): 711 """Outputs a strings representation of an astroid node.""" 712 if node in done: 713 result.append( 714 indent + f"<Recursion on {type(node).__name__} with id={id(node)}" 715 ) 716 return False 717 done.add(node) 718 719 if max_depth and depth > max_depth: 720 result.append("...") 721 return False 722 depth += 1 723 cur_indent += indent 724 if ids: 725 result.append(f"{type(node).__name__}<0x{id(node):x}>(\n") 726 else: 727 result.append(f"{type(node).__name__}(") 728 fields = [] 729 if include_linenos: 730 fields.extend(("lineno", "col_offset")) 731 fields.extend(node._other_fields) 732 fields.extend(node._astroid_fields) 733 if ast_state: 734 fields.extend(node._other_other_fields) 735 if not fields: 736 broken = False 737 elif len(fields) == 1: 738 result.append(f"{fields[0]}=") 739 broken = _repr_tree( 740 getattr(node, fields[0]), result, done, cur_indent, depth 741 ) 742 else: 743 result.append("\n") 744 result.append(cur_indent) 745 for field in fields[:-1]: 746 result.append(f"{field}=") 747 _repr_tree(getattr(node, field), result, done, cur_indent, depth) 748 result.append(",\n") 749 result.append(cur_indent) 750 result.append(f"{fields[-1]}=") 751 _repr_tree(getattr(node, fields[-1]), result, done, cur_indent, depth) 752 broken = True 753 result.append(")") 754 return broken 755 756 result: List[str] = [] 757 _repr_tree(self, result, set()) 758 return "".join(result) 759 760 def bool_value(self, context=None): 761 """Determine the boolean value of this node. 762 763 The boolean value of a node can have three 764 possible values: 765 766 * False: For instance, empty data structures, 767 False, empty strings, instances which return 768 explicitly False from the __nonzero__ / __bool__ 769 method. 770 * True: Most of constructs are True by default: 771 classes, functions, modules etc 772 * Uninferable: The inference engine is uncertain of the 773 node's value. 774 775 :returns: The boolean value of this node. 776 :rtype: bool or Uninferable 777 """ 778 return util.Uninferable 779 780 def op_precedence(self): 781 # Look up by class name or default to highest precedence 782 return OP_PRECEDENCE.get(self.__class__.__name__, len(OP_PRECEDENCE)) 783 784 def op_left_associative(self): 785 # Everything is left associative except `**` and IfExp 786 return True 787