1# Copyright (c) 2009-2011, 2013-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr> 2# Copyright (c) 2010 Daniel Harding <dharding@gmail.com> 3# Copyright (c) 2012 FELD Boris <lothiraldan@gmail.com> 4# Copyright (c) 2013-2014 Google, Inc. 5# Copyright (c) 2014-2021 Claudiu Popa <pcmanticore@gmail.com> 6# Copyright (c) 2014 Eevee (Alex Munroe) <amunroe@yelp.com> 7# Copyright (c) 2015-2016 Ceridwen <ceridwenv@gmail.com> 8# Copyright (c) 2015 Florian Bruhin <me@the-compiler.org> 9# Copyright (c) 2016-2017 Derek Gustafson <degustaf@gmail.com> 10# Copyright (c) 2016 Jared Garst <jgarst@users.noreply.github.com> 11# Copyright (c) 2016 Jakub Wilk <jwilk@jwilk.net> 12# Copyright (c) 2016 Dave Baum <dbaum@google.com> 13# Copyright (c) 2017-2020 Ashley Whetter <ashley@awhetter.co.uk> 14# Copyright (c) 2017, 2019 Łukasz Rogalski <rogalski.91@gmail.com> 15# Copyright (c) 2017 rr- <rr-@sakuya.pl> 16# Copyright (c) 2018, 2021 Nick Drozd <nicholasdrozd@gmail.com> 17# Copyright (c) 2018-2021 hippo91 <guillaume.peillex@gmail.com> 18# Copyright (c) 2018 Bryce Guinta <bryce.paul.guinta@gmail.com> 19# Copyright (c) 2018 Ville Skyttä <ville.skytta@iki.fi> 20# Copyright (c) 2018 brendanator <brendan.maginnis@gmail.com> 21# Copyright (c) 2018 HoverHell <hoverhell@gmail.com> 22# Copyright (c) 2019 kavins14 <kavin.singh@mail.utoronto.ca> 23# Copyright (c) 2019 kavins14 <kavinsingh@hotmail.com> 24# Copyright (c) 2020 Raphael Gaschignard <raphael@rtpg.co> 25# Copyright (c) 2020 Bryce Guinta <bryce.guinta@protonmail.com> 26# Copyright (c) 2021 Marc Mueller <30130371+cdce8p@users.noreply.github.com> 27# Copyright (c) 2021 Pierre Sassoulas <pierre.sassoulas@gmail.com> 28# Copyright (c) 2021 Daniël van Noord <13665637+DanielNoord@users.noreply.github.com> 29# Copyright (c) 2021 David Liu <david@cs.toronto.edu> 30# Copyright (c) 2021 Alphadelta14 <alpha@alphaservcomputing.solutions> 31# Copyright (c) 2021 Andrew Haigh <hello@nelf.in> 32# Copyright (c) 2021 Federico Bond <federicobond@gmail.com> 33 34# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html 35# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE 36 37"""Module for some node classes. More nodes in scoped_nodes.py""" 38 39import abc 40import itertools 41import sys 42import typing 43import warnings 44from functools import lru_cache 45from typing import TYPE_CHECKING, Callable, Generator, Optional 46 47from astroid import decorators, mixins, util 48from astroid.bases import Instance, _infer_stmts 49from astroid.const import Context 50from astroid.context import InferenceContext 51from astroid.exceptions import ( 52 AstroidIndexError, 53 AstroidTypeError, 54 InferenceError, 55 NoDefault, 56 ParentMissingError, 57) 58from astroid.manager import AstroidManager 59from astroid.nodes.const import OP_PRECEDENCE 60from astroid.nodes.node_ng import NodeNG 61 62if sys.version_info >= (3, 8): 63 from typing import Literal 64else: 65 from typing_extensions import Literal 66 67if TYPE_CHECKING: 68 from astroid.nodes import LocalsDictNodeNG 69 70 71def _is_const(value): 72 return isinstance(value, tuple(CONST_CLS)) 73 74 75@decorators.raise_if_nothing_inferred 76def unpack_infer(stmt, context=None): 77 """recursively generate nodes inferred by the given statement. 78 If the inferred value is a list or a tuple, recurse on the elements 79 """ 80 if isinstance(stmt, (List, Tuple)): 81 for elt in stmt.elts: 82 if elt is util.Uninferable: 83 yield elt 84 continue 85 yield from unpack_infer(elt, context) 86 return dict(node=stmt, context=context) 87 # if inferred is a final node, return it and stop 88 inferred = next(stmt.infer(context), util.Uninferable) 89 if inferred is stmt: 90 yield inferred 91 return dict(node=stmt, context=context) 92 # else, infer recursively, except Uninferable object that should be returned as is 93 for inferred in stmt.infer(context): 94 if inferred is util.Uninferable: 95 yield inferred 96 else: 97 yield from unpack_infer(inferred, context) 98 99 return dict(node=stmt, context=context) 100 101 102def are_exclusive(stmt1, stmt2, exceptions: Optional[typing.List[str]] = None) -> bool: 103 """return true if the two given statements are mutually exclusive 104 105 `exceptions` may be a list of exception names. If specified, discard If 106 branches and check one of the statement is in an exception handler catching 107 one of the given exceptions. 108 109 algorithm : 110 1) index stmt1's parents 111 2) climb among stmt2's parents until we find a common parent 112 3) if the common parent is a If or TryExcept statement, look if nodes are 113 in exclusive branches 114 """ 115 # index stmt1's parents 116 stmt1_parents = {} 117 children = {} 118 previous = stmt1 119 for node in stmt1.node_ancestors(): 120 stmt1_parents[node] = 1 121 children[node] = previous 122 previous = node 123 # climb among stmt2's parents until we find a common parent 124 previous = stmt2 125 for node in stmt2.node_ancestors(): 126 if node in stmt1_parents: 127 # if the common parent is a If or TryExcept statement, look if 128 # nodes are in exclusive branches 129 if isinstance(node, If) and exceptions is None: 130 if ( 131 node.locate_child(previous)[1] 132 is not node.locate_child(children[node])[1] 133 ): 134 return True 135 elif isinstance(node, TryExcept): 136 c2attr, c2node = node.locate_child(previous) 137 c1attr, c1node = node.locate_child(children[node]) 138 if c1node is not c2node: 139 first_in_body_caught_by_handlers = ( 140 c2attr == "handlers" 141 and c1attr == "body" 142 and previous.catch(exceptions) 143 ) 144 second_in_body_caught_by_handlers = ( 145 c2attr == "body" 146 and c1attr == "handlers" 147 and children[node].catch(exceptions) 148 ) 149 first_in_else_other_in_handlers = ( 150 c2attr == "handlers" and c1attr == "orelse" 151 ) 152 second_in_else_other_in_handlers = ( 153 c2attr == "orelse" and c1attr == "handlers" 154 ) 155 if any( 156 ( 157 first_in_body_caught_by_handlers, 158 second_in_body_caught_by_handlers, 159 first_in_else_other_in_handlers, 160 second_in_else_other_in_handlers, 161 ) 162 ): 163 return True 164 elif c2attr == "handlers" and c1attr == "handlers": 165 return previous is not children[node] 166 return False 167 previous = node 168 return False 169 170 171# getitem() helpers. 172 173_SLICE_SENTINEL = object() 174 175 176def _slice_value(index, context=None): 177 """Get the value of the given slice index.""" 178 179 if isinstance(index, Const): 180 if isinstance(index.value, (int, type(None))): 181 return index.value 182 elif index is None: 183 return None 184 else: 185 # Try to infer what the index actually is. 186 # Since we can't return all the possible values, 187 # we'll stop at the first possible value. 188 try: 189 inferred = next(index.infer(context=context)) 190 except (InferenceError, StopIteration): 191 pass 192 else: 193 if isinstance(inferred, Const): 194 if isinstance(inferred.value, (int, type(None))): 195 return inferred.value 196 197 # Use a sentinel, because None can be a valid 198 # value that this function can return, 199 # as it is the case for unspecified bounds. 200 return _SLICE_SENTINEL 201 202 203def _infer_slice(node, context=None): 204 lower = _slice_value(node.lower, context) 205 upper = _slice_value(node.upper, context) 206 step = _slice_value(node.step, context) 207 if all(elem is not _SLICE_SENTINEL for elem in (lower, upper, step)): 208 return slice(lower, upper, step) 209 210 raise AstroidTypeError( 211 message="Could not infer slice used in subscript", 212 node=node, 213 index=node.parent, 214 context=context, 215 ) 216 217 218def _container_getitem(instance, elts, index, context=None): 219 """Get a slice or an item, using the given *index*, for the given sequence.""" 220 try: 221 if isinstance(index, Slice): 222 index_slice = _infer_slice(index, context=context) 223 new_cls = instance.__class__() 224 new_cls.elts = elts[index_slice] 225 new_cls.parent = instance.parent 226 return new_cls 227 if isinstance(index, Const): 228 return elts[index.value] 229 except IndexError as exc: 230 raise AstroidIndexError( 231 message="Index {index!s} out of range", 232 node=instance, 233 index=index, 234 context=context, 235 ) from exc 236 except TypeError as exc: 237 raise AstroidTypeError( 238 message="Type error {error!r}", node=instance, index=index, context=context 239 ) from exc 240 241 raise AstroidTypeError(f"Could not use {index} as subscript index") 242 243 244class Statement(NodeNG): 245 """Statement node adding a few attributes""" 246 247 is_statement = True 248 """Whether this node indicates a statement.""" 249 250 def next_sibling(self): 251 """The next sibling statement node. 252 253 :returns: The next sibling statement node. 254 :rtype: NodeNG or None 255 """ 256 stmts = self.parent.child_sequence(self) 257 index = stmts.index(self) 258 try: 259 return stmts[index + 1] 260 except IndexError: 261 return None 262 263 def previous_sibling(self): 264 """The previous sibling statement. 265 266 :returns: The previous sibling statement node. 267 :rtype: NodeNG or None 268 """ 269 stmts = self.parent.child_sequence(self) 270 index = stmts.index(self) 271 if index >= 1: 272 return stmts[index - 1] 273 return None 274 275 276class BaseContainer( 277 mixins.ParentAssignTypeMixin, NodeNG, Instance, metaclass=abc.ABCMeta 278): 279 """Base class for Set, FrozenSet, Tuple and List.""" 280 281 _astroid_fields = ("elts",) 282 283 def __init__( 284 self, 285 lineno: Optional[int] = None, 286 col_offset: Optional[int] = None, 287 parent: Optional[NodeNG] = None, 288 *, 289 end_lineno: Optional[int] = None, 290 end_col_offset: Optional[int] = None, 291 ) -> None: 292 """ 293 :param lineno: The line that this node appears on in the source code. 294 295 :param col_offset: The column that this node appears on in the 296 source code. 297 298 :param parent: The parent node in the syntax tree. 299 300 :param end_lineno: The last line this node appears on in the source code. 301 302 :param end_col_offset: The end column this node appears on in the 303 source code. Note: This is after the last symbol. 304 """ 305 self.elts: typing.List[NodeNG] = [] 306 """The elements in the node.""" 307 308 super().__init__( 309 lineno=lineno, 310 col_offset=col_offset, 311 end_lineno=end_lineno, 312 end_col_offset=end_col_offset, 313 parent=parent, 314 ) 315 316 def postinit(self, elts: typing.List[NodeNG]) -> None: 317 """Do some setup after initialisation. 318 319 :param elts: The list of elements the that node contains. 320 """ 321 self.elts = elts 322 323 @classmethod 324 def from_elements(cls, elts=None): 325 """Create a node of this type from the given list of elements. 326 327 :param elts: The list of elements that the node should contain. 328 :type elts: list(NodeNG) 329 330 :returns: A new node containing the given elements. 331 :rtype: NodeNG 332 """ 333 node = cls() 334 if elts is None: 335 node.elts = [] 336 else: 337 node.elts = [const_factory(e) if _is_const(e) else e for e in elts] 338 return node 339 340 def itered(self): 341 """An iterator over the elements this node contains. 342 343 :returns: The contents of this node. 344 :rtype: iterable(NodeNG) 345 """ 346 return self.elts 347 348 def bool_value(self, context=None): 349 """Determine the boolean value of this node. 350 351 :returns: The boolean value of this node. 352 :rtype: bool or Uninferable 353 """ 354 return bool(self.elts) 355 356 @abc.abstractmethod 357 def pytype(self): 358 """Get the name of the type that this node represents. 359 360 :returns: The name of the type. 361 :rtype: str 362 """ 363 364 def get_children(self): 365 yield from self.elts 366 367 368class LookupMixIn: 369 """Mixin to look up a name in the right scope.""" 370 371 @lru_cache(maxsize=None) 372 def lookup(self, name): 373 """Lookup where the given variable is assigned. 374 375 The lookup starts from self's scope. If self is not a frame itself 376 and the name is found in the inner frame locals, statements will be 377 filtered to remove ignorable statements according to self's location. 378 379 :param name: The name of the variable to find assignments for. 380 :type name: str 381 382 :returns: The scope node and the list of assignments associated to the 383 given name according to the scope where it has been found (locals, 384 globals or builtin). 385 :rtype: tuple(str, list(NodeNG)) 386 """ 387 return self.scope().scope_lookup(self, name) 388 389 def ilookup(self, name): 390 """Lookup the inferred values of the given variable. 391 392 :param name: The variable name to find values for. 393 :type name: str 394 395 :returns: The inferred values of the statements returned from 396 :meth:`lookup`. 397 :rtype: iterable 398 """ 399 frame, stmts = self.lookup(name) 400 context = InferenceContext() 401 return _infer_stmts(stmts, context, frame) 402 403 def _get_filtered_node_statements(self, nodes): 404 statements = [(node, node.statement()) for node in nodes] 405 # Next we check if we have ExceptHandlers that are parent 406 # of the underlying variable, in which case the last one survives 407 if len(statements) > 1 and all( 408 isinstance(stmt, ExceptHandler) for _, stmt in statements 409 ): 410 statements = [ 411 (node, stmt) for node, stmt in statements if stmt.parent_of(self) 412 ] 413 return statements 414 415 def _filter_stmts(self, stmts, frame, offset): 416 """Filter the given list of statements to remove ignorable statements. 417 418 If self is not a frame itself and the name is found in the inner 419 frame locals, statements will be filtered to remove ignorable 420 statements according to self's location. 421 422 :param stmts: The statements to filter. 423 :type stmts: list(NodeNG) 424 425 :param frame: The frame that all of the given statements belong to. 426 :type frame: NodeNG 427 428 :param offset: The line offset to filter statements up to. 429 :type offset: int 430 431 :returns: The filtered statements. 432 :rtype: list(NodeNG) 433 """ 434 # if offset == -1, my actual frame is not the inner frame but its parent 435 # 436 # class A(B): pass 437 # 438 # we need this to resolve B correctly 439 if offset == -1: 440 myframe = self.frame().parent.frame() 441 else: 442 myframe = self.frame() 443 # If the frame of this node is the same as the statement 444 # of this node, then the node is part of a class or 445 # a function definition and the frame of this node should be the 446 # the upper frame, not the frame of the definition. 447 # For more information why this is important, 448 # see Pylint issue #295. 449 # For example, for 'b', the statement is the same 450 # as the frame / scope: 451 # 452 # def test(b=1): 453 # ... 454 455 if self.statement() is myframe and myframe.parent: 456 myframe = myframe.parent.frame() 457 mystmt = self.statement() 458 # line filtering if we are in the same frame 459 # 460 # take care node may be missing lineno information (this is the case for 461 # nodes inserted for living objects) 462 if myframe is frame and mystmt.fromlineno is not None: 463 assert mystmt.fromlineno is not None, mystmt 464 mylineno = mystmt.fromlineno + offset 465 else: 466 # disabling lineno filtering 467 mylineno = 0 468 469 _stmts = [] 470 _stmt_parents = [] 471 statements = self._get_filtered_node_statements(stmts) 472 for node, stmt in statements: 473 # line filtering is on and we have reached our location, break 474 if stmt.fromlineno and stmt.fromlineno > mylineno > 0: 475 break 476 # Ignore decorators with the same name as the 477 # decorated function 478 # Fixes issue #375 479 if mystmt is stmt and is_from_decorator(self): 480 continue 481 assert hasattr(node, "assign_type"), ( 482 node, 483 node.scope(), 484 node.scope().locals, 485 ) 486 assign_type = node.assign_type() 487 if node.has_base(self): 488 break 489 490 _stmts, done = assign_type._get_filtered_stmts(self, node, _stmts, mystmt) 491 if done: 492 break 493 494 optional_assign = assign_type.optional_assign 495 if optional_assign and assign_type.parent_of(self): 496 # we are inside a loop, loop var assignment is hiding previous 497 # assignment 498 _stmts = [node] 499 _stmt_parents = [stmt.parent] 500 continue 501 502 if isinstance(assign_type, NamedExpr): 503 # If the NamedExpr is in an if statement we do some basic control flow inference 504 if_parent = _get_if_statement_ancestor(assign_type) 505 if if_parent: 506 # If the if statement is within another if statement we append the node 507 # to possible statements 508 if _get_if_statement_ancestor(if_parent): 509 optional_assign = False 510 _stmts.append(node) 511 _stmt_parents.append(stmt.parent) 512 # If the if statement is first-level and not within an orelse block 513 # we know that it will be evaluated 514 elif not if_parent.is_orelse: 515 _stmts = [node] 516 _stmt_parents = [stmt.parent] 517 # Else we do not known enough about the control flow to be 100% certain 518 # and we append to possible statements 519 else: 520 _stmts.append(node) 521 _stmt_parents.append(stmt.parent) 522 else: 523 _stmts = [node] 524 _stmt_parents = [stmt.parent] 525 526 # XXX comment various branches below!!! 527 try: 528 pindex = _stmt_parents.index(stmt.parent) 529 except ValueError: 530 pass 531 else: 532 # we got a parent index, this means the currently visited node 533 # is at the same block level as a previously visited node 534 if _stmts[pindex].assign_type().parent_of(assign_type): 535 # both statements are not at the same block level 536 continue 537 # if currently visited node is following previously considered 538 # assignment and both are not exclusive, we can drop the 539 # previous one. For instance in the following code :: 540 # 541 # if a: 542 # x = 1 543 # else: 544 # x = 2 545 # print x 546 # 547 # we can't remove neither x = 1 nor x = 2 when looking for 'x' 548 # of 'print x'; while in the following :: 549 # 550 # x = 1 551 # x = 2 552 # print x 553 # 554 # we can remove x = 1 when we see x = 2 555 # 556 # moreover, on loop assignment types, assignment won't 557 # necessarily be done if the loop has no iteration, so we don't 558 # want to clear previous assignments if any (hence the test on 559 # optional_assign) 560 if not (optional_assign or are_exclusive(_stmts[pindex], node)): 561 del _stmt_parents[pindex] 562 del _stmts[pindex] 563 564 # If self and node are exclusive, then we can ignore node 565 if are_exclusive(self, node): 566 continue 567 568 # An AssignName node overrides previous assignments if: 569 # 1. node's statement always assigns 570 # 2. node and self are in the same block (i.e., has the same parent as self) 571 if isinstance(node, (NamedExpr, AssignName)): 572 if isinstance(stmt, ExceptHandler): 573 # If node's statement is an ExceptHandler, then it is the variable 574 # bound to the caught exception. If self is not contained within 575 # the exception handler block, node should override previous assignments; 576 # otherwise, node should be ignored, as an exception variable 577 # is local to the handler block. 578 if stmt.parent_of(self): 579 _stmts = [] 580 _stmt_parents = [] 581 else: 582 continue 583 elif not optional_assign and stmt.parent is mystmt.parent: 584 _stmts = [] 585 _stmt_parents = [] 586 elif isinstance(node, DelName): 587 # Remove all previously stored assignments 588 _stmts = [] 589 _stmt_parents = [] 590 continue 591 # Add the new assignment 592 _stmts.append(node) 593 if isinstance(node, Arguments) or isinstance(node.parent, Arguments): 594 # Special case for _stmt_parents when node is a function parameter; 595 # in this case, stmt is the enclosing FunctionDef, which is what we 596 # want to add to _stmt_parents, not stmt.parent. This case occurs when 597 # node is an Arguments node (representing varargs or kwargs parameter), 598 # and when node.parent is an Arguments node (other parameters). 599 # See issue #180. 600 _stmt_parents.append(stmt) 601 else: 602 _stmt_parents.append(stmt.parent) 603 return _stmts 604 605 606# Name classes 607 608 609class AssignName( 610 mixins.NoChildrenMixin, LookupMixIn, mixins.ParentAssignTypeMixin, NodeNG 611): 612 """Variation of :class:`ast.Assign` representing assignment to a name. 613 614 An :class:`AssignName` is the name of something that is assigned to. 615 This includes variables defined in a function signature or in a loop. 616 617 >>> import astroid 618 >>> node = astroid.extract_node('variable = range(10)') 619 >>> node 620 <Assign l.1 at 0x7effe1db8550> 621 >>> list(node.get_children()) 622 [<AssignName.variable l.1 at 0x7effe1db8748>, <Call l.1 at 0x7effe1db8630>] 623 >>> list(node.get_children())[0].as_string() 624 'variable' 625 """ 626 627 _other_fields = ("name",) 628 629 @decorators.deprecate_default_argument_values(name="str") 630 def __init__( 631 self, 632 name: Optional[str] = None, 633 lineno: Optional[int] = None, 634 col_offset: Optional[int] = None, 635 parent: Optional[NodeNG] = None, 636 *, 637 end_lineno: Optional[int] = None, 638 end_col_offset: Optional[int] = None, 639 ) -> None: 640 """ 641 :param name: The name that is assigned to. 642 643 :param lineno: The line that this node appears on in the source code. 644 645 :param col_offset: The column that this node appears on in the 646 source code. 647 648 :param parent: The parent node in the syntax tree. 649 650 :param end_lineno: The last line this node appears on in the source code. 651 652 :param end_col_offset: The end column this node appears on in the 653 source code. Note: This is after the last symbol. 654 """ 655 self.name: Optional[str] = name 656 """The name that is assigned to.""" 657 658 super().__init__( 659 lineno=lineno, 660 col_offset=col_offset, 661 end_lineno=end_lineno, 662 end_col_offset=end_col_offset, 663 parent=parent, 664 ) 665 666 667class DelName( 668 mixins.NoChildrenMixin, LookupMixIn, mixins.ParentAssignTypeMixin, NodeNG 669): 670 """Variation of :class:`ast.Delete` representing deletion of a name. 671 672 A :class:`DelName` is the name of something that is deleted. 673 674 >>> import astroid 675 >>> node = astroid.extract_node("del variable #@") 676 >>> list(node.get_children()) 677 [<DelName.variable l.1 at 0x7effe1da4d30>] 678 >>> list(node.get_children())[0].as_string() 679 'variable' 680 """ 681 682 _other_fields = ("name",) 683 684 @decorators.deprecate_default_argument_values(name="str") 685 def __init__( 686 self, 687 name: Optional[str] = None, 688 lineno: Optional[int] = None, 689 col_offset: Optional[int] = None, 690 parent: Optional[NodeNG] = None, 691 *, 692 end_lineno: Optional[int] = None, 693 end_col_offset: Optional[int] = None, 694 ) -> None: 695 """ 696 :param name: The name that is being deleted. 697 698 :param lineno: The line that this node appears on in the source code. 699 700 :param col_offset: The column that this node appears on in the 701 source code. 702 703 :param parent: The parent node in the syntax tree. 704 705 :param end_lineno: The last line this node appears on in the source code. 706 707 :param end_col_offset: The end column this node appears on in the 708 source code. Note: This is after the last symbol. 709 """ 710 self.name: Optional[str] = name 711 """The name that is being deleted.""" 712 713 super().__init__( 714 lineno=lineno, 715 col_offset=col_offset, 716 end_lineno=end_lineno, 717 end_col_offset=end_col_offset, 718 parent=parent, 719 ) 720 721 722class Name(mixins.NoChildrenMixin, LookupMixIn, NodeNG): 723 """Class representing an :class:`ast.Name` node. 724 725 A :class:`Name` node is something that is named, but not covered by 726 :class:`AssignName` or :class:`DelName`. 727 728 >>> import astroid 729 >>> node = astroid.extract_node('range(10)') 730 >>> node 731 <Call l.1 at 0x7effe1db8710> 732 >>> list(node.get_children()) 733 [<Name.range l.1 at 0x7effe1db86a0>, <Const.int l.1 at 0x7effe1db8518>] 734 >>> list(node.get_children())[0].as_string() 735 'range' 736 """ 737 738 _other_fields = ("name",) 739 740 @decorators.deprecate_default_argument_values(name="str") 741 def __init__( 742 self, 743 name: Optional[str] = None, 744 lineno: Optional[int] = None, 745 col_offset: Optional[int] = None, 746 parent: Optional[NodeNG] = None, 747 *, 748 end_lineno: Optional[int] = None, 749 end_col_offset: Optional[int] = None, 750 ) -> None: 751 """ 752 :param name: The name that this node refers to. 753 754 :param lineno: The line that this node appears on in the source code. 755 756 :param col_offset: The column that this node appears on in the 757 source code. 758 759 :param parent: The parent node in the syntax tree. 760 761 :param end_lineno: The last line this node appears on in the source code. 762 763 :param end_col_offset: The end column this node appears on in the 764 source code. Note: This is after the last symbol. 765 """ 766 self.name: Optional[str] = name 767 """The name that this node refers to.""" 768 769 super().__init__( 770 lineno=lineno, 771 col_offset=col_offset, 772 end_lineno=end_lineno, 773 end_col_offset=end_col_offset, 774 parent=parent, 775 ) 776 777 def _get_name_nodes(self): 778 yield self 779 780 for child_node in self.get_children(): 781 yield from child_node._get_name_nodes() 782 783 784class Arguments(mixins.AssignTypeMixin, NodeNG): 785 """Class representing an :class:`ast.arguments` node. 786 787 An :class:`Arguments` node represents that arguments in a 788 function definition. 789 790 >>> import astroid 791 >>> node = astroid.extract_node('def foo(bar): pass') 792 >>> node 793 <FunctionDef.foo l.1 at 0x7effe1db8198> 794 >>> node.args 795 <Arguments l.1 at 0x7effe1db82e8> 796 """ 797 798 # Python 3.4+ uses a different approach regarding annotations, 799 # each argument is a new class, _ast.arg, which exposes an 800 # 'annotation' attribute. In astroid though, arguments are exposed 801 # as is in the Arguments node and the only way to expose annotations 802 # is by using something similar with Python 3.3: 803 # - we expose 'varargannotation' and 'kwargannotation' of annotations 804 # of varargs and kwargs. 805 # - we expose 'annotation', a list with annotations for 806 # for each normal argument. If an argument doesn't have an 807 # annotation, its value will be None. 808 _astroid_fields = ( 809 "args", 810 "defaults", 811 "kwonlyargs", 812 "posonlyargs", 813 "posonlyargs_annotations", 814 "kw_defaults", 815 "annotations", 816 "varargannotation", 817 "kwargannotation", 818 "kwonlyargs_annotations", 819 "type_comment_args", 820 "type_comment_kwonlyargs", 821 "type_comment_posonlyargs", 822 ) 823 824 _other_fields = ("vararg", "kwarg") 825 826 lineno: None 827 col_offset: None 828 end_lineno: None 829 end_col_offset: None 830 831 def __init__( 832 self, 833 vararg: Optional[str] = None, 834 kwarg: Optional[str] = None, 835 parent: Optional[NodeNG] = None, 836 ) -> None: 837 """ 838 :param vararg: The name of the variable length arguments. 839 840 :param kwarg: The name of the variable length keyword arguments. 841 842 :param parent: The parent node in the syntax tree. 843 """ 844 super().__init__(parent=parent) 845 846 self.vararg: Optional[str] = vararg # can be None 847 """The name of the variable length arguments.""" 848 849 self.kwarg: Optional[str] = kwarg # can be None 850 """The name of the variable length keyword arguments.""" 851 852 self.args: typing.List[AssignName] 853 """The names of the required arguments.""" 854 855 self.defaults: typing.List[NodeNG] 856 """The default values for arguments that can be passed positionally.""" 857 858 self.kwonlyargs: typing.List[AssignName] 859 """The keyword arguments that cannot be passed positionally.""" 860 861 self.posonlyargs: typing.List[AssignName] = [] 862 """The arguments that can only be passed positionally.""" 863 864 self.kw_defaults: typing.List[Optional[NodeNG]] 865 """The default values for keyword arguments that cannot be passed positionally.""" 866 867 self.annotations: typing.List[Optional[NodeNG]] 868 """The type annotations of arguments that can be passed positionally.""" 869 870 self.posonlyargs_annotations: typing.List[Optional[NodeNG]] = [] 871 """The type annotations of arguments that can only be passed positionally.""" 872 873 self.kwonlyargs_annotations: typing.List[Optional[NodeNG]] = [] 874 """The type annotations of arguments that cannot be passed positionally.""" 875 876 self.type_comment_args: typing.List[Optional[NodeNG]] = [] 877 """The type annotation, passed by a type comment, of each argument. 878 879 If an argument does not have a type comment, 880 the value for that argument will be None. 881 """ 882 883 self.type_comment_kwonlyargs: typing.List[Optional[NodeNG]] = [] 884 """The type annotation, passed by a type comment, of each keyword only argument. 885 886 If an argument does not have a type comment, 887 the value for that argument will be None. 888 """ 889 890 self.type_comment_posonlyargs: typing.List[Optional[NodeNG]] = [] 891 """The type annotation, passed by a type comment, of each positional argument. 892 893 If an argument does not have a type comment, 894 the value for that argument will be None. 895 """ 896 897 self.varargannotation: Optional[NodeNG] = None # can be None 898 """The type annotation for the variable length arguments.""" 899 900 self.kwargannotation: Optional[NodeNG] = None # can be None 901 """The type annotation for the variable length keyword arguments.""" 902 903 # pylint: disable=too-many-arguments 904 def postinit( 905 self, 906 args: typing.List[AssignName], 907 defaults: typing.List[NodeNG], 908 kwonlyargs: typing.List[AssignName], 909 kw_defaults: typing.List[Optional[NodeNG]], 910 annotations: typing.List[Optional[NodeNG]], 911 posonlyargs: Optional[typing.List[AssignName]] = None, 912 kwonlyargs_annotations: Optional[typing.List[Optional[NodeNG]]] = None, 913 posonlyargs_annotations: Optional[typing.List[Optional[NodeNG]]] = None, 914 varargannotation: Optional[NodeNG] = None, 915 kwargannotation: Optional[NodeNG] = None, 916 type_comment_args: Optional[typing.List[Optional[NodeNG]]] = None, 917 type_comment_kwonlyargs: Optional[typing.List[Optional[NodeNG]]] = None, 918 type_comment_posonlyargs: Optional[typing.List[Optional[NodeNG]]] = None, 919 ) -> None: 920 """Do some setup after initialisation. 921 922 :param args: The names of the required arguments. 923 924 :param defaults: The default values for arguments that can be passed 925 positionally. 926 927 :param kwonlyargs: The keyword arguments that cannot be passed 928 positionally. 929 930 :param posonlyargs: The arguments that can only be passed 931 positionally. 932 933 :param kw_defaults: The default values for keyword arguments that 934 cannot be passed positionally. 935 936 :param annotations: The type annotations of arguments that can be 937 passed positionally. 938 939 :param kwonlyargs_annotations: The type annotations of arguments that 940 cannot be passed positionally. This should always be passed in 941 Python 3. 942 943 :param posonlyargs_annotations: The type annotations of arguments that 944 can only be passed positionally. This should always be passed in 945 Python 3. 946 947 :param varargannotation: The type annotation for the variable length 948 arguments. 949 950 :param kwargannotation: The type annotation for the variable length 951 keyword arguments. 952 953 :param type_comment_args: The type annotation, 954 passed by a type comment, of each argument. 955 956 :param type_comment_args: The type annotation, 957 passed by a type comment, of each keyword only argument. 958 959 :param type_comment_args: The type annotation, 960 passed by a type comment, of each positional argument. 961 """ 962 self.args = args 963 self.defaults = defaults 964 self.kwonlyargs = kwonlyargs 965 if posonlyargs is not None: 966 self.posonlyargs = posonlyargs 967 self.kw_defaults = kw_defaults 968 self.annotations = annotations 969 if kwonlyargs_annotations is not None: 970 self.kwonlyargs_annotations = kwonlyargs_annotations 971 if posonlyargs_annotations is not None: 972 self.posonlyargs_annotations = posonlyargs_annotations 973 self.varargannotation = varargannotation 974 self.kwargannotation = kwargannotation 975 if type_comment_args is not None: 976 self.type_comment_args = type_comment_args 977 if type_comment_kwonlyargs is not None: 978 self.type_comment_kwonlyargs = type_comment_kwonlyargs 979 if type_comment_posonlyargs is not None: 980 self.type_comment_posonlyargs = type_comment_posonlyargs 981 982 def _infer_name(self, frame, name): 983 if self.parent is frame: 984 return name 985 return None 986 987 @decorators.cachedproperty 988 def fromlineno(self): 989 """The first line that this node appears on in the source code. 990 991 :type: int or None 992 """ 993 lineno = super().fromlineno 994 return max(lineno, self.parent.fromlineno or 0) 995 996 @decorators.cachedproperty 997 def arguments(self): 998 """Get all the arguments for this node, including positional only and positional and keyword""" 999 return list(itertools.chain((self.posonlyargs or ()), self.args or ())) 1000 1001 def format_args(self): 1002 """Get the arguments formatted as string. 1003 1004 :returns: The formatted arguments. 1005 :rtype: str 1006 """ 1007 result = [] 1008 positional_only_defaults = [] 1009 positional_or_keyword_defaults = self.defaults 1010 if self.defaults: 1011 args = self.args or [] 1012 positional_or_keyword_defaults = self.defaults[-len(args) :] 1013 positional_only_defaults = self.defaults[: len(self.defaults) - len(args)] 1014 1015 if self.posonlyargs: 1016 result.append( 1017 _format_args( 1018 self.posonlyargs, 1019 positional_only_defaults, 1020 self.posonlyargs_annotations, 1021 ) 1022 ) 1023 result.append("/") 1024 if self.args: 1025 result.append( 1026 _format_args( 1027 self.args, 1028 positional_or_keyword_defaults, 1029 getattr(self, "annotations", None), 1030 ) 1031 ) 1032 if self.vararg: 1033 result.append(f"*{self.vararg}") 1034 if self.kwonlyargs: 1035 if not self.vararg: 1036 result.append("*") 1037 result.append( 1038 _format_args( 1039 self.kwonlyargs, self.kw_defaults, self.kwonlyargs_annotations 1040 ) 1041 ) 1042 if self.kwarg: 1043 result.append(f"**{self.kwarg}") 1044 return ", ".join(result) 1045 1046 def default_value(self, argname): 1047 """Get the default value for an argument. 1048 1049 :param argname: The name of the argument to get the default value for. 1050 :type argname: str 1051 1052 :raises NoDefault: If there is no default value defined for the 1053 given argument. 1054 """ 1055 args = self.arguments 1056 index = _find_arg(argname, args)[0] 1057 if index is not None: 1058 idx = index - (len(args) - len(self.defaults)) 1059 if idx >= 0: 1060 return self.defaults[idx] 1061 index = _find_arg(argname, self.kwonlyargs)[0] 1062 if index is not None and self.kw_defaults[index] is not None: 1063 return self.kw_defaults[index] 1064 raise NoDefault(func=self.parent, name=argname) 1065 1066 def is_argument(self, name): 1067 """Check if the given name is defined in the arguments. 1068 1069 :param name: The name to check for. 1070 :type name: str 1071 1072 :returns: True if the given name is defined in the arguments, 1073 False otherwise. 1074 :rtype: bool 1075 """ 1076 if name == self.vararg: 1077 return True 1078 if name == self.kwarg: 1079 return True 1080 return ( 1081 self.find_argname(name, rec=True)[1] is not None 1082 or self.kwonlyargs 1083 and _find_arg(name, self.kwonlyargs, rec=True)[1] is not None 1084 ) 1085 1086 def find_argname(self, argname, rec=False): 1087 """Get the index and :class:`AssignName` node for given name. 1088 1089 :param argname: The name of the argument to search for. 1090 :type argname: str 1091 1092 :param rec: Whether or not to include arguments in unpacked tuples 1093 in the search. 1094 :type rec: bool 1095 1096 :returns: The index and node for the argument. 1097 :rtype: tuple(str or None, AssignName or None) 1098 """ 1099 if self.arguments: 1100 return _find_arg(argname, self.arguments, rec) 1101 return None, None 1102 1103 def get_children(self): 1104 yield from self.posonlyargs or () 1105 1106 for elt in self.posonlyargs_annotations: 1107 if elt is not None: 1108 yield elt 1109 1110 yield from self.args or () 1111 1112 yield from self.defaults 1113 yield from self.kwonlyargs 1114 1115 for elt in self.kw_defaults: 1116 if elt is not None: 1117 yield elt 1118 1119 for elt in self.annotations: 1120 if elt is not None: 1121 yield elt 1122 1123 if self.varargannotation is not None: 1124 yield self.varargannotation 1125 1126 if self.kwargannotation is not None: 1127 yield self.kwargannotation 1128 1129 for elt in self.kwonlyargs_annotations: 1130 if elt is not None: 1131 yield elt 1132 1133 1134def _find_arg(argname, args, rec=False): 1135 for i, arg in enumerate(args): 1136 if isinstance(arg, Tuple): 1137 if rec: 1138 found = _find_arg(argname, arg.elts) 1139 if found[0] is not None: 1140 return found 1141 elif arg.name == argname: 1142 return i, arg 1143 return None, None 1144 1145 1146def _format_args(args, defaults=None, annotations=None): 1147 values = [] 1148 if args is None: 1149 return "" 1150 if annotations is None: 1151 annotations = [] 1152 if defaults is not None: 1153 default_offset = len(args) - len(defaults) 1154 packed = itertools.zip_longest(args, annotations) 1155 for i, (arg, annotation) in enumerate(packed): 1156 if isinstance(arg, Tuple): 1157 values.append(f"({_format_args(arg.elts)})") 1158 else: 1159 argname = arg.name 1160 default_sep = "=" 1161 if annotation is not None: 1162 argname += ": " + annotation.as_string() 1163 default_sep = " = " 1164 values.append(argname) 1165 1166 if defaults is not None and i >= default_offset: 1167 if defaults[i - default_offset] is not None: 1168 values[-1] += default_sep + defaults[i - default_offset].as_string() 1169 return ", ".join(values) 1170 1171 1172class AssignAttr(mixins.ParentAssignTypeMixin, NodeNG): 1173 """Variation of :class:`ast.Assign` representing assignment to an attribute. 1174 1175 >>> import astroid 1176 >>> node = astroid.extract_node('self.attribute = range(10)') 1177 >>> node 1178 <Assign l.1 at 0x7effe1d521d0> 1179 >>> list(node.get_children()) 1180 [<AssignAttr.attribute l.1 at 0x7effe1d52320>, <Call l.1 at 0x7effe1d522e8>] 1181 >>> list(node.get_children())[0].as_string() 1182 'self.attribute' 1183 """ 1184 1185 _astroid_fields = ("expr",) 1186 _other_fields = ("attrname",) 1187 1188 @decorators.deprecate_default_argument_values(attrname="str") 1189 def __init__( 1190 self, 1191 attrname: Optional[str] = None, 1192 lineno: Optional[int] = None, 1193 col_offset: Optional[int] = None, 1194 parent: Optional[NodeNG] = None, 1195 *, 1196 end_lineno: Optional[int] = None, 1197 end_col_offset: Optional[int] = None, 1198 ) -> None: 1199 """ 1200 :param attrname: The name of the attribute being assigned to. 1201 1202 :param lineno: The line that this node appears on in the source code. 1203 1204 :param col_offset: The column that this node appears on in the 1205 source code. 1206 1207 :param parent: The parent node in the syntax tree. 1208 1209 :param end_lineno: The last line this node appears on in the source code. 1210 1211 :param end_col_offset: The end column this node appears on in the 1212 source code. Note: This is after the last symbol. 1213 """ 1214 self.expr: Optional[NodeNG] = None 1215 """What has the attribute that is being assigned to.""" 1216 1217 self.attrname: Optional[str] = attrname 1218 """The name of the attribute being assigned to.""" 1219 1220 super().__init__( 1221 lineno=lineno, 1222 col_offset=col_offset, 1223 end_lineno=end_lineno, 1224 end_col_offset=end_col_offset, 1225 parent=parent, 1226 ) 1227 1228 def postinit(self, expr: Optional[NodeNG] = None) -> None: 1229 """Do some setup after initialisation. 1230 1231 :param expr: What has the attribute that is being assigned to. 1232 """ 1233 self.expr = expr 1234 1235 def get_children(self): 1236 yield self.expr 1237 1238 1239class Assert(Statement): 1240 """Class representing an :class:`ast.Assert` node. 1241 1242 An :class:`Assert` node represents an assert statement. 1243 1244 >>> import astroid 1245 >>> node = astroid.extract_node('assert len(things) == 10, "Not enough things"') 1246 >>> node 1247 <Assert l.1 at 0x7effe1d527b8> 1248 """ 1249 1250 _astroid_fields = ("test", "fail") 1251 1252 def __init__( 1253 self, 1254 lineno: Optional[int] = None, 1255 col_offset: Optional[int] = None, 1256 parent: Optional[NodeNG] = None, 1257 *, 1258 end_lineno: Optional[int] = None, 1259 end_col_offset: Optional[int] = None, 1260 ) -> None: 1261 """ 1262 :param lineno: The line that this node appears on in the source code. 1263 1264 :param col_offset: The column that this node appears on in the 1265 source code. 1266 1267 :param parent: The parent node in the syntax tree. 1268 1269 :param end_lineno: The last line this node appears on in the source code. 1270 1271 :param end_col_offset: The end column this node appears on in the 1272 source code. Note: This is after the last symbol. 1273 """ 1274 self.test: Optional[NodeNG] = None 1275 """The test that passes or fails the assertion.""" 1276 1277 self.fail: Optional[NodeNG] = None # can be None 1278 """The message shown when the assertion fails.""" 1279 1280 super().__init__( 1281 lineno=lineno, 1282 col_offset=col_offset, 1283 end_lineno=end_lineno, 1284 end_col_offset=end_col_offset, 1285 parent=parent, 1286 ) 1287 1288 def postinit( 1289 self, test: Optional[NodeNG] = None, fail: Optional[NodeNG] = None 1290 ) -> None: 1291 """Do some setup after initialisation. 1292 1293 :param test: The test that passes or fails the assertion. 1294 1295 :param fail: The message shown when the assertion fails. 1296 """ 1297 self.fail = fail 1298 self.test = test 1299 1300 def get_children(self): 1301 yield self.test 1302 1303 if self.fail is not None: 1304 yield self.fail 1305 1306 1307class Assign(mixins.AssignTypeMixin, Statement): 1308 """Class representing an :class:`ast.Assign` node. 1309 1310 An :class:`Assign` is a statement where something is explicitly 1311 asssigned to. 1312 1313 >>> import astroid 1314 >>> node = astroid.extract_node('variable = range(10)') 1315 >>> node 1316 <Assign l.1 at 0x7effe1db8550> 1317 """ 1318 1319 _astroid_fields = ("targets", "value") 1320 _other_other_fields = ("type_annotation",) 1321 1322 def __init__( 1323 self, 1324 lineno: Optional[int] = None, 1325 col_offset: Optional[int] = None, 1326 parent: Optional[NodeNG] = None, 1327 *, 1328 end_lineno: Optional[int] = None, 1329 end_col_offset: Optional[int] = None, 1330 ) -> None: 1331 """ 1332 :param lineno: The line that this node appears on in the source code. 1333 1334 :param col_offset: The column that this node appears on in the 1335 source code. 1336 1337 :param parent: The parent node in the syntax tree. 1338 1339 :param end_lineno: The last line this node appears on in the source code. 1340 1341 :param end_col_offset: The end column this node appears on in the 1342 source code. Note: This is after the last symbol. 1343 """ 1344 self.targets: typing.List[NodeNG] = [] 1345 """What is being assigned to.""" 1346 1347 self.value: Optional[NodeNG] = None 1348 """The value being assigned to the variables.""" 1349 1350 self.type_annotation: Optional[NodeNG] = None # can be None 1351 """If present, this will contain the type annotation passed by a type comment""" 1352 1353 super().__init__( 1354 lineno=lineno, 1355 col_offset=col_offset, 1356 end_lineno=end_lineno, 1357 end_col_offset=end_col_offset, 1358 parent=parent, 1359 ) 1360 1361 def postinit( 1362 self, 1363 targets: Optional[typing.List[NodeNG]] = None, 1364 value: Optional[NodeNG] = None, 1365 type_annotation: Optional[NodeNG] = None, 1366 ) -> None: 1367 """Do some setup after initialisation. 1368 1369 :param targets: What is being assigned to. 1370 :param value: The value being assigned to the variables. 1371 :param type_annotation: 1372 """ 1373 if targets is not None: 1374 self.targets = targets 1375 self.value = value 1376 self.type_annotation = type_annotation 1377 1378 def get_children(self): 1379 yield from self.targets 1380 1381 yield self.value 1382 1383 @decorators.cached 1384 def _get_assign_nodes(self): 1385 return [self] + list(self.value._get_assign_nodes()) 1386 1387 def _get_yield_nodes_skip_lambdas(self): 1388 yield from self.value._get_yield_nodes_skip_lambdas() 1389 1390 1391class AnnAssign(mixins.AssignTypeMixin, Statement): 1392 """Class representing an :class:`ast.AnnAssign` node. 1393 1394 An :class:`AnnAssign` is an assignment with a type annotation. 1395 1396 >>> import astroid 1397 >>> node = astroid.extract_node('variable: List[int] = range(10)') 1398 >>> node 1399 <AnnAssign l.1 at 0x7effe1d4c630> 1400 """ 1401 1402 _astroid_fields = ("target", "annotation", "value") 1403 _other_fields = ("simple",) 1404 1405 def __init__( 1406 self, 1407 lineno: Optional[int] = None, 1408 col_offset: Optional[int] = None, 1409 parent: Optional[NodeNG] = None, 1410 *, 1411 end_lineno: Optional[int] = None, 1412 end_col_offset: Optional[int] = None, 1413 ) -> None: 1414 """ 1415 :param lineno: The line that this node appears on in the source code. 1416 1417 :param col_offset: The column that this node appears on in the 1418 source code. 1419 1420 :param parent: The parent node in the syntax tree. 1421 1422 :param end_lineno: The last line this node appears on in the source code. 1423 1424 :param end_col_offset: The end column this node appears on in the 1425 source code. Note: This is after the last symbol. 1426 """ 1427 self.target: Optional[NodeNG] = None 1428 """What is being assigned to.""" 1429 1430 self.annotation: Optional[NodeNG] = None 1431 """The type annotation of what is being assigned to.""" 1432 1433 self.value: Optional[NodeNG] = None # can be None 1434 """The value being assigned to the variables.""" 1435 1436 self.simple: Optional[int] = None 1437 """Whether :attr:`target` is a pure name or a complex statement.""" 1438 1439 super().__init__( 1440 lineno=lineno, 1441 col_offset=col_offset, 1442 end_lineno=end_lineno, 1443 end_col_offset=end_col_offset, 1444 parent=parent, 1445 ) 1446 1447 def postinit( 1448 self, 1449 target: NodeNG, 1450 annotation: NodeNG, 1451 simple: int, 1452 value: Optional[NodeNG] = None, 1453 ) -> None: 1454 """Do some setup after initialisation. 1455 1456 :param target: What is being assigned to. 1457 1458 :param annotation: The type annotation of what is being assigned to. 1459 1460 :param simple: Whether :attr:`target` is a pure name 1461 or a complex statement. 1462 1463 :param value: The value being assigned to the variables. 1464 """ 1465 self.target = target 1466 self.annotation = annotation 1467 self.value = value 1468 self.simple = simple 1469 1470 def get_children(self): 1471 yield self.target 1472 yield self.annotation 1473 1474 if self.value is not None: 1475 yield self.value 1476 1477 1478class AugAssign(mixins.AssignTypeMixin, Statement): 1479 """Class representing an :class:`ast.AugAssign` node. 1480 1481 An :class:`AugAssign` is an assignment paired with an operator. 1482 1483 >>> import astroid 1484 >>> node = astroid.extract_node('variable += 1') 1485 >>> node 1486 <AugAssign l.1 at 0x7effe1db4d68> 1487 """ 1488 1489 _astroid_fields = ("target", "value") 1490 _other_fields = ("op",) 1491 1492 @decorators.deprecate_default_argument_values(op="str") 1493 def __init__( 1494 self, 1495 op: Optional[str] = None, 1496 lineno: Optional[int] = None, 1497 col_offset: Optional[int] = None, 1498 parent: Optional[NodeNG] = None, 1499 *, 1500 end_lineno: Optional[int] = None, 1501 end_col_offset: Optional[int] = None, 1502 ) -> None: 1503 """ 1504 :param op: The operator that is being combined with the assignment. 1505 This includes the equals sign. 1506 1507 :param lineno: The line that this node appears on in the source code. 1508 1509 :param col_offset: The column that this node appears on in the 1510 source code. 1511 1512 :param parent: The parent node in the syntax tree. 1513 1514 :param end_lineno: The last line this node appears on in the source code. 1515 1516 :param end_col_offset: The end column this node appears on in the 1517 source code. Note: This is after the last symbol. 1518 """ 1519 self.target: Optional[NodeNG] = None 1520 """What is being assigned to.""" 1521 1522 self.op: Optional[str] = op 1523 """The operator that is being combined with the assignment. 1524 1525 This includes the equals sign. 1526 """ 1527 1528 self.value: Optional[NodeNG] = None 1529 """The value being assigned to the variable.""" 1530 1531 super().__init__( 1532 lineno=lineno, 1533 col_offset=col_offset, 1534 end_lineno=end_lineno, 1535 end_col_offset=end_col_offset, 1536 parent=parent, 1537 ) 1538 1539 def postinit( 1540 self, target: Optional[NodeNG] = None, value: Optional[NodeNG] = None 1541 ) -> None: 1542 """Do some setup after initialisation. 1543 1544 :param target: What is being assigned to. 1545 1546 :param value: The value being assigned to the variable. 1547 """ 1548 self.target = target 1549 self.value = value 1550 1551 # This is set by inference.py 1552 def _infer_augassign(self, context=None): 1553 raise NotImplementedError 1554 1555 def type_errors(self, context=None): 1556 """Get a list of type errors which can occur during inference. 1557 1558 Each TypeError is represented by a :class:`BadBinaryOperationMessage` , 1559 which holds the original exception. 1560 1561 :returns: The list of possible type errors. 1562 :rtype: list(BadBinaryOperationMessage) 1563 """ 1564 try: 1565 results = self._infer_augassign(context=context) 1566 return [ 1567 result 1568 for result in results 1569 if isinstance(result, util.BadBinaryOperationMessage) 1570 ] 1571 except InferenceError: 1572 return [] 1573 1574 def get_children(self): 1575 yield self.target 1576 yield self.value 1577 1578 def _get_yield_nodes_skip_lambdas(self): 1579 """An AugAssign node can contain a Yield node in the value""" 1580 yield from self.value._get_yield_nodes_skip_lambdas() 1581 yield from super()._get_yield_nodes_skip_lambdas() 1582 1583 1584class BinOp(NodeNG): 1585 """Class representing an :class:`ast.BinOp` node. 1586 1587 A :class:`BinOp` node is an application of a binary operator. 1588 1589 >>> import astroid 1590 >>> node = astroid.extract_node('a + b') 1591 >>> node 1592 <BinOp l.1 at 0x7f23b2e8cfd0> 1593 """ 1594 1595 _astroid_fields = ("left", "right") 1596 _other_fields = ("op",) 1597 1598 @decorators.deprecate_default_argument_values(op="str") 1599 def __init__( 1600 self, 1601 op: Optional[str] = None, 1602 lineno: Optional[int] = None, 1603 col_offset: Optional[int] = None, 1604 parent: Optional[NodeNG] = None, 1605 *, 1606 end_lineno: Optional[int] = None, 1607 end_col_offset: Optional[int] = None, 1608 ) -> None: 1609 """ 1610 :param op: The operator. 1611 1612 :param lineno: The line that this node appears on in the source code. 1613 1614 :param col_offset: The column that this node appears on in the 1615 source code. 1616 1617 :param parent: The parent node in the syntax tree. 1618 1619 :param end_lineno: The last line this node appears on in the source code. 1620 1621 :param end_col_offset: The end column this node appears on in the 1622 source code. Note: This is after the last symbol. 1623 """ 1624 self.left: Optional[NodeNG] = None 1625 """What is being applied to the operator on the left side.""" 1626 1627 self.op: Optional[str] = op 1628 """The operator.""" 1629 1630 self.right: Optional[NodeNG] = None 1631 """What is being applied to the operator on the right side.""" 1632 1633 super().__init__( 1634 lineno=lineno, 1635 col_offset=col_offset, 1636 end_lineno=end_lineno, 1637 end_col_offset=end_col_offset, 1638 parent=parent, 1639 ) 1640 1641 def postinit( 1642 self, left: Optional[NodeNG] = None, right: Optional[NodeNG] = None 1643 ) -> None: 1644 """Do some setup after initialisation. 1645 1646 :param left: What is being applied to the operator on the left side. 1647 1648 :param right: What is being applied to the operator on the right side. 1649 """ 1650 self.left = left 1651 self.right = right 1652 1653 # This is set by inference.py 1654 def _infer_binop(self, context=None): 1655 raise NotImplementedError 1656 1657 def type_errors(self, context=None): 1658 """Get a list of type errors which can occur during inference. 1659 1660 Each TypeError is represented by a :class:`BadBinaryOperationMessage`, 1661 which holds the original exception. 1662 1663 :returns: The list of possible type errors. 1664 :rtype: list(BadBinaryOperationMessage) 1665 """ 1666 try: 1667 results = self._infer_binop(context=context) 1668 return [ 1669 result 1670 for result in results 1671 if isinstance(result, util.BadBinaryOperationMessage) 1672 ] 1673 except InferenceError: 1674 return [] 1675 1676 def get_children(self): 1677 yield self.left 1678 yield self.right 1679 1680 def op_precedence(self): 1681 return OP_PRECEDENCE[self.op] 1682 1683 def op_left_associative(self): 1684 # 2**3**4 == 2**(3**4) 1685 return self.op != "**" 1686 1687 1688class BoolOp(NodeNG): 1689 """Class representing an :class:`ast.BoolOp` node. 1690 1691 A :class:`BoolOp` is an application of a boolean operator. 1692 1693 >>> import astroid 1694 >>> node = astroid.extract_node('a and b') 1695 >>> node 1696 <BinOp l.1 at 0x7f23b2e71c50> 1697 """ 1698 1699 _astroid_fields = ("values",) 1700 _other_fields = ("op",) 1701 1702 @decorators.deprecate_default_argument_values(op="str") 1703 def __init__( 1704 self, 1705 op: Optional[str] = None, 1706 lineno: Optional[int] = None, 1707 col_offset: Optional[int] = None, 1708 parent: Optional[NodeNG] = None, 1709 *, 1710 end_lineno: Optional[int] = None, 1711 end_col_offset: Optional[int] = None, 1712 ) -> None: 1713 """ 1714 :param op: The operator. 1715 1716 :param lineno: The line that this node appears on in the source code. 1717 1718 :param col_offset: The column that this node appears on in the 1719 source code. 1720 1721 :param parent: The parent node in the syntax tree. 1722 1723 :param end_lineno: The last line this node appears on in the source code. 1724 1725 :param end_col_offset: The end column this node appears on in the 1726 source code. Note: This is after the last symbol. 1727 """ 1728 self.op: Optional[str] = op 1729 """The operator.""" 1730 1731 self.values: typing.List[NodeNG] = [] 1732 """The values being applied to the operator.""" 1733 1734 super().__init__( 1735 lineno=lineno, 1736 col_offset=col_offset, 1737 end_lineno=end_lineno, 1738 end_col_offset=end_col_offset, 1739 parent=parent, 1740 ) 1741 1742 def postinit(self, values: Optional[typing.List[NodeNG]] = None) -> None: 1743 """Do some setup after initialisation. 1744 1745 :param values: The values being applied to the operator. 1746 """ 1747 if values is not None: 1748 self.values = values 1749 1750 def get_children(self): 1751 yield from self.values 1752 1753 def op_precedence(self): 1754 return OP_PRECEDENCE[self.op] 1755 1756 1757class Break(mixins.NoChildrenMixin, Statement): 1758 """Class representing an :class:`ast.Break` node. 1759 1760 >>> import astroid 1761 >>> node = astroid.extract_node('break') 1762 >>> node 1763 <Break l.1 at 0x7f23b2e9e5c0> 1764 """ 1765 1766 1767class Call(NodeNG): 1768 """Class representing an :class:`ast.Call` node. 1769 1770 A :class:`Call` node is a call to a function, method, etc. 1771 1772 >>> import astroid 1773 >>> node = astroid.extract_node('function()') 1774 >>> node 1775 <Call l.1 at 0x7f23b2e71eb8> 1776 """ 1777 1778 _astroid_fields = ("func", "args", "keywords") 1779 1780 def __init__( 1781 self, 1782 lineno: Optional[int] = None, 1783 col_offset: Optional[int] = None, 1784 parent: Optional[NodeNG] = None, 1785 *, 1786 end_lineno: Optional[int] = None, 1787 end_col_offset: Optional[int] = None, 1788 ) -> None: 1789 """ 1790 :param lineno: The line that this node appears on in the source code. 1791 1792 :param col_offset: The column that this node appears on in the 1793 source code. 1794 1795 :param parent: The parent node in the syntax tree. 1796 1797 :param end_lineno: The last line this node appears on in the source code. 1798 1799 :param end_col_offset: The end column this node appears on in the 1800 source code. Note: This is after the last symbol. 1801 """ 1802 self.func: Optional[NodeNG] = None 1803 """What is being called.""" 1804 1805 self.args: typing.List[NodeNG] = [] 1806 """The positional arguments being given to the call.""" 1807 1808 self.keywords: typing.List["Keyword"] = [] 1809 """The keyword arguments being given to the call.""" 1810 1811 super().__init__( 1812 lineno=lineno, 1813 col_offset=col_offset, 1814 end_lineno=end_lineno, 1815 end_col_offset=end_col_offset, 1816 parent=parent, 1817 ) 1818 1819 def postinit( 1820 self, 1821 func: Optional[NodeNG] = None, 1822 args: Optional[typing.List[NodeNG]] = None, 1823 keywords: Optional[typing.List["Keyword"]] = None, 1824 ) -> None: 1825 """Do some setup after initialisation. 1826 1827 :param func: What is being called. 1828 1829 :param args: The positional arguments being given to the call. 1830 1831 :param keywords: The keyword arguments being given to the call. 1832 """ 1833 self.func = func 1834 if args is not None: 1835 self.args = args 1836 if keywords is not None: 1837 self.keywords = keywords 1838 1839 @property 1840 def starargs(self) -> typing.List["Starred"]: 1841 """The positional arguments that unpack something.""" 1842 return [arg for arg in self.args if isinstance(arg, Starred)] 1843 1844 @property 1845 def kwargs(self) -> typing.List["Keyword"]: 1846 """The keyword arguments that unpack something.""" 1847 return [keyword for keyword in self.keywords if keyword.arg is None] 1848 1849 def get_children(self): 1850 yield self.func 1851 1852 yield from self.args 1853 1854 yield from self.keywords 1855 1856 1857class Compare(NodeNG): 1858 """Class representing an :class:`ast.Compare` node. 1859 1860 A :class:`Compare` node indicates a comparison. 1861 1862 >>> import astroid 1863 >>> node = astroid.extract_node('a <= b <= c') 1864 >>> node 1865 <Compare l.1 at 0x7f23b2e9e6d8> 1866 >>> node.ops 1867 [('<=', <Name.b l.1 at 0x7f23b2e9e2b0>), ('<=', <Name.c l.1 at 0x7f23b2e9e390>)] 1868 """ 1869 1870 _astroid_fields = ("left", "ops") 1871 1872 def __init__( 1873 self, 1874 lineno: Optional[int] = None, 1875 col_offset: Optional[int] = None, 1876 parent: Optional[NodeNG] = None, 1877 *, 1878 end_lineno: Optional[int] = None, 1879 end_col_offset: Optional[int] = None, 1880 ) -> None: 1881 """ 1882 :param lineno: The line that this node appears on in the source code. 1883 1884 :param col_offset: The column that this node appears on in the 1885 source code. 1886 1887 :param parent: The parent node in the syntax tree. 1888 1889 :param end_lineno: The last line this node appears on in the source code. 1890 1891 :param end_col_offset: The end column this node appears on in the 1892 source code. Note: This is after the last symbol. 1893 """ 1894 self.left: Optional[NodeNG] = None 1895 """The value at the left being applied to a comparison operator.""" 1896 1897 self.ops: typing.List[typing.Tuple[str, NodeNG]] = [] 1898 """The remainder of the operators and their relevant right hand value.""" 1899 1900 super().__init__( 1901 lineno=lineno, 1902 col_offset=col_offset, 1903 end_lineno=end_lineno, 1904 end_col_offset=end_col_offset, 1905 parent=parent, 1906 ) 1907 1908 def postinit( 1909 self, 1910 left: Optional[NodeNG] = None, 1911 ops: Optional[typing.List[typing.Tuple[str, NodeNG]]] = None, 1912 ) -> None: 1913 """Do some setup after initialisation. 1914 1915 :param left: The value at the left being applied to a comparison 1916 operator. 1917 1918 :param ops: The remainder of the operators 1919 and their relevant right hand value. 1920 """ 1921 self.left = left 1922 if ops is not None: 1923 self.ops = ops 1924 1925 def get_children(self): 1926 """Get the child nodes below this node. 1927 1928 Overridden to handle the tuple fields and skip returning the operator 1929 strings. 1930 1931 :returns: The children. 1932 :rtype: iterable(NodeNG) 1933 """ 1934 yield self.left 1935 for _, comparator in self.ops: 1936 yield comparator # we don't want the 'op' 1937 1938 def last_child(self): 1939 """An optimized version of list(get_children())[-1] 1940 1941 :returns: The last child. 1942 :rtype: NodeNG 1943 """ 1944 # XXX maybe if self.ops: 1945 return self.ops[-1][1] 1946 # return self.left 1947 1948 1949class Comprehension(NodeNG): 1950 """Class representing an :class:`ast.comprehension` node. 1951 1952 A :class:`Comprehension` indicates the loop inside any type of 1953 comprehension including generator expressions. 1954 1955 >>> import astroid 1956 >>> node = astroid.extract_node('[x for x in some_values]') 1957 >>> list(node.get_children()) 1958 [<Name.x l.1 at 0x7f23b2e352b0>, <Comprehension l.1 at 0x7f23b2e35320>] 1959 >>> list(node.get_children())[1].as_string() 1960 'for x in some_values' 1961 """ 1962 1963 _astroid_fields = ("target", "iter", "ifs") 1964 _other_fields = ("is_async",) 1965 1966 optional_assign = True 1967 """Whether this node optionally assigns a variable.""" 1968 1969 lineno: None 1970 col_offset: None 1971 end_lineno: None 1972 end_col_offset: None 1973 1974 def __init__(self, parent: Optional[NodeNG] = None) -> None: 1975 """ 1976 :param parent: The parent node in the syntax tree. 1977 """ 1978 self.target: Optional[NodeNG] = None 1979 """What is assigned to by the comprehension.""" 1980 1981 self.iter: Optional[NodeNG] = None 1982 """What is iterated over by the comprehension.""" 1983 1984 self.ifs: typing.List[NodeNG] = [] 1985 """The contents of any if statements that filter the comprehension.""" 1986 1987 self.is_async: Optional[bool] = None 1988 """Whether this is an asynchronous comprehension or not.""" 1989 1990 super().__init__(parent=parent) 1991 1992 # pylint: disable=redefined-builtin; same name as builtin ast module. 1993 def postinit( 1994 self, 1995 target: Optional[NodeNG] = None, 1996 iter: Optional[NodeNG] = None, 1997 ifs: Optional[typing.List[NodeNG]] = None, 1998 is_async: Optional[bool] = None, 1999 ) -> None: 2000 """Do some setup after initialisation. 2001 2002 :param target: What is assigned to by the comprehension. 2003 2004 :param iter: What is iterated over by the comprehension. 2005 2006 :param ifs: The contents of any if statements that filter 2007 the comprehension. 2008 2009 :param is_async: Whether this is an asynchronous comprehension or not. 2010 """ 2011 self.target = target 2012 self.iter = iter 2013 if ifs is not None: 2014 self.ifs = ifs 2015 self.is_async = is_async 2016 2017 def assign_type(self): 2018 """The type of assignment that this node performs. 2019 2020 :returns: The assignment type. 2021 :rtype: NodeNG 2022 """ 2023 return self 2024 2025 def _get_filtered_stmts(self, lookup_node, node, stmts, mystmt): 2026 """method used in filter_stmts""" 2027 if self is mystmt: 2028 if isinstance(lookup_node, (Const, Name)): 2029 return [lookup_node], True 2030 2031 elif self.statement() is mystmt: 2032 # original node's statement is the assignment, only keeps 2033 # current node (gen exp, list comp) 2034 2035 return [node], True 2036 2037 return stmts, False 2038 2039 def get_children(self): 2040 yield self.target 2041 yield self.iter 2042 2043 yield from self.ifs 2044 2045 2046class Const(mixins.NoChildrenMixin, NodeNG, Instance): 2047 """Class representing any constant including num, str, bool, None, bytes. 2048 2049 >>> import astroid 2050 >>> node = astroid.extract_node('(5, "This is a string.", True, None, b"bytes")') 2051 >>> node 2052 <Tuple.tuple l.1 at 0x7f23b2e358d0> 2053 >>> list(node.get_children()) 2054 [<Const.int l.1 at 0x7f23b2e35940>, 2055 <Const.str l.1 at 0x7f23b2e35978>, 2056 <Const.bool l.1 at 0x7f23b2e359b0>, 2057 <Const.NoneType l.1 at 0x7f23b2e359e8>, 2058 <Const.bytes l.1 at 0x7f23b2e35a20>] 2059 """ 2060 2061 _other_fields = ("value", "kind") 2062 2063 def __init__( 2064 self, 2065 value: typing.Any, 2066 lineno: Optional[int] = None, 2067 col_offset: Optional[int] = None, 2068 parent: Optional[NodeNG] = None, 2069 kind: Optional[str] = None, 2070 *, 2071 end_lineno: Optional[int] = None, 2072 end_col_offset: Optional[int] = None, 2073 ) -> None: 2074 """ 2075 :param value: The value that the constant represents. 2076 2077 :param lineno: The line that this node appears on in the source code. 2078 2079 :param col_offset: The column that this node appears on in the 2080 source code. 2081 2082 :param parent: The parent node in the syntax tree. 2083 2084 :param kind: The string prefix. "u" for u-prefixed strings and ``None`` otherwise. Python 3.8+ only. 2085 2086 :param end_lineno: The last line this node appears on in the source code. 2087 2088 :param end_col_offset: The end column this node appears on in the 2089 source code. Note: This is after the last symbol. 2090 """ 2091 self.value: typing.Any = value 2092 """The value that the constant represents.""" 2093 2094 self.kind: Optional[str] = kind # can be None 2095 """"The string prefix. "u" for u-prefixed strings and ``None`` otherwise. Python 3.8+ only.""" 2096 2097 super().__init__( 2098 lineno=lineno, 2099 col_offset=col_offset, 2100 end_lineno=end_lineno, 2101 end_col_offset=end_col_offset, 2102 parent=parent, 2103 ) 2104 2105 def __getattr__(self, name): 2106 # This is needed because of Proxy's __getattr__ method. 2107 # Calling object.__new__ on this class without calling 2108 # __init__ would result in an infinite loop otherwise 2109 # since __getattr__ is called when an attribute doesn't 2110 # exist and self._proxied indirectly calls self.value 2111 # and Proxy __getattr__ calls self.value 2112 if name == "value": 2113 raise AttributeError 2114 return super().__getattr__(name) 2115 2116 def getitem(self, index, context=None): 2117 """Get an item from this node if subscriptable. 2118 2119 :param index: The node to use as a subscript index. 2120 :type index: Const or Slice 2121 2122 :raises AstroidTypeError: When the given index cannot be used as a 2123 subscript index, or if this node is not subscriptable. 2124 """ 2125 if isinstance(index, Const): 2126 index_value = index.value 2127 elif isinstance(index, Slice): 2128 index_value = _infer_slice(index, context=context) 2129 2130 else: 2131 raise AstroidTypeError( 2132 f"Could not use type {type(index)} as subscript index" 2133 ) 2134 2135 try: 2136 if isinstance(self.value, (str, bytes)): 2137 return Const(self.value[index_value]) 2138 except IndexError as exc: 2139 raise AstroidIndexError( 2140 message="Index {index!r} out of range", 2141 node=self, 2142 index=index, 2143 context=context, 2144 ) from exc 2145 except TypeError as exc: 2146 raise AstroidTypeError( 2147 message="Type error {error!r}", node=self, index=index, context=context 2148 ) from exc 2149 2150 raise AstroidTypeError(f"{self!r} (value={self.value})") 2151 2152 def has_dynamic_getattr(self): 2153 """Check if the node has a custom __getattr__ or __getattribute__. 2154 2155 :returns: True if the class has a custom 2156 __getattr__ or __getattribute__, False otherwise. 2157 For a :class:`Const` this is always ``False``. 2158 :rtype: bool 2159 """ 2160 return False 2161 2162 def itered(self): 2163 """An iterator over the elements this node contains. 2164 2165 :returns: The contents of this node. 2166 :rtype: iterable(Const) 2167 2168 :raises TypeError: If this node does not represent something that is iterable. 2169 """ 2170 if isinstance(self.value, str): 2171 return [const_factory(elem) for elem in self.value] 2172 raise TypeError(f"Cannot iterate over type {type(self.value)!r}") 2173 2174 def pytype(self): 2175 """Get the name of the type that this node represents. 2176 2177 :returns: The name of the type. 2178 :rtype: str 2179 """ 2180 return self._proxied.qname() 2181 2182 def bool_value(self, context=None): 2183 """Determine the boolean value of this node. 2184 2185 :returns: The boolean value of this node. 2186 :rtype: bool 2187 """ 2188 return bool(self.value) 2189 2190 2191class Continue(mixins.NoChildrenMixin, Statement): 2192 """Class representing an :class:`ast.Continue` node. 2193 2194 >>> import astroid 2195 >>> node = astroid.extract_node('continue') 2196 >>> node 2197 <Continue l.1 at 0x7f23b2e35588> 2198 """ 2199 2200 2201class Decorators(NodeNG): 2202 """A node representing a list of decorators. 2203 2204 A :class:`Decorators` is the decorators that are applied to 2205 a method or function. 2206 2207 >>> import astroid 2208 >>> node = astroid.extract_node(''' 2209 @property 2210 def my_property(self): 2211 return 3 2212 ''') 2213 >>> node 2214 <FunctionDef.my_property l.2 at 0x7f23b2e35d30> 2215 >>> list(node.get_children())[0] 2216 <Decorators l.1 at 0x7f23b2e35d68> 2217 """ 2218 2219 _astroid_fields = ("nodes",) 2220 2221 def __init__( 2222 self, 2223 lineno: Optional[int] = None, 2224 col_offset: Optional[int] = None, 2225 parent: Optional[NodeNG] = None, 2226 *, 2227 end_lineno: Optional[int] = None, 2228 end_col_offset: Optional[int] = None, 2229 ) -> None: 2230 """ 2231 :param lineno: The line that this node appears on in the source code. 2232 2233 :param col_offset: The column that this node appears on in the 2234 source code. 2235 2236 :param parent: The parent node in the syntax tree. 2237 2238 :param end_lineno: The last line this node appears on in the source code. 2239 2240 :param end_col_offset: The end column this node appears on in the 2241 source code. Note: This is after the last symbol. 2242 """ 2243 self.nodes: typing.List[NodeNG] 2244 """The decorators that this node contains. 2245 2246 :type: list(Name or Call) or None 2247 """ 2248 2249 super().__init__( 2250 lineno=lineno, 2251 col_offset=col_offset, 2252 end_lineno=end_lineno, 2253 end_col_offset=end_col_offset, 2254 parent=parent, 2255 ) 2256 2257 def postinit(self, nodes: typing.List[NodeNG]) -> None: 2258 """Do some setup after initialisation. 2259 2260 :param nodes: The decorators that this node contains. 2261 :type nodes: list(Name or Call) 2262 """ 2263 self.nodes = nodes 2264 2265 def scope(self) -> "LocalsDictNodeNG": 2266 """The first parent node defining a new scope. 2267 These can be Module, FunctionDef, ClassDef, Lambda, or GeneratorExp nodes. 2268 2269 :returns: The first parent scope node. 2270 """ 2271 # skip the function node to go directly to the upper level scope 2272 if not self.parent: 2273 raise ParentMissingError(target=self) 2274 if not self.parent.parent: 2275 raise ParentMissingError(target=self.parent) 2276 return self.parent.parent.scope() 2277 2278 def get_children(self): 2279 yield from self.nodes 2280 2281 2282class DelAttr(mixins.ParentAssignTypeMixin, NodeNG): 2283 """Variation of :class:`ast.Delete` representing deletion of an attribute. 2284 2285 >>> import astroid 2286 >>> node = astroid.extract_node('del self.attr') 2287 >>> node 2288 <Delete l.1 at 0x7f23b2e35f60> 2289 >>> list(node.get_children())[0] 2290 <DelAttr.attr l.1 at 0x7f23b2e411d0> 2291 """ 2292 2293 _astroid_fields = ("expr",) 2294 _other_fields = ("attrname",) 2295 2296 @decorators.deprecate_default_argument_values(attrname="str") 2297 def __init__( 2298 self, 2299 attrname: Optional[str] = None, 2300 lineno: Optional[int] = None, 2301 col_offset: Optional[int] = None, 2302 parent: Optional[NodeNG] = None, 2303 *, 2304 end_lineno: Optional[int] = None, 2305 end_col_offset: Optional[int] = None, 2306 ) -> None: 2307 """ 2308 :param attrname: The name of the attribute that is being deleted. 2309 2310 :param lineno: The line that this node appears on in the source code. 2311 2312 :param col_offset: The column that this node appears on in the 2313 source code. 2314 2315 :param parent: The parent node in the syntax tree. 2316 2317 :param end_lineno: The last line this node appears on in the source code. 2318 2319 :param end_col_offset: The end column this node appears on in the 2320 source code. Note: This is after the last symbol. 2321 """ 2322 self.expr: Optional[NodeNG] = None 2323 """The name that this node represents. 2324 2325 :type: Name or None 2326 """ 2327 2328 self.attrname: Optional[str] = attrname 2329 """The name of the attribute that is being deleted.""" 2330 2331 super().__init__( 2332 lineno=lineno, 2333 col_offset=col_offset, 2334 end_lineno=end_lineno, 2335 end_col_offset=end_col_offset, 2336 parent=parent, 2337 ) 2338 2339 def postinit(self, expr: Optional[NodeNG] = None) -> None: 2340 """Do some setup after initialisation. 2341 2342 :param expr: The name that this node represents. 2343 :type expr: Name or None 2344 """ 2345 self.expr = expr 2346 2347 def get_children(self): 2348 yield self.expr 2349 2350 2351class Delete(mixins.AssignTypeMixin, Statement): 2352 """Class representing an :class:`ast.Delete` node. 2353 2354 A :class:`Delete` is a ``del`` statement this is deleting something. 2355 2356 >>> import astroid 2357 >>> node = astroid.extract_node('del self.attr') 2358 >>> node 2359 <Delete l.1 at 0x7f23b2e35f60> 2360 """ 2361 2362 _astroid_fields = ("targets",) 2363 2364 def __init__( 2365 self, 2366 lineno: Optional[int] = None, 2367 col_offset: Optional[int] = None, 2368 parent: Optional[NodeNG] = None, 2369 *, 2370 end_lineno: Optional[int] = None, 2371 end_col_offset: Optional[int] = None, 2372 ) -> None: 2373 """ 2374 :param lineno: The line that this node appears on in the source code. 2375 2376 :param col_offset: The column that this node appears on in the 2377 source code. 2378 2379 :param parent: The parent node in the syntax tree. 2380 2381 :param end_lineno: The last line this node appears on in the source code. 2382 2383 :param end_col_offset: The end column this node appears on in the 2384 source code. Note: This is after the last symbol. 2385 """ 2386 self.targets: typing.List[NodeNG] = [] 2387 """What is being deleted.""" 2388 2389 super().__init__( 2390 lineno=lineno, 2391 col_offset=col_offset, 2392 end_lineno=end_lineno, 2393 end_col_offset=end_col_offset, 2394 parent=parent, 2395 ) 2396 2397 def postinit(self, targets: Optional[typing.List[NodeNG]] = None) -> None: 2398 """Do some setup after initialisation. 2399 2400 :param targets: What is being deleted. 2401 """ 2402 if targets is not None: 2403 self.targets = targets 2404 2405 def get_children(self): 2406 yield from self.targets 2407 2408 2409class Dict(NodeNG, Instance): 2410 """Class representing an :class:`ast.Dict` node. 2411 2412 A :class:`Dict` is a dictionary that is created with ``{}`` syntax. 2413 2414 >>> import astroid 2415 >>> node = astroid.extract_node('{1: "1"}') 2416 >>> node 2417 <Dict.dict l.1 at 0x7f23b2e35cc0> 2418 """ 2419 2420 _astroid_fields = ("items",) 2421 2422 def __init__( 2423 self, 2424 lineno: Optional[int] = None, 2425 col_offset: Optional[int] = None, 2426 parent: Optional[NodeNG] = None, 2427 *, 2428 end_lineno: Optional[int] = None, 2429 end_col_offset: Optional[int] = None, 2430 ) -> None: 2431 """ 2432 :param lineno: The line that this node appears on in the source code. 2433 2434 :param col_offset: The column that this node appears on in the 2435 source code. 2436 2437 :param parent: The parent node in the syntax tree. 2438 2439 :param end_lineno: The last line this node appears on in the source code. 2440 2441 :param end_col_offset: The end column this node appears on in the 2442 source code. Note: This is after the last symbol. 2443 """ 2444 self.items: typing.List[typing.Tuple[NodeNG, NodeNG]] = [] 2445 """The key-value pairs contained in the dictionary.""" 2446 2447 super().__init__( 2448 lineno=lineno, 2449 col_offset=col_offset, 2450 end_lineno=end_lineno, 2451 end_col_offset=end_col_offset, 2452 parent=parent, 2453 ) 2454 2455 def postinit(self, items: typing.List[typing.Tuple[NodeNG, NodeNG]]) -> None: 2456 """Do some setup after initialisation. 2457 2458 :param items: The key-value pairs contained in the dictionary. 2459 """ 2460 self.items = items 2461 2462 @classmethod 2463 def from_elements(cls, items=None): 2464 """Create a :class:`Dict` of constants from a live dictionary. 2465 2466 :param items: The items to store in the node. 2467 :type items: dict 2468 2469 :returns: The created dictionary node. 2470 :rtype: Dict 2471 """ 2472 node = cls() 2473 if items is None: 2474 node.items = [] 2475 else: 2476 node.items = [ 2477 (const_factory(k), const_factory(v) if _is_const(v) else v) 2478 for k, v in items.items() 2479 # The keys need to be constants 2480 if _is_const(k) 2481 ] 2482 return node 2483 2484 def pytype(self): 2485 """Get the name of the type that this node represents. 2486 2487 :returns: The name of the type. 2488 :rtype: str 2489 """ 2490 return "builtins.dict" 2491 2492 def get_children(self): 2493 """Get the key and value nodes below this node. 2494 2495 Children are returned in the order that they are defined in the source 2496 code, key first then the value. 2497 2498 :returns: The children. 2499 :rtype: iterable(NodeNG) 2500 """ 2501 for key, value in self.items: 2502 yield key 2503 yield value 2504 2505 def last_child(self): 2506 """An optimized version of list(get_children())[-1] 2507 2508 :returns: The last child, or None if no children exist. 2509 :rtype: NodeNG or None 2510 """ 2511 if self.items: 2512 return self.items[-1][1] 2513 return None 2514 2515 def itered(self): 2516 """An iterator over the keys this node contains. 2517 2518 :returns: The keys of this node. 2519 :rtype: iterable(NodeNG) 2520 """ 2521 return [key for (key, _) in self.items] 2522 2523 def getitem(self, index, context=None): 2524 """Get an item from this node. 2525 2526 :param index: The node to use as a subscript index. 2527 :type index: Const or Slice 2528 2529 :raises AstroidTypeError: When the given index cannot be used as a 2530 subscript index, or if this node is not subscriptable. 2531 :raises AstroidIndexError: If the given index does not exist in the 2532 dictionary. 2533 """ 2534 for key, value in self.items: 2535 # TODO(cpopa): no support for overriding yet, {1:2, **{1: 3}}. 2536 if isinstance(key, DictUnpack): 2537 try: 2538 return value.getitem(index, context) 2539 except (AstroidTypeError, AstroidIndexError): 2540 continue 2541 for inferredkey in key.infer(context): 2542 if inferredkey is util.Uninferable: 2543 continue 2544 if isinstance(inferredkey, Const) and isinstance(index, Const): 2545 if inferredkey.value == index.value: 2546 return value 2547 2548 raise AstroidIndexError(index) 2549 2550 def bool_value(self, context=None): 2551 """Determine the boolean value of this node. 2552 2553 :returns: The boolean value of this node. 2554 :rtype: bool 2555 """ 2556 return bool(self.items) 2557 2558 2559class Expr(Statement): 2560 """Class representing an :class:`ast.Expr` node. 2561 2562 An :class:`Expr` is any expression that does not have its value used or 2563 stored. 2564 2565 >>> import astroid 2566 >>> node = astroid.extract_node('method()') 2567 >>> node 2568 <Call l.1 at 0x7f23b2e352b0> 2569 >>> node.parent 2570 <Expr l.1 at 0x7f23b2e35278> 2571 """ 2572 2573 _astroid_fields = ("value",) 2574 2575 def __init__( 2576 self, 2577 lineno: Optional[int] = None, 2578 col_offset: Optional[int] = None, 2579 parent: Optional[NodeNG] = None, 2580 *, 2581 end_lineno: Optional[int] = None, 2582 end_col_offset: Optional[int] = None, 2583 ) -> None: 2584 """ 2585 :param lineno: The line that this node appears on in the source code. 2586 2587 :param col_offset: The column that this node appears on in the 2588 source code. 2589 2590 :param parent: The parent node in the syntax tree. 2591 2592 :param end_lineno: The last line this node appears on in the source code. 2593 2594 :param end_col_offset: The end column this node appears on in the 2595 source code. Note: This is after the last symbol. 2596 """ 2597 self.value: Optional[NodeNG] = None 2598 """What the expression does.""" 2599 2600 super().__init__( 2601 lineno=lineno, 2602 col_offset=col_offset, 2603 end_lineno=end_lineno, 2604 end_col_offset=end_col_offset, 2605 parent=parent, 2606 ) 2607 2608 def postinit(self, value: Optional[NodeNG] = None) -> None: 2609 """Do some setup after initialisation. 2610 2611 :param value: What the expression does. 2612 """ 2613 self.value = value 2614 2615 def get_children(self): 2616 yield self.value 2617 2618 def _get_yield_nodes_skip_lambdas(self): 2619 if not self.value.is_lambda: 2620 yield from self.value._get_yield_nodes_skip_lambdas() 2621 2622 2623class Ellipsis(mixins.NoChildrenMixin, NodeNG): # pylint: disable=redefined-builtin 2624 """Class representing an :class:`ast.Ellipsis` node. 2625 2626 An :class:`Ellipsis` is the ``...`` syntax. 2627 2628 Deprecated since v2.6.0 - Use :class:`Const` instead. 2629 Will be removed with the release v2.7.0 2630 """ 2631 2632 2633class EmptyNode(mixins.NoChildrenMixin, NodeNG): 2634 """Holds an arbitrary object in the :attr:`LocalsDictNodeNG.locals`.""" 2635 2636 object = None 2637 2638 2639class ExceptHandler(mixins.MultiLineBlockMixin, mixins.AssignTypeMixin, Statement): 2640 """Class representing an :class:`ast.ExceptHandler`. node. 2641 2642 An :class:`ExceptHandler` is an ``except`` block on a try-except. 2643 2644 >>> import astroid 2645 >>> node = astroid.extract_node(''' 2646 try: 2647 do_something() 2648 except Exception as error: 2649 print("Error!") 2650 ''') 2651 >>> node 2652 <TryExcept l.2 at 0x7f23b2e9d908> 2653 >>> node.handlers 2654 [<ExceptHandler l.4 at 0x7f23b2e9e860>] 2655 """ 2656 2657 _astroid_fields = ("type", "name", "body") 2658 _multi_line_block_fields = ("body",) 2659 2660 def __init__( 2661 self, 2662 lineno: Optional[int] = None, 2663 col_offset: Optional[int] = None, 2664 parent: Optional[NodeNG] = None, 2665 *, 2666 end_lineno: Optional[int] = None, 2667 end_col_offset: Optional[int] = None, 2668 ) -> None: 2669 """ 2670 :param lineno: The line that this node appears on in the source code. 2671 2672 :param col_offset: The column that this node appears on in the 2673 source code. 2674 2675 :param parent: The parent node in the syntax tree. 2676 2677 :param end_lineno: The last line this node appears on in the source code. 2678 2679 :param end_col_offset: The end column this node appears on in the 2680 source code. Note: This is after the last symbol. 2681 """ 2682 self.type: Optional[NodeNG] = None # can be None 2683 """The types that the block handles. 2684 2685 :type: Tuple or NodeNG or None 2686 """ 2687 2688 self.name: Optional[AssignName] = None # can be None 2689 """The name that the caught exception is assigned to.""" 2690 2691 self.body: typing.List[NodeNG] = [] 2692 """The contents of the block.""" 2693 2694 super().__init__( 2695 lineno=lineno, 2696 col_offset=col_offset, 2697 end_lineno=end_lineno, 2698 end_col_offset=end_col_offset, 2699 parent=parent, 2700 ) 2701 2702 def get_children(self): 2703 if self.type is not None: 2704 yield self.type 2705 2706 if self.name is not None: 2707 yield self.name 2708 2709 yield from self.body 2710 2711 # pylint: disable=redefined-builtin; had to use the same name as builtin ast module. 2712 def postinit( 2713 self, 2714 type: Optional[NodeNG] = None, 2715 name: Optional[AssignName] = None, 2716 body: Optional[typing.List[NodeNG]] = None, 2717 ) -> None: 2718 """Do some setup after initialisation. 2719 2720 :param type: The types that the block handles. 2721 :type type: Tuple or NodeNG or None 2722 2723 :param name: The name that the caught exception is assigned to. 2724 2725 :param body:The contents of the block. 2726 """ 2727 self.type = type 2728 self.name = name 2729 if body is not None: 2730 self.body = body 2731 2732 @decorators.cachedproperty 2733 def blockstart_tolineno(self): 2734 """The line on which the beginning of this block ends. 2735 2736 :type: int 2737 """ 2738 if self.name: 2739 return self.name.tolineno 2740 if self.type: 2741 return self.type.tolineno 2742 return self.lineno 2743 2744 def catch(self, exceptions: Optional[typing.List[str]]) -> bool: 2745 """Check if this node handles any of the given 2746 2747 :param exceptions: The names of the exceptions to check for. 2748 """ 2749 if self.type is None or exceptions is None: 2750 return True 2751 for node in self.type._get_name_nodes(): 2752 if node.name in exceptions: 2753 return True 2754 return False 2755 2756 2757class ExtSlice(NodeNG): 2758 """Class representing an :class:`ast.ExtSlice` node. 2759 2760 An :class:`ExtSlice` is a complex slice expression. 2761 2762 Deprecated since v2.6.0 - Now part of the :class:`Subscript` node. 2763 Will be removed with the release of v2.7.0 2764 """ 2765 2766 2767class For( 2768 mixins.MultiLineBlockMixin, 2769 mixins.BlockRangeMixIn, 2770 mixins.AssignTypeMixin, 2771 Statement, 2772): 2773 """Class representing an :class:`ast.For` node. 2774 2775 >>> import astroid 2776 >>> node = astroid.extract_node('for thing in things: print(thing)') 2777 >>> node 2778 <For l.1 at 0x7f23b2e8cf28> 2779 """ 2780 2781 _astroid_fields = ("target", "iter", "body", "orelse") 2782 _other_other_fields = ("type_annotation",) 2783 _multi_line_block_fields = ("body", "orelse") 2784 2785 optional_assign = True 2786 """Whether this node optionally assigns a variable. 2787 2788 This is always ``True`` for :class:`For` nodes. 2789 """ 2790 2791 def __init__( 2792 self, 2793 lineno: Optional[int] = None, 2794 col_offset: Optional[int] = None, 2795 parent: Optional[NodeNG] = None, 2796 *, 2797 end_lineno: Optional[int] = None, 2798 end_col_offset: Optional[int] = None, 2799 ) -> None: 2800 """ 2801 :param lineno: The line that this node appears on in the source code. 2802 2803 :param col_offset: The column that this node appears on in the 2804 source code. 2805 2806 :param parent: The parent node in the syntax tree. 2807 2808 :param end_lineno: The last line this node appears on in the source code. 2809 2810 :param end_col_offset: The end column this node appears on in the 2811 source code. Note: This is after the last symbol. 2812 """ 2813 self.target: Optional[NodeNG] = None 2814 """What the loop assigns to.""" 2815 2816 self.iter: Optional[NodeNG] = None 2817 """What the loop iterates over.""" 2818 2819 self.body: typing.List[NodeNG] = [] 2820 """The contents of the body of the loop.""" 2821 2822 self.orelse: typing.List[NodeNG] = [] 2823 """The contents of the ``else`` block of the loop.""" 2824 2825 self.type_annotation: Optional[NodeNG] = None # can be None 2826 """If present, this will contain the type annotation passed by a type comment""" 2827 2828 super().__init__( 2829 lineno=lineno, 2830 col_offset=col_offset, 2831 end_lineno=end_lineno, 2832 end_col_offset=end_col_offset, 2833 parent=parent, 2834 ) 2835 2836 # pylint: disable=redefined-builtin; had to use the same name as builtin ast module. 2837 def postinit( 2838 self, 2839 target: Optional[NodeNG] = None, 2840 iter: Optional[NodeNG] = None, 2841 body: Optional[typing.List[NodeNG]] = None, 2842 orelse: Optional[typing.List[NodeNG]] = None, 2843 type_annotation: Optional[NodeNG] = None, 2844 ) -> None: 2845 """Do some setup after initialisation. 2846 2847 :param target: What the loop assigns to. 2848 2849 :param iter: What the loop iterates over. 2850 2851 :param body: The contents of the body of the loop. 2852 2853 :param orelse: The contents of the ``else`` block of the loop. 2854 """ 2855 self.target = target 2856 self.iter = iter 2857 if body is not None: 2858 self.body = body 2859 if orelse is not None: 2860 self.orelse = orelse 2861 self.type_annotation = type_annotation 2862 2863 @decorators.cachedproperty 2864 def blockstart_tolineno(self): 2865 """The line on which the beginning of this block ends. 2866 2867 :type: int 2868 """ 2869 return self.iter.tolineno 2870 2871 def get_children(self): 2872 yield self.target 2873 yield self.iter 2874 2875 yield from self.body 2876 yield from self.orelse 2877 2878 2879class AsyncFor(For): 2880 """Class representing an :class:`ast.AsyncFor` node. 2881 2882 An :class:`AsyncFor` is an asynchronous :class:`For` built with 2883 the ``async`` keyword. 2884 2885 >>> import astroid 2886 >>> node = astroid.extract_node(''' 2887 async def func(things): 2888 async for thing in things: 2889 print(thing) 2890 ''') 2891 >>> node 2892 <AsyncFunctionDef.func l.2 at 0x7f23b2e416d8> 2893 >>> node.body[0] 2894 <AsyncFor l.3 at 0x7f23b2e417b8> 2895 """ 2896 2897 2898class Await(NodeNG): 2899 """Class representing an :class:`ast.Await` node. 2900 2901 An :class:`Await` is the ``await`` keyword. 2902 2903 >>> import astroid 2904 >>> node = astroid.extract_node(''' 2905 async def func(things): 2906 await other_func() 2907 ''') 2908 >>> node 2909 <AsyncFunctionDef.func l.2 at 0x7f23b2e41748> 2910 >>> node.body[0] 2911 <Expr l.3 at 0x7f23b2e419e8> 2912 >>> list(node.body[0].get_children())[0] 2913 <Await l.3 at 0x7f23b2e41a20> 2914 """ 2915 2916 _astroid_fields = ("value",) 2917 2918 def __init__( 2919 self, 2920 lineno: Optional[int] = None, 2921 col_offset: Optional[int] = None, 2922 parent: Optional[NodeNG] = None, 2923 *, 2924 end_lineno: Optional[int] = None, 2925 end_col_offset: Optional[int] = None, 2926 ) -> None: 2927 """ 2928 :param lineno: The line that this node appears on in the source code. 2929 2930 :param col_offset: The column that this node appears on in the 2931 source code. 2932 2933 :param parent: The parent node in the syntax tree. 2934 2935 :param end_lineno: The last line this node appears on in the source code. 2936 2937 :param end_col_offset: The end column this node appears on in the 2938 source code. Note: This is after the last symbol. 2939 """ 2940 self.value: Optional[NodeNG] = None 2941 """What to wait for.""" 2942 2943 super().__init__( 2944 lineno=lineno, 2945 col_offset=col_offset, 2946 end_lineno=end_lineno, 2947 end_col_offset=end_col_offset, 2948 parent=parent, 2949 ) 2950 2951 def postinit(self, value: Optional[NodeNG] = None) -> None: 2952 """Do some setup after initialisation. 2953 2954 :param value: What to wait for. 2955 """ 2956 self.value = value 2957 2958 def get_children(self): 2959 yield self.value 2960 2961 2962class ImportFrom(mixins.NoChildrenMixin, mixins.ImportFromMixin, Statement): 2963 """Class representing an :class:`ast.ImportFrom` node. 2964 2965 >>> import astroid 2966 >>> node = astroid.extract_node('from my_package import my_module') 2967 >>> node 2968 <ImportFrom l.1 at 0x7f23b2e415c0> 2969 """ 2970 2971 _other_fields = ("modname", "names", "level") 2972 2973 def __init__( 2974 self, 2975 fromname: Optional[str], 2976 names: typing.List[typing.Tuple[str, Optional[str]]], 2977 level: Optional[int] = 0, 2978 lineno: Optional[int] = None, 2979 col_offset: Optional[int] = None, 2980 parent: Optional[NodeNG] = None, 2981 *, 2982 end_lineno: Optional[int] = None, 2983 end_col_offset: Optional[int] = None, 2984 ) -> None: 2985 """ 2986 :param fromname: The module that is being imported from. 2987 2988 :param names: What is being imported from the module. 2989 2990 :param level: The level of relative import. 2991 2992 :param lineno: The line that this node appears on in the source code. 2993 2994 :param col_offset: The column that this node appears on in the 2995 source code. 2996 2997 :param parent: The parent node in the syntax tree. 2998 2999 :param end_lineno: The last line this node appears on in the source code. 3000 3001 :param end_col_offset: The end column this node appears on in the 3002 source code. Note: This is after the last symbol. 3003 """ 3004 self.modname: Optional[str] = fromname # can be None 3005 """The module that is being imported from. 3006 3007 This is ``None`` for relative imports. 3008 """ 3009 3010 self.names: typing.List[typing.Tuple[str, Optional[str]]] = names 3011 """What is being imported from the module. 3012 3013 Each entry is a :class:`tuple` of the name being imported, 3014 and the alias that the name is assigned to (if any). 3015 """ 3016 3017 # TODO When is 'level' None? 3018 self.level: Optional[int] = level # can be None 3019 """The level of relative import. 3020 3021 Essentially this is the number of dots in the import. 3022 This is always 0 for absolute imports. 3023 """ 3024 3025 super().__init__( 3026 lineno=lineno, 3027 col_offset=col_offset, 3028 end_lineno=end_lineno, 3029 end_col_offset=end_col_offset, 3030 parent=parent, 3031 ) 3032 3033 3034class Attribute(NodeNG): 3035 """Class representing an :class:`ast.Attribute` node.""" 3036 3037 _astroid_fields = ("expr",) 3038 _other_fields = ("attrname",) 3039 3040 @decorators.deprecate_default_argument_values(attrname="str") 3041 def __init__( 3042 self, 3043 attrname: Optional[str] = None, 3044 lineno: Optional[int] = None, 3045 col_offset: Optional[int] = None, 3046 parent: Optional[NodeNG] = None, 3047 *, 3048 end_lineno: Optional[int] = None, 3049 end_col_offset: Optional[int] = None, 3050 ) -> None: 3051 """ 3052 :param attrname: The name of the attribute. 3053 3054 :param lineno: The line that this node appears on in the source code. 3055 3056 :param col_offset: The column that this node appears on in the 3057 source code. 3058 3059 :param parent: The parent node in the syntax tree. 3060 3061 :param end_lineno: The last line this node appears on in the source code. 3062 3063 :param end_col_offset: The end column this node appears on in the 3064 source code. Note: This is after the last symbol. 3065 """ 3066 self.expr: Optional[NodeNG] = None 3067 """The name that this node represents. 3068 3069 :type: Name or None 3070 """ 3071 3072 self.attrname: Optional[str] = attrname 3073 """The name of the attribute.""" 3074 3075 super().__init__( 3076 lineno=lineno, 3077 col_offset=col_offset, 3078 end_lineno=end_lineno, 3079 end_col_offset=end_col_offset, 3080 parent=parent, 3081 ) 3082 3083 def postinit(self, expr: Optional[NodeNG] = None) -> None: 3084 """Do some setup after initialisation. 3085 3086 :param expr: The name that this node represents. 3087 :type expr: Name or None 3088 """ 3089 self.expr = expr 3090 3091 def get_children(self): 3092 yield self.expr 3093 3094 3095class Global(mixins.NoChildrenMixin, Statement): 3096 """Class representing an :class:`ast.Global` node. 3097 3098 >>> import astroid 3099 >>> node = astroid.extract_node('global a_global') 3100 >>> node 3101 <Global l.1 at 0x7f23b2e9de10> 3102 """ 3103 3104 _other_fields = ("names",) 3105 3106 def __init__( 3107 self, 3108 names: typing.List[str], 3109 lineno: Optional[int] = None, 3110 col_offset: Optional[int] = None, 3111 parent: Optional[NodeNG] = None, 3112 *, 3113 end_lineno: Optional[int] = None, 3114 end_col_offset: Optional[int] = None, 3115 ) -> None: 3116 """ 3117 :param names: The names being declared as global. 3118 3119 :param lineno: The line that this node appears on in the source code. 3120 3121 :param col_offset: The column that this node appears on in the 3122 source code. 3123 3124 :param parent: The parent node in the syntax tree. 3125 3126 :param end_lineno: The last line this node appears on in the source code. 3127 3128 :param end_col_offset: The end column this node appears on in the 3129 source code. Note: This is after the last symbol. 3130 """ 3131 self.names: typing.List[str] = names 3132 """The names being declared as global.""" 3133 3134 super().__init__( 3135 lineno=lineno, 3136 col_offset=col_offset, 3137 end_lineno=end_lineno, 3138 end_col_offset=end_col_offset, 3139 parent=parent, 3140 ) 3141 3142 def _infer_name(self, frame, name): 3143 return name 3144 3145 3146class If(mixins.MultiLineBlockMixin, mixins.BlockRangeMixIn, Statement): 3147 """Class representing an :class:`ast.If` node. 3148 3149 >>> import astroid 3150 >>> node = astroid.extract_node('if condition: print(True)') 3151 >>> node 3152 <If l.1 at 0x7f23b2e9dd30> 3153 """ 3154 3155 _astroid_fields = ("test", "body", "orelse") 3156 _multi_line_block_fields = ("body", "orelse") 3157 3158 def __init__( 3159 self, 3160 lineno: Optional[int] = None, 3161 col_offset: Optional[int] = None, 3162 parent: Optional[NodeNG] = None, 3163 *, 3164 end_lineno: Optional[int] = None, 3165 end_col_offset: Optional[int] = None, 3166 ) -> None: 3167 """ 3168 :param lineno: The line that this node appears on in the source code. 3169 3170 :param col_offset: The column that this node appears on in the 3171 source code. 3172 3173 :param parent: The parent node in the syntax tree. 3174 3175 :param end_lineno: The last line this node appears on in the source code. 3176 3177 :param end_col_offset: The end column this node appears on in the 3178 source code. Note: This is after the last symbol. 3179 """ 3180 self.test: Optional[NodeNG] = None 3181 """The condition that the statement tests.""" 3182 3183 self.body: typing.List[NodeNG] = [] 3184 """The contents of the block.""" 3185 3186 self.orelse: typing.List[NodeNG] = [] 3187 """The contents of the ``else`` block.""" 3188 3189 self.is_orelse: bool = False 3190 """Whether the if-statement is the orelse-block of another if statement.""" 3191 3192 super().__init__( 3193 lineno=lineno, 3194 col_offset=col_offset, 3195 end_lineno=end_lineno, 3196 end_col_offset=end_col_offset, 3197 parent=parent, 3198 ) 3199 3200 def postinit( 3201 self, 3202 test: Optional[NodeNG] = None, 3203 body: Optional[typing.List[NodeNG]] = None, 3204 orelse: Optional[typing.List[NodeNG]] = None, 3205 ) -> None: 3206 """Do some setup after initialisation. 3207 3208 :param test: The condition that the statement tests. 3209 3210 :param body: The contents of the block. 3211 3212 :param orelse: The contents of the ``else`` block. 3213 """ 3214 self.test = test 3215 if body is not None: 3216 self.body = body 3217 if orelse is not None: 3218 self.orelse = orelse 3219 if isinstance(self.parent, If) and self in self.parent.orelse: 3220 self.is_orelse = True 3221 3222 @decorators.cachedproperty 3223 def blockstart_tolineno(self): 3224 """The line on which the beginning of this block ends. 3225 3226 :type: int 3227 """ 3228 return self.test.tolineno 3229 3230 def block_range(self, lineno): 3231 """Get a range from the given line number to where this node ends. 3232 3233 :param lineno: The line number to start the range at. 3234 :type lineno: int 3235 3236 :returns: The range of line numbers that this node belongs to, 3237 starting at the given line number. 3238 :rtype: tuple(int, int) 3239 """ 3240 if lineno == self.body[0].fromlineno: 3241 return lineno, lineno 3242 if lineno <= self.body[-1].tolineno: 3243 return lineno, self.body[-1].tolineno 3244 return self._elsed_block_range(lineno, self.orelse, self.body[0].fromlineno - 1) 3245 3246 def get_children(self): 3247 yield self.test 3248 3249 yield from self.body 3250 yield from self.orelse 3251 3252 def has_elif_block(self): 3253 return len(self.orelse) == 1 and isinstance(self.orelse[0], If) 3254 3255 def _get_yield_nodes_skip_lambdas(self): 3256 """An If node can contain a Yield node in the test""" 3257 yield from self.test._get_yield_nodes_skip_lambdas() 3258 yield from super()._get_yield_nodes_skip_lambdas() 3259 3260 def is_sys_guard(self) -> bool: 3261 """Return True if IF stmt is a sys.version_info guard. 3262 3263 >>> import astroid 3264 >>> node = astroid.extract_node(''' 3265 import sys 3266 if sys.version_info > (3, 8): 3267 from typing import Literal 3268 else: 3269 from typing_extensions import Literal 3270 ''') 3271 >>> node.is_sys_guard() 3272 True 3273 """ 3274 warnings.warn( 3275 "The 'is_sys_guard' function is deprecated and will be removed in astroid 3.0.0 " 3276 "It has been moved to pylint and can be imported from 'pylint.checkers.utils' " 3277 "starting with pylint 2.12", 3278 DeprecationWarning, 3279 ) 3280 if isinstance(self.test, Compare): 3281 value = self.test.left 3282 if isinstance(value, Subscript): 3283 value = value.value 3284 if isinstance(value, Attribute) and value.as_string() == "sys.version_info": 3285 return True 3286 3287 return False 3288 3289 def is_typing_guard(self) -> bool: 3290 """Return True if IF stmt is a typing guard. 3291 3292 >>> import astroid 3293 >>> node = astroid.extract_node(''' 3294 from typing import TYPE_CHECKING 3295 if TYPE_CHECKING: 3296 from xyz import a 3297 ''') 3298 >>> node.is_typing_guard() 3299 True 3300 """ 3301 warnings.warn( 3302 "The 'is_typing_guard' function is deprecated and will be removed in astroid 3.0.0 " 3303 "It has been moved to pylint and can be imported from 'pylint.checkers.utils' " 3304 "starting with pylint 2.12", 3305 DeprecationWarning, 3306 ) 3307 return isinstance( 3308 self.test, (Name, Attribute) 3309 ) and self.test.as_string().endswith("TYPE_CHECKING") 3310 3311 3312class IfExp(NodeNG): 3313 """Class representing an :class:`ast.IfExp` node. 3314 >>> import astroid 3315 >>> node = astroid.extract_node('value if condition else other') 3316 >>> node 3317 <IfExp l.1 at 0x7f23b2e9dbe0> 3318 """ 3319 3320 _astroid_fields = ("test", "body", "orelse") 3321 3322 def __init__( 3323 self, 3324 lineno: Optional[int] = None, 3325 col_offset: Optional[int] = None, 3326 parent: Optional[NodeNG] = None, 3327 *, 3328 end_lineno: Optional[int] = None, 3329 end_col_offset: Optional[int] = None, 3330 ) -> None: 3331 """ 3332 :param lineno: The line that this node appears on in the source code. 3333 3334 :param col_offset: The column that this node appears on in the 3335 source code. 3336 3337 :param parent: The parent node in the syntax tree. 3338 3339 :param end_lineno: The last line this node appears on in the source code. 3340 3341 :param end_col_offset: The end column this node appears on in the 3342 source code. Note: This is after the last symbol. 3343 """ 3344 self.test: Optional[NodeNG] = None 3345 """The condition that the statement tests.""" 3346 3347 self.body: Optional[NodeNG] = None 3348 """The contents of the block.""" 3349 3350 self.orelse: Optional[NodeNG] = None 3351 """The contents of the ``else`` block.""" 3352 3353 super().__init__( 3354 lineno=lineno, 3355 col_offset=col_offset, 3356 end_lineno=end_lineno, 3357 end_col_offset=end_col_offset, 3358 parent=parent, 3359 ) 3360 3361 def postinit( 3362 self, 3363 test: Optional[NodeNG] = None, 3364 body: Optional[NodeNG] = None, 3365 orelse: Optional[NodeNG] = None, 3366 ) -> None: 3367 """Do some setup after initialisation. 3368 3369 :param test: The condition that the statement tests. 3370 3371 :param body: The contents of the block. 3372 3373 :param orelse: The contents of the ``else`` block. 3374 """ 3375 self.test = test 3376 self.body = body 3377 self.orelse = orelse 3378 3379 def get_children(self): 3380 yield self.test 3381 yield self.body 3382 yield self.orelse 3383 3384 def op_left_associative(self): 3385 # `1 if True else 2 if False else 3` is parsed as 3386 # `1 if True else (2 if False else 3)` 3387 return False 3388 3389 3390class Import(mixins.NoChildrenMixin, mixins.ImportFromMixin, Statement): 3391 """Class representing an :class:`ast.Import` node. 3392 >>> import astroid 3393 >>> node = astroid.extract_node('import astroid') 3394 >>> node 3395 <Import l.1 at 0x7f23b2e4e5c0> 3396 """ 3397 3398 _other_fields = ("names",) 3399 3400 @decorators.deprecate_default_argument_values(names="list[tuple[str, str | None]]") 3401 def __init__( 3402 self, 3403 names: Optional[typing.List[typing.Tuple[str, Optional[str]]]] = None, 3404 lineno: Optional[int] = None, 3405 col_offset: Optional[int] = None, 3406 parent: Optional[NodeNG] = None, 3407 *, 3408 end_lineno: Optional[int] = None, 3409 end_col_offset: Optional[int] = None, 3410 ) -> None: 3411 """ 3412 :param names: The names being imported. 3413 3414 :param lineno: The line that this node appears on in the source code. 3415 3416 :param col_offset: The column that this node appears on in the 3417 source code. 3418 3419 :param parent: The parent node in the syntax tree. 3420 3421 :param end_lineno: The last line this node appears on in the source code. 3422 3423 :param end_col_offset: The end column this node appears on in the 3424 source code. Note: This is after the last symbol. 3425 """ 3426 self.names: typing.List[typing.Tuple[str, Optional[str]]] = names or [] 3427 """The names being imported. 3428 3429 Each entry is a :class:`tuple` of the name being imported, 3430 and the alias that the name is assigned to (if any). 3431 """ 3432 3433 super().__init__( 3434 lineno=lineno, 3435 col_offset=col_offset, 3436 end_lineno=end_lineno, 3437 end_col_offset=end_col_offset, 3438 parent=parent, 3439 ) 3440 3441 3442class Index(NodeNG): 3443 """Class representing an :class:`ast.Index` node. 3444 3445 An :class:`Index` is a simple subscript. 3446 3447 Deprecated since v2.6.0 - Now part of the :class:`Subscript` node. 3448 Will be removed with the release of v2.7.0 3449 """ 3450 3451 3452class Keyword(NodeNG): 3453 """Class representing an :class:`ast.keyword` node. 3454 3455 >>> import astroid 3456 >>> node = astroid.extract_node('function(a_kwarg=True)') 3457 >>> node 3458 <Call l.1 at 0x7f23b2e9e320> 3459 >>> node.keywords 3460 [<Keyword l.1 at 0x7f23b2e9e9b0>] 3461 """ 3462 3463 _astroid_fields = ("value",) 3464 _other_fields = ("arg",) 3465 3466 def __init__( 3467 self, 3468 arg: Optional[str] = None, 3469 lineno: Optional[int] = None, 3470 col_offset: Optional[int] = None, 3471 parent: Optional[NodeNG] = None, 3472 *, 3473 end_lineno: Optional[int] = None, 3474 end_col_offset: Optional[int] = None, 3475 ) -> None: 3476 """ 3477 :param arg: The argument being assigned to. 3478 3479 :param lineno: The line that this node appears on in the source code. 3480 3481 :param col_offset: The column that this node appears on in the 3482 source code. 3483 3484 :param parent: The parent node in the syntax tree. 3485 3486 :param end_lineno: The last line this node appears on in the source code. 3487 3488 :param end_col_offset: The end column this node appears on in the 3489 source code. Note: This is after the last symbol. 3490 """ 3491 self.arg: Optional[str] = arg # can be None 3492 """The argument being assigned to.""" 3493 3494 self.value: Optional[NodeNG] = None 3495 """The value being assigned to the keyword argument.""" 3496 3497 super().__init__( 3498 lineno=lineno, 3499 col_offset=col_offset, 3500 end_lineno=end_lineno, 3501 end_col_offset=end_col_offset, 3502 parent=parent, 3503 ) 3504 3505 def postinit(self, value: Optional[NodeNG] = None) -> None: 3506 """Do some setup after initialisation. 3507 3508 :param value: The value being assigned to the ketword argument. 3509 """ 3510 self.value = value 3511 3512 def get_children(self): 3513 yield self.value 3514 3515 3516class List(BaseContainer): 3517 """Class representing an :class:`ast.List` node. 3518 3519 >>> import astroid 3520 >>> node = astroid.extract_node('[1, 2, 3]') 3521 >>> node 3522 <List.list l.1 at 0x7f23b2e9e128> 3523 """ 3524 3525 _other_fields = ("ctx",) 3526 3527 def __init__( 3528 self, 3529 ctx: Optional[Context] = None, 3530 lineno: Optional[int] = None, 3531 col_offset: Optional[int] = None, 3532 parent: Optional[NodeNG] = None, 3533 *, 3534 end_lineno: Optional[int] = None, 3535 end_col_offset: Optional[int] = None, 3536 ) -> None: 3537 """ 3538 :param ctx: Whether the list is assigned to or loaded from. 3539 3540 :param lineno: The line that this node appears on in the source code. 3541 3542 :param col_offset: The column that this node appears on in the 3543 source code. 3544 3545 :param parent: The parent node in the syntax tree. 3546 3547 :param end_lineno: The last line this node appears on in the source code. 3548 3549 :param end_col_offset: The end column this node appears on in the 3550 source code. Note: This is after the last symbol. 3551 """ 3552 self.ctx: Optional[Context] = ctx 3553 """Whether the list is assigned to or loaded from.""" 3554 3555 super().__init__( 3556 lineno=lineno, 3557 col_offset=col_offset, 3558 end_lineno=end_lineno, 3559 end_col_offset=end_col_offset, 3560 parent=parent, 3561 ) 3562 3563 def pytype(self): 3564 """Get the name of the type that this node represents. 3565 3566 :returns: The name of the type. 3567 :rtype: str 3568 """ 3569 return "builtins.list" 3570 3571 def getitem(self, index, context=None): 3572 """Get an item from this node. 3573 3574 :param index: The node to use as a subscript index. 3575 :type index: Const or Slice 3576 """ 3577 return _container_getitem(self, self.elts, index, context=context) 3578 3579 3580class Nonlocal(mixins.NoChildrenMixin, Statement): 3581 """Class representing an :class:`ast.Nonlocal` node. 3582 3583 >>> import astroid 3584 >>> node = astroid.extract_node(''' 3585 def function(): 3586 nonlocal var 3587 ''') 3588 >>> node 3589 <FunctionDef.function l.2 at 0x7f23b2e9e208> 3590 >>> node.body[0] 3591 <Nonlocal l.3 at 0x7f23b2e9e908> 3592 """ 3593 3594 _other_fields = ("names",) 3595 3596 def __init__( 3597 self, 3598 names: typing.List[str], 3599 lineno: Optional[int] = None, 3600 col_offset: Optional[int] = None, 3601 parent: Optional[NodeNG] = None, 3602 *, 3603 end_lineno: Optional[int] = None, 3604 end_col_offset: Optional[int] = None, 3605 ) -> None: 3606 """ 3607 :param names: The names being declared as not local. 3608 3609 :param lineno: The line that this node appears on in the source code. 3610 3611 :param col_offset: The column that this node appears on in the 3612 source code. 3613 3614 :param parent: The parent node in the syntax tree. 3615 3616 :param end_lineno: The last line this node appears on in the source code. 3617 3618 :param end_col_offset: The end column this node appears on in the 3619 source code. Note: This is after the last symbol. 3620 """ 3621 self.names: typing.List[str] = names 3622 """The names being declared as not local.""" 3623 3624 super().__init__( 3625 lineno=lineno, 3626 col_offset=col_offset, 3627 end_lineno=end_lineno, 3628 end_col_offset=end_col_offset, 3629 parent=parent, 3630 ) 3631 3632 def _infer_name(self, frame, name): 3633 return name 3634 3635 3636class Pass(mixins.NoChildrenMixin, Statement): 3637 """Class representing an :class:`ast.Pass` node. 3638 3639 >>> import astroid 3640 >>> node = astroid.extract_node('pass') 3641 >>> node 3642 <Pass l.1 at 0x7f23b2e9e748> 3643 """ 3644 3645 3646class Raise(Statement): 3647 """Class representing an :class:`ast.Raise` node. 3648 3649 >>> import astroid 3650 >>> node = astroid.extract_node('raise RuntimeError("Something bad happened!")') 3651 >>> node 3652 <Raise l.1 at 0x7f23b2e9e828> 3653 """ 3654 3655 _astroid_fields = ("exc", "cause") 3656 3657 def __init__( 3658 self, 3659 lineno: Optional[int] = None, 3660 col_offset: Optional[int] = None, 3661 parent: Optional[NodeNG] = None, 3662 *, 3663 end_lineno: Optional[int] = None, 3664 end_col_offset: Optional[int] = None, 3665 ) -> None: 3666 """ 3667 :param lineno: The line that this node appears on in the source code. 3668 3669 :param col_offset: The column that this node appears on in the 3670 source code. 3671 3672 :param parent: The parent node in the syntax tree. 3673 3674 :param end_lineno: The last line this node appears on in the source code. 3675 3676 :param end_col_offset: The end column this node appears on in the 3677 source code. Note: This is after the last symbol. 3678 """ 3679 self.exc: Optional[NodeNG] = None # can be None 3680 """What is being raised.""" 3681 3682 self.cause: Optional[NodeNG] = None # can be None 3683 """The exception being used to raise this one.""" 3684 3685 super().__init__( 3686 lineno=lineno, 3687 col_offset=col_offset, 3688 end_lineno=end_lineno, 3689 end_col_offset=end_col_offset, 3690 parent=parent, 3691 ) 3692 3693 def postinit( 3694 self, 3695 exc: Optional[NodeNG] = None, 3696 cause: Optional[NodeNG] = None, 3697 ) -> None: 3698 """Do some setup after initialisation. 3699 3700 :param exc: What is being raised. 3701 3702 :param cause: The exception being used to raise this one. 3703 """ 3704 self.exc = exc 3705 self.cause = cause 3706 3707 def raises_not_implemented(self): 3708 """Check if this node raises a :class:`NotImplementedError`. 3709 3710 :returns: True if this node raises a :class:`NotImplementedError`, 3711 False otherwise. 3712 :rtype: bool 3713 """ 3714 if not self.exc: 3715 return False 3716 for name in self.exc._get_name_nodes(): 3717 if name.name == "NotImplementedError": 3718 return True 3719 return False 3720 3721 def get_children(self): 3722 if self.exc is not None: 3723 yield self.exc 3724 3725 if self.cause is not None: 3726 yield self.cause 3727 3728 3729class Return(Statement): 3730 """Class representing an :class:`ast.Return` node. 3731 3732 >>> import astroid 3733 >>> node = astroid.extract_node('return True') 3734 >>> node 3735 <Return l.1 at 0x7f23b8211908> 3736 """ 3737 3738 _astroid_fields = ("value",) 3739 3740 def __init__( 3741 self, 3742 lineno: Optional[int] = None, 3743 col_offset: Optional[int] = None, 3744 parent: Optional[NodeNG] = None, 3745 *, 3746 end_lineno: Optional[int] = None, 3747 end_col_offset: Optional[int] = None, 3748 ) -> None: 3749 """ 3750 :param lineno: The line that this node appears on in the source code. 3751 3752 :param col_offset: The column that this node appears on in the 3753 source code. 3754 3755 :param parent: The parent node in the syntax tree. 3756 3757 :param end_lineno: The last line this node appears on in the source code. 3758 3759 :param end_col_offset: The end column this node appears on in the 3760 source code. Note: This is after the last symbol. 3761 """ 3762 self.value: Optional[NodeNG] = None # can be None 3763 """The value being returned.""" 3764 3765 super().__init__( 3766 lineno=lineno, 3767 col_offset=col_offset, 3768 end_lineno=end_lineno, 3769 end_col_offset=end_col_offset, 3770 parent=parent, 3771 ) 3772 3773 def postinit(self, value: Optional[NodeNG] = None) -> None: 3774 """Do some setup after initialisation. 3775 3776 :param value: The value being returned. 3777 """ 3778 self.value = value 3779 3780 def get_children(self): 3781 if self.value is not None: 3782 yield self.value 3783 3784 def is_tuple_return(self): 3785 return isinstance(self.value, Tuple) 3786 3787 def _get_return_nodes_skip_functions(self): 3788 yield self 3789 3790 3791class Set(BaseContainer): 3792 """Class representing an :class:`ast.Set` node. 3793 3794 >>> import astroid 3795 >>> node = astroid.extract_node('{1, 2, 3}') 3796 >>> node 3797 <Set.set l.1 at 0x7f23b2e71d68> 3798 """ 3799 3800 def pytype(self): 3801 """Get the name of the type that this node represents. 3802 3803 :returns: The name of the type. 3804 :rtype: str 3805 """ 3806 return "builtins.set" 3807 3808 3809class Slice(NodeNG): 3810 """Class representing an :class:`ast.Slice` node. 3811 3812 >>> import astroid 3813 >>> node = astroid.extract_node('things[1:3]') 3814 >>> node 3815 <Subscript l.1 at 0x7f23b2e71f60> 3816 >>> node.slice 3817 <Slice l.1 at 0x7f23b2e71e80> 3818 """ 3819 3820 _astroid_fields = ("lower", "upper", "step") 3821 3822 def __init__( 3823 self, 3824 lineno: Optional[int] = None, 3825 col_offset: Optional[int] = None, 3826 parent: Optional[NodeNG] = None, 3827 *, 3828 end_lineno: Optional[int] = None, 3829 end_col_offset: Optional[int] = None, 3830 ) -> None: 3831 """ 3832 :param lineno: The line that this node appears on in the source code. 3833 3834 :param col_offset: The column that this node appears on in the 3835 source code. 3836 3837 :param parent: The parent node in the syntax tree. 3838 3839 :param end_lineno: The last line this node appears on in the source code. 3840 3841 :param end_col_offset: The end column this node appears on in the 3842 source code. Note: This is after the last symbol. 3843 """ 3844 self.lower: Optional[NodeNG] = None # can be None 3845 """The lower index in the slice.""" 3846 3847 self.upper: Optional[NodeNG] = None # can be None 3848 """The upper index in the slice.""" 3849 3850 self.step: Optional[NodeNG] = None # can be None 3851 """The step to take between indexes.""" 3852 3853 super().__init__( 3854 lineno=lineno, 3855 col_offset=col_offset, 3856 end_lineno=end_lineno, 3857 end_col_offset=end_col_offset, 3858 parent=parent, 3859 ) 3860 3861 def postinit( 3862 self, 3863 lower: Optional[NodeNG] = None, 3864 upper: Optional[NodeNG] = None, 3865 step: Optional[NodeNG] = None, 3866 ) -> None: 3867 """Do some setup after initialisation. 3868 3869 :param lower: The lower index in the slice. 3870 3871 :param upper: The upper index in the slice. 3872 3873 :param step: The step to take between index. 3874 """ 3875 self.lower = lower 3876 self.upper = upper 3877 self.step = step 3878 3879 def _wrap_attribute(self, attr): 3880 """Wrap the empty attributes of the Slice in a Const node.""" 3881 if not attr: 3882 const = const_factory(attr) 3883 const.parent = self 3884 return const 3885 return attr 3886 3887 @decorators.cachedproperty 3888 def _proxied(self): 3889 builtins = AstroidManager().builtins_module 3890 return builtins.getattr("slice")[0] 3891 3892 def pytype(self): 3893 """Get the name of the type that this node represents. 3894 3895 :returns: The name of the type. 3896 :rtype: str 3897 """ 3898 return "builtins.slice" 3899 3900 def igetattr(self, attrname, context=None): 3901 """Infer the possible values of the given attribute on the slice. 3902 3903 :param attrname: The name of the attribute to infer. 3904 :type attrname: str 3905 3906 :returns: The inferred possible values. 3907 :rtype: iterable(NodeNG) 3908 """ 3909 if attrname == "start": 3910 yield self._wrap_attribute(self.lower) 3911 elif attrname == "stop": 3912 yield self._wrap_attribute(self.upper) 3913 elif attrname == "step": 3914 yield self._wrap_attribute(self.step) 3915 else: 3916 yield from self.getattr(attrname, context=context) 3917 3918 def getattr(self, attrname, context=None): 3919 return self._proxied.getattr(attrname, context) 3920 3921 def get_children(self): 3922 if self.lower is not None: 3923 yield self.lower 3924 3925 if self.upper is not None: 3926 yield self.upper 3927 3928 if self.step is not None: 3929 yield self.step 3930 3931 3932class Starred(mixins.ParentAssignTypeMixin, NodeNG): 3933 """Class representing an :class:`ast.Starred` node. 3934 3935 >>> import astroid 3936 >>> node = astroid.extract_node('*args') 3937 >>> node 3938 <Starred l.1 at 0x7f23b2e41978> 3939 """ 3940 3941 _astroid_fields = ("value",) 3942 _other_fields = ("ctx",) 3943 3944 def __init__( 3945 self, 3946 ctx: Optional[Context] = None, 3947 lineno: Optional[int] = None, 3948 col_offset: Optional[int] = None, 3949 parent: Optional[NodeNG] = None, 3950 *, 3951 end_lineno: Optional[int] = None, 3952 end_col_offset: Optional[int] = None, 3953 ) -> None: 3954 """ 3955 :param ctx: Whether the list is assigned to or loaded from. 3956 3957 :param lineno: The line that this node appears on in the source code. 3958 3959 :param col_offset: The column that this node appears on in the 3960 source code. 3961 3962 :param parent: The parent node in the syntax tree. 3963 3964 :param end_lineno: The last line this node appears on in the source code. 3965 3966 :param end_col_offset: The end column this node appears on in the 3967 source code. Note: This is after the last symbol. 3968 """ 3969 self.value: Optional[NodeNG] = None 3970 """What is being unpacked.""" 3971 3972 self.ctx: Optional[Context] = ctx 3973 """Whether the starred item is assigned to or loaded from.""" 3974 3975 super().__init__( 3976 lineno=lineno, 3977 col_offset=col_offset, 3978 end_lineno=end_lineno, 3979 end_col_offset=end_col_offset, 3980 parent=parent, 3981 ) 3982 3983 def postinit(self, value: Optional[NodeNG] = None) -> None: 3984 """Do some setup after initialisation. 3985 3986 :param value: What is being unpacked. 3987 """ 3988 self.value = value 3989 3990 def get_children(self): 3991 yield self.value 3992 3993 3994class Subscript(NodeNG): 3995 """Class representing an :class:`ast.Subscript` node. 3996 3997 >>> import astroid 3998 >>> node = astroid.extract_node('things[1:3]') 3999 >>> node 4000 <Subscript l.1 at 0x7f23b2e71f60> 4001 """ 4002 4003 _astroid_fields = ("value", "slice") 4004 _other_fields = ("ctx",) 4005 4006 def __init__( 4007 self, 4008 ctx: Optional[Context] = None, 4009 lineno: Optional[int] = None, 4010 col_offset: Optional[int] = None, 4011 parent: Optional[NodeNG] = None, 4012 *, 4013 end_lineno: Optional[int] = None, 4014 end_col_offset: Optional[int] = None, 4015 ) -> None: 4016 """ 4017 :param ctx: Whether the subscripted item is assigned to or loaded from. 4018 4019 :param lineno: The line that this node appears on in the source code. 4020 4021 :param col_offset: The column that this node appears on in the 4022 source code. 4023 4024 :param parent: The parent node in the syntax tree. 4025 4026 :param end_lineno: The last line this node appears on in the source code. 4027 4028 :param end_col_offset: The end column this node appears on in the 4029 source code. Note: This is after the last symbol. 4030 """ 4031 self.value: Optional[NodeNG] = None 4032 """What is being indexed.""" 4033 4034 self.slice: Optional[NodeNG] = None 4035 """The slice being used to lookup.""" 4036 4037 self.ctx: Optional[Context] = ctx 4038 """Whether the subscripted item is assigned to or loaded from.""" 4039 4040 super().__init__( 4041 lineno=lineno, 4042 col_offset=col_offset, 4043 end_lineno=end_lineno, 4044 end_col_offset=end_col_offset, 4045 parent=parent, 4046 ) 4047 4048 # pylint: disable=redefined-builtin; had to use the same name as builtin ast module. 4049 def postinit( 4050 self, value: Optional[NodeNG] = None, slice: Optional[NodeNG] = None 4051 ) -> None: 4052 """Do some setup after initialisation. 4053 4054 :param value: What is being indexed. 4055 4056 :param slice: The slice being used to lookup. 4057 """ 4058 self.value = value 4059 self.slice = slice 4060 4061 def get_children(self): 4062 yield self.value 4063 yield self.slice 4064 4065 4066class TryExcept(mixins.MultiLineBlockMixin, mixins.BlockRangeMixIn, Statement): 4067 """Class representing an :class:`ast.TryExcept` node. 4068 4069 >>> import astroid 4070 >>> node = astroid.extract_node(''' 4071 try: 4072 do_something() 4073 except Exception as error: 4074 print("Error!") 4075 ''') 4076 >>> node 4077 <TryExcept l.2 at 0x7f23b2e9d908> 4078 """ 4079 4080 _astroid_fields = ("body", "handlers", "orelse") 4081 _multi_line_block_fields = ("body", "handlers", "orelse") 4082 4083 def __init__( 4084 self, 4085 lineno: Optional[int] = None, 4086 col_offset: Optional[int] = None, 4087 parent: Optional[NodeNG] = None, 4088 *, 4089 end_lineno: Optional[int] = None, 4090 end_col_offset: Optional[int] = None, 4091 ) -> None: 4092 """ 4093 :param lineno: The line that this node appears on in the source code. 4094 4095 :param col_offset: The column that this node appears on in the 4096 source code. 4097 4098 :param parent: The parent node in the syntax tree. 4099 4100 :param end_lineno: The last line this node appears on in the source code. 4101 4102 :param end_col_offset: The end column this node appears on in the 4103 source code. Note: This is after the last symbol. 4104 """ 4105 self.body: typing.List[NodeNG] = [] 4106 """The contents of the block to catch exceptions from.""" 4107 4108 self.handlers: typing.List[ExceptHandler] = [] 4109 """The exception handlers.""" 4110 4111 self.orelse: typing.List[NodeNG] = [] 4112 """The contents of the ``else`` block.""" 4113 4114 super().__init__( 4115 lineno=lineno, 4116 col_offset=col_offset, 4117 end_lineno=end_lineno, 4118 end_col_offset=end_col_offset, 4119 parent=parent, 4120 ) 4121 4122 def postinit( 4123 self, 4124 body: Optional[typing.List[NodeNG]] = None, 4125 handlers: Optional[typing.List[ExceptHandler]] = None, 4126 orelse: Optional[typing.List[NodeNG]] = None, 4127 ) -> None: 4128 """Do some setup after initialisation. 4129 4130 :param body: The contents of the block to catch exceptions from. 4131 4132 :param handlers: The exception handlers. 4133 4134 :param orelse: The contents of the ``else`` block. 4135 """ 4136 if body is not None: 4137 self.body = body 4138 if handlers is not None: 4139 self.handlers = handlers 4140 if orelse is not None: 4141 self.orelse = orelse 4142 4143 def _infer_name(self, frame, name): 4144 return name 4145 4146 def block_range(self, lineno): 4147 """Get a range from the given line number to where this node ends. 4148 4149 :param lineno: The line number to start the range at. 4150 :type lineno: int 4151 4152 :returns: The range of line numbers that this node belongs to, 4153 starting at the given line number. 4154 :rtype: tuple(int, int) 4155 """ 4156 last = None 4157 for exhandler in self.handlers: 4158 if exhandler.type and lineno == exhandler.type.fromlineno: 4159 return lineno, lineno 4160 if exhandler.body[0].fromlineno <= lineno <= exhandler.body[-1].tolineno: 4161 return lineno, exhandler.body[-1].tolineno 4162 if last is None: 4163 last = exhandler.body[0].fromlineno - 1 4164 return self._elsed_block_range(lineno, self.orelse, last) 4165 4166 def get_children(self): 4167 yield from self.body 4168 4169 yield from self.handlers or () 4170 yield from self.orelse or () 4171 4172 4173class TryFinally(mixins.MultiLineBlockMixin, mixins.BlockRangeMixIn, Statement): 4174 """Class representing an :class:`ast.TryFinally` node. 4175 4176 >>> import astroid 4177 >>> node = astroid.extract_node(''' 4178 try: 4179 do_something() 4180 except Exception as error: 4181 print("Error!") 4182 finally: 4183 print("Cleanup!") 4184 ''') 4185 >>> node 4186 <TryFinally l.2 at 0x7f23b2e41d68> 4187 """ 4188 4189 _astroid_fields = ("body", "finalbody") 4190 _multi_line_block_fields = ("body", "finalbody") 4191 4192 def __init__( 4193 self, 4194 lineno: Optional[int] = None, 4195 col_offset: Optional[int] = None, 4196 parent: Optional[NodeNG] = None, 4197 *, 4198 end_lineno: Optional[int] = None, 4199 end_col_offset: Optional[int] = None, 4200 ) -> None: 4201 """ 4202 :param lineno: The line that this node appears on in the source code. 4203 4204 :param col_offset: The column that this node appears on in the 4205 source code. 4206 4207 :param parent: The parent node in the syntax tree. 4208 4209 :param end_lineno: The last line this node appears on in the source code. 4210 4211 :param end_col_offset: The end column this node appears on in the 4212 source code. Note: This is after the last symbol. 4213 """ 4214 self.body: typing.Union[typing.List[TryExcept], typing.List[NodeNG]] = [] 4215 """The try-except that the finally is attached to.""" 4216 4217 self.finalbody: typing.List[NodeNG] = [] 4218 """The contents of the ``finally`` block.""" 4219 4220 super().__init__( 4221 lineno=lineno, 4222 col_offset=col_offset, 4223 end_lineno=end_lineno, 4224 end_col_offset=end_col_offset, 4225 parent=parent, 4226 ) 4227 4228 def postinit( 4229 self, 4230 body: typing.Union[typing.List[TryExcept], typing.List[NodeNG], None] = None, 4231 finalbody: Optional[typing.List[NodeNG]] = None, 4232 ) -> None: 4233 """Do some setup after initialisation. 4234 4235 :param body: The try-except that the finally is attached to. 4236 4237 :param finalbody: The contents of the ``finally`` block. 4238 """ 4239 if body is not None: 4240 self.body = body 4241 if finalbody is not None: 4242 self.finalbody = finalbody 4243 4244 def block_range(self, lineno): 4245 """Get a range from the given line number to where this node ends. 4246 4247 :param lineno: The line number to start the range at. 4248 :type lineno: int 4249 4250 :returns: The range of line numbers that this node belongs to, 4251 starting at the given line number. 4252 :rtype: tuple(int, int) 4253 """ 4254 child = self.body[0] 4255 # py2.5 try: except: finally: 4256 if ( 4257 isinstance(child, TryExcept) 4258 and child.fromlineno == self.fromlineno 4259 and child.tolineno >= lineno > self.fromlineno 4260 ): 4261 return child.block_range(lineno) 4262 return self._elsed_block_range(lineno, self.finalbody) 4263 4264 def get_children(self): 4265 yield from self.body 4266 yield from self.finalbody 4267 4268 4269class Tuple(BaseContainer): 4270 """Class representing an :class:`ast.Tuple` node. 4271 4272 >>> import astroid 4273 >>> node = astroid.extract_node('(1, 2, 3)') 4274 >>> node 4275 <Tuple.tuple l.1 at 0x7f23b2e41780> 4276 """ 4277 4278 _other_fields = ("ctx",) 4279 4280 def __init__( 4281 self, 4282 ctx: Optional[Context] = None, 4283 lineno: Optional[int] = None, 4284 col_offset: Optional[int] = None, 4285 parent: Optional[NodeNG] = None, 4286 *, 4287 end_lineno: Optional[int] = None, 4288 end_col_offset: Optional[int] = None, 4289 ) -> None: 4290 """ 4291 :param ctx: Whether the tuple is assigned to or loaded from. 4292 4293 :param lineno: The line that this node appears on in the source code. 4294 4295 :param col_offset: The column that this node appears on in the 4296 source code. 4297 4298 :param parent: The parent node in the syntax tree. 4299 4300 :param end_lineno: The last line this node appears on in the source code. 4301 4302 :param end_col_offset: The end column this node appears on in the 4303 source code. Note: This is after the last symbol. 4304 """ 4305 self.ctx: Optional[Context] = ctx 4306 """Whether the tuple is assigned to or loaded from.""" 4307 4308 super().__init__( 4309 lineno=lineno, 4310 col_offset=col_offset, 4311 end_lineno=end_lineno, 4312 end_col_offset=end_col_offset, 4313 parent=parent, 4314 ) 4315 4316 def pytype(self): 4317 """Get the name of the type that this node represents. 4318 4319 :returns: The name of the type. 4320 :rtype: str 4321 """ 4322 return "builtins.tuple" 4323 4324 def getitem(self, index, context=None): 4325 """Get an item from this node. 4326 4327 :param index: The node to use as a subscript index. 4328 :type index: Const or Slice 4329 """ 4330 return _container_getitem(self, self.elts, index, context=context) 4331 4332 4333class UnaryOp(NodeNG): 4334 """Class representing an :class:`ast.UnaryOp` node. 4335 4336 >>> import astroid 4337 >>> node = astroid.extract_node('-5') 4338 >>> node 4339 <UnaryOp l.1 at 0x7f23b2e4e198> 4340 """ 4341 4342 _astroid_fields = ("operand",) 4343 _other_fields = ("op",) 4344 4345 @decorators.deprecate_default_argument_values(op="str") 4346 def __init__( 4347 self, 4348 op: Optional[str] = None, 4349 lineno: Optional[int] = None, 4350 col_offset: Optional[int] = None, 4351 parent: Optional[NodeNG] = None, 4352 *, 4353 end_lineno: Optional[int] = None, 4354 end_col_offset: Optional[int] = None, 4355 ) -> None: 4356 """ 4357 :param op: The operator. 4358 4359 :param lineno: The line that this node appears on in the source code. 4360 4361 :param col_offset: The column that this node appears on in the 4362 source code. 4363 4364 :param parent: The parent node in the syntax tree. 4365 4366 :param end_lineno: The last line this node appears on in the source code. 4367 4368 :param end_col_offset: The end column this node appears on in the 4369 source code. Note: This is after the last symbol. 4370 """ 4371 self.op: Optional[str] = op 4372 """The operator.""" 4373 4374 self.operand: Optional[NodeNG] = None 4375 """What the unary operator is applied to.""" 4376 4377 super().__init__( 4378 lineno=lineno, 4379 col_offset=col_offset, 4380 end_lineno=end_lineno, 4381 end_col_offset=end_col_offset, 4382 parent=parent, 4383 ) 4384 4385 def postinit(self, operand: Optional[NodeNG] = None) -> None: 4386 """Do some setup after initialisation. 4387 4388 :param operand: What the unary operator is applied to. 4389 """ 4390 self.operand = operand 4391 4392 # This is set by inference.py 4393 def _infer_unaryop(self, context=None): 4394 raise NotImplementedError 4395 4396 def type_errors(self, context=None): 4397 """Get a list of type errors which can occur during inference. 4398 4399 Each TypeError is represented by a :class:`BadBinaryOperationMessage`, 4400 which holds the original exception. 4401 4402 :returns: The list of possible type errors. 4403 :rtype: list(BadBinaryOperationMessage) 4404 """ 4405 try: 4406 results = self._infer_unaryop(context=context) 4407 return [ 4408 result 4409 for result in results 4410 if isinstance(result, util.BadUnaryOperationMessage) 4411 ] 4412 except InferenceError: 4413 return [] 4414 4415 def get_children(self): 4416 yield self.operand 4417 4418 def op_precedence(self): 4419 if self.op == "not": 4420 return OP_PRECEDENCE[self.op] 4421 4422 return super().op_precedence() 4423 4424 4425class While(mixins.MultiLineBlockMixin, mixins.BlockRangeMixIn, Statement): 4426 """Class representing an :class:`ast.While` node. 4427 4428 >>> import astroid 4429 >>> node = astroid.extract_node(''' 4430 while condition(): 4431 print("True") 4432 ''') 4433 >>> node 4434 <While l.2 at 0x7f23b2e4e390> 4435 """ 4436 4437 _astroid_fields = ("test", "body", "orelse") 4438 _multi_line_block_fields = ("body", "orelse") 4439 4440 def __init__( 4441 self, 4442 lineno: Optional[int] = None, 4443 col_offset: Optional[int] = None, 4444 parent: Optional[NodeNG] = None, 4445 *, 4446 end_lineno: Optional[int] = None, 4447 end_col_offset: Optional[int] = None, 4448 ) -> None: 4449 """ 4450 :param lineno: The line that this node appears on in the source code. 4451 4452 :param col_offset: The column that this node appears on in the 4453 source code. 4454 4455 :param parent: The parent node in the syntax tree. 4456 4457 :param end_lineno: The last line this node appears on in the source code. 4458 4459 :param end_col_offset: The end column this node appears on in the 4460 source code. Note: This is after the last symbol. 4461 """ 4462 self.test: Optional[NodeNG] = None 4463 """The condition that the loop tests.""" 4464 4465 self.body: typing.List[NodeNG] = [] 4466 """The contents of the loop.""" 4467 4468 self.orelse: typing.List[NodeNG] = [] 4469 """The contents of the ``else`` block.""" 4470 4471 super().__init__( 4472 lineno=lineno, 4473 col_offset=col_offset, 4474 end_lineno=end_lineno, 4475 end_col_offset=end_col_offset, 4476 parent=parent, 4477 ) 4478 4479 def postinit( 4480 self, 4481 test: Optional[NodeNG] = None, 4482 body: Optional[typing.List[NodeNG]] = None, 4483 orelse: Optional[typing.List[NodeNG]] = None, 4484 ) -> None: 4485 """Do some setup after initialisation. 4486 4487 :param test: The condition that the loop tests. 4488 4489 :param body: The contents of the loop. 4490 4491 :param orelse: The contents of the ``else`` block. 4492 """ 4493 self.test = test 4494 if body is not None: 4495 self.body = body 4496 if orelse is not None: 4497 self.orelse = orelse 4498 4499 @decorators.cachedproperty 4500 def blockstart_tolineno(self): 4501 """The line on which the beginning of this block ends. 4502 4503 :type: int 4504 """ 4505 return self.test.tolineno 4506 4507 def block_range(self, lineno): 4508 """Get a range from the given line number to where this node ends. 4509 4510 :param lineno: The line number to start the range at. 4511 :type lineno: int 4512 4513 :returns: The range of line numbers that this node belongs to, 4514 starting at the given line number. 4515 :rtype: tuple(int, int) 4516 """ 4517 return self._elsed_block_range(lineno, self.orelse) 4518 4519 def get_children(self): 4520 yield self.test 4521 4522 yield from self.body 4523 yield from self.orelse 4524 4525 def _get_yield_nodes_skip_lambdas(self): 4526 """A While node can contain a Yield node in the test""" 4527 yield from self.test._get_yield_nodes_skip_lambdas() 4528 yield from super()._get_yield_nodes_skip_lambdas() 4529 4530 4531class With( 4532 mixins.MultiLineBlockMixin, 4533 mixins.BlockRangeMixIn, 4534 mixins.AssignTypeMixin, 4535 Statement, 4536): 4537 """Class representing an :class:`ast.With` node. 4538 4539 >>> import astroid 4540 >>> node = astroid.extract_node(''' 4541 with open(file_path) as file_: 4542 print(file_.read()) 4543 ''') 4544 >>> node 4545 <With l.2 at 0x7f23b2e4e710> 4546 """ 4547 4548 _astroid_fields = ("items", "body") 4549 _other_other_fields = ("type_annotation",) 4550 _multi_line_block_fields = ("body",) 4551 4552 def __init__( 4553 self, 4554 lineno: Optional[int] = None, 4555 col_offset: Optional[int] = None, 4556 parent: Optional[NodeNG] = None, 4557 *, 4558 end_lineno: Optional[int] = None, 4559 end_col_offset: Optional[int] = None, 4560 ) -> None: 4561 """ 4562 :param lineno: The line that this node appears on in the source code. 4563 4564 :param col_offset: The column that this node appears on in the 4565 source code. 4566 4567 :param parent: The parent node in the syntax tree. 4568 4569 :param end_lineno: The last line this node appears on in the source code. 4570 4571 :param end_col_offset: The end column this node appears on in the 4572 source code. Note: This is after the last symbol. 4573 """ 4574 self.items: typing.List[typing.Tuple[NodeNG, Optional[NodeNG]]] = [] 4575 """The pairs of context managers and the names they are assigned to.""" 4576 4577 self.body: typing.List[NodeNG] = [] 4578 """The contents of the ``with`` block.""" 4579 4580 self.type_annotation: Optional[NodeNG] = None # can be None 4581 """If present, this will contain the type annotation passed by a type comment""" 4582 4583 super().__init__( 4584 lineno=lineno, 4585 col_offset=col_offset, 4586 end_lineno=end_lineno, 4587 end_col_offset=end_col_offset, 4588 parent=parent, 4589 ) 4590 4591 def postinit( 4592 self, 4593 items: Optional[typing.List[typing.Tuple[NodeNG, Optional[NodeNG]]]] = None, 4594 body: Optional[typing.List[NodeNG]] = None, 4595 type_annotation: Optional[NodeNG] = None, 4596 ) -> None: 4597 """Do some setup after initialisation. 4598 4599 :param items: The pairs of context managers and the names 4600 they are assigned to. 4601 4602 :param body: The contents of the ``with`` block. 4603 """ 4604 if items is not None: 4605 self.items = items 4606 if body is not None: 4607 self.body = body 4608 self.type_annotation = type_annotation 4609 4610 @decorators.cachedproperty 4611 def blockstart_tolineno(self): 4612 """The line on which the beginning of this block ends. 4613 4614 :type: int 4615 """ 4616 return self.items[-1][0].tolineno 4617 4618 def get_children(self): 4619 """Get the child nodes below this node. 4620 4621 :returns: The children. 4622 :rtype: iterable(NodeNG) 4623 """ 4624 for expr, var in self.items: 4625 yield expr 4626 if var: 4627 yield var 4628 yield from self.body 4629 4630 4631class AsyncWith(With): 4632 """Asynchronous ``with`` built with the ``async`` keyword.""" 4633 4634 4635class Yield(NodeNG): 4636 """Class representing an :class:`ast.Yield` node. 4637 4638 >>> import astroid 4639 >>> node = astroid.extract_node('yield True') 4640 >>> node 4641 <Yield l.1 at 0x7f23b2e4e5f8> 4642 """ 4643 4644 _astroid_fields = ("value",) 4645 4646 def __init__( 4647 self, 4648 lineno: Optional[int] = None, 4649 col_offset: Optional[int] = None, 4650 parent: Optional[NodeNG] = None, 4651 *, 4652 end_lineno: Optional[int] = None, 4653 end_col_offset: Optional[int] = None, 4654 ) -> None: 4655 """ 4656 :param lineno: The line that this node appears on in the source code. 4657 4658 :param col_offset: The column that this node appears on in the 4659 source code. 4660 4661 :param parent: The parent node in the syntax tree. 4662 4663 :param end_lineno: The last line this node appears on in the source code. 4664 4665 :param end_col_offset: The end column this node appears on in the 4666 source code. Note: This is after the last symbol. 4667 """ 4668 self.value: Optional[NodeNG] = None # can be None 4669 """The value to yield.""" 4670 4671 super().__init__( 4672 lineno=lineno, 4673 col_offset=col_offset, 4674 end_lineno=end_lineno, 4675 end_col_offset=end_col_offset, 4676 parent=parent, 4677 ) 4678 4679 def postinit(self, value: Optional[NodeNG] = None) -> None: 4680 """Do some setup after initialisation. 4681 4682 :param value: The value to yield. 4683 """ 4684 self.value = value 4685 4686 def get_children(self): 4687 if self.value is not None: 4688 yield self.value 4689 4690 def _get_yield_nodes_skip_lambdas(self): 4691 yield self 4692 4693 4694class YieldFrom(Yield): # TODO value is required, not optional 4695 """Class representing an :class:`ast.YieldFrom` node.""" 4696 4697 4698class DictUnpack(mixins.NoChildrenMixin, NodeNG): 4699 """Represents the unpacking of dicts into dicts using :pep:`448`.""" 4700 4701 4702class FormattedValue(NodeNG): 4703 """Class representing an :class:`ast.FormattedValue` node. 4704 4705 Represents a :pep:`498` format string. 4706 4707 >>> import astroid 4708 >>> node = astroid.extract_node('f"Format {type_}"') 4709 >>> node 4710 <JoinedStr l.1 at 0x7f23b2e4ed30> 4711 >>> node.values 4712 [<Const.str l.1 at 0x7f23b2e4eda0>, <FormattedValue l.1 at 0x7f23b2e4edd8>] 4713 """ 4714 4715 _astroid_fields = ("value", "format_spec") 4716 _other_fields = ("conversion",) 4717 4718 def __init__( 4719 self, 4720 lineno: Optional[int] = None, 4721 col_offset: Optional[int] = None, 4722 parent: Optional[NodeNG] = None, 4723 *, 4724 end_lineno: Optional[int] = None, 4725 end_col_offset: Optional[int] = None, 4726 ) -> None: 4727 """ 4728 :param lineno: The line that this node appears on in the source code. 4729 4730 :param col_offset: The column that this node appears on in the 4731 source code. 4732 4733 :param parent: The parent node in the syntax tree. 4734 4735 :param end_lineno: The last line this node appears on in the source code. 4736 4737 :param end_col_offset: The end column this node appears on in the 4738 source code. Note: This is after the last symbol. 4739 """ 4740 self.value: NodeNG 4741 """The value to be formatted into the string.""" 4742 4743 self.conversion: Optional[int] = None # can be None 4744 """The type of formatting to be applied to the value. 4745 4746 .. seealso:: 4747 :class:`ast.FormattedValue` 4748 """ 4749 4750 self.format_spec: Optional[NodeNG] = None # can be None 4751 """The formatting to be applied to the value. 4752 4753 .. seealso:: 4754 :class:`ast.FormattedValue` 4755 4756 :type: JoinedStr or None 4757 """ 4758 4759 super().__init__( 4760 lineno=lineno, 4761 col_offset=col_offset, 4762 end_lineno=end_lineno, 4763 end_col_offset=end_col_offset, 4764 parent=parent, 4765 ) 4766 4767 def postinit( 4768 self, 4769 value: NodeNG, 4770 conversion: Optional[int] = None, 4771 format_spec: Optional[NodeNG] = None, 4772 ) -> None: 4773 """Do some setup after initialisation. 4774 4775 :param value: The value to be formatted into the string. 4776 4777 :param conversion: The type of formatting to be applied to the value. 4778 4779 :param format_spec: The formatting to be applied to the value. 4780 :type format_spec: JoinedStr or None 4781 """ 4782 self.value = value 4783 self.conversion = conversion 4784 self.format_spec = format_spec 4785 4786 def get_children(self): 4787 yield self.value 4788 4789 if self.format_spec is not None: 4790 yield self.format_spec 4791 4792 4793class JoinedStr(NodeNG): 4794 """Represents a list of string expressions to be joined. 4795 4796 >>> import astroid 4797 >>> node = astroid.extract_node('f"Format {type_}"') 4798 >>> node 4799 <JoinedStr l.1 at 0x7f23b2e4ed30> 4800 """ 4801 4802 _astroid_fields = ("values",) 4803 4804 def __init__( 4805 self, 4806 lineno: Optional[int] = None, 4807 col_offset: Optional[int] = None, 4808 parent: Optional[NodeNG] = None, 4809 *, 4810 end_lineno: Optional[int] = None, 4811 end_col_offset: Optional[int] = None, 4812 ) -> None: 4813 """ 4814 :param lineno: The line that this node appears on in the source code. 4815 4816 :param col_offset: The column that this node appears on in the 4817 source code. 4818 4819 :param parent: The parent node in the syntax tree. 4820 4821 :param end_lineno: The last line this node appears on in the source code. 4822 4823 :param end_col_offset: The end column this node appears on in the 4824 source code. Note: This is after the last symbol. 4825 """ 4826 self.values: typing.List[NodeNG] = [] 4827 """The string expressions to be joined. 4828 4829 :type: list(FormattedValue or Const) 4830 """ 4831 4832 super().__init__( 4833 lineno=lineno, 4834 col_offset=col_offset, 4835 end_lineno=end_lineno, 4836 end_col_offset=end_col_offset, 4837 parent=parent, 4838 ) 4839 4840 def postinit(self, values: Optional[typing.List[NodeNG]] = None) -> None: 4841 """Do some setup after initialisation. 4842 4843 :param value: The string expressions to be joined. 4844 4845 :type: list(FormattedValue or Const) 4846 """ 4847 if values is not None: 4848 self.values = values 4849 4850 def get_children(self): 4851 yield from self.values 4852 4853 4854class NamedExpr(mixins.AssignTypeMixin, NodeNG): 4855 """Represents the assignment from the assignment expression 4856 4857 >>> import astroid 4858 >>> module = astroid.parse('if a := 1: pass') 4859 >>> module.body[0].test 4860 <NamedExpr l.1 at 0x7f23b2e4ed30> 4861 """ 4862 4863 _astroid_fields = ("target", "value") 4864 4865 optional_assign = True 4866 """Whether this node optionally assigns a variable. 4867 4868 Since NamedExpr are not always called they do not always assign.""" 4869 4870 def __init__( 4871 self, 4872 lineno: Optional[int] = None, 4873 col_offset: Optional[int] = None, 4874 parent: Optional[NodeNG] = None, 4875 *, 4876 end_lineno: Optional[int] = None, 4877 end_col_offset: Optional[int] = None, 4878 ) -> None: 4879 """ 4880 :param lineno: The line that this node appears on in the source code. 4881 4882 :param col_offset: The column that this node appears on in the 4883 source code. 4884 4885 :param parent: The parent node in the syntax tree. 4886 4887 :param end_lineno: The last line this node appears on in the source code. 4888 4889 :param end_col_offset: The end column this node appears on in the 4890 source code. Note: This is after the last symbol. 4891 """ 4892 self.target: NodeNG 4893 """The assignment target 4894 4895 :type: Name 4896 """ 4897 4898 self.value: NodeNG 4899 """The value that gets assigned in the expression""" 4900 4901 super().__init__( 4902 lineno=lineno, 4903 col_offset=col_offset, 4904 end_lineno=end_lineno, 4905 end_col_offset=end_col_offset, 4906 parent=parent, 4907 ) 4908 4909 def postinit(self, target: NodeNG, value: NodeNG) -> None: 4910 self.target = target 4911 self.value = value 4912 4913 def frame(self): 4914 """The first parent frame node. 4915 4916 A frame node is a :class:`Module`, :class:`FunctionDef`, 4917 or :class:`ClassDef`. 4918 4919 :returns: The first parent frame node. 4920 """ 4921 if not self.parent: 4922 raise ParentMissingError(target=self) 4923 4924 # For certain parents NamedExpr evaluate to the scope of the parent 4925 if isinstance(self.parent, (Arguments, Keyword, Comprehension)): 4926 if not self.parent.parent: 4927 raise ParentMissingError(target=self.parent) 4928 if not self.parent.parent.parent: 4929 raise ParentMissingError(target=self.parent.parent) 4930 return self.parent.parent.parent.frame() 4931 4932 return self.parent.frame() 4933 4934 def scope(self) -> "LocalsDictNodeNG": 4935 """The first parent node defining a new scope. 4936 These can be Module, FunctionDef, ClassDef, Lambda, or GeneratorExp nodes. 4937 4938 :returns: The first parent scope node. 4939 """ 4940 if not self.parent: 4941 raise ParentMissingError(target=self) 4942 4943 # For certain parents NamedExpr evaluate to the scope of the parent 4944 if isinstance(self.parent, (Arguments, Keyword, Comprehension)): 4945 if not self.parent.parent: 4946 raise ParentMissingError(target=self.parent) 4947 if not self.parent.parent.parent: 4948 raise ParentMissingError(target=self.parent.parent) 4949 return self.parent.parent.parent.scope() 4950 4951 return self.parent.scope() 4952 4953 def set_local(self, name: str, stmt: AssignName) -> None: 4954 """Define that the given name is declared in the given statement node. 4955 NamedExpr's in Arguments, Keyword or Comprehension are evaluated in their 4956 parent's parent scope. So we add to their frame's locals. 4957 4958 .. seealso:: :meth:`scope` 4959 4960 :param name: The name that is being defined. 4961 4962 :param stmt: The statement that defines the given name. 4963 """ 4964 self.frame().set_local(name, stmt) 4965 4966 4967class Unknown(mixins.AssignTypeMixin, NodeNG): 4968 """This node represents a node in a constructed AST where 4969 introspection is not possible. At the moment, it's only used in 4970 the args attribute of FunctionDef nodes where function signature 4971 introspection failed. 4972 """ 4973 4974 name = "Unknown" 4975 4976 def qname(self): 4977 return "Unknown" 4978 4979 def _infer(self, context=None, **kwargs): 4980 """Inference on an Unknown node immediately terminates.""" 4981 yield util.Uninferable 4982 4983 4984class EvaluatedObject(NodeNG): 4985 """Contains an object that has already been inferred 4986 4987 This class is useful to pre-evaluate a particular node, 4988 with the resulting class acting as the non-evaluated node. 4989 """ 4990 4991 name = "EvaluatedObject" 4992 _astroid_fields = ("original",) 4993 _other_fields = ("value",) 4994 4995 def __init__( 4996 self, original: NodeNG, value: typing.Union[NodeNG, util.Uninferable] 4997 ) -> None: 4998 self.original: NodeNG = original 4999 """The original node that has already been evaluated""" 5000 5001 self.value: typing.Union[NodeNG, util.Uninferable] = value 5002 """The inferred value""" 5003 5004 super().__init__( 5005 lineno=self.original.lineno, 5006 col_offset=self.original.col_offset, 5007 parent=self.original.parent, 5008 ) 5009 5010 def infer(self, context=None, **kwargs): 5011 yield self.value 5012 5013 5014# Pattern matching ####################################################### 5015 5016 5017class Match(Statement): 5018 """Class representing a :class:`ast.Match` node. 5019 5020 >>> import astroid 5021 >>> node = astroid.extract_node(''' 5022 match x: 5023 case 200: 5024 ... 5025 case _: 5026 ... 5027 ''') 5028 >>> node 5029 <Match l.2 at 0x10c24e170> 5030 """ 5031 5032 _astroid_fields = ("subject", "cases") 5033 5034 def __init__( 5035 self, 5036 lineno: Optional[int] = None, 5037 col_offset: Optional[int] = None, 5038 parent: Optional[NodeNG] = None, 5039 *, 5040 end_lineno: Optional[int] = None, 5041 end_col_offset: Optional[int] = None, 5042 ) -> None: 5043 self.subject: NodeNG 5044 self.cases: typing.List["MatchCase"] 5045 super().__init__( 5046 lineno=lineno, 5047 col_offset=col_offset, 5048 end_lineno=end_lineno, 5049 end_col_offset=end_col_offset, 5050 parent=parent, 5051 ) 5052 5053 def postinit( 5054 self, 5055 *, 5056 subject: NodeNG, 5057 cases: typing.List["MatchCase"], 5058 ) -> None: 5059 self.subject = subject 5060 self.cases = cases 5061 5062 5063class Pattern(NodeNG): 5064 """Base class for all Pattern nodes.""" 5065 5066 5067class MatchCase(mixins.MultiLineBlockMixin, NodeNG): 5068 """Class representing a :class:`ast.match_case` node. 5069 5070 >>> import astroid 5071 >>> node = astroid.extract_node(''' 5072 match x: 5073 case 200: 5074 ... 5075 ''') 5076 >>> node.cases[0] 5077 <MatchCase l.3 at 0x10c24e590> 5078 """ 5079 5080 _astroid_fields = ("pattern", "guard", "body") 5081 _multi_line_block_fields = ("body",) 5082 5083 lineno: None 5084 col_offset: None 5085 end_lineno: None 5086 end_col_offset: None 5087 5088 def __init__(self, *, parent: Optional[NodeNG] = None) -> None: 5089 self.pattern: Pattern 5090 self.guard: Optional[NodeNG] 5091 self.body: typing.List[NodeNG] 5092 super().__init__(parent=parent) 5093 5094 def postinit( 5095 self, 5096 *, 5097 pattern: Pattern, 5098 guard: Optional[NodeNG], 5099 body: typing.List[NodeNG], 5100 ) -> None: 5101 self.pattern = pattern 5102 self.guard = guard 5103 self.body = body 5104 5105 5106class MatchValue(Pattern): 5107 """Class representing a :class:`ast.MatchValue` node. 5108 5109 >>> import astroid 5110 >>> node = astroid.extract_node(''' 5111 match x: 5112 case 200: 5113 ... 5114 ''') 5115 >>> node.cases[0].pattern 5116 <MatchValue l.3 at 0x10c24e200> 5117 """ 5118 5119 _astroid_fields = ("value",) 5120 5121 def __init__( 5122 self, 5123 lineno: Optional[int] = None, 5124 col_offset: Optional[int] = None, 5125 parent: Optional[NodeNG] = None, 5126 *, 5127 end_lineno: Optional[int] = None, 5128 end_col_offset: Optional[int] = None, 5129 ) -> None: 5130 self.value: NodeNG 5131 super().__init__( 5132 lineno=lineno, 5133 col_offset=col_offset, 5134 end_lineno=end_lineno, 5135 end_col_offset=end_col_offset, 5136 parent=parent, 5137 ) 5138 5139 def postinit(self, *, value: NodeNG) -> None: 5140 self.value = value 5141 5142 5143class MatchSingleton(Pattern): 5144 """Class representing a :class:`ast.MatchSingleton` node. 5145 5146 >>> import astroid 5147 >>> node = astroid.extract_node(''' 5148 match x: 5149 case True: 5150 ... 5151 case False: 5152 ... 5153 case None: 5154 ... 5155 ''') 5156 >>> node.cases[0].pattern 5157 <MatchSingleton l.3 at 0x10c2282e0> 5158 >>> node.cases[1].pattern 5159 <MatchSingleton l.5 at 0x10c228af0> 5160 >>> node.cases[2].pattern 5161 <MatchSingleton l.7 at 0x10c229f90> 5162 """ 5163 5164 _other_fields = ("value",) 5165 5166 def __init__( 5167 self, 5168 *, 5169 value: Literal[True, False, None], 5170 lineno: Optional[int] = None, 5171 col_offset: Optional[int] = None, 5172 end_lineno: Optional[int] = None, 5173 end_col_offset: Optional[int] = None, 5174 parent: Optional[NodeNG] = None, 5175 ) -> None: 5176 self.value: Literal[True, False, None] = value 5177 super().__init__( 5178 lineno=lineno, 5179 col_offset=col_offset, 5180 end_lineno=end_lineno, 5181 end_col_offset=end_col_offset, 5182 parent=parent, 5183 ) 5184 5185 5186class MatchSequence(Pattern): 5187 """Class representing a :class:`ast.MatchSequence` node. 5188 5189 >>> import astroid 5190 >>> node = astroid.extract_node(''' 5191 match x: 5192 case [1, 2]: 5193 ... 5194 case (1, 2, *_): 5195 ... 5196 ''') 5197 >>> node.cases[0].pattern 5198 <MatchSequence l.3 at 0x10ca80d00> 5199 >>> node.cases[1].pattern 5200 <MatchSequence l.5 at 0x10ca80b20> 5201 """ 5202 5203 _astroid_fields = ("patterns",) 5204 5205 def __init__( 5206 self, 5207 lineno: Optional[int] = None, 5208 col_offset: Optional[int] = None, 5209 parent: Optional[NodeNG] = None, 5210 *, 5211 end_lineno: Optional[int] = None, 5212 end_col_offset: Optional[int] = None, 5213 ) -> None: 5214 self.patterns: typing.List[Pattern] 5215 super().__init__( 5216 lineno=lineno, 5217 col_offset=col_offset, 5218 end_lineno=end_lineno, 5219 end_col_offset=end_col_offset, 5220 parent=parent, 5221 ) 5222 5223 def postinit(self, *, patterns: typing.List[Pattern]) -> None: 5224 self.patterns = patterns 5225 5226 5227class MatchMapping(mixins.AssignTypeMixin, Pattern): 5228 """Class representing a :class:`ast.MatchMapping` node. 5229 5230 >>> import astroid 5231 >>> node = astroid.extract_node(''' 5232 match x: 5233 case {1: "Hello", 2: "World", 3: _, **rest}: 5234 ... 5235 ''') 5236 >>> node.cases[0].pattern 5237 <MatchMapping l.3 at 0x10c8a8850> 5238 """ 5239 5240 _astroid_fields = ("keys", "patterns", "rest") 5241 5242 def __init__( 5243 self, 5244 lineno: Optional[int] = None, 5245 col_offset: Optional[int] = None, 5246 parent: Optional[NodeNG] = None, 5247 *, 5248 end_lineno: Optional[int] = None, 5249 end_col_offset: Optional[int] = None, 5250 ) -> None: 5251 self.keys: typing.List[NodeNG] 5252 self.patterns: typing.List[Pattern] 5253 self.rest: Optional[AssignName] 5254 super().__init__( 5255 lineno=lineno, 5256 col_offset=col_offset, 5257 end_lineno=end_lineno, 5258 end_col_offset=end_col_offset, 5259 parent=parent, 5260 ) 5261 5262 def postinit( 5263 self, 5264 *, 5265 keys: typing.List[NodeNG], 5266 patterns: typing.List[Pattern], 5267 rest: Optional[AssignName], 5268 ) -> None: 5269 self.keys = keys 5270 self.patterns = patterns 5271 self.rest = rest 5272 5273 assigned_stmts: Callable[ 5274 [ 5275 "MatchMapping", 5276 AssignName, 5277 Optional[InferenceContext], 5278 Literal[None], 5279 ], 5280 Generator[NodeNG, None, None], 5281 ] 5282 5283 5284class MatchClass(Pattern): 5285 """Class representing a :class:`ast.MatchClass` node. 5286 5287 >>> import astroid 5288 >>> node = astroid.extract_node(''' 5289 match x: 5290 case Point2D(0, 0): 5291 ... 5292 case Point3D(x=0, y=0, z=0): 5293 ... 5294 ''') 5295 >>> node.cases[0].pattern 5296 <MatchClass l.3 at 0x10ca83940> 5297 >>> node.cases[1].pattern 5298 <MatchClass l.5 at 0x10ca80880> 5299 """ 5300 5301 _astroid_fields = ("cls", "patterns", "kwd_patterns") 5302 _other_fields = ("kwd_attrs",) 5303 5304 def __init__( 5305 self, 5306 lineno: Optional[int] = None, 5307 col_offset: Optional[int] = None, 5308 parent: Optional[NodeNG] = None, 5309 *, 5310 end_lineno: Optional[int] = None, 5311 end_col_offset: Optional[int] = None, 5312 ) -> None: 5313 self.cls: NodeNG 5314 self.patterns: typing.List[Pattern] 5315 self.kwd_attrs: typing.List[str] 5316 self.kwd_patterns: typing.List[Pattern] 5317 super().__init__( 5318 lineno=lineno, 5319 col_offset=col_offset, 5320 end_lineno=end_lineno, 5321 end_col_offset=end_col_offset, 5322 parent=parent, 5323 ) 5324 5325 def postinit( 5326 self, 5327 *, 5328 cls: NodeNG, 5329 patterns: typing.List[Pattern], 5330 kwd_attrs: typing.List[str], 5331 kwd_patterns: typing.List[Pattern], 5332 ) -> None: 5333 self.cls = cls 5334 self.patterns = patterns 5335 self.kwd_attrs = kwd_attrs 5336 self.kwd_patterns = kwd_patterns 5337 5338 5339class MatchStar(mixins.AssignTypeMixin, Pattern): 5340 """Class representing a :class:`ast.MatchStar` node. 5341 5342 >>> import astroid 5343 >>> node = astroid.extract_node(''' 5344 match x: 5345 case [1, *_]: 5346 ... 5347 ''') 5348 >>> node.cases[0].pattern.patterns[1] 5349 <MatchStar l.3 at 0x10ca809a0> 5350 """ 5351 5352 _astroid_fields = ("name",) 5353 5354 def __init__( 5355 self, 5356 lineno: Optional[int] = None, 5357 col_offset: Optional[int] = None, 5358 parent: Optional[NodeNG] = None, 5359 *, 5360 end_lineno: Optional[int] = None, 5361 end_col_offset: Optional[int] = None, 5362 ) -> None: 5363 self.name: Optional[AssignName] 5364 super().__init__( 5365 lineno=lineno, 5366 col_offset=col_offset, 5367 end_lineno=end_lineno, 5368 end_col_offset=end_col_offset, 5369 parent=parent, 5370 ) 5371 5372 def postinit(self, *, name: Optional[AssignName]) -> None: 5373 self.name = name 5374 5375 assigned_stmts: Callable[ 5376 [ 5377 "MatchStar", 5378 AssignName, 5379 Optional[InferenceContext], 5380 Literal[None], 5381 ], 5382 Generator[NodeNG, None, None], 5383 ] 5384 5385 5386class MatchAs(mixins.AssignTypeMixin, Pattern): 5387 """Class representing a :class:`ast.MatchAs` node. 5388 5389 >>> import astroid 5390 >>> node = astroid.extract_node(''' 5391 match x: 5392 case [1, a]: 5393 ... 5394 case {'key': b}: 5395 ... 5396 case Point2D(0, 0) as c: 5397 ... 5398 case d: 5399 ... 5400 ''') 5401 >>> node.cases[0].pattern.patterns[1] 5402 <MatchAs l.3 at 0x10d0b2da0> 5403 >>> node.cases[1].pattern.patterns[0] 5404 <MatchAs l.5 at 0x10d0b2920> 5405 >>> node.cases[2].pattern 5406 <MatchAs l.7 at 0x10d0b06a0> 5407 >>> node.cases[3].pattern 5408 <MatchAs l.9 at 0x10d09b880> 5409 """ 5410 5411 _astroid_fields = ("pattern", "name") 5412 5413 def __init__( 5414 self, 5415 lineno: Optional[int] = None, 5416 col_offset: Optional[int] = None, 5417 parent: Optional[NodeNG] = None, 5418 *, 5419 end_lineno: Optional[int] = None, 5420 end_col_offset: Optional[int] = None, 5421 ) -> None: 5422 self.pattern: Optional[Pattern] 5423 self.name: Optional[AssignName] 5424 super().__init__( 5425 lineno=lineno, 5426 col_offset=col_offset, 5427 end_lineno=end_lineno, 5428 end_col_offset=end_col_offset, 5429 parent=parent, 5430 ) 5431 5432 def postinit( 5433 self, 5434 *, 5435 pattern: Optional[Pattern], 5436 name: Optional[AssignName], 5437 ) -> None: 5438 self.pattern = pattern 5439 self.name = name 5440 5441 assigned_stmts: Callable[ 5442 [ 5443 "MatchAs", 5444 AssignName, 5445 Optional[InferenceContext], 5446 Literal[None], 5447 ], 5448 Generator[NodeNG, None, None], 5449 ] 5450 5451 5452class MatchOr(Pattern): 5453 """Class representing a :class:`ast.MatchOr` node. 5454 5455 >>> import astroid 5456 >>> node = astroid.extract_node(''' 5457 match x: 5458 case 400 | 401 | 402: 5459 ... 5460 ''') 5461 >>> node.cases[0].pattern 5462 <MatchOr l.3 at 0x10d0b0b50> 5463 """ 5464 5465 _astroid_fields = ("patterns",) 5466 5467 def __init__( 5468 self, 5469 lineno: Optional[int] = None, 5470 col_offset: Optional[int] = None, 5471 parent: Optional[NodeNG] = None, 5472 *, 5473 end_lineno: Optional[int] = None, 5474 end_col_offset: Optional[int] = None, 5475 ) -> None: 5476 self.patterns: typing.List[Pattern] 5477 super().__init__( 5478 lineno=lineno, 5479 col_offset=col_offset, 5480 end_lineno=end_lineno, 5481 end_col_offset=end_col_offset, 5482 parent=parent, 5483 ) 5484 5485 def postinit(self, *, patterns: typing.List[Pattern]) -> None: 5486 self.patterns = patterns 5487 5488 5489# constants ############################################################## 5490 5491CONST_CLS = { 5492 list: List, 5493 tuple: Tuple, 5494 dict: Dict, 5495 set: Set, 5496 type(None): Const, 5497 type(NotImplemented): Const, 5498 type(...): Const, 5499} 5500 5501 5502def _update_const_classes(): 5503 """update constant classes, so the keys of CONST_CLS can be reused""" 5504 klasses = (bool, int, float, complex, str, bytes) 5505 for kls in klasses: 5506 CONST_CLS[kls] = Const 5507 5508 5509_update_const_classes() 5510 5511 5512def _two_step_initialization(cls, value): 5513 instance = cls() 5514 instance.postinit(value) 5515 return instance 5516 5517 5518def _dict_initialization(cls, value): 5519 if isinstance(value, dict): 5520 value = tuple(value.items()) 5521 return _two_step_initialization(cls, value) 5522 5523 5524_CONST_CLS_CONSTRUCTORS = { 5525 List: _two_step_initialization, 5526 Tuple: _two_step_initialization, 5527 Dict: _dict_initialization, 5528 Set: _two_step_initialization, 5529 Const: lambda cls, value: cls(value), 5530} 5531 5532 5533def const_factory(value): 5534 """return an astroid node for a python value""" 5535 # XXX we should probably be stricter here and only consider stuff in 5536 # CONST_CLS or do better treatment: in case where value is not in CONST_CLS, 5537 # we should rather recall the builder on this value than returning an empty 5538 # node (another option being that const_factory shouldn't be called with something 5539 # not in CONST_CLS) 5540 assert not isinstance(value, NodeNG) 5541 5542 # Hack for ignoring elements of a sequence 5543 # or a mapping, in order to avoid transforming 5544 # each element to an AST. This is fixed in 2.0 5545 # and this approach is a temporary hack. 5546 if isinstance(value, (list, set, tuple, dict)): 5547 elts = [] 5548 else: 5549 elts = value 5550 5551 try: 5552 initializer_cls = CONST_CLS[value.__class__] 5553 initializer = _CONST_CLS_CONSTRUCTORS[initializer_cls] 5554 return initializer(initializer_cls, elts) 5555 except (KeyError, AttributeError): 5556 node = EmptyNode() 5557 node.object = value 5558 return node 5559 5560 5561def is_from_decorator(node): 5562 """Return True if the given node is the child of a decorator""" 5563 for parent in node.node_ancestors(): 5564 if isinstance(parent, Decorators): 5565 return True 5566 return False 5567 5568 5569def _get_if_statement_ancestor(node: NodeNG) -> Optional[If]: 5570 """Return the first parent node that is an If node (or None)""" 5571 for parent in node.node_ancestors(): 5572 if isinstance(parent, If): 5573 return parent 5574 return None 5575