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

2109 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: iterable(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( 

343 self, 

344 context: InferenceContext | None = None, 

345 **kwargs: Any, 

346 ) -> Iterator[Self]: 

347 has_starred_named_expr = any( 

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

349 ) 

350 if has_starred_named_expr: 

351 values = self._infer_sequence_helper(context) 

352 new_seq = type(self)( 

353 lineno=self.lineno, 

354 col_offset=self.col_offset, 

355 parent=self.parent, 

356 end_lineno=self.end_lineno, 

357 end_col_offset=self.end_col_offset, 

358 ) 

359 new_seq.postinit(values) 

360 

361 yield new_seq 

362 else: 

363 yield self 

364 

365 def _infer_sequence_helper( 

366 self, context: InferenceContext | None = None 

367 ) -> list[SuccessfulInferenceResult]: 

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

369 values = [] 

370 

371 for elt in self.elts: 

372 if isinstance(elt, Starred): 

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

374 if not starred: 

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

376 if isinstance(starred, TypeVarTuple): 

377 # TypeVarTuple unpacking (*Ts) represents a variadic 

378 # type parameter, not an iterable to expand. 

379 values.append(elt) 

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

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

382 else: 

383 # TODO: fresh context? 

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

385 elif isinstance(elt, NamedExpr): 

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

387 if not value: 

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

389 values.append(value) 

390 else: 

391 values.append(elt) 

392 return values 

393 

394 

395# Name classes 

396 

397 

398class AssignName( 

399 _base_nodes.NoChildrenNode, 

400 _base_nodes.LookupMixIn, 

401 _base_nodes.ParentAssignNode, 

402): 

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

404 

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

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

407 

408 >>> import astroid 

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

410 >>> node 

411 <Assign l.1 at 0x7effe1db8550> 

412 >>> list(node.get_children()) 

413 [<AssignName.variable l.1 at 0x7effe1db8748>, <Call l.1 at 0x7effe1db8630>] 

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

415 'variable' 

416 """ 

417 

418 _other_fields = ("name",) 

419 

420 def __init__( 

421 self, 

422 name: str, 

423 lineno: int, 

424 col_offset: int, 

425 parent: NodeNG, 

426 *, 

427 end_lineno: int | None, 

428 end_col_offset: int | None, 

429 ) -> None: 

430 self.name = name 

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

432 

433 super().__init__( 

434 lineno=lineno, 

435 col_offset=col_offset, 

436 end_lineno=end_lineno, 

437 end_col_offset=end_col_offset, 

438 parent=parent, 

439 ) 

440 

441 assigned_stmts = protocols.assend_assigned_stmts 

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

443 See astroid/protocols.py for actual implementation. 

444 """ 

445 

446 @decorators.raise_if_nothing_inferred 

447 @decorators.path_wrapper 

448 def _infer( 

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

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

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

452 assign node. 

453 """ 

454 if isinstance(self.parent, AugAssign): 

455 return self.parent.infer(context) 

456 

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

458 return _infer_stmts(stmts, context) 

459 

460 @decorators.raise_if_nothing_inferred 

461 def infer_lhs( 

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

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

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

465 

466 Same implementation as Name._infer.""" 

467 # pylint: disable=import-outside-toplevel 

468 from astroid.constraint import get_constraints 

469 from astroid.helpers import _higher_function_scope 

470 

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

472 if not stmts: 

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

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

475 parent_function = _higher_function_scope(self.scope()) 

476 if parent_function: 

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

478 

479 if not stmts: 

480 raise NameInferenceError( 

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

482 ) 

483 context = copy_context(context) 

484 context.lookupname = self.name 

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

486 

487 return _infer_stmts(stmts, context, frame) 

488 

489 

490class DelName( 

491 _base_nodes.NoChildrenNode, _base_nodes.LookupMixIn, _base_nodes.ParentAssignNode 

492): 

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

494 

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

496 

497 >>> import astroid 

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

499 >>> list(node.get_children()) 

500 [<DelName.variable l.1 at 0x7effe1da4d30>] 

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

502 'variable' 

503 """ 

504 

505 _other_fields = ("name",) 

506 

507 def __init__( 

508 self, 

509 name: str, 

510 lineno: int, 

511 col_offset: int, 

512 parent: NodeNG, 

513 *, 

514 end_lineno: int | None, 

515 end_col_offset: int | None, 

516 ) -> None: 

517 self.name = name 

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

519 

520 super().__init__( 

521 lineno=lineno, 

522 col_offset=col_offset, 

523 end_lineno=end_lineno, 

524 end_col_offset=end_col_offset, 

525 parent=parent, 

526 ) 

527 

528 

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

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

531 

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

533 :class:`AssignName` or :class:`DelName`. 

534 

535 >>> import astroid 

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

537 >>> node 

538 <Call l.1 at 0x7effe1db8710> 

539 >>> list(node.get_children()) 

540 [<Name.range l.1 at 0x7effe1db86a0>, <Const.int l.1 at 0x7effe1db8518>] 

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

542 'range' 

543 """ 

544 

545 _other_fields = ("name",) 

546 

547 def __init__( 

548 self, 

549 name: str, 

550 lineno: int, 

551 col_offset: int, 

552 parent: NodeNG, 

553 *, 

554 end_lineno: int | None, 

555 end_col_offset: int | None, 

556 ) -> None: 

557 self.name = name 

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

559 

560 super().__init__( 

561 lineno=lineno, 

562 col_offset=col_offset, 

563 end_lineno=end_lineno, 

564 end_col_offset=end_col_offset, 

565 parent=parent, 

566 ) 

567 

568 def _get_name_nodes(self): 

569 yield self 

570 

571 for child_node in self.get_children(): 

572 yield from child_node._get_name_nodes() 

573 

574 @decorators.raise_if_nothing_inferred 

575 @decorators.path_wrapper 

576 def _infer( 

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

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

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

580 

581 Same implementation as AssignName._infer_lhs.""" 

582 # pylint: disable=import-outside-toplevel 

583 from astroid.constraint import get_constraints 

584 from astroid.helpers import _higher_function_scope 

585 

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

587 if not stmts: 

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

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

590 parent_function = _higher_function_scope(self.scope()) 

591 if parent_function: 

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

593 

594 if not stmts: 

595 raise NameInferenceError( 

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

597 ) 

598 context = copy_context(context) 

599 context.lookupname = self.name 

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

601 

602 return _infer_stmts(stmts, context, frame) 

603 

604 

605class Arguments( 

606 _base_nodes.AssignTypeNode 

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

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

609 

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

611 function definition. 

612 

613 >>> import astroid 

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

615 >>> node 

616 <FunctionDef.foo l.1 at 0x7effe1db8198> 

617 >>> node.args 

618 <Arguments l.1 at 0x7effe1db82e8> 

619 """ 

620 

621 # Python 3.4+ uses a different approach regarding annotations, 

622 # each argument is a new class, _ast.arg, which exposes an 

623 # 'annotation' attribute. In astroid though, arguments are exposed 

624 # as is in the Arguments node and the only way to expose annotations 

625 # is by using something similar with Python 3.3: 

626 # - we expose 'varargannotation' and 'kwargannotation' of annotations 

627 # of varargs and kwargs. 

628 # - we expose 'annotation', a list with annotations for 

629 # for each normal argument. If an argument doesn't have an 

630 # annotation, its value will be None. 

631 _astroid_fields = ( 

632 "args", 

633 "defaults", 

634 "kwonlyargs", 

635 "posonlyargs", 

636 "posonlyargs_annotations", 

637 "kw_defaults", 

638 "annotations", 

639 "varargannotation", 

640 "kwargannotation", 

641 "kwonlyargs_annotations", 

642 "type_comment_args", 

643 "type_comment_kwonlyargs", 

644 "type_comment_posonlyargs", 

645 ) 

646 

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

648 

649 args: list[AssignName] | None 

650 """The names of the required arguments. 

651 

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

653 signature and the arguments are therefore unknown. 

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

655 incomplete signature information. 

656 """ 

657 

658 defaults: list[NodeNG] | None 

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

660 

661 kwonlyargs: list[AssignName] 

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

663 

664 posonlyargs: list[AssignName] 

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

666 

667 kw_defaults: list[NodeNG | None] | None 

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

669 

670 annotations: list[NodeNG | None] 

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

672 

673 posonlyargs_annotations: list[NodeNG | None] 

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

675 

676 kwonlyargs_annotations: list[NodeNG | None] 

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

678 

679 type_comment_args: list[NodeNG | None] 

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

681 

682 If an argument does not have a type comment, 

683 the value for that argument will be None. 

684 """ 

685 

686 type_comment_kwonlyargs: list[NodeNG | None] 

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

688 

689 If an argument does not have a type comment, 

690 the value for that argument will be None. 

691 """ 

692 

693 type_comment_posonlyargs: list[NodeNG | None] 

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

695 

696 If an argument does not have a type comment, 

697 the value for that argument will be None. 

698 """ 

699 

700 varargannotation: NodeNG | None 

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

702 

703 kwargannotation: NodeNG | None 

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

705 

706 vararg_node: AssignName | None 

707 """The node for variable length arguments""" 

708 

709 kwarg_node: AssignName | None 

710 """The node for variable keyword arguments""" 

711 

712 def __init__( 

713 self, 

714 vararg: str | None, 

715 kwarg: str | None, 

716 parent: NodeNG, 

717 vararg_node: AssignName | None = None, 

718 kwarg_node: AssignName | None = None, 

719 ) -> None: 

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

721 super().__init__( 

722 parent=parent, 

723 lineno=None, 

724 col_offset=None, 

725 end_lineno=None, 

726 end_col_offset=None, 

727 ) 

728 

729 self.vararg = vararg 

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

731 

732 self.kwarg = kwarg 

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

734 

735 self.vararg_node = vararg_node 

736 self.kwarg_node = kwarg_node 

737 

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

739 def postinit( 

740 self, 

741 args: list[AssignName] | None, 

742 defaults: list[NodeNG] | None, 

743 kwonlyargs: list[AssignName], 

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

745 annotations: list[NodeNG | None], 

746 posonlyargs: list[AssignName], 

747 kwonlyargs_annotations: list[NodeNG | None], 

748 posonlyargs_annotations: list[NodeNG | None], 

749 varargannotation: NodeNG | None = None, 

750 kwargannotation: NodeNG | None = None, 

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

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

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

754 ) -> None: 

755 self.args = args 

756 self.defaults = defaults 

757 self.kwonlyargs = kwonlyargs 

758 self.posonlyargs = posonlyargs 

759 self.kw_defaults = kw_defaults 

760 self.annotations = annotations 

761 self.kwonlyargs_annotations = kwonlyargs_annotations 

762 self.posonlyargs_annotations = posonlyargs_annotations 

763 

764 # Parameters that got added later and need a default 

765 self.varargannotation = varargannotation 

766 self.kwargannotation = kwargannotation 

767 if type_comment_args is None: 

768 type_comment_args = [] 

769 self.type_comment_args = type_comment_args 

770 if type_comment_kwonlyargs is None: 

771 type_comment_kwonlyargs = [] 

772 self.type_comment_kwonlyargs = type_comment_kwonlyargs 

773 if type_comment_posonlyargs is None: 

774 type_comment_posonlyargs = [] 

775 self.type_comment_posonlyargs = type_comment_posonlyargs 

776 

777 assigned_stmts = protocols.arguments_assigned_stmts 

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

779 See astroid/protocols.py for actual implementation. 

780 """ 

781 

782 def _infer_name(self, frame, name): 

783 if self.parent is frame: 

784 return name 

785 return None 

786 

787 @cached_property 

788 def fromlineno(self) -> int: 

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

790 

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

792 """ 

793 lineno = super().fromlineno 

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

795 

796 @cached_property 

797 def arguments(self): 

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

799 * Positional only arguments 

800 * Positional arguments 

801 * Keyword arguments 

802 * Variable arguments (.e.g *args) 

803 * Variable keyword arguments (e.g **kwargs) 

804 """ 

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

806 if self.vararg_node: 

807 retval.append(self.vararg_node) 

808 retval += self.kwonlyargs or () 

809 if self.kwarg_node: 

810 retval.append(self.kwarg_node) 

811 

812 return retval 

813 

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

815 """Get the arguments formatted as string. 

816 

817 :returns: The formatted arguments. 

818 :rtype: str 

819 """ 

820 result = [] 

821 positional_only_defaults = [] 

822 positional_or_keyword_defaults = self.defaults 

823 if self.defaults: 

824 args = self.args or [] 

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

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

827 

828 if self.posonlyargs: 

829 result.append( 

830 _format_args( 

831 self.posonlyargs, 

832 positional_only_defaults, 

833 self.posonlyargs_annotations, 

834 skippable_names=skippable_names, 

835 ) 

836 ) 

837 result.append("/") 

838 if self.args: 

839 result.append( 

840 _format_args( 

841 self.args, 

842 positional_or_keyword_defaults, 

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

844 skippable_names=skippable_names, 

845 ) 

846 ) 

847 if self.vararg: 

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

849 if self.kwonlyargs: 

850 if not self.vararg: 

851 result.append("*") 

852 result.append( 

853 _format_args( 

854 self.kwonlyargs, 

855 self.kw_defaults, 

856 self.kwonlyargs_annotations, 

857 skippable_names=skippable_names, 

858 ) 

859 ) 

860 if self.kwarg: 

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

862 return ", ".join(result) 

863 

864 def _get_arguments_data( 

865 self, 

866 ) -> tuple[ 

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

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

869 ]: 

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

871 

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

873 and their default value, if any. 

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

875 returns the data that is used to do so. 

876 """ 

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

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

879 

880 # Setup and match defaults with arguments 

881 positional_only_defaults = [] 

882 positional_or_keyword_defaults = self.defaults 

883 if self.defaults: 

884 args = self.args or [] 

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

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

887 

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

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

890 if annotation is not None: 

891 annotation = annotation.as_string() 

892 if positional_only_defaults: 

893 default = positional_only_defaults[index].as_string() 

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

895 

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

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

898 if annotation is not None: 

899 annotation = annotation.as_string() 

900 if positional_or_keyword_defaults: 

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

902 default_index = index - defaults_offset 

903 if ( 

904 default_index > -1 

905 and positional_or_keyword_defaults[default_index] is not None 

906 ): 

907 default = positional_or_keyword_defaults[default_index].as_string() 

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

909 

910 if self.vararg: 

911 annotation = self.varargannotation 

912 if annotation is not None: 

913 annotation = annotation.as_string() 

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

915 

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

917 annotation = self.kwonlyargs_annotations[index] 

918 if annotation is not None: 

919 annotation = annotation.as_string() 

920 default = self.kw_defaults[index] 

921 if default is not None: 

922 default = default.as_string() 

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

924 

925 if self.kwarg: 

926 annotation = self.kwargannotation 

927 if annotation is not None: 

928 annotation = annotation.as_string() 

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

930 

931 return pos_only, kw_only 

932 

933 def default_value(self, argname): 

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

935 

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

937 :type argname: str 

938 

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

940 given argument. 

941 """ 

942 args = [ 

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

944 ] 

945 

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

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

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

949 return self.kw_defaults[index] 

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

951 

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

953 if index is not None: 

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

955 if idx >= 0: 

956 return self.defaults[idx] 

957 

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

959 

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

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

962 

963 :param name: The name to check for. 

964 :type name: str 

965 

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

967 """ 

968 if name == self.vararg: 

969 return True 

970 if name == self.kwarg: 

971 return True 

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

973 

974 def find_argname(self, argname): 

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

976 

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

978 :type argname: str 

979 

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

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

982 """ 

983 if self.arguments: 

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

985 if argument: 

986 return index, argument 

987 return None, None 

988 

989 def get_children(self): 

990 yield from self.posonlyargs or () 

991 

992 for elt in self.posonlyargs_annotations: 

993 if elt is not None: 

994 yield elt 

995 

996 yield from self.args or () 

997 

998 if self.defaults is not None: 

999 yield from self.defaults 

1000 yield from self.kwonlyargs 

1001 

1002 for elt in self.kw_defaults or (): 

1003 if elt is not None: 

1004 yield elt 

1005 

1006 for elt in self.annotations: 

1007 if elt is not None: 

1008 yield elt 

1009 

1010 if self.varargannotation is not None: 

1011 yield self.varargannotation 

1012 

1013 if self.kwargannotation is not None: 

1014 yield self.kwargannotation 

1015 

1016 for elt in self.kwonlyargs_annotations: 

1017 if elt is not None: 

1018 yield elt 

1019 

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

1021 """Iterate over all annotations nodes.""" 

1022 for elt in self.posonlyargs_annotations: 

1023 if elt is not None: 

1024 yield elt 

1025 for elt in self.annotations: 

1026 if elt is not None: 

1027 yield elt 

1028 if self.varargannotation is not None: 

1029 yield self.varargannotation 

1030 

1031 for elt in self.kwonlyargs_annotations: 

1032 if elt is not None: 

1033 yield elt 

1034 if self.kwargannotation is not None: 

1035 yield self.kwargannotation 

1036 

1037 @decorators.raise_if_nothing_inferred 

1038 def _infer( 

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

1040 ) -> Generator[InferenceResult]: 

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

1042 from astroid.protocols import _arguments_infer_argname 

1043 

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

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

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

1047 

1048 

1049def _find_arg(argname, args): 

1050 for i, arg in enumerate(args): 

1051 if arg.name == argname: 

1052 return i, arg 

1053 return None, None 

1054 

1055 

1056def _format_args( 

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

1058) -> str: 

1059 if skippable_names is None: 

1060 skippable_names = set() 

1061 values = [] 

1062 if args is None: 

1063 return "" 

1064 if annotations is None: 

1065 annotations = [] 

1066 if defaults is not None: 

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

1068 else: 

1069 default_offset = None 

1070 packed = itertools.zip_longest(args, annotations) 

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

1072 if arg.name in skippable_names: 

1073 continue 

1074 if isinstance(arg, Tuple): 

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

1076 else: 

1077 argname = arg.name 

1078 default_sep = "=" 

1079 if annotation is not None: 

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

1081 default_sep = " = " 

1082 values.append(argname) 

1083 

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

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

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

1087 return ", ".join(values) 

1088 

1089 

1090def _infer_attribute( 

1091 node: nodes.AssignAttr | nodes.Attribute, 

1092 context: InferenceContext | None = None, 

1093 **kwargs: Any, 

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

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

1096 # pylint: disable=import-outside-toplevel 

1097 from astroid.constraint import get_constraints 

1098 from astroid.nodes import ClassDef 

1099 

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

1101 if isinstance(owner, util.UninferableBase): 

1102 yield owner 

1103 continue 

1104 

1105 context = copy_context(context) 

1106 old_boundnode = context.boundnode 

1107 try: 

1108 context.boundnode = owner 

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

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

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

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

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

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

1115 yield util.Uninferable 

1116 else: 

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

1118 except ( 

1119 AttributeInferenceError, 

1120 InferenceError, 

1121 AttributeError, 

1122 ): 

1123 pass 

1124 finally: 

1125 context.boundnode = old_boundnode 

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

1127 

1128 

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

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

1131 

1132 >>> import astroid 

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

1134 >>> node 

1135 <Assign l.1 at 0x7effe1d521d0> 

1136 >>> list(node.get_children()) 

1137 [<AssignAttr.attribute l.1 at 0x7effe1d52320>, <Call l.1 at 0x7effe1d522e8>] 

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

1139 'self.attribute' 

1140 """ 

1141 

1142 expr: NodeNG 

1143 

1144 _astroid_fields = ("expr",) 

1145 _other_fields = ("attrname",) 

1146 

1147 def __init__( 

1148 self, 

1149 attrname: str, 

1150 lineno: int, 

1151 col_offset: int, 

1152 parent: NodeNG, 

1153 *, 

1154 end_lineno: int | None, 

1155 end_col_offset: int | None, 

1156 ) -> None: 

1157 self.attrname = attrname 

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

1159 

1160 super().__init__( 

1161 lineno=lineno, 

1162 col_offset=col_offset, 

1163 end_lineno=end_lineno, 

1164 end_col_offset=end_col_offset, 

1165 parent=parent, 

1166 ) 

1167 

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

1169 self.expr = expr 

1170 

1171 assigned_stmts = protocols.assend_assigned_stmts 

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

1173 See astroid/protocols.py for actual implementation. 

1174 """ 

1175 

1176 def get_children(self): 

1177 yield self.expr 

1178 

1179 @decorators.raise_if_nothing_inferred 

1180 @decorators.path_wrapper 

1181 def _infer( 

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

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

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

1185 assign node. 

1186 """ 

1187 if isinstance(self.parent, AugAssign): 

1188 return self.parent.infer(context) 

1189 

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

1191 return _infer_stmts(stmts, context) 

1192 

1193 @decorators.raise_if_nothing_inferred 

1194 @decorators.path_wrapper 

1195 def infer_lhs( 

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

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

1198 return _infer_attribute(self, context, **kwargs) 

1199 

1200 

1201class Assert(_base_nodes.Statement): 

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

1203 

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

1205 

1206 >>> import astroid 

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

1208 >>> node 

1209 <Assert l.1 at 0x7effe1d527b8> 

1210 """ 

1211 

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

1213 

1214 test: NodeNG 

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

1216 

1217 fail: NodeNG | None 

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

1219 

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

1221 self.fail = fail 

1222 self.test = test 

1223 

1224 def get_children(self): 

1225 yield self.test 

1226 

1227 if self.fail is not None: 

1228 yield self.fail 

1229 

1230 

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

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

1233 

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

1235 asssigned to. 

1236 

1237 >>> import astroid 

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

1239 >>> node 

1240 <Assign l.1 at 0x7effe1db8550> 

1241 """ 

1242 

1243 targets: list[NodeNG] 

1244 """What is being assigned to.""" 

1245 

1246 value: NodeNG 

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

1248 

1249 type_annotation: NodeNG | None 

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

1251 

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

1253 _other_other_fields = ("type_annotation",) 

1254 

1255 def postinit( 

1256 self, 

1257 targets: list[NodeNG], 

1258 value: NodeNG, 

1259 type_annotation: NodeNG | None, 

1260 ) -> None: 

1261 self.targets = targets 

1262 self.value = value 

1263 self.type_annotation = type_annotation 

1264 

1265 assigned_stmts = protocols.assign_assigned_stmts 

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

1267 See astroid/protocols.py for actual implementation. 

1268 """ 

1269 

1270 def get_children(self): 

1271 yield from self.targets 

1272 

1273 yield self.value 

1274 

1275 @cached_property 

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

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

1278 

1279 def _get_yield_nodes_skip_functions(self): 

1280 yield from self.value._get_yield_nodes_skip_functions() 

1281 

1282 def _get_yield_nodes_skip_lambdas(self): 

1283 yield from self.value._get_yield_nodes_skip_lambdas() 

1284 

1285 

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

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

1288 

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

1290 

1291 >>> import astroid 

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

1293 >>> node 

1294 <AnnAssign l.1 at 0x7effe1d4c630> 

1295 """ 

1296 

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

1298 _other_fields = ("simple",) 

1299 

1300 target: Name | Attribute | Subscript 

1301 """What is being assigned to.""" 

1302 

1303 annotation: NodeNG 

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

1305 

1306 value: NodeNG | None 

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

1308 

1309 simple: int 

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

1311 

1312 def postinit( 

1313 self, 

1314 target: Name | Attribute | Subscript, 

1315 annotation: NodeNG, 

1316 simple: int, 

1317 value: NodeNG | None, 

1318 ) -> None: 

1319 self.target = target 

1320 self.annotation = annotation 

1321 self.value = value 

1322 self.simple = simple 

1323 

1324 assigned_stmts = protocols.assign_annassigned_stmts 

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

1326 See astroid/protocols.py for actual implementation. 

1327 """ 

1328 

1329 def get_children(self): 

1330 yield self.target 

1331 yield self.annotation 

1332 

1333 if self.value is not None: 

1334 yield self.value 

1335 

1336 

1337class AugAssign( 

1338 _base_nodes.AssignTypeNode, _base_nodes.OperatorNode, _base_nodes.Statement 

1339): 

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

1341 

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

1343 

1344 >>> import astroid 

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

1346 >>> node 

1347 <AugAssign l.1 at 0x7effe1db4d68> 

1348 """ 

1349 

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

1351 _other_fields = ("op",) 

1352 

1353 target: Name | Attribute | Subscript 

1354 """What is being assigned to.""" 

1355 

1356 value: NodeNG 

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

1358 

1359 def __init__( 

1360 self, 

1361 op: str, 

1362 lineno: int, 

1363 col_offset: int, 

1364 parent: NodeNG, 

1365 *, 

1366 end_lineno: int | None, 

1367 end_col_offset: int | None, 

1368 ) -> None: 

1369 self.op = op 

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

1371 

1372 This includes the equals sign. 

1373 """ 

1374 

1375 super().__init__( 

1376 lineno=lineno, 

1377 col_offset=col_offset, 

1378 end_lineno=end_lineno, 

1379 end_col_offset=end_col_offset, 

1380 parent=parent, 

1381 ) 

1382 

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

1384 self.target = target 

1385 self.value = value 

1386 

1387 assigned_stmts = protocols.assign_assigned_stmts 

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

1389 See astroid/protocols.py for actual implementation. 

1390 """ 

1391 

1392 def type_errors( 

1393 self, context: InferenceContext | None = None 

1394 ) -> list[util.BadBinaryOperationMessage]: 

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

1396 

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

1398 which holds the original exception. 

1399 

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

1401 """ 

1402 bad = [] 

1403 try: 

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

1405 if result is util.Uninferable: 

1406 raise InferenceError 

1407 if isinstance(result, util.BadBinaryOperationMessage): 

1408 bad.append(result) 

1409 except InferenceError: 

1410 return [] 

1411 return bad 

1412 

1413 def get_children(self): 

1414 yield self.target 

1415 yield self.value 

1416 

1417 def _get_yield_nodes_skip_functions(self): 

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

1419 yield from self.value._get_yield_nodes_skip_functions() 

1420 yield from super()._get_yield_nodes_skip_functions() 

1421 

1422 def _get_yield_nodes_skip_lambdas(self): 

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

1424 yield from self.value._get_yield_nodes_skip_lambdas() 

1425 yield from super()._get_yield_nodes_skip_lambdas() 

1426 

1427 def _infer_augassign( 

1428 self, context: InferenceContext | None = None 

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

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

1431 context = context or InferenceContext() 

1432 

1433 rhs_context = context.clone() 

1434 

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

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

1437 

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

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

1440 # Don't know how to process this. 

1441 yield util.Uninferable 

1442 return 

1443 

1444 try: 

1445 yield from self._infer_binary_operation( 

1446 left=lhs, 

1447 right=rhs, 

1448 binary_opnode=self, 

1449 context=context, 

1450 flow_factory=self._get_aug_flow, 

1451 ) 

1452 except _NonDeducibleTypeHierarchy: 

1453 yield util.Uninferable 

1454 

1455 @decorators.raise_if_nothing_inferred 

1456 @decorators.path_wrapper 

1457 def _infer( 

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

1459 ) -> Generator[InferenceResult]: 

1460 return self._filter_operation_errors( 

1461 self._infer_augassign, context, util.BadBinaryOperationMessage 

1462 ) 

1463 

1464 

1465class BinOp(_base_nodes.OperatorNode): 

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

1467 

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

1469 

1470 >>> import astroid 

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

1472 >>> node 

1473 <BinOp l.1 at 0x7f23b2e8cfd0> 

1474 """ 

1475 

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

1477 _other_fields = ("op",) 

1478 

1479 left: NodeNG 

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

1481 

1482 right: NodeNG 

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

1484 

1485 def __init__( 

1486 self, 

1487 op: str, 

1488 lineno: int, 

1489 col_offset: int, 

1490 parent: NodeNG, 

1491 *, 

1492 end_lineno: int | None, 

1493 end_col_offset: int | None, 

1494 ) -> None: 

1495 self.op = op 

1496 """The operator.""" 

1497 

1498 super().__init__( 

1499 lineno=lineno, 

1500 col_offset=col_offset, 

1501 end_lineno=end_lineno, 

1502 end_col_offset=end_col_offset, 

1503 parent=parent, 

1504 ) 

1505 

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

1507 self.left = left 

1508 self.right = right 

1509 

1510 def type_errors( 

1511 self, context: InferenceContext | None = None 

1512 ) -> list[util.BadBinaryOperationMessage]: 

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

1514 

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

1516 which holds the original exception. 

1517 

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

1519 """ 

1520 bad = [] 

1521 try: 

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

1523 if result is util.Uninferable: 

1524 raise InferenceError 

1525 if isinstance(result, util.BadBinaryOperationMessage): 

1526 bad.append(result) 

1527 except InferenceError: 

1528 return [] 

1529 return bad 

1530 

1531 def get_children(self): 

1532 yield self.left 

1533 yield self.right 

1534 

1535 def op_precedence(self) -> int: 

1536 return OP_PRECEDENCE[self.op] 

1537 

1538 def op_left_associative(self) -> bool: 

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

1540 return self.op != "**" 

1541 

1542 def _infer_binop( 

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

1544 ) -> Generator[InferenceResult]: 

1545 """Binary operation inference logic.""" 

1546 left = self.left 

1547 right = self.right 

1548 

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

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

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

1552 context = context or InferenceContext() 

1553 lhs_context = copy_context(context) 

1554 rhs_context = copy_context(context) 

1555 lhs_iter = left.infer(context=lhs_context) 

1556 rhs_iter = right.infer(context=rhs_context) 

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

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

1559 # Don't know how to process this. 

1560 yield util.Uninferable 

1561 return 

1562 

1563 try: 

1564 yield from self._infer_binary_operation( 

1565 lhs, rhs, self, context, self._get_binop_flow 

1566 ) 

1567 except _NonDeducibleTypeHierarchy: 

1568 yield util.Uninferable 

1569 

1570 @decorators.yes_if_nothing_inferred 

1571 @decorators.path_wrapper 

1572 def _infer( 

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

1574 ) -> Generator[InferenceResult]: 

1575 return self._filter_operation_errors( 

1576 self._infer_binop, context, util.BadBinaryOperationMessage 

1577 ) 

1578 

1579 

1580class BoolOp(NodeNG): 

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

1582 

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

1584 

1585 >>> import astroid 

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

1587 >>> node 

1588 <BinOp l.1 at 0x7f23b2e71c50> 

1589 """ 

1590 

1591 _astroid_fields = ("values",) 

1592 _other_fields = ("op",) 

1593 

1594 def __init__( 

1595 self, 

1596 op: str, 

1597 lineno: int | None = None, 

1598 col_offset: int | None = None, 

1599 parent: NodeNG | None = None, 

1600 *, 

1601 end_lineno: int | None = None, 

1602 end_col_offset: int | None = None, 

1603 ) -> None: 

1604 """ 

1605 :param op: The operator. 

1606 

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

1608 

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

1610 source code. 

1611 

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

1613 

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

1615 

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

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

1618 """ 

1619 self.op: str = op 

1620 """The operator.""" 

1621 

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

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

1624 

1625 super().__init__( 

1626 lineno=lineno, 

1627 col_offset=col_offset, 

1628 end_lineno=end_lineno, 

1629 end_col_offset=end_col_offset, 

1630 parent=parent, 

1631 ) 

1632 

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

1634 """Do some setup after initialisation. 

1635 

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

1637 """ 

1638 if values is not None: 

1639 self.values = values 

1640 

1641 def get_children(self): 

1642 yield from self.values 

1643 

1644 def op_precedence(self) -> int: 

1645 return OP_PRECEDENCE[self.op] 

1646 

1647 @decorators.raise_if_nothing_inferred 

1648 @decorators.path_wrapper 

1649 def _infer( 

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

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

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

1653 

1654 The function will calculate the boolean operation 

1655 for all pairs generated through inference for each component 

1656 node. 

1657 """ 

1658 values = self.values 

1659 if self.op == "or": 

1660 predicate = operator.truth 

1661 else: 

1662 predicate = operator.not_ 

1663 

1664 try: 

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

1666 except InferenceError: 

1667 yield util.Uninferable 

1668 return None 

1669 

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

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

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

1673 yield util.Uninferable 

1674 continue 

1675 

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

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

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

1679 yield util.Uninferable 

1680 continue 

1681 

1682 # Since the boolean operations are short circuited operations, 

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

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

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

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

1687 # 1 and 0 -> 1 

1688 # 0 and 1 -> 0 

1689 # 1 or 0 -> 1 

1690 # 0 or 1 -> 1 

1691 value = util.Uninferable 

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

1693 if predicate(bool_value): 

1694 yield value 

1695 break 

1696 else: 

1697 yield value 

1698 

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

1700 

1701 

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

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

1704 

1705 >>> import astroid 

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

1707 >>> node 

1708 <Break l.1 at 0x7f23b2e9e5c0> 

1709 """ 

1710 

1711 

1712class Call(NodeNG): 

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

1714 

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

1716 

1717 >>> import astroid 

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

1719 >>> node 

1720 <Call l.1 at 0x7f23b2e71eb8> 

1721 """ 

1722 

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

1724 

1725 func: NodeNG 

1726 """What is being called.""" 

1727 

1728 args: list[NodeNG] 

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

1730 

1731 keywords: list[Keyword] 

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

1733 

1734 def postinit( 

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

1736 ) -> None: 

1737 self.func = func 

1738 self.args = args 

1739 self.keywords = keywords 

1740 

1741 @property 

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

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

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

1745 

1746 @property 

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

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

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

1750 

1751 def get_children(self): 

1752 yield self.func 

1753 

1754 yield from self.args 

1755 

1756 yield from self.keywords 

1757 

1758 @decorators.raise_if_nothing_inferred 

1759 @decorators.path_wrapper 

1760 def _infer( 

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

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

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

1764 callcontext = copy_context(context) 

1765 callcontext.boundnode = None 

1766 if context is not None: 

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

1768 

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

1770 if isinstance(callee, util.UninferableBase): 

1771 yield callee 

1772 continue 

1773 try: 

1774 if hasattr(callee, "infer_call_result"): 

1775 callcontext.callcontext = CallContext( 

1776 args=self.args, keywords=self.keywords, callee=callee 

1777 ) 

1778 yield from callee.infer_call_result( 

1779 caller=self, context=callcontext 

1780 ) 

1781 except InferenceError: 

1782 continue 

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

1784 

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

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

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

1788 if context is None: 

1789 return context_lookup 

1790 for arg in self.args: 

1791 if isinstance(arg, Starred): 

1792 context_lookup[arg.value] = context 

1793 else: 

1794 context_lookup[arg] = context 

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

1796 for keyword in keywords: 

1797 context_lookup[keyword.value] = context 

1798 return context_lookup 

1799 

1800 

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

1802 "==": operator.eq, 

1803 "!=": operator.ne, 

1804 "<": operator.lt, 

1805 "<=": operator.le, 

1806 ">": operator.gt, 

1807 ">=": operator.ge, 

1808 "in": lambda a, b: a in b, 

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

1810} 

1811UNINFERABLE_OPS = { 

1812 "is", 

1813 "is not", 

1814} 

1815 

1816 

1817class Compare(NodeNG): 

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

1819 

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

1821 

1822 >>> import astroid 

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

1824 >>> node 

1825 <Compare l.1 at 0x7f23b2e9e6d8> 

1826 >>> node.ops 

1827 [('<=', <Name.b l.1 at 0x7f23b2e9e2b0>), ('<=', <Name.c l.1 at 0x7f23b2e9e390>)] 

1828 """ 

1829 

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

1831 

1832 left: NodeNG 

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

1834 

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

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

1837 

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

1839 self.left = left 

1840 self.ops = ops 

1841 

1842 def get_children(self): 

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

1844 

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

1846 strings. 

1847 

1848 :returns: The children. 

1849 :rtype: iterable(NodeNG) 

1850 """ 

1851 yield self.left 

1852 for _, comparator in self.ops: 

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

1854 

1855 def last_child(self): 

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

1857 

1858 :returns: The last child. 

1859 :rtype: NodeNG 

1860 """ 

1861 # XXX maybe if self.ops: 

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

1863 # return self.left 

1864 

1865 # TODO: move to util? 

1866 @staticmethod 

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

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

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

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

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

1872 

1873 def _do_compare( 

1874 self, 

1875 left_iter: Iterable[InferenceResult], 

1876 op: str, 

1877 right_iter: Iterable[InferenceResult], 

1878 ) -> bool | util.UninferableBase: 

1879 """ 

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

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

1882 True 

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

1884 False 

1885 

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

1887 are False, return Uninferable: 

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

1889 util.Uninferable 

1890 """ 

1891 retval: bool | None = None 

1892 if op in UNINFERABLE_OPS: 

1893 return util.Uninferable 

1894 op_func = COMPARE_OPS[op] 

1895 

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

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

1898 right, util.UninferableBase 

1899 ): 

1900 return util.Uninferable 

1901 

1902 try: 

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

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

1905 return util.Uninferable 

1906 

1907 try: 

1908 expr = op_func(left, right) 

1909 except TypeError as exc: 

1910 raise AstroidTypeError from exc 

1911 

1912 if retval is None: 

1913 retval = expr 

1914 elif retval != expr: 

1915 return util.Uninferable 

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

1917 

1918 assert retval is not None 

1919 return retval # it was all the same value 

1920 

1921 def _infer( 

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

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

1924 """Chained comparison inference logic.""" 

1925 retval: bool | util.UninferableBase = True 

1926 

1927 ops = self.ops 

1928 left_node = self.left 

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

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

1931 for op, right_node in ops: 

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

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

1934 try: 

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

1936 except AstroidTypeError: 

1937 retval = util.Uninferable 

1938 break 

1939 if retval is not True: 

1940 break # short-circuit 

1941 lhs = rhs # continue 

1942 if retval is util.Uninferable: 

1943 yield retval # type: ignore[misc] 

1944 else: 

1945 yield Const(retval) 

1946 

1947 

1948class Comprehension(NodeNG): 

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

1950 

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

1952 comprehension including generator expressions. 

1953 

1954 >>> import astroid 

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

1956 >>> list(node.get_children()) 

1957 [<Name.x l.1 at 0x7f23b2e352b0>, <Comprehension l.1 at 0x7f23b2e35320>] 

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

1959 'for x in some_values' 

1960 """ 

1961 

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

1963 _other_fields = ("is_async",) 

1964 

1965 optional_assign = True 

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

1967 

1968 target: NodeNG 

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

1970 

1971 iter: NodeNG 

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

1973 

1974 ifs: list[NodeNG] 

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

1976 

1977 is_async: bool 

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

1979 

1980 def postinit( 

1981 self, 

1982 target: NodeNG, 

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

1984 ifs: list[NodeNG], 

1985 is_async: bool, 

1986 ) -> None: 

1987 self.target = target 

1988 self.iter = iter 

1989 self.ifs = ifs 

1990 self.is_async = is_async 

1991 

1992 assigned_stmts = protocols.for_assigned_stmts 

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

1994 See astroid/protocols.py for actual implementation. 

1995 """ 

1996 

1997 def assign_type(self): 

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

1999 

2000 :returns: The assignment type. 

2001 :rtype: NodeNG 

2002 """ 

2003 return self 

2004 

2005 def _get_filtered_stmts( 

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

2007 ): 

2008 """method used in filter_stmts""" 

2009 if self is mystmt: 

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

2011 return [lookup_node], True 

2012 

2013 elif self.statement() is mystmt: 

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

2015 # current node (gen exp, list comp) 

2016 

2017 return [node], True 

2018 

2019 return stmts, False 

2020 

2021 def get_children(self): 

2022 yield self.target 

2023 yield self.iter 

2024 

2025 yield from self.ifs 

2026 

2027 

2028class Const(_base_nodes.NoChildrenNode, Instance): 

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

2030 

2031 >>> import astroid 

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

2033 >>> node 

2034 <Tuple.tuple l.1 at 0x7f23b2e358d0> 

2035 >>> list(node.get_children()) 

2036 [<Const.int l.1 at 0x7f23b2e35940>, 

2037 <Const.str l.1 at 0x7f23b2e35978>, 

2038 <Const.bool l.1 at 0x7f23b2e359b0>, 

2039 <Const.NoneType l.1 at 0x7f23b2e359e8>, 

2040 <Const.bytes l.1 at 0x7f23b2e35a20>] 

2041 """ 

2042 

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

2044 

2045 def __init__( 

2046 self, 

2047 value: Any, 

2048 lineno: int | None = None, 

2049 col_offset: int | None = None, 

2050 parent: NodeNG = SYNTHETIC_ROOT, 

2051 kind: str | None = None, 

2052 *, 

2053 end_lineno: int | None = None, 

2054 end_col_offset: int | None = None, 

2055 ) -> None: 

2056 """ 

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

2058 

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

2060 

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

2062 source code. 

2063 

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

2065 

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

2067 

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

2069 

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

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

2072 """ 

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

2074 warnings.warn( # pragma: no cover 

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

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

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

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

2079 RuntimeWarning, 

2080 stacklevel=0, 

2081 ) 

2082 self.value = value 

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

2084 

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

2086 """"The string prefix. "u" for u-prefixed strings and ``None`` otherwise. Python 3.8+ only.""" 

2087 

2088 super().__init__( 

2089 lineno=lineno, 

2090 col_offset=col_offset, 

2091 end_lineno=end_lineno, 

2092 end_col_offset=end_col_offset, 

2093 parent=parent, 

2094 ) 

2095 

2096 Instance.__init__(self, None) 

2097 

2098 infer_unary_op = protocols.const_infer_unary_op 

2099 infer_binary_op = protocols.const_infer_binary_op 

2100 

2101 def __getattr__(self, name): 

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

2103 # Calling object.__new__ on this class without calling 

2104 # __init__ would result in an infinite loop otherwise 

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

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

2107 # and Proxy __getattr__ calls self.value 

2108 if name == "value": 

2109 raise AttributeError 

2110 return super().__getattr__(name) 

2111 

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

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

2114 

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

2116 :type index: Const or Slice 

2117 

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

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

2120 """ 

2121 if isinstance(index, Const): 

2122 index_value = index.value 

2123 elif isinstance(index, Slice): 

2124 index_value = _infer_slice(index, context=context) 

2125 

2126 else: 

2127 raise AstroidTypeError( 

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

2129 ) 

2130 

2131 try: 

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

2133 return Const(self.value[index_value]) 

2134 except ValueError as exc: 

2135 raise AstroidValueError( 

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

2137 ) from exc 

2138 except IndexError as exc: 

2139 raise AstroidIndexError( 

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

2141 node=self, 

2142 index=index, 

2143 context=context, 

2144 ) from exc 

2145 except TypeError as exc: 

2146 raise AstroidTypeError( 

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

2148 ) from exc 

2149 

2150 try: 

2151 value_str = str(self.value) 

2152 except ValueError: 

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

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

2155 

2156 def has_dynamic_getattr(self) -> bool: 

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

2158 

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

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

2161 """ 

2162 return False 

2163 

2164 def itered(self): 

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

2166 

2167 :returns: The contents of this node. 

2168 :rtype: iterable(Const) 

2169 

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

2171 """ 

2172 if isinstance(self.value, str): 

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

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

2175 

2176 def pytype(self) -> str: 

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

2178 

2179 :returns: The name of the type. 

2180 """ 

2181 return self._proxied.qname() 

2182 

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

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

2185 

2186 :returns: The boolean value of this node. 

2187 :rtype: bool or Uninferable 

2188 """ 

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

2190 # and returns True for versions under 3.14 

2191 if self.value is NotImplemented: 

2192 return util.Uninferable if PY314_PLUS else True 

2193 return bool(self.value) 

2194 

2195 def _infer( 

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

2197 ) -> Iterator[Const]: 

2198 yield self 

2199 

2200 

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

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

2203 

2204 >>> import astroid 

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

2206 >>> node 

2207 <Continue l.1 at 0x7f23b2e35588> 

2208 """ 

2209 

2210 

2211class Decorators(NodeNG): 

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

2213 

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

2215 a method or function. 

2216 

2217 >>> import astroid 

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

2219 @property 

2220 def my_property(self): 

2221 return 3 

2222 ''') 

2223 >>> node 

2224 <FunctionDef.my_property l.2 at 0x7f23b2e35d30> 

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

2226 <Decorators l.1 at 0x7f23b2e35d68> 

2227 """ 

2228 

2229 _astroid_fields = ("nodes",) 

2230 

2231 nodes: list[NodeNG] 

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

2233 

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

2235 self.nodes = nodes 

2236 

2237 def scope(self) -> LocalsDictNodeNG: 

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

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

2240 

2241 :returns: The first parent scope node. 

2242 """ 

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

2244 if not self.parent: 

2245 raise ParentMissingError(target=self) 

2246 if not self.parent.parent: 

2247 raise ParentMissingError(target=self.parent) 

2248 return self.parent.parent.scope() 

2249 

2250 def frame(self) -> FrameType: 

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

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

2253 if not self.parent: 

2254 raise ParentMissingError(target=self) 

2255 if not self.parent.parent: 

2256 raise ParentMissingError(target=self.parent) 

2257 return self.parent.parent.frame() 

2258 

2259 def get_children(self): 

2260 yield from self.nodes 

2261 

2262 

2263class DelAttr(_base_nodes.ParentAssignNode): 

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

2265 

2266 >>> import astroid 

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

2268 >>> node 

2269 <Delete l.1 at 0x7f23b2e35f60> 

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

2271 <DelAttr.attr l.1 at 0x7f23b2e411d0> 

2272 """ 

2273 

2274 _astroid_fields = ("expr",) 

2275 _other_fields = ("attrname",) 

2276 

2277 expr: NodeNG 

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

2279 

2280 def __init__( 

2281 self, 

2282 attrname: str, 

2283 lineno: int, 

2284 col_offset: int, 

2285 parent: NodeNG, 

2286 *, 

2287 end_lineno: int | None, 

2288 end_col_offset: int | None, 

2289 ) -> None: 

2290 self.attrname = attrname 

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

2292 

2293 super().__init__( 

2294 lineno=lineno, 

2295 col_offset=col_offset, 

2296 end_lineno=end_lineno, 

2297 end_col_offset=end_col_offset, 

2298 parent=parent, 

2299 ) 

2300 

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

2302 self.expr = expr 

2303 

2304 def get_children(self): 

2305 yield self.expr 

2306 

2307 

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

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

2310 

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

2312 

2313 >>> import astroid 

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

2315 >>> node 

2316 <Delete l.1 at 0x7f23b2e35f60> 

2317 """ 

2318 

2319 _astroid_fields = ("targets",) 

2320 

2321 def __init__( 

2322 self, 

2323 lineno: int, 

2324 col_offset: int, 

2325 parent: NodeNG, 

2326 *, 

2327 end_lineno: int | None, 

2328 end_col_offset: int | None, 

2329 ) -> None: 

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

2331 """What is being deleted.""" 

2332 

2333 super().__init__( 

2334 lineno=lineno, 

2335 col_offset=col_offset, 

2336 end_lineno=end_lineno, 

2337 end_col_offset=end_col_offset, 

2338 parent=parent, 

2339 ) 

2340 

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

2342 self.targets = targets 

2343 

2344 def get_children(self): 

2345 yield from self.targets 

2346 

2347 

2348class Dict(NodeNG, Instance): 

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

2350 

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

2352 

2353 >>> import astroid 

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

2355 >>> node 

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

2357 """ 

2358 

2359 _astroid_fields = ("items",) 

2360 

2361 def __init__( 

2362 self, 

2363 lineno: int | None, 

2364 col_offset: int | None, 

2365 parent: NodeNG | None, 

2366 *, 

2367 end_lineno: int | None, 

2368 end_col_offset: int | None, 

2369 ) -> None: 

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

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

2372 

2373 super().__init__( 

2374 lineno=lineno, 

2375 col_offset=col_offset, 

2376 end_lineno=end_lineno, 

2377 end_col_offset=end_col_offset, 

2378 parent=parent, 

2379 ) 

2380 

2381 def postinit(self, items: list[tuple[InferenceResult, InferenceResult]]) -> None: 

2382 """Do some setup after initialisation. 

2383 

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

2385 """ 

2386 self.items = items 

2387 

2388 infer_unary_op = protocols.dict_infer_unary_op 

2389 

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

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

2392 

2393 :returns: The name of the type. 

2394 """ 

2395 return "builtins.dict" 

2396 

2397 def get_children(self): 

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

2399 

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

2401 code, key first then the value. 

2402 

2403 :returns: The children. 

2404 :rtype: iterable(NodeNG) 

2405 """ 

2406 for key, value in self.items: 

2407 yield key 

2408 yield value 

2409 

2410 def last_child(self): 

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

2412 

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

2414 :rtype: NodeNG or None 

2415 """ 

2416 if self.items: 

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

2418 return None 

2419 

2420 def itered(self): 

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

2422 

2423 :returns: The keys of this node. 

2424 :rtype: iterable(NodeNG) 

2425 """ 

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

2427 

2428 def getitem( 

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

2430 ) -> NodeNG: 

2431 """Get an item from this node. 

2432 

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

2434 

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

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

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

2438 dictionary. 

2439 """ 

2440 for key, value in self.items: 

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

2442 if isinstance(key, DictUnpack): 

2443 inferred_value = util.safe_infer(value, context) 

2444 if not isinstance(inferred_value, Dict): 

2445 continue 

2446 

2447 try: 

2448 return inferred_value.getitem(index, context) 

2449 except (AstroidTypeError, AstroidIndexError): 

2450 continue 

2451 

2452 for inferredkey in key.infer(context): 

2453 if isinstance(inferredkey, util.UninferableBase): 

2454 continue 

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

2456 if inferredkey.value == index.value: 

2457 return value 

2458 

2459 raise AstroidIndexError(index) 

2460 

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

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

2463 

2464 :returns: The boolean value of this node. 

2465 :rtype: bool 

2466 """ 

2467 return bool(self.items) 

2468 

2469 def _infer( 

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

2471 ) -> Iterator[nodes.Dict]: 

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

2473 yield self 

2474 else: 

2475 items = self._infer_map(context) 

2476 new_seq = type(self)( 

2477 lineno=self.lineno, 

2478 col_offset=self.col_offset, 

2479 parent=self.parent, 

2480 end_lineno=self.end_lineno, 

2481 end_col_offset=self.end_col_offset, 

2482 ) 

2483 new_seq.postinit(list(items.items())) 

2484 yield new_seq 

2485 

2486 @staticmethod 

2487 def _update_with_replacement( 

2488 lhs_dict: dict[SuccessfulInferenceResult, SuccessfulInferenceResult], 

2489 rhs_dict: dict[SuccessfulInferenceResult, SuccessfulInferenceResult], 

2490 ) -> dict[SuccessfulInferenceResult, SuccessfulInferenceResult]: 

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

2492 

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

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

2495 don't get through 

2496 

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

2498 

2499 Fixes issue with DictUnpack causing duplicate keys 

2500 in inferred Dict items 

2501 

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

2503 :param rhs_dict: Dictionary with nodes to pull from 

2504 :return : merged dictionary of nodes 

2505 """ 

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

2507 # Overwrite keys which have the same string values 

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

2509 # Return to dictionary 

2510 return dict(string_map.values()) 

2511 

2512 def _infer_map( 

2513 self, context: InferenceContext | None 

2514 ) -> dict[SuccessfulInferenceResult, SuccessfulInferenceResult]: 

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

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

2517 for name, value in self.items: 

2518 if isinstance(name, DictUnpack): 

2519 double_starred = util.safe_infer(value, context) 

2520 if not double_starred: 

2521 raise InferenceError 

2522 if not isinstance(double_starred, Dict): 

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

2524 unpack_items = double_starred._infer_map(context) 

2525 values = self._update_with_replacement(values, unpack_items) 

2526 else: 

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

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

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

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

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

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

2533 return values 

2534 

2535 

2536class Expr(_base_nodes.Statement): 

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

2538 

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

2540 stored. 

2541 

2542 >>> import astroid 

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

2544 >>> node 

2545 <Call l.1 at 0x7f23b2e352b0> 

2546 >>> node.parent 

2547 <Expr l.1 at 0x7f23b2e35278> 

2548 """ 

2549 

2550 _astroid_fields = ("value",) 

2551 

2552 value: NodeNG 

2553 """What the expression does.""" 

2554 

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

2556 self.value = value 

2557 

2558 def get_children(self): 

2559 yield self.value 

2560 

2561 def _get_yield_nodes_skip_functions(self): 

2562 if not self.value.is_function: 

2563 yield from self.value._get_yield_nodes_skip_functions() 

2564 

2565 def _get_yield_nodes_skip_lambdas(self): 

2566 if not self.value.is_lambda: 

2567 yield from self.value._get_yield_nodes_skip_lambdas() 

2568 

2569 

2570class EmptyNode(_base_nodes.NoChildrenNode): 

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

2572 

2573 object = None 

2574 

2575 def __init__( 

2576 self, 

2577 lineno: None = None, 

2578 col_offset: None = None, 

2579 parent: NodeNG = SYNTHETIC_ROOT, 

2580 *, 

2581 end_lineno: None = None, 

2582 end_col_offset: None = None, 

2583 ) -> None: 

2584 super().__init__( 

2585 lineno=lineno, 

2586 col_offset=col_offset, 

2587 end_lineno=end_lineno, 

2588 end_col_offset=end_col_offset, 

2589 parent=parent, 

2590 ) 

2591 

2592 def has_underlying_object(self) -> bool: 

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

2594 

2595 @decorators.raise_if_nothing_inferred 

2596 @decorators.path_wrapper 

2597 def _infer( 

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

2599 ) -> Generator[InferenceResult]: 

2600 if not self.has_underlying_object(): 

2601 yield util.Uninferable 

2602 else: 

2603 try: 

2604 yield from AstroidManager().infer_ast_from_something( 

2605 self.object, context=context 

2606 ) 

2607 except AstroidError: 

2608 yield util.Uninferable 

2609 

2610 

2611class ExceptHandler( 

2612 _base_nodes.MultiLineBlockNode, _base_nodes.AssignTypeNode, _base_nodes.Statement 

2613): 

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

2615 

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

2617 

2618 >>> import astroid 

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

2620 try: 

2621 do_something() 

2622 except Exception as error: 

2623 print("Error!") 

2624 ''') 

2625 >>> node 

2626 <Try l.2 at 0x7f23b2e9d908> 

2627 >>> node.handlers 

2628 [<ExceptHandler l.4 at 0x7f23b2e9e860>] 

2629 """ 

2630 

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

2632 _multi_line_block_fields = ("body",) 

2633 

2634 type: NodeNG | None 

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

2636 

2637 name: AssignName | None 

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

2639 

2640 body: list[NodeNG] 

2641 """The contents of the block.""" 

2642 

2643 assigned_stmts = protocols.excepthandler_assigned_stmts 

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

2645 See astroid/protocols.py for actual implementation. 

2646 """ 

2647 

2648 def postinit( 

2649 self, 

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

2651 name: AssignName | None, 

2652 body: list[NodeNG], 

2653 ) -> None: 

2654 self.type = type 

2655 self.name = name 

2656 self.body = body 

2657 

2658 def get_children(self): 

2659 if self.type is not None: 

2660 yield self.type 

2661 

2662 if self.name is not None: 

2663 yield self.name 

2664 

2665 yield from self.body 

2666 

2667 @cached_property 

2668 def blockstart_tolineno(self): 

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

2670 

2671 :type: int 

2672 """ 

2673 if self.name: 

2674 return self.name.tolineno 

2675 if self.type: 

2676 return self.type.tolineno 

2677 return self.lineno 

2678 

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

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

2681 

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

2683 """ 

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

2685 return True 

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

2687 

2688 

2689class For( 

2690 _base_nodes.MultiLineWithElseBlockNode, 

2691 _base_nodes.AssignTypeNode, 

2692 _base_nodes.Statement, 

2693): 

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

2695 

2696 >>> import astroid 

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

2698 >>> node 

2699 <For l.1 at 0x7f23b2e8cf28> 

2700 """ 

2701 

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

2703 _other_other_fields = ("type_annotation",) 

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

2705 

2706 optional_assign = True 

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

2708 

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

2710 """ 

2711 

2712 target: NodeNG 

2713 """What the loop assigns to.""" 

2714 

2715 iter: NodeNG 

2716 """What the loop iterates over.""" 

2717 

2718 body: list[NodeNG] 

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

2720 

2721 orelse: list[NodeNG] 

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

2723 

2724 type_annotation: NodeNG | None 

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

2726 

2727 def postinit( 

2728 self, 

2729 target: NodeNG, 

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

2731 body: list[NodeNG], 

2732 orelse: list[NodeNG], 

2733 type_annotation: NodeNG | None, 

2734 ) -> None: 

2735 self.target = target 

2736 self.iter = iter 

2737 self.body = body 

2738 self.orelse = orelse 

2739 self.type_annotation = type_annotation 

2740 

2741 assigned_stmts = protocols.for_assigned_stmts 

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

2743 See astroid/protocols.py for actual implementation. 

2744 """ 

2745 

2746 @cached_property 

2747 def blockstart_tolineno(self): 

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

2749 

2750 :type: int 

2751 """ 

2752 return self.iter.tolineno 

2753 

2754 def get_children(self): 

2755 yield self.target 

2756 yield self.iter 

2757 

2758 yield from self.body 

2759 yield from self.orelse 

2760 

2761 

2762class AsyncFor(For): 

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

2764 

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

2766 the ``async`` keyword. 

2767 

2768 >>> import astroid 

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

2770 async def func(things): 

2771 async for thing in things: 

2772 print(thing) 

2773 ''') 

2774 >>> node 

2775 <AsyncFunctionDef.func l.2 at 0x7f23b2e416d8> 

2776 >>> node.body[0] 

2777 <AsyncFor l.3 at 0x7f23b2e417b8> 

2778 """ 

2779 

2780 

2781class Await(NodeNG): 

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

2783 

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

2785 

2786 >>> import astroid 

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

2788 async def func(things): 

2789 await other_func() 

2790 ''') 

2791 >>> node 

2792 <AsyncFunctionDef.func l.2 at 0x7f23b2e41748> 

2793 >>> node.body[0] 

2794 <Expr l.3 at 0x7f23b2e419e8> 

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

2796 <Await l.3 at 0x7f23b2e41a20> 

2797 """ 

2798 

2799 _astroid_fields = ("value",) 

2800 

2801 value: NodeNG 

2802 """What to wait for.""" 

2803 

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

2805 self.value = value 

2806 

2807 def get_children(self): 

2808 yield self.value 

2809 

2810 

2811class ImportFrom(_base_nodes.ImportNode): 

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

2813 

2814 >>> import astroid 

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

2816 >>> node 

2817 <ImportFrom l.1 at 0x7f23b2e415c0> 

2818 """ 

2819 

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

2821 

2822 def __init__( 

2823 self, 

2824 fromname: str | None, 

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

2826 level: int | None = 0, 

2827 lineno: int | None = None, 

2828 col_offset: int | None = None, 

2829 parent: NodeNG | None = None, 

2830 *, 

2831 end_lineno: int | None = None, 

2832 end_col_offset: int | None = None, 

2833 ) -> None: 

2834 """ 

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

2836 

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

2838 

2839 :param level: The level of relative import. 

2840 

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

2842 

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

2844 source code. 

2845 

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

2847 

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

2849 

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

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

2852 """ 

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

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

2855 

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

2857 """ 

2858 

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

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

2861 

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

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

2864 """ 

2865 

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

2867 """The level of relative import. 

2868 

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

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

2871 """ 

2872 

2873 super().__init__( 

2874 lineno=lineno, 

2875 col_offset=col_offset, 

2876 end_lineno=end_lineno, 

2877 end_col_offset=end_col_offset, 

2878 parent=parent, 

2879 ) 

2880 

2881 @decorators.raise_if_nothing_inferred 

2882 @decorators.path_wrapper 

2883 def _infer( 

2884 self, 

2885 context: InferenceContext | None = None, 

2886 asname: bool = True, 

2887 **kwargs: Any, 

2888 ) -> Generator[InferenceResult]: 

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

2890 context = context or InferenceContext() 

2891 name = context.lookupname 

2892 if name is None: 

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

2894 if asname: 

2895 try: 

2896 name = self.real_name(name) 

2897 except AttributeInferenceError as exc: 

2898 # See https://github.com/pylint-dev/pylint/issues/4692 

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

2900 try: 

2901 module = self.do_import_module() 

2902 except AstroidBuildingError as exc: 

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

2904 

2905 try: 

2906 context = copy_context(context) 

2907 context.lookupname = name 

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

2909 return _infer_stmts(stmts, context) 

2910 except AttributeInferenceError as error: 

2911 raise InferenceError( 

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

2913 ) from error 

2914 

2915 

2916class Attribute(NodeNG): 

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

2918 

2919 expr: NodeNG 

2920 

2921 _astroid_fields = ("expr",) 

2922 _other_fields = ("attrname",) 

2923 

2924 def __init__( 

2925 self, 

2926 attrname: str, 

2927 lineno: int, 

2928 col_offset: int, 

2929 parent: NodeNG, 

2930 *, 

2931 end_lineno: int | None, 

2932 end_col_offset: int | None, 

2933 ) -> None: 

2934 self.attrname = attrname 

2935 """The name of the attribute.""" 

2936 

2937 super().__init__( 

2938 lineno=lineno, 

2939 col_offset=col_offset, 

2940 end_lineno=end_lineno, 

2941 end_col_offset=end_col_offset, 

2942 parent=parent, 

2943 ) 

2944 

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

2946 self.expr = expr 

2947 

2948 def get_children(self): 

2949 yield self.expr 

2950 

2951 @decorators.raise_if_nothing_inferred 

2952 @decorators.path_wrapper 

2953 def _infer( 

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

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

2956 return _infer_attribute(self, context, **kwargs) 

2957 

2958 

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

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

2961 

2962 >>> import astroid 

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

2964 >>> node 

2965 <Global l.1 at 0x7f23b2e9de10> 

2966 """ 

2967 

2968 _other_fields = ("names",) 

2969 

2970 def __init__( 

2971 self, 

2972 names: list[str], 

2973 lineno: int | None = None, 

2974 col_offset: int | None = None, 

2975 parent: NodeNG | None = None, 

2976 *, 

2977 end_lineno: int | None = None, 

2978 end_col_offset: int | None = None, 

2979 ) -> None: 

2980 """ 

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

2982 

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

2984 

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

2986 source code. 

2987 

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

2989 

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

2991 

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

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

2994 """ 

2995 self.names: list[str] = names 

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

2997 

2998 super().__init__( 

2999 lineno=lineno, 

3000 col_offset=col_offset, 

3001 end_lineno=end_lineno, 

3002 end_col_offset=end_col_offset, 

3003 parent=parent, 

3004 ) 

3005 

3006 def _infer_name(self, frame, name): 

3007 return name 

3008 

3009 @decorators.raise_if_nothing_inferred 

3010 @decorators.path_wrapper 

3011 def _infer( 

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

3013 ) -> Generator[InferenceResult]: 

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

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

3016 try: 

3017 # pylint: disable-next=no-member 

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

3019 except AttributeInferenceError as error: 

3020 raise InferenceError( 

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

3022 ) from error 

3023 

3024 

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

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

3027 

3028 >>> import astroid 

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

3030 >>> node 

3031 <If l.1 at 0x7f23b2e9dd30> 

3032 """ 

3033 

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

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

3036 

3037 test: NodeNG 

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

3039 

3040 body: list[NodeNG] 

3041 """The contents of the block.""" 

3042 

3043 orelse: list[NodeNG] 

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

3045 

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

3047 self.test = test 

3048 self.body = body 

3049 self.orelse = orelse 

3050 

3051 @cached_property 

3052 def blockstart_tolineno(self): 

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

3054 

3055 :type: int 

3056 """ 

3057 return self.test.tolineno 

3058 

3059 def get_children(self): 

3060 yield self.test 

3061 

3062 yield from self.body 

3063 yield from self.orelse 

3064 

3065 def has_elif_block(self) -> bool: 

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

3067 

3068 def _get_yield_nodes_skip_functions(self): 

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

3070 yield from self.test._get_yield_nodes_skip_functions() 

3071 yield from super()._get_yield_nodes_skip_functions() 

3072 

3073 def _get_yield_nodes_skip_lambdas(self): 

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

3075 yield from self.test._get_yield_nodes_skip_lambdas() 

3076 yield from super()._get_yield_nodes_skip_lambdas() 

3077 

3078 

3079class IfExp(NodeNG): 

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

3081 >>> import astroid 

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

3083 >>> node 

3084 <IfExp l.1 at 0x7f23b2e9dbe0> 

3085 """ 

3086 

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

3088 

3089 test: NodeNG 

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

3091 

3092 body: NodeNG 

3093 """The contents of the block.""" 

3094 

3095 orelse: NodeNG 

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

3097 

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

3099 self.test = test 

3100 self.body = body 

3101 self.orelse = orelse 

3102 

3103 def get_children(self): 

3104 yield self.test 

3105 yield self.body 

3106 yield self.orelse 

3107 

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

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

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

3111 return False 

3112 

3113 @decorators.raise_if_nothing_inferred 

3114 def _infer( 

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

3116 ) -> Generator[InferenceResult]: 

3117 """Support IfExp inference. 

3118 

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

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

3121 depending on the condition. 

3122 """ 

3123 

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

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

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

3127 context = context or InferenceContext() 

3128 lhs_context = copy_context(context) 

3129 rhs_context = copy_context(context) 

3130 

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

3132 # evaluating both branches. 

3133 condition: bool | None = None 

3134 try: 

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

3136 if isinstance(test, util.UninferableBase): 

3137 condition = None 

3138 break 

3139 test_bool_value = test.bool_value() 

3140 if isinstance(test_bool_value, util.UninferableBase): 

3141 condition = None 

3142 break 

3143 if condition is None: 

3144 condition = test_bool_value 

3145 elif test_bool_value != condition: 

3146 condition = None 

3147 break 

3148 except InferenceError: 

3149 condition = None 

3150 

3151 if condition is True or condition is None: 

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

3153 if condition is False or condition is None: 

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

3155 

3156 

3157class Import(_base_nodes.ImportNode): 

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

3159 >>> import astroid 

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

3161 >>> node 

3162 <Import l.1 at 0x7f23b2e4e5c0> 

3163 """ 

3164 

3165 _other_fields = ("names",) 

3166 

3167 def __init__( 

3168 self, 

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

3170 lineno: int | None = None, 

3171 col_offset: int | None = None, 

3172 parent: NodeNG | None = None, 

3173 *, 

3174 end_lineno: int | None = None, 

3175 end_col_offset: int | None = None, 

3176 ) -> None: 

3177 """ 

3178 :param names: The names being imported. 

3179 

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

3181 

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

3183 source code. 

3184 

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

3186 

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

3188 

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

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

3191 """ 

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

3193 """The names being imported. 

3194 

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

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

3197 """ 

3198 

3199 super().__init__( 

3200 lineno=lineno, 

3201 col_offset=col_offset, 

3202 end_lineno=end_lineno, 

3203 end_col_offset=end_col_offset, 

3204 parent=parent, 

3205 ) 

3206 

3207 @decorators.raise_if_nothing_inferred 

3208 @decorators.path_wrapper 

3209 def _infer( 

3210 self, 

3211 context: InferenceContext | None = None, 

3212 asname: bool = True, 

3213 **kwargs: Any, 

3214 ) -> Generator[nodes.Module]: 

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

3216 context = context or InferenceContext() 

3217 name = context.lookupname 

3218 if name is None: 

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

3220 

3221 try: 

3222 if asname: 

3223 yield self.do_import_module(self.real_name(name)) 

3224 else: 

3225 yield self.do_import_module(name) 

3226 except AstroidBuildingError as exc: 

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

3228 

3229 

3230class Keyword(NodeNG): 

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

3232 

3233 >>> import astroid 

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

3235 >>> node 

3236 <Call l.1 at 0x7f23b2e9e320> 

3237 >>> node.keywords 

3238 [<Keyword l.1 at 0x7f23b2e9e9b0>] 

3239 """ 

3240 

3241 _astroid_fields = ("value",) 

3242 _other_fields = ("arg",) 

3243 

3244 value: NodeNG 

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

3246 

3247 def __init__( 

3248 self, 

3249 arg: str | None, 

3250 lineno: int | None, 

3251 col_offset: int | None, 

3252 parent: NodeNG, 

3253 *, 

3254 end_lineno: int | None, 

3255 end_col_offset: int | None, 

3256 ) -> None: 

3257 self.arg = arg 

3258 """The argument being assigned to.""" 

3259 

3260 super().__init__( 

3261 lineno=lineno, 

3262 col_offset=col_offset, 

3263 end_lineno=end_lineno, 

3264 end_col_offset=end_col_offset, 

3265 parent=parent, 

3266 ) 

3267 

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

3269 self.value = value 

3270 

3271 def get_children(self): 

3272 yield self.value 

3273 

3274 

3275class List(BaseContainer): 

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

3277 

3278 >>> import astroid 

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

3280 >>> node 

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

3282 """ 

3283 

3284 _other_fields = ("ctx",) 

3285 

3286 def __init__( 

3287 self, 

3288 ctx: Context | None = None, 

3289 lineno: int | None = None, 

3290 col_offset: int | None = None, 

3291 parent: NodeNG | None = None, 

3292 *, 

3293 end_lineno: int | None = None, 

3294 end_col_offset: int | None = None, 

3295 ) -> None: 

3296 """ 

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

3298 

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

3300 

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

3302 source code. 

3303 

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

3305 

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

3307 

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

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

3310 """ 

3311 self.ctx: Context | None = ctx 

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

3313 

3314 super().__init__( 

3315 lineno=lineno, 

3316 col_offset=col_offset, 

3317 end_lineno=end_lineno, 

3318 end_col_offset=end_col_offset, 

3319 parent=parent, 

3320 ) 

3321 

3322 assigned_stmts = protocols.sequence_assigned_stmts 

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

3324 See astroid/protocols.py for actual implementation. 

3325 """ 

3326 

3327 infer_unary_op = protocols.list_infer_unary_op 

3328 infer_binary_op = protocols.tl_infer_binary_op 

3329 

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

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

3332 

3333 :returns: The name of the type. 

3334 """ 

3335 return "builtins.list" 

3336 

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

3338 """Get an item from this node. 

3339 

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

3341 :type index: Const or Slice 

3342 """ 

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

3344 

3345 

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

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

3348 

3349 >>> import astroid 

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

3351 def function(): 

3352 nonlocal var 

3353 ''') 

3354 >>> node 

3355 <FunctionDef.function l.2 at 0x7f23b2e9e208> 

3356 >>> node.body[0] 

3357 <Nonlocal l.3 at 0x7f23b2e9e908> 

3358 """ 

3359 

3360 _other_fields = ("names",) 

3361 

3362 def __init__( 

3363 self, 

3364 names: list[str], 

3365 lineno: int | None = None, 

3366 col_offset: int | None = None, 

3367 parent: NodeNG | None = None, 

3368 *, 

3369 end_lineno: int | None = None, 

3370 end_col_offset: int | None = None, 

3371 ) -> None: 

3372 """ 

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

3374 

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

3376 

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

3378 source code. 

3379 

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

3381 

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

3383 

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

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

3386 """ 

3387 self.names: list[str] = names 

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

3389 

3390 super().__init__( 

3391 lineno=lineno, 

3392 col_offset=col_offset, 

3393 end_lineno=end_lineno, 

3394 end_col_offset=end_col_offset, 

3395 parent=parent, 

3396 ) 

3397 

3398 def _infer_name(self, frame, name): 

3399 return name 

3400 

3401 

3402class ParamSpec(_base_nodes.AssignTypeNode): 

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

3404 

3405 >>> import astroid 

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

3407 >>> node.type_params[0] 

3408 <ParamSpec l.1 at 0x7f23b2e4e198> 

3409 """ 

3410 

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

3412 name: AssignName 

3413 default_value: NodeNG | None 

3414 

3415 def __init__( 

3416 self, 

3417 lineno: int, 

3418 col_offset: int, 

3419 parent: NodeNG, 

3420 *, 

3421 end_lineno: int, 

3422 end_col_offset: int, 

3423 ) -> None: 

3424 super().__init__( 

3425 lineno=lineno, 

3426 col_offset=col_offset, 

3427 end_lineno=end_lineno, 

3428 end_col_offset=end_col_offset, 

3429 parent=parent, 

3430 ) 

3431 

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

3433 self.name = name 

3434 self.default_value = default_value 

3435 

3436 def _infer( 

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

3438 ) -> Iterator[ParamSpec]: 

3439 yield self 

3440 

3441 assigned_stmts = protocols.generic_type_assigned_stmts 

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

3443 See astroid/protocols.py for actual implementation. 

3444 """ 

3445 

3446 

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

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

3449 

3450 >>> import astroid 

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

3452 >>> node 

3453 <Pass l.1 at 0x7f23b2e9e748> 

3454 """ 

3455 

3456 

3457class Raise(_base_nodes.Statement): 

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

3459 

3460 >>> import astroid 

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

3462 >>> node 

3463 <Raise l.1 at 0x7f23b2e9e828> 

3464 """ 

3465 

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

3467 

3468 exc: NodeNG | None 

3469 """What is being raised.""" 

3470 

3471 cause: NodeNG | None 

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

3473 

3474 def postinit( 

3475 self, 

3476 exc: NodeNG | None, 

3477 cause: NodeNG | None, 

3478 ) -> None: 

3479 self.exc = exc 

3480 self.cause = cause 

3481 

3482 def raises_not_implemented(self) -> bool: 

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

3484 

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

3486 """ 

3487 if not self.exc: 

3488 return False 

3489 return any( 

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

3491 ) 

3492 

3493 def get_children(self): 

3494 if self.exc is not None: 

3495 yield self.exc 

3496 

3497 if self.cause is not None: 

3498 yield self.cause 

3499 

3500 

3501class Return(_base_nodes.Statement): 

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

3503 

3504 >>> import astroid 

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

3506 >>> node 

3507 <Return l.1 at 0x7f23b8211908> 

3508 """ 

3509 

3510 _astroid_fields = ("value",) 

3511 

3512 value: NodeNG | None 

3513 """The value being returned.""" 

3514 

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

3516 self.value = value 

3517 

3518 def get_children(self): 

3519 if self.value is not None: 

3520 yield self.value 

3521 

3522 def is_tuple_return(self) -> bool: 

3523 return isinstance(self.value, Tuple) 

3524 

3525 def _get_return_nodes_skip_functions(self): 

3526 yield self 

3527 

3528 

3529class Set(BaseContainer): 

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

3531 

3532 >>> import astroid 

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

3534 >>> node 

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

3536 """ 

3537 

3538 infer_unary_op = protocols.set_infer_unary_op 

3539 

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

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

3542 

3543 :returns: The name of the type. 

3544 """ 

3545 return "builtins.set" 

3546 

3547 

3548class Slice(NodeNG): 

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

3550 

3551 >>> import astroid 

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

3553 >>> node 

3554 <Subscript l.1 at 0x7f23b2e71f60> 

3555 >>> node.slice 

3556 <Slice l.1 at 0x7f23b2e71e80> 

3557 """ 

3558 

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

3560 

3561 lower: NodeNG | None 

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

3563 

3564 upper: NodeNG | None 

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

3566 

3567 step: NodeNG | None 

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

3569 

3570 def postinit( 

3571 self, 

3572 lower: NodeNG | None, 

3573 upper: NodeNG | None, 

3574 step: NodeNG | None, 

3575 ) -> None: 

3576 self.lower = lower 

3577 self.upper = upper 

3578 self.step = step 

3579 

3580 def _wrap_attribute(self, attr): 

3581 """Wrap the empty attributes of the Slice in a Const node.""" 

3582 if not attr: 

3583 const = const_factory(attr) 

3584 const.parent = self 

3585 return const 

3586 return attr 

3587 

3588 @cached_property 

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

3590 builtins = AstroidManager().builtins_module 

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

3592 

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

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

3595 

3596 :returns: The name of the type. 

3597 """ 

3598 return "builtins.slice" 

3599 

3600 def display_type(self) -> Literal["Slice"]: 

3601 """A human readable type of this node. 

3602 

3603 :returns: The type of this node. 

3604 """ 

3605 return "Slice" 

3606 

3607 def igetattr( 

3608 self, attrname: str, context: InferenceContext | None = None 

3609 ) -> Iterator[SuccessfulInferenceResult]: 

3610 """Infer the possible values of the given attribute on the slice. 

3611 

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

3613 

3614 :returns: The inferred possible values. 

3615 """ 

3616 if attrname == "start": 

3617 yield self._wrap_attribute(self.lower) 

3618 elif attrname == "stop": 

3619 yield self._wrap_attribute(self.upper) 

3620 elif attrname == "step": 

3621 yield self._wrap_attribute(self.step) 

3622 else: 

3623 yield from self.getattr(attrname, context=context) 

3624 

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

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

3627 

3628 def get_children(self): 

3629 if self.lower is not None: 

3630 yield self.lower 

3631 

3632 if self.upper is not None: 

3633 yield self.upper 

3634 

3635 if self.step is not None: 

3636 yield self.step 

3637 

3638 def _infer( 

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

3640 ) -> Iterator[Slice]: 

3641 yield self 

3642 

3643 

3644class Starred(_base_nodes.ParentAssignNode): 

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

3646 

3647 >>> import astroid 

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

3649 >>> node 

3650 <Starred l.1 at 0x7f23b2e41978> 

3651 """ 

3652 

3653 _astroid_fields = ("value",) 

3654 _other_fields = ("ctx",) 

3655 

3656 value: NodeNG 

3657 """What is being unpacked.""" 

3658 

3659 def __init__( 

3660 self, 

3661 ctx: Context, 

3662 lineno: int, 

3663 col_offset: int, 

3664 parent: NodeNG, 

3665 *, 

3666 end_lineno: int | None, 

3667 end_col_offset: int | None, 

3668 ) -> None: 

3669 self.ctx = ctx 

3670 """Whether the starred item is assigned to or loaded from.""" 

3671 

3672 super().__init__( 

3673 lineno=lineno, 

3674 col_offset=col_offset, 

3675 end_lineno=end_lineno, 

3676 end_col_offset=end_col_offset, 

3677 parent=parent, 

3678 ) 

3679 

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

3681 self.value = value 

3682 

3683 assigned_stmts = protocols.starred_assigned_stmts 

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

3685 See astroid/protocols.py for actual implementation. 

3686 """ 

3687 

3688 def get_children(self): 

3689 yield self.value 

3690 

3691 

3692class Subscript(NodeNG): 

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

3694 

3695 >>> import astroid 

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

3697 >>> node 

3698 <Subscript l.1 at 0x7f23b2e71f60> 

3699 """ 

3700 

3701 _SUBSCRIPT_SENTINEL = object() 

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

3703 _other_fields = ("ctx",) 

3704 

3705 value: NodeNG 

3706 """What is being indexed.""" 

3707 

3708 slice: NodeNG 

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

3710 

3711 def __init__( 

3712 self, 

3713 ctx: Context, 

3714 lineno: int, 

3715 col_offset: int, 

3716 parent: NodeNG, 

3717 *, 

3718 end_lineno: int | None, 

3719 end_col_offset: int | None, 

3720 ) -> None: 

3721 self.ctx = ctx 

3722 """Whether the subscripted item is assigned to or loaded from.""" 

3723 

3724 super().__init__( 

3725 lineno=lineno, 

3726 col_offset=col_offset, 

3727 end_lineno=end_lineno, 

3728 end_col_offset=end_col_offset, 

3729 parent=parent, 

3730 ) 

3731 

3732 # pylint: disable=redefined-builtin; had to use the same name as builtin ast module. 

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

3734 self.value = value 

3735 self.slice = slice 

3736 

3737 def get_children(self): 

3738 yield self.value 

3739 yield self.slice 

3740 

3741 def _infer_subscript( 

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

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

3744 """Inference for subscripts. 

3745 

3746 We're understanding if the index is a Const 

3747 or a slice, passing the result of inference 

3748 to the value's `getitem` method, which should 

3749 handle each supported index type accordingly. 

3750 """ 

3751 from astroid import helpers # pylint: disable=import-outside-toplevel 

3752 

3753 found_one = False 

3754 for value in self.value.infer(context): 

3755 if isinstance(value, util.UninferableBase): 

3756 yield util.Uninferable 

3757 return None 

3758 for index in self.slice.infer(context): 

3759 if isinstance(index, util.UninferableBase): 

3760 yield util.Uninferable 

3761 return None 

3762 

3763 # Try to deduce the index value. 

3764 index_value = self._SUBSCRIPT_SENTINEL 

3765 if value.__class__ == Instance: 

3766 index_value = index 

3767 elif index.__class__ == Instance: 

3768 instance_as_index = helpers.class_instance_as_index(index) 

3769 if instance_as_index: 

3770 index_value = instance_as_index 

3771 else: 

3772 index_value = index 

3773 

3774 if index_value is self._SUBSCRIPT_SENTINEL: 

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

3776 

3777 try: 

3778 assigned = value.getitem(index_value, context) 

3779 except ( 

3780 AstroidTypeError, 

3781 AstroidIndexError, 

3782 AstroidValueError, 

3783 AttributeInferenceError, 

3784 AttributeError, 

3785 ) as exc: 

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

3787 

3788 # Prevent inferring if the inferred subscript 

3789 # is the same as the original subscripted object. 

3790 if self is assigned or isinstance(assigned, util.UninferableBase): 

3791 yield util.Uninferable 

3792 return None 

3793 yield from assigned.infer(context) 

3794 found_one = True 

3795 

3796 if found_one: 

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

3798 return None 

3799 

3800 @decorators.raise_if_nothing_inferred 

3801 @decorators.path_wrapper 

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

3803 return self._infer_subscript(context, **kwargs) 

3804 

3805 @decorators.raise_if_nothing_inferred 

3806 def infer_lhs(self, context: InferenceContext | None = None, **kwargs: Any): 

3807 return self._infer_subscript(context, **kwargs) 

3808 

3809 

3810class Try(_base_nodes.MultiLineWithElseBlockNode, _base_nodes.Statement): 

3811 """Class representing a :class:`ast.Try` node. 

3812 

3813 >>> import astroid 

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

3815 try: 

3816 do_something() 

3817 except Exception as error: 

3818 print("Error!") 

3819 finally: 

3820 print("Cleanup!") 

3821 ''') 

3822 >>> node 

3823 <Try l.2 at 0x7f23b2e41d68> 

3824 """ 

3825 

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

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

3828 

3829 def __init__( 

3830 self, 

3831 *, 

3832 lineno: int, 

3833 col_offset: int, 

3834 end_lineno: int, 

3835 end_col_offset: int, 

3836 parent: NodeNG, 

3837 ) -> None: 

3838 """ 

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

3840 

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

3842 source code. 

3843 

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

3845 

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

3847 

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

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

3850 """ 

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

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

3853 

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

3855 """The exception handlers.""" 

3856 

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

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

3859 

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

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

3862 

3863 super().__init__( 

3864 lineno=lineno, 

3865 col_offset=col_offset, 

3866 end_lineno=end_lineno, 

3867 end_col_offset=end_col_offset, 

3868 parent=parent, 

3869 ) 

3870 

3871 def postinit( 

3872 self, 

3873 *, 

3874 body: list[NodeNG], 

3875 handlers: list[ExceptHandler], 

3876 orelse: list[NodeNG], 

3877 finalbody: list[NodeNG], 

3878 ) -> None: 

3879 """Do some setup after initialisation. 

3880 

3881 :param body: The contents of the block to catch exceptions from. 

3882 

3883 :param handlers: The exception handlers. 

3884 

3885 :param orelse: The contents of the ``else`` block. 

3886 

3887 :param finalbody: The contents of the ``finally`` block. 

3888 """ 

3889 self.body = body 

3890 self.handlers = handlers 

3891 self.orelse = orelse 

3892 self.finalbody = finalbody 

3893 

3894 def _infer_name(self, frame, name): 

3895 return name 

3896 

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

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

3899 for exhandler in self.handlers: 

3900 if exhandler.type and lineno == exhandler.type.fromlineno: 

3901 return lineno, exhandler.tolineno 

3902 if exhandler.body[0].fromlineno <= lineno <= exhandler.body[-1].tolineno: 

3903 return lineno, exhandler.body[-1].tolineno 

3904 if self.finalbody: 

3905 if self.finalbody[0].fromlineno - 1 == lineno: 

3906 return lineno, self.finalbody[0].tolineno 

3907 if self.finalbody[0].fromlineno <= lineno <= self.finalbody[-1].tolineno: 

3908 return lineno, self.finalbody[-1].tolineno 

3909 

3910 # If not within any of the ExceptHandlers or `finally` body, fall back to regular 

3911 # handling of block_range for nodes with a potential `else` statement. 

3912 return super().block_range(lineno) 

3913 

3914 def get_children(self): 

3915 yield from self.body 

3916 yield from self.handlers 

3917 yield from self.orelse 

3918 yield from self.finalbody 

3919 

3920 

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

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

3923 

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

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

3926 

3927 def __init__( 

3928 self, 

3929 *, 

3930 lineno: int | None = None, 

3931 col_offset: int | None = None, 

3932 end_lineno: int | None = None, 

3933 end_col_offset: int | None = None, 

3934 parent: NodeNG | None = None, 

3935 ) -> None: 

3936 """ 

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

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

3939 source code. 

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

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

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

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

3944 """ 

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

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

3947 

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

3949 """The exception handlers.""" 

3950 

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

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

3953 

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

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

3956 

3957 super().__init__( 

3958 lineno=lineno, 

3959 col_offset=col_offset, 

3960 end_lineno=end_lineno, 

3961 end_col_offset=end_col_offset, 

3962 parent=parent, 

3963 ) 

3964 

3965 def postinit( 

3966 self, 

3967 *, 

3968 body: list[NodeNG] | None = None, 

3969 handlers: list[ExceptHandler] | None = None, 

3970 orelse: list[NodeNG] | None = None, 

3971 finalbody: list[NodeNG] | None = None, 

3972 ) -> None: 

3973 """Do some setup after initialisation. 

3974 :param body: The contents of the block to catch exceptions from. 

3975 :param handlers: The exception handlers. 

3976 :param orelse: The contents of the ``else`` block. 

3977 :param finalbody: The contents of the ``finally`` block. 

3978 """ 

3979 if body: 

3980 self.body = body 

3981 if handlers: 

3982 self.handlers = handlers 

3983 if orelse: 

3984 self.orelse = orelse 

3985 if finalbody: 

3986 self.finalbody = finalbody 

3987 

3988 def _infer_name(self, frame, name): 

3989 return name 

3990 

3991 def get_children(self): 

3992 yield from self.body 

3993 yield from self.handlers 

3994 yield from self.orelse 

3995 yield from self.finalbody 

3996 

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

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

3999 for exhandler in self.handlers: 

4000 if exhandler.type and lineno == exhandler.type.fromlineno: 

4001 return lineno, exhandler.tolineno 

4002 if exhandler.body[0].fromlineno <= lineno <= exhandler.body[-1].tolineno: 

4003 return lineno, exhandler.body[-1].tolineno 

4004 if self.finalbody: 

4005 if self.finalbody[0].fromlineno - 1 == lineno: 

4006 return lineno, self.finalbody[0].tolineno 

4007 if self.finalbody[0].fromlineno <= lineno <= self.finalbody[-1].tolineno: 

4008 return lineno, self.finalbody[-1].tolineno 

4009 

4010 # If not within any of the ExceptHandlers or `finally` body, fall back to regular 

4011 # handling of block_range for nodes with a potential `else` statement. 

4012 return super().block_range(lineno) 

4013 

4014 

4015class Tuple(BaseContainer): 

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

4017 

4018 >>> import astroid 

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

4020 >>> node 

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

4022 """ 

4023 

4024 _other_fields = ("ctx",) 

4025 

4026 def __init__( 

4027 self, 

4028 ctx: Context | None = None, 

4029 lineno: int | None = None, 

4030 col_offset: int | None = None, 

4031 parent: NodeNG | None = None, 

4032 *, 

4033 end_lineno: int | None = None, 

4034 end_col_offset: int | None = None, 

4035 ) -> None: 

4036 """ 

4037 :param ctx: Whether the tuple is assigned to or loaded from. 

4038 

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

4040 

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

4042 source code. 

4043 

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

4045 

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

4047 

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

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

4050 """ 

4051 self.ctx: Context | None = ctx 

4052 """Whether the tuple is assigned to or loaded from.""" 

4053 

4054 super().__init__( 

4055 lineno=lineno, 

4056 col_offset=col_offset, 

4057 end_lineno=end_lineno, 

4058 end_col_offset=end_col_offset, 

4059 parent=parent, 

4060 ) 

4061 

4062 assigned_stmts = protocols.sequence_assigned_stmts 

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

4064 See astroid/protocols.py for actual implementation. 

4065 """ 

4066 

4067 infer_unary_op = protocols.tuple_infer_unary_op 

4068 infer_binary_op = protocols.tl_infer_binary_op 

4069 

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

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

4072 

4073 :returns: The name of the type. 

4074 """ 

4075 return "builtins.tuple" 

4076 

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

4078 """Get an item from this node. 

4079 

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

4081 :type index: Const or Slice 

4082 """ 

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

4084 

4085 

4086class TypeAlias(_base_nodes.AssignTypeNode, _base_nodes.Statement): 

4087 """Class representing a :class:`ast.TypeAlias` node. 

4088 

4089 >>> import astroid 

4090 >>> node = astroid.extract_node('type Point = tuple[float, float]') 

4091 >>> node 

4092 <TypeAlias l.1 at 0x7f23b2e4e198> 

4093 """ 

4094 

4095 _astroid_fields = ("name", "type_params", "value") 

4096 

4097 name: AssignName 

4098 type_params: list[TypeVar | ParamSpec | TypeVarTuple] 

4099 value: NodeNG 

4100 

4101 def __init__( 

4102 self, 

4103 lineno: int, 

4104 col_offset: int, 

4105 parent: NodeNG, 

4106 *, 

4107 end_lineno: int, 

4108 end_col_offset: int, 

4109 ) -> None: 

4110 super().__init__( 

4111 lineno=lineno, 

4112 col_offset=col_offset, 

4113 end_lineno=end_lineno, 

4114 end_col_offset=end_col_offset, 

4115 parent=parent, 

4116 ) 

4117 

4118 def postinit( 

4119 self, 

4120 *, 

4121 name: AssignName, 

4122 type_params: list[TypeVar | ParamSpec | TypeVarTuple], 

4123 value: NodeNG, 

4124 ) -> None: 

4125 self.name = name 

4126 self.type_params = type_params 

4127 self.value = value 

4128 

4129 def _infer( 

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

4131 ) -> Iterator[TypeAlias]: 

4132 yield self 

4133 

4134 assigned_stmts: ClassVar[ 

4135 Callable[ 

4136 [ 

4137 TypeAlias, 

4138 AssignName, 

4139 InferenceContext | None, 

4140 None, 

4141 ], 

4142 Generator[NodeNG], 

4143 ] 

4144 ] = protocols.assign_assigned_stmts 

4145 

4146 

4147class TypeVar(_base_nodes.AssignTypeNode): 

4148 """Class representing a :class:`ast.TypeVar` node. 

4149 

4150 >>> import astroid 

4151 >>> node = astroid.extract_node('type Point[T] = tuple[float, float]') 

4152 >>> node.type_params[0] 

4153 <TypeVar l.1 at 0x7f23b2e4e198> 

4154 """ 

4155 

4156 _astroid_fields = ("name", "bound", "default_value") 

4157 name: AssignName 

4158 bound: NodeNG | None 

4159 default_value: NodeNG | None 

4160 

4161 def __init__( 

4162 self, 

4163 lineno: int, 

4164 col_offset: int, 

4165 parent: NodeNG, 

4166 *, 

4167 end_lineno: int, 

4168 end_col_offset: int, 

4169 ) -> None: 

4170 super().__init__( 

4171 lineno=lineno, 

4172 col_offset=col_offset, 

4173 end_lineno=end_lineno, 

4174 end_col_offset=end_col_offset, 

4175 parent=parent, 

4176 ) 

4177 

4178 def postinit( 

4179 self, 

4180 *, 

4181 name: AssignName, 

4182 bound: NodeNG | None, 

4183 default_value: NodeNG | None = None, 

4184 ) -> None: 

4185 self.name = name 

4186 self.bound = bound 

4187 self.default_value = default_value 

4188 

4189 def _infer( 

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

4191 ) -> Iterator[TypeVar]: 

4192 yield self 

4193 

4194 assigned_stmts = protocols.generic_type_assigned_stmts 

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

4196 See astroid/protocols.py for actual implementation. 

4197 """ 

4198 

4199 

4200class TypeVarTuple(_base_nodes.AssignTypeNode): 

4201 """Class representing a :class:`ast.TypeVarTuple` node. 

4202 

4203 >>> import astroid 

4204 >>> node = astroid.extract_node('type Alias[*Ts] = tuple[*Ts]') 

4205 >>> node.type_params[0] 

4206 <TypeVarTuple l.1 at 0x7f23b2e4e198> 

4207 """ 

4208 

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

4210 name: AssignName 

4211 default_value: NodeNG | None 

4212 

4213 def __init__( 

4214 self, 

4215 lineno: int, 

4216 col_offset: int, 

4217 parent: NodeNG, 

4218 *, 

4219 end_lineno: int, 

4220 end_col_offset: int, 

4221 ) -> None: 

4222 super().__init__( 

4223 lineno=lineno, 

4224 col_offset=col_offset, 

4225 end_lineno=end_lineno, 

4226 end_col_offset=end_col_offset, 

4227 parent=parent, 

4228 ) 

4229 

4230 def postinit( 

4231 self, *, name: AssignName, default_value: NodeNG | None = None 

4232 ) -> None: 

4233 self.name = name 

4234 self.default_value = default_value 

4235 

4236 def _infer( 

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

4238 ) -> Iterator[TypeVarTuple]: 

4239 yield self 

4240 

4241 assigned_stmts = protocols.generic_type_assigned_stmts 

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

4243 See astroid/protocols.py for actual implementation. 

4244 """ 

4245 

4246 

4247UNARY_OP_METHOD = { 

4248 "+": "__pos__", 

4249 "-": "__neg__", 

4250 "~": "__invert__", 

4251 "not": None, # XXX not '__nonzero__' 

4252} 

4253 

4254 

4255class UnaryOp(_base_nodes.OperatorNode): 

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

4257 

4258 >>> import astroid 

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

4260 >>> node 

4261 <UnaryOp l.1 at 0x7f23b2e4e198> 

4262 """ 

4263 

4264 _astroid_fields = ("operand",) 

4265 _other_fields = ("op",) 

4266 

4267 operand: NodeNG 

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

4269 

4270 def __init__( 

4271 self, 

4272 op: str, 

4273 lineno: int, 

4274 col_offset: int, 

4275 parent: NodeNG, 

4276 *, 

4277 end_lineno: int | None, 

4278 end_col_offset: int | None, 

4279 ) -> None: 

4280 self.op = op 

4281 """The operator.""" 

4282 

4283 super().__init__( 

4284 lineno=lineno, 

4285 col_offset=col_offset, 

4286 end_lineno=end_lineno, 

4287 end_col_offset=end_col_offset, 

4288 parent=parent, 

4289 ) 

4290 

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

4292 self.operand = operand 

4293 

4294 def type_errors( 

4295 self, context: InferenceContext | None = None 

4296 ) -> list[util.BadUnaryOperationMessage]: 

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

4298 

4299 Each TypeError is represented by a :class:`BadUnaryOperationMessage`, 

4300 which holds the original exception. 

4301 

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

4303 """ 

4304 bad = [] 

4305 try: 

4306 for result in self._infer_unaryop(context=context): 

4307 if result is util.Uninferable: 

4308 raise InferenceError 

4309 if isinstance(result, util.BadUnaryOperationMessage): 

4310 bad.append(result) 

4311 except InferenceError: 

4312 return [] 

4313 return bad 

4314 

4315 def get_children(self): 

4316 yield self.operand 

4317 

4318 def op_precedence(self) -> int: 

4319 if self.op == "not": 

4320 return OP_PRECEDENCE[self.op] 

4321 

4322 return super().op_precedence() 

4323 

4324 def _infer_unaryop( 

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

4326 ) -> Generator[ 

4327 InferenceResult | util.BadUnaryOperationMessage, None, InferenceErrorInfo 

4328 ]: 

4329 """Infer what an UnaryOp should return when evaluated.""" 

4330 from astroid.nodes import ClassDef # pylint: disable=import-outside-toplevel 

4331 

4332 for operand in self.operand.infer(context): 

4333 try: 

4334 yield operand.infer_unary_op(self.op) 

4335 except TypeError as exc: 

4336 # The operand doesn't support this operation. 

4337 yield util.BadUnaryOperationMessage(operand, self.op, exc) 

4338 except AttributeError as exc: 

4339 meth = UNARY_OP_METHOD[self.op] 

4340 if meth is None: 

4341 # `not node`. Determine node's boolean 

4342 # value and negate its result, unless it is 

4343 # Uninferable, which will be returned as is. 

4344 bool_value = operand.bool_value() 

4345 if not isinstance(bool_value, util.UninferableBase): 

4346 yield const_factory(not bool_value) 

4347 else: 

4348 yield util.Uninferable 

4349 else: 

4350 if not isinstance(operand, (Instance, ClassDef)): 

4351 # The operation was used on something which 

4352 # doesn't support it. 

4353 yield util.BadUnaryOperationMessage(operand, self.op, exc) 

4354 continue 

4355 

4356 try: 

4357 try: 

4358 methods = dunder_lookup.lookup(operand, meth) 

4359 except AttributeInferenceError: 

4360 yield util.BadUnaryOperationMessage(operand, self.op, exc) 

4361 continue 

4362 

4363 meth = methods[0] 

4364 inferred = next(meth.infer(context=context), None) 

4365 if ( 

4366 isinstance(inferred, util.UninferableBase) 

4367 or not inferred.callable() 

4368 ): 

4369 continue 

4370 

4371 context = copy_context(context) 

4372 context.boundnode = operand 

4373 context.callcontext = CallContext(args=[], callee=inferred) 

4374 

4375 call_results = inferred.infer_call_result(self, context=context) 

4376 result = next(call_results, None) 

4377 if result is None: 

4378 # Failed to infer, return the same type. 

4379 yield operand 

4380 else: 

4381 yield result 

4382 except AttributeInferenceError as inner_exc: 

4383 # The unary operation special method was not found. 

4384 yield util.BadUnaryOperationMessage(operand, self.op, inner_exc) 

4385 except InferenceError: 

4386 yield util.Uninferable 

4387 

4388 @decorators.raise_if_nothing_inferred 

4389 @decorators.path_wrapper 

4390 def _infer( 

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

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

4393 """Infer what an UnaryOp should return when evaluated.""" 

4394 yield from self._filter_operation_errors( 

4395 self._infer_unaryop, context, util.BadUnaryOperationMessage 

4396 ) 

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

4398 

4399 

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

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

4402 

4403 >>> import astroid 

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

4405 while condition(): 

4406 print("True") 

4407 ''') 

4408 >>> node 

4409 <While l.2 at 0x7f23b2e4e390> 

4410 """ 

4411 

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

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

4414 

4415 test: NodeNG 

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

4417 

4418 body: list[NodeNG] 

4419 """The contents of the loop.""" 

4420 

4421 orelse: list[NodeNG] 

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

4423 

4424 def postinit( 

4425 self, 

4426 test: NodeNG, 

4427 body: list[NodeNG], 

4428 orelse: list[NodeNG], 

4429 ) -> None: 

4430 self.test = test 

4431 self.body = body 

4432 self.orelse = orelse 

4433 

4434 @cached_property 

4435 def blockstart_tolineno(self): 

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

4437 

4438 :type: int 

4439 """ 

4440 return self.test.tolineno 

4441 

4442 def get_children(self): 

4443 yield self.test 

4444 

4445 yield from self.body 

4446 yield from self.orelse 

4447 

4448 def _get_yield_nodes_skip_functions(self): 

4449 """A While node can contain a Yield node in the test""" 

4450 yield from self.test._get_yield_nodes_skip_functions() 

4451 yield from super()._get_yield_nodes_skip_functions() 

4452 

4453 def _get_yield_nodes_skip_lambdas(self): 

4454 """A While node can contain a Yield node in the test""" 

4455 yield from self.test._get_yield_nodes_skip_lambdas() 

4456 yield from super()._get_yield_nodes_skip_lambdas() 

4457 

4458 

4459class With( 

4460 _base_nodes.MultiLineWithElseBlockNode, 

4461 _base_nodes.AssignTypeNode, 

4462 _base_nodes.Statement, 

4463): 

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

4465 

4466 >>> import astroid 

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

4468 with open(file_path) as file_: 

4469 print(file_.read()) 

4470 ''') 

4471 >>> node 

4472 <With l.2 at 0x7f23b2e4e710> 

4473 """ 

4474 

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

4476 _other_other_fields = ("type_annotation",) 

4477 _multi_line_block_fields = ("body",) 

4478 

4479 def __init__( 

4480 self, 

4481 lineno: int | None = None, 

4482 col_offset: int | None = None, 

4483 parent: NodeNG | None = None, 

4484 *, 

4485 end_lineno: int | None = None, 

4486 end_col_offset: int | None = None, 

4487 ) -> None: 

4488 """ 

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

4490 

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

4492 source code. 

4493 

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

4495 

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

4497 

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

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

4500 """ 

4501 self.items: list[tuple[NodeNG, NodeNG | None]] = [] 

4502 """The pairs of context managers and the names they are assigned to.""" 

4503 

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

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

4506 

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

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

4509 

4510 super().__init__( 

4511 lineno=lineno, 

4512 col_offset=col_offset, 

4513 end_lineno=end_lineno, 

4514 end_col_offset=end_col_offset, 

4515 parent=parent, 

4516 ) 

4517 

4518 def postinit( 

4519 self, 

4520 items: list[tuple[NodeNG, NodeNG | None]] | None = None, 

4521 body: list[NodeNG] | None = None, 

4522 type_annotation: NodeNG | None = None, 

4523 ) -> None: 

4524 """Do some setup after initialisation. 

4525 

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

4527 they are assigned to. 

4528 

4529 :param body: The contents of the ``with`` block. 

4530 """ 

4531 if items is not None: 

4532 self.items = items 

4533 if body is not None: 

4534 self.body = body 

4535 self.type_annotation = type_annotation 

4536 

4537 assigned_stmts = protocols.with_assigned_stmts 

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

4539 See astroid/protocols.py for actual implementation. 

4540 """ 

4541 

4542 @cached_property 

4543 def blockstart_tolineno(self): 

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

4545 

4546 :type: int 

4547 """ 

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

4549 

4550 def get_children(self): 

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

4552 

4553 :returns: The children. 

4554 :rtype: iterable(NodeNG) 

4555 """ 

4556 for expr, var in self.items: 

4557 yield expr 

4558 if var: 

4559 yield var 

4560 yield from self.body 

4561 

4562 

4563class AsyncWith(With): 

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

4565 

4566 

4567class Yield(NodeNG): 

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

4569 

4570 >>> import astroid 

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

4572 >>> node 

4573 <Yield l.1 at 0x7f23b2e4e5f8> 

4574 """ 

4575 

4576 _astroid_fields = ("value",) 

4577 

4578 value: NodeNG | None 

4579 """The value to yield.""" 

4580 

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

4582 self.value = value 

4583 

4584 def get_children(self): 

4585 if self.value is not None: 

4586 yield self.value 

4587 

4588 def _get_yield_nodes_skip_functions(self): 

4589 yield self 

4590 

4591 def _get_yield_nodes_skip_lambdas(self): 

4592 yield self 

4593 

4594 

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

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

4597 

4598 

4599class DictUnpack(_base_nodes.NoChildrenNode): 

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

4601 

4602 

4603class FormattedValue(NodeNG): 

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

4605 

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

4607 

4608 >>> import astroid 

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

4610 >>> node 

4611 <JoinedStr l.1 at 0x7f23b2e4ed30> 

4612 >>> node.values 

4613 [<Const.str l.1 at 0x7f23b2e4eda0>, <FormattedValue l.1 at 0x7f23b2e4edd8>] 

4614 """ 

4615 

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

4617 _other_fields = ("conversion",) 

4618 

4619 def __init__( 

4620 self, 

4621 lineno: int | None = None, 

4622 col_offset: int | None = None, 

4623 parent: NodeNG | None = None, 

4624 *, 

4625 end_lineno: int | None = None, 

4626 end_col_offset: int | None = None, 

4627 ) -> None: 

4628 """ 

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

4630 

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

4632 source code. 

4633 

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

4635 

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

4637 

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

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

4640 """ 

4641 self.value: NodeNG 

4642 """The value to be formatted into the string.""" 

4643 

4644 self.conversion: int 

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

4646 

4647 .. seealso:: 

4648 :class:`ast.FormattedValue` 

4649 """ 

4650 

4651 self.format_spec: JoinedStr | None = None 

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

4653 

4654 .. seealso:: 

4655 :class:`ast.FormattedValue` 

4656 """ 

4657 

4658 super().__init__( 

4659 lineno=lineno, 

4660 col_offset=col_offset, 

4661 end_lineno=end_lineno, 

4662 end_col_offset=end_col_offset, 

4663 parent=parent, 

4664 ) 

4665 

4666 def postinit( 

4667 self, 

4668 *, 

4669 value: NodeNG, 

4670 conversion: int, 

4671 format_spec: JoinedStr | None = None, 

4672 ) -> None: 

4673 """Do some setup after initialisation. 

4674 

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

4676 

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

4678 

4679 :param format_spec: The formatting to be applied to the value. 

4680 :type format_spec: JoinedStr or None 

4681 """ 

4682 self.value = value 

4683 self.conversion = conversion 

4684 self.format_spec = format_spec 

4685 

4686 def get_children(self): 

4687 yield self.value 

4688 

4689 if self.format_spec is not None: 

4690 yield self.format_spec 

4691 

4692 def _infer( 

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

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

4695 format_specs = Const("") if self.format_spec is None else self.format_spec 

4696 uninferable_already_generated = False 

4697 for format_spec in format_specs.infer(context, **kwargs): 

4698 if not isinstance(format_spec, Const): 

4699 if not uninferable_already_generated: 

4700 yield util.Uninferable 

4701 uninferable_already_generated = True 

4702 continue 

4703 for value in self.value.infer(context, **kwargs): 

4704 if value is util.Uninferable: 

4705 yield util.Uninferable 

4706 return 

4707 value_to_format = value 

4708 if isinstance(value, Const): 

4709 value_to_format = value.value 

4710 try: 

4711 formatted = format(value_to_format, format_spec.value) 

4712 yield Const( 

4713 formatted, 

4714 lineno=self.lineno, 

4715 col_offset=self.col_offset, 

4716 end_lineno=self.end_lineno, 

4717 end_col_offset=self.end_col_offset, 

4718 ) 

4719 continue 

4720 except (ValueError, TypeError, MemoryError): 

4721 # ValueError/TypeError: invalid format spec 

4722 # MemoryError: format spec with huge width (e.g. f'{0:11111111111}') 

4723 yield util.Uninferable 

4724 uninferable_already_generated = True 

4725 continue 

4726 

4727 

4728UNINFERABLE_VALUE = "{Uninferable}" 

4729 

4730 

4731class JoinedStr(NodeNG): 

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

4733 

4734 >>> import astroid 

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

4736 >>> node 

4737 <JoinedStr l.1 at 0x7f23b2e4ed30> 

4738 """ 

4739 

4740 _astroid_fields = ("values",) 

4741 

4742 def __init__( 

4743 self, 

4744 lineno: int | None = None, 

4745 col_offset: int | None = None, 

4746 parent: NodeNG | None = None, 

4747 *, 

4748 end_lineno: int | None = None, 

4749 end_col_offset: int | None = None, 

4750 ) -> None: 

4751 """ 

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

4753 

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

4755 source code. 

4756 

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

4758 

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

4760 

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

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

4763 """ 

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

4765 """The string expressions to be joined. 

4766 

4767 :type: list(FormattedValue or Const) 

4768 """ 

4769 

4770 super().__init__( 

4771 lineno=lineno, 

4772 col_offset=col_offset, 

4773 end_lineno=end_lineno, 

4774 end_col_offset=end_col_offset, 

4775 parent=parent, 

4776 ) 

4777 

4778 def postinit(self, values: list[NodeNG] | None = None) -> None: 

4779 """Do some setup after initialisation. 

4780 

4781 :param value: The string expressions to be joined. 

4782 

4783 :type: list(FormattedValue or Const) 

4784 """ 

4785 if values is not None: 

4786 self.values = values 

4787 

4788 def get_children(self): 

4789 yield from self.values 

4790 

4791 def _infer( 

4792 self, context: InferenceContext | None = None, **kwargs: Any 

4793 ) -> Generator[InferenceResult, None, InferenceErrorInfo | None]: 

4794 if self.values: 

4795 yield from self._infer_with_values(context) 

4796 else: 

4797 yield Const("") 

4798 

4799 def _infer_with_values( 

4800 self, context: InferenceContext | None = None, **kwargs: Any 

4801 ) -> Generator[InferenceResult, None, InferenceErrorInfo | None]: 

4802 uninferable_already_generated = False 

4803 for inferred in self._infer_from_values(self.values, context): 

4804 failed = inferred is util.Uninferable or ( 

4805 isinstance(inferred, Const) and UNINFERABLE_VALUE in inferred.value 

4806 ) 

4807 if failed: 

4808 if not uninferable_already_generated: 

4809 uninferable_already_generated = True 

4810 yield util.Uninferable 

4811 continue 

4812 yield inferred 

4813 

4814 @classmethod 

4815 def _infer_from_values( 

4816 cls, nodes: list[NodeNG], context: InferenceContext | None = None, **kwargs: Any 

4817 ) -> Generator[InferenceResult, None, InferenceErrorInfo | None]: 

4818 if not nodes: 

4819 return 

4820 if len(nodes) == 1: 

4821 for node in cls._safe_infer_from_node(nodes[0], context, **kwargs): 

4822 if isinstance(node, Const): 

4823 yield node 

4824 continue 

4825 yield Const(UNINFERABLE_VALUE) 

4826 return 

4827 for prefix in cls._safe_infer_from_node(nodes[0], context, **kwargs): 

4828 for suffix in cls._infer_from_values(nodes[1:], context, **kwargs): 

4829 result = "" 

4830 for node in (prefix, suffix): 

4831 if isinstance(node, Const): 

4832 result += str(node.value) 

4833 continue 

4834 result += UNINFERABLE_VALUE 

4835 yield Const(result) 

4836 

4837 @classmethod 

4838 def _safe_infer_from_node( 

4839 cls, node: NodeNG, context: InferenceContext | None = None, **kwargs: Any 

4840 ) -> Generator[InferenceResult, None, InferenceErrorInfo | None]: 

4841 try: 

4842 yield from node._infer(context, **kwargs) 

4843 except InferenceError: 

4844 yield util.Uninferable 

4845 

4846 

4847class NamedExpr(_base_nodes.AssignTypeNode): 

4848 """Represents the assignment from the assignment expression 

4849 

4850 >>> import astroid 

4851 >>> module = astroid.parse('if a := 1: pass') 

4852 >>> module.body[0].test 

4853 <NamedExpr l.1 at 0x7f23b2e4ed30> 

4854 """ 

4855 

4856 _astroid_fields = ("target", "value") 

4857 

4858 optional_assign = True 

4859 """Whether this node optionally assigns a variable. 

4860 

4861 Since NamedExpr are not always called they do not always assign.""" 

4862 

4863 def __init__( 

4864 self, 

4865 lineno: int | None = None, 

4866 col_offset: int | None = None, 

4867 parent: NodeNG | None = None, 

4868 *, 

4869 end_lineno: int | None = None, 

4870 end_col_offset: int | None = None, 

4871 ) -> None: 

4872 """ 

4873 :param lineno: The line that this node appears on in the source code. 

4874 

4875 :param col_offset: The column that this node appears on in the 

4876 source code. 

4877 

4878 :param parent: The parent node in the syntax tree. 

4879 

4880 :param end_lineno: The last line this node appears on in the source code. 

4881 

4882 :param end_col_offset: The end column this node appears on in the 

4883 source code. Note: This is after the last symbol. 

4884 """ 

4885 self.target: NodeNG 

4886 """The assignment target 

4887 

4888 :type: Name 

4889 """ 

4890 

4891 self.value: NodeNG 

4892 """The value that gets assigned in the expression""" 

4893 

4894 super().__init__( 

4895 lineno=lineno, 

4896 col_offset=col_offset, 

4897 end_lineno=end_lineno, 

4898 end_col_offset=end_col_offset, 

4899 parent=parent, 

4900 ) 

4901 

4902 def postinit(self, target: NodeNG, value: NodeNG) -> None: 

4903 self.target = target 

4904 self.value = value 

4905 

4906 assigned_stmts = protocols.named_expr_assigned_stmts 

4907 """Returns the assigned statement (non inferred) according to the assignment type. 

4908 See astroid/protocols.py for actual implementation. 

4909 """ 

4910 

4911 def frame(self) -> FrameType: 

4912 """The first parent frame node. 

4913 

4914 A frame node is a :class:`Module`, :class:`FunctionDef`, 

4915 or :class:`ClassDef`. 

4916 

4917 :returns: The first parent frame node. 

4918 """ 

4919 if not self.parent: 

4920 raise ParentMissingError(target=self) 

4921 

4922 # For certain parents NamedExpr evaluate to the scope of the parent 

4923 if isinstance(self.parent, (Arguments, Keyword, Comprehension)): 

4924 if not self.parent.parent: 

4925 raise ParentMissingError(target=self.parent) 

4926 if not self.parent.parent.parent: 

4927 raise ParentMissingError(target=self.parent.parent) 

4928 return self.parent.parent.parent.frame() 

4929 

4930 return self.parent.frame() 

4931 

4932 def scope(self) -> LocalsDictNodeNG: 

4933 """The first parent node defining a new scope. 

4934 These can be Module, FunctionDef, ClassDef, Lambda, or GeneratorExp nodes. 

4935 

4936 :returns: The first parent scope node. 

4937 """ 

4938 if not self.parent: 

4939 raise ParentMissingError(target=self) 

4940 

4941 # For certain parents NamedExpr evaluate to the scope of the parent 

4942 if isinstance(self.parent, (Arguments, Keyword, Comprehension)): 

4943 if not self.parent.parent: 

4944 raise ParentMissingError(target=self.parent) 

4945 if not self.parent.parent.parent: 

4946 raise ParentMissingError(target=self.parent.parent) 

4947 return self.parent.parent.parent.scope() 

4948 

4949 return self.parent.scope() 

4950 

4951 def set_local(self, name: str, stmt: NodeNG) -> None: 

4952 """Define that the given name is declared in the given statement node. 

4953 NamedExpr's in Arguments, Keyword or Comprehension are evaluated in their 

4954 parent's parent scope. So we add to their frame's locals. 

4955 

4956 .. seealso:: :meth:`scope` 

4957 

4958 :param name: The name that is being defined. 

4959 

4960 :param stmt: The statement that defines the given name. 

4961 """ 

4962 self.frame().set_local(name, stmt) 

4963 

4964 

4965class Unknown(_base_nodes.AssignTypeNode): 

4966 """This node represents a node in a constructed AST where 

4967 introspection is not possible. 

4968 

4969 Used in the args attribute of FunctionDef nodes where function signature 

4970 introspection failed, and as a placeholder in ObjectModel. 

4971 """ 

4972 

4973 name = "Unknown" 

4974 

4975 def __init__( 

4976 self, 

4977 parent: NodeNG, 

4978 lineno: None = None, 

4979 col_offset: None = None, 

4980 *, 

4981 end_lineno: None = None, 

4982 end_col_offset: None = None, 

4983 ) -> None: 

4984 super().__init__( 

4985 lineno=lineno, 

4986 col_offset=col_offset, 

4987 end_lineno=end_lineno, 

4988 end_col_offset=end_col_offset, 

4989 parent=parent, 

4990 ) 

4991 

4992 def qname(self) -> Literal["Unknown"]: 

4993 return "Unknown" 

4994 

4995 def _infer(self, context: InferenceContext | None = None, **kwargs): 

4996 """Inference on an Unknown node immediately terminates.""" 

4997 yield util.Uninferable 

4998 

4999 

5000UNATTACHED_UNKNOWN = Unknown(parent=SYNTHETIC_ROOT) 

5001 

5002 

5003class EvaluatedObject(NodeNG): 

5004 """Contains an object that has already been inferred 

5005 

5006 This class is useful to pre-evaluate a particular node, 

5007 with the resulting class acting as the non-evaluated node. 

5008 """ 

5009 

5010 name = "EvaluatedObject" 

5011 _astroid_fields = ("original",) 

5012 _other_fields = ("value",) 

5013 

5014 def __init__( 

5015 self, original: SuccessfulInferenceResult, value: InferenceResult 

5016 ) -> None: 

5017 self.original: SuccessfulInferenceResult = original 

5018 """The original node that has already been evaluated""" 

5019 

5020 self.value: InferenceResult = value 

5021 """The inferred value""" 

5022 

5023 super().__init__( 

5024 lineno=self.original.lineno, 

5025 col_offset=self.original.col_offset, 

5026 parent=self.original.parent, 

5027 end_lineno=self.original.end_lineno, 

5028 end_col_offset=self.original.end_col_offset, 

5029 ) 

5030 

5031 def _infer( 

5032 self, context: InferenceContext | None = None, **kwargs: Any 

5033 ) -> Generator[NodeNG | util.UninferableBase]: 

5034 yield self.value 

5035 

5036 

5037# Pattern matching ####################################################### 

5038 

5039 

5040class Match(_base_nodes.Statement, _base_nodes.MultiLineBlockNode): 

5041 """Class representing a :class:`ast.Match` node. 

5042 

5043 >>> import astroid 

5044 >>> node = astroid.extract_node(''' 

5045 match x: 

5046 case 200: 

5047 ... 

5048 case _: 

5049 ... 

5050 ''') 

5051 >>> node 

5052 <Match l.2 at 0x10c24e170> 

5053 """ 

5054 

5055 _astroid_fields = ("subject", "cases") 

5056 _multi_line_block_fields = ("cases",) 

5057 

5058 def __init__( 

5059 self, 

5060 lineno: int | None = None, 

5061 col_offset: int | None = None, 

5062 parent: NodeNG | None = None, 

5063 *, 

5064 end_lineno: int | None = None, 

5065 end_col_offset: int | None = None, 

5066 ) -> None: 

5067 self.subject: NodeNG 

5068 self.cases: list[MatchCase] 

5069 super().__init__( 

5070 lineno=lineno, 

5071 col_offset=col_offset, 

5072 end_lineno=end_lineno, 

5073 end_col_offset=end_col_offset, 

5074 parent=parent, 

5075 ) 

5076 

5077 def postinit( 

5078 self, 

5079 *, 

5080 subject: NodeNG, 

5081 cases: list[MatchCase], 

5082 ) -> None: 

5083 self.subject = subject 

5084 self.cases = cases 

5085 

5086 

5087class Pattern(NodeNG): 

5088 """Base class for all Pattern nodes.""" 

5089 

5090 

5091class MatchCase(_base_nodes.MultiLineBlockNode): 

5092 """Class representing a :class:`ast.match_case` node. 

5093 

5094 >>> import astroid 

5095 >>> node = astroid.extract_node(''' 

5096 match x: 

5097 case 200: 

5098 ... 

5099 ''') 

5100 >>> node.cases[0] 

5101 <MatchCase l.3 at 0x10c24e590> 

5102 """ 

5103 

5104 _astroid_fields = ("pattern", "guard", "body") 

5105 _multi_line_block_fields = ("body",) 

5106 

5107 lineno: None 

5108 col_offset: None 

5109 end_lineno: None 

5110 end_col_offset: None 

5111 

5112 def __init__(self, *, parent: NodeNG | None = None) -> None: 

5113 self.pattern: Pattern 

5114 self.guard: NodeNG | None 

5115 self.body: list[NodeNG] 

5116 super().__init__( 

5117 parent=parent, 

5118 lineno=None, 

5119 col_offset=None, 

5120 end_lineno=None, 

5121 end_col_offset=None, 

5122 ) 

5123 

5124 def postinit( 

5125 self, 

5126 *, 

5127 pattern: Pattern, 

5128 guard: NodeNG | None, 

5129 body: list[NodeNG], 

5130 ) -> None: 

5131 self.pattern = pattern 

5132 self.guard = guard 

5133 self.body = body 

5134 

5135 

5136class MatchValue(Pattern): 

5137 """Class representing a :class:`ast.MatchValue` node. 

5138 

5139 >>> import astroid 

5140 >>> node = astroid.extract_node(''' 

5141 match x: 

5142 case 200: 

5143 ... 

5144 ''') 

5145 >>> node.cases[0].pattern 

5146 <MatchValue l.3 at 0x10c24e200> 

5147 """ 

5148 

5149 _astroid_fields = ("value",) 

5150 

5151 def __init__( 

5152 self, 

5153 lineno: int | None = None, 

5154 col_offset: int | None = None, 

5155 parent: NodeNG | None = None, 

5156 *, 

5157 end_lineno: int | None = None, 

5158 end_col_offset: int | None = None, 

5159 ) -> None: 

5160 self.value: NodeNG 

5161 super().__init__( 

5162 lineno=lineno, 

5163 col_offset=col_offset, 

5164 end_lineno=end_lineno, 

5165 end_col_offset=end_col_offset, 

5166 parent=parent, 

5167 ) 

5168 

5169 def postinit(self, *, value: NodeNG) -> None: 

5170 self.value = value 

5171 

5172 

5173class MatchSingleton(Pattern): 

5174 """Class representing a :class:`ast.MatchSingleton` node. 

5175 

5176 >>> import astroid 

5177 >>> node = astroid.extract_node(''' 

5178 match x: 

5179 case True: 

5180 ... 

5181 case False: 

5182 ... 

5183 case None: 

5184 ... 

5185 ''') 

5186 >>> node.cases[0].pattern 

5187 <MatchSingleton l.3 at 0x10c2282e0> 

5188 >>> node.cases[1].pattern 

5189 <MatchSingleton l.5 at 0x10c228af0> 

5190 >>> node.cases[2].pattern 

5191 <MatchSingleton l.7 at 0x10c229f90> 

5192 """ 

5193 

5194 _other_fields = ("value",) 

5195 

5196 def __init__( 

5197 self, 

5198 *, 

5199 value: Literal[True, False, None], 

5200 lineno: int | None = None, 

5201 col_offset: int | None = None, 

5202 end_lineno: int | None = None, 

5203 end_col_offset: int | None = None, 

5204 parent: NodeNG | None = None, 

5205 ) -> None: 

5206 self.value = value 

5207 super().__init__( 

5208 lineno=lineno, 

5209 col_offset=col_offset, 

5210 end_lineno=end_lineno, 

5211 end_col_offset=end_col_offset, 

5212 parent=parent, 

5213 ) 

5214 

5215 

5216class MatchSequence(Pattern): 

5217 """Class representing a :class:`ast.MatchSequence` node. 

5218 

5219 >>> import astroid 

5220 >>> node = astroid.extract_node(''' 

5221 match x: 

5222 case [1, 2]: 

5223 ... 

5224 case (1, 2, *_): 

5225 ... 

5226 ''') 

5227 >>> node.cases[0].pattern 

5228 <MatchSequence l.3 at 0x10ca80d00> 

5229 >>> node.cases[1].pattern 

5230 <MatchSequence l.5 at 0x10ca80b20> 

5231 """ 

5232 

5233 _astroid_fields = ("patterns",) 

5234 

5235 def __init__( 

5236 self, 

5237 lineno: int | None = None, 

5238 col_offset: int | None = None, 

5239 parent: NodeNG | None = None, 

5240 *, 

5241 end_lineno: int | None = None, 

5242 end_col_offset: int | None = None, 

5243 ) -> None: 

5244 self.patterns: list[Pattern] 

5245 super().__init__( 

5246 lineno=lineno, 

5247 col_offset=col_offset, 

5248 end_lineno=end_lineno, 

5249 end_col_offset=end_col_offset, 

5250 parent=parent, 

5251 ) 

5252 

5253 def postinit(self, *, patterns: list[Pattern]) -> None: 

5254 self.patterns = patterns 

5255 

5256 

5257class MatchMapping(_base_nodes.AssignTypeNode, Pattern): 

5258 """Class representing a :class:`ast.MatchMapping` node. 

5259 

5260 >>> import astroid 

5261 >>> node = astroid.extract_node(''' 

5262 match x: 

5263 case {1: "Hello", 2: "World", 3: _, **rest}: 

5264 ... 

5265 ''') 

5266 >>> node.cases[0].pattern 

5267 <MatchMapping l.3 at 0x10c8a8850> 

5268 """ 

5269 

5270 _astroid_fields = ("keys", "patterns", "rest") 

5271 

5272 def __init__( 

5273 self, 

5274 lineno: int | None = None, 

5275 col_offset: int | None = None, 

5276 parent: NodeNG | None = None, 

5277 *, 

5278 end_lineno: int | None = None, 

5279 end_col_offset: int | None = None, 

5280 ) -> None: 

5281 self.keys: list[NodeNG] 

5282 self.patterns: list[Pattern] 

5283 self.rest: AssignName | None 

5284 super().__init__( 

5285 lineno=lineno, 

5286 col_offset=col_offset, 

5287 end_lineno=end_lineno, 

5288 end_col_offset=end_col_offset, 

5289 parent=parent, 

5290 ) 

5291 

5292 def postinit( 

5293 self, 

5294 *, 

5295 keys: list[NodeNG], 

5296 patterns: list[Pattern], 

5297 rest: AssignName | None, 

5298 ) -> None: 

5299 self.keys = keys 

5300 self.patterns = patterns 

5301 self.rest = rest 

5302 

5303 assigned_stmts = protocols.match_mapping_assigned_stmts 

5304 """Returns the assigned statement (non inferred) according to the assignment type. 

5305 See astroid/protocols.py for actual implementation. 

5306 """ 

5307 

5308 

5309class MatchClass(Pattern): 

5310 """Class representing a :class:`ast.MatchClass` node. 

5311 

5312 >>> import astroid 

5313 >>> node = astroid.extract_node(''' 

5314 match x: 

5315 case Point2D(0, 0): 

5316 ... 

5317 case Point3D(x=0, y=0, z=0): 

5318 ... 

5319 ''') 

5320 >>> node.cases[0].pattern 

5321 <MatchClass l.3 at 0x10ca83940> 

5322 >>> node.cases[1].pattern 

5323 <MatchClass l.5 at 0x10ca80880> 

5324 """ 

5325 

5326 _astroid_fields = ("cls", "patterns", "kwd_patterns") 

5327 _other_fields = ("kwd_attrs",) 

5328 

5329 def __init__( 

5330 self, 

5331 lineno: int | None = None, 

5332 col_offset: int | None = None, 

5333 parent: NodeNG | None = None, 

5334 *, 

5335 end_lineno: int | None = None, 

5336 end_col_offset: int | None = None, 

5337 ) -> None: 

5338 self.cls: NodeNG 

5339 self.patterns: list[Pattern] 

5340 self.kwd_attrs: list[str] 

5341 self.kwd_patterns: list[Pattern] 

5342 super().__init__( 

5343 lineno=lineno, 

5344 col_offset=col_offset, 

5345 end_lineno=end_lineno, 

5346 end_col_offset=end_col_offset, 

5347 parent=parent, 

5348 ) 

5349 

5350 def postinit( 

5351 self, 

5352 *, 

5353 cls: NodeNG, 

5354 patterns: list[Pattern], 

5355 kwd_attrs: list[str], 

5356 kwd_patterns: list[Pattern], 

5357 ) -> None: 

5358 self.cls = cls 

5359 self.patterns = patterns 

5360 self.kwd_attrs = kwd_attrs 

5361 self.kwd_patterns = kwd_patterns 

5362 

5363 

5364class MatchStar(_base_nodes.AssignTypeNode, Pattern): 

5365 """Class representing a :class:`ast.MatchStar` node. 

5366 

5367 >>> import astroid 

5368 >>> node = astroid.extract_node(''' 

5369 match x: 

5370 case [1, *_]: 

5371 ... 

5372 ''') 

5373 >>> node.cases[0].pattern.patterns[1] 

5374 <MatchStar l.3 at 0x10ca809a0> 

5375 """ 

5376 

5377 _astroid_fields = ("name",) 

5378 

5379 def __init__( 

5380 self, 

5381 lineno: int | None = None, 

5382 col_offset: int | None = None, 

5383 parent: NodeNG | None = None, 

5384 *, 

5385 end_lineno: int | None = None, 

5386 end_col_offset: int | None = None, 

5387 ) -> None: 

5388 self.name: AssignName | None 

5389 super().__init__( 

5390 lineno=lineno, 

5391 col_offset=col_offset, 

5392 end_lineno=end_lineno, 

5393 end_col_offset=end_col_offset, 

5394 parent=parent, 

5395 ) 

5396 

5397 def postinit(self, *, name: AssignName | None) -> None: 

5398 self.name = name 

5399 

5400 assigned_stmts = protocols.match_star_assigned_stmts 

5401 """Returns the assigned statement (non inferred) according to the assignment type. 

5402 See astroid/protocols.py for actual implementation. 

5403 """ 

5404 

5405 

5406class MatchAs(_base_nodes.AssignTypeNode, Pattern): 

5407 """Class representing a :class:`ast.MatchAs` node. 

5408 

5409 >>> import astroid 

5410 >>> node = astroid.extract_node(''' 

5411 match x: 

5412 case [1, a]: 

5413 ... 

5414 case {'key': b}: 

5415 ... 

5416 case Point2D(0, 0) as c: 

5417 ... 

5418 case d: 

5419 ... 

5420 ''') 

5421 >>> node.cases[0].pattern.patterns[1] 

5422 <MatchAs l.3 at 0x10d0b2da0> 

5423 >>> node.cases[1].pattern.patterns[0] 

5424 <MatchAs l.5 at 0x10d0b2920> 

5425 >>> node.cases[2].pattern 

5426 <MatchAs l.7 at 0x10d0b06a0> 

5427 >>> node.cases[3].pattern 

5428 <MatchAs l.9 at 0x10d09b880> 

5429 """ 

5430 

5431 _astroid_fields = ("pattern", "name") 

5432 

5433 def __init__( 

5434 self, 

5435 lineno: int | None = None, 

5436 col_offset: int | None = None, 

5437 parent: NodeNG | None = None, 

5438 *, 

5439 end_lineno: int | None = None, 

5440 end_col_offset: int | None = None, 

5441 ) -> None: 

5442 self.pattern: Pattern | None 

5443 self.name: AssignName | None 

5444 super().__init__( 

5445 lineno=lineno, 

5446 col_offset=col_offset, 

5447 end_lineno=end_lineno, 

5448 end_col_offset=end_col_offset, 

5449 parent=parent, 

5450 ) 

5451 

5452 def postinit( 

5453 self, 

5454 *, 

5455 pattern: Pattern | None, 

5456 name: AssignName | None, 

5457 ) -> None: 

5458 self.pattern = pattern 

5459 self.name = name 

5460 

5461 assigned_stmts = protocols.match_as_assigned_stmts 

5462 """Returns the assigned statement (non inferred) according to the assignment type. 

5463 See astroid/protocols.py for actual implementation. 

5464 """ 

5465 

5466 

5467class MatchOr(Pattern): 

5468 """Class representing a :class:`ast.MatchOr` node. 

5469 

5470 >>> import astroid 

5471 >>> node = astroid.extract_node(''' 

5472 match x: 

5473 case 400 | 401 | 402: 

5474 ... 

5475 ''') 

5476 >>> node.cases[0].pattern 

5477 <MatchOr l.3 at 0x10d0b0b50> 

5478 """ 

5479 

5480 _astroid_fields = ("patterns",) 

5481 

5482 def __init__( 

5483 self, 

5484 lineno: int | None = None, 

5485 col_offset: int | None = None, 

5486 parent: NodeNG | None = None, 

5487 *, 

5488 end_lineno: int | None = None, 

5489 end_col_offset: int | None = None, 

5490 ) -> None: 

5491 self.patterns: list[Pattern] 

5492 super().__init__( 

5493 lineno=lineno, 

5494 col_offset=col_offset, 

5495 end_lineno=end_lineno, 

5496 end_col_offset=end_col_offset, 

5497 parent=parent, 

5498 ) 

5499 

5500 def postinit(self, *, patterns: list[Pattern]) -> None: 

5501 self.patterns = patterns 

5502 

5503 

5504class TemplateStr(NodeNG): 

5505 """Class representing an :class:`ast.TemplateStr` node. 

5506 

5507 >>> import astroid 

5508 >>> node = astroid.extract_node('t"{name} finished {place!s}"') 

5509 >>> node 

5510 <TemplateStr l.1 at 0x103b7aa50> 

5511 """ 

5512 

5513 _astroid_fields = ("values",) 

5514 

5515 def __init__( 

5516 self, 

5517 lineno: int | None = None, 

5518 col_offset: int | None = None, 

5519 parent: NodeNG | None = None, 

5520 *, 

5521 end_lineno: int | None = None, 

5522 end_col_offset: int | None = None, 

5523 ) -> None: 

5524 self.values: list[NodeNG] 

5525 super().__init__( 

5526 lineno=lineno, 

5527 col_offset=col_offset, 

5528 end_lineno=end_lineno, 

5529 end_col_offset=end_col_offset, 

5530 parent=parent, 

5531 ) 

5532 

5533 def postinit(self, *, values: list[NodeNG]) -> None: 

5534 self.values = values 

5535 

5536 def get_children(self) -> Iterator[NodeNG]: 

5537 yield from self.values 

5538 

5539 

5540class Interpolation(NodeNG): 

5541 """Class representing an :class:`ast.Interpolation` node. 

5542 

5543 >>> import astroid 

5544 >>> node = astroid.extract_node('t"{name} finished {place!s}"') 

5545 >>> node 

5546 <TemplateStr l.1 at 0x103b7aa50> 

5547 >>> node.values[0] 

5548 <Interpolation l.1 at 0x103b7acf0> 

5549 >>> node.values[2] 

5550 <Interpolation l.1 at 0x10411e5d0> 

5551 """ 

5552 

5553 _astroid_fields = ("value", "format_spec") 

5554 _other_fields = ("str", "conversion") 

5555 

5556 def __init__( 

5557 self, 

5558 lineno: int | None = None, 

5559 col_offset: int | None = None, 

5560 parent: NodeNG | None = None, 

5561 *, 

5562 end_lineno: int | None = None, 

5563 end_col_offset: int | None = None, 

5564 ) -> None: 

5565 self.value: NodeNG 

5566 """Any expression node.""" 

5567 

5568 self.str: str 

5569 """Text of the interpolation expression.""" 

5570 

5571 self.conversion: int 

5572 """The type of formatting to be applied to the value. 

5573 

5574 .. seealso:: 

5575 :class:`ast.Interpolation` 

5576 """ 

5577 

5578 self.format_spec: JoinedStr | None = None 

5579 """The formatting to be applied to the value. 

5580 

5581 .. seealso:: 

5582 :class:`ast.Interpolation` 

5583 """ 

5584 

5585 super().__init__( 

5586 lineno=lineno, 

5587 col_offset=col_offset, 

5588 end_lineno=end_lineno, 

5589 end_col_offset=end_col_offset, 

5590 parent=parent, 

5591 ) 

5592 

5593 def postinit( 

5594 self, 

5595 *, 

5596 value: NodeNG, 

5597 str: str, # pylint: disable=redefined-builtin 

5598 conversion: int = -1, 

5599 format_spec: JoinedStr | None = None, 

5600 ) -> None: 

5601 self.value = value 

5602 self.str = str 

5603 self.conversion = conversion 

5604 self.format_spec = format_spec 

5605 

5606 def get_children(self) -> Iterator[NodeNG]: 

5607 yield self.value 

5608 if self.format_spec: 

5609 yield self.format_spec 

5610 

5611 

5612# constants ############################################################## 

5613 

5614# The _proxied attribute of all container types (List, Tuple, etc.) 

5615# are set during bootstrapping by _astroid_bootstrapping(). 

5616CONST_CLS: dict[type, type[NodeNG]] = { 

5617 list: List, 

5618 tuple: Tuple, 

5619 dict: Dict, 

5620 set: Set, 

5621 type(None): Const, 

5622 type(NotImplemented): Const, 

5623 type(...): Const, 

5624 bool: Const, 

5625 int: Const, 

5626 float: Const, 

5627 complex: Const, 

5628 str: Const, 

5629 bytes: Const, 

5630} 

5631 

5632 

5633def _create_basic_elements( 

5634 value: Iterable[Any], node: List | Set | Tuple 

5635) -> list[NodeNG]: 

5636 """Create a list of nodes to function as the elements of a new node.""" 

5637 elements: list[NodeNG] = [] 

5638 for element in value: 

5639 # NOTE: avoid accessing any attributes of element in the loop. 

5640 element_node = const_factory(element) 

5641 element_node.parent = node 

5642 elements.append(element_node) 

5643 return elements 

5644 

5645 

5646def _create_dict_items( 

5647 values: Mapping[Any, Any], node: Dict 

5648) -> list[tuple[SuccessfulInferenceResult, SuccessfulInferenceResult]]: 

5649 """Create a list of node pairs to function as the items of a new dict node.""" 

5650 elements: list[tuple[SuccessfulInferenceResult, SuccessfulInferenceResult]] = [] 

5651 for key, value in values.items(): 

5652 # NOTE: avoid accessing any attributes of both key and value in the loop. 

5653 key_node = const_factory(key) 

5654 key_node.parent = node 

5655 value_node = const_factory(value) 

5656 value_node.parent = node 

5657 elements.append((key_node, value_node)) 

5658 return elements 

5659 

5660 

5661def const_factory(value: Any) -> ConstFactoryResult: 

5662 """Return an astroid node for a python value.""" 

5663 # NOTE: avoid accessing any attributes of value until it is known that value 

5664 # is of a const type, to avoid possibly triggering code for a live object. 

5665 # Accesses include value.__class__ and isinstance(value, ...), but not type(value). 

5666 # See: https://github.com/pylint-dev/astroid/issues/2686 

5667 value_type = type(value) 

5668 assert not issubclass(value_type, NodeNG) 

5669 

5670 # This only handles instances of the CONST types. Any 

5671 # subclasses get inferred as EmptyNode. 

5672 # TODO: See if we should revisit these with the normal builder. 

5673 if value_type not in CONST_CLS: 

5674 node = EmptyNode() 

5675 node.object = value 

5676 return node 

5677 

5678 instance: List | Set | Tuple | Dict 

5679 initializer_cls = CONST_CLS[value_type] 

5680 if issubclass(initializer_cls, (List, Set, Tuple)): 

5681 instance = initializer_cls( 

5682 lineno=None, 

5683 col_offset=None, 

5684 parent=SYNTHETIC_ROOT, 

5685 end_lineno=None, 

5686 end_col_offset=None, 

5687 ) 

5688 instance.postinit(_create_basic_elements(value, instance)) 

5689 return instance 

5690 if issubclass(initializer_cls, Dict): 

5691 instance = initializer_cls( 

5692 lineno=None, 

5693 col_offset=None, 

5694 parent=SYNTHETIC_ROOT, 

5695 end_lineno=None, 

5696 end_col_offset=None, 

5697 ) 

5698 instance.postinit(_create_dict_items(value, instance)) 

5699 return instance 

5700 return Const(value)