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

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 

4 

5"""Module for some node classes. More nodes in scoped_nodes.py""" 

6 

7from __future__ import annotations 

8 

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) 

25 

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) 

49 

50if sys.version_info >= (3, 11): 

51 from typing import Self 

52else: 

53 from typing_extensions import Self 

54 

55 

56if TYPE_CHECKING: 

57 from astroid import nodes 

58 from astroid.nodes import LocalsDictNodeNG 

59 

60 

61def _is_const(value) -> bool: 

62 return isinstance(value, tuple(CONST_CLS)) 

63 

64 

65_NodesT = TypeVar("_NodesT", bound=NodeNG) 

66_BadOpMessageT = TypeVar("_BadOpMessageT", bound=util.BadOperationMessage) 

67 

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] 

87 

88 

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) 

112 

113 return {"node": stmt, "context": context} 

114 

115 

116def are_exclusive(stmt1, stmt2, exceptions: list[str] | None = None) -> bool: 

117 """return true if the two given statements are mutually exclusive 

118 

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. 

122 

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 

187 

188 

189# getitem() helpers. 

190 

191_SLICE_SENTINEL = object() 

192 

193 

194def _slice_value(index, context: InferenceContext | None = None): 

195 """Get the value of the given slice index.""" 

196 

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 

214 

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 

219 

220 

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) 

227 

228 raise AstroidTypeError( 

229 message="Could not infer slice used in subscript", 

230 node=node, 

231 index=node.parent, 

232 context=context, 

233 ) 

234 

235 

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 

265 

266 raise AstroidTypeError(f"Could not use {index} as subscript index") 

267 

268 

269class BaseContainer(_base_nodes.ParentAssignNode, Instance, metaclass=abc.ABCMeta): 

270 """Base class for Set, FrozenSet, Tuple and List.""" 

271 

272 _astroid_fields = ("elts",) 

273 

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.""" 

285 

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 ) 

293 

294 def postinit(self, elts: list[SuccessfulInferenceResult]) -> None: 

295 self.elts = elts 

296 

297 @classmethod 

298 def from_elements(cls, elts: Iterable[Any]) -> Self: 

299 """Create a node of this type from the given list of elements. 

300 

301 :param elts: The list of elements that the node should contain. 

302 

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 

314 

315 def itered(self): 

316 """An iterator over the elements this node contains. 

317 

318 :returns: The contents of this node. 

319 :rtype: iterable(NodeNG) 

320 """ 

321 return self.elts 

322 

323 def bool_value(self, context: InferenceContext | None = None) -> bool: 

324 """Determine the boolean value of this node. 

325 

326 :returns: The boolean value of this node. 

327 """ 

328 return bool(self.elts) 

329 

330 @abc.abstractmethod 

331 def pytype(self) -> str: 

332 """Get the name of the type that this node represents. 

333 

334 :returns: The name of the type. 

335 """ 

336 

337 def get_children(self): 

338 yield from self.elts 

339 

340 

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.""" 

344 

345 @lru_cache # noqa 

346 def lookup(self, name: str) -> tuple[LocalsDictNodeNG, list[NodeNG]]: 

347 """Lookup where the given variable is assigned. 

348 

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. 

352 

353 :param name: The name of the variable to find assignments for. 

354 

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) 

360 

361 def ilookup(self, name): 

362 """Lookup the inferred values of the given variable. 

363 

364 :param name: The variable name to find values for. 

365 :type name: str 

366 

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) 

374 

375 

376# Name classes 

377 

378 

379class AssignName(_base_nodes.NoChildrenNode, LookupMixIn, _base_nodes.ParentAssignNode): 

380 """Variation of :class:`ast.Assign` representing assignment to a name. 

381 

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. 

384 

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 """ 

394 

395 _other_fields = ("name",) 

396 

397 infer_lhs: ClassVar[InferLHS[AssignName]] 

398 

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.""" 

411 

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 ) 

419 

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 """ 

424 

425 

426class DelName(_base_nodes.NoChildrenNode, LookupMixIn, _base_nodes.ParentAssignNode): 

427 """Variation of :class:`ast.Delete` representing deletion of a name. 

428 

429 A :class:`DelName` is the name of something that is deleted. 

430 

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 """ 

438 

439 _other_fields = ("name",) 

440 

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.""" 

453 

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 ) 

461 

462 

463class Name(_base_nodes.NoChildrenNode, LookupMixIn): 

464 """Class representing an :class:`ast.Name` node. 

465 

466 A :class:`Name` node is something that is named, but not covered by 

467 :class:`AssignName` or :class:`DelName`. 

468 

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 """ 

478 

479 _other_fields = ("name",) 

480 

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.""" 

493 

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 ) 

501 

502 def _get_name_nodes(self): 

503 yield self 

504 

505 for child_node in self.get_children(): 

506 yield from child_node._get_name_nodes() 

507 

508 

509class Arguments(_base_nodes.AssignTypeNode): 

510 """Class representing an :class:`ast.arguments` node. 

511 

512 An :class:`Arguments` node represents that arguments in a 

513 function definition. 

514 

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 """ 

522 

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 ) 

548 

549 _other_fields = ("vararg", "kwarg") 

550 

551 args: list[AssignName] | None 

552 """The names of the required arguments. 

553 

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 """ 

559 

560 defaults: list[NodeNG] | None 

561 """The default values for arguments that can be passed positionally.""" 

562 

563 kwonlyargs: list[AssignName] 

564 """The keyword arguments that cannot be passed positionally.""" 

565 

566 posonlyargs: list[AssignName] 

567 """The arguments that can only be passed positionally.""" 

568 

569 kw_defaults: list[NodeNG | None] | None 

570 """The default values for keyword arguments that cannot be passed positionally.""" 

571 

572 annotations: list[NodeNG | None] 

573 """The type annotations of arguments that can be passed positionally.""" 

574 

575 posonlyargs_annotations: list[NodeNG | None] 

576 """The type annotations of arguments that can only be passed positionally.""" 

577 

578 kwonlyargs_annotations: list[NodeNG | None] 

579 """The type annotations of arguments that cannot be passed positionally.""" 

580 

581 type_comment_args: list[NodeNG | None] 

582 """The type annotation, passed by a type comment, of each argument. 

583 

584 If an argument does not have a type comment, 

585 the value for that argument will be None. 

586 """ 

587 

588 type_comment_kwonlyargs: list[NodeNG | None] 

589 """The type annotation, passed by a type comment, of each keyword only argument. 

590 

591 If an argument does not have a type comment, 

592 the value for that argument will be None. 

593 """ 

594 

595 type_comment_posonlyargs: list[NodeNG | None] 

596 """The type annotation, passed by a type comment, of each positional argument. 

597 

598 If an argument does not have a type comment, 

599 the value for that argument will be None. 

600 """ 

601 

602 varargannotation: NodeNG | None 

603 """The type annotation for the variable length arguments.""" 

604 

605 kwargannotation: NodeNG | None 

606 """The type annotation for the variable length keyword arguments.""" 

607 

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 ) 

617 

618 self.vararg = vararg 

619 """The name of the variable length arguments.""" 

620 

621 self.kwarg = kwarg 

622 """The name of the variable length keyword arguments.""" 

623 

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 

649 

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 

662 

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 """ 

667 

668 def _infer_name(self, frame, name): 

669 if self.parent is frame: 

670 return name 

671 return None 

672 

673 @cached_property 

674 def fromlineno(self) -> int: 

675 """The first line that this node appears on in the source code. 

676 

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) 

681 

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 ())) 

686 

687 def format_args(self, *, skippable_names: set[str] | None = None) -> str: 

688 """Get the arguments formatted as string. 

689 

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)] 

700 

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) 

736 

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. 

744 

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]] = {} 

752 

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)] 

760 

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) 

768 

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) 

782 

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) 

788 

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) 

797 

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) 

803 

804 return pos_only, kw_only 

805 

806 def default_value(self, argname): 

807 """Get the default value for an argument. 

808 

809 :param argname: The name of the argument to get the default value for. 

810 :type argname: str 

811 

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) 

825 

826 def is_argument(self, name) -> bool: 

827 """Check if the given name is defined in the arguments. 

828 

829 :param name: The name to check for. 

830 :type name: str 

831 

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 ) 

843 

844 def find_argname(self, argname, rec=False): 

845 """Get the index and :class:`AssignName` node for given name. 

846 

847 :param argname: The name of the argument to search for. 

848 :type argname: str 

849 

850 :param rec: Whether or not to include arguments in unpacked tuples 

851 in the search. 

852 :type rec: bool 

853 

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 

860 

861 def get_children(self): 

862 yield from self.posonlyargs or () 

863 

864 for elt in self.posonlyargs_annotations: 

865 if elt is not None: 

866 yield elt 

867 

868 yield from self.args or () 

869 

870 if self.defaults is not None: 

871 yield from self.defaults 

872 yield from self.kwonlyargs 

873 

874 for elt in self.kw_defaults or (): 

875 if elt is not None: 

876 yield elt 

877 

878 for elt in self.annotations: 

879 if elt is not None: 

880 yield elt 

881 

882 if self.varargannotation is not None: 

883 yield self.varargannotation 

884 

885 if self.kwargannotation is not None: 

886 yield self.kwargannotation 

887 

888 for elt in self.kwonlyargs_annotations: 

889 if elt is not None: 

890 yield elt 

891 

892 

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 

903 

904 

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) 

930 

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) 

935 

936 

937class AssignAttr(_base_nodes.ParentAssignNode): 

938 """Variation of :class:`ast.Assign` representing assignment to an attribute. 

939 

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 """ 

949 

950 _astroid_fields = ("expr",) 

951 _other_fields = ("attrname",) 

952 

953 infer_lhs: ClassVar[InferLHS[AssignAttr]] 

954 

955 expr: NodeNG 

956 """What has the attribute that is being assigned to.""" 

957 

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.""" 

970 

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 ) 

978 

979 def postinit(self, expr: NodeNG) -> None: 

980 self.expr = expr 

981 

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 """ 

986 

987 def get_children(self): 

988 yield self.expr 

989 

990 

991class Assert(_base_nodes.Statement): 

992 """Class representing an :class:`ast.Assert` node. 

993 

994 An :class:`Assert` node represents an assert statement. 

995 

996 >>> import astroid 

997 >>> node = astroid.extract_node('assert len(things) == 10, "Not enough things"') 

998 >>> node 

999 <Assert l.1 at 0x7effe1d527b8> 

1000 """ 

1001 

1002 _astroid_fields = ("test", "fail") 

1003 

1004 test: NodeNG 

1005 """The test that passes or fails the assertion.""" 

1006 

1007 fail: NodeNG | None 

1008 """The message shown when the assertion fails.""" 

1009 

1010 def postinit(self, test: NodeNG, fail: NodeNG | None) -> None: 

1011 self.fail = fail 

1012 self.test = test 

1013 

1014 def get_children(self): 

1015 yield self.test 

1016 

1017 if self.fail is not None: 

1018 yield self.fail 

1019 

1020 

1021class Assign(_base_nodes.AssignTypeNode, _base_nodes.Statement): 

1022 """Class representing an :class:`ast.Assign` node. 

1023 

1024 An :class:`Assign` is a statement where something is explicitly 

1025 asssigned to. 

1026 

1027 >>> import astroid 

1028 >>> node = astroid.extract_node('variable = range(10)') 

1029 >>> node 

1030 <Assign l.1 at 0x7effe1db8550> 

1031 """ 

1032 

1033 targets: list[NodeNG] 

1034 """What is being assigned to.""" 

1035 

1036 value: NodeNG 

1037 """The value being assigned to the variables.""" 

1038 

1039 type_annotation: NodeNG | None 

1040 """If present, this will contain the type annotation passed by a type comment""" 

1041 

1042 _astroid_fields = ("targets", "value") 

1043 _other_other_fields = ("type_annotation",) 

1044 

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 

1054 

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 """ 

1059 

1060 def get_children(self): 

1061 yield from self.targets 

1062 

1063 yield self.value 

1064 

1065 @cached_property 

1066 def _assign_nodes_in_scope(self) -> list[nodes.Assign]: 

1067 return [self, *self.value._assign_nodes_in_scope] 

1068 

1069 def _get_yield_nodes_skip_lambdas(self): 

1070 yield from self.value._get_yield_nodes_skip_lambdas() 

1071 

1072 

1073class AnnAssign(_base_nodes.AssignTypeNode, _base_nodes.Statement): 

1074 """Class representing an :class:`ast.AnnAssign` node. 

1075 

1076 An :class:`AnnAssign` is an assignment with a type annotation. 

1077 

1078 >>> import astroid 

1079 >>> node = astroid.extract_node('variable: List[int] = range(10)') 

1080 >>> node 

1081 <AnnAssign l.1 at 0x7effe1d4c630> 

1082 """ 

1083 

1084 _astroid_fields = ("target", "annotation", "value") 

1085 _other_fields = ("simple",) 

1086 

1087 target: Name | Attribute | Subscript 

1088 """What is being assigned to.""" 

1089 

1090 annotation: NodeNG 

1091 """The type annotation of what is being assigned to.""" 

1092 

1093 value: NodeNG | None 

1094 """The value being assigned to the variables.""" 

1095 

1096 simple: int 

1097 """Whether :attr:`target` is a pure name or a complex statement.""" 

1098 

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 

1110 

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 """ 

1115 

1116 def get_children(self): 

1117 yield self.target 

1118 yield self.annotation 

1119 

1120 if self.value is not None: 

1121 yield self.value 

1122 

1123 

1124class AugAssign(_base_nodes.AssignTypeNode, _base_nodes.Statement): 

1125 """Class representing an :class:`ast.AugAssign` node. 

1126 

1127 An :class:`AugAssign` is an assignment paired with an operator. 

1128 

1129 >>> import astroid 

1130 >>> node = astroid.extract_node('variable += 1') 

1131 >>> node 

1132 <AugAssign l.1 at 0x7effe1db4d68> 

1133 """ 

1134 

1135 _astroid_fields = ("target", "value") 

1136 _other_fields = ("op",) 

1137 

1138 target: Name | Attribute | Subscript 

1139 """What is being assigned to.""" 

1140 

1141 value: NodeNG 

1142 """The value being assigned to the variable.""" 

1143 

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. 

1156 

1157 This includes the equals sign. 

1158 """ 

1159 

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 ) 

1167 

1168 def postinit(self, target: Name | Attribute | Subscript, value: NodeNG) -> None: 

1169 self.target = target 

1170 self.value = value 

1171 

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 """ 

1176 

1177 # This is set by inference.py 

1178 _infer_augassign: ClassVar[ 

1179 InferBinaryOperation[AugAssign, util.BadBinaryOperationMessage] 

1180 ] 

1181 

1182 def type_errors(self, context: InferenceContext | None = None): 

1183 """Get a list of type errors which can occur during inference. 

1184 

1185 Each TypeError is represented by a :class:`BadBinaryOperationMessage` , 

1186 which holds the original exception. 

1187 

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 [] 

1200 

1201 def get_children(self): 

1202 yield self.target 

1203 yield self.value 

1204 

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() 

1209 

1210 

1211class BinOp(NodeNG): 

1212 """Class representing an :class:`ast.BinOp` node. 

1213 

1214 A :class:`BinOp` node is an application of a binary operator. 

1215 

1216 >>> import astroid 

1217 >>> node = astroid.extract_node('a + b') 

1218 >>> node 

1219 <BinOp l.1 at 0x7f23b2e8cfd0> 

1220 """ 

1221 

1222 _astroid_fields = ("left", "right") 

1223 _other_fields = ("op",) 

1224 

1225 left: NodeNG 

1226 """What is being applied to the operator on the left side.""" 

1227 

1228 right: NodeNG 

1229 """What is being applied to the operator on the right side.""" 

1230 

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.""" 

1243 

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 ) 

1251 

1252 def postinit(self, left: NodeNG, right: NodeNG) -> None: 

1253 self.left = left 

1254 self.right = right 

1255 

1256 # This is set by inference.py 

1257 _infer_binop: ClassVar[InferBinaryOperation[BinOp, util.BadBinaryOperationMessage]] 

1258 

1259 def type_errors(self, context: InferenceContext | None = None): 

1260 """Get a list of type errors which can occur during inference. 

1261 

1262 Each TypeError is represented by a :class:`BadBinaryOperationMessage`, 

1263 which holds the original exception. 

1264 

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 [] 

1277 

1278 def get_children(self): 

1279 yield self.left 

1280 yield self.right 

1281 

1282 def op_precedence(self): 

1283 return OP_PRECEDENCE[self.op] 

1284 

1285 def op_left_associative(self) -> bool: 

1286 # 2**3**4 == 2**(3**4) 

1287 return self.op != "**" 

1288 

1289 

1290class BoolOp(NodeNG): 

1291 """Class representing an :class:`ast.BoolOp` node. 

1292 

1293 A :class:`BoolOp` is an application of a boolean operator. 

1294 

1295 >>> import astroid 

1296 >>> node = astroid.extract_node('a and b') 

1297 >>> node 

1298 <BinOp l.1 at 0x7f23b2e71c50> 

1299 """ 

1300 

1301 _astroid_fields = ("values",) 

1302 _other_fields = ("op",) 

1303 

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. 

1317 

1318 :param lineno: The line that this node appears on in the source code. 

1319 

1320 :param col_offset: The column that this node appears on in the 

1321 source code. 

1322 

1323 :param parent: The parent node in the syntax tree. 

1324 

1325 :param end_lineno: The last line this node appears on in the source code. 

1326 

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.""" 

1332 

1333 self.values: list[NodeNG] = [] 

1334 """The values being applied to the operator.""" 

1335 

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 ) 

1343 

1344 def postinit(self, values: list[NodeNG] | None = None) -> None: 

1345 """Do some setup after initialisation. 

1346 

1347 :param values: The values being applied to the operator. 

1348 """ 

1349 if values is not None: 

1350 self.values = values 

1351 

1352 def get_children(self): 

1353 yield from self.values 

1354 

1355 def op_precedence(self): 

1356 return OP_PRECEDENCE[self.op] 

1357 

1358 

1359class Break(_base_nodes.NoChildrenNode, _base_nodes.Statement): 

1360 """Class representing an :class:`ast.Break` node. 

1361 

1362 >>> import astroid 

1363 >>> node = astroid.extract_node('break') 

1364 >>> node 

1365 <Break l.1 at 0x7f23b2e9e5c0> 

1366 """ 

1367 

1368 

1369class Call(NodeNG): 

1370 """Class representing an :class:`ast.Call` node. 

1371 

1372 A :class:`Call` node is a call to a function, method, etc. 

1373 

1374 >>> import astroid 

1375 >>> node = astroid.extract_node('function()') 

1376 >>> node 

1377 <Call l.1 at 0x7f23b2e71eb8> 

1378 """ 

1379 

1380 _astroid_fields = ("func", "args", "keywords") 

1381 

1382 func: NodeNG 

1383 """What is being called.""" 

1384 

1385 args: list[NodeNG] 

1386 """The positional arguments being given to the call.""" 

1387 

1388 keywords: list[Keyword] 

1389 """The keyword arguments being given to the call.""" 

1390 

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 

1397 

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)] 

1402 

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] 

1407 

1408 def get_children(self): 

1409 yield self.func 

1410 

1411 yield from self.args 

1412 

1413 yield from self.keywords 

1414 

1415 

1416class Compare(NodeNG): 

1417 """Class representing an :class:`ast.Compare` node. 

1418 

1419 A :class:`Compare` node indicates a comparison. 

1420 

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 """ 

1428 

1429 _astroid_fields = ("left", "ops") 

1430 

1431 left: NodeNG 

1432 """The value at the left being applied to a comparison operator.""" 

1433 

1434 ops: list[tuple[str, NodeNG]] 

1435 """The remainder of the operators and their relevant right hand value.""" 

1436 

1437 def postinit(self, left: NodeNG, ops: list[tuple[str, NodeNG]]) -> None: 

1438 self.left = left 

1439 self.ops = ops 

1440 

1441 def get_children(self): 

1442 """Get the child nodes below this node. 

1443 

1444 Overridden to handle the tuple fields and skip returning the operator 

1445 strings. 

1446 

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' 

1453 

1454 def last_child(self): 

1455 """An optimized version of list(get_children())[-1] 

1456 

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 

1463 

1464 

1465class Comprehension(NodeNG): 

1466 """Class representing an :class:`ast.comprehension` node. 

1467 

1468 A :class:`Comprehension` indicates the loop inside any type of 

1469 comprehension including generator expressions. 

1470 

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 """ 

1478 

1479 _astroid_fields = ("target", "iter", "ifs") 

1480 _other_fields = ("is_async",) 

1481 

1482 optional_assign = True 

1483 """Whether this node optionally assigns a variable.""" 

1484 

1485 target: NodeNG 

1486 """What is assigned to by the comprehension.""" 

1487 

1488 iter: NodeNG 

1489 """What is iterated over by the comprehension.""" 

1490 

1491 ifs: list[NodeNG] 

1492 """The contents of any if statements that filter the comprehension.""" 

1493 

1494 is_async: bool 

1495 """Whether this is an asynchronous comprehension or not.""" 

1496 

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 

1508 

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 """ 

1513 

1514 def assign_type(self): 

1515 """The type of assignment that this node performs. 

1516 

1517 :returns: The assignment type. 

1518 :rtype: NodeNG 

1519 """ 

1520 return self 

1521 

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 

1529 

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) 

1533 

1534 return [node], True 

1535 

1536 return stmts, False 

1537 

1538 def get_children(self): 

1539 yield self.target 

1540 yield self.iter 

1541 

1542 yield from self.ifs 

1543 

1544 

1545class Const(_base_nodes.NoChildrenNode, Instance): 

1546 """Class representing any constant including num, str, bool, None, bytes. 

1547 

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 """ 

1559 

1560 _other_fields = ("value", "kind") 

1561 

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. 

1575 

1576 :param lineno: The line that this node appears on in the source code. 

1577 

1578 :param col_offset: The column that this node appears on in the 

1579 source code. 

1580 

1581 :param parent: The parent node in the syntax tree. 

1582 

1583 :param kind: The string prefix. "u" for u-prefixed strings and ``None`` otherwise. Python 3.8+ only. 

1584 

1585 :param end_lineno: The last line this node appears on in the source code. 

1586 

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.""" 

1592 

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.""" 

1595 

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 ) 

1603 

1604 Instance.__init__(self, None) 

1605 

1606 infer_unary_op: ClassVar[InferUnaryOp[Const]] 

1607 infer_binary_op: ClassVar[InferBinaryOp[Const]] 

1608 

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) 

1619 

1620 def getitem(self, index, context: InferenceContext | None = None): 

1621 """Get an item from this node if subscriptable. 

1622 

1623 :param index: The node to use as a subscript index. 

1624 :type index: Const or Slice 

1625 

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) 

1633 

1634 else: 

1635 raise AstroidTypeError( 

1636 f"Could not use type {type(index)} as subscript index" 

1637 ) 

1638 

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 

1657 

1658 raise AstroidTypeError(f"{self!r} (value={self.value})") 

1659 

1660 def has_dynamic_getattr(self) -> bool: 

1661 """Check if the node has a custom __getattr__ or __getattribute__. 

1662 

1663 :returns: Whether the class has a custom __getattr__ or __getattribute__. 

1664 For a :class:`Const` this is always ``False``. 

1665 """ 

1666 return False 

1667 

1668 def itered(self): 

1669 """An iterator over the elements this node contains. 

1670 

1671 :returns: The contents of this node. 

1672 :rtype: iterable(Const) 

1673 

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}") 

1679 

1680 def pytype(self) -> str: 

1681 """Get the name of the type that this node represents. 

1682 

1683 :returns: The name of the type. 

1684 """ 

1685 return self._proxied.qname() 

1686 

1687 def bool_value(self, context: InferenceContext | None = None): 

1688 """Determine the boolean value of this node. 

1689 

1690 :returns: The boolean value of this node. 

1691 :rtype: bool 

1692 """ 

1693 return bool(self.value) 

1694 

1695 

1696class Continue(_base_nodes.NoChildrenNode, _base_nodes.Statement): 

1697 """Class representing an :class:`ast.Continue` node. 

1698 

1699 >>> import astroid 

1700 >>> node = astroid.extract_node('continue') 

1701 >>> node 

1702 <Continue l.1 at 0x7f23b2e35588> 

1703 """ 

1704 

1705 

1706class Decorators(NodeNG): 

1707 """A node representing a list of decorators. 

1708 

1709 A :class:`Decorators` is the decorators that are applied to 

1710 a method or function. 

1711 

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 """ 

1723 

1724 _astroid_fields = ("nodes",) 

1725 

1726 nodes: list[NodeNG] 

1727 """The decorators that this node contains.""" 

1728 

1729 def postinit(self, nodes: list[NodeNG]) -> None: 

1730 self.nodes = nodes 

1731 

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. 

1735 

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() 

1744 

1745 def get_children(self): 

1746 yield from self.nodes 

1747 

1748 

1749class DelAttr(_base_nodes.ParentAssignNode): 

1750 """Variation of :class:`ast.Delete` representing deletion of an attribute. 

1751 

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 """ 

1759 

1760 _astroid_fields = ("expr",) 

1761 _other_fields = ("attrname",) 

1762 

1763 expr: NodeNG 

1764 """The name that this node represents.""" 

1765 

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.""" 

1778 

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 ) 

1786 

1787 def postinit(self, expr: NodeNG) -> None: 

1788 self.expr = expr 

1789 

1790 def get_children(self): 

1791 yield self.expr 

1792 

1793 

1794class Delete(_base_nodes.AssignTypeNode, _base_nodes.Statement): 

1795 """Class representing an :class:`ast.Delete` node. 

1796 

1797 A :class:`Delete` is a ``del`` statement this is deleting something. 

1798 

1799 >>> import astroid 

1800 >>> node = astroid.extract_node('del self.attr') 

1801 >>> node 

1802 <Delete l.1 at 0x7f23b2e35f60> 

1803 """ 

1804 

1805 _astroid_fields = ("targets",) 

1806 

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.""" 

1818 

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 ) 

1826 

1827 def postinit(self, targets: list[NodeNG]) -> None: 

1828 self.targets = targets 

1829 

1830 def get_children(self): 

1831 yield from self.targets 

1832 

1833 

1834class Dict(NodeNG, Instance): 

1835 """Class representing an :class:`ast.Dict` node. 

1836 

1837 A :class:`Dict` is a dictionary that is created with ``{}`` syntax. 

1838 

1839 >>> import astroid 

1840 >>> node = astroid.extract_node('{1: "1"}') 

1841 >>> node 

1842 <Dict.dict l.1 at 0x7f23b2e35cc0> 

1843 """ 

1844 

1845 _astroid_fields = ("items",) 

1846 

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.""" 

1858 

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 ) 

1866 

1867 def postinit( 

1868 self, items: list[tuple[SuccessfulInferenceResult, SuccessfulInferenceResult]] 

1869 ) -> None: 

1870 """Do some setup after initialisation. 

1871 

1872 :param items: The key-value pairs contained in the dictionary. 

1873 """ 

1874 self.items = items 

1875 

1876 infer_unary_op: ClassVar[InferUnaryOp[Dict]] 

1877 

1878 def pytype(self) -> Literal["builtins.dict"]: 

1879 """Get the name of the type that this node represents. 

1880 

1881 :returns: The name of the type. 

1882 """ 

1883 return "builtins.dict" 

1884 

1885 def get_children(self): 

1886 """Get the key and value nodes below this node. 

1887 

1888 Children are returned in the order that they are defined in the source 

1889 code, key first then the value. 

1890 

1891 :returns: The children. 

1892 :rtype: iterable(NodeNG) 

1893 """ 

1894 for key, value in self.items: 

1895 yield key 

1896 yield value 

1897 

1898 def last_child(self): 

1899 """An optimized version of list(get_children())[-1] 

1900 

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 

1907 

1908 def itered(self): 

1909 """An iterator over the keys this node contains. 

1910 

1911 :returns: The keys of this node. 

1912 :rtype: iterable(NodeNG) 

1913 """ 

1914 return [key for (key, _) in self.items] 

1915 

1916 def getitem( 

1917 self, index: Const | Slice, context: InferenceContext | None = None 

1918 ) -> NodeNG: 

1919 """Get an item from this node. 

1920 

1921 :param index: The node to use as a subscript index. 

1922 

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 

1930 

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 

1937 

1938 try: 

1939 return inferred_value.getitem(index, context) 

1940 except (AstroidTypeError, AstroidIndexError): 

1941 continue 

1942 

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 

1949 

1950 raise AstroidIndexError(index) 

1951 

1952 def bool_value(self, context: InferenceContext | None = None): 

1953 """Determine the boolean value of this node. 

1954 

1955 :returns: The boolean value of this node. 

1956 :rtype: bool 

1957 """ 

1958 return bool(self.items) 

1959 

1960 

1961class Expr(_base_nodes.Statement): 

1962 """Class representing an :class:`ast.Expr` node. 

1963 

1964 An :class:`Expr` is any expression that does not have its value used or 

1965 stored. 

1966 

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 """ 

1974 

1975 _astroid_fields = ("value",) 

1976 

1977 value: NodeNG 

1978 """What the expression does.""" 

1979 

1980 def postinit(self, value: NodeNG) -> None: 

1981 self.value = value 

1982 

1983 def get_children(self): 

1984 yield self.value 

1985 

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() 

1989 

1990 

1991class EmptyNode(_base_nodes.NoChildrenNode): 

1992 """Holds an arbitrary object in the :attr:`LocalsDictNodeNG.locals`.""" 

1993 

1994 object = None 

1995 

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 ) 

2012 

2013 def has_underlying_object(self) -> bool: 

2014 return self.object is not None and self.object is not _EMPTY_OBJECT_MARKER 

2015 

2016 

2017class ExceptHandler( 

2018 _base_nodes.MultiLineBlockNode, _base_nodes.AssignTypeNode, _base_nodes.Statement 

2019): 

2020 """Class representing an :class:`ast.ExceptHandler`. node. 

2021 

2022 An :class:`ExceptHandler` is an ``except`` block on a try-except. 

2023 

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 """ 

2036 

2037 _astroid_fields = ("type", "name", "body") 

2038 _multi_line_block_fields = ("body",) 

2039 

2040 type: NodeNG | None 

2041 """The types that the block handles.""" 

2042 

2043 name: AssignName | None 

2044 """The name that the caught exception is assigned to.""" 

2045 

2046 body: list[NodeNG] 

2047 """The contents of the block.""" 

2048 

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 """ 

2053 

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 

2063 

2064 def get_children(self): 

2065 if self.type is not None: 

2066 yield self.type 

2067 

2068 if self.name is not None: 

2069 yield self.name 

2070 

2071 yield from self.body 

2072 

2073 @cached_property 

2074 def blockstart_tolineno(self): 

2075 """The line on which the beginning of this block ends. 

2076 

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 

2084 

2085 def catch(self, exceptions: list[str] | None) -> bool: 

2086 """Check if this node handles any of the given 

2087 

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()) 

2093 

2094 

2095class For( 

2096 _base_nodes.MultiLineWithElseBlockNode, 

2097 _base_nodes.AssignTypeNode, 

2098 _base_nodes.Statement, 

2099): 

2100 """Class representing an :class:`ast.For` node. 

2101 

2102 >>> import astroid 

2103 >>> node = astroid.extract_node('for thing in things: print(thing)') 

2104 >>> node 

2105 <For l.1 at 0x7f23b2e8cf28> 

2106 """ 

2107 

2108 _astroid_fields = ("target", "iter", "body", "orelse") 

2109 _other_other_fields = ("type_annotation",) 

2110 _multi_line_block_fields = ("body", "orelse") 

2111 

2112 optional_assign = True 

2113 """Whether this node optionally assigns a variable. 

2114 

2115 This is always ``True`` for :class:`For` nodes. 

2116 """ 

2117 

2118 target: NodeNG 

2119 """What the loop assigns to.""" 

2120 

2121 iter: NodeNG 

2122 """What the loop iterates over.""" 

2123 

2124 body: list[NodeNG] 

2125 """The contents of the body of the loop.""" 

2126 

2127 orelse: list[NodeNG] 

2128 """The contents of the ``else`` block of the loop.""" 

2129 

2130 type_annotation: NodeNG | None 

2131 """If present, this will contain the type annotation passed by a type comment""" 

2132 

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 

2146 

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 """ 

2151 

2152 @cached_property 

2153 def blockstart_tolineno(self): 

2154 """The line on which the beginning of this block ends. 

2155 

2156 :type: int 

2157 """ 

2158 return self.iter.tolineno 

2159 

2160 def get_children(self): 

2161 yield self.target 

2162 yield self.iter 

2163 

2164 yield from self.body 

2165 yield from self.orelse 

2166 

2167 

2168class AsyncFor(For): 

2169 """Class representing an :class:`ast.AsyncFor` node. 

2170 

2171 An :class:`AsyncFor` is an asynchronous :class:`For` built with 

2172 the ``async`` keyword. 

2173 

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 """ 

2185 

2186 

2187class Await(NodeNG): 

2188 """Class representing an :class:`ast.Await` node. 

2189 

2190 An :class:`Await` is the ``await`` keyword. 

2191 

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 """ 

2204 

2205 _astroid_fields = ("value",) 

2206 

2207 value: NodeNG 

2208 """What to wait for.""" 

2209 

2210 def postinit(self, value: NodeNG) -> None: 

2211 self.value = value 

2212 

2213 def get_children(self): 

2214 yield self.value 

2215 

2216 

2217class ImportFrom(_base_nodes.ImportNode): 

2218 """Class representing an :class:`ast.ImportFrom` node. 

2219 

2220 >>> import astroid 

2221 >>> node = astroid.extract_node('from my_package import my_module') 

2222 >>> node 

2223 <ImportFrom l.1 at 0x7f23b2e415c0> 

2224 """ 

2225 

2226 _other_fields = ("modname", "names", "level") 

2227 

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. 

2242 

2243 :param names: What is being imported from the module. 

2244 

2245 :param level: The level of relative import. 

2246 

2247 :param lineno: The line that this node appears on in the source code. 

2248 

2249 :param col_offset: The column that this node appears on in the 

2250 source code. 

2251 

2252 :param parent: The parent node in the syntax tree. 

2253 

2254 :param end_lineno: The last line this node appears on in the source code. 

2255 

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. 

2261 

2262 This is ``None`` for relative imports. 

2263 """ 

2264 

2265 self.names: list[tuple[str, str | None]] = names 

2266 """What is being imported from the module. 

2267 

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 """ 

2271 

2272 # TODO When is 'level' None? 

2273 self.level: int | None = level # can be None 

2274 """The level of relative import. 

2275 

2276 Essentially this is the number of dots in the import. 

2277 This is always 0 for absolute imports. 

2278 """ 

2279 

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 ) 

2287 

2288 

2289class Attribute(NodeNG): 

2290 """Class representing an :class:`ast.Attribute` node.""" 

2291 

2292 _astroid_fields = ("expr",) 

2293 _other_fields = ("attrname",) 

2294 

2295 expr: NodeNG 

2296 """The name that this node represents.""" 

2297 

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.""" 

2310 

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 ) 

2318 

2319 def postinit(self, expr: NodeNG) -> None: 

2320 self.expr = expr 

2321 

2322 def get_children(self): 

2323 yield self.expr 

2324 

2325 

2326class Global(_base_nodes.NoChildrenNode, _base_nodes.Statement): 

2327 """Class representing an :class:`ast.Global` node. 

2328 

2329 >>> import astroid 

2330 >>> node = astroid.extract_node('global a_global') 

2331 >>> node 

2332 <Global l.1 at 0x7f23b2e9de10> 

2333 """ 

2334 

2335 _other_fields = ("names",) 

2336 

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. 

2349 

2350 :param lineno: The line that this node appears on in the source code. 

2351 

2352 :param col_offset: The column that this node appears on in the 

2353 source code. 

2354 

2355 :param parent: The parent node in the syntax tree. 

2356 

2357 :param end_lineno: The last line this node appears on in the source code. 

2358 

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.""" 

2364 

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 ) 

2372 

2373 def _infer_name(self, frame, name): 

2374 return name 

2375 

2376 

2377class If(_base_nodes.MultiLineWithElseBlockNode, _base_nodes.Statement): 

2378 """Class representing an :class:`ast.If` node. 

2379 

2380 >>> import astroid 

2381 >>> node = astroid.extract_node('if condition: print(True)') 

2382 >>> node 

2383 <If l.1 at 0x7f23b2e9dd30> 

2384 """ 

2385 

2386 _astroid_fields = ("test", "body", "orelse") 

2387 _multi_line_block_fields = ("body", "orelse") 

2388 

2389 test: NodeNG 

2390 """The condition that the statement tests.""" 

2391 

2392 body: list[NodeNG] 

2393 """The contents of the block.""" 

2394 

2395 orelse: list[NodeNG] 

2396 """The contents of the ``else`` block.""" 

2397 

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 

2402 

2403 @cached_property 

2404 def blockstart_tolineno(self): 

2405 """The line on which the beginning of this block ends. 

2406 

2407 :type: int 

2408 """ 

2409 return self.test.tolineno 

2410 

2411 def block_range(self, lineno: int) -> tuple[int, int]: 

2412 """Get a range from the given line number to where this node ends. 

2413 

2414 :param lineno: The line number to start the range at. 

2415 

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) 

2424 

2425 def get_children(self): 

2426 yield self.test 

2427 

2428 yield from self.body 

2429 yield from self.orelse 

2430 

2431 def has_elif_block(self): 

2432 return len(self.orelse) == 1 and isinstance(self.orelse[0], If) 

2433 

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() 

2438 

2439 

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 """ 

2447 

2448 _astroid_fields = ("test", "body", "orelse") 

2449 

2450 test: NodeNG 

2451 """The condition that the statement tests.""" 

2452 

2453 body: NodeNG 

2454 """The contents of the block.""" 

2455 

2456 orelse: NodeNG 

2457 """The contents of the ``else`` block.""" 

2458 

2459 def postinit(self, test: NodeNG, body: NodeNG, orelse: NodeNG) -> None: 

2460 self.test = test 

2461 self.body = body 

2462 self.orelse = orelse 

2463 

2464 def get_children(self): 

2465 yield self.test 

2466 yield self.body 

2467 yield self.orelse 

2468 

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 

2473 

2474 

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 """ 

2482 

2483 _other_fields = ("names",) 

2484 

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. 

2498 

2499 :param lineno: The line that this node appears on in the source code. 

2500 

2501 :param col_offset: The column that this node appears on in the 

2502 source code. 

2503 

2504 :param parent: The parent node in the syntax tree. 

2505 

2506 :param end_lineno: The last line this node appears on in the source code. 

2507 

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. 

2513 

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 """ 

2517 

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 ) 

2525 

2526 

2527class Keyword(NodeNG): 

2528 """Class representing an :class:`ast.keyword` node. 

2529 

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 """ 

2537 

2538 _astroid_fields = ("value",) 

2539 _other_fields = ("arg",) 

2540 

2541 value: NodeNG 

2542 """The value being assigned to the keyword argument.""" 

2543 

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.""" 

2556 

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 ) 

2564 

2565 def postinit(self, value: NodeNG) -> None: 

2566 self.value = value 

2567 

2568 def get_children(self): 

2569 yield self.value 

2570 

2571 

2572class List(BaseContainer): 

2573 """Class representing an :class:`ast.List` node. 

2574 

2575 >>> import astroid 

2576 >>> node = astroid.extract_node('[1, 2, 3]') 

2577 >>> node 

2578 <List.list l.1 at 0x7f23b2e9e128> 

2579 """ 

2580 

2581 _other_fields = ("ctx",) 

2582 

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. 

2595 

2596 :param lineno: The line that this node appears on in the source code. 

2597 

2598 :param col_offset: The column that this node appears on in the 

2599 source code. 

2600 

2601 :param parent: The parent node in the syntax tree. 

2602 

2603 :param end_lineno: The last line this node appears on in the source code. 

2604 

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.""" 

2610 

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 ) 

2618 

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 """ 

2623 

2624 infer_unary_op: ClassVar[InferUnaryOp[List]] 

2625 infer_binary_op: ClassVar[InferBinaryOp[List]] 

2626 

2627 def pytype(self) -> Literal["builtins.list"]: 

2628 """Get the name of the type that this node represents. 

2629 

2630 :returns: The name of the type. 

2631 """ 

2632 return "builtins.list" 

2633 

2634 def getitem(self, index, context: InferenceContext | None = None): 

2635 """Get an item from this node. 

2636 

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) 

2641 

2642 

2643class Nonlocal(_base_nodes.NoChildrenNode, _base_nodes.Statement): 

2644 """Class representing an :class:`ast.Nonlocal` node. 

2645 

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 """ 

2656 

2657 _other_fields = ("names",) 

2658 

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. 

2671 

2672 :param lineno: The line that this node appears on in the source code. 

2673 

2674 :param col_offset: The column that this node appears on in the 

2675 source code. 

2676 

2677 :param parent: The parent node in the syntax tree. 

2678 

2679 :param end_lineno: The last line this node appears on in the source code. 

2680 

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.""" 

2686 

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 ) 

2694 

2695 def _infer_name(self, frame, name): 

2696 return name 

2697 

2698 

2699class Pass(_base_nodes.NoChildrenNode, _base_nodes.Statement): 

2700 """Class representing an :class:`ast.Pass` node. 

2701 

2702 >>> import astroid 

2703 >>> node = astroid.extract_node('pass') 

2704 >>> node 

2705 <Pass l.1 at 0x7f23b2e9e748> 

2706 """ 

2707 

2708 

2709class Raise(_base_nodes.Statement): 

2710 """Class representing an :class:`ast.Raise` node. 

2711 

2712 >>> import astroid 

2713 >>> node = astroid.extract_node('raise RuntimeError("Something bad happened!")') 

2714 >>> node 

2715 <Raise l.1 at 0x7f23b2e9e828> 

2716 """ 

2717 

2718 _astroid_fields = ("exc", "cause") 

2719 

2720 exc: NodeNG | None 

2721 """What is being raised.""" 

2722 

2723 cause: NodeNG | None 

2724 """The exception being used to raise this one.""" 

2725 

2726 def postinit( 

2727 self, 

2728 exc: NodeNG | None, 

2729 cause: NodeNG | None, 

2730 ) -> None: 

2731 self.exc = exc 

2732 self.cause = cause 

2733 

2734 def raises_not_implemented(self) -> bool: 

2735 """Check if this node raises a :class:`NotImplementedError`. 

2736 

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 ) 

2744 

2745 def get_children(self): 

2746 if self.exc is not None: 

2747 yield self.exc 

2748 

2749 if self.cause is not None: 

2750 yield self.cause 

2751 

2752 

2753class Return(_base_nodes.Statement): 

2754 """Class representing an :class:`ast.Return` node. 

2755 

2756 >>> import astroid 

2757 >>> node = astroid.extract_node('return True') 

2758 >>> node 

2759 <Return l.1 at 0x7f23b8211908> 

2760 """ 

2761 

2762 _astroid_fields = ("value",) 

2763 

2764 value: NodeNG | None 

2765 """The value being returned.""" 

2766 

2767 def postinit(self, value: NodeNG | None) -> None: 

2768 self.value = value 

2769 

2770 def get_children(self): 

2771 if self.value is not None: 

2772 yield self.value 

2773 

2774 def is_tuple_return(self): 

2775 return isinstance(self.value, Tuple) 

2776 

2777 def _get_return_nodes_skip_functions(self): 

2778 yield self 

2779 

2780 

2781class Set(BaseContainer): 

2782 """Class representing an :class:`ast.Set` node. 

2783 

2784 >>> import astroid 

2785 >>> node = astroid.extract_node('{1, 2, 3}') 

2786 >>> node 

2787 <Set.set l.1 at 0x7f23b2e71d68> 

2788 """ 

2789 

2790 infer_unary_op: ClassVar[InferUnaryOp[Set]] 

2791 

2792 def pytype(self) -> Literal["builtins.set"]: 

2793 """Get the name of the type that this node represents. 

2794 

2795 :returns: The name of the type. 

2796 """ 

2797 return "builtins.set" 

2798 

2799 

2800class Slice(NodeNG): 

2801 """Class representing an :class:`ast.Slice` node. 

2802 

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 """ 

2810 

2811 _astroid_fields = ("lower", "upper", "step") 

2812 

2813 lower: NodeNG | None 

2814 """The lower index in the slice.""" 

2815 

2816 upper: NodeNG | None 

2817 """The upper index in the slice.""" 

2818 

2819 step: NodeNG | None 

2820 """The step to take between indexes.""" 

2821 

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 

2831 

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 

2839 

2840 @cached_property 

2841 def _proxied(self) -> nodes.ClassDef: 

2842 builtins = AstroidManager().builtins_module 

2843 return builtins.getattr("slice")[0] 

2844 

2845 def pytype(self) -> Literal["builtins.slice"]: 

2846 """Get the name of the type that this node represents. 

2847 

2848 :returns: The name of the type. 

2849 """ 

2850 return "builtins.slice" 

2851 

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. 

2856 

2857 :param attrname: The name of the attribute to infer. 

2858 

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) 

2869 

2870 def getattr(self, attrname, context: InferenceContext | None = None): 

2871 return self._proxied.getattr(attrname, context) 

2872 

2873 def get_children(self): 

2874 if self.lower is not None: 

2875 yield self.lower 

2876 

2877 if self.upper is not None: 

2878 yield self.upper 

2879 

2880 if self.step is not None: 

2881 yield self.step 

2882 

2883 

2884class Starred(_base_nodes.ParentAssignNode): 

2885 """Class representing an :class:`ast.Starred` node. 

2886 

2887 >>> import astroid 

2888 >>> node = astroid.extract_node('*args') 

2889 >>> node 

2890 <Starred l.1 at 0x7f23b2e41978> 

2891 """ 

2892 

2893 _astroid_fields = ("value",) 

2894 _other_fields = ("ctx",) 

2895 

2896 value: NodeNG 

2897 """What is being unpacked.""" 

2898 

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.""" 

2911 

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 ) 

2919 

2920 def postinit(self, value: NodeNG) -> None: 

2921 self.value = value 

2922 

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 """ 

2927 

2928 def get_children(self): 

2929 yield self.value 

2930 

2931 

2932class Subscript(NodeNG): 

2933 """Class representing an :class:`ast.Subscript` node. 

2934 

2935 >>> import astroid 

2936 >>> node = astroid.extract_node('things[1:3]') 

2937 >>> node 

2938 <Subscript l.1 at 0x7f23b2e71f60> 

2939 """ 

2940 

2941 _astroid_fields = ("value", "slice") 

2942 _other_fields = ("ctx",) 

2943 

2944 infer_lhs: ClassVar[InferLHS[Subscript]] 

2945 

2946 value: NodeNG 

2947 """What is being indexed.""" 

2948 

2949 slice: NodeNG 

2950 """The slice being used to lookup.""" 

2951 

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.""" 

2964 

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 ) 

2972 

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 

2977 

2978 def get_children(self): 

2979 yield self.value 

2980 yield self.slice 

2981 

2982 

2983class TryExcept(_base_nodes.MultiLineWithElseBlockNode, _base_nodes.Statement): 

2984 """Class representing an :class:`ast.TryExcept` node. 

2985 

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 """ 

2996 

2997 _astroid_fields = ("body", "handlers", "orelse") 

2998 _multi_line_block_fields = ("body", "handlers", "orelse") 

2999 

3000 body: list[NodeNG] 

3001 """The contents of the block to catch exceptions from.""" 

3002 

3003 handlers: list[ExceptHandler] 

3004 """The exception handlers.""" 

3005 

3006 orelse: list[NodeNG] 

3007 """The contents of the ``else`` block.""" 

3008 

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 

3018 

3019 def _infer_name(self, frame, name): 

3020 return name 

3021 

3022 def block_range(self, lineno: int) -> tuple[int, int]: 

3023 """Get a range from the given line number to where this node ends. 

3024 

3025 :param lineno: The line number to start the range at. 

3026 

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) 

3039 

3040 def get_children(self): 

3041 yield from self.body 

3042 

3043 yield from self.handlers or () 

3044 yield from self.orelse or () 

3045 

3046 

3047class TryFinally(_base_nodes.MultiLineWithElseBlockNode, _base_nodes.Statement): 

3048 """Class representing an :class:`ast.TryFinally` node. 

3049 

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 """ 

3062 

3063 _astroid_fields = ("body", "finalbody") 

3064 _multi_line_block_fields = ("body", "finalbody") 

3065 

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. 

3077 

3078 :param col_offset: The column that this node appears on in the 

3079 source code. 

3080 

3081 :param parent: The parent node in the syntax tree. 

3082 

3083 :param end_lineno: The last line this node appears on in the source code. 

3084 

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.""" 

3090 

3091 self.finalbody: list[NodeNG] = [] 

3092 """The contents of the ``finally`` block.""" 

3093 

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 ) 

3101 

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. 

3108 

3109 :param body: The try-except that the finally is attached to. 

3110 

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 

3117 

3118 def block_range(self, lineno: int) -> tuple[int, int]: 

3119 """Get a range from the given line number to where this node ends. 

3120 

3121 :param lineno: The line number to start the range at. 

3122 

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) 

3135 

3136 def get_children(self): 

3137 yield from self.body 

3138 yield from self.finalbody 

3139 

3140 

3141class TryStar(_base_nodes.MultiLineWithElseBlockNode, _base_nodes.Statement): 

3142 """Class representing an :class:`ast.TryStar` node.""" 

3143 

3144 _astroid_fields = ("body", "handlers", "orelse", "finalbody") 

3145 _multi_line_block_fields = ("body", "handlers", "orelse", "finalbody") 

3146 

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.""" 

3167 

3168 self.handlers: list[ExceptHandler] = [] 

3169 """The exception handlers.""" 

3170 

3171 self.orelse: list[NodeNG] = [] 

3172 """The contents of the ``else`` block.""" 

3173 

3174 self.finalbody: list[NodeNG] = [] 

3175 """The contents of the ``finally`` block.""" 

3176 

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 ) 

3184 

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 

3207 

3208 def _infer_name(self, frame, name): 

3209 return name 

3210 

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 

3234 

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 

3240 

3241 

3242class Tuple(BaseContainer): 

3243 """Class representing an :class:`ast.Tuple` node. 

3244 

3245 >>> import astroid 

3246 >>> node = astroid.extract_node('(1, 2, 3)') 

3247 >>> node 

3248 <Tuple.tuple l.1 at 0x7f23b2e41780> 

3249 """ 

3250 

3251 _other_fields = ("ctx",) 

3252 

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. 

3265 

3266 :param lineno: The line that this node appears on in the source code. 

3267 

3268 :param col_offset: The column that this node appears on in the 

3269 source code. 

3270 

3271 :param parent: The parent node in the syntax tree. 

3272 

3273 :param end_lineno: The last line this node appears on in the source code. 

3274 

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.""" 

3280 

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 ) 

3288 

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 """ 

3293 

3294 infer_unary_op: ClassVar[InferUnaryOp[Tuple]] 

3295 infer_binary_op: ClassVar[InferBinaryOp[Tuple]] 

3296 

3297 def pytype(self) -> Literal["builtins.tuple"]: 

3298 """Get the name of the type that this node represents. 

3299 

3300 :returns: The name of the type. 

3301 """ 

3302 return "builtins.tuple" 

3303 

3304 def getitem(self, index, context: InferenceContext | None = None): 

3305 """Get an item from this node. 

3306 

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) 

3311 

3312 

3313class UnaryOp(NodeNG): 

3314 """Class representing an :class:`ast.UnaryOp` node. 

3315 

3316 >>> import astroid 

3317 >>> node = astroid.extract_node('-5') 

3318 >>> node 

3319 <UnaryOp l.1 at 0x7f23b2e4e198> 

3320 """ 

3321 

3322 _astroid_fields = ("operand",) 

3323 _other_fields = ("op",) 

3324 

3325 operand: NodeNG 

3326 """What the unary operator is applied to.""" 

3327 

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.""" 

3340 

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 ) 

3348 

3349 def postinit(self, operand: NodeNG) -> None: 

3350 self.operand = operand 

3351 

3352 # This is set by inference.py 

3353 _infer_unaryop: ClassVar[ 

3354 InferBinaryOperation[UnaryOp, util.BadUnaryOperationMessage] 

3355 ] 

3356 

3357 def type_errors(self, context: InferenceContext | None = None): 

3358 """Get a list of type errors which can occur during inference. 

3359 

3360 Each TypeError is represented by a :class:`BadBinaryOperationMessage`, 

3361 which holds the original exception. 

3362 

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 [] 

3375 

3376 def get_children(self): 

3377 yield self.operand 

3378 

3379 def op_precedence(self): 

3380 if self.op == "not": 

3381 return OP_PRECEDENCE[self.op] 

3382 

3383 return super().op_precedence() 

3384 

3385 

3386class While(_base_nodes.MultiLineWithElseBlockNode, _base_nodes.Statement): 

3387 """Class representing an :class:`ast.While` node. 

3388 

3389 >>> import astroid 

3390 >>> node = astroid.extract_node(''' 

3391 while condition(): 

3392 print("True") 

3393 ''') 

3394 >>> node 

3395 <While l.2 at 0x7f23b2e4e390> 

3396 """ 

3397 

3398 _astroid_fields = ("test", "body", "orelse") 

3399 _multi_line_block_fields = ("body", "orelse") 

3400 

3401 test: NodeNG 

3402 """The condition that the loop tests.""" 

3403 

3404 body: list[NodeNG] 

3405 """The contents of the loop.""" 

3406 

3407 orelse: list[NodeNG] 

3408 """The contents of the ``else`` block.""" 

3409 

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 

3419 

3420 @cached_property 

3421 def blockstart_tolineno(self): 

3422 """The line on which the beginning of this block ends. 

3423 

3424 :type: int 

3425 """ 

3426 return self.test.tolineno 

3427 

3428 def block_range(self, lineno: int) -> tuple[int, int]: 

3429 """Get a range from the given line number to where this node ends. 

3430 

3431 :param lineno: The line number to start the range at. 

3432 

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) 

3437 

3438 def get_children(self): 

3439 yield self.test 

3440 

3441 yield from self.body 

3442 yield from self.orelse 

3443 

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() 

3448 

3449 

3450class With( 

3451 _base_nodes.MultiLineWithElseBlockNode, 

3452 _base_nodes.AssignTypeNode, 

3453 _base_nodes.Statement, 

3454): 

3455 """Class representing an :class:`ast.With` node. 

3456 

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 """ 

3465 

3466 _astroid_fields = ("items", "body") 

3467 _other_other_fields = ("type_annotation",) 

3468 _multi_line_block_fields = ("body",) 

3469 

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. 

3481 

3482 :param col_offset: The column that this node appears on in the 

3483 source code. 

3484 

3485 :param parent: The parent node in the syntax tree. 

3486 

3487 :param end_lineno: The last line this node appears on in the source code. 

3488 

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.""" 

3494 

3495 self.body: list[NodeNG] = [] 

3496 """The contents of the ``with`` block.""" 

3497 

3498 self.type_annotation: NodeNG | None = None # can be None 

3499 """If present, this will contain the type annotation passed by a type comment""" 

3500 

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 ) 

3508 

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. 

3516 

3517 :param items: The pairs of context managers and the names 

3518 they are assigned to. 

3519 

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 

3527 

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 """ 

3532 

3533 @cached_property 

3534 def blockstart_tolineno(self): 

3535 """The line on which the beginning of this block ends. 

3536 

3537 :type: int 

3538 """ 

3539 return self.items[-1][0].tolineno 

3540 

3541 def get_children(self): 

3542 """Get the child nodes below this node. 

3543 

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 

3552 

3553 

3554class AsyncWith(With): 

3555 """Asynchronous ``with`` built with the ``async`` keyword.""" 

3556 

3557 

3558class Yield(NodeNG): 

3559 """Class representing an :class:`ast.Yield` node. 

3560 

3561 >>> import astroid 

3562 >>> node = astroid.extract_node('yield True') 

3563 >>> node 

3564 <Yield l.1 at 0x7f23b2e4e5f8> 

3565 """ 

3566 

3567 _astroid_fields = ("value",) 

3568 

3569 value: NodeNG | None 

3570 """The value to yield.""" 

3571 

3572 def postinit(self, value: NodeNG | None) -> None: 

3573 self.value = value 

3574 

3575 def get_children(self): 

3576 if self.value is not None: 

3577 yield self.value 

3578 

3579 def _get_yield_nodes_skip_lambdas(self): 

3580 yield self 

3581 

3582 

3583class YieldFrom(Yield): # TODO value is required, not optional 

3584 """Class representing an :class:`ast.YieldFrom` node.""" 

3585 

3586 

3587class DictUnpack(_base_nodes.NoChildrenNode): 

3588 """Represents the unpacking of dicts into dicts using :pep:`448`.""" 

3589 

3590 

3591class FormattedValue(NodeNG): 

3592 """Class representing an :class:`ast.FormattedValue` node. 

3593 

3594 Represents a :pep:`498` format string. 

3595 

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 """ 

3603 

3604 _astroid_fields = ("value", "format_spec") 

3605 _other_fields = ("conversion",) 

3606 

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. 

3618 

3619 :param col_offset: The column that this node appears on in the 

3620 source code. 

3621 

3622 :param parent: The parent node in the syntax tree. 

3623 

3624 :param end_lineno: The last line this node appears on in the source code. 

3625 

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.""" 

3631 

3632 self.conversion: int 

3633 """The type of formatting to be applied to the value. 

3634 

3635 .. seealso:: 

3636 :class:`ast.FormattedValue` 

3637 """ 

3638 

3639 self.format_spec: JoinedStr | None = None 

3640 """The formatting to be applied to the value. 

3641 

3642 .. seealso:: 

3643 :class:`ast.FormattedValue` 

3644 """ 

3645 

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 ) 

3653 

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. 

3662 

3663 :param value: The value to be formatted into the string. 

3664 

3665 :param conversion: The type of formatting to be applied to the value. 

3666 

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 

3673 

3674 def get_children(self): 

3675 yield self.value 

3676 

3677 if self.format_spec is not None: 

3678 yield self.format_spec 

3679 

3680 

3681class JoinedStr(NodeNG): 

3682 """Represents a list of string expressions to be joined. 

3683 

3684 >>> import astroid 

3685 >>> node = astroid.extract_node('f"Format {type_}"') 

3686 >>> node 

3687 <JoinedStr l.1 at 0x7f23b2e4ed30> 

3688 """ 

3689 

3690 _astroid_fields = ("values",) 

3691 

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. 

3703 

3704 :param col_offset: The column that this node appears on in the 

3705 source code. 

3706 

3707 :param parent: The parent node in the syntax tree. 

3708 

3709 :param end_lineno: The last line this node appears on in the source code. 

3710 

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. 

3716 

3717 :type: list(FormattedValue or Const) 

3718 """ 

3719 

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 ) 

3727 

3728 def postinit(self, values: list[NodeNG] | None = None) -> None: 

3729 """Do some setup after initialisation. 

3730 

3731 :param value: The string expressions to be joined. 

3732 

3733 :type: list(FormattedValue or Const) 

3734 """ 

3735 if values is not None: 

3736 self.values = values 

3737 

3738 def get_children(self): 

3739 yield from self.values 

3740 

3741 

3742class NamedExpr(_base_nodes.AssignTypeNode): 

3743 """Represents the assignment from the assignment expression 

3744 

3745 >>> import astroid 

3746 >>> module = astroid.parse('if a := 1: pass') 

3747 >>> module.body[0].test 

3748 <NamedExpr l.1 at 0x7f23b2e4ed30> 

3749 """ 

3750 

3751 _astroid_fields = ("target", "value") 

3752 

3753 optional_assign = True 

3754 """Whether this node optionally assigns a variable. 

3755 

3756 Since NamedExpr are not always called they do not always assign.""" 

3757 

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. 

3769 

3770 :param col_offset: The column that this node appears on in the 

3771 source code. 

3772 

3773 :param parent: The parent node in the syntax tree. 

3774 

3775 :param end_lineno: The last line this node appears on in the source code. 

3776 

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 

3782 

3783 :type: Name 

3784 """ 

3785 

3786 self.value: NodeNG 

3787 """The value that gets assigned in the expression""" 

3788 

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 ) 

3796 

3797 def postinit(self, target: NodeNG, value: NodeNG) -> None: 

3798 self.target = target 

3799 self.value = value 

3800 

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 """ 

3805 

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. 

3810 

3811 A frame node is a :class:`Module`, :class:`FunctionDef`, 

3812 or :class:`ClassDef`. 

3813 

3814 :returns: The first parent frame node. 

3815 """ 

3816 if not self.parent: 

3817 raise ParentMissingError(target=self) 

3818 

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) 

3826 

3827 return self.parent.frame(future=True) 

3828 

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. 

3832 

3833 :returns: The first parent scope node. 

3834 """ 

3835 if not self.parent: 

3836 raise ParentMissingError(target=self) 

3837 

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() 

3845 

3846 return self.parent.scope() 

3847 

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. 

3852 

3853 .. seealso:: :meth:`scope` 

3854 

3855 :param name: The name that is being defined. 

3856 

3857 :param stmt: The statement that defines the given name. 

3858 """ 

3859 self.frame(future=True).set_local(name, stmt) 

3860 

3861 

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 """ 

3868 

3869 name = "Unknown" 

3870 

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 ) 

3887 

3888 def qname(self) -> Literal["Unknown"]: 

3889 return "Unknown" 

3890 

3891 def _infer(self, context: InferenceContext | None = None, **kwargs): 

3892 """Inference on an Unknown node immediately terminates.""" 

3893 yield util.Uninferable 

3894 

3895 

3896class EvaluatedObject(NodeNG): 

3897 """Contains an object that has already been inferred 

3898 

3899 This class is useful to pre-evaluate a particular node, 

3900 with the resulting class acting as the non-evaluated node. 

3901 """ 

3902 

3903 name = "EvaluatedObject" 

3904 _astroid_fields = ("original",) 

3905 _other_fields = ("value",) 

3906 

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""" 

3910 

3911 self.value: NodeNG | util.UninferableBase = value 

3912 """The inferred value""" 

3913 

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 ) 

3921 

3922 def _infer( 

3923 self, context: InferenceContext | None = None, **kwargs: Any 

3924 ) -> Generator[NodeNG | util.UninferableBase, None, None]: 

3925 yield self.value 

3926 

3927 

3928# Pattern matching ####################################################### 

3929 

3930 

3931class Match(_base_nodes.Statement, _base_nodes.MultiLineBlockNode): 

3932 """Class representing a :class:`ast.Match` node. 

3933 

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 """ 

3945 

3946 _astroid_fields = ("subject", "cases") 

3947 _multi_line_block_fields = ("cases",) 

3948 

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 ) 

3967 

3968 def postinit( 

3969 self, 

3970 *, 

3971 subject: NodeNG, 

3972 cases: list[MatchCase], 

3973 ) -> None: 

3974 self.subject = subject 

3975 self.cases = cases 

3976 

3977 

3978class Pattern(NodeNG): 

3979 """Base class for all Pattern nodes.""" 

3980 

3981 

3982class MatchCase(_base_nodes.MultiLineBlockNode): 

3983 """Class representing a :class:`ast.match_case` node. 

3984 

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 """ 

3994 

3995 _astroid_fields = ("pattern", "guard", "body") 

3996 _multi_line_block_fields = ("body",) 

3997 

3998 lineno: None 

3999 col_offset: None 

4000 end_lineno: None 

4001 end_col_offset: None 

4002 

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 ) 

4014 

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 

4025 

4026 

4027class MatchValue(Pattern): 

4028 """Class representing a :class:`ast.MatchValue` node. 

4029 

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 """ 

4039 

4040 _astroid_fields = ("value",) 

4041 

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 ) 

4059 

4060 def postinit(self, *, value: NodeNG) -> None: 

4061 self.value = value 

4062 

4063 

4064class MatchSingleton(Pattern): 

4065 """Class representing a :class:`ast.MatchSingleton` node. 

4066 

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 """ 

4084 

4085 _other_fields = ("value",) 

4086 

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 ) 

4105 

4106 

4107class MatchSequence(Pattern): 

4108 """Class representing a :class:`ast.MatchSequence` node. 

4109 

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 """ 

4123 

4124 _astroid_fields = ("patterns",) 

4125 

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 ) 

4143 

4144 def postinit(self, *, patterns: list[Pattern]) -> None: 

4145 self.patterns = patterns 

4146 

4147 

4148class MatchMapping(_base_nodes.AssignTypeNode, Pattern): 

4149 """Class representing a :class:`ast.MatchMapping` node. 

4150 

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 """ 

4160 

4161 _astroid_fields = ("keys", "patterns", "rest") 

4162 

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 ) 

4182 

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 

4193 

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 """ 

4208 

4209 

4210class MatchClass(Pattern): 

4211 """Class representing a :class:`ast.MatchClass` node. 

4212 

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 """ 

4226 

4227 _astroid_fields = ("cls", "patterns", "kwd_patterns") 

4228 _other_fields = ("kwd_attrs",) 

4229 

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 ) 

4250 

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 

4263 

4264 

4265class MatchStar(_base_nodes.AssignTypeNode, Pattern): 

4266 """Class representing a :class:`ast.MatchStar` node. 

4267 

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 """ 

4277 

4278 _astroid_fields = ("name",) 

4279 

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 ) 

4297 

4298 def postinit(self, *, name: AssignName | None) -> None: 

4299 self.name = name 

4300 

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 """ 

4315 

4316 

4317class MatchAs(_base_nodes.AssignTypeNode, Pattern): 

4318 """Class representing a :class:`ast.MatchAs` node. 

4319 

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 """ 

4341 

4342 _astroid_fields = ("pattern", "name") 

4343 

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 ) 

4362 

4363 def postinit( 

4364 self, 

4365 *, 

4366 pattern: Pattern | None, 

4367 name: AssignName | None, 

4368 ) -> None: 

4369 self.pattern = pattern 

4370 self.name = name 

4371 

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 """ 

4386 

4387 

4388class MatchOr(Pattern): 

4389 """Class representing a :class:`ast.MatchOr` node. 

4390 

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 """ 

4400 

4401 _astroid_fields = ("patterns",) 

4402 

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 ) 

4420 

4421 def postinit(self, *, patterns: list[Pattern]) -> None: 

4422 self.patterns = patterns 

4423 

4424 

4425# constants ############################################################## 

4426 

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} 

4444 

4445 

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 

4456 

4457 

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 

4470 

4471 

4472def const_factory(value: Any) -> ConstFactoryResult: 

4473 """Return an astroid node for a python value.""" 

4474 assert not isinstance(value, NodeNG) 

4475 

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 

4483 

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)