Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/astroid/nodes/node_classes.py: 62%
1347 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:53 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:53 +0000
1# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
2# For details: https://github.com/pylint-dev/astroid/blob/main/LICENSE
3# Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt
5"""Module for some node classes. More nodes in scoped_nodes.py"""
7from __future__ import annotations
9import abc
10import itertools
11import sys
12import typing
13from collections.abc import Generator, Iterable, Iterator, Mapping
14from functools import cached_property, lru_cache
15from typing import (
16 TYPE_CHECKING,
17 Any,
18 Callable,
19 ClassVar,
20 Literal,
21 Optional,
22 TypeVar,
23 Union,
24)
26from astroid import decorators, util
27from astroid.bases import Instance, _infer_stmts
28from astroid.const import _EMPTY_OBJECT_MARKER, Context
29from astroid.context import InferenceContext
30from astroid.exceptions import (
31 AstroidIndexError,
32 AstroidTypeError,
33 AstroidValueError,
34 InferenceError,
35 NoDefault,
36 ParentMissingError,
37)
38from astroid.manager import AstroidManager
39from astroid.nodes import _base_nodes
40from astroid.nodes.const import OP_PRECEDENCE
41from astroid.nodes.node_ng import NodeNG
42from astroid.typing import (
43 ConstFactoryResult,
44 InferBinaryOp,
45 InferenceErrorInfo,
46 InferenceResult,
47 SuccessfulInferenceResult,
48)
50if sys.version_info >= (3, 11):
51 from typing import Self
52else:
53 from typing_extensions import Self
56if TYPE_CHECKING:
57 from astroid import nodes
58 from astroid.nodes import LocalsDictNodeNG
61def _is_const(value) -> bool:
62 return isinstance(value, tuple(CONST_CLS))
65_NodesT = TypeVar("_NodesT", bound=NodeNG)
66_BadOpMessageT = TypeVar("_BadOpMessageT", bound=util.BadOperationMessage)
68AssignedStmtsPossibleNode = Union["List", "Tuple", "AssignName", "AssignAttr", None]
69AssignedStmtsCall = Callable[
70 [
71 _NodesT,
72 AssignedStmtsPossibleNode,
73 Optional[InferenceContext],
74 Optional[typing.List[int]],
75 ],
76 Any,
77]
78InferBinaryOperation = Callable[
79 [_NodesT, Optional[InferenceContext]],
80 typing.Generator[Union[InferenceResult, _BadOpMessageT], None, None],
81]
82InferLHS = Callable[
83 [_NodesT, Optional[InferenceContext]],
84 typing.Generator[InferenceResult, None, Optional[InferenceErrorInfo]],
85]
86InferUnaryOp = Callable[[_NodesT, str], ConstFactoryResult]
89@decorators.raise_if_nothing_inferred
90def unpack_infer(stmt, context: InferenceContext | None = None):
91 """recursively generate nodes inferred by the given statement.
92 If the inferred value is a list or a tuple, recurse on the elements
93 """
94 if isinstance(stmt, (List, Tuple)):
95 for elt in stmt.elts:
96 if elt is util.Uninferable:
97 yield elt
98 continue
99 yield from unpack_infer(elt, context)
100 return {"node": stmt, "context": context}
101 # if inferred is a final node, return it and stop
102 inferred = next(stmt.infer(context), util.Uninferable)
103 if inferred is stmt:
104 yield inferred
105 return {"node": stmt, "context": context}
106 # else, infer recursively, except Uninferable object that should be returned as is
107 for inferred in stmt.infer(context):
108 if isinstance(inferred, util.UninferableBase):
109 yield inferred
110 else:
111 yield from unpack_infer(inferred, context)
113 return {"node": stmt, "context": context}
116def are_exclusive(stmt1, stmt2, exceptions: list[str] | None = None) -> bool:
117 """return true if the two given statements are mutually exclusive
119 `exceptions` may be a list of exception names. If specified, discard If
120 branches and check one of the statement is in an exception handler catching
121 one of the given exceptions.
123 algorithm :
124 1) index stmt1's parents
125 2) climb among stmt2's parents until we find a common parent
126 3) if the common parent is a If or TryExcept statement, look if nodes are
127 in exclusive branches
128 """
129 # index stmt1's parents
130 stmt1_parents = {}
131 children = {}
132 previous = stmt1
133 for node in stmt1.node_ancestors():
134 stmt1_parents[node] = 1
135 children[node] = previous
136 previous = node
137 # climb among stmt2's parents until we find a common parent
138 previous = stmt2
139 for node in stmt2.node_ancestors():
140 if node in stmt1_parents:
141 # if the common parent is a If or TryExcept statement, look if
142 # nodes are in exclusive branches
143 if isinstance(node, If) and exceptions is None:
144 c2attr, c2node = node.locate_child(previous)
145 c1attr, c1node = node.locate_child(children[node])
146 if "test" in (c1attr, c2attr):
147 # If any node is `If.test`, then it must be inclusive with
148 # the other node (`If.body` and `If.orelse`)
149 return False
150 if c1attr != c2attr:
151 # different `If` branches (`If.body` and `If.orelse`)
152 return True
153 elif isinstance(node, TryExcept):
154 c2attr, c2node = node.locate_child(previous)
155 c1attr, c1node = node.locate_child(children[node])
156 if c1node is not c2node:
157 first_in_body_caught_by_handlers = (
158 c2attr == "handlers"
159 and c1attr == "body"
160 and previous.catch(exceptions)
161 )
162 second_in_body_caught_by_handlers = (
163 c2attr == "body"
164 and c1attr == "handlers"
165 and children[node].catch(exceptions)
166 )
167 first_in_else_other_in_handlers = (
168 c2attr == "handlers" and c1attr == "orelse"
169 )
170 second_in_else_other_in_handlers = (
171 c2attr == "orelse" and c1attr == "handlers"
172 )
173 if any(
174 (
175 first_in_body_caught_by_handlers,
176 second_in_body_caught_by_handlers,
177 first_in_else_other_in_handlers,
178 second_in_else_other_in_handlers,
179 )
180 ):
181 return True
182 elif c2attr == "handlers" and c1attr == "handlers":
183 return previous is not children[node]
184 return False
185 previous = node
186 return False
189# getitem() helpers.
191_SLICE_SENTINEL = object()
194def _slice_value(index, context: InferenceContext | None = None):
195 """Get the value of the given slice index."""
197 if isinstance(index, Const):
198 if isinstance(index.value, (int, type(None))):
199 return index.value
200 elif index is None:
201 return None
202 else:
203 # Try to infer what the index actually is.
204 # Since we can't return all the possible values,
205 # we'll stop at the first possible value.
206 try:
207 inferred = next(index.infer(context=context))
208 except (InferenceError, StopIteration):
209 pass
210 else:
211 if isinstance(inferred, Const):
212 if isinstance(inferred.value, (int, type(None))):
213 return inferred.value
215 # Use a sentinel, because None can be a valid
216 # value that this function can return,
217 # as it is the case for unspecified bounds.
218 return _SLICE_SENTINEL
221def _infer_slice(node, context: InferenceContext | None = None):
222 lower = _slice_value(node.lower, context)
223 upper = _slice_value(node.upper, context)
224 step = _slice_value(node.step, context)
225 if all(elem is not _SLICE_SENTINEL for elem in (lower, upper, step)):
226 return slice(lower, upper, step)
228 raise AstroidTypeError(
229 message="Could not infer slice used in subscript",
230 node=node,
231 index=node.parent,
232 context=context,
233 )
236def _container_getitem(instance, elts, index, context: InferenceContext | None = None):
237 """Get a slice or an item, using the given *index*, for the given sequence."""
238 try:
239 if isinstance(index, Slice):
240 index_slice = _infer_slice(index, context=context)
241 new_cls = instance.__class__()
242 new_cls.elts = elts[index_slice]
243 new_cls.parent = instance.parent
244 return new_cls
245 if isinstance(index, Const):
246 return elts[index.value]
247 except ValueError as exc:
248 raise AstroidValueError(
249 message="Slice {index!r} cannot index container",
250 node=instance,
251 index=index,
252 context=context,
253 ) from exc
254 except IndexError as exc:
255 raise AstroidIndexError(
256 message="Index {index!s} out of range",
257 node=instance,
258 index=index,
259 context=context,
260 ) from exc
261 except TypeError as exc:
262 raise AstroidTypeError(
263 message="Type error {error!r}", node=instance, index=index, context=context
264 ) from exc
266 raise AstroidTypeError(f"Could not use {index} as subscript index")
269class BaseContainer(_base_nodes.ParentAssignNode, Instance, metaclass=abc.ABCMeta):
270 """Base class for Set, FrozenSet, Tuple and List."""
272 _astroid_fields = ("elts",)
274 def __init__(
275 self,
276 lineno: int | None,
277 col_offset: int | None,
278 parent: NodeNG | None,
279 *,
280 end_lineno: int | None,
281 end_col_offset: int | None,
282 ) -> None:
283 self.elts: list[SuccessfulInferenceResult] = []
284 """The elements in the node."""
286 super().__init__(
287 lineno=lineno,
288 col_offset=col_offset,
289 end_lineno=end_lineno,
290 end_col_offset=end_col_offset,
291 parent=parent,
292 )
294 def postinit(self, elts: list[SuccessfulInferenceResult]) -> None:
295 self.elts = elts
297 @classmethod
298 def from_elements(cls, elts: Iterable[Any]) -> Self:
299 """Create a node of this type from the given list of elements.
301 :param elts: The list of elements that the node should contain.
303 :returns: A new node containing the given elements.
304 """
305 node = cls(
306 lineno=None,
307 col_offset=None,
308 parent=None,
309 end_lineno=None,
310 end_col_offset=None,
311 )
312 node.elts = [const_factory(e) if _is_const(e) else e for e in elts]
313 return node
315 def itered(self):
316 """An iterator over the elements this node contains.
318 :returns: The contents of this node.
319 :rtype: iterable(NodeNG)
320 """
321 return self.elts
323 def bool_value(self, context: InferenceContext | None = None) -> bool:
324 """Determine the boolean value of this node.
326 :returns: The boolean value of this node.
327 """
328 return bool(self.elts)
330 @abc.abstractmethod
331 def pytype(self) -> str:
332 """Get the name of the type that this node represents.
334 :returns: The name of the type.
335 """
337 def get_children(self):
338 yield from self.elts
341# TODO: Move into _base_nodes. Blocked by import of _infer_stmts from bases.
342class LookupMixIn(NodeNG):
343 """Mixin to look up a name in the right scope."""
345 @lru_cache # noqa
346 def lookup(self, name: str) -> tuple[LocalsDictNodeNG, list[NodeNG]]:
347 """Lookup where the given variable is assigned.
349 The lookup starts from self's scope. If self is not a frame itself
350 and the name is found in the inner frame locals, statements will be
351 filtered to remove ignorable statements according to self's location.
353 :param name: The name of the variable to find assignments for.
355 :returns: The scope node and the list of assignments associated to the
356 given name according to the scope where it has been found (locals,
357 globals or builtin).
358 """
359 return self.scope().scope_lookup(self, name)
361 def ilookup(self, name):
362 """Lookup the inferred values of the given variable.
364 :param name: The variable name to find values for.
365 :type name: str
367 :returns: The inferred values of the statements returned from
368 :meth:`lookup`.
369 :rtype: iterable
370 """
371 frame, stmts = self.lookup(name)
372 context = InferenceContext()
373 return _infer_stmts(stmts, context, frame)
376# Name classes
379class AssignName(_base_nodes.NoChildrenNode, LookupMixIn, _base_nodes.ParentAssignNode):
380 """Variation of :class:`ast.Assign` representing assignment to a name.
382 An :class:`AssignName` is the name of something that is assigned to.
383 This includes variables defined in a function signature or in a loop.
385 >>> import astroid
386 >>> node = astroid.extract_node('variable = range(10)')
387 >>> node
388 <Assign l.1 at 0x7effe1db8550>
389 >>> list(node.get_children())
390 [<AssignName.variable l.1 at 0x7effe1db8748>, <Call l.1 at 0x7effe1db8630>]
391 >>> list(node.get_children())[0].as_string()
392 'variable'
393 """
395 _other_fields = ("name",)
397 infer_lhs: ClassVar[InferLHS[AssignName]]
399 def __init__(
400 self,
401 name: str,
402 lineno: int,
403 col_offset: int,
404 parent: NodeNG,
405 *,
406 end_lineno: int | None,
407 end_col_offset: int | None,
408 ) -> None:
409 self.name = name
410 """The name that is assigned to."""
412 super().__init__(
413 lineno=lineno,
414 col_offset=col_offset,
415 end_lineno=end_lineno,
416 end_col_offset=end_col_offset,
417 parent=parent,
418 )
420 assigned_stmts: ClassVar[AssignedStmtsCall[AssignName]]
421 """Returns the assigned statement (non inferred) according to the assignment type.
422 See astroid/protocols.py for actual implementation.
423 """
426class DelName(_base_nodes.NoChildrenNode, LookupMixIn, _base_nodes.ParentAssignNode):
427 """Variation of :class:`ast.Delete` representing deletion of a name.
429 A :class:`DelName` is the name of something that is deleted.
431 >>> import astroid
432 >>> node = astroid.extract_node("del variable #@")
433 >>> list(node.get_children())
434 [<DelName.variable l.1 at 0x7effe1da4d30>]
435 >>> list(node.get_children())[0].as_string()
436 'variable'
437 """
439 _other_fields = ("name",)
441 def __init__(
442 self,
443 name: str,
444 lineno: int,
445 col_offset: int,
446 parent: NodeNG,
447 *,
448 end_lineno: int | None,
449 end_col_offset: int | None,
450 ) -> None:
451 self.name = name
452 """The name that is being deleted."""
454 super().__init__(
455 lineno=lineno,
456 col_offset=col_offset,
457 end_lineno=end_lineno,
458 end_col_offset=end_col_offset,
459 parent=parent,
460 )
463class Name(_base_nodes.NoChildrenNode, LookupMixIn):
464 """Class representing an :class:`ast.Name` node.
466 A :class:`Name` node is something that is named, but not covered by
467 :class:`AssignName` or :class:`DelName`.
469 >>> import astroid
470 >>> node = astroid.extract_node('range(10)')
471 >>> node
472 <Call l.1 at 0x7effe1db8710>
473 >>> list(node.get_children())
474 [<Name.range l.1 at 0x7effe1db86a0>, <Const.int l.1 at 0x7effe1db8518>]
475 >>> list(node.get_children())[0].as_string()
476 'range'
477 """
479 _other_fields = ("name",)
481 def __init__(
482 self,
483 name: str,
484 lineno: int,
485 col_offset: int,
486 parent: NodeNG,
487 *,
488 end_lineno: int | None,
489 end_col_offset: int | None,
490 ) -> None:
491 self.name = name
492 """The name that this node refers to."""
494 super().__init__(
495 lineno=lineno,
496 col_offset=col_offset,
497 end_lineno=end_lineno,
498 end_col_offset=end_col_offset,
499 parent=parent,
500 )
502 def _get_name_nodes(self):
503 yield self
505 for child_node in self.get_children():
506 yield from child_node._get_name_nodes()
509class Arguments(_base_nodes.AssignTypeNode):
510 """Class representing an :class:`ast.arguments` node.
512 An :class:`Arguments` node represents that arguments in a
513 function definition.
515 >>> import astroid
516 >>> node = astroid.extract_node('def foo(bar): pass')
517 >>> node
518 <FunctionDef.foo l.1 at 0x7effe1db8198>
519 >>> node.args
520 <Arguments l.1 at 0x7effe1db82e8>
521 """
523 # Python 3.4+ uses a different approach regarding annotations,
524 # each argument is a new class, _ast.arg, which exposes an
525 # 'annotation' attribute. In astroid though, arguments are exposed
526 # as is in the Arguments node and the only way to expose annotations
527 # is by using something similar with Python 3.3:
528 # - we expose 'varargannotation' and 'kwargannotation' of annotations
529 # of varargs and kwargs.
530 # - we expose 'annotation', a list with annotations for
531 # for each normal argument. If an argument doesn't have an
532 # annotation, its value will be None.
533 _astroid_fields = (
534 "args",
535 "defaults",
536 "kwonlyargs",
537 "posonlyargs",
538 "posonlyargs_annotations",
539 "kw_defaults",
540 "annotations",
541 "varargannotation",
542 "kwargannotation",
543 "kwonlyargs_annotations",
544 "type_comment_args",
545 "type_comment_kwonlyargs",
546 "type_comment_posonlyargs",
547 )
549 _other_fields = ("vararg", "kwarg")
551 args: list[AssignName] | None
552 """The names of the required arguments.
554 Can be None if the associated function does not have a retrievable
555 signature and the arguments are therefore unknown.
556 This can happen with (builtin) functions implemented in C that have
557 incomplete signature information.
558 """
560 defaults: list[NodeNG] | None
561 """The default values for arguments that can be passed positionally."""
563 kwonlyargs: list[AssignName]
564 """The keyword arguments that cannot be passed positionally."""
566 posonlyargs: list[AssignName]
567 """The arguments that can only be passed positionally."""
569 kw_defaults: list[NodeNG | None] | None
570 """The default values for keyword arguments that cannot be passed positionally."""
572 annotations: list[NodeNG | None]
573 """The type annotations of arguments that can be passed positionally."""
575 posonlyargs_annotations: list[NodeNG | None]
576 """The type annotations of arguments that can only be passed positionally."""
578 kwonlyargs_annotations: list[NodeNG | None]
579 """The type annotations of arguments that cannot be passed positionally."""
581 type_comment_args: list[NodeNG | None]
582 """The type annotation, passed by a type comment, of each argument.
584 If an argument does not have a type comment,
585 the value for that argument will be None.
586 """
588 type_comment_kwonlyargs: list[NodeNG | None]
589 """The type annotation, passed by a type comment, of each keyword only argument.
591 If an argument does not have a type comment,
592 the value for that argument will be None.
593 """
595 type_comment_posonlyargs: list[NodeNG | None]
596 """The type annotation, passed by a type comment, of each positional argument.
598 If an argument does not have a type comment,
599 the value for that argument will be None.
600 """
602 varargannotation: NodeNG | None
603 """The type annotation for the variable length arguments."""
605 kwargannotation: NodeNG | None
606 """The type annotation for the variable length keyword arguments."""
608 def __init__(self, vararg: str | None, kwarg: str | None, parent: NodeNG) -> None:
609 """Almost all attributes can be None for living objects where introspection failed."""
610 super().__init__(
611 parent=parent,
612 lineno=None,
613 col_offset=None,
614 end_lineno=None,
615 end_col_offset=None,
616 )
618 self.vararg = vararg
619 """The name of the variable length arguments."""
621 self.kwarg = kwarg
622 """The name of the variable length keyword arguments."""
624 # pylint: disable=too-many-arguments
625 def postinit(
626 self,
627 args: list[AssignName] | None,
628 defaults: list[NodeNG] | None,
629 kwonlyargs: list[AssignName],
630 kw_defaults: list[NodeNG | None] | None,
631 annotations: list[NodeNG | None],
632 posonlyargs: list[AssignName],
633 kwonlyargs_annotations: list[NodeNG | None],
634 posonlyargs_annotations: list[NodeNG | None],
635 varargannotation: NodeNG | None = None,
636 kwargannotation: NodeNG | None = None,
637 type_comment_args: list[NodeNG | None] | None = None,
638 type_comment_kwonlyargs: list[NodeNG | None] | None = None,
639 type_comment_posonlyargs: list[NodeNG | None] | None = None,
640 ) -> None:
641 self.args = args
642 self.defaults = defaults
643 self.kwonlyargs = kwonlyargs
644 self.posonlyargs = posonlyargs
645 self.kw_defaults = kw_defaults
646 self.annotations = annotations
647 self.kwonlyargs_annotations = kwonlyargs_annotations
648 self.posonlyargs_annotations = posonlyargs_annotations
650 # Parameters that got added later and need a default
651 self.varargannotation = varargannotation
652 self.kwargannotation = kwargannotation
653 if type_comment_args is None:
654 type_comment_args = []
655 self.type_comment_args = type_comment_args
656 if type_comment_kwonlyargs is None:
657 type_comment_kwonlyargs = []
658 self.type_comment_kwonlyargs = type_comment_kwonlyargs
659 if type_comment_posonlyargs is None:
660 type_comment_posonlyargs = []
661 self.type_comment_posonlyargs = type_comment_posonlyargs
663 assigned_stmts: ClassVar[AssignedStmtsCall[Arguments]]
664 """Returns the assigned statement (non inferred) according to the assignment type.
665 See astroid/protocols.py for actual implementation.
666 """
668 def _infer_name(self, frame, name):
669 if self.parent is frame:
670 return name
671 return None
673 @cached_property
674 def fromlineno(self) -> int:
675 """The first line that this node appears on in the source code.
677 Can also return 0 if the line can not be determined.
678 """
679 lineno = super().fromlineno
680 return max(lineno, self.parent.fromlineno or 0)
682 @cached_property
683 def arguments(self):
684 """Get all the arguments for this node, including positional only and positional and keyword"""
685 return list(itertools.chain((self.posonlyargs or ()), self.args or ()))
687 def format_args(self, *, skippable_names: set[str] | None = None) -> str:
688 """Get the arguments formatted as string.
690 :returns: The formatted arguments.
691 :rtype: str
692 """
693 result = []
694 positional_only_defaults = []
695 positional_or_keyword_defaults = self.defaults
696 if self.defaults:
697 args = self.args or []
698 positional_or_keyword_defaults = self.defaults[-len(args) :]
699 positional_only_defaults = self.defaults[: len(self.defaults) - len(args)]
701 if self.posonlyargs:
702 result.append(
703 _format_args(
704 self.posonlyargs,
705 positional_only_defaults,
706 self.posonlyargs_annotations,
707 skippable_names=skippable_names,
708 )
709 )
710 result.append("/")
711 if self.args:
712 result.append(
713 _format_args(
714 self.args,
715 positional_or_keyword_defaults,
716 getattr(self, "annotations", None),
717 skippable_names=skippable_names,
718 )
719 )
720 if self.vararg:
721 result.append(f"*{self.vararg}")
722 if self.kwonlyargs:
723 if not self.vararg:
724 result.append("*")
725 result.append(
726 _format_args(
727 self.kwonlyargs,
728 self.kw_defaults,
729 self.kwonlyargs_annotations,
730 skippable_names=skippable_names,
731 )
732 )
733 if self.kwarg:
734 result.append(f"**{self.kwarg}")
735 return ", ".join(result)
737 def _get_arguments_data(
738 self,
739 ) -> tuple[
740 dict[str, tuple[str | None, str | None]],
741 dict[str, tuple[str | None, str | None]],
742 ]:
743 """Get the arguments as dictionary with information about typing and defaults.
745 The return tuple contains a dictionary for positional and keyword arguments with their typing
746 and their default value, if any.
747 The method follows a similar order as format_args but instead of formatting into a string it
748 returns the data that is used to do so.
749 """
750 pos_only: dict[str, tuple[str | None, str | None]] = {}
751 kw_only: dict[str, tuple[str | None, str | None]] = {}
753 # Setup and match defaults with arguments
754 positional_only_defaults = []
755 positional_or_keyword_defaults = self.defaults
756 if self.defaults:
757 args = self.args or []
758 positional_or_keyword_defaults = self.defaults[-len(args) :]
759 positional_only_defaults = self.defaults[: len(self.defaults) - len(args)]
761 for index, posonly in enumerate(self.posonlyargs):
762 annotation, default = self.posonlyargs_annotations[index], None
763 if annotation is not None:
764 annotation = annotation.as_string()
765 if positional_only_defaults:
766 default = positional_only_defaults[index].as_string()
767 pos_only[posonly.name] = (annotation, default)
769 for index, arg in enumerate(self.args):
770 annotation, default = self.annotations[index], None
771 if annotation is not None:
772 annotation = annotation.as_string()
773 if positional_or_keyword_defaults:
774 defaults_offset = len(self.args) - len(positional_or_keyword_defaults)
775 default_index = index - defaults_offset
776 if (
777 default_index > -1
778 and positional_or_keyword_defaults[default_index] is not None
779 ):
780 default = positional_or_keyword_defaults[default_index].as_string()
781 pos_only[arg.name] = (annotation, default)
783 if self.vararg:
784 annotation = self.varargannotation
785 if annotation is not None:
786 annotation = annotation.as_string()
787 pos_only[self.vararg] = (annotation, None)
789 for index, kwarg in enumerate(self.kwonlyargs):
790 annotation = self.kwonlyargs_annotations[index]
791 if annotation is not None:
792 annotation = annotation.as_string()
793 default = self.kw_defaults[index]
794 if default is not None:
795 default = default.as_string()
796 kw_only[kwarg.name] = (annotation, default)
798 if self.kwarg:
799 annotation = self.kwargannotation
800 if annotation is not None:
801 annotation = annotation.as_string()
802 kw_only[self.kwarg] = (annotation, None)
804 return pos_only, kw_only
806 def default_value(self, argname):
807 """Get the default value for an argument.
809 :param argname: The name of the argument to get the default value for.
810 :type argname: str
812 :raises NoDefault: If there is no default value defined for the
813 given argument.
814 """
815 args = self.arguments
816 index = _find_arg(argname, args)[0]
817 if index is not None:
818 idx = index - (len(args) - len(self.defaults))
819 if idx >= 0:
820 return self.defaults[idx]
821 index = _find_arg(argname, self.kwonlyargs)[0]
822 if index is not None and self.kw_defaults[index] is not None:
823 return self.kw_defaults[index]
824 raise NoDefault(func=self.parent, name=argname)
826 def is_argument(self, name) -> bool:
827 """Check if the given name is defined in the arguments.
829 :param name: The name to check for.
830 :type name: str
832 :returns: Whether the given name is defined in the arguments,
833 """
834 if name == self.vararg:
835 return True
836 if name == self.kwarg:
837 return True
838 return (
839 self.find_argname(name, rec=True)[1] is not None
840 or self.kwonlyargs
841 and _find_arg(name, self.kwonlyargs, rec=True)[1] is not None
842 )
844 def find_argname(self, argname, rec=False):
845 """Get the index and :class:`AssignName` node for given name.
847 :param argname: The name of the argument to search for.
848 :type argname: str
850 :param rec: Whether or not to include arguments in unpacked tuples
851 in the search.
852 :type rec: bool
854 :returns: The index and node for the argument.
855 :rtype: tuple(str or None, AssignName or None)
856 """
857 if self.arguments:
858 return _find_arg(argname, self.arguments, rec)
859 return None, None
861 def get_children(self):
862 yield from self.posonlyargs or ()
864 for elt in self.posonlyargs_annotations:
865 if elt is not None:
866 yield elt
868 yield from self.args or ()
870 if self.defaults is not None:
871 yield from self.defaults
872 yield from self.kwonlyargs
874 for elt in self.kw_defaults or ():
875 if elt is not None:
876 yield elt
878 for elt in self.annotations:
879 if elt is not None:
880 yield elt
882 if self.varargannotation is not None:
883 yield self.varargannotation
885 if self.kwargannotation is not None:
886 yield self.kwargannotation
888 for elt in self.kwonlyargs_annotations:
889 if elt is not None:
890 yield elt
893def _find_arg(argname, args, rec=False):
894 for i, arg in enumerate(args):
895 if isinstance(arg, Tuple):
896 if rec:
897 found = _find_arg(argname, arg.elts)
898 if found[0] is not None:
899 return found
900 elif arg.name == argname:
901 return i, arg
902 return None, None
905def _format_args(
906 args, defaults=None, annotations=None, skippable_names: set[str] | None = None
907) -> str:
908 if skippable_names is None:
909 skippable_names = set()
910 values = []
911 if args is None:
912 return ""
913 if annotations is None:
914 annotations = []
915 if defaults is not None:
916 default_offset = len(args) - len(defaults)
917 packed = itertools.zip_longest(args, annotations)
918 for i, (arg, annotation) in enumerate(packed):
919 if arg.name in skippable_names:
920 continue
921 if isinstance(arg, Tuple):
922 values.append(f"({_format_args(arg.elts)})")
923 else:
924 argname = arg.name
925 default_sep = "="
926 if annotation is not None:
927 argname += ": " + annotation.as_string()
928 default_sep = " = "
929 values.append(argname)
931 if defaults is not None and i >= default_offset:
932 if defaults[i - default_offset] is not None:
933 values[-1] += default_sep + defaults[i - default_offset].as_string()
934 return ", ".join(values)
937class AssignAttr(_base_nodes.ParentAssignNode):
938 """Variation of :class:`ast.Assign` representing assignment to an attribute.
940 >>> import astroid
941 >>> node = astroid.extract_node('self.attribute = range(10)')
942 >>> node
943 <Assign l.1 at 0x7effe1d521d0>
944 >>> list(node.get_children())
945 [<AssignAttr.attribute l.1 at 0x7effe1d52320>, <Call l.1 at 0x7effe1d522e8>]
946 >>> list(node.get_children())[0].as_string()
947 'self.attribute'
948 """
950 _astroid_fields = ("expr",)
951 _other_fields = ("attrname",)
953 infer_lhs: ClassVar[InferLHS[AssignAttr]]
955 expr: NodeNG
956 """What has the attribute that is being assigned to."""
958 def __init__(
959 self,
960 attrname: str,
961 lineno: int,
962 col_offset: int,
963 parent: NodeNG,
964 *,
965 end_lineno: int | None,
966 end_col_offset: int | None,
967 ) -> None:
968 self.attrname = attrname
969 """The name of the attribute being assigned to."""
971 super().__init__(
972 lineno=lineno,
973 col_offset=col_offset,
974 end_lineno=end_lineno,
975 end_col_offset=end_col_offset,
976 parent=parent,
977 )
979 def postinit(self, expr: NodeNG) -> None:
980 self.expr = expr
982 assigned_stmts: ClassVar[AssignedStmtsCall[AssignAttr]]
983 """Returns the assigned statement (non inferred) according to the assignment type.
984 See astroid/protocols.py for actual implementation.
985 """
987 def get_children(self):
988 yield self.expr
991class Assert(_base_nodes.Statement):
992 """Class representing an :class:`ast.Assert` node.
994 An :class:`Assert` node represents an assert statement.
996 >>> import astroid
997 >>> node = astroid.extract_node('assert len(things) == 10, "Not enough things"')
998 >>> node
999 <Assert l.1 at 0x7effe1d527b8>
1000 """
1002 _astroid_fields = ("test", "fail")
1004 test: NodeNG
1005 """The test that passes or fails the assertion."""
1007 fail: NodeNG | None
1008 """The message shown when the assertion fails."""
1010 def postinit(self, test: NodeNG, fail: NodeNG | None) -> None:
1011 self.fail = fail
1012 self.test = test
1014 def get_children(self):
1015 yield self.test
1017 if self.fail is not None:
1018 yield self.fail
1021class Assign(_base_nodes.AssignTypeNode, _base_nodes.Statement):
1022 """Class representing an :class:`ast.Assign` node.
1024 An :class:`Assign` is a statement where something is explicitly
1025 asssigned to.
1027 >>> import astroid
1028 >>> node = astroid.extract_node('variable = range(10)')
1029 >>> node
1030 <Assign l.1 at 0x7effe1db8550>
1031 """
1033 targets: list[NodeNG]
1034 """What is being assigned to."""
1036 value: NodeNG
1037 """The value being assigned to the variables."""
1039 type_annotation: NodeNG | None
1040 """If present, this will contain the type annotation passed by a type comment"""
1042 _astroid_fields = ("targets", "value")
1043 _other_other_fields = ("type_annotation",)
1045 def postinit(
1046 self,
1047 targets: list[NodeNG],
1048 value: NodeNG,
1049 type_annotation: NodeNG | None,
1050 ) -> None:
1051 self.targets = targets
1052 self.value = value
1053 self.type_annotation = type_annotation
1055 assigned_stmts: ClassVar[AssignedStmtsCall[Assign]]
1056 """Returns the assigned statement (non inferred) according to the assignment type.
1057 See astroid/protocols.py for actual implementation.
1058 """
1060 def get_children(self):
1061 yield from self.targets
1063 yield self.value
1065 @cached_property
1066 def _assign_nodes_in_scope(self) -> list[nodes.Assign]:
1067 return [self, *self.value._assign_nodes_in_scope]
1069 def _get_yield_nodes_skip_lambdas(self):
1070 yield from self.value._get_yield_nodes_skip_lambdas()
1073class AnnAssign(_base_nodes.AssignTypeNode, _base_nodes.Statement):
1074 """Class representing an :class:`ast.AnnAssign` node.
1076 An :class:`AnnAssign` is an assignment with a type annotation.
1078 >>> import astroid
1079 >>> node = astroid.extract_node('variable: List[int] = range(10)')
1080 >>> node
1081 <AnnAssign l.1 at 0x7effe1d4c630>
1082 """
1084 _astroid_fields = ("target", "annotation", "value")
1085 _other_fields = ("simple",)
1087 target: Name | Attribute | Subscript
1088 """What is being assigned to."""
1090 annotation: NodeNG
1091 """The type annotation of what is being assigned to."""
1093 value: NodeNG | None
1094 """The value being assigned to the variables."""
1096 simple: int
1097 """Whether :attr:`target` is a pure name or a complex statement."""
1099 def postinit(
1100 self,
1101 target: Name | Attribute | Subscript,
1102 annotation: NodeNG,
1103 simple: int,
1104 value: NodeNG | None,
1105 ) -> None:
1106 self.target = target
1107 self.annotation = annotation
1108 self.value = value
1109 self.simple = simple
1111 assigned_stmts: ClassVar[AssignedStmtsCall[AnnAssign]]
1112 """Returns the assigned statement (non inferred) according to the assignment type.
1113 See astroid/protocols.py for actual implementation.
1114 """
1116 def get_children(self):
1117 yield self.target
1118 yield self.annotation
1120 if self.value is not None:
1121 yield self.value
1124class AugAssign(_base_nodes.AssignTypeNode, _base_nodes.Statement):
1125 """Class representing an :class:`ast.AugAssign` node.
1127 An :class:`AugAssign` is an assignment paired with an operator.
1129 >>> import astroid
1130 >>> node = astroid.extract_node('variable += 1')
1131 >>> node
1132 <AugAssign l.1 at 0x7effe1db4d68>
1133 """
1135 _astroid_fields = ("target", "value")
1136 _other_fields = ("op",)
1138 target: Name | Attribute | Subscript
1139 """What is being assigned to."""
1141 value: NodeNG
1142 """The value being assigned to the variable."""
1144 def __init__(
1145 self,
1146 op: str,
1147 lineno: int,
1148 col_offset: int,
1149 parent: NodeNG,
1150 *,
1151 end_lineno: int | None,
1152 end_col_offset: int | None,
1153 ) -> None:
1154 self.op = op
1155 """The operator that is being combined with the assignment.
1157 This includes the equals sign.
1158 """
1160 super().__init__(
1161 lineno=lineno,
1162 col_offset=col_offset,
1163 end_lineno=end_lineno,
1164 end_col_offset=end_col_offset,
1165 parent=parent,
1166 )
1168 def postinit(self, target: Name | Attribute | Subscript, value: NodeNG) -> None:
1169 self.target = target
1170 self.value = value
1172 assigned_stmts: ClassVar[AssignedStmtsCall[AugAssign]]
1173 """Returns the assigned statement (non inferred) according to the assignment type.
1174 See astroid/protocols.py for actual implementation.
1175 """
1177 # This is set by inference.py
1178 _infer_augassign: ClassVar[
1179 InferBinaryOperation[AugAssign, util.BadBinaryOperationMessage]
1180 ]
1182 def type_errors(self, context: InferenceContext | None = None):
1183 """Get a list of type errors which can occur during inference.
1185 Each TypeError is represented by a :class:`BadBinaryOperationMessage` ,
1186 which holds the original exception.
1188 :returns: The list of possible type errors.
1189 :rtype: list(BadBinaryOperationMessage)
1190 """
1191 try:
1192 results = self._infer_augassign(context=context)
1193 return [
1194 result
1195 for result in results
1196 if isinstance(result, util.BadBinaryOperationMessage)
1197 ]
1198 except InferenceError:
1199 return []
1201 def get_children(self):
1202 yield self.target
1203 yield self.value
1205 def _get_yield_nodes_skip_lambdas(self):
1206 """An AugAssign node can contain a Yield node in the value"""
1207 yield from self.value._get_yield_nodes_skip_lambdas()
1208 yield from super()._get_yield_nodes_skip_lambdas()
1211class BinOp(NodeNG):
1212 """Class representing an :class:`ast.BinOp` node.
1214 A :class:`BinOp` node is an application of a binary operator.
1216 >>> import astroid
1217 >>> node = astroid.extract_node('a + b')
1218 >>> node
1219 <BinOp l.1 at 0x7f23b2e8cfd0>
1220 """
1222 _astroid_fields = ("left", "right")
1223 _other_fields = ("op",)
1225 left: NodeNG
1226 """What is being applied to the operator on the left side."""
1228 right: NodeNG
1229 """What is being applied to the operator on the right side."""
1231 def __init__(
1232 self,
1233 op: str,
1234 lineno: int,
1235 col_offset: int,
1236 parent: NodeNG,
1237 *,
1238 end_lineno: int | None,
1239 end_col_offset: int | None,
1240 ) -> None:
1241 self.op = op
1242 """The operator."""
1244 super().__init__(
1245 lineno=lineno,
1246 col_offset=col_offset,
1247 end_lineno=end_lineno,
1248 end_col_offset=end_col_offset,
1249 parent=parent,
1250 )
1252 def postinit(self, left: NodeNG, right: NodeNG) -> None:
1253 self.left = left
1254 self.right = right
1256 # This is set by inference.py
1257 _infer_binop: ClassVar[InferBinaryOperation[BinOp, util.BadBinaryOperationMessage]]
1259 def type_errors(self, context: InferenceContext | None = None):
1260 """Get a list of type errors which can occur during inference.
1262 Each TypeError is represented by a :class:`BadBinaryOperationMessage`,
1263 which holds the original exception.
1265 :returns: The list of possible type errors.
1266 :rtype: list(BadBinaryOperationMessage)
1267 """
1268 try:
1269 results = self._infer_binop(context=context)
1270 return [
1271 result
1272 for result in results
1273 if isinstance(result, util.BadBinaryOperationMessage)
1274 ]
1275 except InferenceError:
1276 return []
1278 def get_children(self):
1279 yield self.left
1280 yield self.right
1282 def op_precedence(self):
1283 return OP_PRECEDENCE[self.op]
1285 def op_left_associative(self) -> bool:
1286 # 2**3**4 == 2**(3**4)
1287 return self.op != "**"
1290class BoolOp(NodeNG):
1291 """Class representing an :class:`ast.BoolOp` node.
1293 A :class:`BoolOp` is an application of a boolean operator.
1295 >>> import astroid
1296 >>> node = astroid.extract_node('a and b')
1297 >>> node
1298 <BinOp l.1 at 0x7f23b2e71c50>
1299 """
1301 _astroid_fields = ("values",)
1302 _other_fields = ("op",)
1304 @decorators.deprecate_default_argument_values(op="str")
1305 def __init__(
1306 self,
1307 op: str | None = None,
1308 lineno: int | None = None,
1309 col_offset: int | None = None,
1310 parent: NodeNG | None = None,
1311 *,
1312 end_lineno: int | None = None,
1313 end_col_offset: int | None = None,
1314 ) -> None:
1315 """
1316 :param op: The operator.
1318 :param lineno: The line that this node appears on in the source code.
1320 :param col_offset: The column that this node appears on in the
1321 source code.
1323 :param parent: The parent node in the syntax tree.
1325 :param end_lineno: The last line this node appears on in the source code.
1327 :param end_col_offset: The end column this node appears on in the
1328 source code. Note: This is after the last symbol.
1329 """
1330 self.op: str | None = op
1331 """The operator."""
1333 self.values: list[NodeNG] = []
1334 """The values being applied to the operator."""
1336 super().__init__(
1337 lineno=lineno,
1338 col_offset=col_offset,
1339 end_lineno=end_lineno,
1340 end_col_offset=end_col_offset,
1341 parent=parent,
1342 )
1344 def postinit(self, values: list[NodeNG] | None = None) -> None:
1345 """Do some setup after initialisation.
1347 :param values: The values being applied to the operator.
1348 """
1349 if values is not None:
1350 self.values = values
1352 def get_children(self):
1353 yield from self.values
1355 def op_precedence(self):
1356 return OP_PRECEDENCE[self.op]
1359class Break(_base_nodes.NoChildrenNode, _base_nodes.Statement):
1360 """Class representing an :class:`ast.Break` node.
1362 >>> import astroid
1363 >>> node = astroid.extract_node('break')
1364 >>> node
1365 <Break l.1 at 0x7f23b2e9e5c0>
1366 """
1369class Call(NodeNG):
1370 """Class representing an :class:`ast.Call` node.
1372 A :class:`Call` node is a call to a function, method, etc.
1374 >>> import astroid
1375 >>> node = astroid.extract_node('function()')
1376 >>> node
1377 <Call l.1 at 0x7f23b2e71eb8>
1378 """
1380 _astroid_fields = ("func", "args", "keywords")
1382 func: NodeNG
1383 """What is being called."""
1385 args: list[NodeNG]
1386 """The positional arguments being given to the call."""
1388 keywords: list[Keyword]
1389 """The keyword arguments being given to the call."""
1391 def postinit(
1392 self, func: NodeNG, args: list[NodeNG], keywords: list[Keyword]
1393 ) -> None:
1394 self.func = func
1395 self.args = args
1396 self.keywords = keywords
1398 @property
1399 def starargs(self) -> list[Starred]:
1400 """The positional arguments that unpack something."""
1401 return [arg for arg in self.args if isinstance(arg, Starred)]
1403 @property
1404 def kwargs(self) -> list[Keyword]:
1405 """The keyword arguments that unpack something."""
1406 return [keyword for keyword in self.keywords if keyword.arg is None]
1408 def get_children(self):
1409 yield self.func
1411 yield from self.args
1413 yield from self.keywords
1416class Compare(NodeNG):
1417 """Class representing an :class:`ast.Compare` node.
1419 A :class:`Compare` node indicates a comparison.
1421 >>> import astroid
1422 >>> node = astroid.extract_node('a <= b <= c')
1423 >>> node
1424 <Compare l.1 at 0x7f23b2e9e6d8>
1425 >>> node.ops
1426 [('<=', <Name.b l.1 at 0x7f23b2e9e2b0>), ('<=', <Name.c l.1 at 0x7f23b2e9e390>)]
1427 """
1429 _astroid_fields = ("left", "ops")
1431 left: NodeNG
1432 """The value at the left being applied to a comparison operator."""
1434 ops: list[tuple[str, NodeNG]]
1435 """The remainder of the operators and their relevant right hand value."""
1437 def postinit(self, left: NodeNG, ops: list[tuple[str, NodeNG]]) -> None:
1438 self.left = left
1439 self.ops = ops
1441 def get_children(self):
1442 """Get the child nodes below this node.
1444 Overridden to handle the tuple fields and skip returning the operator
1445 strings.
1447 :returns: The children.
1448 :rtype: iterable(NodeNG)
1449 """
1450 yield self.left
1451 for _, comparator in self.ops:
1452 yield comparator # we don't want the 'op'
1454 def last_child(self):
1455 """An optimized version of list(get_children())[-1]
1457 :returns: The last child.
1458 :rtype: NodeNG
1459 """
1460 # XXX maybe if self.ops:
1461 return self.ops[-1][1]
1462 # return self.left
1465class Comprehension(NodeNG):
1466 """Class representing an :class:`ast.comprehension` node.
1468 A :class:`Comprehension` indicates the loop inside any type of
1469 comprehension including generator expressions.
1471 >>> import astroid
1472 >>> node = astroid.extract_node('[x for x in some_values]')
1473 >>> list(node.get_children())
1474 [<Name.x l.1 at 0x7f23b2e352b0>, <Comprehension l.1 at 0x7f23b2e35320>]
1475 >>> list(node.get_children())[1].as_string()
1476 'for x in some_values'
1477 """
1479 _astroid_fields = ("target", "iter", "ifs")
1480 _other_fields = ("is_async",)
1482 optional_assign = True
1483 """Whether this node optionally assigns a variable."""
1485 target: NodeNG
1486 """What is assigned to by the comprehension."""
1488 iter: NodeNG
1489 """What is iterated over by the comprehension."""
1491 ifs: list[NodeNG]
1492 """The contents of any if statements that filter the comprehension."""
1494 is_async: bool
1495 """Whether this is an asynchronous comprehension or not."""
1497 def postinit(
1498 self,
1499 target: NodeNG,
1500 iter: NodeNG, # pylint: disable = redefined-builtin
1501 ifs: list[NodeNG],
1502 is_async: bool,
1503 ) -> None:
1504 self.target = target
1505 self.iter = iter
1506 self.ifs = ifs
1507 self.is_async = is_async
1509 assigned_stmts: ClassVar[AssignedStmtsCall[Comprehension]]
1510 """Returns the assigned statement (non inferred) according to the assignment type.
1511 See astroid/protocols.py for actual implementation.
1512 """
1514 def assign_type(self):
1515 """The type of assignment that this node performs.
1517 :returns: The assignment type.
1518 :rtype: NodeNG
1519 """
1520 return self
1522 def _get_filtered_stmts(
1523 self, lookup_node, node, stmts, mystmt: _base_nodes.Statement | None
1524 ):
1525 """method used in filter_stmts"""
1526 if self is mystmt:
1527 if isinstance(lookup_node, (Const, Name)):
1528 return [lookup_node], True
1530 elif self.statement(future=True) is mystmt:
1531 # original node's statement is the assignment, only keeps
1532 # current node (gen exp, list comp)
1534 return [node], True
1536 return stmts, False
1538 def get_children(self):
1539 yield self.target
1540 yield self.iter
1542 yield from self.ifs
1545class Const(_base_nodes.NoChildrenNode, Instance):
1546 """Class representing any constant including num, str, bool, None, bytes.
1548 >>> import astroid
1549 >>> node = astroid.extract_node('(5, "This is a string.", True, None, b"bytes")')
1550 >>> node
1551 <Tuple.tuple l.1 at 0x7f23b2e358d0>
1552 >>> list(node.get_children())
1553 [<Const.int l.1 at 0x7f23b2e35940>,
1554 <Const.str l.1 at 0x7f23b2e35978>,
1555 <Const.bool l.1 at 0x7f23b2e359b0>,
1556 <Const.NoneType l.1 at 0x7f23b2e359e8>,
1557 <Const.bytes l.1 at 0x7f23b2e35a20>]
1558 """
1560 _other_fields = ("value", "kind")
1562 def __init__(
1563 self,
1564 value: Any,
1565 lineno: int | None = None,
1566 col_offset: int | None = None,
1567 parent: NodeNG | None = None,
1568 kind: str | None = None,
1569 *,
1570 end_lineno: int | None = None,
1571 end_col_offset: int | None = None,
1572 ) -> None:
1573 """
1574 :param value: The value that the constant represents.
1576 :param lineno: The line that this node appears on in the source code.
1578 :param col_offset: The column that this node appears on in the
1579 source code.
1581 :param parent: The parent node in the syntax tree.
1583 :param kind: The string prefix. "u" for u-prefixed strings and ``None`` otherwise. Python 3.8+ only.
1585 :param end_lineno: The last line this node appears on in the source code.
1587 :param end_col_offset: The end column this node appears on in the
1588 source code. Note: This is after the last symbol.
1589 """
1590 self.value: Any = value
1591 """The value that the constant represents."""
1593 self.kind: str | None = kind # can be None
1594 """"The string prefix. "u" for u-prefixed strings and ``None`` otherwise. Python 3.8+ only."""
1596 super().__init__(
1597 lineno=lineno,
1598 col_offset=col_offset,
1599 end_lineno=end_lineno,
1600 end_col_offset=end_col_offset,
1601 parent=parent,
1602 )
1604 Instance.__init__(self, None)
1606 infer_unary_op: ClassVar[InferUnaryOp[Const]]
1607 infer_binary_op: ClassVar[InferBinaryOp[Const]]
1609 def __getattr__(self, name):
1610 # This is needed because of Proxy's __getattr__ method.
1611 # Calling object.__new__ on this class without calling
1612 # __init__ would result in an infinite loop otherwise
1613 # since __getattr__ is called when an attribute doesn't
1614 # exist and self._proxied indirectly calls self.value
1615 # and Proxy __getattr__ calls self.value
1616 if name == "value":
1617 raise AttributeError
1618 return super().__getattr__(name)
1620 def getitem(self, index, context: InferenceContext | None = None):
1621 """Get an item from this node if subscriptable.
1623 :param index: The node to use as a subscript index.
1624 :type index: Const or Slice
1626 :raises AstroidTypeError: When the given index cannot be used as a
1627 subscript index, or if this node is not subscriptable.
1628 """
1629 if isinstance(index, Const):
1630 index_value = index.value
1631 elif isinstance(index, Slice):
1632 index_value = _infer_slice(index, context=context)
1634 else:
1635 raise AstroidTypeError(
1636 f"Could not use type {type(index)} as subscript index"
1637 )
1639 try:
1640 if isinstance(self.value, (str, bytes)):
1641 return Const(self.value[index_value])
1642 except ValueError as exc:
1643 raise AstroidValueError(
1644 f"Could not index {self.value!r} with {index_value!r}"
1645 ) from exc
1646 except IndexError as exc:
1647 raise AstroidIndexError(
1648 message="Index {index!r} out of range",
1649 node=self,
1650 index=index,
1651 context=context,
1652 ) from exc
1653 except TypeError as exc:
1654 raise AstroidTypeError(
1655 message="Type error {error!r}", node=self, index=index, context=context
1656 ) from exc
1658 raise AstroidTypeError(f"{self!r} (value={self.value})")
1660 def has_dynamic_getattr(self) -> bool:
1661 """Check if the node has a custom __getattr__ or __getattribute__.
1663 :returns: Whether the class has a custom __getattr__ or __getattribute__.
1664 For a :class:`Const` this is always ``False``.
1665 """
1666 return False
1668 def itered(self):
1669 """An iterator over the elements this node contains.
1671 :returns: The contents of this node.
1672 :rtype: iterable(Const)
1674 :raises TypeError: If this node does not represent something that is iterable.
1675 """
1676 if isinstance(self.value, str):
1677 return [const_factory(elem) for elem in self.value]
1678 raise TypeError(f"Cannot iterate over type {type(self.value)!r}")
1680 def pytype(self) -> str:
1681 """Get the name of the type that this node represents.
1683 :returns: The name of the type.
1684 """
1685 return self._proxied.qname()
1687 def bool_value(self, context: InferenceContext | None = None):
1688 """Determine the boolean value of this node.
1690 :returns: The boolean value of this node.
1691 :rtype: bool
1692 """
1693 return bool(self.value)
1696class Continue(_base_nodes.NoChildrenNode, _base_nodes.Statement):
1697 """Class representing an :class:`ast.Continue` node.
1699 >>> import astroid
1700 >>> node = astroid.extract_node('continue')
1701 >>> node
1702 <Continue l.1 at 0x7f23b2e35588>
1703 """
1706class Decorators(NodeNG):
1707 """A node representing a list of decorators.
1709 A :class:`Decorators` is the decorators that are applied to
1710 a method or function.
1712 >>> import astroid
1713 >>> node = astroid.extract_node('''
1714 @property
1715 def my_property(self):
1716 return 3
1717 ''')
1718 >>> node
1719 <FunctionDef.my_property l.2 at 0x7f23b2e35d30>
1720 >>> list(node.get_children())[0]
1721 <Decorators l.1 at 0x7f23b2e35d68>
1722 """
1724 _astroid_fields = ("nodes",)
1726 nodes: list[NodeNG]
1727 """The decorators that this node contains."""
1729 def postinit(self, nodes: list[NodeNG]) -> None:
1730 self.nodes = nodes
1732 def scope(self) -> LocalsDictNodeNG:
1733 """The first parent node defining a new scope.
1734 These can be Module, FunctionDef, ClassDef, Lambda, or GeneratorExp nodes.
1736 :returns: The first parent scope node.
1737 """
1738 # skip the function node to go directly to the upper level scope
1739 if not self.parent:
1740 raise ParentMissingError(target=self)
1741 if not self.parent.parent:
1742 raise ParentMissingError(target=self.parent)
1743 return self.parent.parent.scope()
1745 def get_children(self):
1746 yield from self.nodes
1749class DelAttr(_base_nodes.ParentAssignNode):
1750 """Variation of :class:`ast.Delete` representing deletion of an attribute.
1752 >>> import astroid
1753 >>> node = astroid.extract_node('del self.attr')
1754 >>> node
1755 <Delete l.1 at 0x7f23b2e35f60>
1756 >>> list(node.get_children())[0]
1757 <DelAttr.attr l.1 at 0x7f23b2e411d0>
1758 """
1760 _astroid_fields = ("expr",)
1761 _other_fields = ("attrname",)
1763 expr: NodeNG
1764 """The name that this node represents."""
1766 def __init__(
1767 self,
1768 attrname: str,
1769 lineno: int,
1770 col_offset: int,
1771 parent: NodeNG,
1772 *,
1773 end_lineno: int | None,
1774 end_col_offset: int | None,
1775 ) -> None:
1776 self.attrname = attrname
1777 """The name of the attribute that is being deleted."""
1779 super().__init__(
1780 lineno=lineno,
1781 col_offset=col_offset,
1782 end_lineno=end_lineno,
1783 end_col_offset=end_col_offset,
1784 parent=parent,
1785 )
1787 def postinit(self, expr: NodeNG) -> None:
1788 self.expr = expr
1790 def get_children(self):
1791 yield self.expr
1794class Delete(_base_nodes.AssignTypeNode, _base_nodes.Statement):
1795 """Class representing an :class:`ast.Delete` node.
1797 A :class:`Delete` is a ``del`` statement this is deleting something.
1799 >>> import astroid
1800 >>> node = astroid.extract_node('del self.attr')
1801 >>> node
1802 <Delete l.1 at 0x7f23b2e35f60>
1803 """
1805 _astroid_fields = ("targets",)
1807 def __init__(
1808 self,
1809 lineno: int,
1810 col_offset: int,
1811 parent: NodeNG,
1812 *,
1813 end_lineno: int | None,
1814 end_col_offset: int | None,
1815 ) -> None:
1816 self.targets: list[NodeNG] = []
1817 """What is being deleted."""
1819 super().__init__(
1820 lineno=lineno,
1821 col_offset=col_offset,
1822 end_lineno=end_lineno,
1823 end_col_offset=end_col_offset,
1824 parent=parent,
1825 )
1827 def postinit(self, targets: list[NodeNG]) -> None:
1828 self.targets = targets
1830 def get_children(self):
1831 yield from self.targets
1834class Dict(NodeNG, Instance):
1835 """Class representing an :class:`ast.Dict` node.
1837 A :class:`Dict` is a dictionary that is created with ``{}`` syntax.
1839 >>> import astroid
1840 >>> node = astroid.extract_node('{1: "1"}')
1841 >>> node
1842 <Dict.dict l.1 at 0x7f23b2e35cc0>
1843 """
1845 _astroid_fields = ("items",)
1847 def __init__(
1848 self,
1849 lineno: int | None,
1850 col_offset: int | None,
1851 parent: NodeNG | None,
1852 *,
1853 end_lineno: int | None,
1854 end_col_offset: int | None,
1855 ) -> None:
1856 self.items: list[tuple[InferenceResult, InferenceResult]] = []
1857 """The key-value pairs contained in the dictionary."""
1859 super().__init__(
1860 lineno=lineno,
1861 col_offset=col_offset,
1862 end_lineno=end_lineno,
1863 end_col_offset=end_col_offset,
1864 parent=parent,
1865 )
1867 def postinit(
1868 self, items: list[tuple[SuccessfulInferenceResult, SuccessfulInferenceResult]]
1869 ) -> None:
1870 """Do some setup after initialisation.
1872 :param items: The key-value pairs contained in the dictionary.
1873 """
1874 self.items = items
1876 infer_unary_op: ClassVar[InferUnaryOp[Dict]]
1878 def pytype(self) -> Literal["builtins.dict"]:
1879 """Get the name of the type that this node represents.
1881 :returns: The name of the type.
1882 """
1883 return "builtins.dict"
1885 def get_children(self):
1886 """Get the key and value nodes below this node.
1888 Children are returned in the order that they are defined in the source
1889 code, key first then the value.
1891 :returns: The children.
1892 :rtype: iterable(NodeNG)
1893 """
1894 for key, value in self.items:
1895 yield key
1896 yield value
1898 def last_child(self):
1899 """An optimized version of list(get_children())[-1]
1901 :returns: The last child, or None if no children exist.
1902 :rtype: NodeNG or None
1903 """
1904 if self.items:
1905 return self.items[-1][1]
1906 return None
1908 def itered(self):
1909 """An iterator over the keys this node contains.
1911 :returns: The keys of this node.
1912 :rtype: iterable(NodeNG)
1913 """
1914 return [key for (key, _) in self.items]
1916 def getitem(
1917 self, index: Const | Slice, context: InferenceContext | None = None
1918 ) -> NodeNG:
1919 """Get an item from this node.
1921 :param index: The node to use as a subscript index.
1923 :raises AstroidTypeError: When the given index cannot be used as a
1924 subscript index, or if this node is not subscriptable.
1925 :raises AstroidIndexError: If the given index does not exist in the
1926 dictionary.
1927 """
1928 # pylint: disable-next=import-outside-toplevel; circular import
1929 from astroid.helpers import safe_infer
1931 for key, value in self.items:
1932 # TODO(cpopa): no support for overriding yet, {1:2, **{1: 3}}.
1933 if isinstance(key, DictUnpack):
1934 inferred_value = safe_infer(value, context)
1935 if not isinstance(inferred_value, Dict):
1936 continue
1938 try:
1939 return inferred_value.getitem(index, context)
1940 except (AstroidTypeError, AstroidIndexError):
1941 continue
1943 for inferredkey in key.infer(context):
1944 if isinstance(inferredkey, util.UninferableBase):
1945 continue
1946 if isinstance(inferredkey, Const) and isinstance(index, Const):
1947 if inferredkey.value == index.value:
1948 return value
1950 raise AstroidIndexError(index)
1952 def bool_value(self, context: InferenceContext | None = None):
1953 """Determine the boolean value of this node.
1955 :returns: The boolean value of this node.
1956 :rtype: bool
1957 """
1958 return bool(self.items)
1961class Expr(_base_nodes.Statement):
1962 """Class representing an :class:`ast.Expr` node.
1964 An :class:`Expr` is any expression that does not have its value used or
1965 stored.
1967 >>> import astroid
1968 >>> node = astroid.extract_node('method()')
1969 >>> node
1970 <Call l.1 at 0x7f23b2e352b0>
1971 >>> node.parent
1972 <Expr l.1 at 0x7f23b2e35278>
1973 """
1975 _astroid_fields = ("value",)
1977 value: NodeNG
1978 """What the expression does."""
1980 def postinit(self, value: NodeNG) -> None:
1981 self.value = value
1983 def get_children(self):
1984 yield self.value
1986 def _get_yield_nodes_skip_lambdas(self):
1987 if not self.value.is_lambda:
1988 yield from self.value._get_yield_nodes_skip_lambdas()
1991class EmptyNode(_base_nodes.NoChildrenNode):
1992 """Holds an arbitrary object in the :attr:`LocalsDictNodeNG.locals`."""
1994 object = None
1996 def __init__(
1997 self,
1998 lineno: None = None,
1999 col_offset: None = None,
2000 parent: None = None,
2001 *,
2002 end_lineno: None = None,
2003 end_col_offset: None = None,
2004 ) -> None:
2005 super().__init__(
2006 lineno=lineno,
2007 col_offset=col_offset,
2008 end_lineno=end_lineno,
2009 end_col_offset=end_col_offset,
2010 parent=parent,
2011 )
2013 def has_underlying_object(self) -> bool:
2014 return self.object is not None and self.object is not _EMPTY_OBJECT_MARKER
2017class ExceptHandler(
2018 _base_nodes.MultiLineBlockNode, _base_nodes.AssignTypeNode, _base_nodes.Statement
2019):
2020 """Class representing an :class:`ast.ExceptHandler`. node.
2022 An :class:`ExceptHandler` is an ``except`` block on a try-except.
2024 >>> import astroid
2025 >>> node = astroid.extract_node('''
2026 try:
2027 do_something()
2028 except Exception as error:
2029 print("Error!")
2030 ''')
2031 >>> node
2032 <TryExcept l.2 at 0x7f23b2e9d908>
2033 >>> node.handlers
2034 [<ExceptHandler l.4 at 0x7f23b2e9e860>]
2035 """
2037 _astroid_fields = ("type", "name", "body")
2038 _multi_line_block_fields = ("body",)
2040 type: NodeNG | None
2041 """The types that the block handles."""
2043 name: AssignName | None
2044 """The name that the caught exception is assigned to."""
2046 body: list[NodeNG]
2047 """The contents of the block."""
2049 assigned_stmts: ClassVar[AssignedStmtsCall[ExceptHandler]]
2050 """Returns the assigned statement (non inferred) according to the assignment type.
2051 See astroid/protocols.py for actual implementation.
2052 """
2054 def postinit(
2055 self,
2056 type: NodeNG | None, # pylint: disable = redefined-builtin
2057 name: AssignName | None,
2058 body: list[NodeNG],
2059 ) -> None:
2060 self.type = type
2061 self.name = name
2062 self.body = body
2064 def get_children(self):
2065 if self.type is not None:
2066 yield self.type
2068 if self.name is not None:
2069 yield self.name
2071 yield from self.body
2073 @cached_property
2074 def blockstart_tolineno(self):
2075 """The line on which the beginning of this block ends.
2077 :type: int
2078 """
2079 if self.name:
2080 return self.name.tolineno
2081 if self.type:
2082 return self.type.tolineno
2083 return self.lineno
2085 def catch(self, exceptions: list[str] | None) -> bool:
2086 """Check if this node handles any of the given
2088 :param exceptions: The names of the exceptions to check for.
2089 """
2090 if self.type is None or exceptions is None:
2091 return True
2092 return any(node.name in exceptions for node in self.type._get_name_nodes())
2095class For(
2096 _base_nodes.MultiLineWithElseBlockNode,
2097 _base_nodes.AssignTypeNode,
2098 _base_nodes.Statement,
2099):
2100 """Class representing an :class:`ast.For` node.
2102 >>> import astroid
2103 >>> node = astroid.extract_node('for thing in things: print(thing)')
2104 >>> node
2105 <For l.1 at 0x7f23b2e8cf28>
2106 """
2108 _astroid_fields = ("target", "iter", "body", "orelse")
2109 _other_other_fields = ("type_annotation",)
2110 _multi_line_block_fields = ("body", "orelse")
2112 optional_assign = True
2113 """Whether this node optionally assigns a variable.
2115 This is always ``True`` for :class:`For` nodes.
2116 """
2118 target: NodeNG
2119 """What the loop assigns to."""
2121 iter: NodeNG
2122 """What the loop iterates over."""
2124 body: list[NodeNG]
2125 """The contents of the body of the loop."""
2127 orelse: list[NodeNG]
2128 """The contents of the ``else`` block of the loop."""
2130 type_annotation: NodeNG | None
2131 """If present, this will contain the type annotation passed by a type comment"""
2133 def postinit(
2134 self,
2135 target: NodeNG,
2136 iter: NodeNG, # pylint: disable = redefined-builtin
2137 body: list[NodeNG],
2138 orelse: list[NodeNG],
2139 type_annotation: NodeNG | None,
2140 ) -> None:
2141 self.target = target
2142 self.iter = iter
2143 self.body = body
2144 self.orelse = orelse
2145 self.type_annotation = type_annotation
2147 assigned_stmts: ClassVar[AssignedStmtsCall[For]]
2148 """Returns the assigned statement (non inferred) according to the assignment type.
2149 See astroid/protocols.py for actual implementation.
2150 """
2152 @cached_property
2153 def blockstart_tolineno(self):
2154 """The line on which the beginning of this block ends.
2156 :type: int
2157 """
2158 return self.iter.tolineno
2160 def get_children(self):
2161 yield self.target
2162 yield self.iter
2164 yield from self.body
2165 yield from self.orelse
2168class AsyncFor(For):
2169 """Class representing an :class:`ast.AsyncFor` node.
2171 An :class:`AsyncFor` is an asynchronous :class:`For` built with
2172 the ``async`` keyword.
2174 >>> import astroid
2175 >>> node = astroid.extract_node('''
2176 async def func(things):
2177 async for thing in things:
2178 print(thing)
2179 ''')
2180 >>> node
2181 <AsyncFunctionDef.func l.2 at 0x7f23b2e416d8>
2182 >>> node.body[0]
2183 <AsyncFor l.3 at 0x7f23b2e417b8>
2184 """
2187class Await(NodeNG):
2188 """Class representing an :class:`ast.Await` node.
2190 An :class:`Await` is the ``await`` keyword.
2192 >>> import astroid
2193 >>> node = astroid.extract_node('''
2194 async def func(things):
2195 await other_func()
2196 ''')
2197 >>> node
2198 <AsyncFunctionDef.func l.2 at 0x7f23b2e41748>
2199 >>> node.body[0]
2200 <Expr l.3 at 0x7f23b2e419e8>
2201 >>> list(node.body[0].get_children())[0]
2202 <Await l.3 at 0x7f23b2e41a20>
2203 """
2205 _astroid_fields = ("value",)
2207 value: NodeNG
2208 """What to wait for."""
2210 def postinit(self, value: NodeNG) -> None:
2211 self.value = value
2213 def get_children(self):
2214 yield self.value
2217class ImportFrom(_base_nodes.ImportNode):
2218 """Class representing an :class:`ast.ImportFrom` node.
2220 >>> import astroid
2221 >>> node = astroid.extract_node('from my_package import my_module')
2222 >>> node
2223 <ImportFrom l.1 at 0x7f23b2e415c0>
2224 """
2226 _other_fields = ("modname", "names", "level")
2228 def __init__(
2229 self,
2230 fromname: str | None,
2231 names: list[tuple[str, str | None]],
2232 level: int | None = 0,
2233 lineno: int | None = None,
2234 col_offset: int | None = None,
2235 parent: NodeNG | None = None,
2236 *,
2237 end_lineno: int | None = None,
2238 end_col_offset: int | None = None,
2239 ) -> None:
2240 """
2241 :param fromname: The module that is being imported from.
2243 :param names: What is being imported from the module.
2245 :param level: The level of relative import.
2247 :param lineno: The line that this node appears on in the source code.
2249 :param col_offset: The column that this node appears on in the
2250 source code.
2252 :param parent: The parent node in the syntax tree.
2254 :param end_lineno: The last line this node appears on in the source code.
2256 :param end_col_offset: The end column this node appears on in the
2257 source code. Note: This is after the last symbol.
2258 """
2259 self.modname: str | None = fromname # can be None
2260 """The module that is being imported from.
2262 This is ``None`` for relative imports.
2263 """
2265 self.names: list[tuple[str, str | None]] = names
2266 """What is being imported from the module.
2268 Each entry is a :class:`tuple` of the name being imported,
2269 and the alias that the name is assigned to (if any).
2270 """
2272 # TODO When is 'level' None?
2273 self.level: int | None = level # can be None
2274 """The level of relative import.
2276 Essentially this is the number of dots in the import.
2277 This is always 0 for absolute imports.
2278 """
2280 super().__init__(
2281 lineno=lineno,
2282 col_offset=col_offset,
2283 end_lineno=end_lineno,
2284 end_col_offset=end_col_offset,
2285 parent=parent,
2286 )
2289class Attribute(NodeNG):
2290 """Class representing an :class:`ast.Attribute` node."""
2292 _astroid_fields = ("expr",)
2293 _other_fields = ("attrname",)
2295 expr: NodeNG
2296 """The name that this node represents."""
2298 def __init__(
2299 self,
2300 attrname: str,
2301 lineno: int,
2302 col_offset: int,
2303 parent: NodeNG,
2304 *,
2305 end_lineno: int | None,
2306 end_col_offset: int | None,
2307 ) -> None:
2308 self.attrname = attrname
2309 """The name of the attribute."""
2311 super().__init__(
2312 lineno=lineno,
2313 col_offset=col_offset,
2314 end_lineno=end_lineno,
2315 end_col_offset=end_col_offset,
2316 parent=parent,
2317 )
2319 def postinit(self, expr: NodeNG) -> None:
2320 self.expr = expr
2322 def get_children(self):
2323 yield self.expr
2326class Global(_base_nodes.NoChildrenNode, _base_nodes.Statement):
2327 """Class representing an :class:`ast.Global` node.
2329 >>> import astroid
2330 >>> node = astroid.extract_node('global a_global')
2331 >>> node
2332 <Global l.1 at 0x7f23b2e9de10>
2333 """
2335 _other_fields = ("names",)
2337 def __init__(
2338 self,
2339 names: list[str],
2340 lineno: int | None = None,
2341 col_offset: int | None = None,
2342 parent: NodeNG | None = None,
2343 *,
2344 end_lineno: int | None = None,
2345 end_col_offset: int | None = None,
2346 ) -> None:
2347 """
2348 :param names: The names being declared as global.
2350 :param lineno: The line that this node appears on in the source code.
2352 :param col_offset: The column that this node appears on in the
2353 source code.
2355 :param parent: The parent node in the syntax tree.
2357 :param end_lineno: The last line this node appears on in the source code.
2359 :param end_col_offset: The end column this node appears on in the
2360 source code. Note: This is after the last symbol.
2361 """
2362 self.names: list[str] = names
2363 """The names being declared as global."""
2365 super().__init__(
2366 lineno=lineno,
2367 col_offset=col_offset,
2368 end_lineno=end_lineno,
2369 end_col_offset=end_col_offset,
2370 parent=parent,
2371 )
2373 def _infer_name(self, frame, name):
2374 return name
2377class If(_base_nodes.MultiLineWithElseBlockNode, _base_nodes.Statement):
2378 """Class representing an :class:`ast.If` node.
2380 >>> import astroid
2381 >>> node = astroid.extract_node('if condition: print(True)')
2382 >>> node
2383 <If l.1 at 0x7f23b2e9dd30>
2384 """
2386 _astroid_fields = ("test", "body", "orelse")
2387 _multi_line_block_fields = ("body", "orelse")
2389 test: NodeNG
2390 """The condition that the statement tests."""
2392 body: list[NodeNG]
2393 """The contents of the block."""
2395 orelse: list[NodeNG]
2396 """The contents of the ``else`` block."""
2398 def postinit(self, test: NodeNG, body: list[NodeNG], orelse: list[NodeNG]) -> None:
2399 self.test = test
2400 self.body = body
2401 self.orelse = orelse
2403 @cached_property
2404 def blockstart_tolineno(self):
2405 """The line on which the beginning of this block ends.
2407 :type: int
2408 """
2409 return self.test.tolineno
2411 def block_range(self, lineno: int) -> tuple[int, int]:
2412 """Get a range from the given line number to where this node ends.
2414 :param lineno: The line number to start the range at.
2416 :returns: The range of line numbers that this node belongs to,
2417 starting at the given line number.
2418 """
2419 if lineno == self.body[0].fromlineno:
2420 return lineno, lineno
2421 if lineno <= self.body[-1].tolineno:
2422 return lineno, self.body[-1].tolineno
2423 return self._elsed_block_range(lineno, self.orelse, self.body[0].fromlineno - 1)
2425 def get_children(self):
2426 yield self.test
2428 yield from self.body
2429 yield from self.orelse
2431 def has_elif_block(self):
2432 return len(self.orelse) == 1 and isinstance(self.orelse[0], If)
2434 def _get_yield_nodes_skip_lambdas(self):
2435 """An If node can contain a Yield node in the test"""
2436 yield from self.test._get_yield_nodes_skip_lambdas()
2437 yield from super()._get_yield_nodes_skip_lambdas()
2440class IfExp(NodeNG):
2441 """Class representing an :class:`ast.IfExp` node.
2442 >>> import astroid
2443 >>> node = astroid.extract_node('value if condition else other')
2444 >>> node
2445 <IfExp l.1 at 0x7f23b2e9dbe0>
2446 """
2448 _astroid_fields = ("test", "body", "orelse")
2450 test: NodeNG
2451 """The condition that the statement tests."""
2453 body: NodeNG
2454 """The contents of the block."""
2456 orelse: NodeNG
2457 """The contents of the ``else`` block."""
2459 def postinit(self, test: NodeNG, body: NodeNG, orelse: NodeNG) -> None:
2460 self.test = test
2461 self.body = body
2462 self.orelse = orelse
2464 def get_children(self):
2465 yield self.test
2466 yield self.body
2467 yield self.orelse
2469 def op_left_associative(self) -> Literal[False]:
2470 # `1 if True else 2 if False else 3` is parsed as
2471 # `1 if True else (2 if False else 3)`
2472 return False
2475class Import(_base_nodes.ImportNode):
2476 """Class representing an :class:`ast.Import` node.
2477 >>> import astroid
2478 >>> node = astroid.extract_node('import astroid')
2479 >>> node
2480 <Import l.1 at 0x7f23b2e4e5c0>
2481 """
2483 _other_fields = ("names",)
2485 @decorators.deprecate_default_argument_values(names="list[tuple[str, str | None]]")
2486 def __init__(
2487 self,
2488 names: list[tuple[str, str | None]] | None = None,
2489 lineno: int | None = None,
2490 col_offset: int | None = None,
2491 parent: NodeNG | None = None,
2492 *,
2493 end_lineno: int | None = None,
2494 end_col_offset: int | None = None,
2495 ) -> None:
2496 """
2497 :param names: The names being imported.
2499 :param lineno: The line that this node appears on in the source code.
2501 :param col_offset: The column that this node appears on in the
2502 source code.
2504 :param parent: The parent node in the syntax tree.
2506 :param end_lineno: The last line this node appears on in the source code.
2508 :param end_col_offset: The end column this node appears on in the
2509 source code. Note: This is after the last symbol.
2510 """
2511 self.names: list[tuple[str, str | None]] = names or []
2512 """The names being imported.
2514 Each entry is a :class:`tuple` of the name being imported,
2515 and the alias that the name is assigned to (if any).
2516 """
2518 super().__init__(
2519 lineno=lineno,
2520 col_offset=col_offset,
2521 end_lineno=end_lineno,
2522 end_col_offset=end_col_offset,
2523 parent=parent,
2524 )
2527class Keyword(NodeNG):
2528 """Class representing an :class:`ast.keyword` node.
2530 >>> import astroid
2531 >>> node = astroid.extract_node('function(a_kwarg=True)')
2532 >>> node
2533 <Call l.1 at 0x7f23b2e9e320>
2534 >>> node.keywords
2535 [<Keyword l.1 at 0x7f23b2e9e9b0>]
2536 """
2538 _astroid_fields = ("value",)
2539 _other_fields = ("arg",)
2541 value: NodeNG
2542 """The value being assigned to the keyword argument."""
2544 def __init__(
2545 self,
2546 arg: str | None,
2547 lineno: int | None,
2548 col_offset: int | None,
2549 parent: NodeNG,
2550 *,
2551 end_lineno: int | None,
2552 end_col_offset: int | None,
2553 ) -> None:
2554 self.arg = arg
2555 """The argument being assigned to."""
2557 super().__init__(
2558 lineno=lineno,
2559 col_offset=col_offset,
2560 end_lineno=end_lineno,
2561 end_col_offset=end_col_offset,
2562 parent=parent,
2563 )
2565 def postinit(self, value: NodeNG) -> None:
2566 self.value = value
2568 def get_children(self):
2569 yield self.value
2572class List(BaseContainer):
2573 """Class representing an :class:`ast.List` node.
2575 >>> import astroid
2576 >>> node = astroid.extract_node('[1, 2, 3]')
2577 >>> node
2578 <List.list l.1 at 0x7f23b2e9e128>
2579 """
2581 _other_fields = ("ctx",)
2583 def __init__(
2584 self,
2585 ctx: Context | None = None,
2586 lineno: int | None = None,
2587 col_offset: int | None = None,
2588 parent: NodeNG | None = None,
2589 *,
2590 end_lineno: int | None = None,
2591 end_col_offset: int | None = None,
2592 ) -> None:
2593 """
2594 :param ctx: Whether the list is assigned to or loaded from.
2596 :param lineno: The line that this node appears on in the source code.
2598 :param col_offset: The column that this node appears on in the
2599 source code.
2601 :param parent: The parent node in the syntax tree.
2603 :param end_lineno: The last line this node appears on in the source code.
2605 :param end_col_offset: The end column this node appears on in the
2606 source code. Note: This is after the last symbol.
2607 """
2608 self.ctx: Context | None = ctx
2609 """Whether the list is assigned to or loaded from."""
2611 super().__init__(
2612 lineno=lineno,
2613 col_offset=col_offset,
2614 end_lineno=end_lineno,
2615 end_col_offset=end_col_offset,
2616 parent=parent,
2617 )
2619 assigned_stmts: ClassVar[AssignedStmtsCall[List]]
2620 """Returns the assigned statement (non inferred) according to the assignment type.
2621 See astroid/protocols.py for actual implementation.
2622 """
2624 infer_unary_op: ClassVar[InferUnaryOp[List]]
2625 infer_binary_op: ClassVar[InferBinaryOp[List]]
2627 def pytype(self) -> Literal["builtins.list"]:
2628 """Get the name of the type that this node represents.
2630 :returns: The name of the type.
2631 """
2632 return "builtins.list"
2634 def getitem(self, index, context: InferenceContext | None = None):
2635 """Get an item from this node.
2637 :param index: The node to use as a subscript index.
2638 :type index: Const or Slice
2639 """
2640 return _container_getitem(self, self.elts, index, context=context)
2643class Nonlocal(_base_nodes.NoChildrenNode, _base_nodes.Statement):
2644 """Class representing an :class:`ast.Nonlocal` node.
2646 >>> import astroid
2647 >>> node = astroid.extract_node('''
2648 def function():
2649 nonlocal var
2650 ''')
2651 >>> node
2652 <FunctionDef.function l.2 at 0x7f23b2e9e208>
2653 >>> node.body[0]
2654 <Nonlocal l.3 at 0x7f23b2e9e908>
2655 """
2657 _other_fields = ("names",)
2659 def __init__(
2660 self,
2661 names: list[str],
2662 lineno: int | None = None,
2663 col_offset: int | None = None,
2664 parent: NodeNG | None = None,
2665 *,
2666 end_lineno: int | None = None,
2667 end_col_offset: int | None = None,
2668 ) -> None:
2669 """
2670 :param names: The names being declared as not local.
2672 :param lineno: The line that this node appears on in the source code.
2674 :param col_offset: The column that this node appears on in the
2675 source code.
2677 :param parent: The parent node in the syntax tree.
2679 :param end_lineno: The last line this node appears on in the source code.
2681 :param end_col_offset: The end column this node appears on in the
2682 source code. Note: This is after the last symbol.
2683 """
2684 self.names: list[str] = names
2685 """The names being declared as not local."""
2687 super().__init__(
2688 lineno=lineno,
2689 col_offset=col_offset,
2690 end_lineno=end_lineno,
2691 end_col_offset=end_col_offset,
2692 parent=parent,
2693 )
2695 def _infer_name(self, frame, name):
2696 return name
2699class Pass(_base_nodes.NoChildrenNode, _base_nodes.Statement):
2700 """Class representing an :class:`ast.Pass` node.
2702 >>> import astroid
2703 >>> node = astroid.extract_node('pass')
2704 >>> node
2705 <Pass l.1 at 0x7f23b2e9e748>
2706 """
2709class Raise(_base_nodes.Statement):
2710 """Class representing an :class:`ast.Raise` node.
2712 >>> import astroid
2713 >>> node = astroid.extract_node('raise RuntimeError("Something bad happened!")')
2714 >>> node
2715 <Raise l.1 at 0x7f23b2e9e828>
2716 """
2718 _astroid_fields = ("exc", "cause")
2720 exc: NodeNG | None
2721 """What is being raised."""
2723 cause: NodeNG | None
2724 """The exception being used to raise this one."""
2726 def postinit(
2727 self,
2728 exc: NodeNG | None,
2729 cause: NodeNG | None,
2730 ) -> None:
2731 self.exc = exc
2732 self.cause = cause
2734 def raises_not_implemented(self) -> bool:
2735 """Check if this node raises a :class:`NotImplementedError`.
2737 :returns: Whether this node raises a :class:`NotImplementedError`.
2738 """
2739 if not self.exc:
2740 return False
2741 return any(
2742 name.name == "NotImplementedError" for name in self.exc._get_name_nodes()
2743 )
2745 def get_children(self):
2746 if self.exc is not None:
2747 yield self.exc
2749 if self.cause is not None:
2750 yield self.cause
2753class Return(_base_nodes.Statement):
2754 """Class representing an :class:`ast.Return` node.
2756 >>> import astroid
2757 >>> node = astroid.extract_node('return True')
2758 >>> node
2759 <Return l.1 at 0x7f23b8211908>
2760 """
2762 _astroid_fields = ("value",)
2764 value: NodeNG | None
2765 """The value being returned."""
2767 def postinit(self, value: NodeNG | None) -> None:
2768 self.value = value
2770 def get_children(self):
2771 if self.value is not None:
2772 yield self.value
2774 def is_tuple_return(self):
2775 return isinstance(self.value, Tuple)
2777 def _get_return_nodes_skip_functions(self):
2778 yield self
2781class Set(BaseContainer):
2782 """Class representing an :class:`ast.Set` node.
2784 >>> import astroid
2785 >>> node = astroid.extract_node('{1, 2, 3}')
2786 >>> node
2787 <Set.set l.1 at 0x7f23b2e71d68>
2788 """
2790 infer_unary_op: ClassVar[InferUnaryOp[Set]]
2792 def pytype(self) -> Literal["builtins.set"]:
2793 """Get the name of the type that this node represents.
2795 :returns: The name of the type.
2796 """
2797 return "builtins.set"
2800class Slice(NodeNG):
2801 """Class representing an :class:`ast.Slice` node.
2803 >>> import astroid
2804 >>> node = astroid.extract_node('things[1:3]')
2805 >>> node
2806 <Subscript l.1 at 0x7f23b2e71f60>
2807 >>> node.slice
2808 <Slice l.1 at 0x7f23b2e71e80>
2809 """
2811 _astroid_fields = ("lower", "upper", "step")
2813 lower: NodeNG | None
2814 """The lower index in the slice."""
2816 upper: NodeNG | None
2817 """The upper index in the slice."""
2819 step: NodeNG | None
2820 """The step to take between indexes."""
2822 def postinit(
2823 self,
2824 lower: NodeNG | None,
2825 upper: NodeNG | None,
2826 step: NodeNG | None,
2827 ) -> None:
2828 self.lower = lower
2829 self.upper = upper
2830 self.step = step
2832 def _wrap_attribute(self, attr):
2833 """Wrap the empty attributes of the Slice in a Const node."""
2834 if not attr:
2835 const = const_factory(attr)
2836 const.parent = self
2837 return const
2838 return attr
2840 @cached_property
2841 def _proxied(self) -> nodes.ClassDef:
2842 builtins = AstroidManager().builtins_module
2843 return builtins.getattr("slice")[0]
2845 def pytype(self) -> Literal["builtins.slice"]:
2846 """Get the name of the type that this node represents.
2848 :returns: The name of the type.
2849 """
2850 return "builtins.slice"
2852 def igetattr(
2853 self, attrname: str, context: InferenceContext | None = None
2854 ) -> Iterator[SuccessfulInferenceResult]:
2855 """Infer the possible values of the given attribute on the slice.
2857 :param attrname: The name of the attribute to infer.
2859 :returns: The inferred possible values.
2860 """
2861 if attrname == "start":
2862 yield self._wrap_attribute(self.lower)
2863 elif attrname == "stop":
2864 yield self._wrap_attribute(self.upper)
2865 elif attrname == "step":
2866 yield self._wrap_attribute(self.step)
2867 else:
2868 yield from self.getattr(attrname, context=context)
2870 def getattr(self, attrname, context: InferenceContext | None = None):
2871 return self._proxied.getattr(attrname, context)
2873 def get_children(self):
2874 if self.lower is not None:
2875 yield self.lower
2877 if self.upper is not None:
2878 yield self.upper
2880 if self.step is not None:
2881 yield self.step
2884class Starred(_base_nodes.ParentAssignNode):
2885 """Class representing an :class:`ast.Starred` node.
2887 >>> import astroid
2888 >>> node = astroid.extract_node('*args')
2889 >>> node
2890 <Starred l.1 at 0x7f23b2e41978>
2891 """
2893 _astroid_fields = ("value",)
2894 _other_fields = ("ctx",)
2896 value: NodeNG
2897 """What is being unpacked."""
2899 def __init__(
2900 self,
2901 ctx: Context,
2902 lineno: int,
2903 col_offset: int,
2904 parent: NodeNG,
2905 *,
2906 end_lineno: int | None,
2907 end_col_offset: int | None,
2908 ) -> None:
2909 self.ctx = ctx
2910 """Whether the starred item is assigned to or loaded from."""
2912 super().__init__(
2913 lineno=lineno,
2914 col_offset=col_offset,
2915 end_lineno=end_lineno,
2916 end_col_offset=end_col_offset,
2917 parent=parent,
2918 )
2920 def postinit(self, value: NodeNG) -> None:
2921 self.value = value
2923 assigned_stmts: ClassVar[AssignedStmtsCall[Starred]]
2924 """Returns the assigned statement (non inferred) according to the assignment type.
2925 See astroid/protocols.py for actual implementation.
2926 """
2928 def get_children(self):
2929 yield self.value
2932class Subscript(NodeNG):
2933 """Class representing an :class:`ast.Subscript` node.
2935 >>> import astroid
2936 >>> node = astroid.extract_node('things[1:3]')
2937 >>> node
2938 <Subscript l.1 at 0x7f23b2e71f60>
2939 """
2941 _astroid_fields = ("value", "slice")
2942 _other_fields = ("ctx",)
2944 infer_lhs: ClassVar[InferLHS[Subscript]]
2946 value: NodeNG
2947 """What is being indexed."""
2949 slice: NodeNG
2950 """The slice being used to lookup."""
2952 def __init__(
2953 self,
2954 ctx: Context,
2955 lineno: int,
2956 col_offset: int,
2957 parent: NodeNG,
2958 *,
2959 end_lineno: int | None,
2960 end_col_offset: int | None,
2961 ) -> None:
2962 self.ctx = ctx
2963 """Whether the subscripted item is assigned to or loaded from."""
2965 super().__init__(
2966 lineno=lineno,
2967 col_offset=col_offset,
2968 end_lineno=end_lineno,
2969 end_col_offset=end_col_offset,
2970 parent=parent,
2971 )
2973 # pylint: disable=redefined-builtin; had to use the same name as builtin ast module.
2974 def postinit(self, value: NodeNG, slice: NodeNG) -> None:
2975 self.value = value
2976 self.slice = slice
2978 def get_children(self):
2979 yield self.value
2980 yield self.slice
2983class TryExcept(_base_nodes.MultiLineWithElseBlockNode, _base_nodes.Statement):
2984 """Class representing an :class:`ast.TryExcept` node.
2986 >>> import astroid
2987 >>> node = astroid.extract_node('''
2988 try:
2989 do_something()
2990 except Exception as error:
2991 print("Error!")
2992 ''')
2993 >>> node
2994 <TryExcept l.2 at 0x7f23b2e9d908>
2995 """
2997 _astroid_fields = ("body", "handlers", "orelse")
2998 _multi_line_block_fields = ("body", "handlers", "orelse")
3000 body: list[NodeNG]
3001 """The contents of the block to catch exceptions from."""
3003 handlers: list[ExceptHandler]
3004 """The exception handlers."""
3006 orelse: list[NodeNG]
3007 """The contents of the ``else`` block."""
3009 def postinit(
3010 self,
3011 body: list[NodeNG],
3012 handlers: list[ExceptHandler],
3013 orelse: list[NodeNG],
3014 ) -> None:
3015 self.body = body
3016 self.handlers = handlers
3017 self.orelse = orelse
3019 def _infer_name(self, frame, name):
3020 return name
3022 def block_range(self, lineno: int) -> tuple[int, int]:
3023 """Get a range from the given line number to where this node ends.
3025 :param lineno: The line number to start the range at.
3027 :returns: The range of line numbers that this node belongs to,
3028 starting at the given line number.
3029 """
3030 last = None
3031 for exhandler in self.handlers:
3032 if exhandler.type and lineno == exhandler.type.fromlineno:
3033 return lineno, lineno
3034 if exhandler.body[0].fromlineno <= lineno <= exhandler.body[-1].tolineno:
3035 return lineno, exhandler.body[-1].tolineno
3036 if last is None:
3037 last = exhandler.body[0].fromlineno - 1
3038 return self._elsed_block_range(lineno, self.orelse, last)
3040 def get_children(self):
3041 yield from self.body
3043 yield from self.handlers or ()
3044 yield from self.orelse or ()
3047class TryFinally(_base_nodes.MultiLineWithElseBlockNode, _base_nodes.Statement):
3048 """Class representing an :class:`ast.TryFinally` node.
3050 >>> import astroid
3051 >>> node = astroid.extract_node('''
3052 try:
3053 do_something()
3054 except Exception as error:
3055 print("Error!")
3056 finally:
3057 print("Cleanup!")
3058 ''')
3059 >>> node
3060 <TryFinally l.2 at 0x7f23b2e41d68>
3061 """
3063 _astroid_fields = ("body", "finalbody")
3064 _multi_line_block_fields = ("body", "finalbody")
3066 def __init__(
3067 self,
3068 lineno: int | None = None,
3069 col_offset: int | None = None,
3070 parent: NodeNG | None = None,
3071 *,
3072 end_lineno: int | None = None,
3073 end_col_offset: int | None = None,
3074 ) -> None:
3075 """
3076 :param lineno: The line that this node appears on in the source code.
3078 :param col_offset: The column that this node appears on in the
3079 source code.
3081 :param parent: The parent node in the syntax tree.
3083 :param end_lineno: The last line this node appears on in the source code.
3085 :param end_col_offset: The end column this node appears on in the
3086 source code. Note: This is after the last symbol.
3087 """
3088 self.body: list[NodeNG | TryExcept] = []
3089 """The try-except that the finally is attached to."""
3091 self.finalbody: list[NodeNG] = []
3092 """The contents of the ``finally`` block."""
3094 super().__init__(
3095 lineno=lineno,
3096 col_offset=col_offset,
3097 end_lineno=end_lineno,
3098 end_col_offset=end_col_offset,
3099 parent=parent,
3100 )
3102 def postinit(
3103 self,
3104 body: list[NodeNG | TryExcept] | None = None,
3105 finalbody: list[NodeNG] | None = None,
3106 ) -> None:
3107 """Do some setup after initialisation.
3109 :param body: The try-except that the finally is attached to.
3111 :param finalbody: The contents of the ``finally`` block.
3112 """
3113 if body is not None:
3114 self.body = body
3115 if finalbody is not None:
3116 self.finalbody = finalbody
3118 def block_range(self, lineno: int) -> tuple[int, int]:
3119 """Get a range from the given line number to where this node ends.
3121 :param lineno: The line number to start the range at.
3123 :returns: The range of line numbers that this node belongs to,
3124 starting at the given line number.
3125 """
3126 child = self.body[0]
3127 # py2.5 try: except: finally:
3128 if (
3129 isinstance(child, TryExcept)
3130 and child.fromlineno == self.fromlineno
3131 and child.tolineno >= lineno > self.fromlineno
3132 ):
3133 return child.block_range(lineno)
3134 return self._elsed_block_range(lineno, self.finalbody)
3136 def get_children(self):
3137 yield from self.body
3138 yield from self.finalbody
3141class TryStar(_base_nodes.MultiLineWithElseBlockNode, _base_nodes.Statement):
3142 """Class representing an :class:`ast.TryStar` node."""
3144 _astroid_fields = ("body", "handlers", "orelse", "finalbody")
3145 _multi_line_block_fields = ("body", "handlers", "orelse", "finalbody")
3147 def __init__(
3148 self,
3149 *,
3150 lineno: int | None = None,
3151 col_offset: int | None = None,
3152 end_lineno: int | None = None,
3153 end_col_offset: int | None = None,
3154 parent: NodeNG | None = None,
3155 ) -> None:
3156 """
3157 :param lineno: The line that this node appears on in the source code.
3158 :param col_offset: The column that this node appears on in the
3159 source code.
3160 :param parent: The parent node in the syntax tree.
3161 :param end_lineno: The last line this node appears on in the source code.
3162 :param end_col_offset: The end column this node appears on in the
3163 source code. Note: This is after the last symbol.
3164 """
3165 self.body: list[NodeNG] = []
3166 """The contents of the block to catch exceptions from."""
3168 self.handlers: list[ExceptHandler] = []
3169 """The exception handlers."""
3171 self.orelse: list[NodeNG] = []
3172 """The contents of the ``else`` block."""
3174 self.finalbody: list[NodeNG] = []
3175 """The contents of the ``finally`` block."""
3177 super().__init__(
3178 lineno=lineno,
3179 col_offset=col_offset,
3180 end_lineno=end_lineno,
3181 end_col_offset=end_col_offset,
3182 parent=parent,
3183 )
3185 def postinit(
3186 self,
3187 *,
3188 body: list[NodeNG] | None = None,
3189 handlers: list[ExceptHandler] | None = None,
3190 orelse: list[NodeNG] | None = None,
3191 finalbody: list[NodeNG] | None = None,
3192 ) -> None:
3193 """Do some setup after initialisation.
3194 :param body: The contents of the block to catch exceptions from.
3195 :param handlers: The exception handlers.
3196 :param orelse: The contents of the ``else`` block.
3197 :param finalbody: The contents of the ``finally`` block.
3198 """
3199 if body:
3200 self.body = body
3201 if handlers:
3202 self.handlers = handlers
3203 if orelse:
3204 self.orelse = orelse
3205 if finalbody:
3206 self.finalbody = finalbody
3208 def _infer_name(self, frame, name):
3209 return name
3211 def block_range(self, lineno: int) -> tuple[int, int]:
3212 """Get a range from a given line number to where this node ends."""
3213 if lineno == self.fromlineno:
3214 return lineno, lineno
3215 if self.body and self.body[0].fromlineno <= lineno <= self.body[-1].tolineno:
3216 # Inside try body - return from lineno till end of try body
3217 return lineno, self.body[-1].tolineno
3218 for exhandler in self.handlers:
3219 if exhandler.type and lineno == exhandler.type.fromlineno:
3220 return lineno, lineno
3221 if exhandler.body[0].fromlineno <= lineno <= exhandler.body[-1].tolineno:
3222 return lineno, exhandler.body[-1].tolineno
3223 if self.orelse:
3224 if self.orelse[0].fromlineno - 1 == lineno:
3225 return lineno, lineno
3226 if self.orelse[0].fromlineno <= lineno <= self.orelse[-1].tolineno:
3227 return lineno, self.orelse[-1].tolineno
3228 if self.finalbody:
3229 if self.finalbody[0].fromlineno - 1 == lineno:
3230 return lineno, lineno
3231 if self.finalbody[0].fromlineno <= lineno <= self.finalbody[-1].tolineno:
3232 return lineno, self.finalbody[-1].tolineno
3233 return lineno, self.tolineno
3235 def get_children(self):
3236 yield from self.body
3237 yield from self.handlers
3238 yield from self.orelse
3239 yield from self.finalbody
3242class Tuple(BaseContainer):
3243 """Class representing an :class:`ast.Tuple` node.
3245 >>> import astroid
3246 >>> node = astroid.extract_node('(1, 2, 3)')
3247 >>> node
3248 <Tuple.tuple l.1 at 0x7f23b2e41780>
3249 """
3251 _other_fields = ("ctx",)
3253 def __init__(
3254 self,
3255 ctx: Context | None = None,
3256 lineno: int | None = None,
3257 col_offset: int | None = None,
3258 parent: NodeNG | None = None,
3259 *,
3260 end_lineno: int | None = None,
3261 end_col_offset: int | None = None,
3262 ) -> None:
3263 """
3264 :param ctx: Whether the tuple is assigned to or loaded from.
3266 :param lineno: The line that this node appears on in the source code.
3268 :param col_offset: The column that this node appears on in the
3269 source code.
3271 :param parent: The parent node in the syntax tree.
3273 :param end_lineno: The last line this node appears on in the source code.
3275 :param end_col_offset: The end column this node appears on in the
3276 source code. Note: This is after the last symbol.
3277 """
3278 self.ctx: Context | None = ctx
3279 """Whether the tuple is assigned to or loaded from."""
3281 super().__init__(
3282 lineno=lineno,
3283 col_offset=col_offset,
3284 end_lineno=end_lineno,
3285 end_col_offset=end_col_offset,
3286 parent=parent,
3287 )
3289 assigned_stmts: ClassVar[AssignedStmtsCall[Tuple]]
3290 """Returns the assigned statement (non inferred) according to the assignment type.
3291 See astroid/protocols.py for actual implementation.
3292 """
3294 infer_unary_op: ClassVar[InferUnaryOp[Tuple]]
3295 infer_binary_op: ClassVar[InferBinaryOp[Tuple]]
3297 def pytype(self) -> Literal["builtins.tuple"]:
3298 """Get the name of the type that this node represents.
3300 :returns: The name of the type.
3301 """
3302 return "builtins.tuple"
3304 def getitem(self, index, context: InferenceContext | None = None):
3305 """Get an item from this node.
3307 :param index: The node to use as a subscript index.
3308 :type index: Const or Slice
3309 """
3310 return _container_getitem(self, self.elts, index, context=context)
3313class UnaryOp(NodeNG):
3314 """Class representing an :class:`ast.UnaryOp` node.
3316 >>> import astroid
3317 >>> node = astroid.extract_node('-5')
3318 >>> node
3319 <UnaryOp l.1 at 0x7f23b2e4e198>
3320 """
3322 _astroid_fields = ("operand",)
3323 _other_fields = ("op",)
3325 operand: NodeNG
3326 """What the unary operator is applied to."""
3328 def __init__(
3329 self,
3330 op: str,
3331 lineno: int,
3332 col_offset: int,
3333 parent: NodeNG,
3334 *,
3335 end_lineno: int | None,
3336 end_col_offset: int | None,
3337 ) -> None:
3338 self.op = op
3339 """The operator."""
3341 super().__init__(
3342 lineno=lineno,
3343 col_offset=col_offset,
3344 end_lineno=end_lineno,
3345 end_col_offset=end_col_offset,
3346 parent=parent,
3347 )
3349 def postinit(self, operand: NodeNG) -> None:
3350 self.operand = operand
3352 # This is set by inference.py
3353 _infer_unaryop: ClassVar[
3354 InferBinaryOperation[UnaryOp, util.BadUnaryOperationMessage]
3355 ]
3357 def type_errors(self, context: InferenceContext | None = None):
3358 """Get a list of type errors which can occur during inference.
3360 Each TypeError is represented by a :class:`BadBinaryOperationMessage`,
3361 which holds the original exception.
3363 :returns: The list of possible type errors.
3364 :rtype: list(BadBinaryOperationMessage)
3365 """
3366 try:
3367 results = self._infer_unaryop(context=context)
3368 return [
3369 result
3370 for result in results
3371 if isinstance(result, util.BadUnaryOperationMessage)
3372 ]
3373 except InferenceError:
3374 return []
3376 def get_children(self):
3377 yield self.operand
3379 def op_precedence(self):
3380 if self.op == "not":
3381 return OP_PRECEDENCE[self.op]
3383 return super().op_precedence()
3386class While(_base_nodes.MultiLineWithElseBlockNode, _base_nodes.Statement):
3387 """Class representing an :class:`ast.While` node.
3389 >>> import astroid
3390 >>> node = astroid.extract_node('''
3391 while condition():
3392 print("True")
3393 ''')
3394 >>> node
3395 <While l.2 at 0x7f23b2e4e390>
3396 """
3398 _astroid_fields = ("test", "body", "orelse")
3399 _multi_line_block_fields = ("body", "orelse")
3401 test: NodeNG
3402 """The condition that the loop tests."""
3404 body: list[NodeNG]
3405 """The contents of the loop."""
3407 orelse: list[NodeNG]
3408 """The contents of the ``else`` block."""
3410 def postinit(
3411 self,
3412 test: NodeNG,
3413 body: list[NodeNG],
3414 orelse: list[NodeNG],
3415 ) -> None:
3416 self.test = test
3417 self.body = body
3418 self.orelse = orelse
3420 @cached_property
3421 def blockstart_tolineno(self):
3422 """The line on which the beginning of this block ends.
3424 :type: int
3425 """
3426 return self.test.tolineno
3428 def block_range(self, lineno: int) -> tuple[int, int]:
3429 """Get a range from the given line number to where this node ends.
3431 :param lineno: The line number to start the range at.
3433 :returns: The range of line numbers that this node belongs to,
3434 starting at the given line number.
3435 """
3436 return self._elsed_block_range(lineno, self.orelse)
3438 def get_children(self):
3439 yield self.test
3441 yield from self.body
3442 yield from self.orelse
3444 def _get_yield_nodes_skip_lambdas(self):
3445 """A While node can contain a Yield node in the test"""
3446 yield from self.test._get_yield_nodes_skip_lambdas()
3447 yield from super()._get_yield_nodes_skip_lambdas()
3450class With(
3451 _base_nodes.MultiLineWithElseBlockNode,
3452 _base_nodes.AssignTypeNode,
3453 _base_nodes.Statement,
3454):
3455 """Class representing an :class:`ast.With` node.
3457 >>> import astroid
3458 >>> node = astroid.extract_node('''
3459 with open(file_path) as file_:
3460 print(file_.read())
3461 ''')
3462 >>> node
3463 <With l.2 at 0x7f23b2e4e710>
3464 """
3466 _astroid_fields = ("items", "body")
3467 _other_other_fields = ("type_annotation",)
3468 _multi_line_block_fields = ("body",)
3470 def __init__(
3471 self,
3472 lineno: int | None = None,
3473 col_offset: int | None = None,
3474 parent: NodeNG | None = None,
3475 *,
3476 end_lineno: int | None = None,
3477 end_col_offset: int | None = None,
3478 ) -> None:
3479 """
3480 :param lineno: The line that this node appears on in the source code.
3482 :param col_offset: The column that this node appears on in the
3483 source code.
3485 :param parent: The parent node in the syntax tree.
3487 :param end_lineno: The last line this node appears on in the source code.
3489 :param end_col_offset: The end column this node appears on in the
3490 source code. Note: This is after the last symbol.
3491 """
3492 self.items: list[tuple[NodeNG, NodeNG | None]] = []
3493 """The pairs of context managers and the names they are assigned to."""
3495 self.body: list[NodeNG] = []
3496 """The contents of the ``with`` block."""
3498 self.type_annotation: NodeNG | None = None # can be None
3499 """If present, this will contain the type annotation passed by a type comment"""
3501 super().__init__(
3502 lineno=lineno,
3503 col_offset=col_offset,
3504 end_lineno=end_lineno,
3505 end_col_offset=end_col_offset,
3506 parent=parent,
3507 )
3509 def postinit(
3510 self,
3511 items: list[tuple[NodeNG, NodeNG | None]] | None = None,
3512 body: list[NodeNG] | None = None,
3513 type_annotation: NodeNG | None = None,
3514 ) -> None:
3515 """Do some setup after initialisation.
3517 :param items: The pairs of context managers and the names
3518 they are assigned to.
3520 :param body: The contents of the ``with`` block.
3521 """
3522 if items is not None:
3523 self.items = items
3524 if body is not None:
3525 self.body = body
3526 self.type_annotation = type_annotation
3528 assigned_stmts: ClassVar[AssignedStmtsCall[With]]
3529 """Returns the assigned statement (non inferred) according to the assignment type.
3530 See astroid/protocols.py for actual implementation.
3531 """
3533 @cached_property
3534 def blockstart_tolineno(self):
3535 """The line on which the beginning of this block ends.
3537 :type: int
3538 """
3539 return self.items[-1][0].tolineno
3541 def get_children(self):
3542 """Get the child nodes below this node.
3544 :returns: The children.
3545 :rtype: iterable(NodeNG)
3546 """
3547 for expr, var in self.items:
3548 yield expr
3549 if var:
3550 yield var
3551 yield from self.body
3554class AsyncWith(With):
3555 """Asynchronous ``with`` built with the ``async`` keyword."""
3558class Yield(NodeNG):
3559 """Class representing an :class:`ast.Yield` node.
3561 >>> import astroid
3562 >>> node = astroid.extract_node('yield True')
3563 >>> node
3564 <Yield l.1 at 0x7f23b2e4e5f8>
3565 """
3567 _astroid_fields = ("value",)
3569 value: NodeNG | None
3570 """The value to yield."""
3572 def postinit(self, value: NodeNG | None) -> None:
3573 self.value = value
3575 def get_children(self):
3576 if self.value is not None:
3577 yield self.value
3579 def _get_yield_nodes_skip_lambdas(self):
3580 yield self
3583class YieldFrom(Yield): # TODO value is required, not optional
3584 """Class representing an :class:`ast.YieldFrom` node."""
3587class DictUnpack(_base_nodes.NoChildrenNode):
3588 """Represents the unpacking of dicts into dicts using :pep:`448`."""
3591class FormattedValue(NodeNG):
3592 """Class representing an :class:`ast.FormattedValue` node.
3594 Represents a :pep:`498` format string.
3596 >>> import astroid
3597 >>> node = astroid.extract_node('f"Format {type_}"')
3598 >>> node
3599 <JoinedStr l.1 at 0x7f23b2e4ed30>
3600 >>> node.values
3601 [<Const.str l.1 at 0x7f23b2e4eda0>, <FormattedValue l.1 at 0x7f23b2e4edd8>]
3602 """
3604 _astroid_fields = ("value", "format_spec")
3605 _other_fields = ("conversion",)
3607 def __init__(
3608 self,
3609 lineno: int | None = None,
3610 col_offset: int | None = None,
3611 parent: NodeNG | None = None,
3612 *,
3613 end_lineno: int | None = None,
3614 end_col_offset: int | None = None,
3615 ) -> None:
3616 """
3617 :param lineno: The line that this node appears on in the source code.
3619 :param col_offset: The column that this node appears on in the
3620 source code.
3622 :param parent: The parent node in the syntax tree.
3624 :param end_lineno: The last line this node appears on in the source code.
3626 :param end_col_offset: The end column this node appears on in the
3627 source code. Note: This is after the last symbol.
3628 """
3629 self.value: NodeNG
3630 """The value to be formatted into the string."""
3632 self.conversion: int
3633 """The type of formatting to be applied to the value.
3635 .. seealso::
3636 :class:`ast.FormattedValue`
3637 """
3639 self.format_spec: JoinedStr | None = None
3640 """The formatting to be applied to the value.
3642 .. seealso::
3643 :class:`ast.FormattedValue`
3644 """
3646 super().__init__(
3647 lineno=lineno,
3648 col_offset=col_offset,
3649 end_lineno=end_lineno,
3650 end_col_offset=end_col_offset,
3651 parent=parent,
3652 )
3654 def postinit(
3655 self,
3656 *,
3657 value: NodeNG,
3658 conversion: int,
3659 format_spec: JoinedStr | None = None,
3660 ) -> None:
3661 """Do some setup after initialisation.
3663 :param value: The value to be formatted into the string.
3665 :param conversion: The type of formatting to be applied to the value.
3667 :param format_spec: The formatting to be applied to the value.
3668 :type format_spec: JoinedStr or None
3669 """
3670 self.value = value
3671 self.conversion = conversion
3672 self.format_spec = format_spec
3674 def get_children(self):
3675 yield self.value
3677 if self.format_spec is not None:
3678 yield self.format_spec
3681class JoinedStr(NodeNG):
3682 """Represents a list of string expressions to be joined.
3684 >>> import astroid
3685 >>> node = astroid.extract_node('f"Format {type_}"')
3686 >>> node
3687 <JoinedStr l.1 at 0x7f23b2e4ed30>
3688 """
3690 _astroid_fields = ("values",)
3692 def __init__(
3693 self,
3694 lineno: int | None = None,
3695 col_offset: int | None = None,
3696 parent: NodeNG | None = None,
3697 *,
3698 end_lineno: int | None = None,
3699 end_col_offset: int | None = None,
3700 ) -> None:
3701 """
3702 :param lineno: The line that this node appears on in the source code.
3704 :param col_offset: The column that this node appears on in the
3705 source code.
3707 :param parent: The parent node in the syntax tree.
3709 :param end_lineno: The last line this node appears on in the source code.
3711 :param end_col_offset: The end column this node appears on in the
3712 source code. Note: This is after the last symbol.
3713 """
3714 self.values: list[NodeNG] = []
3715 """The string expressions to be joined.
3717 :type: list(FormattedValue or Const)
3718 """
3720 super().__init__(
3721 lineno=lineno,
3722 col_offset=col_offset,
3723 end_lineno=end_lineno,
3724 end_col_offset=end_col_offset,
3725 parent=parent,
3726 )
3728 def postinit(self, values: list[NodeNG] | None = None) -> None:
3729 """Do some setup after initialisation.
3731 :param value: The string expressions to be joined.
3733 :type: list(FormattedValue or Const)
3734 """
3735 if values is not None:
3736 self.values = values
3738 def get_children(self):
3739 yield from self.values
3742class NamedExpr(_base_nodes.AssignTypeNode):
3743 """Represents the assignment from the assignment expression
3745 >>> import astroid
3746 >>> module = astroid.parse('if a := 1: pass')
3747 >>> module.body[0].test
3748 <NamedExpr l.1 at 0x7f23b2e4ed30>
3749 """
3751 _astroid_fields = ("target", "value")
3753 optional_assign = True
3754 """Whether this node optionally assigns a variable.
3756 Since NamedExpr are not always called they do not always assign."""
3758 def __init__(
3759 self,
3760 lineno: int | None = None,
3761 col_offset: int | None = None,
3762 parent: NodeNG | None = None,
3763 *,
3764 end_lineno: int | None = None,
3765 end_col_offset: int | None = None,
3766 ) -> None:
3767 """
3768 :param lineno: The line that this node appears on in the source code.
3770 :param col_offset: The column that this node appears on in the
3771 source code.
3773 :param parent: The parent node in the syntax tree.
3775 :param end_lineno: The last line this node appears on in the source code.
3777 :param end_col_offset: The end column this node appears on in the
3778 source code. Note: This is after the last symbol.
3779 """
3780 self.target: NodeNG
3781 """The assignment target
3783 :type: Name
3784 """
3786 self.value: NodeNG
3787 """The value that gets assigned in the expression"""
3789 super().__init__(
3790 lineno=lineno,
3791 col_offset=col_offset,
3792 end_lineno=end_lineno,
3793 end_col_offset=end_col_offset,
3794 parent=parent,
3795 )
3797 def postinit(self, target: NodeNG, value: NodeNG) -> None:
3798 self.target = target
3799 self.value = value
3801 assigned_stmts: ClassVar[AssignedStmtsCall[NamedExpr]]
3802 """Returns the assigned statement (non inferred) according to the assignment type.
3803 See astroid/protocols.py for actual implementation.
3804 """
3806 def frame(
3807 self, *, future: Literal[None, True] = None
3808 ) -> nodes.FunctionDef | nodes.Module | nodes.ClassDef | nodes.Lambda:
3809 """The first parent frame node.
3811 A frame node is a :class:`Module`, :class:`FunctionDef`,
3812 or :class:`ClassDef`.
3814 :returns: The first parent frame node.
3815 """
3816 if not self.parent:
3817 raise ParentMissingError(target=self)
3819 # For certain parents NamedExpr evaluate to the scope of the parent
3820 if isinstance(self.parent, (Arguments, Keyword, Comprehension)):
3821 if not self.parent.parent:
3822 raise ParentMissingError(target=self.parent)
3823 if not self.parent.parent.parent:
3824 raise ParentMissingError(target=self.parent.parent)
3825 return self.parent.parent.parent.frame(future=True)
3827 return self.parent.frame(future=True)
3829 def scope(self) -> LocalsDictNodeNG:
3830 """The first parent node defining a new scope.
3831 These can be Module, FunctionDef, ClassDef, Lambda, or GeneratorExp nodes.
3833 :returns: The first parent scope node.
3834 """
3835 if not self.parent:
3836 raise ParentMissingError(target=self)
3838 # For certain parents NamedExpr evaluate to the scope of the parent
3839 if isinstance(self.parent, (Arguments, Keyword, Comprehension)):
3840 if not self.parent.parent:
3841 raise ParentMissingError(target=self.parent)
3842 if not self.parent.parent.parent:
3843 raise ParentMissingError(target=self.parent.parent)
3844 return self.parent.parent.parent.scope()
3846 return self.parent.scope()
3848 def set_local(self, name: str, stmt: NodeNG) -> None:
3849 """Define that the given name is declared in the given statement node.
3850 NamedExpr's in Arguments, Keyword or Comprehension are evaluated in their
3851 parent's parent scope. So we add to their frame's locals.
3853 .. seealso:: :meth:`scope`
3855 :param name: The name that is being defined.
3857 :param stmt: The statement that defines the given name.
3858 """
3859 self.frame(future=True).set_local(name, stmt)
3862class Unknown(_base_nodes.AssignTypeNode):
3863 """This node represents a node in a constructed AST where
3864 introspection is not possible. At the moment, it's only used in
3865 the args attribute of FunctionDef nodes where function signature
3866 introspection failed.
3867 """
3869 name = "Unknown"
3871 def __init__(
3872 self,
3873 lineno: None = None,
3874 col_offset: None = None,
3875 parent: None = None,
3876 *,
3877 end_lineno: None = None,
3878 end_col_offset: None = None,
3879 ) -> None:
3880 super().__init__(
3881 lineno=lineno,
3882 col_offset=col_offset,
3883 end_lineno=end_lineno,
3884 end_col_offset=end_col_offset,
3885 parent=parent,
3886 )
3888 def qname(self) -> Literal["Unknown"]:
3889 return "Unknown"
3891 def _infer(self, context: InferenceContext | None = None, **kwargs):
3892 """Inference on an Unknown node immediately terminates."""
3893 yield util.Uninferable
3896class EvaluatedObject(NodeNG):
3897 """Contains an object that has already been inferred
3899 This class is useful to pre-evaluate a particular node,
3900 with the resulting class acting as the non-evaluated node.
3901 """
3903 name = "EvaluatedObject"
3904 _astroid_fields = ("original",)
3905 _other_fields = ("value",)
3907 def __init__(self, original: NodeNG, value: NodeNG | util.UninferableBase) -> None:
3908 self.original: NodeNG = original
3909 """The original node that has already been evaluated"""
3911 self.value: NodeNG | util.UninferableBase = value
3912 """The inferred value"""
3914 super().__init__(
3915 lineno=self.original.lineno,
3916 col_offset=self.original.col_offset,
3917 parent=self.original.parent,
3918 end_lineno=self.original.end_lineno,
3919 end_col_offset=self.original.end_col_offset,
3920 )
3922 def _infer(
3923 self, context: InferenceContext | None = None, **kwargs: Any
3924 ) -> Generator[NodeNG | util.UninferableBase, None, None]:
3925 yield self.value
3928# Pattern matching #######################################################
3931class Match(_base_nodes.Statement, _base_nodes.MultiLineBlockNode):
3932 """Class representing a :class:`ast.Match` node.
3934 >>> import astroid
3935 >>> node = astroid.extract_node('''
3936 match x:
3937 case 200:
3938 ...
3939 case _:
3940 ...
3941 ''')
3942 >>> node
3943 <Match l.2 at 0x10c24e170>
3944 """
3946 _astroid_fields = ("subject", "cases")
3947 _multi_line_block_fields = ("cases",)
3949 def __init__(
3950 self,
3951 lineno: int | None = None,
3952 col_offset: int | None = None,
3953 parent: NodeNG | None = None,
3954 *,
3955 end_lineno: int | None = None,
3956 end_col_offset: int | None = None,
3957 ) -> None:
3958 self.subject: NodeNG
3959 self.cases: list[MatchCase]
3960 super().__init__(
3961 lineno=lineno,
3962 col_offset=col_offset,
3963 end_lineno=end_lineno,
3964 end_col_offset=end_col_offset,
3965 parent=parent,
3966 )
3968 def postinit(
3969 self,
3970 *,
3971 subject: NodeNG,
3972 cases: list[MatchCase],
3973 ) -> None:
3974 self.subject = subject
3975 self.cases = cases
3978class Pattern(NodeNG):
3979 """Base class for all Pattern nodes."""
3982class MatchCase(_base_nodes.MultiLineBlockNode):
3983 """Class representing a :class:`ast.match_case` node.
3985 >>> import astroid
3986 >>> node = astroid.extract_node('''
3987 match x:
3988 case 200:
3989 ...
3990 ''')
3991 >>> node.cases[0]
3992 <MatchCase l.3 at 0x10c24e590>
3993 """
3995 _astroid_fields = ("pattern", "guard", "body")
3996 _multi_line_block_fields = ("body",)
3998 lineno: None
3999 col_offset: None
4000 end_lineno: None
4001 end_col_offset: None
4003 def __init__(self, *, parent: NodeNG | None = None) -> None:
4004 self.pattern: Pattern
4005 self.guard: NodeNG | None
4006 self.body: list[NodeNG]
4007 super().__init__(
4008 parent=parent,
4009 lineno=None,
4010 col_offset=None,
4011 end_lineno=None,
4012 end_col_offset=None,
4013 )
4015 def postinit(
4016 self,
4017 *,
4018 pattern: Pattern,
4019 guard: NodeNG | None,
4020 body: list[NodeNG],
4021 ) -> None:
4022 self.pattern = pattern
4023 self.guard = guard
4024 self.body = body
4027class MatchValue(Pattern):
4028 """Class representing a :class:`ast.MatchValue` node.
4030 >>> import astroid
4031 >>> node = astroid.extract_node('''
4032 match x:
4033 case 200:
4034 ...
4035 ''')
4036 >>> node.cases[0].pattern
4037 <MatchValue l.3 at 0x10c24e200>
4038 """
4040 _astroid_fields = ("value",)
4042 def __init__(
4043 self,
4044 lineno: int | None = None,
4045 col_offset: int | None = None,
4046 parent: NodeNG | None = None,
4047 *,
4048 end_lineno: int | None = None,
4049 end_col_offset: int | None = None,
4050 ) -> None:
4051 self.value: NodeNG
4052 super().__init__(
4053 lineno=lineno,
4054 col_offset=col_offset,
4055 end_lineno=end_lineno,
4056 end_col_offset=end_col_offset,
4057 parent=parent,
4058 )
4060 def postinit(self, *, value: NodeNG) -> None:
4061 self.value = value
4064class MatchSingleton(Pattern):
4065 """Class representing a :class:`ast.MatchSingleton` node.
4067 >>> import astroid
4068 >>> node = astroid.extract_node('''
4069 match x:
4070 case True:
4071 ...
4072 case False:
4073 ...
4074 case None:
4075 ...
4076 ''')
4077 >>> node.cases[0].pattern
4078 <MatchSingleton l.3 at 0x10c2282e0>
4079 >>> node.cases[1].pattern
4080 <MatchSingleton l.5 at 0x10c228af0>
4081 >>> node.cases[2].pattern
4082 <MatchSingleton l.7 at 0x10c229f90>
4083 """
4085 _other_fields = ("value",)
4087 def __init__(
4088 self,
4089 *,
4090 value: Literal[True, False, None],
4091 lineno: int | None = None,
4092 col_offset: int | None = None,
4093 end_lineno: int | None = None,
4094 end_col_offset: int | None = None,
4095 parent: NodeNG | None = None,
4096 ) -> None:
4097 self.value = value
4098 super().__init__(
4099 lineno=lineno,
4100 col_offset=col_offset,
4101 end_lineno=end_lineno,
4102 end_col_offset=end_col_offset,
4103 parent=parent,
4104 )
4107class MatchSequence(Pattern):
4108 """Class representing a :class:`ast.MatchSequence` node.
4110 >>> import astroid
4111 >>> node = astroid.extract_node('''
4112 match x:
4113 case [1, 2]:
4114 ...
4115 case (1, 2, *_):
4116 ...
4117 ''')
4118 >>> node.cases[0].pattern
4119 <MatchSequence l.3 at 0x10ca80d00>
4120 >>> node.cases[1].pattern
4121 <MatchSequence l.5 at 0x10ca80b20>
4122 """
4124 _astroid_fields = ("patterns",)
4126 def __init__(
4127 self,
4128 lineno: int | None = None,
4129 col_offset: int | None = None,
4130 parent: NodeNG | None = None,
4131 *,
4132 end_lineno: int | None = None,
4133 end_col_offset: int | None = None,
4134 ) -> None:
4135 self.patterns: list[Pattern]
4136 super().__init__(
4137 lineno=lineno,
4138 col_offset=col_offset,
4139 end_lineno=end_lineno,
4140 end_col_offset=end_col_offset,
4141 parent=parent,
4142 )
4144 def postinit(self, *, patterns: list[Pattern]) -> None:
4145 self.patterns = patterns
4148class MatchMapping(_base_nodes.AssignTypeNode, Pattern):
4149 """Class representing a :class:`ast.MatchMapping` node.
4151 >>> import astroid
4152 >>> node = astroid.extract_node('''
4153 match x:
4154 case {1: "Hello", 2: "World", 3: _, **rest}:
4155 ...
4156 ''')
4157 >>> node.cases[0].pattern
4158 <MatchMapping l.3 at 0x10c8a8850>
4159 """
4161 _astroid_fields = ("keys", "patterns", "rest")
4163 def __init__(
4164 self,
4165 lineno: int | None = None,
4166 col_offset: int | None = None,
4167 parent: NodeNG | None = None,
4168 *,
4169 end_lineno: int | None = None,
4170 end_col_offset: int | None = None,
4171 ) -> None:
4172 self.keys: list[NodeNG]
4173 self.patterns: list[Pattern]
4174 self.rest: AssignName | None
4175 super().__init__(
4176 lineno=lineno,
4177 col_offset=col_offset,
4178 end_lineno=end_lineno,
4179 end_col_offset=end_col_offset,
4180 parent=parent,
4181 )
4183 def postinit(
4184 self,
4185 *,
4186 keys: list[NodeNG],
4187 patterns: list[Pattern],
4188 rest: AssignName | None,
4189 ) -> None:
4190 self.keys = keys
4191 self.patterns = patterns
4192 self.rest = rest
4194 assigned_stmts: ClassVar[
4195 Callable[
4196 [
4197 MatchMapping,
4198 AssignName,
4199 InferenceContext | None,
4200 None,
4201 ],
4202 Generator[NodeNG, None, None],
4203 ]
4204 ]
4205 """Returns the assigned statement (non inferred) according to the assignment type.
4206 See astroid/protocols.py for actual implementation.
4207 """
4210class MatchClass(Pattern):
4211 """Class representing a :class:`ast.MatchClass` node.
4213 >>> import astroid
4214 >>> node = astroid.extract_node('''
4215 match x:
4216 case Point2D(0, 0):
4217 ...
4218 case Point3D(x=0, y=0, z=0):
4219 ...
4220 ''')
4221 >>> node.cases[0].pattern
4222 <MatchClass l.3 at 0x10ca83940>
4223 >>> node.cases[1].pattern
4224 <MatchClass l.5 at 0x10ca80880>
4225 """
4227 _astroid_fields = ("cls", "patterns", "kwd_patterns")
4228 _other_fields = ("kwd_attrs",)
4230 def __init__(
4231 self,
4232 lineno: int | None = None,
4233 col_offset: int | None = None,
4234 parent: NodeNG | None = None,
4235 *,
4236 end_lineno: int | None = None,
4237 end_col_offset: int | None = None,
4238 ) -> None:
4239 self.cls: NodeNG
4240 self.patterns: list[Pattern]
4241 self.kwd_attrs: list[str]
4242 self.kwd_patterns: list[Pattern]
4243 super().__init__(
4244 lineno=lineno,
4245 col_offset=col_offset,
4246 end_lineno=end_lineno,
4247 end_col_offset=end_col_offset,
4248 parent=parent,
4249 )
4251 def postinit(
4252 self,
4253 *,
4254 cls: NodeNG,
4255 patterns: list[Pattern],
4256 kwd_attrs: list[str],
4257 kwd_patterns: list[Pattern],
4258 ) -> None:
4259 self.cls = cls
4260 self.patterns = patterns
4261 self.kwd_attrs = kwd_attrs
4262 self.kwd_patterns = kwd_patterns
4265class MatchStar(_base_nodes.AssignTypeNode, Pattern):
4266 """Class representing a :class:`ast.MatchStar` node.
4268 >>> import astroid
4269 >>> node = astroid.extract_node('''
4270 match x:
4271 case [1, *_]:
4272 ...
4273 ''')
4274 >>> node.cases[0].pattern.patterns[1]
4275 <MatchStar l.3 at 0x10ca809a0>
4276 """
4278 _astroid_fields = ("name",)
4280 def __init__(
4281 self,
4282 lineno: int | None = None,
4283 col_offset: int | None = None,
4284 parent: NodeNG | None = None,
4285 *,
4286 end_lineno: int | None = None,
4287 end_col_offset: int | None = None,
4288 ) -> None:
4289 self.name: AssignName | None
4290 super().__init__(
4291 lineno=lineno,
4292 col_offset=col_offset,
4293 end_lineno=end_lineno,
4294 end_col_offset=end_col_offset,
4295 parent=parent,
4296 )
4298 def postinit(self, *, name: AssignName | None) -> None:
4299 self.name = name
4301 assigned_stmts: ClassVar[
4302 Callable[
4303 [
4304 MatchStar,
4305 AssignName,
4306 InferenceContext | None,
4307 None,
4308 ],
4309 Generator[NodeNG, None, None],
4310 ]
4311 ]
4312 """Returns the assigned statement (non inferred) according to the assignment type.
4313 See astroid/protocols.py for actual implementation.
4314 """
4317class MatchAs(_base_nodes.AssignTypeNode, Pattern):
4318 """Class representing a :class:`ast.MatchAs` node.
4320 >>> import astroid
4321 >>> node = astroid.extract_node('''
4322 match x:
4323 case [1, a]:
4324 ...
4325 case {'key': b}:
4326 ...
4327 case Point2D(0, 0) as c:
4328 ...
4329 case d:
4330 ...
4331 ''')
4332 >>> node.cases[0].pattern.patterns[1]
4333 <MatchAs l.3 at 0x10d0b2da0>
4334 >>> node.cases[1].pattern.patterns[0]
4335 <MatchAs l.5 at 0x10d0b2920>
4336 >>> node.cases[2].pattern
4337 <MatchAs l.7 at 0x10d0b06a0>
4338 >>> node.cases[3].pattern
4339 <MatchAs l.9 at 0x10d09b880>
4340 """
4342 _astroid_fields = ("pattern", "name")
4344 def __init__(
4345 self,
4346 lineno: int | None = None,
4347 col_offset: int | None = None,
4348 parent: NodeNG | None = None,
4349 *,
4350 end_lineno: int | None = None,
4351 end_col_offset: int | None = None,
4352 ) -> None:
4353 self.pattern: Pattern | None
4354 self.name: AssignName | None
4355 super().__init__(
4356 lineno=lineno,
4357 col_offset=col_offset,
4358 end_lineno=end_lineno,
4359 end_col_offset=end_col_offset,
4360 parent=parent,
4361 )
4363 def postinit(
4364 self,
4365 *,
4366 pattern: Pattern | None,
4367 name: AssignName | None,
4368 ) -> None:
4369 self.pattern = pattern
4370 self.name = name
4372 assigned_stmts: ClassVar[
4373 Callable[
4374 [
4375 MatchAs,
4376 AssignName,
4377 InferenceContext | None,
4378 None,
4379 ],
4380 Generator[NodeNG, None, None],
4381 ]
4382 ]
4383 """Returns the assigned statement (non inferred) according to the assignment type.
4384 See astroid/protocols.py for actual implementation.
4385 """
4388class MatchOr(Pattern):
4389 """Class representing a :class:`ast.MatchOr` node.
4391 >>> import astroid
4392 >>> node = astroid.extract_node('''
4393 match x:
4394 case 400 | 401 | 402:
4395 ...
4396 ''')
4397 >>> node.cases[0].pattern
4398 <MatchOr l.3 at 0x10d0b0b50>
4399 """
4401 _astroid_fields = ("patterns",)
4403 def __init__(
4404 self,
4405 lineno: int | None = None,
4406 col_offset: int | None = None,
4407 parent: NodeNG | None = None,
4408 *,
4409 end_lineno: int | None = None,
4410 end_col_offset: int | None = None,
4411 ) -> None:
4412 self.patterns: list[Pattern]
4413 super().__init__(
4414 lineno=lineno,
4415 col_offset=col_offset,
4416 end_lineno=end_lineno,
4417 end_col_offset=end_col_offset,
4418 parent=parent,
4419 )
4421 def postinit(self, *, patterns: list[Pattern]) -> None:
4422 self.patterns = patterns
4425# constants ##############################################################
4427# The _proxied attribute of all container types (List, Tuple, etc.)
4428# are set during bootstrapping by _astroid_bootstrapping().
4429CONST_CLS: dict[type, type[NodeNG]] = {
4430 list: List,
4431 tuple: Tuple,
4432 dict: Dict,
4433 set: Set,
4434 type(None): Const,
4435 type(NotImplemented): Const,
4436 type(...): Const,
4437 bool: Const,
4438 int: Const,
4439 float: Const,
4440 complex: Const,
4441 str: Const,
4442 bytes: Const,
4443}
4446def _create_basic_elements(
4447 value: Iterable[Any], node: List | Set | Tuple
4448) -> list[NodeNG]:
4449 """Create a list of nodes to function as the elements of a new node."""
4450 elements: list[NodeNG] = []
4451 for element in value:
4452 element_node = const_factory(element)
4453 element_node.parent = node
4454 elements.append(element_node)
4455 return elements
4458def _create_dict_items(
4459 values: Mapping[Any, Any], node: Dict
4460) -> list[tuple[SuccessfulInferenceResult, SuccessfulInferenceResult]]:
4461 """Create a list of node pairs to function as the items of a new dict node."""
4462 elements: list[tuple[SuccessfulInferenceResult, SuccessfulInferenceResult]] = []
4463 for key, value in values.items():
4464 key_node = const_factory(key)
4465 key_node.parent = node
4466 value_node = const_factory(value)
4467 value_node.parent = node
4468 elements.append((key_node, value_node))
4469 return elements
4472def const_factory(value: Any) -> ConstFactoryResult:
4473 """Return an astroid node for a python value."""
4474 assert not isinstance(value, NodeNG)
4476 # This only handles instances of the CONST types. Any
4477 # subclasses get inferred as EmptyNode.
4478 # TODO: See if we should revisit these with the normal builder.
4479 if value.__class__ not in CONST_CLS:
4480 node = EmptyNode()
4481 node.object = value
4482 return node
4484 instance: List | Set | Tuple | Dict
4485 initializer_cls = CONST_CLS[value.__class__]
4486 if issubclass(initializer_cls, (List, Set, Tuple)):
4487 instance = initializer_cls(
4488 lineno=None,
4489 col_offset=None,
4490 parent=None,
4491 end_lineno=None,
4492 end_col_offset=None,
4493 )
4494 instance.postinit(_create_basic_elements(value, instance))
4495 return instance
4496 if issubclass(initializer_cls, Dict):
4497 instance = initializer_cls(
4498 lineno=None,
4499 col_offset=None,
4500 parent=None,
4501 end_lineno=None,
4502 end_col_offset=None,
4503 )
4504 instance.postinit(_create_dict_items(value, instance))
4505 return instance
4506 return Const(value)