Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/astroid/nodes/node_classes.py: 64%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

2128 statements  

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 ast 

11import itertools 

12import operator 

13import sys 

14import typing 

15import warnings 

16from collections.abc import Callable, Generator, Iterable, Iterator, Mapping 

17from functools import cached_property 

18from typing import TYPE_CHECKING, Any, ClassVar, Literal, Union 

19 

20from astroid import decorators, protocols, util 

21from astroid.bases import Instance, _infer_stmts 

22from astroid.const import _EMPTY_OBJECT_MARKER, PY314_PLUS, Context 

23from astroid.context import CallContext, InferenceContext, copy_context 

24from astroid.exceptions import ( 

25 AstroidBuildingError, 

26 AstroidError, 

27 AstroidIndexError, 

28 AstroidTypeError, 

29 AstroidValueError, 

30 AttributeInferenceError, 

31 InferenceError, 

32 NameInferenceError, 

33 NoDefault, 

34 ParentMissingError, 

35 _NonDeducibleTypeHierarchy, 

36) 

37from astroid.interpreter import dunder_lookup 

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.nodes.scoped_nodes import SYNTHETIC_ROOT 

43from astroid.typing import ( 

44 ConstFactoryResult, 

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 

55if TYPE_CHECKING: 

56 from astroid import nodes 

57 from astroid.nodes import LocalsDictNodeNG 

58 from astroid.nodes.node_ng import FrameType 

59 

60 

61def _is_const(value) -> bool: 

62 return isinstance(value, tuple(CONST_CLS)) 

63 

64 

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

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

67 

68# pylint: disable-next=consider-alternative-union-syntax 

69AssignedStmtsPossibleNode = Union["List", "Tuple", "AssignName", "AssignAttr", None] 

70AssignedStmtsCall = Callable[ 

71 [ 

72 _NodesT, 

73 AssignedStmtsPossibleNode, 

74 InferenceContext | None, 

75 list[int] | None, 

76 ], 

77 Any, 

78] 

79InferBinaryOperation = Callable[ 

80 [_NodesT, InferenceContext | None], 

81 Generator[InferenceResult | _BadOpMessageT], 

82] 

83InferLHS = Callable[ 

84 [_NodesT, InferenceContext | None], 

85 Generator[InferenceResult, None, InferenceErrorInfo | None], 

86] 

87InferUnaryOp = Callable[[_NodesT, str], ConstFactoryResult] 

88 

89 

90@decorators.raise_if_nothing_inferred 

91def unpack_infer(stmt, context: InferenceContext | None = None): 

92 """recursively generate nodes inferred by the given statement. 

93 If the inferred value is a list or a tuple, recurse on the elements 

94 """ 

95 if isinstance(stmt, (List, Tuple)): 

96 for elt in stmt.elts: 

97 if elt is util.Uninferable: 

98 yield elt 

99 continue 

100 yield from unpack_infer(elt, context) 

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

102 # if inferred is a final node, return it and stop 

103 inferred = next(stmt.infer(context), util.Uninferable) 

104 if inferred is stmt: 

105 yield inferred 

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

107 # else, infer recursively, except Uninferable object that should be returned as is 

108 for inferred in stmt.infer(context): 

109 if isinstance(inferred, util.UninferableBase): 

110 yield inferred 

111 else: 

112 yield from unpack_infer(inferred, context) 

113 

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

115 

116 

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

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

119 

120 `exceptions` may be a list of exception names. If specified, discard If 

121 branches and check one of the statement is in an exception handler catching 

122 one of the given exceptions. 

123 

124 algorithm : 

125 1) index stmt1's parents 

126 2) climb among stmt2's parents until we find a common parent 

127 3) if the common parent is a If or Try statement, look if nodes are 

128 in exclusive branches 

129 """ 

130 # index stmt1's parents 

131 stmt1_parents = {} 

132 children = {} 

133 previous = stmt1 

134 for node in stmt1.node_ancestors(): 

135 stmt1_parents[node] = 1 

136 children[node] = previous 

137 previous = node 

138 # climb among stmt2's parents until we find a common parent 

139 previous = stmt2 

140 for node in stmt2.node_ancestors(): 

141 if node in stmt1_parents: 

142 # if the common parent is a If or Try statement, look if 

143 # nodes are in exclusive branches 

144 if isinstance(node, If) and exceptions is None: 

145 c2attr, c2node = node.locate_child(previous) 

146 c1attr, c1node = node.locate_child(children[node]) 

147 if "test" in (c1attr, c2attr): 

148 # If any node is `If.test`, then it must be inclusive with 

149 # the other node (`If.body` and `If.orelse`) 

150 return False 

151 if c1attr != c2attr: 

152 # different `If` branches (`If.body` and `If.orelse`) 

153 return True 

154 elif isinstance(node, Try): 

155 c2attr, c2node = node.locate_child(previous) 

156 c1attr, c1node = node.locate_child(children[node]) 

157 if c1node is not c2node: 

158 first_in_body_caught_by_handlers = ( 

159 c2attr == "handlers" 

160 and c1attr == "body" 

161 and previous.catch(exceptions) 

162 ) 

163 second_in_body_caught_by_handlers = ( 

164 c2attr == "body" 

165 and c1attr == "handlers" 

166 and children[node].catch(exceptions) 

167 ) 

168 first_in_else_other_in_handlers = ( 

169 c2attr == "handlers" and c1attr == "orelse" 

170 ) 

171 second_in_else_other_in_handlers = ( 

172 c2attr == "orelse" and c1attr == "handlers" 

173 ) 

174 if any( 

175 ( 

176 first_in_body_caught_by_handlers, 

177 second_in_body_caught_by_handlers, 

178 first_in_else_other_in_handlers, 

179 second_in_else_other_in_handlers, 

180 ) 

181 ): 

182 return True 

183 elif c2attr == "handlers" and c1attr == "handlers": 

184 return previous is not children[node] 

185 return False 

186 previous = node 

187 return False 

188 

189 

190# getitem() helpers. 

191 

192_SLICE_SENTINEL = object() 

193 

194 

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

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

197 

198 if isinstance(index, Const): 

199 if isinstance(index.value, (int, type(None))): 

200 return index.value 

201 elif index is None: 

202 return None 

203 else: 

204 # Try to infer what the index actually is. 

205 # Since we can't return all the possible values, 

206 # we'll stop at the first possible value. 

207 try: 

208 inferred = next(index.infer(context=context)) 

209 except (InferenceError, StopIteration): 

210 pass 

211 else: 

212 if isinstance(inferred, Const): 

213 if isinstance(inferred.value, (int, type(None))): 

214 return inferred.value 

215 

216 # Use a sentinel, because None can be a valid 

217 # value that this function can return, 

218 # as it is the case for unspecified bounds. 

219 return _SLICE_SENTINEL 

220 

221 

222def _infer_slice(node, context: InferenceContext | None = None): 

223 lower = _slice_value(node.lower, context) 

224 upper = _slice_value(node.upper, context) 

225 step = _slice_value(node.step, context) 

226 if all(elem is not _SLICE_SENTINEL for elem in (lower, upper, step)): 

227 return slice(lower, upper, step) 

228 

229 raise AstroidTypeError( 

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

231 node=node, 

232 index=node.parent, 

233 context=context, 

234 ) 

235 

236 

237def _container_getitem(instance, elts, index, context: InferenceContext | None = None): 

238 """Get a slice or an item, using the given *index*, for the given sequence.""" 

239 try: 

240 if isinstance(index, Slice): 

241 index_slice = _infer_slice(index, context=context) 

242 new_cls = instance.__class__() 

243 new_cls.elts = elts[index_slice] 

244 new_cls.parent = instance.parent 

245 return new_cls 

246 if isinstance(index, Const): 

247 return elts[index.value] 

248 except ValueError as exc: 

249 raise AstroidValueError( 

250 message="Slice {index!r} cannot index container", 

251 node=instance, 

252 index=index, 

253 context=context, 

254 ) from exc 

255 except IndexError as exc: 

256 raise AstroidIndexError( 

257 message="Index {index!s} out of range", 

258 node=instance, 

259 index=index, 

260 context=context, 

261 ) from exc 

262 except TypeError as exc: 

263 raise AstroidTypeError( 

264 message="Type error {error!r}", node=instance, index=index, context=context 

265 ) from exc 

266 

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

268 

269 

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

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

272 

273 _astroid_fields = ("elts",) 

274 

275 def __init__( 

276 self, 

277 lineno: int | None, 

278 col_offset: int | None, 

279 parent: NodeNG | None, 

280 *, 

281 end_lineno: int | None, 

282 end_col_offset: int | None, 

283 ) -> None: 

284 self.elts: list[SuccessfulInferenceResult] = [] 

285 """The elements in the node.""" 

286 

287 super().__init__( 

288 lineno=lineno, 

289 col_offset=col_offset, 

290 end_lineno=end_lineno, 

291 end_col_offset=end_col_offset, 

292 parent=parent, 

293 ) 

294 

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

296 self.elts = elts 

297 

298 @classmethod 

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

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

301 

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

303 

304 :returns: A new node containing the given elements. 

305 """ 

306 node = cls( 

307 lineno=None, 

308 col_offset=None, 

309 parent=None, 

310 end_lineno=None, 

311 end_col_offset=None, 

312 ) 

313 node.elts = [const_factory(e) if _is_const(e) else e for e in elts] 

314 return node 

315 

316 def itered(self): 

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

318 

319 :returns: The contents of this node. 

320 :rtype: Iterator[NodeNG] 

321 """ 

322 return self.elts 

323 

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

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

326 

327 :returns: The boolean value of this node. 

328 """ 

329 return bool(self.elts) 

330 

331 @abc.abstractmethod 

332 def pytype(self) -> str: 

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

334 

335 :returns: The name of the type. 

336 """ 

337 

338 def get_children(self): 

339 yield from self.elts 

340 

341 @decorators.raise_if_nothing_inferred 

342 def _infer(self, context: InferenceContext | None = None) -> Iterator[Self]: 

343 has_starred_named_expr = any( 

344 isinstance(e, (Starred, NamedExpr)) for e in self.elts 

345 ) 

346 if has_starred_named_expr: 

347 values = self._infer_sequence_helper(context) 

348 new_seq = type(self)( 

349 lineno=self.lineno, 

350 col_offset=self.col_offset, 

351 parent=self.parent, 

352 end_lineno=self.end_lineno, 

353 end_col_offset=self.end_col_offset, 

354 ) 

355 new_seq.postinit(values) 

356 

357 yield new_seq 

358 else: 

359 yield self 

360 

361 def _infer_sequence_helper( 

362 self, context: InferenceContext | None = None 

363 ) -> list[SuccessfulInferenceResult]: 

364 """Infer all values based on BaseContainer.elts.""" 

365 values = [] 

366 

367 for elt in self.elts: 

368 if isinstance(elt, Starred): 

369 starred = util.safe_infer(elt.value, context) 

370 if not starred: 

371 raise InferenceError(node=self, context=context) 

372 if isinstance(starred, TypeVarTuple): 

373 # TypeVarTuple unpacking (*Ts) represents a variadic 

374 # type parameter, not an iterable to expand. 

375 values.append(elt) 

376 elif not hasattr(starred, "elts"): 

377 raise InferenceError(node=self, context=context) 

378 else: 

379 # TODO: fresh context? 

380 values.extend(starred._infer_sequence_helper(context)) 

381 elif isinstance(elt, NamedExpr): 

382 value = util.safe_infer(elt.value, context) 

383 if not value: 

384 raise InferenceError(node=self, context=context) 

385 values.append(value) 

386 else: 

387 values.append(elt) 

388 return values 

389 

390 

391# Name classes 

392 

393 

394class AssignName( 

395 _base_nodes.NoChildrenNode, 

396 _base_nodes.LookupMixIn, 

397 _base_nodes.ParentAssignNode, 

398): 

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

400 

401 An :class:`AssignName` is the name of something that is assigned to. 

402 This includes variables defined in a function signature or in a loop. 

403 

404 >>> import astroid 

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

406 >>> node 

407 <Assign l.1 at 0x...> 

408 >>> list(node.get_children()) 

409 [<AssignName.variable l.1 at 0x...>, <Call l.1 at 0x...>] 

410 >>> list(node.get_children())[0].as_string() 

411 'variable' 

412 """ 

413 

414 _other_fields = ("name",) 

415 

416 def __init__( 

417 self, 

418 name: str, 

419 lineno: int, 

420 col_offset: int, 

421 parent: NodeNG, 

422 *, 

423 end_lineno: int | None, 

424 end_col_offset: int | None, 

425 ) -> None: 

426 self.name = name 

427 """The name that is assigned to.""" 

428 

429 super().__init__( 

430 lineno=lineno, 

431 col_offset=col_offset, 

432 end_lineno=end_lineno, 

433 end_col_offset=end_col_offset, 

434 parent=parent, 

435 ) 

436 

437 assigned_stmts = protocols.assend_assigned_stmts 

438 """Returns the assigned statement (non inferred) according to the assignment type. 

439 See astroid/protocols.py for actual implementation. 

440 """ 

441 

442 @decorators.raise_if_nothing_inferred 

443 @decorators.path_wrapper 

444 def _infer( 

445 self, context: InferenceContext | None = None 

446 ) -> Generator[InferenceResult, None, InferenceErrorInfo | None]: 

447 """Infer an AssignName: need to inspect the RHS part of the 

448 assign node. 

449 """ 

450 if isinstance(self.parent, AugAssign): 

451 return self.parent.infer(context) 

452 

453 stmts = list(self.assigned_stmts(context=context)) 

454 return _infer_stmts(stmts, context) 

455 

456 @decorators.raise_if_nothing_inferred 

457 def infer_lhs( 

458 self, context: InferenceContext | None = None 

459 ) -> Generator[InferenceResult, None, InferenceErrorInfo | None]: 

460 """Infer a Name: use name lookup rules. 

461 

462 Same implementation as Name._infer.""" 

463 # pylint: disable=import-outside-toplevel 

464 from astroid.constraint import get_constraints 

465 from astroid.helpers import _higher_function_scope 

466 

467 frame, stmts = self.lookup(self.name) 

468 if not stmts: 

469 # Try to see if the name is enclosed in a nested function 

470 # and use the higher (first function) scope for searching. 

471 parent_function = _higher_function_scope(self.scope()) 

472 if parent_function: 

473 _, stmts = parent_function.lookup(self.name) 

474 

475 if not stmts: 

476 raise NameInferenceError( 

477 name=self.name, scope=self.scope(), context=context 

478 ) 

479 context = copy_context(context) 

480 context.lookupname = self.name 

481 context.constraints[self.name] = get_constraints(self, frame) 

482 

483 return _infer_stmts(stmts, context, frame) 

484 

485 

486class DelName( 

487 _base_nodes.NoChildrenNode, _base_nodes.LookupMixIn, _base_nodes.ParentAssignNode 

488): 

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

490 

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

492 

493 >>> import astroid 

494 >>> node = astroid.extract_node("del variable #@") 

495 >>> list(node.get_children()) 

496 [<DelName.variable l.1 at 0x...>] 

497 >>> list(node.get_children())[0].as_string() 

498 'variable' 

499 """ 

500 

501 _other_fields = ("name",) 

502 

503 def __init__( 

504 self, 

505 name: str, 

506 lineno: int, 

507 col_offset: int, 

508 parent: NodeNG, 

509 *, 

510 end_lineno: int | None, 

511 end_col_offset: int | None, 

512 ) -> None: 

513 self.name = name 

514 """The name that is being deleted.""" 

515 

516 super().__init__( 

517 lineno=lineno, 

518 col_offset=col_offset, 

519 end_lineno=end_lineno, 

520 end_col_offset=end_col_offset, 

521 parent=parent, 

522 ) 

523 

524 

525class Name(_base_nodes.LookupMixIn, _base_nodes.NoChildrenNode): 

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

527 

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

529 :class:`AssignName` or :class:`DelName`. 

530 

531 >>> import astroid 

532 >>> node = astroid.extract_node('range(10)') 

533 >>> node 

534 <Call l.1 at 0x...> 

535 >>> list(node.get_children()) 

536 [<Name.range l.1 at 0x...>, <Const.int l.1 at 0x...>] 

537 >>> list(node.get_children())[0].as_string() 

538 'range' 

539 """ 

540 

541 _other_fields = ("name",) 

542 

543 def __init__( 

544 self, 

545 name: str, 

546 lineno: int, 

547 col_offset: int, 

548 parent: NodeNG, 

549 *, 

550 end_lineno: int | None, 

551 end_col_offset: int | None, 

552 ) -> None: 

553 self.name = name 

554 """The name that this node refers to.""" 

555 

556 super().__init__( 

557 lineno=lineno, 

558 col_offset=col_offset, 

559 end_lineno=end_lineno, 

560 end_col_offset=end_col_offset, 

561 parent=parent, 

562 ) 

563 

564 def _get_name_nodes(self): 

565 yield self 

566 

567 for child_node in self.get_children(): 

568 yield from child_node._get_name_nodes() 

569 

570 @decorators.raise_if_nothing_inferred 

571 @decorators.path_wrapper 

572 def _infer( 

573 self, context: InferenceContext | None = None 

574 ) -> Generator[InferenceResult, None, InferenceErrorInfo | None]: 

575 """Infer a Name: use name lookup rules 

576 

577 Same implementation as AssignName._infer_lhs.""" 

578 # pylint: disable=import-outside-toplevel 

579 from astroid.constraint import get_constraints 

580 from astroid.helpers import _higher_function_scope 

581 

582 frame, stmts = self.lookup(self.name) 

583 if not stmts: 

584 # Try to see if the name is enclosed in a nested function 

585 # and use the higher (first function) scope for searching. 

586 parent_function = _higher_function_scope(self.scope()) 

587 if parent_function: 

588 _, stmts = parent_function.lookup(self.name) 

589 

590 if not stmts: 

591 raise NameInferenceError( 

592 name=self.name, scope=self.scope(), context=context 

593 ) 

594 context = copy_context(context) 

595 context.lookupname = self.name 

596 context.constraints[self.name] = get_constraints(self, frame) 

597 

598 return _infer_stmts(stmts, context, frame) 

599 

600 

601class Arguments( 

602 _base_nodes.AssignTypeNode 

603): # pylint: disable=too-many-instance-attributes 

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

605 

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

607 function definition. 

608 

609 >>> import astroid 

610 >>> node = astroid.extract_node('def foo(bar): pass') 

611 >>> node 

612 <FunctionDef.foo l.1 at 0x...> 

613 >>> node.args 

614 <Arguments l.1 at 0x...> 

615 """ 

616 

617 # In the ast module, each argument is a new class, _ast.arg, which 

618 # exposes an 'annotation' attribute. In astroid though, arguments are 

619 # exposed as is in the Arguments node, so annotations are exposed 

620 # separately: 

621 # - we expose 'varargannotation' and 'kwargannotation' for the 

622 # annotations of varargs and kwargs. 

623 # - we expose 'annotations', a list with annotations for 

624 # each normal argument. If an argument doesn't have an 

625 # annotation, its value will be None. 

626 _astroid_fields = ( 

627 "args", 

628 "defaults", 

629 "kwonlyargs", 

630 "posonlyargs", 

631 "posonlyargs_annotations", 

632 "kw_defaults", 

633 "annotations", 

634 "varargannotation", 

635 "kwargannotation", 

636 "kwonlyargs_annotations", 

637 "type_comment_args", 

638 "type_comment_kwonlyargs", 

639 "type_comment_posonlyargs", 

640 ) 

641 

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

643 

644 args: list[AssignName] | None 

645 """The names of the required arguments. 

646 

647 Can be None if the associated function does not have a retrievable 

648 signature and the arguments are therefore unknown. 

649 This can happen with (builtin) functions implemented in C that have 

650 incomplete signature information. 

651 """ 

652 

653 defaults: list[NodeNG] | None 

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

655 

656 kwonlyargs: list[AssignName] 

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

658 

659 posonlyargs: list[AssignName] 

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

661 

662 kw_defaults: list[NodeNG | None] | None 

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

664 

665 annotations: list[NodeNG | None] 

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

667 

668 posonlyargs_annotations: list[NodeNG | None] 

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

670 

671 kwonlyargs_annotations: list[NodeNG | None] 

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

673 

674 type_comment_args: list[NodeNG | None] 

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

676 

677 If an argument does not have a type comment, 

678 the value for that argument will be None. 

679 """ 

680 

681 type_comment_kwonlyargs: list[NodeNG | None] 

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

683 

684 If an argument does not have a type comment, 

685 the value for that argument will be None. 

686 """ 

687 

688 type_comment_posonlyargs: list[NodeNG | None] 

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

690 

691 If an argument does not have a type comment, 

692 the value for that argument will be None. 

693 """ 

694 

695 varargannotation: NodeNG | None 

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

697 

698 kwargannotation: NodeNG | None 

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

700 

701 vararg_node: AssignName | None 

702 """The node for variable length arguments""" 

703 

704 kwarg_node: AssignName | None 

705 """The node for variable keyword arguments""" 

706 

707 def __init__( 

708 self, 

709 vararg: str | None, 

710 kwarg: str | None, 

711 parent: NodeNG, 

712 vararg_node: AssignName | None = None, 

713 kwarg_node: AssignName | None = None, 

714 ) -> None: 

715 """Almost all attributes can be None for living objects where introspection failed.""" 

716 super().__init__( 

717 parent=parent, 

718 lineno=None, 

719 col_offset=None, 

720 end_lineno=None, 

721 end_col_offset=None, 

722 ) 

723 

724 self.vararg = vararg 

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

726 

727 self.kwarg = kwarg 

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

729 

730 self.vararg_node = vararg_node 

731 self.kwarg_node = kwarg_node 

732 

733 # pylint: disable=too-many-arguments, too-many-positional-arguments 

734 def postinit( 

735 self, 

736 args: list[AssignName] | None, 

737 defaults: list[NodeNG] | None, 

738 kwonlyargs: list[AssignName], 

739 kw_defaults: list[NodeNG | None] | None, 

740 annotations: list[NodeNG | None], 

741 posonlyargs: list[AssignName], 

742 kwonlyargs_annotations: list[NodeNG | None], 

743 posonlyargs_annotations: list[NodeNG | None], 

744 varargannotation: NodeNG | None = None, 

745 kwargannotation: NodeNG | None = None, 

746 type_comment_args: list[NodeNG | None] | None = None, 

747 type_comment_kwonlyargs: list[NodeNG | None] | None = None, 

748 type_comment_posonlyargs: list[NodeNG | None] | None = None, 

749 ) -> None: 

750 self.args = args 

751 self.defaults = defaults 

752 self.kwonlyargs = kwonlyargs 

753 self.posonlyargs = posonlyargs 

754 self.kw_defaults = kw_defaults 

755 self.annotations = annotations 

756 self.kwonlyargs_annotations = kwonlyargs_annotations 

757 self.posonlyargs_annotations = posonlyargs_annotations 

758 

759 # Parameters that got added later and need a default 

760 self.varargannotation = varargannotation 

761 self.kwargannotation = kwargannotation 

762 if type_comment_args is None: 

763 type_comment_args = [] 

764 self.type_comment_args = type_comment_args 

765 if type_comment_kwonlyargs is None: 

766 type_comment_kwonlyargs = [] 

767 self.type_comment_kwonlyargs = type_comment_kwonlyargs 

768 if type_comment_posonlyargs is None: 

769 type_comment_posonlyargs = [] 

770 self.type_comment_posonlyargs = type_comment_posonlyargs 

771 

772 assigned_stmts = protocols.arguments_assigned_stmts 

773 """Returns the assigned statement (non inferred) according to the assignment type. 

774 See astroid/protocols.py for actual implementation. 

775 """ 

776 

777 def _infer_name(self, frame, name): 

778 if self.parent is frame: 

779 return name 

780 return None 

781 

782 @cached_property 

783 def fromlineno(self) -> int: 

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

785 

786 Can also return 0 if the line can not be determined. 

787 """ 

788 lineno = super().fromlineno 

789 return max(lineno, self.parent.fromlineno or 0) 

790 

791 @cached_property 

792 def arguments(self): 

793 """Get all the arguments for this node. This includes: 

794 

795 * Positional only arguments 

796 * Positional arguments 

797 * Keyword arguments 

798 * Variable arguments (e.g. ``*args``) 

799 * Variable keyword arguments (e.g. ``**kwargs``) 

800 """ 

801 retval = list(itertools.chain((self.posonlyargs or ()), (self.args or ()))) 

802 if self.vararg_node: 

803 retval.append(self.vararg_node) 

804 retval += self.kwonlyargs or () 

805 if self.kwarg_node: 

806 retval.append(self.kwarg_node) 

807 

808 return retval 

809 

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

811 """Get the arguments formatted as string. 

812 

813 :returns: The formatted arguments. 

814 :rtype: str 

815 """ 

816 result = [] 

817 positional_only_defaults = [] 

818 positional_or_keyword_defaults = self.defaults 

819 if self.defaults: 

820 args = self.args or [] 

821 positional_or_keyword_defaults = self.defaults[-len(args) :] 

822 positional_only_defaults = self.defaults[: len(self.defaults) - len(args)] 

823 

824 if self.posonlyargs: 

825 result.append( 

826 _format_args( 

827 self.posonlyargs, 

828 positional_only_defaults, 

829 self.posonlyargs_annotations, 

830 skippable_names=skippable_names, 

831 ) 

832 ) 

833 result.append("/") 

834 if self.args: 

835 result.append( 

836 _format_args( 

837 self.args, 

838 positional_or_keyword_defaults, 

839 getattr(self, "annotations", None), 

840 skippable_names=skippable_names, 

841 ) 

842 ) 

843 if self.vararg: 

844 result.append(f"*{self.vararg}") 

845 if self.kwonlyargs: 

846 if not self.vararg: 

847 result.append("*") 

848 result.append( 

849 _format_args( 

850 self.kwonlyargs, 

851 self.kw_defaults, 

852 self.kwonlyargs_annotations, 

853 skippable_names=skippable_names, 

854 ) 

855 ) 

856 if self.kwarg: 

857 result.append(f"**{self.kwarg}") 

858 return ", ".join(result) 

859 

860 def _get_arguments_data( 

861 self, 

862 ) -> tuple[ 

863 dict[str, tuple[str | None, str | None]], 

864 dict[str, tuple[str | None, str | None]], 

865 ]: 

866 """Get the arguments as dictionary with information about typing and defaults. 

867 

868 The return tuple contains a dictionary for positional and keyword arguments with their typing 

869 and their default value, if any. 

870 The method follows a similar order as format_args but instead of formatting into a string it 

871 returns the data that is used to do so. 

872 """ 

873 pos_only: dict[str, tuple[str | None, str | None]] = {} 

874 kw_only: dict[str, tuple[str | None, str | None]] = {} 

875 

876 # Setup and match defaults with arguments 

877 positional_only_defaults = [] 

878 positional_or_keyword_defaults = self.defaults 

879 if self.defaults: 

880 args = self.args or [] 

881 positional_or_keyword_defaults = self.defaults[-len(args) :] 

882 positional_only_defaults = self.defaults[: len(self.defaults) - len(args)] 

883 

884 for index, posonly in enumerate(self.posonlyargs): 

885 annotation, default = self.posonlyargs_annotations[index], None 

886 if annotation is not None: 

887 annotation = annotation.as_string() 

888 if positional_only_defaults: 

889 default = positional_only_defaults[index].as_string() 

890 pos_only[posonly.name] = (annotation, default) 

891 

892 for index, arg in enumerate(self.args): 

893 annotation, default = self.annotations[index], None 

894 if annotation is not None: 

895 annotation = annotation.as_string() 

896 if positional_or_keyword_defaults: 

897 defaults_offset = len(self.args) - len(positional_or_keyword_defaults) 

898 default_index = index - defaults_offset 

899 if ( 

900 default_index > -1 

901 and positional_or_keyword_defaults[default_index] is not None 

902 ): 

903 default = positional_or_keyword_defaults[default_index].as_string() 

904 pos_only[arg.name] = (annotation, default) 

905 

906 if self.vararg: 

907 annotation = self.varargannotation 

908 if annotation is not None: 

909 annotation = annotation.as_string() 

910 pos_only[self.vararg] = (annotation, None) 

911 

912 for index, kwarg in enumerate(self.kwonlyargs): 

913 annotation = self.kwonlyargs_annotations[index] 

914 if annotation is not None: 

915 annotation = annotation.as_string() 

916 default = self.kw_defaults[index] 

917 if default is not None: 

918 default = default.as_string() 

919 kw_only[kwarg.name] = (annotation, default) 

920 

921 if self.kwarg: 

922 annotation = self.kwargannotation 

923 if annotation is not None: 

924 annotation = annotation.as_string() 

925 kw_only[self.kwarg] = (annotation, None) 

926 

927 return pos_only, kw_only 

928 

929 def default_value(self, argname): 

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

931 

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

933 :type argname: str 

934 

935 :raises NoDefault: If there is no default value defined for the 

936 given argument. 

937 """ 

938 args = [ 

939 arg for arg in self.arguments if arg.name not in [self.vararg, self.kwarg] 

940 ] 

941 

942 index = _find_arg(argname, self.kwonlyargs)[0] 

943 if (index is not None) and (len(self.kw_defaults) > index): 

944 if self.kw_defaults[index] is not None: 

945 return self.kw_defaults[index] 

946 raise NoDefault(func=self.parent, name=argname) 

947 

948 index = _find_arg(argname, args)[0] 

949 if index is not None: 

950 idx = index - (len(args) - len(self.defaults) - len(self.kw_defaults)) 

951 if idx >= 0: 

952 return self.defaults[idx] 

953 

954 raise NoDefault(func=self.parent, name=argname) 

955 

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

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

958 

959 :param name: The name to check for. 

960 :type name: str 

961 

962 :returns: Whether the given name is defined in the arguments, 

963 """ 

964 if name == self.vararg: 

965 return True 

966 if name == self.kwarg: 

967 return True 

968 return self.find_argname(name)[1] is not None 

969 

970 def find_argname(self, argname): 

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

972 

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

974 :type argname: str 

975 

976 :returns: The index and node for the argument. 

977 :rtype: tuple(str or None, AssignName or None) 

978 """ 

979 if self.arguments: 

980 index, argument = _find_arg(argname, self.arguments) 

981 if argument: 

982 return index, argument 

983 return None, None 

984 

985 def get_children(self): 

986 yield from self.posonlyargs or () 

987 

988 for elt in self.posonlyargs_annotations: 

989 if elt is not None: 

990 yield elt 

991 

992 yield from self.args or () 

993 

994 if self.defaults is not None: 

995 yield from self.defaults 

996 yield from self.kwonlyargs 

997 

998 for elt in self.kw_defaults or (): 

999 if elt is not None: 

1000 yield elt 

1001 

1002 for elt in self.annotations: 

1003 if elt is not None: 

1004 yield elt 

1005 

1006 if self.varargannotation is not None: 

1007 yield self.varargannotation 

1008 

1009 if self.kwargannotation is not None: 

1010 yield self.kwargannotation 

1011 

1012 for elt in self.kwonlyargs_annotations: 

1013 if elt is not None: 

1014 yield elt 

1015 

1016 def get_annotations(self) -> Iterator[nodes.NodeNG]: 

1017 """Iterate over all annotations nodes.""" 

1018 for elt in self.posonlyargs_annotations: 

1019 if elt is not None: 

1020 yield elt 

1021 for elt in self.annotations: 

1022 if elt is not None: 

1023 yield elt 

1024 if self.varargannotation is not None: 

1025 yield self.varargannotation 

1026 

1027 for elt in self.kwonlyargs_annotations: 

1028 if elt is not None: 

1029 yield elt 

1030 if self.kwargannotation is not None: 

1031 yield self.kwargannotation 

1032 

1033 @decorators.raise_if_nothing_inferred 

1034 def _infer( 

1035 self, context: InferenceContext | None = None 

1036 ) -> Generator[InferenceResult]: 

1037 # pylint: disable-next=import-outside-toplevel 

1038 from astroid.protocols import _arguments_infer_argname 

1039 

1040 if context is None or context.lookupname is None: 

1041 raise InferenceError(node=self, context=context) 

1042 return _arguments_infer_argname(self, context.lookupname, context) 

1043 

1044 

1045def _find_arg(argname, args): 

1046 for i, arg in enumerate(args): 

1047 if arg.name == argname: 

1048 return i, arg 

1049 return None, None 

1050 

1051 

1052def _format_args( 

1053 args, defaults=None, annotations=None, skippable_names: set[str] | None = None 

1054) -> str: 

1055 if skippable_names is None: 

1056 skippable_names = set() 

1057 values = [] 

1058 if args is None: 

1059 return "" 

1060 if annotations is None: 

1061 annotations = [] 

1062 if defaults is not None: 

1063 default_offset = len(args) - len(defaults) 

1064 else: 

1065 default_offset = None 

1066 packed = itertools.zip_longest(args, annotations) 

1067 for i, (arg, annotation) in enumerate(packed): 

1068 if arg.name in skippable_names: 

1069 continue 

1070 if isinstance(arg, Tuple): 

1071 values.append(f"({_format_args(arg.elts)})") 

1072 else: 

1073 argname = arg.name 

1074 default_sep = "=" 

1075 if annotation is not None: 

1076 argname += ": " + annotation.as_string() 

1077 default_sep = " = " 

1078 values.append(argname) 

1079 

1080 if default_offset is not None and i >= default_offset: 

1081 if defaults[i - default_offset] is not None: 

1082 values[-1] += default_sep + defaults[i - default_offset].as_string() 

1083 return ", ".join(values) 

1084 

1085 

1086def _infer_attribute( 

1087 node: nodes.AssignAttr | nodes.Attribute, context: InferenceContext | None = None 

1088) -> Generator[InferenceResult, None, InferenceErrorInfo]: 

1089 """Infer an AssignAttr/Attribute node by using getattr on the associated object.""" 

1090 # pylint: disable=import-outside-toplevel 

1091 from astroid.constraint import get_constraints 

1092 from astroid.nodes import ClassDef 

1093 

1094 for owner in node.expr.infer(context): 

1095 if isinstance(owner, util.UninferableBase): 

1096 yield owner 

1097 continue 

1098 

1099 context = copy_context(context) 

1100 old_boundnode = context.boundnode 

1101 try: 

1102 context.boundnode = owner 

1103 if isinstance(owner, (ClassDef, Instance)): 

1104 frame = owner if isinstance(owner, ClassDef) else owner._proxied 

1105 context.constraints[node.attrname] = get_constraints(node, frame=frame) 

1106 if node.attrname == "argv" and owner.name == "sys": 

1107 # sys.argv will never be inferable during static analysis 

1108 # It's value would be the args passed to the linter itself 

1109 yield util.Uninferable 

1110 else: 

1111 yield from owner.igetattr(node.attrname, context) 

1112 except ( 

1113 AttributeInferenceError, 

1114 InferenceError, 

1115 AttributeError, 

1116 ): 

1117 pass 

1118 finally: 

1119 context.boundnode = old_boundnode 

1120 return InferenceErrorInfo(node=node, context=context) 

1121 

1122 

1123class AssignAttr(_base_nodes.LookupMixIn, _base_nodes.ParentAssignNode): 

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

1125 

1126 >>> import astroid 

1127 >>> node = astroid.extract_node('self.attribute = range(10)') 

1128 >>> node 

1129 <Assign l.1 at 0x...> 

1130 >>> list(node.get_children()) 

1131 [<AssignAttr.attribute l.1 at 0x...>, <Call l.1 at 0x...>] 

1132 >>> list(node.get_children())[0].as_string() 

1133 'self.attribute' 

1134 """ 

1135 

1136 expr: NodeNG 

1137 

1138 _astroid_fields = ("expr",) 

1139 _other_fields = ("attrname",) 

1140 

1141 def __init__( 

1142 self, 

1143 attrname: str, 

1144 lineno: int, 

1145 col_offset: int, 

1146 parent: NodeNG, 

1147 *, 

1148 end_lineno: int | None, 

1149 end_col_offset: int | None, 

1150 ) -> None: 

1151 self.attrname = attrname 

1152 """The name of the attribute being assigned to.""" 

1153 

1154 super().__init__( 

1155 lineno=lineno, 

1156 col_offset=col_offset, 

1157 end_lineno=end_lineno, 

1158 end_col_offset=end_col_offset, 

1159 parent=parent, 

1160 ) 

1161 

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

1163 self.expr = expr 

1164 

1165 assigned_stmts = protocols.assend_assigned_stmts 

1166 """Returns the assigned statement (non inferred) according to the assignment type. 

1167 See astroid/protocols.py for actual implementation. 

1168 """ 

1169 

1170 def get_children(self): 

1171 yield self.expr 

1172 

1173 @decorators.raise_if_nothing_inferred 

1174 @decorators.path_wrapper 

1175 def _infer( 

1176 self, context: InferenceContext | None = None 

1177 ) -> Generator[InferenceResult, None, InferenceErrorInfo | None]: 

1178 """Infer an AssignAttr: need to inspect the RHS part of the 

1179 assign node. 

1180 """ 

1181 if isinstance(self.parent, AugAssign): 

1182 return self.parent.infer(context) 

1183 

1184 stmts = list(self.assigned_stmts(context=context)) 

1185 return _infer_stmts(stmts, context) 

1186 

1187 @decorators.raise_if_nothing_inferred 

1188 @decorators.path_wrapper 

1189 def infer_lhs( 

1190 self, context: InferenceContext | None = None 

1191 ) -> Generator[InferenceResult, None, InferenceErrorInfo | None]: 

1192 return _infer_attribute(self, context) 

1193 

1194 

1195class Assert(_base_nodes.Statement): 

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

1197 

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

1199 

1200 >>> import astroid 

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

1202 >>> node 

1203 <Assert l.1 at 0x...> 

1204 """ 

1205 

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

1207 

1208 test: NodeNG 

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

1210 

1211 fail: NodeNG | None 

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

1213 

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

1215 self.fail = fail 

1216 self.test = test 

1217 

1218 def get_children(self): 

1219 yield self.test 

1220 

1221 if self.fail is not None: 

1222 yield self.fail 

1223 

1224 

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

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

1227 

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

1229 asssigned to. 

1230 

1231 >>> import astroid 

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

1233 >>> node 

1234 <Assign l.1 at 0x...> 

1235 """ 

1236 

1237 targets: list[NodeNG] 

1238 """What is being assigned to.""" 

1239 

1240 value: NodeNG 

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

1242 

1243 type_annotation: NodeNG | None 

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

1245 

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

1247 _other_other_fields = ("type_annotation",) 

1248 

1249 def postinit( 

1250 self, 

1251 targets: list[NodeNG], 

1252 value: NodeNG, 

1253 type_annotation: NodeNG | None, 

1254 ) -> None: 

1255 self.targets = targets 

1256 self.value = value 

1257 self.type_annotation = type_annotation 

1258 

1259 assigned_stmts = protocols.assign_assigned_stmts 

1260 """Returns the assigned statement (non inferred) according to the assignment type. 

1261 See astroid/protocols.py for actual implementation. 

1262 """ 

1263 

1264 def get_children(self): 

1265 yield from self.targets 

1266 

1267 yield self.value 

1268 

1269 @cached_property 

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

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

1272 

1273 def _get_yield_nodes_skip_functions(self): 

1274 yield from self.value._get_yield_nodes_skip_functions() 

1275 

1276 def _get_yield_nodes_skip_lambdas(self): 

1277 yield from self.value._get_yield_nodes_skip_lambdas() 

1278 

1279 

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

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

1282 

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

1284 

1285 >>> import astroid 

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

1287 >>> node 

1288 <AnnAssign l.1 at 0x...> 

1289 """ 

1290 

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

1292 _other_fields = ("simple",) 

1293 

1294 target: Name | Attribute | Subscript 

1295 """What is being assigned to.""" 

1296 

1297 annotation: NodeNG 

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

1299 

1300 value: NodeNG | None 

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

1302 

1303 simple: int 

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

1305 

1306 def postinit( 

1307 self, 

1308 target: Name | Attribute | Subscript, 

1309 annotation: NodeNG, 

1310 simple: int, 

1311 value: NodeNG | None, 

1312 ) -> None: 

1313 self.target = target 

1314 self.annotation = annotation 

1315 self.value = value 

1316 self.simple = simple 

1317 

1318 assigned_stmts = protocols.assign_annassigned_stmts 

1319 """Returns the assigned statement (non inferred) according to the assignment type. 

1320 See astroid/protocols.py for actual implementation. 

1321 """ 

1322 

1323 def get_children(self): 

1324 yield self.target 

1325 yield self.annotation 

1326 

1327 if self.value is not None: 

1328 yield self.value 

1329 

1330 

1331class AugAssign( 

1332 _base_nodes.AssignTypeNode, _base_nodes.OperatorNode, _base_nodes.Statement 

1333): 

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

1335 

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

1337 

1338 >>> import astroid 

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

1340 >>> node 

1341 <AugAssign l.1 at 0x...> 

1342 """ 

1343 

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

1345 _other_fields = ("op",) 

1346 

1347 target: Name | Attribute | Subscript 

1348 """What is being assigned to.""" 

1349 

1350 value: NodeNG 

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

1352 

1353 def __init__( 

1354 self, 

1355 op: str, 

1356 lineno: int, 

1357 col_offset: int, 

1358 parent: NodeNG, 

1359 *, 

1360 end_lineno: int | None, 

1361 end_col_offset: int | None, 

1362 ) -> None: 

1363 self.op = op 

1364 """The operator that is being combined with the assignment. 

1365 

1366 This includes the equals sign. 

1367 """ 

1368 

1369 super().__init__( 

1370 lineno=lineno, 

1371 col_offset=col_offset, 

1372 end_lineno=end_lineno, 

1373 end_col_offset=end_col_offset, 

1374 parent=parent, 

1375 ) 

1376 

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

1378 self.target = target 

1379 self.value = value 

1380 

1381 assigned_stmts = protocols.assign_assigned_stmts 

1382 """Returns the assigned statement (non inferred) according to the assignment type. 

1383 See astroid/protocols.py for actual implementation. 

1384 """ 

1385 

1386 def type_errors( 

1387 self, context: InferenceContext | None = None 

1388 ) -> list[util.BadBinaryOperationMessage]: 

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

1390 

1391 Each TypeError is represented by a :class:`~astroid.util.BadBinaryOperationMessage`, 

1392 which holds the original exception. 

1393 

1394 If any inferred result is uninferable, an empty list is returned. 

1395 """ 

1396 bad = [] 

1397 try: 

1398 for result in self._infer_augassign(context=context): 

1399 if result is util.Uninferable: 

1400 raise InferenceError 

1401 if isinstance(result, util.BadBinaryOperationMessage): 

1402 bad.append(result) 

1403 except InferenceError: 

1404 return [] 

1405 return bad 

1406 

1407 def get_children(self): 

1408 yield self.target 

1409 yield self.value 

1410 

1411 def _get_yield_nodes_skip_functions(self): 

1412 """An AugAssign node can contain a Yield node in the value""" 

1413 yield from self.value._get_yield_nodes_skip_functions() 

1414 yield from super()._get_yield_nodes_skip_functions() 

1415 

1416 def _get_yield_nodes_skip_lambdas(self): 

1417 """An AugAssign node can contain a Yield node in the value""" 

1418 yield from self.value._get_yield_nodes_skip_lambdas() 

1419 yield from super()._get_yield_nodes_skip_lambdas() 

1420 

1421 def _infer_augassign( 

1422 self, context: InferenceContext | None = None 

1423 ) -> Generator[InferenceResult | util.BadBinaryOperationMessage]: 

1424 """Inference logic for augmented binary operations.""" 

1425 context = context or InferenceContext() 

1426 

1427 rhs_context = context.clone() 

1428 

1429 lhs_iter = self.target.infer_lhs(context=context) 

1430 rhs_iter = self.value.infer(context=rhs_context) 

1431 

1432 for lhs, rhs in itertools.product(lhs_iter, rhs_iter): 

1433 if any(isinstance(value, util.UninferableBase) for value in (rhs, lhs)): 

1434 # Don't know how to process this. 

1435 yield util.Uninferable 

1436 return 

1437 

1438 try: 

1439 yield from self._infer_binary_operation( 

1440 left=lhs, 

1441 right=rhs, 

1442 binary_opnode=self, 

1443 context=context, 

1444 flow_factory=self._get_aug_flow, 

1445 ) 

1446 except _NonDeducibleTypeHierarchy: 

1447 yield util.Uninferable 

1448 

1449 @decorators.raise_if_nothing_inferred 

1450 @decorators.path_wrapper 

1451 def _infer( 

1452 self, context: InferenceContext | None = None 

1453 ) -> Generator[InferenceResult]: 

1454 return self._filter_operation_errors( 

1455 self._infer_augassign, context, util.BadBinaryOperationMessage 

1456 ) 

1457 

1458 

1459class BinOp(_base_nodes.OperatorNode): 

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

1461 

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

1463 

1464 >>> import astroid 

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

1466 >>> node 

1467 <BinOp l.1 at 0x...> 

1468 """ 

1469 

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

1471 _other_fields = ("op",) 

1472 

1473 left: NodeNG 

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

1475 

1476 right: NodeNG 

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

1478 

1479 def __init__( 

1480 self, 

1481 op: str, 

1482 lineno: int, 

1483 col_offset: int, 

1484 parent: NodeNG, 

1485 *, 

1486 end_lineno: int | None, 

1487 end_col_offset: int | None, 

1488 ) -> None: 

1489 self.op = op 

1490 """The operator.""" 

1491 

1492 super().__init__( 

1493 lineno=lineno, 

1494 col_offset=col_offset, 

1495 end_lineno=end_lineno, 

1496 end_col_offset=end_col_offset, 

1497 parent=parent, 

1498 ) 

1499 

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

1501 self.left = left 

1502 self.right = right 

1503 

1504 def type_errors( 

1505 self, context: InferenceContext | None = None 

1506 ) -> list[util.BadBinaryOperationMessage]: 

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

1508 

1509 Each TypeError is represented by a :class:`~astroid.util.BadBinaryOperationMessage`, 

1510 which holds the original exception. 

1511 

1512 If any inferred result is uninferable, an empty list is returned. 

1513 """ 

1514 bad = [] 

1515 try: 

1516 for result in self._infer_binop(context=context): 

1517 if result is util.Uninferable: 

1518 raise InferenceError 

1519 if isinstance(result, util.BadBinaryOperationMessage): 

1520 bad.append(result) 

1521 except InferenceError: 

1522 return [] 

1523 return bad 

1524 

1525 def get_children(self): 

1526 yield self.left 

1527 yield self.right 

1528 

1529 def op_precedence(self) -> int: 

1530 return OP_PRECEDENCE[self.op] 

1531 

1532 def op_left_associative(self) -> bool: 

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

1534 return self.op != "**" 

1535 

1536 def _infer_binop( 

1537 self, context: InferenceContext | None = None 

1538 ) -> Generator[InferenceResult]: 

1539 """Binary operation inference logic.""" 

1540 left = self.left 

1541 right = self.right 

1542 

1543 # we use two separate contexts for evaluating lhs and rhs because 

1544 # 1. evaluating lhs may leave some undesired entries in context.path 

1545 # which may not let us infer right value of rhs 

1546 context = context or InferenceContext() 

1547 lhs_context = copy_context(context) 

1548 rhs_context = copy_context(context) 

1549 lhs_iter = left.infer(context=lhs_context) 

1550 rhs_iter = right.infer(context=rhs_context) 

1551 for lhs, rhs in itertools.product(lhs_iter, rhs_iter): 

1552 if any(isinstance(value, util.UninferableBase) for value in (rhs, lhs)): 

1553 # Don't know how to process this. 

1554 yield util.Uninferable 

1555 return 

1556 

1557 try: 

1558 yield from self._infer_binary_operation( 

1559 lhs, rhs, self, context, self._get_binop_flow 

1560 ) 

1561 except _NonDeducibleTypeHierarchy: 

1562 yield util.Uninferable 

1563 

1564 @decorators.yes_if_nothing_inferred 

1565 @decorators.path_wrapper 

1566 def _infer( 

1567 self, context: InferenceContext | None = None 

1568 ) -> Generator[InferenceResult]: 

1569 return self._filter_operation_errors( 

1570 self._infer_binop, context, util.BadBinaryOperationMessage 

1571 ) 

1572 

1573 

1574class BoolOp(NodeNG): 

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

1576 

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

1578 

1579 >>> import astroid 

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

1581 >>> node 

1582 <BoolOp l.1 at 0x...> 

1583 """ 

1584 

1585 _astroid_fields = ("values",) 

1586 _other_fields = ("op",) 

1587 

1588 def __init__( 

1589 self, 

1590 op: str, 

1591 lineno: int | None = None, 

1592 col_offset: int | None = None, 

1593 parent: NodeNG | None = None, 

1594 *, 

1595 end_lineno: int | None = None, 

1596 end_col_offset: int | None = None, 

1597 ) -> None: 

1598 """ 

1599 :param op: The operator. 

1600 

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

1602 

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

1604 source code. 

1605 

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

1607 

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

1609 

1610 :param end_col_offset: The end column this node appears on in the 

1611 source code. Note: This is after the last symbol. 

1612 """ 

1613 self.op: str = op 

1614 """The operator.""" 

1615 

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

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

1618 

1619 super().__init__( 

1620 lineno=lineno, 

1621 col_offset=col_offset, 

1622 end_lineno=end_lineno, 

1623 end_col_offset=end_col_offset, 

1624 parent=parent, 

1625 ) 

1626 

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

1628 """Do some setup after initialisation. 

1629 

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

1631 """ 

1632 if values is not None: 

1633 self.values = values 

1634 

1635 def get_children(self): 

1636 yield from self.values 

1637 

1638 def op_precedence(self) -> int: 

1639 return OP_PRECEDENCE[self.op] 

1640 

1641 @decorators.raise_if_nothing_inferred 

1642 @decorators.path_wrapper 

1643 def _infer( 

1644 self, context: InferenceContext | None = None 

1645 ) -> Generator[InferenceResult, None, InferenceErrorInfo | None]: 

1646 """Infer a boolean operation (and / or / not). 

1647 

1648 The function will calculate the boolean operation 

1649 for all pairs generated through inference for each component 

1650 node. 

1651 """ 

1652 values = self.values 

1653 if self.op == "or": 

1654 predicate = operator.truth 

1655 else: 

1656 predicate = operator.not_ 

1657 

1658 try: 

1659 inferred_values = [value.infer(context=context) for value in values] 

1660 except InferenceError: 

1661 yield util.Uninferable 

1662 return None 

1663 

1664 for pair in itertools.product(*inferred_values): 

1665 if any(isinstance(item, util.UninferableBase) for item in pair): 

1666 # Can't infer the final result, just yield Uninferable. 

1667 yield util.Uninferable 

1668 continue 

1669 

1670 bool_values = [item.bool_value() for item in pair] 

1671 if any(isinstance(item, util.UninferableBase) for item in bool_values): 

1672 # Can't infer the final result, just yield Uninferable. 

1673 yield util.Uninferable 

1674 continue 

1675 

1676 # Since the boolean operations are short circuited operations, 

1677 # this code yields the first value for which the predicate is True 

1678 # and if no value respected the predicate, then the last value will 

1679 # be returned (or Uninferable if there was no last value). 

1680 # This is conforming to the semantics of `and` and `or`: 

1681 # 1 and 0 -> 1 

1682 # 0 and 1 -> 0 

1683 # 1 or 0 -> 1 

1684 # 0 or 1 -> 1 

1685 value = util.Uninferable 

1686 for value, bool_value in zip(pair, bool_values): 

1687 if predicate(bool_value): 

1688 yield value 

1689 break 

1690 else: 

1691 yield value 

1692 

1693 return InferenceErrorInfo(node=self, context=context) 

1694 

1695 

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

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

1698 

1699 >>> import astroid 

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

1701 >>> node 

1702 <Break l.1 at 0x...> 

1703 """ 

1704 

1705 

1706class Call(NodeNG): 

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

1708 

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

1710 

1711 >>> import astroid 

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

1713 >>> node 

1714 <Call l.1 at 0x...> 

1715 """ 

1716 

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

1718 

1719 func: NodeNG 

1720 """What is being called.""" 

1721 

1722 args: list[NodeNG] 

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

1724 

1725 keywords: list[Keyword] 

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

1727 

1728 def postinit( 

1729 self, func: NodeNG, args: list[NodeNG], keywords: list[Keyword] 

1730 ) -> None: 

1731 self.func = func 

1732 self.args = args 

1733 self.keywords = keywords 

1734 

1735 @property 

1736 def starargs(self) -> list[Starred]: 

1737 """The positional arguments that unpack something.""" 

1738 return [arg for arg in self.args if isinstance(arg, Starred)] 

1739 

1740 @property 

1741 def kwargs(self) -> list[Keyword]: 

1742 """The keyword arguments that unpack something.""" 

1743 return [keyword for keyword in self.keywords if keyword.arg is None] 

1744 

1745 def get_children(self): 

1746 yield self.func 

1747 

1748 yield from self.args 

1749 

1750 yield from self.keywords 

1751 

1752 @decorators.raise_if_nothing_inferred 

1753 @decorators.path_wrapper 

1754 def _infer( 

1755 self, context: InferenceContext | None = None 

1756 ) -> Generator[InferenceResult, None, InferenceErrorInfo]: 

1757 """Infer a Call node by trying to guess what the function returns.""" 

1758 callcontext = copy_context(context) 

1759 callcontext.boundnode = None 

1760 if context is not None: 

1761 callcontext.extra_context = self._populate_context_lookup(context.clone()) 

1762 

1763 for callee in self.func.infer(context): 

1764 if isinstance(callee, util.UninferableBase): 

1765 yield callee 

1766 continue 

1767 try: 

1768 if hasattr(callee, "infer_call_result"): 

1769 callcontext.callcontext = CallContext( 

1770 args=self.args, keywords=self.keywords, callee=callee 

1771 ) 

1772 yield from callee.infer_call_result( 

1773 caller=self, context=callcontext 

1774 ) 

1775 except InferenceError: 

1776 continue 

1777 return InferenceErrorInfo(node=self, context=context) 

1778 

1779 def _populate_context_lookup(self, context: InferenceContext | None): 

1780 """Allows context to be saved for later for inference inside a function.""" 

1781 context_lookup: dict[InferenceResult, InferenceContext] = {} 

1782 if context is None: 

1783 return context_lookup 

1784 for arg in self.args: 

1785 if isinstance(arg, Starred): 

1786 context_lookup[arg.value] = context 

1787 else: 

1788 context_lookup[arg] = context 

1789 keywords = self.keywords if self.keywords is not None else [] 

1790 for keyword in keywords: 

1791 context_lookup[keyword.value] = context 

1792 return context_lookup 

1793 

1794 

1795COMPARE_OPS: dict[str, Callable[[Any, Any], bool]] = { 

1796 "==": operator.eq, 

1797 "!=": operator.ne, 

1798 "<": operator.lt, 

1799 "<=": operator.le, 

1800 ">": operator.gt, 

1801 ">=": operator.ge, 

1802 "in": lambda a, b: a in b, 

1803 "not in": lambda a, b: a not in b, 

1804} 

1805UNINFERABLE_OPS = { 

1806 "is", 

1807 "is not", 

1808} 

1809 

1810 

1811class Compare(NodeNG): 

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

1813 

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

1815 

1816 >>> import astroid 

1817 >>> node = astroid.extract_node('a <= b <= c') 

1818 >>> node 

1819 <Compare l.1 at 0x...> 

1820 >>> node.ops 

1821 [('<=', <Name.b l.1 at 0x...>), ('<=', <Name.c l.1 at 0x...>)] 

1822 """ 

1823 

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

1825 

1826 left: NodeNG 

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

1828 

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

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

1831 

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

1833 self.left = left 

1834 self.ops = ops 

1835 

1836 def get_children(self): 

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

1838 

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

1840 strings. 

1841 

1842 :returns: The children. 

1843 :rtype: Iterator[NodeNG] 

1844 """ 

1845 yield self.left 

1846 for _, comparator in self.ops: 

1847 yield comparator # we don't want the 'op' 

1848 

1849 def last_child(self): 

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

1851 

1852 :returns: The last child. 

1853 :rtype: NodeNG 

1854 """ 

1855 # XXX maybe if self.ops: 

1856 return self.ops[-1][1] 

1857 # return self.left 

1858 

1859 # TODO: move to util? 

1860 @staticmethod 

1861 def _to_literal(node: SuccessfulInferenceResult) -> Any: 

1862 # Can raise SyntaxError, ValueError, or TypeError from ast.literal_eval 

1863 # Can raise AttributeError from node.as_string() as not all nodes have a visitor 

1864 # Is this the stupidest idea or the simplest idea? 

1865 return ast.literal_eval(node.as_string()) 

1866 

1867 def _do_compare( 

1868 self, 

1869 left_iter: Iterable[InferenceResult], 

1870 op: str, 

1871 right_iter: Iterable[InferenceResult], 

1872 ) -> bool | util.UninferableBase: 

1873 """ 

1874 If all possible combinations are either True or False, return that: 

1875 >>> _do_compare([1, 2], '<=', [3, 4]) 

1876 True 

1877 >>> _do_compare([1, 2], '==', [3, 4]) 

1878 False 

1879 

1880 If any item is uninferable, or if some combinations are True and some 

1881 are False, return Uninferable: 

1882 >>> _do_compare([1, 3], '<=', [2, 4]) 

1883 util.Uninferable 

1884 """ 

1885 retval: bool | None = None 

1886 if op in UNINFERABLE_OPS: 

1887 return util.Uninferable 

1888 op_func = COMPARE_OPS[op] 

1889 

1890 for left, right in itertools.product(left_iter, right_iter): 

1891 if isinstance(left, util.UninferableBase) or isinstance( 

1892 right, util.UninferableBase 

1893 ): 

1894 return util.Uninferable 

1895 

1896 try: 

1897 left, right = self._to_literal(left), self._to_literal(right) 

1898 except (SyntaxError, ValueError, AttributeError, TypeError): 

1899 return util.Uninferable 

1900 

1901 try: 

1902 expr = op_func(left, right) 

1903 except TypeError as exc: 

1904 raise AstroidTypeError from exc 

1905 

1906 if retval is None: 

1907 retval = expr 

1908 elif retval != expr: 

1909 return util.Uninferable 

1910 # (or both, but "True | False" is basically the same) 

1911 

1912 assert retval is not None 

1913 return retval # it was all the same value 

1914 

1915 def _infer( 

1916 self, context: InferenceContext | None = None 

1917 ) -> Generator[nodes.Const | util.UninferableBase]: 

1918 """Chained comparison inference logic.""" 

1919 retval: bool | util.UninferableBase = True 

1920 

1921 ops = self.ops 

1922 left_node = self.left 

1923 lhs = list(left_node.infer(context=context)) 

1924 # should we break early if first element is uninferable? 

1925 for op, right_node in ops: 

1926 # eagerly evaluate rhs so that values can be re-used as lhs 

1927 rhs = list(right_node.infer(context=context)) 

1928 try: 

1929 retval = self._do_compare(lhs, op, rhs) 

1930 except AstroidTypeError: 

1931 retval = util.Uninferable 

1932 break 

1933 if retval is not True: 

1934 break # short-circuit 

1935 lhs = rhs # continue 

1936 if retval is util.Uninferable: 

1937 yield retval # type: ignore[misc] 

1938 else: 

1939 yield Const(retval) 

1940 

1941 

1942class Comprehension(NodeNG): 

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

1944 

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

1946 comprehension including generator expressions. 

1947 

1948 >>> import astroid 

1949 >>> node = astroid.extract_node('[x for x in some_values]') 

1950 >>> list(node.get_children()) 

1951 [<Name.x l.1 at 0x...>, <Comprehension l.1 at 0x...>] 

1952 >>> list(node.get_children())[1].as_string() 

1953 'for x in some_values' 

1954 """ 

1955 

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

1957 _other_fields = ("is_async",) 

1958 

1959 optional_assign = True 

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

1961 

1962 target: NodeNG 

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

1964 

1965 iter: NodeNG 

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

1967 

1968 ifs: list[NodeNG] 

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

1970 

1971 is_async: bool 

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

1973 

1974 def postinit( 

1975 self, 

1976 target: NodeNG, 

1977 iter: NodeNG, # pylint: disable = redefined-builtin 

1978 ifs: list[NodeNG], 

1979 is_async: bool, 

1980 ) -> None: 

1981 self.target = target 

1982 self.iter = iter 

1983 self.ifs = ifs 

1984 self.is_async = is_async 

1985 

1986 assigned_stmts = protocols.for_assigned_stmts 

1987 """Returns the assigned statement (non inferred) according to the assignment type. 

1988 See astroid/protocols.py for actual implementation. 

1989 """ 

1990 

1991 def assign_type(self): 

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

1993 

1994 :returns: The assignment type. 

1995 :rtype: NodeNG 

1996 """ 

1997 return self 

1998 

1999 def _get_filtered_stmts( 

2000 self, lookup_node, node, stmts, mystmt: _base_nodes.Statement | None 

2001 ): 

2002 """method used in filter_stmts""" 

2003 if self is mystmt: 

2004 if isinstance(lookup_node, (Const, Name)): 

2005 return [lookup_node], True 

2006 

2007 elif self.statement() is mystmt: 

2008 # original node's statement is the assignment, only keeps 

2009 # current node (gen exp, list comp) 

2010 

2011 return [node], True 

2012 

2013 return stmts, False 

2014 

2015 def get_children(self): 

2016 yield self.target 

2017 yield self.iter 

2018 

2019 yield from self.ifs 

2020 

2021 

2022class Const(_base_nodes.NoChildrenNode, Instance): 

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

2024 

2025 >>> import astroid 

2026 >>> node = astroid.extract_node('(5, "This is a string.", True, None, b"bytes")') 

2027 >>> node 

2028 <Tuple.tuple l.1 at 0x...> 

2029 >>> list(node.get_children()) 

2030 [<Const.int l.1 at 0x...>, 

2031 <Const.str l.1 at 0x...>, 

2032 <Const.bool l.1 at 0x...>, 

2033 <Const.NoneType l.1 at 0x...>, 

2034 <Const.bytes l.1 at 0x...>] 

2035 """ 

2036 

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

2038 

2039 def __init__( 

2040 self, 

2041 value: Any, 

2042 lineno: int | None = None, 

2043 col_offset: int | None = None, 

2044 parent: NodeNG = SYNTHETIC_ROOT, 

2045 kind: str | None = None, 

2046 *, 

2047 end_lineno: int | None = None, 

2048 end_col_offset: int | None = None, 

2049 ) -> None: 

2050 """ 

2051 :param value: The value that the constant represents. 

2052 

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

2054 

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

2056 source code. 

2057 

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

2059 

2060 :param kind: The string prefix. "u" for u-prefixed strings and ``None`` otherwise. 

2061 

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

2063 

2064 :param end_col_offset: The end column this node appears on in the 

2065 source code. Note: This is after the last symbol. 

2066 """ 

2067 if getattr(value, "__name__", None) == "__doc__": 

2068 warnings.warn( # pragma: no cover 

2069 "You have most likely called a __doc__ field of some object " 

2070 "and it didn't return a string. " 

2071 "That happens to some symbols from the standard library. " 

2072 "Check for isinstance(<X>.__doc__, str).", 

2073 RuntimeWarning, 

2074 stacklevel=0, 

2075 ) 

2076 self.value = value 

2077 """The value that the constant represents.""" 

2078 

2079 self.kind: str | None = kind # can be None 

2080 """"The string prefix. "u" for u-prefixed strings and ``None`` otherwise.""" 

2081 

2082 super().__init__( 

2083 lineno=lineno, 

2084 col_offset=col_offset, 

2085 end_lineno=end_lineno, 

2086 end_col_offset=end_col_offset, 

2087 parent=parent, 

2088 ) 

2089 

2090 Instance.__init__(self, None) 

2091 

2092 infer_unary_op = protocols.const_infer_unary_op 

2093 infer_binary_op = protocols.const_infer_binary_op 

2094 

2095 def __getattr__(self, name): 

2096 # This is needed because of Proxy's __getattr__ method. 

2097 # Calling object.__new__ on this class without calling 

2098 # __init__ would result in an infinite loop otherwise 

2099 # since __getattr__ is called when an attribute doesn't 

2100 # exist and self._proxied indirectly calls self.value 

2101 # and Proxy __getattr__ calls self.value 

2102 if name == "value": 

2103 raise AttributeError 

2104 return super().__getattr__(name) 

2105 

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

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

2108 

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

2110 :type index: Const or Slice 

2111 

2112 :raises AstroidTypeError: When the given index cannot be used as a 

2113 subscript index, or if this node is not subscriptable. 

2114 """ 

2115 if isinstance(index, Const): 

2116 index_value = index.value 

2117 elif isinstance(index, Slice): 

2118 index_value = _infer_slice(index, context=context) 

2119 

2120 else: 

2121 raise AstroidTypeError( 

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

2123 ) 

2124 

2125 try: 

2126 if isinstance(self.value, (str, bytes)): 

2127 return Const(self.value[index_value]) 

2128 except ValueError as exc: 

2129 raise AstroidValueError( 

2130 f"Could not index {self.value!r} with {index_value!r}" 

2131 ) from exc 

2132 except IndexError as exc: 

2133 raise AstroidIndexError( 

2134 message="Index {index!r} out of range", 

2135 node=self, 

2136 index=index, 

2137 context=context, 

2138 ) from exc 

2139 except TypeError as exc: 

2140 raise AstroidTypeError( 

2141 message="Type error {error!r}", node=self, index=index, context=context 

2142 ) from exc 

2143 

2144 try: 

2145 value_str = str(self.value) 

2146 except ValueError: 

2147 value_str = f"<{type(self.value).__name__} (too large to display)>" 

2148 raise AstroidTypeError(f"{self!r} (value={value_str})") 

2149 

2150 def has_dynamic_getattr(self) -> bool: 

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

2152 

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

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

2155 """ 

2156 return False 

2157 

2158 def itered(self): 

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

2160 

2161 :returns: The contents of this node. 

2162 :rtype: Iterator[Const] 

2163 

2164 :raises TypeError: If this node does not represent something that is iterable. 

2165 """ 

2166 if isinstance(self.value, str): 

2167 return [const_factory(elem) for elem in self.value] 

2168 raise TypeError(f"Cannot iterate over type {type(self.value)!r}") 

2169 

2170 def pytype(self) -> str: 

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

2172 

2173 :returns: The name of the type. 

2174 """ 

2175 return self._proxied.qname() 

2176 

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

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

2179 

2180 :returns: The boolean value of this node. 

2181 :rtype: bool or Uninferable 

2182 """ 

2183 # bool(NotImplemented) is deprecated; it raises TypeError starting from Python 3.14 

2184 # and returns True for versions under 3.14 

2185 if self.value is NotImplemented: 

2186 return util.Uninferable if PY314_PLUS else True 

2187 return bool(self.value) 

2188 

2189 def _infer(self, context: InferenceContext | None = None) -> Iterator[Const]: 

2190 yield self 

2191 

2192 

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

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

2195 

2196 >>> import astroid 

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

2198 >>> node 

2199 <Continue l.1 at 0x...> 

2200 """ 

2201 

2202 

2203class Decorators(NodeNG): 

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

2205 

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

2207 a method or function. 

2208 

2209 >>> import astroid 

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

2211 ... @property 

2212 ... def my_property(self): 

2213 ... return 3 

2214 ... ''') 

2215 >>> node 

2216 <FunctionDef.my_property l.3 at 0x...> 

2217 >>> list(node.get_children())[0] 

2218 <Decorators l.2 at 0x...> 

2219 """ 

2220 

2221 _astroid_fields = ("nodes",) 

2222 

2223 nodes: list[NodeNG] 

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

2225 

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

2227 self.nodes = nodes 

2228 

2229 def scope(self) -> LocalsDictNodeNG: 

2230 """The first parent node defining a new scope. 

2231 These can be Module, FunctionDef, ClassDef, Lambda, or GeneratorExp nodes. 

2232 

2233 :returns: The first parent scope node. 

2234 """ 

2235 # skip the function or class node to go directly to the upper level scope 

2236 if not self.parent: 

2237 raise ParentMissingError(target=self) 

2238 if not self.parent.parent: 

2239 raise ParentMissingError(target=self.parent) 

2240 return self.parent.parent.scope() 

2241 

2242 def frame(self) -> FrameType: 

2243 """The first parent node defining a new frame.""" 

2244 # skip the function or class node to go directly to the upper level frame 

2245 if not self.parent: 

2246 raise ParentMissingError(target=self) 

2247 if not self.parent.parent: 

2248 raise ParentMissingError(target=self.parent) 

2249 return self.parent.parent.frame() 

2250 

2251 def get_children(self): 

2252 yield from self.nodes 

2253 

2254 

2255class DelAttr(_base_nodes.ParentAssignNode): 

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

2257 

2258 >>> import astroid 

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

2260 >>> node 

2261 <Delete l.1 at 0x...> 

2262 >>> list(node.get_children())[0] 

2263 <DelAttr.attr l.1 at 0x...> 

2264 """ 

2265 

2266 _astroid_fields = ("expr",) 

2267 _other_fields = ("attrname",) 

2268 

2269 expr: NodeNG 

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

2271 

2272 def __init__( 

2273 self, 

2274 attrname: str, 

2275 lineno: int, 

2276 col_offset: int, 

2277 parent: NodeNG, 

2278 *, 

2279 end_lineno: int | None, 

2280 end_col_offset: int | None, 

2281 ) -> None: 

2282 self.attrname = attrname 

2283 """The name of the attribute that is being deleted.""" 

2284 

2285 super().__init__( 

2286 lineno=lineno, 

2287 col_offset=col_offset, 

2288 end_lineno=end_lineno, 

2289 end_col_offset=end_col_offset, 

2290 parent=parent, 

2291 ) 

2292 

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

2294 self.expr = expr 

2295 

2296 def get_children(self): 

2297 yield self.expr 

2298 

2299 

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

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

2302 

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

2304 

2305 >>> import astroid 

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

2307 >>> node 

2308 <Delete l.1 at 0x...> 

2309 """ 

2310 

2311 _astroid_fields = ("targets",) 

2312 

2313 def __init__( 

2314 self, 

2315 lineno: int, 

2316 col_offset: int, 

2317 parent: NodeNG, 

2318 *, 

2319 end_lineno: int | None, 

2320 end_col_offset: int | None, 

2321 ) -> None: 

2322 self.targets: list[NodeNG] = [] 

2323 """What is being deleted.""" 

2324 

2325 super().__init__( 

2326 lineno=lineno, 

2327 col_offset=col_offset, 

2328 end_lineno=end_lineno, 

2329 end_col_offset=end_col_offset, 

2330 parent=parent, 

2331 ) 

2332 

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

2334 self.targets = targets 

2335 

2336 def get_children(self): 

2337 yield from self.targets 

2338 

2339 

2340class Dict(NodeNG, Instance): 

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

2342 

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

2344 

2345 >>> import astroid 

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

2347 >>> node 

2348 <Dict.dict l.1 at 0x...> 

2349 """ 

2350 

2351 _astroid_fields = ("items",) 

2352 

2353 def __init__( 

2354 self, 

2355 lineno: int | None, 

2356 col_offset: int | None, 

2357 parent: NodeNG | None, 

2358 *, 

2359 end_lineno: int | None, 

2360 end_col_offset: int | None, 

2361 ) -> None: 

2362 self.items: list[tuple[InferenceResult, InferenceResult]] = [] 

2363 """The key-value pairs contained in the dictionary.""" 

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 postinit(self, items: list[tuple[InferenceResult, InferenceResult]]) -> None: 

2374 """Do some setup after initialisation. 

2375 

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

2377 """ 

2378 self.items = items 

2379 

2380 infer_unary_op = protocols.dict_infer_unary_op 

2381 

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

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

2384 

2385 :returns: The name of the type. 

2386 """ 

2387 return "builtins.dict" 

2388 

2389 def get_children(self): 

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

2391 

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

2393 code, key first then the value. 

2394 

2395 :returns: The children. 

2396 :rtype: Iterator[NodeNG] 

2397 """ 

2398 for key, value in self.items: 

2399 yield key 

2400 yield value 

2401 

2402 def last_child(self): 

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

2404 

2405 :returns: The last child, or None if no children exist. 

2406 :rtype: NodeNG or None 

2407 """ 

2408 if self.items: 

2409 return self.items[-1][1] 

2410 return None 

2411 

2412 def itered(self): 

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

2414 

2415 :returns: The keys of this node. 

2416 :rtype: Iterator[NodeNG] 

2417 """ 

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

2419 

2420 def getitem( 

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

2422 ) -> NodeNG: 

2423 """Get an item from this node. 

2424 

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

2426 

2427 :raises AstroidTypeError: When the given index cannot be used as a 

2428 subscript index, or if this node is not subscriptable. 

2429 :raises AstroidIndexError: If the given index does not exist in the 

2430 dictionary. 

2431 """ 

2432 for key, value in self.items: 

2433 # TODO(cpopa): no support for overriding yet, {1:2, **{1: 3}}. 

2434 if isinstance(key, DictUnpack): 

2435 inferred_value = util.safe_infer(value, context) 

2436 if not isinstance(inferred_value, Dict): 

2437 continue 

2438 

2439 try: 

2440 return inferred_value.getitem(index, context) 

2441 except (AstroidTypeError, AstroidIndexError): 

2442 continue 

2443 

2444 for inferredkey in key.infer(context): 

2445 if isinstance(inferredkey, util.UninferableBase): 

2446 continue 

2447 if isinstance(inferredkey, Const) and isinstance(index, Const): 

2448 if inferredkey.value == index.value: 

2449 return value 

2450 

2451 raise AstroidIndexError(index) 

2452 

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

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

2455 

2456 :returns: The boolean value of this node. 

2457 :rtype: bool 

2458 """ 

2459 return bool(self.items) 

2460 

2461 def _infer(self, context: InferenceContext | None = None) -> Iterator[nodes.Dict]: 

2462 if not any(isinstance(k, DictUnpack) for k, _ in self.items): 

2463 yield self 

2464 else: 

2465 items = self._infer_map(context) 

2466 new_seq = type(self)( 

2467 lineno=self.lineno, 

2468 col_offset=self.col_offset, 

2469 parent=self.parent, 

2470 end_lineno=self.end_lineno, 

2471 end_col_offset=self.end_col_offset, 

2472 ) 

2473 new_seq.postinit(list(items.items())) 

2474 yield new_seq 

2475 

2476 @staticmethod 

2477 def _update_with_replacement( 

2478 lhs_dict: dict[SuccessfulInferenceResult, SuccessfulInferenceResult], 

2479 rhs_dict: dict[SuccessfulInferenceResult, SuccessfulInferenceResult], 

2480 ) -> dict[SuccessfulInferenceResult, SuccessfulInferenceResult]: 

2481 """Delete nodes that equate to duplicate keys. 

2482 

2483 Since an astroid node doesn't 'equal' another node with the same value, 

2484 this function uses the as_string method to make sure duplicate keys 

2485 don't get through 

2486 

2487 Note that both the key and the value are astroid nodes 

2488 

2489 Fixes issue with DictUnpack causing duplicate keys 

2490 in inferred Dict items 

2491 

2492 :param lhs_dict: Dictionary to 'merge' nodes into 

2493 :param rhs_dict: Dictionary with nodes to pull from 

2494 :return : merged dictionary of nodes 

2495 """ 

2496 combined_dict = itertools.chain(lhs_dict.items(), rhs_dict.items()) 

2497 # Overwrite keys which have the same string values 

2498 string_map = {key.as_string(): (key, value) for key, value in combined_dict} 

2499 # Return to dictionary 

2500 return dict(string_map.values()) 

2501 

2502 def _infer_map( 

2503 self, context: InferenceContext | None 

2504 ) -> dict[SuccessfulInferenceResult, SuccessfulInferenceResult]: 

2505 """Infer all values based on Dict.items.""" 

2506 values: dict[SuccessfulInferenceResult, SuccessfulInferenceResult] = {} 

2507 for name, value in self.items: 

2508 if isinstance(name, DictUnpack): 

2509 double_starred = util.safe_infer(value, context) 

2510 if not double_starred: 

2511 raise InferenceError 

2512 if not isinstance(double_starred, Dict): 

2513 raise InferenceError(node=self, context=context) 

2514 unpack_items = double_starred._infer_map(context) 

2515 values = self._update_with_replacement(values, unpack_items) 

2516 else: 

2517 key = util.safe_infer(name, context=context) 

2518 safe_value = util.safe_infer(value, context=context) 

2519 if any(not elem for elem in (key, safe_value)): 

2520 raise InferenceError(node=self, context=context) 

2521 # safe_value is SuccessfulInferenceResult as bool(Uninferable) == False 

2522 values = self._update_with_replacement(values, {key: safe_value}) 

2523 return values 

2524 

2525 

2526class Expr(_base_nodes.Statement): 

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

2528 

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

2530 stored. 

2531 

2532 >>> import astroid 

2533 >>> node = astroid.extract_node('method()') 

2534 >>> node 

2535 <Call l.1 at 0x...> 

2536 >>> node.parent 

2537 <Expr l.1 at 0x...> 

2538 """ 

2539 

2540 _astroid_fields = ("value",) 

2541 

2542 value: NodeNG 

2543 """What the expression does.""" 

2544 

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

2546 self.value = value 

2547 

2548 def get_children(self): 

2549 yield self.value 

2550 

2551 def _get_yield_nodes_skip_functions(self): 

2552 if not self.value.is_function: 

2553 yield from self.value._get_yield_nodes_skip_functions() 

2554 

2555 def _get_yield_nodes_skip_lambdas(self): 

2556 if not self.value.is_lambda: 

2557 yield from self.value._get_yield_nodes_skip_lambdas() 

2558 

2559 

2560class EmptyNode(_base_nodes.NoChildrenNode): 

2561 """Holds an arbitrary object in the :attr:`~astroid.nodes.LocalsDictNodeNG.locals`.""" 

2562 

2563 object = None 

2564 

2565 def __init__( 

2566 self, 

2567 lineno: None = None, 

2568 col_offset: None = None, 

2569 parent: NodeNG = SYNTHETIC_ROOT, 

2570 *, 

2571 end_lineno: None = None, 

2572 end_col_offset: None = None, 

2573 ) -> None: 

2574 super().__init__( 

2575 lineno=lineno, 

2576 col_offset=col_offset, 

2577 end_lineno=end_lineno, 

2578 end_col_offset=end_col_offset, 

2579 parent=parent, 

2580 ) 

2581 

2582 def has_underlying_object(self) -> bool: 

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

2584 

2585 @decorators.raise_if_nothing_inferred 

2586 @decorators.path_wrapper 

2587 def _infer( 

2588 self, context: InferenceContext | None = None 

2589 ) -> Generator[InferenceResult]: 

2590 if not self.has_underlying_object(): 

2591 yield util.Uninferable 

2592 else: 

2593 try: 

2594 yield from AstroidManager().infer_ast_from_something( 

2595 self.object, context=context 

2596 ) 

2597 except AstroidError: 

2598 yield util.Uninferable 

2599 

2600 

2601class ExceptHandler( 

2602 _base_nodes.MultiLineBlockNode, _base_nodes.AssignTypeNode, _base_nodes.Statement 

2603): 

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

2605 

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

2607 

2608 >>> import astroid 

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

2610 ... try: 

2611 ... do_something() 

2612 ... except Exception as error: 

2613 ... print("Error!") 

2614 ... ''') 

2615 >>> node 

2616 <Try l.2 at 0x...> 

2617 >>> node.handlers 

2618 [<ExceptHandler l.4 at 0x...>] 

2619 """ 

2620 

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

2622 _multi_line_block_fields = ("body",) 

2623 

2624 type: NodeNG | None 

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

2626 

2627 name: AssignName | None 

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

2629 

2630 body: list[NodeNG] 

2631 """The contents of the block.""" 

2632 

2633 assigned_stmts = protocols.excepthandler_assigned_stmts 

2634 """Returns the assigned statement (non inferred) according to the assignment type. 

2635 See astroid/protocols.py for actual implementation. 

2636 """ 

2637 

2638 def postinit( 

2639 self, 

2640 type: NodeNG | None, # pylint: disable = redefined-builtin 

2641 name: AssignName | None, 

2642 body: list[NodeNG], 

2643 ) -> None: 

2644 self.type = type 

2645 self.name = name 

2646 self.body = body 

2647 

2648 def get_children(self): 

2649 if self.type is not None: 

2650 yield self.type 

2651 

2652 if self.name is not None: 

2653 yield self.name 

2654 

2655 yield from self.body 

2656 

2657 @cached_property 

2658 def blockstart_tolineno(self): 

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

2660 

2661 :type: int 

2662 """ 

2663 if self.name: 

2664 return self.name.tolineno 

2665 if self.type: 

2666 return self.type.tolineno 

2667 return self.lineno 

2668 

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

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

2671 

2672 :param exceptions: The names of the exceptions to check for. 

2673 """ 

2674 if self.type is None or exceptions is None: 

2675 return True 

2676 return any(node.name in exceptions for node in self.type._get_name_nodes()) 

2677 

2678 

2679class For( 

2680 _base_nodes.MultiLineWithElseBlockNode, 

2681 _base_nodes.AssignTypeNode, 

2682 _base_nodes.Statement, 

2683): 

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

2685 

2686 >>> import astroid 

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

2688 >>> node 

2689 <For l.1 at 0x...> 

2690 """ 

2691 

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

2693 _other_other_fields = ("type_annotation",) 

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

2695 

2696 optional_assign = True 

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

2698 

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

2700 """ 

2701 

2702 target: NodeNG 

2703 """What the loop assigns to.""" 

2704 

2705 iter: NodeNG 

2706 """What the loop iterates over.""" 

2707 

2708 body: list[NodeNG] 

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

2710 

2711 orelse: list[NodeNG] 

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

2713 

2714 type_annotation: NodeNG | None 

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

2716 

2717 def postinit( 

2718 self, 

2719 target: NodeNG, 

2720 iter: NodeNG, # pylint: disable = redefined-builtin 

2721 body: list[NodeNG], 

2722 orelse: list[NodeNG], 

2723 type_annotation: NodeNG | None, 

2724 ) -> None: 

2725 self.target = target 

2726 self.iter = iter 

2727 self.body = body 

2728 self.orelse = orelse 

2729 self.type_annotation = type_annotation 

2730 

2731 assigned_stmts = protocols.for_assigned_stmts 

2732 """Returns the assigned statement (non inferred) according to the assignment type. 

2733 See astroid/protocols.py for actual implementation. 

2734 """ 

2735 

2736 @cached_property 

2737 def blockstart_tolineno(self): 

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

2739 

2740 :type: int 

2741 """ 

2742 return self.iter.tolineno 

2743 

2744 def get_children(self): 

2745 yield self.target 

2746 yield self.iter 

2747 

2748 yield from self.body 

2749 yield from self.orelse 

2750 

2751 

2752class AsyncFor(For): 

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

2754 

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

2756 the ``async`` keyword. 

2757 

2758 >>> import astroid 

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

2760 ... async def func(things): 

2761 ... async for thing in things: 

2762 ... print(thing) 

2763 ... ''') 

2764 >>> node 

2765 <AsyncFunctionDef.func l.2 at 0x...> 

2766 >>> node.body[0] 

2767 <AsyncFor l.3 at 0x...> 

2768 """ 

2769 

2770 

2771class Await(NodeNG): 

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

2773 

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

2775 

2776 >>> import astroid 

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

2778 ... async def func(things): 

2779 ... await other_func() 

2780 ... ''') 

2781 >>> node 

2782 <AsyncFunctionDef.func l.2 at 0x...> 

2783 >>> node.body[0] 

2784 <Expr l.3 at 0x...> 

2785 >>> list(node.body[0].get_children())[0] 

2786 <Await l.3 at 0x...> 

2787 """ 

2788 

2789 _astroid_fields = ("value",) 

2790 

2791 value: NodeNG 

2792 """What to wait for.""" 

2793 

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

2795 self.value = value 

2796 

2797 def get_children(self): 

2798 yield self.value 

2799 

2800 

2801class ImportFrom(_base_nodes.ImportNode): 

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

2803 

2804 >>> import astroid 

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

2806 >>> node 

2807 <ImportFrom l.1 at 0x...> 

2808 """ 

2809 

2810 _other_fields = ("modname", "names", "level", "is_lazy") 

2811 

2812 def __init__( 

2813 self, 

2814 fromname: str | None, 

2815 names: list[tuple[str, str | None]], 

2816 level: int | None = 0, 

2817 lineno: int | None = None, 

2818 col_offset: int | None = None, 

2819 parent: NodeNG | None = None, 

2820 *, 

2821 end_lineno: int | None = None, 

2822 end_col_offset: int | None = None, 

2823 is_lazy: int = 0, 

2824 ) -> None: 

2825 """ 

2826 :param fromname: The module that is being imported from. 

2827 

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

2829 

2830 :param level: The level of relative import. 

2831 

2832 :param is_lazy: Whether this is a PEP 810 lazy import (``lazy from ...``). 

2833 

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

2835 

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

2837 source code. 

2838 

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

2840 

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

2842 

2843 :param end_col_offset: The end column this node appears on in the 

2844 source code. Note: This is after the last symbol. 

2845 """ 

2846 self.modname: str | None = fromname # can be None 

2847 """The module that is being imported from. 

2848 

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

2850 """ 

2851 

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

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

2854 

2855 Each entry is a :class:`tuple` of the name being imported, 

2856 and the alias that the name is assigned to (if any). 

2857 """ 

2858 

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

2860 """The level of relative import. 

2861 

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

2863 This is ``None`` for absolute imports. 

2864 """ 

2865 

2866 self.is_lazy: int = is_lazy 

2867 """Whether this is a PEP 810 lazy import (``lazy from ... import ...``). 

2868 

2869 Always ``0`` before Python 3.15. 

2870 """ 

2871 

2872 super().__init__( 

2873 lineno=lineno, 

2874 col_offset=col_offset, 

2875 end_lineno=end_lineno, 

2876 end_col_offset=end_col_offset, 

2877 parent=parent, 

2878 ) 

2879 

2880 @decorators.raise_if_nothing_inferred 

2881 @decorators.path_wrapper 

2882 def _infer( 

2883 self, context: InferenceContext | None = None 

2884 ) -> Generator[InferenceResult]: 

2885 """Infer a ImportFrom node: return the imported module/object.""" 

2886 context = context or InferenceContext() 

2887 name = context.lookupname 

2888 if name is None: 

2889 raise InferenceError(node=self, context=context) 

2890 try: 

2891 module = self.do_import_module() 

2892 except AstroidBuildingError as exc: 

2893 raise InferenceError(node=self, context=context) from exc 

2894 

2895 try: 

2896 context = copy_context(context) 

2897 context.lookupname = name 

2898 stmts = module.getattr(name, ignore_locals=module is self.root()) 

2899 return _infer_stmts(stmts, context) 

2900 except AttributeInferenceError as error: 

2901 raise InferenceError( 

2902 str(error), target=self, attribute=name, context=context 

2903 ) from error 

2904 

2905 

2906class Attribute(NodeNG): 

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

2908 

2909 expr: NodeNG 

2910 

2911 _astroid_fields = ("expr",) 

2912 _other_fields = ("attrname",) 

2913 

2914 def __init__( 

2915 self, 

2916 attrname: str, 

2917 lineno: int, 

2918 col_offset: int, 

2919 parent: NodeNG, 

2920 *, 

2921 end_lineno: int | None, 

2922 end_col_offset: int | None, 

2923 ) -> None: 

2924 self.attrname = attrname 

2925 """The name of the attribute.""" 

2926 

2927 super().__init__( 

2928 lineno=lineno, 

2929 col_offset=col_offset, 

2930 end_lineno=end_lineno, 

2931 end_col_offset=end_col_offset, 

2932 parent=parent, 

2933 ) 

2934 

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

2936 self.expr = expr 

2937 

2938 def get_children(self): 

2939 yield self.expr 

2940 

2941 @decorators.raise_if_nothing_inferred 

2942 @decorators.path_wrapper 

2943 def _infer( 

2944 self, context: InferenceContext | None = None 

2945 ) -> Generator[InferenceResult, None, InferenceErrorInfo]: 

2946 return _infer_attribute(self, context) 

2947 

2948 

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

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

2951 

2952 >>> import astroid 

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

2954 >>> node 

2955 <Global l.1 at 0x...> 

2956 """ 

2957 

2958 _other_fields = ("names",) 

2959 

2960 def __init__( 

2961 self, 

2962 names: list[str], 

2963 lineno: int | None = None, 

2964 col_offset: int | None = None, 

2965 parent: NodeNG | None = None, 

2966 *, 

2967 end_lineno: int | None = None, 

2968 end_col_offset: int | None = None, 

2969 ) -> None: 

2970 """ 

2971 :param names: The names being declared as global. 

2972 

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

2974 

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

2976 source code. 

2977 

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

2979 

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

2981 

2982 :param end_col_offset: The end column this node appears on in the 

2983 source code. Note: This is after the last symbol. 

2984 """ 

2985 self.names: list[str] = names 

2986 """The names being declared as global.""" 

2987 

2988 super().__init__( 

2989 lineno=lineno, 

2990 col_offset=col_offset, 

2991 end_lineno=end_lineno, 

2992 end_col_offset=end_col_offset, 

2993 parent=parent, 

2994 ) 

2995 

2996 def _infer_name(self, frame, name): 

2997 return name 

2998 

2999 @decorators.raise_if_nothing_inferred 

3000 @decorators.path_wrapper 

3001 def _infer( 

3002 self, context: InferenceContext | None = None 

3003 ) -> Generator[InferenceResult]: 

3004 if context is None or context.lookupname is None: 

3005 raise InferenceError(node=self, context=context) 

3006 try: 

3007 # pylint: disable-next=no-member 

3008 return _infer_stmts(self.root().getattr(context.lookupname), context) 

3009 except AttributeInferenceError as error: 

3010 raise InferenceError( 

3011 str(error), target=self, attribute=context.lookupname, context=context 

3012 ) from error 

3013 

3014 

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

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

3017 

3018 >>> import astroid 

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

3020 >>> node 

3021 <If l.1 at 0x...> 

3022 """ 

3023 

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

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

3026 

3027 test: NodeNG 

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

3029 

3030 body: list[NodeNG] 

3031 """The contents of the block.""" 

3032 

3033 orelse: list[NodeNG] 

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

3035 

3036 def postinit(self, test: NodeNG, body: list[NodeNG], orelse: list[NodeNG]) -> None: 

3037 self.test = test 

3038 self.body = body 

3039 self.orelse = orelse 

3040 

3041 @cached_property 

3042 def blockstart_tolineno(self): 

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

3044 

3045 :type: int 

3046 """ 

3047 return self.test.tolineno 

3048 

3049 def get_children(self): 

3050 yield self.test 

3051 

3052 yield from self.body 

3053 yield from self.orelse 

3054 

3055 def has_elif_block(self) -> bool: 

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

3057 

3058 def _get_yield_nodes_skip_functions(self): 

3059 """An If node can contain a Yield node in the test""" 

3060 yield from self.test._get_yield_nodes_skip_functions() 

3061 yield from super()._get_yield_nodes_skip_functions() 

3062 

3063 def _get_yield_nodes_skip_lambdas(self): 

3064 """An If node can contain a Yield node in the test""" 

3065 yield from self.test._get_yield_nodes_skip_lambdas() 

3066 yield from super()._get_yield_nodes_skip_lambdas() 

3067 

3068 

3069class IfExp(NodeNG): 

3070 """Class representing an :class:`ast.IfExp` node. 

3071 >>> import astroid 

3072 >>> node = astroid.extract_node('value if condition else other') 

3073 >>> node 

3074 <IfExp l.1 at 0x...> 

3075 """ 

3076 

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

3078 

3079 test: NodeNG 

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

3081 

3082 body: NodeNG 

3083 """The contents of the block.""" 

3084 

3085 orelse: NodeNG 

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

3087 

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

3089 self.test = test 

3090 self.body = body 

3091 self.orelse = orelse 

3092 

3093 def get_children(self): 

3094 yield self.test 

3095 yield self.body 

3096 yield self.orelse 

3097 

3098 def op_left_associative(self) -> Literal[False]: 

3099 # `1 if True else 2 if False else 3` is parsed as 

3100 # `1 if True else (2 if False else 3)` 

3101 return False 

3102 

3103 @decorators.raise_if_nothing_inferred 

3104 def _infer( 

3105 self, context: InferenceContext | None = None 

3106 ) -> Generator[InferenceResult]: 

3107 """Support IfExp inference. 

3108 

3109 If we can't infer the truthiness of the condition, we default 

3110 to inferring both branches. Otherwise, we infer either branch 

3111 depending on the condition. 

3112 """ 

3113 

3114 # We use two separate contexts for evaluating lhs and rhs because 

3115 # evaluating lhs may leave some undesired entries in context.path 

3116 # which may not let us infer right value of rhs. 

3117 context = context or InferenceContext() 

3118 lhs_context = copy_context(context) 

3119 rhs_context = copy_context(context) 

3120 

3121 # Infer bool condition. Stop inferring if in doubt and fallback to 

3122 # evaluating both branches. 

3123 condition: bool | None = None 

3124 try: 

3125 for test in self.test.infer(context=context.clone()): 

3126 if isinstance(test, util.UninferableBase): 

3127 condition = None 

3128 break 

3129 test_bool_value = test.bool_value() 

3130 if isinstance(test_bool_value, util.UninferableBase): 

3131 condition = None 

3132 break 

3133 if condition is None: 

3134 condition = test_bool_value 

3135 elif test_bool_value != condition: 

3136 condition = None 

3137 break 

3138 except InferenceError: 

3139 condition = None 

3140 

3141 if condition is True or condition is None: 

3142 yield from self.body.infer(context=lhs_context) 

3143 if condition is False or condition is None: 

3144 yield from self.orelse.infer(context=rhs_context) 

3145 

3146 

3147class Import(_base_nodes.ImportNode): 

3148 """Class representing an :class:`ast.Import` node. 

3149 >>> import astroid 

3150 >>> node = astroid.extract_node('import astroid') 

3151 >>> node 

3152 <Import l.1 at 0x...> 

3153 """ 

3154 

3155 _other_fields = ("names", "is_lazy") 

3156 

3157 def __init__( 

3158 self, 

3159 names: list[tuple[str, str | None]], 

3160 lineno: int | None = None, 

3161 col_offset: int | None = None, 

3162 parent: NodeNG | None = None, 

3163 *, 

3164 end_lineno: int | None = None, 

3165 end_col_offset: int | None = None, 

3166 is_lazy: int = 0, 

3167 ) -> None: 

3168 """ 

3169 :param names: The names being imported. 

3170 

3171 :param is_lazy: Whether this is a PEP 810 lazy import (``lazy import ...``). 

3172 

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

3174 

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

3176 source code. 

3177 

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

3179 

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

3181 

3182 :param end_col_offset: The end column this node appears on in the 

3183 source code. Note: This is after the last symbol. 

3184 """ 

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

3186 """The names being imported. 

3187 

3188 Each entry is a :class:`tuple` of the name being imported, 

3189 and the alias that the name is assigned to (if any). 

3190 """ 

3191 

3192 self.is_lazy: int = is_lazy 

3193 """Whether this is a PEP 810 lazy import (``lazy import ...``). 

3194 

3195 Always ``0`` before Python 3.15. 

3196 """ 

3197 

3198 super().__init__( 

3199 lineno=lineno, 

3200 col_offset=col_offset, 

3201 end_lineno=end_lineno, 

3202 end_col_offset=end_col_offset, 

3203 parent=parent, 

3204 ) 

3205 

3206 @decorators.raise_if_nothing_inferred 

3207 @decorators.path_wrapper 

3208 def _infer( 

3209 self, 

3210 context: InferenceContext | None = None, 

3211 ) -> Generator[nodes.Module]: 

3212 """Infer an Import node: return the imported module/object.""" 

3213 context = context or InferenceContext() 

3214 name = context.lookupname 

3215 if name is None: 

3216 raise InferenceError(node=self, context=context) 

3217 

3218 try: 

3219 yield self.do_import_module(name) 

3220 except AstroidBuildingError as exc: 

3221 raise InferenceError(node=self, context=context) from exc 

3222 

3223 

3224class Keyword(NodeNG): 

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

3226 

3227 >>> import astroid 

3228 >>> node = astroid.extract_node('function(a_kwarg=True)') 

3229 >>> node 

3230 <Call l.1 at 0x...> 

3231 >>> node.keywords 

3232 [<Keyword l.1 at 0x...>] 

3233 """ 

3234 

3235 _astroid_fields = ("value",) 

3236 _other_fields = ("arg",) 

3237 

3238 value: NodeNG 

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

3240 

3241 def __init__( 

3242 self, 

3243 arg: str | None, 

3244 lineno: int | None, 

3245 col_offset: int | None, 

3246 parent: NodeNG, 

3247 *, 

3248 end_lineno: int | None, 

3249 end_col_offset: int | None, 

3250 ) -> None: 

3251 self.arg = arg 

3252 """The argument being assigned to.""" 

3253 

3254 super().__init__( 

3255 lineno=lineno, 

3256 col_offset=col_offset, 

3257 end_lineno=end_lineno, 

3258 end_col_offset=end_col_offset, 

3259 parent=parent, 

3260 ) 

3261 

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

3263 self.value = value 

3264 

3265 def get_children(self): 

3266 yield self.value 

3267 

3268 

3269class List(BaseContainer): 

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

3271 

3272 >>> import astroid 

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

3274 >>> node 

3275 <List.list l.1 at 0x...> 

3276 """ 

3277 

3278 _other_fields = ("ctx",) 

3279 

3280 def __init__( 

3281 self, 

3282 ctx: Context | None = None, 

3283 lineno: int | None = None, 

3284 col_offset: int | None = None, 

3285 parent: NodeNG | None = None, 

3286 *, 

3287 end_lineno: int | None = None, 

3288 end_col_offset: int | None = None, 

3289 ) -> None: 

3290 """ 

3291 :param ctx: Whether the list is assigned to or loaded from. 

3292 

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

3294 

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

3296 source code. 

3297 

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

3299 

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

3301 

3302 :param end_col_offset: The end column this node appears on in the 

3303 source code. Note: This is after the last symbol. 

3304 """ 

3305 self.ctx: Context | None = ctx 

3306 """Whether the list is assigned to or loaded from.""" 

3307 

3308 super().__init__( 

3309 lineno=lineno, 

3310 col_offset=col_offset, 

3311 end_lineno=end_lineno, 

3312 end_col_offset=end_col_offset, 

3313 parent=parent, 

3314 ) 

3315 

3316 assigned_stmts = protocols.sequence_assigned_stmts 

3317 """Returns the assigned statement (non inferred) according to the assignment type. 

3318 See astroid/protocols.py for actual implementation. 

3319 """ 

3320 

3321 infer_unary_op = protocols.list_infer_unary_op 

3322 infer_binary_op = protocols.tl_infer_binary_op 

3323 

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

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

3326 

3327 :returns: The name of the type. 

3328 """ 

3329 return "builtins.list" 

3330 

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

3332 """Get an item from this node. 

3333 

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

3335 :type index: Const or Slice 

3336 """ 

3337 return _container_getitem(self, self.elts, index, context=context) 

3338 

3339 

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

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

3342 

3343 >>> import astroid 

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

3345 ... def function(): 

3346 ... nonlocal var 

3347 ... ''') 

3348 >>> node 

3349 <FunctionDef.function l.2 at 0x...> 

3350 >>> node.body[0] 

3351 <Nonlocal l.3 at 0x...> 

3352 """ 

3353 

3354 _other_fields = ("names",) 

3355 

3356 def __init__( 

3357 self, 

3358 names: list[str], 

3359 lineno: int | None = None, 

3360 col_offset: int | None = None, 

3361 parent: NodeNG | None = None, 

3362 *, 

3363 end_lineno: int | None = None, 

3364 end_col_offset: int | None = None, 

3365 ) -> None: 

3366 """ 

3367 :param names: The names being declared as not local. 

3368 

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

3370 

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

3372 source code. 

3373 

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

3375 

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

3377 

3378 :param end_col_offset: The end column this node appears on in the 

3379 source code. Note: This is after the last symbol. 

3380 """ 

3381 self.names: list[str] = names 

3382 """The names being declared as not local.""" 

3383 

3384 super().__init__( 

3385 lineno=lineno, 

3386 col_offset=col_offset, 

3387 end_lineno=end_lineno, 

3388 end_col_offset=end_col_offset, 

3389 parent=parent, 

3390 ) 

3391 

3392 def _infer_name(self, frame, name): 

3393 return name 

3394 

3395 

3396class ParamSpec(_base_nodes.AssignTypeNode): 

3397 """Class representing a :class:`ast.ParamSpec` node. 

3398 

3399 >>> import astroid 

3400 >>> node = astroid.extract_node('type Alias[**P] = Callable[P, int]') 

3401 >>> node.type_params[0] 

3402 <ParamSpec l.1 at 0x...> 

3403 """ 

3404 

3405 _astroid_fields = ("name", "default_value") 

3406 name: AssignName 

3407 default_value: NodeNG | None 

3408 

3409 def __init__( 

3410 self, 

3411 lineno: int, 

3412 col_offset: int, 

3413 parent: NodeNG, 

3414 *, 

3415 end_lineno: int, 

3416 end_col_offset: int, 

3417 ) -> None: 

3418 super().__init__( 

3419 lineno=lineno, 

3420 col_offset=col_offset, 

3421 end_lineno=end_lineno, 

3422 end_col_offset=end_col_offset, 

3423 parent=parent, 

3424 ) 

3425 

3426 def postinit(self, *, name: AssignName, default_value: NodeNG | None) -> None: 

3427 self.name = name 

3428 self.default_value = default_value 

3429 

3430 def pytype(self) -> Literal["typing.ParamSpec"]: 

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

3432 

3433 :returns: The name of the type. 

3434 """ 

3435 return "typing.ParamSpec" 

3436 

3437 def qname(self) -> Literal["typing.ParamSpec"]: 

3438 """Get the qualified name of the type that this node represents. 

3439 

3440 :returns: The qualified name of the type. 

3441 """ 

3442 return "typing.ParamSpec" 

3443 

3444 def _infer(self, context: InferenceContext | None = None) -> Iterator[ParamSpec]: 

3445 yield self 

3446 

3447 assigned_stmts = protocols.generic_type_assigned_stmts 

3448 """Returns the assigned statement (non inferred) according to the assignment type. 

3449 See astroid/protocols.py for actual implementation. 

3450 """ 

3451 

3452 

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

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

3455 

3456 >>> import astroid 

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

3458 >>> node 

3459 <Pass l.1 at 0x...> 

3460 """ 

3461 

3462 

3463class Raise(_base_nodes.Statement): 

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

3465 

3466 >>> import astroid 

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

3468 >>> node 

3469 <Raise l.1 at 0x...> 

3470 """ 

3471 

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

3473 

3474 exc: NodeNG | None 

3475 """What is being raised.""" 

3476 

3477 cause: NodeNG | None 

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

3479 

3480 def postinit( 

3481 self, 

3482 exc: NodeNG | None, 

3483 cause: NodeNG | None, 

3484 ) -> None: 

3485 self.exc = exc 

3486 self.cause = cause 

3487 

3488 def raises_not_implemented(self) -> bool: 

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

3490 

3491 :returns: Whether this node raises a :class:`NotImplementedError`. 

3492 """ 

3493 if not self.exc: 

3494 return False 

3495 return any( 

3496 name.name == "NotImplementedError" for name in self.exc._get_name_nodes() 

3497 ) 

3498 

3499 def get_children(self): 

3500 if self.exc is not None: 

3501 yield self.exc 

3502 

3503 if self.cause is not None: 

3504 yield self.cause 

3505 

3506 

3507class Return(_base_nodes.Statement): 

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

3509 

3510 >>> import astroid 

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

3512 >>> node 

3513 <Return l.1 at 0x...> 

3514 """ 

3515 

3516 _astroid_fields = ("value",) 

3517 

3518 value: NodeNG | None 

3519 """The value being returned.""" 

3520 

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

3522 self.value = value 

3523 

3524 def get_children(self): 

3525 if self.value is not None: 

3526 yield self.value 

3527 

3528 def is_tuple_return(self) -> bool: 

3529 return isinstance(self.value, Tuple) 

3530 

3531 def _get_return_nodes_skip_functions(self): 

3532 yield self 

3533 

3534 

3535class Set(BaseContainer): 

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

3537 

3538 >>> import astroid 

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

3540 >>> node 

3541 <Set.set l.1 at 0x...> 

3542 """ 

3543 

3544 infer_unary_op = protocols.set_infer_unary_op 

3545 

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

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

3548 

3549 :returns: The name of the type. 

3550 """ 

3551 return "builtins.set" 

3552 

3553 

3554class Slice(NodeNG): 

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

3556 

3557 >>> import astroid 

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

3559 >>> node 

3560 <Subscript l.1 at 0x...> 

3561 >>> node.slice 

3562 <Slice l.1 at 0x...> 

3563 """ 

3564 

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

3566 

3567 lower: NodeNG | None 

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

3569 

3570 upper: NodeNG | None 

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

3572 

3573 step: NodeNG | None 

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

3575 

3576 def postinit( 

3577 self, 

3578 lower: NodeNG | None, 

3579 upper: NodeNG | None, 

3580 step: NodeNG | None, 

3581 ) -> None: 

3582 self.lower = lower 

3583 self.upper = upper 

3584 self.step = step 

3585 

3586 def _wrap_attribute(self, attr): 

3587 """Wrap the empty attributes of the Slice in a Const node.""" 

3588 if not attr: 

3589 const = const_factory(attr) 

3590 const.parent = self 

3591 return const 

3592 return attr 

3593 

3594 @cached_property 

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

3596 builtins = AstroidManager().builtins_module 

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

3598 

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

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

3601 

3602 :returns: The name of the type. 

3603 """ 

3604 return "builtins.slice" 

3605 

3606 def qname(self) -> Literal["builtins.slice"]: 

3607 """Get the qualified name of the type that this node represents. 

3608 

3609 :returns: The qualified name of the type. 

3610 """ 

3611 return "builtins.slice" 

3612 

3613 def display_type(self) -> Literal["Slice"]: 

3614 """A human readable type of this node. 

3615 

3616 :returns: The type of this node. 

3617 """ 

3618 return "Slice" 

3619 

3620 def igetattr( 

3621 self, attrname: str, context: InferenceContext | None = None 

3622 ) -> Iterator[SuccessfulInferenceResult]: 

3623 """Infer the possible values of the given attribute on the slice. 

3624 

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

3626 

3627 :returns: The inferred possible values. 

3628 """ 

3629 if attrname == "start": 

3630 yield self._wrap_attribute(self.lower) 

3631 elif attrname == "stop": 

3632 yield self._wrap_attribute(self.upper) 

3633 elif attrname == "step": 

3634 yield self._wrap_attribute(self.step) 

3635 else: 

3636 yield from self.getattr(attrname, context=context) 

3637 

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

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

3640 

3641 def get_children(self): 

3642 if self.lower is not None: 

3643 yield self.lower 

3644 

3645 if self.upper is not None: 

3646 yield self.upper 

3647 

3648 if self.step is not None: 

3649 yield self.step 

3650 

3651 def _infer(self, context: InferenceContext | None = None) -> Iterator[Slice]: 

3652 yield self 

3653 

3654 

3655class Starred(_base_nodes.ParentAssignNode): 

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

3657 

3658 >>> import astroid 

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

3660 >>> node 

3661 <Starred l.1 at 0x...> 

3662 """ 

3663 

3664 _astroid_fields = ("value",) 

3665 _other_fields = ("ctx",) 

3666 

3667 value: NodeNG 

3668 """What is being unpacked.""" 

3669 

3670 def __init__( 

3671 self, 

3672 ctx: Context, 

3673 lineno: int, 

3674 col_offset: int, 

3675 parent: NodeNG, 

3676 *, 

3677 end_lineno: int | None, 

3678 end_col_offset: int | None, 

3679 ) -> None: 

3680 self.ctx = ctx 

3681 """Whether the starred item is assigned to or loaded from.""" 

3682 

3683 super().__init__( 

3684 lineno=lineno, 

3685 col_offset=col_offset, 

3686 end_lineno=end_lineno, 

3687 end_col_offset=end_col_offset, 

3688 parent=parent, 

3689 ) 

3690 

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

3692 self.value = value 

3693 

3694 assigned_stmts = protocols.starred_assigned_stmts 

3695 """Returns the assigned statement (non inferred) according to the assignment type. 

3696 See astroid/protocols.py for actual implementation. 

3697 """ 

3698 

3699 def get_children(self): 

3700 yield self.value 

3701 

3702 

3703class Subscript(NodeNG): 

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

3705 

3706 >>> import astroid 

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

3708 >>> node 

3709 <Subscript l.1 at 0x...> 

3710 """ 

3711 

3712 _SUBSCRIPT_SENTINEL = object() 

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

3714 _other_fields = ("ctx",) 

3715 

3716 value: NodeNG 

3717 """What is being indexed.""" 

3718 

3719 slice: NodeNG 

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

3721 

3722 def __init__( 

3723 self, 

3724 ctx: Context, 

3725 lineno: int, 

3726 col_offset: int, 

3727 parent: NodeNG, 

3728 *, 

3729 end_lineno: int | None, 

3730 end_col_offset: int | None, 

3731 ) -> None: 

3732 self.ctx = ctx 

3733 """Whether the subscripted item is assigned to or loaded from.""" 

3734 

3735 super().__init__( 

3736 lineno=lineno, 

3737 col_offset=col_offset, 

3738 end_lineno=end_lineno, 

3739 end_col_offset=end_col_offset, 

3740 parent=parent, 

3741 ) 

3742 

3743 # pylint: disable=redefined-builtin; had to use the same name as builtin ast module. 

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

3745 self.value = value 

3746 self.slice = slice 

3747 

3748 def get_children(self): 

3749 yield self.value 

3750 yield self.slice 

3751 

3752 def _infer_subscript( 

3753 self, context: InferenceContext | None = None 

3754 ) -> Generator[InferenceResult, None, InferenceErrorInfo | None]: 

3755 """Inference for subscripts. 

3756 

3757 We're understanding if the index is a Const 

3758 or a slice, passing the result of inference 

3759 to the value's `getitem` method, which should 

3760 handle each supported index type accordingly. 

3761 """ 

3762 from astroid import helpers # pylint: disable=import-outside-toplevel 

3763 

3764 found_one = False 

3765 for value in self.value.infer(context): 

3766 if isinstance(value, util.UninferableBase): 

3767 yield util.Uninferable 

3768 return None 

3769 for index in self.slice.infer(context): 

3770 if isinstance(index, util.UninferableBase): 

3771 yield util.Uninferable 

3772 return None 

3773 

3774 # Try to deduce the index value. 

3775 index_value = self._SUBSCRIPT_SENTINEL 

3776 if value.__class__ == Instance: 

3777 index_value = index 

3778 elif index.__class__ == Instance: 

3779 instance_as_index = helpers.class_instance_as_index(index) 

3780 if instance_as_index: 

3781 index_value = instance_as_index 

3782 else: 

3783 index_value = index 

3784 

3785 if index_value is self._SUBSCRIPT_SENTINEL: 

3786 raise InferenceError(node=self, context=context) 

3787 

3788 try: 

3789 assigned = value.getitem(index_value, context) 

3790 except ( 

3791 AstroidTypeError, 

3792 AstroidIndexError, 

3793 AstroidValueError, 

3794 AttributeInferenceError, 

3795 AttributeError, 

3796 ) as exc: 

3797 raise InferenceError(node=self, context=context) from exc 

3798 

3799 # Prevent inferring if the inferred subscript 

3800 # is the same as the original subscripted object. 

3801 if self is assigned or isinstance(assigned, util.UninferableBase): 

3802 yield util.Uninferable 

3803 return None 

3804 yield from assigned.infer(context) 

3805 found_one = True 

3806 

3807 if found_one: 

3808 return InferenceErrorInfo(node=self, context=context) 

3809 return None 

3810 

3811 @decorators.raise_if_nothing_inferred 

3812 @decorators.path_wrapper 

3813 def _infer(self, context: InferenceContext | None = None): 

3814 return self._infer_subscript(context) 

3815 

3816 @decorators.raise_if_nothing_inferred 

3817 def infer_lhs(self, context: InferenceContext | None = None): 

3818 return self._infer_subscript(context) 

3819 

3820 

3821class Try(_base_nodes.MultiLineWithElseBlockNode, _base_nodes.Statement): 

3822 """Class representing a :class:`ast.Try` node. 

3823 

3824 >>> import astroid 

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

3826 ... try: 

3827 ... do_something() 

3828 ... except Exception as error: 

3829 ... print("Error!") 

3830 ... finally: 

3831 ... print("Cleanup!") 

3832 ... ''') 

3833 >>> node 

3834 <Try l.2 at 0x...> 

3835 """ 

3836 

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

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

3839 

3840 def __init__( 

3841 self, 

3842 *, 

3843 lineno: int, 

3844 col_offset: int, 

3845 end_lineno: int, 

3846 end_col_offset: int, 

3847 parent: NodeNG, 

3848 ) -> None: 

3849 """ 

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

3851 

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

3853 source code. 

3854 

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

3856 

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

3858 

3859 :param end_col_offset: The end column this node appears on in the 

3860 source code. Note: This is after the last symbol. 

3861 """ 

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

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

3864 

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

3866 """The exception handlers.""" 

3867 

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

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

3870 

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

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

3873 

3874 super().__init__( 

3875 lineno=lineno, 

3876 col_offset=col_offset, 

3877 end_lineno=end_lineno, 

3878 end_col_offset=end_col_offset, 

3879 parent=parent, 

3880 ) 

3881 

3882 def postinit( 

3883 self, 

3884 *, 

3885 body: list[NodeNG], 

3886 handlers: list[ExceptHandler], 

3887 orelse: list[NodeNG], 

3888 finalbody: list[NodeNG], 

3889 ) -> None: 

3890 """Do some setup after initialisation. 

3891 

3892 :param body: The contents of the block to catch exceptions from. 

3893 

3894 :param handlers: The exception handlers. 

3895 

3896 :param orelse: The contents of the ``else`` block. 

3897 

3898 :param finalbody: The contents of the ``finally`` block. 

3899 """ 

3900 self.body = body 

3901 self.handlers = handlers 

3902 self.orelse = orelse 

3903 self.finalbody = finalbody 

3904 

3905 def _infer_name(self, frame, name): 

3906 return name 

3907 

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

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

3910 for exhandler in self.handlers: 

3911 if exhandler.type and lineno == exhandler.type.fromlineno: 

3912 return lineno, exhandler.tolineno 

3913 if exhandler.body[0].fromlineno <= lineno <= exhandler.body[-1].tolineno: 

3914 return lineno, exhandler.body[-1].tolineno 

3915 if self.finalbody: 

3916 if self.finalbody[0].fromlineno - 1 == lineno: 

3917 return lineno, self.finalbody[0].tolineno 

3918 if self.finalbody[0].fromlineno <= lineno <= self.finalbody[-1].tolineno: 

3919 return lineno, self.finalbody[-1].tolineno 

3920 

3921 # If not within any of the ExceptHandlers or `finally` body, fall back to regular 

3922 # handling of block_range for nodes with a potential `else` statement. 

3923 return super().block_range(lineno) 

3924 

3925 def get_children(self): 

3926 yield from self.body 

3927 yield from self.handlers 

3928 yield from self.orelse 

3929 yield from self.finalbody 

3930 

3931 

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

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

3934 

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

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

3937 

3938 def __init__( 

3939 self, 

3940 *, 

3941 lineno: int | None = None, 

3942 col_offset: int | None = None, 

3943 end_lineno: int | None = None, 

3944 end_col_offset: int | None = None, 

3945 parent: NodeNG | None = None, 

3946 ) -> None: 

3947 """ 

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

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

3950 source code. 

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

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

3953 :param end_col_offset: The end column this node appears on in the 

3954 source code. Note: This is after the last symbol. 

3955 """ 

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

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

3958 

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

3960 """The exception handlers.""" 

3961 

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

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

3964 

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

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

3967 

3968 super().__init__( 

3969 lineno=lineno, 

3970 col_offset=col_offset, 

3971 end_lineno=end_lineno, 

3972 end_col_offset=end_col_offset, 

3973 parent=parent, 

3974 ) 

3975 

3976 def postinit( 

3977 self, 

3978 *, 

3979 body: list[NodeNG] | None = None, 

3980 handlers: list[ExceptHandler] | None = None, 

3981 orelse: list[NodeNG] | None = None, 

3982 finalbody: list[NodeNG] | None = None, 

3983 ) -> None: 

3984 """Do some setup after initialisation. 

3985 :param body: The contents of the block to catch exceptions from. 

3986 :param handlers: The exception handlers. 

3987 :param orelse: The contents of the ``else`` block. 

3988 :param finalbody: The contents of the ``finally`` block. 

3989 """ 

3990 if body: 

3991 self.body = body 

3992 if handlers: 

3993 self.handlers = handlers 

3994 if orelse: 

3995 self.orelse = orelse 

3996 if finalbody: 

3997 self.finalbody = finalbody 

3998 

3999 def _infer_name(self, frame, name): 

4000 return name 

4001 

4002 def get_children(self): 

4003 yield from self.body 

4004 yield from self.handlers 

4005 yield from self.orelse 

4006 yield from self.finalbody 

4007 

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

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

4010 for exhandler in self.handlers: 

4011 if exhandler.type and lineno == exhandler.type.fromlineno: 

4012 return lineno, exhandler.tolineno 

4013 if exhandler.body[0].fromlineno <= lineno <= exhandler.body[-1].tolineno: 

4014 return lineno, exhandler.body[-1].tolineno 

4015 if self.finalbody: 

4016 if self.finalbody[0].fromlineno - 1 == lineno: 

4017 return lineno, self.finalbody[0].tolineno 

4018 if self.finalbody[0].fromlineno <= lineno <= self.finalbody[-1].tolineno: 

4019 return lineno, self.finalbody[-1].tolineno 

4020 

4021 # If not within any of the ExceptHandlers or `finally` body, fall back to regular 

4022 # handling of block_range for nodes with a potential `else` statement. 

4023 return super().block_range(lineno) 

4024 

4025 

4026class Tuple(BaseContainer): 

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

4028 

4029 >>> import astroid 

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

4031 >>> node 

4032 <Tuple.tuple l.1 at 0x...> 

4033 """ 

4034 

4035 _other_fields = ("ctx",) 

4036 

4037 def __init__( 

4038 self, 

4039 ctx: Context | None = None, 

4040 lineno: int | None = None, 

4041 col_offset: int | None = None, 

4042 parent: NodeNG | None = None, 

4043 *, 

4044 end_lineno: int | None = None, 

4045 end_col_offset: int | None = None, 

4046 ) -> None: 

4047 """ 

4048 :param ctx: Whether the tuple is assigned to or loaded from. 

4049 

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

4051 

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

4053 source code. 

4054 

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

4056 

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

4058 

4059 :param end_col_offset: The end column this node appears on in the 

4060 source code. Note: This is after the last symbol. 

4061 """ 

4062 self.ctx: Context | None = ctx 

4063 """Whether the tuple is assigned to or loaded from.""" 

4064 

4065 super().__init__( 

4066 lineno=lineno, 

4067 col_offset=col_offset, 

4068 end_lineno=end_lineno, 

4069 end_col_offset=end_col_offset, 

4070 parent=parent, 

4071 ) 

4072 

4073 assigned_stmts = protocols.sequence_assigned_stmts 

4074 """Returns the assigned statement (non inferred) according to the assignment type. 

4075 See astroid/protocols.py for actual implementation. 

4076 """ 

4077 

4078 infer_unary_op = protocols.tuple_infer_unary_op 

4079 infer_binary_op = protocols.tl_infer_binary_op 

4080 

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

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

4083 

4084 :returns: The name of the type. 

4085 """ 

4086 return "builtins.tuple" 

4087 

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

4089 """Get an item from this node. 

4090 

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

4092 :type index: Const or Slice 

4093 """ 

4094 return _container_getitem(self, self.elts, index, context=context) 

4095 

4096 

4097class TypeAlias(_base_nodes.AssignTypeNode, _base_nodes.Statement): 

4098 """Class representing a :class:`ast.TypeAlias` node. 

4099 

4100 >>> import astroid 

4101 >>> node = astroid.extract_node('type Point = tuple[float, float]') 

4102 >>> node 

4103 <TypeAlias l.1 at 0x...> 

4104 """ 

4105 

4106 _astroid_fields = ("name", "type_params", "value") 

4107 

4108 name: AssignName 

4109 type_params: list[TypeVar | ParamSpec | TypeVarTuple] 

4110 value: NodeNG 

4111 

4112 def __init__( 

4113 self, 

4114 lineno: int, 

4115 col_offset: int, 

4116 parent: NodeNG, 

4117 *, 

4118 end_lineno: int, 

4119 end_col_offset: int, 

4120 ) -> None: 

4121 super().__init__( 

4122 lineno=lineno, 

4123 col_offset=col_offset, 

4124 end_lineno=end_lineno, 

4125 end_col_offset=end_col_offset, 

4126 parent=parent, 

4127 ) 

4128 

4129 def postinit( 

4130 self, 

4131 *, 

4132 name: AssignName, 

4133 type_params: list[TypeVar | ParamSpec | TypeVarTuple], 

4134 value: NodeNG, 

4135 ) -> None: 

4136 self.name = name 

4137 self.type_params = type_params 

4138 self.value = value 

4139 

4140 def pytype(self) -> Literal["typing.TypeAliasType"]: 

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

4142 

4143 :returns: The name of the type. 

4144 """ 

4145 return "typing.TypeAliasType" 

4146 

4147 def qname(self) -> Literal["typing.TypeAliasType"]: 

4148 """Get the qualified name of the type that this node represents. 

4149 

4150 :returns: The qualified name of the type. 

4151 """ 

4152 return "typing.TypeAliasType" 

4153 

4154 def _infer(self, context: InferenceContext | None = None) -> Iterator[TypeAlias]: 

4155 yield self 

4156 

4157 assigned_stmts: ClassVar[ 

4158 Callable[ 

4159 [ 

4160 TypeAlias, 

4161 AssignName, 

4162 InferenceContext | None, 

4163 None, 

4164 ], 

4165 Generator[NodeNG], 

4166 ] 

4167 ] = protocols.assign_assigned_stmts 

4168 

4169 

4170class TypeVar(_base_nodes.AssignTypeNode): 

4171 """Class representing a :class:`ast.TypeVar` node. 

4172 

4173 >>> import astroid 

4174 >>> node = astroid.extract_node('type Point[T] = tuple[float, float]') 

4175 >>> node.type_params[0] 

4176 <TypeVar l.1 at 0x...> 

4177 """ 

4178 

4179 _astroid_fields = ("name", "bound", "default_value") 

4180 name: AssignName 

4181 bound: NodeNG | None 

4182 default_value: NodeNG | None 

4183 

4184 def __init__( 

4185 self, 

4186 lineno: int, 

4187 col_offset: int, 

4188 parent: NodeNG, 

4189 *, 

4190 end_lineno: int, 

4191 end_col_offset: int, 

4192 ) -> None: 

4193 super().__init__( 

4194 lineno=lineno, 

4195 col_offset=col_offset, 

4196 end_lineno=end_lineno, 

4197 end_col_offset=end_col_offset, 

4198 parent=parent, 

4199 ) 

4200 

4201 def postinit( 

4202 self, 

4203 *, 

4204 name: AssignName, 

4205 bound: NodeNG | None, 

4206 default_value: NodeNG | None = None, 

4207 ) -> None: 

4208 self.name = name 

4209 self.bound = bound 

4210 self.default_value = default_value 

4211 

4212 def pytype(self) -> Literal["typing.TypeVar"]: 

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

4214 

4215 :returns: The name of the type. 

4216 """ 

4217 return "typing.TypeVar" 

4218 

4219 def qname(self) -> Literal["typing.TypeVar"]: 

4220 """Get the qualified name of the type that this node represents. 

4221 

4222 :returns: The qualified name of the type. 

4223 """ 

4224 return "typing.TypeVar" 

4225 

4226 def _infer(self, context: InferenceContext | None = None) -> Iterator[TypeVar]: 

4227 yield self 

4228 

4229 assigned_stmts = protocols.generic_type_assigned_stmts 

4230 """Returns the assigned statement (non inferred) according to the assignment type. 

4231 See astroid/protocols.py for actual implementation. 

4232 """ 

4233 

4234 

4235class TypeVarTuple(_base_nodes.AssignTypeNode): 

4236 """Class representing a :class:`ast.TypeVarTuple` node. 

4237 

4238 >>> import astroid 

4239 >>> node = astroid.extract_node('type Alias[*Ts] = tuple[*Ts]') 

4240 >>> node.type_params[0] 

4241 <TypeVarTuple l.1 at 0x...> 

4242 """ 

4243 

4244 _astroid_fields = ("name", "default_value") 

4245 name: AssignName 

4246 default_value: NodeNG | None 

4247 

4248 def __init__( 

4249 self, 

4250 lineno: int, 

4251 col_offset: int, 

4252 parent: NodeNG, 

4253 *, 

4254 end_lineno: int, 

4255 end_col_offset: int, 

4256 ) -> None: 

4257 super().__init__( 

4258 lineno=lineno, 

4259 col_offset=col_offset, 

4260 end_lineno=end_lineno, 

4261 end_col_offset=end_col_offset, 

4262 parent=parent, 

4263 ) 

4264 

4265 def postinit( 

4266 self, *, name: AssignName, default_value: NodeNG | None = None 

4267 ) -> None: 

4268 self.name = name 

4269 self.default_value = default_value 

4270 

4271 def pytype(self) -> Literal["typing.TypeVarTuple"]: 

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

4273 

4274 :returns: The name of the type. 

4275 """ 

4276 return "typing.TypeVarTuple" 

4277 

4278 def qname(self) -> Literal["typing.TypeVarTuple"]: 

4279 """Get the qualified name of the type that this node represents. 

4280 

4281 :returns: The qualified name of the type. 

4282 """ 

4283 return "typing.TypeVarTuple" 

4284 

4285 def _infer(self, context: InferenceContext | None = None) -> Iterator[TypeVarTuple]: 

4286 yield self 

4287 

4288 assigned_stmts = protocols.generic_type_assigned_stmts 

4289 """Returns the assigned statement (non inferred) according to the assignment type. 

4290 See astroid/protocols.py for actual implementation. 

4291 """ 

4292 

4293 

4294UNARY_OP_METHOD = { 

4295 "+": "__pos__", 

4296 "-": "__neg__", 

4297 "~": "__invert__", 

4298 "not": None, # 'not' delegates to __bool__, there is no dedicated method 

4299} 

4300 

4301 

4302class UnaryOp(_base_nodes.OperatorNode): 

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

4304 

4305 >>> import astroid 

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

4307 >>> node 

4308 <UnaryOp l.1 at 0x...> 

4309 """ 

4310 

4311 _astroid_fields = ("operand",) 

4312 _other_fields = ("op",) 

4313 

4314 operand: NodeNG 

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

4316 

4317 def __init__( 

4318 self, 

4319 op: str, 

4320 lineno: int, 

4321 col_offset: int, 

4322 parent: NodeNG, 

4323 *, 

4324 end_lineno: int | None, 

4325 end_col_offset: int | None, 

4326 ) -> None: 

4327 self.op = op 

4328 """The operator.""" 

4329 

4330 super().__init__( 

4331 lineno=lineno, 

4332 col_offset=col_offset, 

4333 end_lineno=end_lineno, 

4334 end_col_offset=end_col_offset, 

4335 parent=parent, 

4336 ) 

4337 

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

4339 self.operand = operand 

4340 

4341 def type_errors( 

4342 self, context: InferenceContext | None = None 

4343 ) -> list[util.BadUnaryOperationMessage]: 

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

4345 

4346 Each TypeError is represented by a :class:`~astroid.util.BadUnaryOperationMessage`, 

4347 which holds the original exception. 

4348 

4349 If any inferred result is uninferable, an empty list is returned. 

4350 """ 

4351 bad = [] 

4352 try: 

4353 for result in self._infer_unaryop(context=context): 

4354 if result is util.Uninferable: 

4355 raise InferenceError 

4356 if isinstance(result, util.BadUnaryOperationMessage): 

4357 bad.append(result) 

4358 except InferenceError: 

4359 return [] 

4360 return bad 

4361 

4362 def get_children(self): 

4363 yield self.operand 

4364 

4365 def op_precedence(self) -> int: 

4366 if self.op == "not": 

4367 return OP_PRECEDENCE[self.op] 

4368 

4369 return super().op_precedence() 

4370 

4371 def _infer_unaryop( 

4372 self, context: InferenceContext | None = None 

4373 ) -> Generator[ 

4374 InferenceResult | util.BadUnaryOperationMessage, None, InferenceErrorInfo 

4375 ]: 

4376 """Infer what an UnaryOp should return when evaluated.""" 

4377 from astroid.nodes import ClassDef # pylint: disable=import-outside-toplevel 

4378 

4379 for operand in self.operand.infer(context): 

4380 try: 

4381 yield operand.infer_unary_op(self.op) 

4382 except TypeError as exc: 

4383 # The operand doesn't support this operation. 

4384 yield util.BadUnaryOperationMessage(operand, self.op, exc) 

4385 except AttributeError as exc: 

4386 meth = UNARY_OP_METHOD[self.op] 

4387 if meth is None: 

4388 # `not node`. Determine node's boolean 

4389 # value and negate its result, unless it is 

4390 # Uninferable, which will be returned as is. 

4391 bool_value = operand.bool_value() 

4392 if not isinstance(bool_value, util.UninferableBase): 

4393 yield const_factory(not bool_value) 

4394 else: 

4395 yield util.Uninferable 

4396 else: 

4397 if not isinstance(operand, (Instance, ClassDef)): 

4398 # The operation was used on something which 

4399 # doesn't support it. 

4400 yield util.BadUnaryOperationMessage(operand, self.op, exc) 

4401 continue 

4402 

4403 try: 

4404 try: 

4405 methods = dunder_lookup.lookup(operand, meth) 

4406 except AttributeInferenceError: 

4407 yield util.BadUnaryOperationMessage(operand, self.op, exc) 

4408 continue 

4409 

4410 meth = methods[0] 

4411 inferred = next(meth.infer(context=context), None) 

4412 if ( 

4413 isinstance(inferred, util.UninferableBase) 

4414 or not inferred.callable() 

4415 ): 

4416 continue 

4417 

4418 context = copy_context(context) 

4419 context.boundnode = operand 

4420 context.callcontext = CallContext(args=[], callee=inferred) 

4421 

4422 call_results = inferred.infer_call_result(self, context=context) 

4423 result = next(call_results, None) 

4424 if result is None: 

4425 # Failed to infer, return the same type. 

4426 yield operand 

4427 else: 

4428 yield result 

4429 except AttributeInferenceError as inner_exc: 

4430 # The unary operation special method was not found. 

4431 yield util.BadUnaryOperationMessage(operand, self.op, inner_exc) 

4432 except InferenceError: 

4433 yield util.Uninferable 

4434 

4435 @decorators.raise_if_nothing_inferred 

4436 @decorators.path_wrapper 

4437 def _infer( 

4438 self, context: InferenceContext | None = None 

4439 ) -> Generator[InferenceResult, None, InferenceErrorInfo]: 

4440 """Infer what an UnaryOp should return when evaluated.""" 

4441 yield from self._filter_operation_errors( 

4442 self._infer_unaryop, context, util.BadUnaryOperationMessage 

4443 ) 

4444 return InferenceErrorInfo(node=self, context=context) 

4445 

4446 

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

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

4449 

4450 >>> import astroid 

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

4452 ... while condition(): 

4453 ... print("True") 

4454 ... ''') 

4455 >>> node 

4456 <While l.2 at 0x...> 

4457 """ 

4458 

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

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

4461 

4462 test: NodeNG 

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

4464 

4465 body: list[NodeNG] 

4466 """The contents of the loop.""" 

4467 

4468 orelse: list[NodeNG] 

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

4470 

4471 def postinit( 

4472 self, 

4473 test: NodeNG, 

4474 body: list[NodeNG], 

4475 orelse: list[NodeNG], 

4476 ) -> None: 

4477 self.test = test 

4478 self.body = body 

4479 self.orelse = orelse 

4480 

4481 @cached_property 

4482 def blockstart_tolineno(self): 

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

4484 

4485 :type: int 

4486 """ 

4487 return self.test.tolineno 

4488 

4489 def get_children(self): 

4490 yield self.test 

4491 

4492 yield from self.body 

4493 yield from self.orelse 

4494 

4495 def _get_yield_nodes_skip_functions(self): 

4496 """A While node can contain a Yield node in the test""" 

4497 yield from self.test._get_yield_nodes_skip_functions() 

4498 yield from super()._get_yield_nodes_skip_functions() 

4499 

4500 def _get_yield_nodes_skip_lambdas(self): 

4501 """A While node can contain a Yield node in the test""" 

4502 yield from self.test._get_yield_nodes_skip_lambdas() 

4503 yield from super()._get_yield_nodes_skip_lambdas() 

4504 

4505 

4506class With( 

4507 _base_nodes.MultiLineWithElseBlockNode, 

4508 _base_nodes.AssignTypeNode, 

4509 _base_nodes.Statement, 

4510): 

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

4512 

4513 >>> import astroid 

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

4515 ... with open(file_path) as file_: 

4516 ... print(file_.read()) 

4517 ... ''') 

4518 >>> node 

4519 <With l.2 at 0x...> 

4520 """ 

4521 

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

4523 _other_other_fields = ("type_annotation",) 

4524 _multi_line_block_fields = ("body",) 

4525 

4526 def __init__( 

4527 self, 

4528 lineno: int | None = None, 

4529 col_offset: int | None = None, 

4530 parent: NodeNG | None = None, 

4531 *, 

4532 end_lineno: int | None = None, 

4533 end_col_offset: int | None = None, 

4534 ) -> None: 

4535 """ 

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

4537 

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

4539 source code. 

4540 

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

4542 

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

4544 

4545 :param end_col_offset: The end column this node appears on in the 

4546 source code. Note: This is after the last symbol. 

4547 """ 

4548 self.items: list[tuple[NodeNG, NodeNG | None]] = [] 

4549 """The pairs of context managers and the names they are assigned to.""" 

4550 

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

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

4553 

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

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

4556 

4557 super().__init__( 

4558 lineno=lineno, 

4559 col_offset=col_offset, 

4560 end_lineno=end_lineno, 

4561 end_col_offset=end_col_offset, 

4562 parent=parent, 

4563 ) 

4564 

4565 def postinit( 

4566 self, 

4567 items: list[tuple[NodeNG, NodeNG | None]] | None = None, 

4568 body: list[NodeNG] | None = None, 

4569 type_annotation: NodeNG | None = None, 

4570 ) -> None: 

4571 """Do some setup after initialisation. 

4572 

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

4574 they are assigned to. 

4575 

4576 :param body: The contents of the ``with`` block. 

4577 """ 

4578 if items is not None: 

4579 self.items = items 

4580 if body is not None: 

4581 self.body = body 

4582 self.type_annotation = type_annotation 

4583 

4584 assigned_stmts = protocols.with_assigned_stmts 

4585 """Returns the assigned statement (non inferred) according to the assignment type. 

4586 See astroid/protocols.py for actual implementation. 

4587 """ 

4588 

4589 @cached_property 

4590 def blockstart_tolineno(self): 

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

4592 

4593 :type: int 

4594 """ 

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

4596 

4597 def get_children(self): 

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

4599 

4600 :returns: The children. 

4601 :rtype: Iterator[NodeNG] 

4602 """ 

4603 for expr, var in self.items: 

4604 yield expr 

4605 if var: 

4606 yield var 

4607 yield from self.body 

4608 

4609 

4610class AsyncWith(With): 

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

4612 

4613 

4614class Yield(NodeNG): 

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

4616 

4617 >>> import astroid 

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

4619 >>> node 

4620 <Yield l.1 at 0x...> 

4621 """ 

4622 

4623 _astroid_fields = ("value",) 

4624 

4625 value: NodeNG | None 

4626 """The value to yield.""" 

4627 

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

4629 self.value = value 

4630 

4631 def get_children(self): 

4632 if self.value is not None: 

4633 yield self.value 

4634 

4635 def _get_yield_nodes_skip_functions(self): 

4636 yield self 

4637 

4638 def _get_yield_nodes_skip_lambdas(self): 

4639 yield self 

4640 

4641 

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

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

4644 

4645 

4646class DictUnpack(_base_nodes.NoChildrenNode): 

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

4648 

4649 

4650class FormattedValue(NodeNG): 

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

4652 

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

4654 

4655 >>> import astroid 

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

4657 >>> node 

4658 <JoinedStr l.1 at 0x...> 

4659 >>> node.values 

4660 [<Const.str l.1 at 0x...>, <FormattedValue l.1 at 0x...>] 

4661 """ 

4662 

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

4664 _other_fields = ("conversion",) 

4665 

4666 def __init__( 

4667 self, 

4668 lineno: int | None = None, 

4669 col_offset: int | None = None, 

4670 parent: NodeNG | None = None, 

4671 *, 

4672 end_lineno: int | None = None, 

4673 end_col_offset: int | None = None, 

4674 ) -> None: 

4675 """ 

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

4677 

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

4679 source code. 

4680 

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

4682 

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

4684 

4685 :param end_col_offset: The end column this node appears on in the 

4686 source code. Note: This is after the last symbol. 

4687 """ 

4688 self.value: NodeNG 

4689 """The value to be formatted into the string.""" 

4690 

4691 self.conversion: int 

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

4693 

4694 .. seealso:: 

4695 :class:`ast.FormattedValue` 

4696 """ 

4697 

4698 self.format_spec: JoinedStr | None = None 

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

4700 

4701 .. seealso:: 

4702 :class:`ast.FormattedValue` 

4703 """ 

4704 

4705 super().__init__( 

4706 lineno=lineno, 

4707 col_offset=col_offset, 

4708 end_lineno=end_lineno, 

4709 end_col_offset=end_col_offset, 

4710 parent=parent, 

4711 ) 

4712 

4713 def postinit( 

4714 self, 

4715 *, 

4716 value: NodeNG, 

4717 conversion: int, 

4718 format_spec: JoinedStr | None = None, 

4719 ) -> None: 

4720 """Do some setup after initialisation. 

4721 

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

4723 

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

4725 

4726 :param format_spec: The formatting to be applied to the value. 

4727 :type format_spec: JoinedStr or None 

4728 """ 

4729 self.value = value 

4730 self.conversion = conversion 

4731 self.format_spec = format_spec 

4732 

4733 def get_children(self): 

4734 yield self.value 

4735 

4736 if self.format_spec is not None: 

4737 yield self.format_spec 

4738 

4739 def _infer( 

4740 self, context: InferenceContext | None = None 

4741 ) -> Generator[InferenceResult, None, InferenceErrorInfo | None]: 

4742 format_specs = Const("") if self.format_spec is None else self.format_spec 

4743 uninferable_already_generated = False 

4744 for format_spec in format_specs.infer(context): 

4745 if not isinstance(format_spec, Const): 

4746 if not uninferable_already_generated: 

4747 yield util.Uninferable 

4748 uninferable_already_generated = True 

4749 continue 

4750 for value in self.value.infer(context): 

4751 if value is util.Uninferable: 

4752 yield util.Uninferable 

4753 return 

4754 value_to_format = value 

4755 if isinstance(value, Const): 

4756 value_to_format = value.value 

4757 if isinstance(format_spec.value, str) and util.format_spec_too_large( 

4758 format_spec.value 

4759 ): 

4760 yield util.Uninferable 

4761 uninferable_already_generated = True 

4762 continue 

4763 try: 

4764 formatted = format(value_to_format, format_spec.value) 

4765 yield Const( 

4766 formatted, 

4767 lineno=self.lineno, 

4768 col_offset=self.col_offset, 

4769 end_lineno=self.end_lineno, 

4770 end_col_offset=self.end_col_offset, 

4771 ) 

4772 continue 

4773 except (ValueError, TypeError, MemoryError): 

4774 # ValueError/TypeError: invalid format spec 

4775 # MemoryError: format spec with huge width (e.g. f'{0:11111111111}') 

4776 yield util.Uninferable 

4777 uninferable_already_generated = True 

4778 continue 

4779 

4780 

4781UNINFERABLE_VALUE = "{Uninferable}" 

4782 

4783 

4784class JoinedStr(NodeNG): 

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

4786 

4787 >>> import astroid 

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

4789 >>> node 

4790 <JoinedStr l.1 at 0x...> 

4791 """ 

4792 

4793 _astroid_fields = ("values",) 

4794 

4795 def __init__( 

4796 self, 

4797 lineno: int | None = None, 

4798 col_offset: int | None = None, 

4799 parent: NodeNG | None = None, 

4800 *, 

4801 end_lineno: int | None = None, 

4802 end_col_offset: int | None = None, 

4803 ) -> None: 

4804 """ 

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

4806 

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

4808 source code. 

4809 

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

4811 

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

4813 

4814 :param end_col_offset: The end column this node appears on in the 

4815 source code. Note: This is after the last symbol. 

4816 """ 

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

4818 """The string expressions to be joined. 

4819 

4820 :type: list(FormattedValue or Const) 

4821 """ 

4822 

4823 super().__init__( 

4824 lineno=lineno, 

4825 col_offset=col_offset, 

4826 end_lineno=end_lineno, 

4827 end_col_offset=end_col_offset, 

4828 parent=parent, 

4829 ) 

4830 

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

4832 """Do some setup after initialisation. 

4833 

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

4835 

4836 :type: list(FormattedValue or Const) 

4837 """ 

4838 if values is not None: 

4839 self.values = values 

4840 

4841 def get_children(self): 

4842 yield from self.values 

4843 

4844 def _infer( 

4845 self, context: InferenceContext | None = None 

4846 ) -> Generator[InferenceResult, None, InferenceErrorInfo | None]: 

4847 if self.values: 

4848 yield from self._infer_with_values(context) 

4849 else: 

4850 yield Const("") 

4851 

4852 def _infer_with_values( 

4853 self, context: InferenceContext | None = None 

4854 ) -> Generator[InferenceResult, None, InferenceErrorInfo | None]: 

4855 uninferable_already_generated = False 

4856 for inferred in self._infer_from_values(self.values, context): 

4857 failed = inferred is util.Uninferable or ( 

4858 isinstance(inferred, Const) and UNINFERABLE_VALUE in inferred.value 

4859 ) 

4860 if failed: 

4861 if not uninferable_already_generated: 

4862 uninferable_already_generated = True 

4863 yield util.Uninferable 

4864 continue 

4865 yield inferred 

4866 

4867 @classmethod 

4868 def _infer_from_values( 

4869 cls, nodes: list[NodeNG], context: InferenceContext | None = None 

4870 ) -> Generator[InferenceResult, None, InferenceErrorInfo | None]: 

4871 if not nodes: 

4872 return 

4873 if len(nodes) == 1: 

4874 for node in cls._safe_infer_from_node(nodes[0], context): 

4875 if isinstance(node, Const): 

4876 yield node 

4877 continue 

4878 yield Const(UNINFERABLE_VALUE) 

4879 return 

4880 for prefix in cls._safe_infer_from_node(nodes[0], context): 

4881 for suffix in cls._infer_from_values(nodes[1:], context): 

4882 result = "" 

4883 for node in (prefix, suffix): 

4884 if isinstance(node, Const): 

4885 result += str(node.value) 

4886 continue 

4887 result += UNINFERABLE_VALUE 

4888 yield Const(result) 

4889 

4890 @classmethod 

4891 def _safe_infer_from_node( 

4892 cls, node: NodeNG, context: InferenceContext | None = None 

4893 ) -> Generator[InferenceResult, None, InferenceErrorInfo | None]: 

4894 try: 

4895 yield from node._infer(context) 

4896 except InferenceError: 

4897 yield util.Uninferable 

4898 

4899 

4900class NamedExpr(_base_nodes.AssignTypeNode): 

4901 """Represents the assignment from the assignment expression 

4902 

4903 >>> import astroid 

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

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

4906 <NamedExpr l.1 at 0x...> 

4907 """ 

4908 

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

4910 

4911 optional_assign = True 

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

4913 

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

4915 

4916 def __init__( 

4917 self, 

4918 lineno: int | None = None, 

4919 col_offset: int | None = None, 

4920 parent: NodeNG | None = None, 

4921 *, 

4922 end_lineno: int | None = None, 

4923 end_col_offset: int | None = None, 

4924 ) -> None: 

4925 """ 

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

4927 

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

4929 source code. 

4930 

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

4932 

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

4934 

4935 :param end_col_offset: The end column this node appears on in the 

4936 source code. Note: This is after the last symbol. 

4937 """ 

4938 self.target: NodeNG 

4939 """The assignment target 

4940 

4941 :type: Name 

4942 """ 

4943 

4944 self.value: NodeNG 

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

4946 

4947 super().__init__( 

4948 lineno=lineno, 

4949 col_offset=col_offset, 

4950 end_lineno=end_lineno, 

4951 end_col_offset=end_col_offset, 

4952 parent=parent, 

4953 ) 

4954 

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

4956 self.target = target 

4957 self.value = value 

4958 

4959 assigned_stmts = protocols.named_expr_assigned_stmts 

4960 """Returns the assigned statement (non inferred) according to the assignment type. 

4961 See astroid/protocols.py for actual implementation. 

4962 """ 

4963 

4964 def frame(self) -> FrameType: 

4965 """The first parent frame node. 

4966 

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

4968 or :class:`ClassDef`. 

4969 

4970 :returns: The first parent frame node. 

4971 """ 

4972 if not self.parent: 

4973 raise ParentMissingError(target=self) 

4974 

4975 # For certain parents NamedExpr evaluate to the scope of the parent 

4976 if isinstance(self.parent, (Arguments, Keyword, Comprehension)): 

4977 if not self.parent.parent: 

4978 raise ParentMissingError(target=self.parent) 

4979 if not self.parent.parent.parent: 

4980 raise ParentMissingError(target=self.parent.parent) 

4981 return self.parent.parent.parent.frame() 

4982 

4983 return self.parent.frame() 

4984 

4985 def scope(self) -> LocalsDictNodeNG: 

4986 """The first parent node defining a new scope. 

4987 These can be Module, FunctionDef, ClassDef, Lambda, or GeneratorExp nodes. 

4988 

4989 :returns: The first parent scope node. 

4990 """ 

4991 if not self.parent: 

4992 raise ParentMissingError(target=self) 

4993 

4994 # For certain parents NamedExpr evaluate to the scope of the parent 

4995 if isinstance(self.parent, (Arguments, Keyword, Comprehension)): 

4996 if not self.parent.parent: 

4997 raise ParentMissingError(target=self.parent) 

4998 if not self.parent.parent.parent: 

4999 raise ParentMissingError(target=self.parent.parent) 

5000 return self.parent.parent.parent.scope() 

5001 

5002 return self.parent.scope() 

5003 

5004 def set_local(self, name: str, stmt: NodeNG) -> None: 

5005 """Define that the given name is declared in the given statement node. 

5006 NamedExpr's in Arguments, Keyword or Comprehension are evaluated in their 

5007 parent's parent scope. So we add to their frame's locals. 

5008 

5009 .. seealso:: :meth:`scope` 

5010 

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

5012 

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

5014 """ 

5015 self.frame().set_local(name, stmt) 

5016 

5017 

5018class Unknown(_base_nodes.AssignTypeNode): 

5019 """This node represents a node in a constructed AST where 

5020 introspection is not possible. 

5021 

5022 Used in the args attribute of FunctionDef nodes where function signature 

5023 introspection failed, and as a placeholder in ObjectModel. 

5024 """ 

5025 

5026 name = "Unknown" 

5027 

5028 def __init__( 

5029 self, 

5030 parent: NodeNG, 

5031 lineno: None = None, 

5032 col_offset: None = None, 

5033 *, 

5034 end_lineno: None = None, 

5035 end_col_offset: None = None, 

5036 ) -> None: 

5037 super().__init__( 

5038 lineno=lineno, 

5039 col_offset=col_offset, 

5040 end_lineno=end_lineno, 

5041 end_col_offset=end_col_offset, 

5042 parent=parent, 

5043 ) 

5044 

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

5046 return "Unknown" 

5047 

5048 def _infer(self, context: InferenceContext | None = None): 

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

5050 yield util.Uninferable 

5051 

5052 

5053UNATTACHED_UNKNOWN = Unknown(parent=SYNTHETIC_ROOT) 

5054 

5055 

5056class EvaluatedObject(NodeNG): 

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

5058 

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

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

5061 """ 

5062 

5063 name = "EvaluatedObject" 

5064 _astroid_fields = ("original",) 

5065 _other_fields = ("value",) 

5066 

5067 def __init__( 

5068 self, original: SuccessfulInferenceResult, value: InferenceResult 

5069 ) -> None: 

5070 self.original: SuccessfulInferenceResult = original 

5071 """The original node that has already been evaluated""" 

5072 

5073 self.value: InferenceResult = value 

5074 """The inferred value""" 

5075 

5076 super().__init__( 

5077 lineno=self.original.lineno, 

5078 col_offset=self.original.col_offset, 

5079 parent=self.original.parent, 

5080 end_lineno=self.original.end_lineno, 

5081 end_col_offset=self.original.end_col_offset, 

5082 ) 

5083 

5084 def _infer( 

5085 self, context: InferenceContext | None = None 

5086 ) -> Generator[NodeNG | util.UninferableBase]: 

5087 yield self.value 

5088 

5089 

5090# Pattern matching ####################################################### 

5091 

5092 

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

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

5095 

5096 >>> import astroid 

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

5098 ... match x: 

5099 ... case 200: 

5100 ... ... 

5101 ... case _: 

5102 ... ... 

5103 ... ''') 

5104 >>> node 

5105 <Match l.2 at 0x...> 

5106 """ 

5107 

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

5109 _multi_line_block_fields = ("cases",) 

5110 

5111 def __init__( 

5112 self, 

5113 lineno: int | None = None, 

5114 col_offset: int | None = None, 

5115 parent: NodeNG | None = None, 

5116 *, 

5117 end_lineno: int | None = None, 

5118 end_col_offset: int | None = None, 

5119 ) -> None: 

5120 self.subject: NodeNG 

5121 self.cases: list[MatchCase] 

5122 super().__init__( 

5123 lineno=lineno, 

5124 col_offset=col_offset, 

5125 end_lineno=end_lineno, 

5126 end_col_offset=end_col_offset, 

5127 parent=parent, 

5128 ) 

5129 

5130 def postinit( 

5131 self, 

5132 *, 

5133 subject: NodeNG, 

5134 cases: list[MatchCase], 

5135 ) -> None: 

5136 self.subject = subject 

5137 self.cases = cases 

5138 

5139 

5140class Pattern(NodeNG): 

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

5142 

5143 

5144class MatchCase(_base_nodes.MultiLineBlockNode): 

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

5146 

5147 >>> import astroid 

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

5149 ... match x: 

5150 ... case 200: 

5151 ... ... 

5152 ... ''') 

5153 >>> node.cases[0] 

5154 <MatchCase l.3 at 0x...> 

5155 """ 

5156 

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

5158 _multi_line_block_fields = ("body",) 

5159 

5160 lineno: None 

5161 col_offset: None 

5162 end_lineno: None 

5163 end_col_offset: None 

5164 

5165 def __init__(self, *, parent: NodeNG | None = None) -> None: 

5166 self.pattern: Pattern 

5167 self.guard: NodeNG | None 

5168 self.body: list[NodeNG] 

5169 super().__init__( 

5170 parent=parent, 

5171 lineno=None, 

5172 col_offset=None, 

5173 end_lineno=None, 

5174 end_col_offset=None, 

5175 ) 

5176 

5177 def postinit( 

5178 self, 

5179 *, 

5180 pattern: Pattern, 

5181 guard: NodeNG | None, 

5182 body: list[NodeNG], 

5183 ) -> None: 

5184 self.pattern = pattern 

5185 self.guard = guard 

5186 self.body = body 

5187 

5188 

5189class MatchValue(Pattern): 

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

5191 

5192 >>> import astroid 

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

5194 ... match x: 

5195 ... case 200: 

5196 ... ... 

5197 ... ''') 

5198 >>> node.cases[0].pattern 

5199 <MatchValue l.3 at 0x...> 

5200 """ 

5201 

5202 _astroid_fields = ("value",) 

5203 

5204 def __init__( 

5205 self, 

5206 lineno: int | None = None, 

5207 col_offset: int | None = None, 

5208 parent: NodeNG | None = None, 

5209 *, 

5210 end_lineno: int | None = None, 

5211 end_col_offset: int | None = None, 

5212 ) -> None: 

5213 self.value: NodeNG 

5214 super().__init__( 

5215 lineno=lineno, 

5216 col_offset=col_offset, 

5217 end_lineno=end_lineno, 

5218 end_col_offset=end_col_offset, 

5219 parent=parent, 

5220 ) 

5221 

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

5223 self.value = value 

5224 

5225 

5226class MatchSingleton(Pattern): 

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

5228 

5229 >>> import astroid 

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

5231 ... match x: 

5232 ... case True: 

5233 ... ... 

5234 ... case False: 

5235 ... ... 

5236 ... case None: 

5237 ... ... 

5238 ... ''') 

5239 >>> node.cases[0].pattern 

5240 <MatchSingleton l.3 at 0x...> 

5241 >>> node.cases[1].pattern 

5242 <MatchSingleton l.5 at 0x...> 

5243 >>> node.cases[2].pattern 

5244 <MatchSingleton l.7 at 0x...> 

5245 """ 

5246 

5247 _other_fields = ("value",) 

5248 

5249 def __init__( 

5250 self, 

5251 *, 

5252 value: Literal[True, False, None], 

5253 lineno: int | None = None, 

5254 col_offset: int | None = None, 

5255 end_lineno: int | None = None, 

5256 end_col_offset: int | None = None, 

5257 parent: NodeNG | None = None, 

5258 ) -> None: 

5259 self.value = value 

5260 super().__init__( 

5261 lineno=lineno, 

5262 col_offset=col_offset, 

5263 end_lineno=end_lineno, 

5264 end_col_offset=end_col_offset, 

5265 parent=parent, 

5266 ) 

5267 

5268 

5269class MatchSequence(Pattern): 

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

5271 

5272 >>> import astroid 

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

5274 ... match x: 

5275 ... case [1, 2]: 

5276 ... ... 

5277 ... case (1, 2, *_): 

5278 ... ... 

5279 ... ''') 

5280 >>> node.cases[0].pattern 

5281 <MatchSequence l.3 at 0x...> 

5282 >>> node.cases[1].pattern 

5283 <MatchSequence l.5 at 0x...> 

5284 """ 

5285 

5286 _astroid_fields = ("patterns",) 

5287 

5288 def __init__( 

5289 self, 

5290 lineno: int | None = None, 

5291 col_offset: int | None = None, 

5292 parent: NodeNG | None = None, 

5293 *, 

5294 end_lineno: int | None = None, 

5295 end_col_offset: int | None = None, 

5296 ) -> None: 

5297 self.patterns: list[Pattern] 

5298 super().__init__( 

5299 lineno=lineno, 

5300 col_offset=col_offset, 

5301 end_lineno=end_lineno, 

5302 end_col_offset=end_col_offset, 

5303 parent=parent, 

5304 ) 

5305 

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

5307 self.patterns = patterns 

5308 

5309 

5310class MatchMapping(_base_nodes.AssignTypeNode, Pattern): 

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

5312 

5313 >>> import astroid 

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

5315 ... match x: 

5316 ... case {1: "Hello", 2: "World", 3: _, **rest}: 

5317 ... ... 

5318 ... ''') 

5319 >>> node.cases[0].pattern 

5320 <MatchMapping l.3 at 0x...> 

5321 """ 

5322 

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

5324 

5325 def __init__( 

5326 self, 

5327 lineno: int | None = None, 

5328 col_offset: int | None = None, 

5329 parent: NodeNG | None = None, 

5330 *, 

5331 end_lineno: int | None = None, 

5332 end_col_offset: int | None = None, 

5333 ) -> None: 

5334 self.keys: list[NodeNG] 

5335 self.patterns: list[Pattern] 

5336 self.rest: AssignName | None 

5337 super().__init__( 

5338 lineno=lineno, 

5339 col_offset=col_offset, 

5340 end_lineno=end_lineno, 

5341 end_col_offset=end_col_offset, 

5342 parent=parent, 

5343 ) 

5344 

5345 def postinit( 

5346 self, 

5347 *, 

5348 keys: list[NodeNG], 

5349 patterns: list[Pattern], 

5350 rest: AssignName | None, 

5351 ) -> None: 

5352 self.keys = keys 

5353 self.patterns = patterns 

5354 self.rest = rest 

5355 

5356 assigned_stmts = protocols.match_mapping_assigned_stmts 

5357 """Returns the assigned statement (non inferred) according to the assignment type. 

5358 See astroid/protocols.py for actual implementation. 

5359 """ 

5360 

5361 

5362class MatchClass(Pattern): 

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

5364 

5365 >>> import astroid 

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

5367 ... match x: 

5368 ... case Point2D(0, 0): 

5369 ... ... 

5370 ... case Point3D(x=0, y=0, z=0): 

5371 ... ... 

5372 ... ''') 

5373 >>> node.cases[0].pattern 

5374 <MatchClass l.3 at 0x...> 

5375 >>> node.cases[1].pattern 

5376 <MatchClass l.5 at 0x...> 

5377 """ 

5378 

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

5380 _other_fields = ("kwd_attrs",) 

5381 

5382 def __init__( 

5383 self, 

5384 lineno: int | None = None, 

5385 col_offset: int | None = None, 

5386 parent: NodeNG | None = None, 

5387 *, 

5388 end_lineno: int | None = None, 

5389 end_col_offset: int | None = None, 

5390 ) -> None: 

5391 self.cls: NodeNG 

5392 self.patterns: list[Pattern] 

5393 self.kwd_attrs: list[str] 

5394 self.kwd_patterns: list[Pattern] 

5395 super().__init__( 

5396 lineno=lineno, 

5397 col_offset=col_offset, 

5398 end_lineno=end_lineno, 

5399 end_col_offset=end_col_offset, 

5400 parent=parent, 

5401 ) 

5402 

5403 def postinit( 

5404 self, 

5405 *, 

5406 cls: NodeNG, 

5407 patterns: list[Pattern], 

5408 kwd_attrs: list[str], 

5409 kwd_patterns: list[Pattern], 

5410 ) -> None: 

5411 self.cls = cls 

5412 self.patterns = patterns 

5413 self.kwd_attrs = kwd_attrs 

5414 self.kwd_patterns = kwd_patterns 

5415 

5416 

5417class MatchStar(_base_nodes.AssignTypeNode, Pattern): 

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

5419 

5420 >>> import astroid 

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

5422 ... match x: 

5423 ... case [1, *_]: 

5424 ... ... 

5425 ... ''') 

5426 >>> node.cases[0].pattern.patterns[1] 

5427 <MatchStar l.3 at 0x...> 

5428 """ 

5429 

5430 _astroid_fields = ("name",) 

5431 

5432 def __init__( 

5433 self, 

5434 lineno: int | None = None, 

5435 col_offset: int | None = None, 

5436 parent: NodeNG | None = None, 

5437 *, 

5438 end_lineno: int | None = None, 

5439 end_col_offset: int | None = None, 

5440 ) -> None: 

5441 self.name: AssignName | None 

5442 super().__init__( 

5443 lineno=lineno, 

5444 col_offset=col_offset, 

5445 end_lineno=end_lineno, 

5446 end_col_offset=end_col_offset, 

5447 parent=parent, 

5448 ) 

5449 

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

5451 self.name = name 

5452 

5453 assigned_stmts = protocols.match_star_assigned_stmts 

5454 """Returns the assigned statement (non inferred) according to the assignment type. 

5455 See astroid/protocols.py for actual implementation. 

5456 """ 

5457 

5458 

5459class MatchAs(_base_nodes.AssignTypeNode, Pattern): 

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

5461 

5462 >>> import astroid 

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

5464 ... match x: 

5465 ... case [1, a]: 

5466 ... ... 

5467 ... case {'key': b}: 

5468 ... ... 

5469 ... case Point2D(0, 0) as c: 

5470 ... ... 

5471 ... case d: 

5472 ... ... 

5473 ... ''') 

5474 >>> node.cases[0].pattern.patterns[1] 

5475 <MatchAs l.3 at 0x...> 

5476 >>> node.cases[1].pattern.patterns[0] 

5477 <MatchAs l.5 at 0x...> 

5478 >>> node.cases[2].pattern 

5479 <MatchAs l.7 at 0x...> 

5480 >>> node.cases[3].pattern 

5481 <MatchAs l.9 at 0x...> 

5482 """ 

5483 

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

5485 

5486 def __init__( 

5487 self, 

5488 lineno: int | None = None, 

5489 col_offset: int | None = None, 

5490 parent: NodeNG | None = None, 

5491 *, 

5492 end_lineno: int | None = None, 

5493 end_col_offset: int | None = None, 

5494 ) -> None: 

5495 self.pattern: Pattern | None 

5496 self.name: AssignName | None 

5497 super().__init__( 

5498 lineno=lineno, 

5499 col_offset=col_offset, 

5500 end_lineno=end_lineno, 

5501 end_col_offset=end_col_offset, 

5502 parent=parent, 

5503 ) 

5504 

5505 def postinit( 

5506 self, 

5507 *, 

5508 pattern: Pattern | None, 

5509 name: AssignName | None, 

5510 ) -> None: 

5511 self.pattern = pattern 

5512 self.name = name 

5513 

5514 assigned_stmts = protocols.match_as_assigned_stmts 

5515 """Returns the assigned statement (non inferred) according to the assignment type. 

5516 See astroid/protocols.py for actual implementation. 

5517 """ 

5518 

5519 

5520class MatchOr(Pattern): 

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

5522 

5523 >>> import astroid 

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

5525 ... match x: 

5526 ... case 400 | 401 | 402: 

5527 ... ... 

5528 ... ''') 

5529 >>> node.cases[0].pattern 

5530 <MatchOr l.3 at 0x...> 

5531 """ 

5532 

5533 _astroid_fields = ("patterns",) 

5534 

5535 def __init__( 

5536 self, 

5537 lineno: int | None = None, 

5538 col_offset: int | None = None, 

5539 parent: NodeNG | None = None, 

5540 *, 

5541 end_lineno: int | None = None, 

5542 end_col_offset: int | None = None, 

5543 ) -> None: 

5544 self.patterns: list[Pattern] 

5545 super().__init__( 

5546 lineno=lineno, 

5547 col_offset=col_offset, 

5548 end_lineno=end_lineno, 

5549 end_col_offset=end_col_offset, 

5550 parent=parent, 

5551 ) 

5552 

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

5554 self.patterns = patterns 

5555 

5556 

5557class TemplateStr(NodeNG): 

5558 """Class representing an :class:`ast.TemplateStr` node. 

5559 

5560 >>> import astroid 

5561 >>> node = astroid.extract_node('t"{name} finished {place!s}"') 

5562 >>> node 

5563 <TemplateStr l.1 at 0x...> 

5564 """ 

5565 

5566 _astroid_fields = ("values",) 

5567 

5568 def __init__( 

5569 self, 

5570 lineno: int | None = None, 

5571 col_offset: int | None = None, 

5572 parent: NodeNG | None = None, 

5573 *, 

5574 end_lineno: int | None = None, 

5575 end_col_offset: int | None = None, 

5576 ) -> None: 

5577 self.values: list[NodeNG] 

5578 super().__init__( 

5579 lineno=lineno, 

5580 col_offset=col_offset, 

5581 end_lineno=end_lineno, 

5582 end_col_offset=end_col_offset, 

5583 parent=parent, 

5584 ) 

5585 

5586 def postinit(self, *, values: list[NodeNG]) -> None: 

5587 self.values = values 

5588 

5589 def get_children(self) -> Iterator[NodeNG]: 

5590 yield from self.values 

5591 

5592 

5593class Interpolation(NodeNG): 

5594 """Class representing an :class:`ast.Interpolation` node. 

5595 

5596 >>> import astroid 

5597 >>> node = astroid.extract_node('t"{name} finished {place!s}"') 

5598 >>> node 

5599 <TemplateStr l.1 at 0x...> 

5600 >>> node.values[0] 

5601 <Interpolation l.1 at 0x...> 

5602 >>> node.values[2] 

5603 <Interpolation l.1 at 0x...> 

5604 """ 

5605 

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

5607 _other_fields = ("str", "conversion") 

5608 

5609 def __init__( 

5610 self, 

5611 lineno: int | None = None, 

5612 col_offset: int | None = None, 

5613 parent: NodeNG | None = None, 

5614 *, 

5615 end_lineno: int | None = None, 

5616 end_col_offset: int | None = None, 

5617 ) -> None: 

5618 self.value: NodeNG 

5619 """Any expression node.""" 

5620 

5621 self.str: str 

5622 """Text of the interpolation expression.""" 

5623 

5624 self.conversion: int 

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

5626 

5627 .. seealso:: 

5628 :class:`ast.Interpolation` 

5629 """ 

5630 

5631 self.format_spec: JoinedStr | None = None 

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

5633 

5634 .. seealso:: 

5635 :class:`ast.Interpolation` 

5636 """ 

5637 

5638 super().__init__( 

5639 lineno=lineno, 

5640 col_offset=col_offset, 

5641 end_lineno=end_lineno, 

5642 end_col_offset=end_col_offset, 

5643 parent=parent, 

5644 ) 

5645 

5646 def postinit( 

5647 self, 

5648 *, 

5649 value: NodeNG, 

5650 str: str, # pylint: disable=redefined-builtin 

5651 conversion: int = -1, 

5652 format_spec: JoinedStr | None = None, 

5653 ) -> None: 

5654 self.value = value 

5655 self.str = str 

5656 self.conversion = conversion 

5657 self.format_spec = format_spec 

5658 

5659 def get_children(self) -> Iterator[NodeNG]: 

5660 yield self.value 

5661 if self.format_spec: 

5662 yield self.format_spec 

5663 

5664 

5665# constants ############################################################## 

5666 

5667# The _proxied attribute of all container types (List, Tuple, etc.) 

5668# are set during bootstrapping by _astroid_bootstrapping(). 

5669CONST_CLS: dict[type, type[NodeNG]] = { 

5670 list: List, 

5671 tuple: Tuple, 

5672 dict: Dict, 

5673 set: Set, 

5674 type(None): Const, 

5675 type(NotImplemented): Const, 

5676 type(...): Const, 

5677 bool: Const, 

5678 int: Const, 

5679 float: Const, 

5680 complex: Const, 

5681 str: Const, 

5682 bytes: Const, 

5683} 

5684 

5685 

5686def _create_basic_elements( 

5687 value: Iterable[Any], node: List | Set | Tuple 

5688) -> list[NodeNG]: 

5689 """Create a list of nodes to function as the elements of a new node.""" 

5690 elements: list[NodeNG] = [] 

5691 for element in value: 

5692 # NOTE: avoid accessing any attributes of element in the loop. 

5693 element_node = const_factory(element) 

5694 element_node.parent = node 

5695 elements.append(element_node) 

5696 return elements 

5697 

5698 

5699def _create_dict_items( 

5700 values: Mapping[Any, Any], node: Dict 

5701) -> list[tuple[SuccessfulInferenceResult, SuccessfulInferenceResult]]: 

5702 """Create a list of node pairs to function as the items of a new dict node.""" 

5703 elements: list[tuple[SuccessfulInferenceResult, SuccessfulInferenceResult]] = [] 

5704 for key, value in values.items(): 

5705 # NOTE: avoid accessing any attributes of both key and value in the loop. 

5706 key_node = const_factory(key) 

5707 key_node.parent = node 

5708 value_node = const_factory(value) 

5709 value_node.parent = node 

5710 elements.append((key_node, value_node)) 

5711 return elements 

5712 

5713 

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

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

5716 # NOTE: avoid accessing any attributes of value until it is known that value 

5717 # is of a const type, to avoid possibly triggering code for a live object. 

5718 # Accesses include value.__class__ and isinstance(value, ...), but not type(value). 

5719 # See: https://github.com/pylint-dev/astroid/issues/2686 

5720 value_type = type(value) 

5721 assert not issubclass(value_type, NodeNG) 

5722 

5723 # This only handles instances of the CONST types. Any 

5724 # subclasses get inferred as EmptyNode. 

5725 # TODO: See if we should revisit these with the normal builder. 

5726 if value_type not in CONST_CLS: 

5727 node = EmptyNode() 

5728 node.object = value 

5729 return node 

5730 

5731 instance: List | Set | Tuple | Dict 

5732 initializer_cls = CONST_CLS[value_type] 

5733 if issubclass(initializer_cls, (List, Set, Tuple)): 

5734 instance = initializer_cls( 

5735 lineno=None, 

5736 col_offset=None, 

5737 parent=SYNTHETIC_ROOT, 

5738 end_lineno=None, 

5739 end_col_offset=None, 

5740 ) 

5741 instance.postinit(_create_basic_elements(value, instance)) 

5742 return instance 

5743 if issubclass(initializer_cls, Dict): 

5744 instance = initializer_cls( 

5745 lineno=None, 

5746 col_offset=None, 

5747 parent=SYNTHETIC_ROOT, 

5748 end_lineno=None, 

5749 end_col_offset=None, 

5750 ) 

5751 instance.postinit(_create_dict_items(value, instance)) 

5752 return instance 

5753 return Const(value)