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

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

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

19 TYPE_CHECKING, 

20 Any, 

21 ClassVar, 

22 Literal, 

23 Optional, 

24 Union, 

25) 

26 

27from astroid import decorators, protocols, util 

28from astroid.bases import Instance, _infer_stmts 

29from astroid.const import _EMPTY_OBJECT_MARKER, Context 

30from astroid.context import CallContext, InferenceContext, copy_context 

31from astroid.exceptions import ( 

32 AstroidBuildingError, 

33 AstroidError, 

34 AstroidIndexError, 

35 AstroidTypeError, 

36 AstroidValueError, 

37 AttributeInferenceError, 

38 InferenceError, 

39 NameInferenceError, 

40 NoDefault, 

41 ParentMissingError, 

42 _NonDeducibleTypeHierarchy, 

43) 

44from astroid.interpreter import dunder_lookup 

45from astroid.manager import AstroidManager 

46from astroid.nodes import _base_nodes 

47from astroid.nodes.const import OP_PRECEDENCE 

48from astroid.nodes.node_ng import NodeNG 

49from astroid.nodes.scoped_nodes import SYNTHETIC_ROOT 

50from astroid.typing import ( 

51 ConstFactoryResult, 

52 InferenceErrorInfo, 

53 InferenceResult, 

54 SuccessfulInferenceResult, 

55) 

56 

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

58 from typing import Self 

59else: 

60 from typing_extensions import Self 

61 

62if TYPE_CHECKING: 

63 from astroid import nodes 

64 from astroid.nodes import LocalsDictNodeNG 

65 

66 

67def _is_const(value) -> bool: 

68 return isinstance(value, tuple(CONST_CLS)) 

69 

70 

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

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

73 

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

75AssignedStmtsCall = Callable[ 

76 [ 

77 _NodesT, 

78 AssignedStmtsPossibleNode, 

79 Optional[InferenceContext], 

80 Optional[list[int]], 

81 ], 

82 Any, 

83] 

84InferBinaryOperation = Callable[ 

85 [_NodesT, Optional[InferenceContext]], 

86 Generator[Union[InferenceResult, _BadOpMessageT]], 

87] 

88InferLHS = Callable[ 

89 [_NodesT, Optional[InferenceContext]], 

90 Generator[InferenceResult, None, Optional[InferenceErrorInfo]], 

91] 

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

93 

94 

95@decorators.raise_if_nothing_inferred 

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

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

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

99 """ 

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

101 for elt in stmt.elts: 

102 if elt is util.Uninferable: 

103 yield elt 

104 continue 

105 yield from unpack_infer(elt, context) 

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

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

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

109 if inferred is stmt: 

110 yield inferred 

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

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

113 for inferred in stmt.infer(context): 

114 if isinstance(inferred, util.UninferableBase): 

115 yield inferred 

116 else: 

117 yield from unpack_infer(inferred, context) 

118 

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

120 

121 

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

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

124 

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

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

127 one of the given exceptions. 

128 

129 algorithm : 

130 1) index stmt1's parents 

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

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

133 in exclusive branches 

134 """ 

135 # index stmt1's parents 

136 stmt1_parents = {} 

137 children = {} 

138 previous = stmt1 

139 for node in stmt1.node_ancestors(): 

140 stmt1_parents[node] = 1 

141 children[node] = previous 

142 previous = node 

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

144 previous = stmt2 

145 for node in stmt2.node_ancestors(): 

146 if node in stmt1_parents: 

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

148 # nodes are in exclusive branches 

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

150 c2attr, c2node = node.locate_child(previous) 

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

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

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

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

155 return False 

156 if c1attr != c2attr: 

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

158 return True 

159 elif isinstance(node, Try): 

160 c2attr, c2node = node.locate_child(previous) 

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

162 if c1node is not c2node: 

163 first_in_body_caught_by_handlers = ( 

164 c2attr == "handlers" 

165 and c1attr == "body" 

166 and previous.catch(exceptions) 

167 ) 

168 second_in_body_caught_by_handlers = ( 

169 c2attr == "body" 

170 and c1attr == "handlers" 

171 and children[node].catch(exceptions) 

172 ) 

173 first_in_else_other_in_handlers = ( 

174 c2attr == "handlers" and c1attr == "orelse" 

175 ) 

176 second_in_else_other_in_handlers = ( 

177 c2attr == "orelse" and c1attr == "handlers" 

178 ) 

179 if any( 

180 ( 

181 first_in_body_caught_by_handlers, 

182 second_in_body_caught_by_handlers, 

183 first_in_else_other_in_handlers, 

184 second_in_else_other_in_handlers, 

185 ) 

186 ): 

187 return True 

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

189 return previous is not children[node] 

190 return False 

191 previous = node 

192 return False 

193 

194 

195# getitem() helpers. 

196 

197_SLICE_SENTINEL = object() 

198 

199 

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

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

202 

203 if isinstance(index, Const): 

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

205 return index.value 

206 elif index is None: 

207 return None 

208 else: 

209 # Try to infer what the index actually is. 

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

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

212 try: 

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

214 except (InferenceError, StopIteration): 

215 pass 

216 else: 

217 if isinstance(inferred, Const): 

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

219 return inferred.value 

220 

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

222 # value that this function can return, 

223 # as it is the case for unspecified bounds. 

224 return _SLICE_SENTINEL 

225 

226 

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

228 lower = _slice_value(node.lower, context) 

229 upper = _slice_value(node.upper, context) 

230 step = _slice_value(node.step, context) 

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

232 return slice(lower, upper, step) 

233 

234 raise AstroidTypeError( 

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

236 node=node, 

237 index=node.parent, 

238 context=context, 

239 ) 

240 

241 

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

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

244 try: 

245 if isinstance(index, Slice): 

246 index_slice = _infer_slice(index, context=context) 

247 new_cls = instance.__class__() 

248 new_cls.elts = elts[index_slice] 

249 new_cls.parent = instance.parent 

250 return new_cls 

251 if isinstance(index, Const): 

252 return elts[index.value] 

253 except ValueError as exc: 

254 raise AstroidValueError( 

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

256 node=instance, 

257 index=index, 

258 context=context, 

259 ) from exc 

260 except IndexError as exc: 

261 raise AstroidIndexError( 

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

263 node=instance, 

264 index=index, 

265 context=context, 

266 ) from exc 

267 except TypeError as exc: 

268 raise AstroidTypeError( 

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

270 ) from exc 

271 

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

273 

274 

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

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

277 

278 _astroid_fields = ("elts",) 

279 

280 def __init__( 

281 self, 

282 lineno: int | None, 

283 col_offset: int | None, 

284 parent: NodeNG | None, 

285 *, 

286 end_lineno: int | None, 

287 end_col_offset: int | None, 

288 ) -> None: 

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

290 """The elements in the node.""" 

291 

292 super().__init__( 

293 lineno=lineno, 

294 col_offset=col_offset, 

295 end_lineno=end_lineno, 

296 end_col_offset=end_col_offset, 

297 parent=parent, 

298 ) 

299 

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

301 self.elts = elts 

302 

303 @classmethod 

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

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

306 

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

308 

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

310 """ 

311 node = cls( 

312 lineno=None, 

313 col_offset=None, 

314 parent=None, 

315 end_lineno=None, 

316 end_col_offset=None, 

317 ) 

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

319 return node 

320 

321 def itered(self): 

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

323 

324 :returns: The contents of this node. 

325 :rtype: iterable(NodeNG) 

326 """ 

327 return self.elts 

328 

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

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

331 

332 :returns: The boolean value of this node. 

333 """ 

334 return bool(self.elts) 

335 

336 @abc.abstractmethod 

337 def pytype(self) -> str: 

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

339 

340 :returns: The name of the type. 

341 """ 

342 

343 def get_children(self): 

344 yield from self.elts 

345 

346 @decorators.raise_if_nothing_inferred 

347 def _infer( 

348 self, 

349 context: InferenceContext | None = None, 

350 **kwargs: Any, 

351 ) -> Iterator[Self]: 

352 has_starred_named_expr = any( 

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

354 ) 

355 if has_starred_named_expr: 

356 values = self._infer_sequence_helper(context) 

357 new_seq = type(self)( 

358 lineno=self.lineno, 

359 col_offset=self.col_offset, 

360 parent=self.parent, 

361 end_lineno=self.end_lineno, 

362 end_col_offset=self.end_col_offset, 

363 ) 

364 new_seq.postinit(values) 

365 

366 yield new_seq 

367 else: 

368 yield self 

369 

370 def _infer_sequence_helper( 

371 self, context: InferenceContext | None = None 

372 ) -> list[SuccessfulInferenceResult]: 

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

374 values = [] 

375 

376 for elt in self.elts: 

377 if isinstance(elt, Starred): 

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

379 if not starred: 

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

381 if not hasattr(starred, "elts"): 

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

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 

605DEPRECATED_ARGUMENT_DEFAULT = "DEPRECATED_ARGUMENT_DEFAULT" 

606 

607 

608class Arguments( 

609 _base_nodes.AssignTypeNode 

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

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

612 

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

614 function definition. 

615 

616 >>> import astroid 

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

618 >>> node 

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

620 >>> node.args 

621 <Arguments l.1 at 0x7effe1db82e8> 

622 """ 

623 

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

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

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

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

628 # is by using something similar with Python 3.3: 

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

630 # of varargs and kwargs. 

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

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

633 # annotation, its value will be None. 

634 _astroid_fields = ( 

635 "args", 

636 "defaults", 

637 "kwonlyargs", 

638 "posonlyargs", 

639 "posonlyargs_annotations", 

640 "kw_defaults", 

641 "annotations", 

642 "varargannotation", 

643 "kwargannotation", 

644 "kwonlyargs_annotations", 

645 "type_comment_args", 

646 "type_comment_kwonlyargs", 

647 "type_comment_posonlyargs", 

648 ) 

649 

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

651 

652 args: list[AssignName] | None 

653 """The names of the required arguments. 

654 

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

656 signature and the arguments are therefore unknown. 

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

658 incomplete signature information. 

659 """ 

660 

661 defaults: list[NodeNG] | None 

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

663 

664 kwonlyargs: list[AssignName] 

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

666 

667 posonlyargs: list[AssignName] 

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

669 

670 kw_defaults: list[NodeNG | None] | None 

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

672 

673 annotations: list[NodeNG | None] 

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

675 

676 posonlyargs_annotations: list[NodeNG | None] 

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

678 

679 kwonlyargs_annotations: list[NodeNG | None] 

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

681 

682 type_comment_args: list[NodeNG | None] 

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

684 

685 If an argument does not have a type comment, 

686 the value for that argument will be None. 

687 """ 

688 

689 type_comment_kwonlyargs: list[NodeNG | None] 

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

691 

692 If an argument does not have a type comment, 

693 the value for that argument will be None. 

694 """ 

695 

696 type_comment_posonlyargs: list[NodeNG | None] 

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

698 

699 If an argument does not have a type comment, 

700 the value for that argument will be None. 

701 """ 

702 

703 varargannotation: NodeNG | None 

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

705 

706 kwargannotation: NodeNG | None 

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

708 

709 vararg_node: AssignName | None 

710 """The node for variable length arguments""" 

711 

712 kwarg_node: AssignName | None 

713 """The node for variable keyword arguments""" 

714 

715 def __init__( 

716 self, 

717 vararg: str | None, 

718 kwarg: str | None, 

719 parent: NodeNG, 

720 vararg_node: AssignName | None = None, 

721 kwarg_node: AssignName | None = None, 

722 ) -> None: 

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

724 super().__init__( 

725 parent=parent, 

726 lineno=None, 

727 col_offset=None, 

728 end_lineno=None, 

729 end_col_offset=None, 

730 ) 

731 

732 self.vararg = vararg 

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

734 

735 self.kwarg = kwarg 

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

737 

738 self.vararg_node = vararg_node 

739 self.kwarg_node = kwarg_node 

740 

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

742 def postinit( 

743 self, 

744 args: list[AssignName] | None, 

745 defaults: list[NodeNG] | None, 

746 kwonlyargs: list[AssignName], 

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

748 annotations: list[NodeNG | None], 

749 posonlyargs: list[AssignName], 

750 kwonlyargs_annotations: list[NodeNG | None], 

751 posonlyargs_annotations: list[NodeNG | None], 

752 varargannotation: NodeNG | None = None, 

753 kwargannotation: NodeNG | None = None, 

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

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

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

757 ) -> None: 

758 self.args = args 

759 self.defaults = defaults 

760 self.kwonlyargs = kwonlyargs 

761 self.posonlyargs = posonlyargs 

762 self.kw_defaults = kw_defaults 

763 self.annotations = annotations 

764 self.kwonlyargs_annotations = kwonlyargs_annotations 

765 self.posonlyargs_annotations = posonlyargs_annotations 

766 

767 # Parameters that got added later and need a default 

768 self.varargannotation = varargannotation 

769 self.kwargannotation = kwargannotation 

770 if type_comment_args is None: 

771 type_comment_args = [] 

772 self.type_comment_args = type_comment_args 

773 if type_comment_kwonlyargs is None: 

774 type_comment_kwonlyargs = [] 

775 self.type_comment_kwonlyargs = type_comment_kwonlyargs 

776 if type_comment_posonlyargs is None: 

777 type_comment_posonlyargs = [] 

778 self.type_comment_posonlyargs = type_comment_posonlyargs 

779 

780 assigned_stmts = protocols.arguments_assigned_stmts 

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

782 See astroid/protocols.py for actual implementation. 

783 """ 

784 

785 def _infer_name(self, frame, name): 

786 if self.parent is frame: 

787 return name 

788 return None 

789 

790 @cached_property 

791 def fromlineno(self) -> int: 

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

793 

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

795 """ 

796 lineno = super().fromlineno 

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

798 

799 @cached_property 

800 def arguments(self): 

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

802 * Positional only arguments 

803 * Positional arguments 

804 * Keyword arguments 

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

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

807 """ 

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

809 if self.vararg_node: 

810 retval.append(self.vararg_node) 

811 retval += self.kwonlyargs or () 

812 if self.kwarg_node: 

813 retval.append(self.kwarg_node) 

814 

815 return retval 

816 

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

818 """Get the arguments formatted as string. 

819 

820 :returns: The formatted arguments. 

821 :rtype: str 

822 """ 

823 result = [] 

824 positional_only_defaults = [] 

825 positional_or_keyword_defaults = self.defaults 

826 if self.defaults: 

827 args = self.args or [] 

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

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

830 

831 if self.posonlyargs: 

832 result.append( 

833 _format_args( 

834 self.posonlyargs, 

835 positional_only_defaults, 

836 self.posonlyargs_annotations, 

837 skippable_names=skippable_names, 

838 ) 

839 ) 

840 result.append("/") 

841 if self.args: 

842 result.append( 

843 _format_args( 

844 self.args, 

845 positional_or_keyword_defaults, 

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

847 skippable_names=skippable_names, 

848 ) 

849 ) 

850 if self.vararg: 

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

852 if self.kwonlyargs: 

853 if not self.vararg: 

854 result.append("*") 

855 result.append( 

856 _format_args( 

857 self.kwonlyargs, 

858 self.kw_defaults, 

859 self.kwonlyargs_annotations, 

860 skippable_names=skippable_names, 

861 ) 

862 ) 

863 if self.kwarg: 

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

865 return ", ".join(result) 

866 

867 def _get_arguments_data( 

868 self, 

869 ) -> tuple[ 

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

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

872 ]: 

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

874 

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

876 and their default value, if any. 

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

878 returns the data that is used to do so. 

879 """ 

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

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

882 

883 # Setup and match defaults with arguments 

884 positional_only_defaults = [] 

885 positional_or_keyword_defaults = self.defaults 

886 if self.defaults: 

887 args = self.args or [] 

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

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

890 

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

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

893 if annotation is not None: 

894 annotation = annotation.as_string() 

895 if positional_only_defaults: 

896 default = positional_only_defaults[index].as_string() 

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

898 

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

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

901 if annotation is not None: 

902 annotation = annotation.as_string() 

903 if positional_or_keyword_defaults: 

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

905 default_index = index - defaults_offset 

906 if ( 

907 default_index > -1 

908 and positional_or_keyword_defaults[default_index] is not None 

909 ): 

910 default = positional_or_keyword_defaults[default_index].as_string() 

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

912 

913 if self.vararg: 

914 annotation = self.varargannotation 

915 if annotation is not None: 

916 annotation = annotation.as_string() 

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

918 

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

920 annotation = self.kwonlyargs_annotations[index] 

921 if annotation is not None: 

922 annotation = annotation.as_string() 

923 default = self.kw_defaults[index] 

924 if default is not None: 

925 default = default.as_string() 

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

927 

928 if self.kwarg: 

929 annotation = self.kwargannotation 

930 if annotation is not None: 

931 annotation = annotation.as_string() 

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

933 

934 return pos_only, kw_only 

935 

936 def default_value(self, argname): 

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

938 

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

940 :type argname: str 

941 

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

943 given argument. 

944 """ 

945 args = [ 

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

947 ] 

948 

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

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

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

952 return self.kw_defaults[index] 

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

954 

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

956 if index is not None: 

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

958 if idx >= 0: 

959 return self.defaults[idx] 

960 

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

962 

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

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

965 

966 :param name: The name to check for. 

967 :type name: str 

968 

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

970 """ 

971 if name == self.vararg: 

972 return True 

973 if name == self.kwarg: 

974 return True 

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

976 

977 def find_argname(self, argname, rec=DEPRECATED_ARGUMENT_DEFAULT): 

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

979 

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

981 :type argname: str 

982 

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

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

985 """ 

986 if rec != DEPRECATED_ARGUMENT_DEFAULT: # pragma: no cover 

987 warnings.warn( 

988 "The rec argument will be removed in astroid 3.1.", 

989 DeprecationWarning, 

990 stacklevel=2, 

991 ) 

992 if self.arguments: 

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

994 if argument: 

995 return index, argument 

996 return None, None 

997 

998 def get_children(self): 

999 yield from self.posonlyargs or () 

1000 

1001 for elt in self.posonlyargs_annotations: 

1002 if elt is not None: 

1003 yield elt 

1004 

1005 yield from self.args or () 

1006 

1007 if self.defaults is not None: 

1008 yield from self.defaults 

1009 yield from self.kwonlyargs 

1010 

1011 for elt in self.kw_defaults or (): 

1012 if elt is not None: 

1013 yield elt 

1014 

1015 for elt in self.annotations: 

1016 if elt is not None: 

1017 yield elt 

1018 

1019 if self.varargannotation is not None: 

1020 yield self.varargannotation 

1021 

1022 if self.kwargannotation is not None: 

1023 yield self.kwargannotation 

1024 

1025 for elt in self.kwonlyargs_annotations: 

1026 if elt is not None: 

1027 yield elt 

1028 

1029 @decorators.raise_if_nothing_inferred 

1030 def _infer( 

1031 self: nodes.Arguments, context: InferenceContext | None = None, **kwargs: Any 

1032 ) -> Generator[InferenceResult]: 

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

1034 from astroid.protocols import _arguments_infer_argname 

1035 

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

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

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

1039 

1040 

1041def _find_arg(argname, args): 

1042 for i, arg in enumerate(args): 

1043 if arg.name == argname: 

1044 return i, arg 

1045 return None, None 

1046 

1047 

1048def _format_args( 

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

1050) -> str: 

1051 if skippable_names is None: 

1052 skippable_names = set() 

1053 values = [] 

1054 if args is None: 

1055 return "" 

1056 if annotations is None: 

1057 annotations = [] 

1058 if defaults is not None: 

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

1060 else: 

1061 default_offset = None 

1062 packed = itertools.zip_longest(args, annotations) 

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

1064 if arg.name in skippable_names: 

1065 continue 

1066 if isinstance(arg, Tuple): 

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

1068 else: 

1069 argname = arg.name 

1070 default_sep = "=" 

1071 if annotation is not None: 

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

1073 default_sep = " = " 

1074 values.append(argname) 

1075 

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

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

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

1079 return ", ".join(values) 

1080 

1081 

1082def _infer_attribute( 

1083 node: nodes.AssignAttr | nodes.Attribute, 

1084 context: InferenceContext | None = None, 

1085 **kwargs: Any, 

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

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

1088 # pylint: disable=import-outside-toplevel 

1089 from astroid.constraint import get_constraints 

1090 from astroid.nodes import ClassDef 

1091 

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

1093 if isinstance(owner, util.UninferableBase): 

1094 yield owner 

1095 continue 

1096 

1097 context = copy_context(context) 

1098 old_boundnode = context.boundnode 

1099 try: 

1100 context.boundnode = owner 

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

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

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

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

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

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

1107 yield util.Uninferable 

1108 else: 

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

1110 except ( 

1111 AttributeInferenceError, 

1112 InferenceError, 

1113 AttributeError, 

1114 ): 

1115 pass 

1116 finally: 

1117 context.boundnode = old_boundnode 

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

1119 

1120 

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

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

1123 

1124 >>> import astroid 

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

1126 >>> node 

1127 <Assign l.1 at 0x7effe1d521d0> 

1128 >>> list(node.get_children()) 

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

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

1131 'self.attribute' 

1132 """ 

1133 

1134 expr: NodeNG 

1135 

1136 _astroid_fields = ("expr",) 

1137 _other_fields = ("attrname",) 

1138 

1139 def __init__( 

1140 self, 

1141 attrname: str, 

1142 lineno: int, 

1143 col_offset: int, 

1144 parent: NodeNG, 

1145 *, 

1146 end_lineno: int | None, 

1147 end_col_offset: int | None, 

1148 ) -> None: 

1149 self.attrname = attrname 

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

1151 

1152 super().__init__( 

1153 lineno=lineno, 

1154 col_offset=col_offset, 

1155 end_lineno=end_lineno, 

1156 end_col_offset=end_col_offset, 

1157 parent=parent, 

1158 ) 

1159 

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

1161 self.expr = expr 

1162 

1163 assigned_stmts = protocols.assend_assigned_stmts 

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

1165 See astroid/protocols.py for actual implementation. 

1166 """ 

1167 

1168 def get_children(self): 

1169 yield self.expr 

1170 

1171 @decorators.raise_if_nothing_inferred 

1172 @decorators.path_wrapper 

1173 def _infer( 

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

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

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

1177 assign node. 

1178 """ 

1179 if isinstance(self.parent, AugAssign): 

1180 return self.parent.infer(context) 

1181 

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

1183 return _infer_stmts(stmts, context) 

1184 

1185 @decorators.raise_if_nothing_inferred 

1186 @decorators.path_wrapper 

1187 def infer_lhs( 

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

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

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

1191 

1192 

1193class Assert(_base_nodes.Statement): 

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

1195 

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

1197 

1198 >>> import astroid 

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

1200 >>> node 

1201 <Assert l.1 at 0x7effe1d527b8> 

1202 """ 

1203 

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

1205 

1206 test: NodeNG 

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

1208 

1209 fail: NodeNG | None 

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

1211 

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

1213 self.fail = fail 

1214 self.test = test 

1215 

1216 def get_children(self): 

1217 yield self.test 

1218 

1219 if self.fail is not None: 

1220 yield self.fail 

1221 

1222 

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

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

1225 

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

1227 asssigned to. 

1228 

1229 >>> import astroid 

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

1231 >>> node 

1232 <Assign l.1 at 0x7effe1db8550> 

1233 """ 

1234 

1235 targets: list[NodeNG] 

1236 """What is being assigned to.""" 

1237 

1238 value: NodeNG 

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

1240 

1241 type_annotation: NodeNG | None 

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

1243 

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

1245 _other_other_fields = ("type_annotation",) 

1246 

1247 def postinit( 

1248 self, 

1249 targets: list[NodeNG], 

1250 value: NodeNG, 

1251 type_annotation: NodeNG | None, 

1252 ) -> None: 

1253 self.targets = targets 

1254 self.value = value 

1255 self.type_annotation = type_annotation 

1256 

1257 assigned_stmts = protocols.assign_assigned_stmts 

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

1259 See astroid/protocols.py for actual implementation. 

1260 """ 

1261 

1262 def get_children(self): 

1263 yield from self.targets 

1264 

1265 yield self.value 

1266 

1267 @cached_property 

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

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

1270 

1271 def _get_yield_nodes_skip_functions(self): 

1272 yield from self.value._get_yield_nodes_skip_functions() 

1273 

1274 def _get_yield_nodes_skip_lambdas(self): 

1275 yield from self.value._get_yield_nodes_skip_lambdas() 

1276 

1277 

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

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

1280 

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

1282 

1283 >>> import astroid 

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

1285 >>> node 

1286 <AnnAssign l.1 at 0x7effe1d4c630> 

1287 """ 

1288 

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

1290 _other_fields = ("simple",) 

1291 

1292 target: Name | Attribute | Subscript 

1293 """What is being assigned to.""" 

1294 

1295 annotation: NodeNG 

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

1297 

1298 value: NodeNG | None 

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

1300 

1301 simple: int 

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

1303 

1304 def postinit( 

1305 self, 

1306 target: Name | Attribute | Subscript, 

1307 annotation: NodeNG, 

1308 simple: int, 

1309 value: NodeNG | None, 

1310 ) -> None: 

1311 self.target = target 

1312 self.annotation = annotation 

1313 self.value = value 

1314 self.simple = simple 

1315 

1316 assigned_stmts = protocols.assign_annassigned_stmts 

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

1318 See astroid/protocols.py for actual implementation. 

1319 """ 

1320 

1321 def get_children(self): 

1322 yield self.target 

1323 yield self.annotation 

1324 

1325 if self.value is not None: 

1326 yield self.value 

1327 

1328 

1329class AugAssign( 

1330 _base_nodes.AssignTypeNode, _base_nodes.OperatorNode, _base_nodes.Statement 

1331): 

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

1333 

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

1335 

1336 >>> import astroid 

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

1338 >>> node 

1339 <AugAssign l.1 at 0x7effe1db4d68> 

1340 """ 

1341 

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

1343 _other_fields = ("op",) 

1344 

1345 target: Name | Attribute | Subscript 

1346 """What is being assigned to.""" 

1347 

1348 value: NodeNG 

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

1350 

1351 def __init__( 

1352 self, 

1353 op: str, 

1354 lineno: int, 

1355 col_offset: int, 

1356 parent: NodeNG, 

1357 *, 

1358 end_lineno: int | None, 

1359 end_col_offset: int | None, 

1360 ) -> None: 

1361 self.op = op 

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

1363 

1364 This includes the equals sign. 

1365 """ 

1366 

1367 super().__init__( 

1368 lineno=lineno, 

1369 col_offset=col_offset, 

1370 end_lineno=end_lineno, 

1371 end_col_offset=end_col_offset, 

1372 parent=parent, 

1373 ) 

1374 

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

1376 self.target = target 

1377 self.value = value 

1378 

1379 assigned_stmts = protocols.assign_assigned_stmts 

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

1381 See astroid/protocols.py for actual implementation. 

1382 """ 

1383 

1384 def type_errors( 

1385 self, context: InferenceContext | None = None 

1386 ) -> list[util.BadBinaryOperationMessage]: 

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

1388 

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

1390 which holds the original exception. 

1391 

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

1393 """ 

1394 bad = [] 

1395 try: 

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

1397 if result is util.Uninferable: 

1398 raise InferenceError 

1399 if isinstance(result, util.BadBinaryOperationMessage): 

1400 bad.append(result) 

1401 except InferenceError: 

1402 return [] 

1403 return bad 

1404 

1405 def get_children(self): 

1406 yield self.target 

1407 yield self.value 

1408 

1409 def _get_yield_nodes_skip_functions(self): 

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

1411 yield from self.value._get_yield_nodes_skip_functions() 

1412 yield from super()._get_yield_nodes_skip_functions() 

1413 

1414 def _get_yield_nodes_skip_lambdas(self): 

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

1416 yield from self.value._get_yield_nodes_skip_lambdas() 

1417 yield from super()._get_yield_nodes_skip_lambdas() 

1418 

1419 def _infer_augassign( 

1420 self, context: InferenceContext | None = None 

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

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

1423 context = context or InferenceContext() 

1424 

1425 rhs_context = context.clone() 

1426 

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

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

1429 

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

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

1432 # Don't know how to process this. 

1433 yield util.Uninferable 

1434 return 

1435 

1436 try: 

1437 yield from self._infer_binary_operation( 

1438 left=lhs, 

1439 right=rhs, 

1440 binary_opnode=self, 

1441 context=context, 

1442 flow_factory=self._get_aug_flow, 

1443 ) 

1444 except _NonDeducibleTypeHierarchy: 

1445 yield util.Uninferable 

1446 

1447 @decorators.raise_if_nothing_inferred 

1448 @decorators.path_wrapper 

1449 def _infer( 

1450 self: nodes.AugAssign, context: InferenceContext | None = None, **kwargs: Any 

1451 ) -> Generator[InferenceResult]: 

1452 return self._filter_operation_errors( 

1453 self._infer_augassign, context, util.BadBinaryOperationMessage 

1454 ) 

1455 

1456 

1457class BinOp(_base_nodes.OperatorNode): 

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

1459 

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

1461 

1462 >>> import astroid 

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

1464 >>> node 

1465 <BinOp l.1 at 0x7f23b2e8cfd0> 

1466 """ 

1467 

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

1469 _other_fields = ("op",) 

1470 

1471 left: NodeNG 

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

1473 

1474 right: NodeNG 

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

1476 

1477 def __init__( 

1478 self, 

1479 op: str, 

1480 lineno: int, 

1481 col_offset: int, 

1482 parent: NodeNG, 

1483 *, 

1484 end_lineno: int | None, 

1485 end_col_offset: int | None, 

1486 ) -> None: 

1487 self.op = op 

1488 """The operator.""" 

1489 

1490 super().__init__( 

1491 lineno=lineno, 

1492 col_offset=col_offset, 

1493 end_lineno=end_lineno, 

1494 end_col_offset=end_col_offset, 

1495 parent=parent, 

1496 ) 

1497 

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

1499 self.left = left 

1500 self.right = right 

1501 

1502 def type_errors( 

1503 self, context: InferenceContext | None = None 

1504 ) -> list[util.BadBinaryOperationMessage]: 

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

1506 

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

1508 which holds the original exception. 

1509 

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

1511 """ 

1512 bad = [] 

1513 try: 

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

1515 if result is util.Uninferable: 

1516 raise InferenceError 

1517 if isinstance(result, util.BadBinaryOperationMessage): 

1518 bad.append(result) 

1519 except InferenceError: 

1520 return [] 

1521 return bad 

1522 

1523 def get_children(self): 

1524 yield self.left 

1525 yield self.right 

1526 

1527 def op_precedence(self) -> int: 

1528 return OP_PRECEDENCE[self.op] 

1529 

1530 def op_left_associative(self) -> bool: 

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

1532 return self.op != "**" 

1533 

1534 def _infer_binop( 

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

1536 ) -> Generator[InferenceResult]: 

1537 """Binary operation inference logic.""" 

1538 left = self.left 

1539 right = self.right 

1540 

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

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

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

1544 context = context or InferenceContext() 

1545 lhs_context = copy_context(context) 

1546 rhs_context = copy_context(context) 

1547 lhs_iter = left.infer(context=lhs_context) 

1548 rhs_iter = right.infer(context=rhs_context) 

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

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

1551 # Don't know how to process this. 

1552 yield util.Uninferable 

1553 return 

1554 

1555 try: 

1556 yield from self._infer_binary_operation( 

1557 lhs, rhs, self, context, self._get_binop_flow 

1558 ) 

1559 except _NonDeducibleTypeHierarchy: 

1560 yield util.Uninferable 

1561 

1562 @decorators.yes_if_nothing_inferred 

1563 @decorators.path_wrapper 

1564 def _infer( 

1565 self: nodes.BinOp, context: InferenceContext | None = None, **kwargs: Any 

1566 ) -> Generator[InferenceResult]: 

1567 return self._filter_operation_errors( 

1568 self._infer_binop, context, util.BadBinaryOperationMessage 

1569 ) 

1570 

1571 

1572class BoolOp(NodeNG): 

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

1574 

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

1576 

1577 >>> import astroid 

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

1579 >>> node 

1580 <BinOp l.1 at 0x7f23b2e71c50> 

1581 """ 

1582 

1583 _astroid_fields = ("values",) 

1584 _other_fields = ("op",) 

1585 

1586 def __init__( 

1587 self, 

1588 op: str, 

1589 lineno: int | None = None, 

1590 col_offset: int | None = None, 

1591 parent: NodeNG | None = None, 

1592 *, 

1593 end_lineno: int | None = None, 

1594 end_col_offset: int | None = None, 

1595 ) -> None: 

1596 """ 

1597 :param op: The operator. 

1598 

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

1600 

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

1602 source code. 

1603 

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

1605 

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

1607 

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

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

1610 """ 

1611 self.op: str = op 

1612 """The operator.""" 

1613 

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

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

1616 

1617 super().__init__( 

1618 lineno=lineno, 

1619 col_offset=col_offset, 

1620 end_lineno=end_lineno, 

1621 end_col_offset=end_col_offset, 

1622 parent=parent, 

1623 ) 

1624 

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

1626 """Do some setup after initialisation. 

1627 

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

1629 """ 

1630 if values is not None: 

1631 self.values = values 

1632 

1633 def get_children(self): 

1634 yield from self.values 

1635 

1636 def op_precedence(self) -> int: 

1637 return OP_PRECEDENCE[self.op] 

1638 

1639 @decorators.raise_if_nothing_inferred 

1640 @decorators.path_wrapper 

1641 def _infer( 

1642 self: nodes.BoolOp, context: InferenceContext | None = None, **kwargs: Any 

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

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

1645 

1646 The function will calculate the boolean operation 

1647 for all pairs generated through inference for each component 

1648 node. 

1649 """ 

1650 values = self.values 

1651 if self.op == "or": 

1652 predicate = operator.truth 

1653 else: 

1654 predicate = operator.not_ 

1655 

1656 try: 

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

1658 except InferenceError: 

1659 yield util.Uninferable 

1660 return None 

1661 

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

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

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

1665 yield util.Uninferable 

1666 continue 

1667 

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

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

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

1671 yield util.Uninferable 

1672 continue 

1673 

1674 # Since the boolean operations are short circuited operations, 

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

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

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

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

1679 # 1 and 0 -> 1 

1680 # 0 and 1 -> 0 

1681 # 1 or 0 -> 1 

1682 # 0 or 1 -> 1 

1683 value = util.Uninferable 

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

1685 if predicate(bool_value): 

1686 yield value 

1687 break 

1688 else: 

1689 yield value 

1690 

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

1692 

1693 

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

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

1696 

1697 >>> import astroid 

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

1699 >>> node 

1700 <Break l.1 at 0x7f23b2e9e5c0> 

1701 """ 

1702 

1703 

1704class Call(NodeNG): 

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

1706 

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

1708 

1709 >>> import astroid 

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

1711 >>> node 

1712 <Call l.1 at 0x7f23b2e71eb8> 

1713 """ 

1714 

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

1716 

1717 func: NodeNG 

1718 """What is being called.""" 

1719 

1720 args: list[NodeNG] 

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

1722 

1723 keywords: list[Keyword] 

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

1725 

1726 def postinit( 

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

1728 ) -> None: 

1729 self.func = func 

1730 self.args = args 

1731 self.keywords = keywords 

1732 

1733 @property 

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

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

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

1737 

1738 @property 

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

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

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

1742 

1743 def get_children(self): 

1744 yield self.func 

1745 

1746 yield from self.args 

1747 

1748 yield from self.keywords 

1749 

1750 @decorators.raise_if_nothing_inferred 

1751 @decorators.path_wrapper 

1752 def _infer( 

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

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

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

1756 callcontext = copy_context(context) 

1757 callcontext.boundnode = None 

1758 if context is not None: 

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

1760 

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

1762 if isinstance(callee, util.UninferableBase): 

1763 yield callee 

1764 continue 

1765 try: 

1766 if hasattr(callee, "infer_call_result"): 

1767 callcontext.callcontext = CallContext( 

1768 args=self.args, keywords=self.keywords, callee=callee 

1769 ) 

1770 yield from callee.infer_call_result( 

1771 caller=self, context=callcontext 

1772 ) 

1773 except InferenceError: 

1774 continue 

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

1776 

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

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

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

1780 if context is None: 

1781 return context_lookup 

1782 for arg in self.args: 

1783 if isinstance(arg, Starred): 

1784 context_lookup[arg.value] = context 

1785 else: 

1786 context_lookup[arg] = context 

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

1788 for keyword in keywords: 

1789 context_lookup[keyword.value] = context 

1790 return context_lookup 

1791 

1792 

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

1794 "==": operator.eq, 

1795 "!=": operator.ne, 

1796 "<": operator.lt, 

1797 "<=": operator.le, 

1798 ">": operator.gt, 

1799 ">=": operator.ge, 

1800 "in": lambda a, b: a in b, 

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

1802} 

1803UNINFERABLE_OPS = { 

1804 "is", 

1805 "is not", 

1806} 

1807 

1808 

1809class Compare(NodeNG): 

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

1811 

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

1813 

1814 >>> import astroid 

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

1816 >>> node 

1817 <Compare l.1 at 0x7f23b2e9e6d8> 

1818 >>> node.ops 

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

1820 """ 

1821 

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

1823 

1824 left: NodeNG 

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

1826 

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

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

1829 

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

1831 self.left = left 

1832 self.ops = ops 

1833 

1834 def get_children(self): 

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

1836 

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

1838 strings. 

1839 

1840 :returns: The children. 

1841 :rtype: iterable(NodeNG) 

1842 """ 

1843 yield self.left 

1844 for _, comparator in self.ops: 

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

1846 

1847 def last_child(self): 

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

1849 

1850 :returns: The last child. 

1851 :rtype: NodeNG 

1852 """ 

1853 # XXX maybe if self.ops: 

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

1855 # return self.left 

1856 

1857 # TODO: move to util? 

1858 @staticmethod 

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

1860 # Can raise SyntaxError or ValueError from ast.literal_eval 

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

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

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

1864 

1865 def _do_compare( 

1866 self, 

1867 left_iter: Iterable[InferenceResult], 

1868 op: str, 

1869 right_iter: Iterable[InferenceResult], 

1870 ) -> bool | util.UninferableBase: 

1871 """ 

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

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

1874 True 

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

1876 False 

1877 

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

1879 are False, return Uninferable: 

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

1881 util.Uninferable 

1882 """ 

1883 retval: bool | None = None 

1884 if op in UNINFERABLE_OPS: 

1885 return util.Uninferable 

1886 op_func = COMPARE_OPS[op] 

1887 

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

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

1890 right, util.UninferableBase 

1891 ): 

1892 return util.Uninferable 

1893 

1894 try: 

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

1896 except (SyntaxError, ValueError, AttributeError): 

1897 return util.Uninferable 

1898 

1899 try: 

1900 expr = op_func(left, right) 

1901 except TypeError as exc: 

1902 raise AstroidTypeError from exc 

1903 

1904 if retval is None: 

1905 retval = expr 

1906 elif retval != expr: 

1907 return util.Uninferable 

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

1909 

1910 assert retval is not None 

1911 return retval # it was all the same value 

1912 

1913 def _infer( 

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

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

1916 """Chained comparison inference logic.""" 

1917 retval: bool | util.UninferableBase = True 

1918 

1919 ops = self.ops 

1920 left_node = self.left 

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

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

1923 for op, right_node in ops: 

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

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

1926 try: 

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

1928 except AstroidTypeError: 

1929 retval = util.Uninferable 

1930 break 

1931 if retval is not True: 

1932 break # short-circuit 

1933 lhs = rhs # continue 

1934 if retval is util.Uninferable: 

1935 yield retval # type: ignore[misc] 

1936 else: 

1937 yield Const(retval) 

1938 

1939 

1940class Comprehension(NodeNG): 

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

1942 

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

1944 comprehension including generator expressions. 

1945 

1946 >>> import astroid 

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

1948 >>> list(node.get_children()) 

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

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

1951 'for x in some_values' 

1952 """ 

1953 

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

1955 _other_fields = ("is_async",) 

1956 

1957 optional_assign = True 

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

1959 

1960 target: NodeNG 

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

1962 

1963 iter: NodeNG 

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

1965 

1966 ifs: list[NodeNG] 

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

1968 

1969 is_async: bool 

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

1971 

1972 def postinit( 

1973 self, 

1974 target: NodeNG, 

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

1976 ifs: list[NodeNG], 

1977 is_async: bool, 

1978 ) -> None: 

1979 self.target = target 

1980 self.iter = iter 

1981 self.ifs = ifs 

1982 self.is_async = is_async 

1983 

1984 assigned_stmts = protocols.for_assigned_stmts 

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

1986 See astroid/protocols.py for actual implementation. 

1987 """ 

1988 

1989 def assign_type(self): 

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

1991 

1992 :returns: The assignment type. 

1993 :rtype: NodeNG 

1994 """ 

1995 return self 

1996 

1997 def _get_filtered_stmts( 

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

1999 ): 

2000 """method used in filter_stmts""" 

2001 if self is mystmt: 

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

2003 return [lookup_node], True 

2004 

2005 elif self.statement() is mystmt: 

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

2007 # current node (gen exp, list comp) 

2008 

2009 return [node], True 

2010 

2011 return stmts, False 

2012 

2013 def get_children(self): 

2014 yield self.target 

2015 yield self.iter 

2016 

2017 yield from self.ifs 

2018 

2019 

2020class Const(_base_nodes.NoChildrenNode, Instance): 

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

2022 

2023 >>> import astroid 

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

2025 >>> node 

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

2027 >>> list(node.get_children()) 

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

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

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

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

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

2033 """ 

2034 

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

2036 

2037 def __init__( 

2038 self, 

2039 value: Any, 

2040 lineno: int | None = None, 

2041 col_offset: int | None = None, 

2042 parent: NodeNG = SYNTHETIC_ROOT, 

2043 kind: str | None = None, 

2044 *, 

2045 end_lineno: int | None = None, 

2046 end_col_offset: int | None = None, 

2047 ) -> None: 

2048 """ 

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

2050 

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

2052 

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

2054 source code. 

2055 

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

2057 

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

2059 

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

2061 

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

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

2064 """ 

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

2066 warnings.warn( # pragma: no cover 

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

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

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

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

2071 RuntimeWarning, 

2072 stacklevel=0, 

2073 ) 

2074 self.value = value 

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

2076 

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

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

2079 

2080 super().__init__( 

2081 lineno=lineno, 

2082 col_offset=col_offset, 

2083 end_lineno=end_lineno, 

2084 end_col_offset=end_col_offset, 

2085 parent=parent, 

2086 ) 

2087 

2088 Instance.__init__(self, None) 

2089 

2090 infer_unary_op = protocols.const_infer_unary_op 

2091 infer_binary_op = protocols.const_infer_binary_op 

2092 

2093 def __getattr__(self, name): 

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

2095 # Calling object.__new__ on this class without calling 

2096 # __init__ would result in an infinite loop otherwise 

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

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

2099 # and Proxy __getattr__ calls self.value 

2100 if name == "value": 

2101 raise AttributeError 

2102 return super().__getattr__(name) 

2103 

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

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

2106 

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

2108 :type index: Const or Slice 

2109 

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

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

2112 """ 

2113 if isinstance(index, Const): 

2114 index_value = index.value 

2115 elif isinstance(index, Slice): 

2116 index_value = _infer_slice(index, context=context) 

2117 

2118 else: 

2119 raise AstroidTypeError( 

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

2121 ) 

2122 

2123 try: 

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

2125 return Const(self.value[index_value]) 

2126 except ValueError as exc: 

2127 raise AstroidValueError( 

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

2129 ) from exc 

2130 except IndexError as exc: 

2131 raise AstroidIndexError( 

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

2133 node=self, 

2134 index=index, 

2135 context=context, 

2136 ) from exc 

2137 except TypeError as exc: 

2138 raise AstroidTypeError( 

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

2140 ) from exc 

2141 

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

2143 

2144 def has_dynamic_getattr(self) -> bool: 

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

2146 

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

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

2149 """ 

2150 return False 

2151 

2152 def itered(self): 

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

2154 

2155 :returns: The contents of this node. 

2156 :rtype: iterable(Const) 

2157 

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

2159 """ 

2160 if isinstance(self.value, str): 

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

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

2163 

2164 def pytype(self) -> str: 

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

2166 

2167 :returns: The name of the type. 

2168 """ 

2169 return self._proxied.qname() 

2170 

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

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

2173 

2174 :returns: The boolean value of this node. 

2175 :rtype: bool 

2176 """ 

2177 return bool(self.value) 

2178 

2179 def _infer( 

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

2181 ) -> Iterator[Const]: 

2182 yield self 

2183 

2184 

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

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

2187 

2188 >>> import astroid 

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

2190 >>> node 

2191 <Continue l.1 at 0x7f23b2e35588> 

2192 """ 

2193 

2194 

2195class Decorators(NodeNG): 

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

2197 

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

2199 a method or function. 

2200 

2201 >>> import astroid 

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

2203 @property 

2204 def my_property(self): 

2205 return 3 

2206 ''') 

2207 >>> node 

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

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

2210 <Decorators l.1 at 0x7f23b2e35d68> 

2211 """ 

2212 

2213 _astroid_fields = ("nodes",) 

2214 

2215 nodes: list[NodeNG] 

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

2217 

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

2219 self.nodes = nodes 

2220 

2221 def scope(self) -> LocalsDictNodeNG: 

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

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

2224 

2225 :returns: The first parent scope node. 

2226 """ 

2227 # skip the function node to go directly to the upper level scope 

2228 if not self.parent: 

2229 raise ParentMissingError(target=self) 

2230 if not self.parent.parent: 

2231 raise ParentMissingError(target=self.parent) 

2232 return self.parent.parent.scope() 

2233 

2234 def get_children(self): 

2235 yield from self.nodes 

2236 

2237 

2238class DelAttr(_base_nodes.ParentAssignNode): 

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

2240 

2241 >>> import astroid 

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

2243 >>> node 

2244 <Delete l.1 at 0x7f23b2e35f60> 

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

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

2247 """ 

2248 

2249 _astroid_fields = ("expr",) 

2250 _other_fields = ("attrname",) 

2251 

2252 expr: NodeNG 

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

2254 

2255 def __init__( 

2256 self, 

2257 attrname: str, 

2258 lineno: int, 

2259 col_offset: int, 

2260 parent: NodeNG, 

2261 *, 

2262 end_lineno: int | None, 

2263 end_col_offset: int | None, 

2264 ) -> None: 

2265 self.attrname = attrname 

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

2267 

2268 super().__init__( 

2269 lineno=lineno, 

2270 col_offset=col_offset, 

2271 end_lineno=end_lineno, 

2272 end_col_offset=end_col_offset, 

2273 parent=parent, 

2274 ) 

2275 

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

2277 self.expr = expr 

2278 

2279 def get_children(self): 

2280 yield self.expr 

2281 

2282 

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

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

2285 

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

2287 

2288 >>> import astroid 

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

2290 >>> node 

2291 <Delete l.1 at 0x7f23b2e35f60> 

2292 """ 

2293 

2294 _astroid_fields = ("targets",) 

2295 

2296 def __init__( 

2297 self, 

2298 lineno: int, 

2299 col_offset: int, 

2300 parent: NodeNG, 

2301 *, 

2302 end_lineno: int | None, 

2303 end_col_offset: int | None, 

2304 ) -> None: 

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

2306 """What is being deleted.""" 

2307 

2308 super().__init__( 

2309 lineno=lineno, 

2310 col_offset=col_offset, 

2311 end_lineno=end_lineno, 

2312 end_col_offset=end_col_offset, 

2313 parent=parent, 

2314 ) 

2315 

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

2317 self.targets = targets 

2318 

2319 def get_children(self): 

2320 yield from self.targets 

2321 

2322 

2323class Dict(NodeNG, Instance): 

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

2325 

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

2327 

2328 >>> import astroid 

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

2330 >>> node 

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

2332 """ 

2333 

2334 _astroid_fields = ("items",) 

2335 

2336 def __init__( 

2337 self, 

2338 lineno: int | None, 

2339 col_offset: int | None, 

2340 parent: NodeNG | None, 

2341 *, 

2342 end_lineno: int | None, 

2343 end_col_offset: int | None, 

2344 ) -> None: 

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

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

2347 

2348 super().__init__( 

2349 lineno=lineno, 

2350 col_offset=col_offset, 

2351 end_lineno=end_lineno, 

2352 end_col_offset=end_col_offset, 

2353 parent=parent, 

2354 ) 

2355 

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

2357 """Do some setup after initialisation. 

2358 

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

2360 """ 

2361 self.items = items 

2362 

2363 infer_unary_op = protocols.dict_infer_unary_op 

2364 

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

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

2367 

2368 :returns: The name of the type. 

2369 """ 

2370 return "builtins.dict" 

2371 

2372 def get_children(self): 

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

2374 

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

2376 code, key first then the value. 

2377 

2378 :returns: The children. 

2379 :rtype: iterable(NodeNG) 

2380 """ 

2381 for key, value in self.items: 

2382 yield key 

2383 yield value 

2384 

2385 def last_child(self): 

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

2387 

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

2389 :rtype: NodeNG or None 

2390 """ 

2391 if self.items: 

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

2393 return None 

2394 

2395 def itered(self): 

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

2397 

2398 :returns: The keys of this node. 

2399 :rtype: iterable(NodeNG) 

2400 """ 

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

2402 

2403 def getitem( 

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

2405 ) -> NodeNG: 

2406 """Get an item from this node. 

2407 

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

2409 

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

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

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

2413 dictionary. 

2414 """ 

2415 for key, value in self.items: 

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

2417 if isinstance(key, DictUnpack): 

2418 inferred_value = util.safe_infer(value, context) 

2419 if not isinstance(inferred_value, Dict): 

2420 continue 

2421 

2422 try: 

2423 return inferred_value.getitem(index, context) 

2424 except (AstroidTypeError, AstroidIndexError): 

2425 continue 

2426 

2427 for inferredkey in key.infer(context): 

2428 if isinstance(inferredkey, util.UninferableBase): 

2429 continue 

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

2431 if inferredkey.value == index.value: 

2432 return value 

2433 

2434 raise AstroidIndexError(index) 

2435 

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

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

2438 

2439 :returns: The boolean value of this node. 

2440 :rtype: bool 

2441 """ 

2442 return bool(self.items) 

2443 

2444 def _infer( 

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

2446 ) -> Iterator[nodes.Dict]: 

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

2448 yield self 

2449 else: 

2450 items = self._infer_map(context) 

2451 new_seq = type(self)( 

2452 lineno=self.lineno, 

2453 col_offset=self.col_offset, 

2454 parent=self.parent, 

2455 end_lineno=self.end_lineno, 

2456 end_col_offset=self.end_col_offset, 

2457 ) 

2458 new_seq.postinit(list(items.items())) 

2459 yield new_seq 

2460 

2461 @staticmethod 

2462 def _update_with_replacement( 

2463 lhs_dict: dict[SuccessfulInferenceResult, SuccessfulInferenceResult], 

2464 rhs_dict: dict[SuccessfulInferenceResult, SuccessfulInferenceResult], 

2465 ) -> dict[SuccessfulInferenceResult, SuccessfulInferenceResult]: 

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

2467 

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

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

2470 don't get through 

2471 

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

2473 

2474 Fixes issue with DictUnpack causing duplicate keys 

2475 in inferred Dict items 

2476 

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

2478 :param rhs_dict: Dictionary with nodes to pull from 

2479 :return : merged dictionary of nodes 

2480 """ 

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

2482 # Overwrite keys which have the same string values 

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

2484 # Return to dictionary 

2485 return dict(string_map.values()) 

2486 

2487 def _infer_map( 

2488 self, context: InferenceContext | None 

2489 ) -> dict[SuccessfulInferenceResult, SuccessfulInferenceResult]: 

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

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

2492 for name, value in self.items: 

2493 if isinstance(name, DictUnpack): 

2494 double_starred = util.safe_infer(value, context) 

2495 if not double_starred: 

2496 raise InferenceError 

2497 if not isinstance(double_starred, Dict): 

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

2499 unpack_items = double_starred._infer_map(context) 

2500 values = self._update_with_replacement(values, unpack_items) 

2501 else: 

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

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

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

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

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

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

2508 return values 

2509 

2510 

2511class Expr(_base_nodes.Statement): 

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

2513 

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

2515 stored. 

2516 

2517 >>> import astroid 

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

2519 >>> node 

2520 <Call l.1 at 0x7f23b2e352b0> 

2521 >>> node.parent 

2522 <Expr l.1 at 0x7f23b2e35278> 

2523 """ 

2524 

2525 _astroid_fields = ("value",) 

2526 

2527 value: NodeNG 

2528 """What the expression does.""" 

2529 

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

2531 self.value = value 

2532 

2533 def get_children(self): 

2534 yield self.value 

2535 

2536 def _get_yield_nodes_skip_functions(self): 

2537 if not self.value.is_function: 

2538 yield from self.value._get_yield_nodes_skip_functions() 

2539 

2540 def _get_yield_nodes_skip_lambdas(self): 

2541 if not self.value.is_lambda: 

2542 yield from self.value._get_yield_nodes_skip_lambdas() 

2543 

2544 

2545class EmptyNode(_base_nodes.NoChildrenNode): 

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

2547 

2548 object = None 

2549 

2550 def __init__( 

2551 self, 

2552 lineno: None = None, 

2553 col_offset: None = None, 

2554 parent: NodeNG = SYNTHETIC_ROOT, 

2555 *, 

2556 end_lineno: None = None, 

2557 end_col_offset: None = None, 

2558 ) -> None: 

2559 super().__init__( 

2560 lineno=lineno, 

2561 col_offset=col_offset, 

2562 end_lineno=end_lineno, 

2563 end_col_offset=end_col_offset, 

2564 parent=parent, 

2565 ) 

2566 

2567 def has_underlying_object(self) -> bool: 

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

2569 

2570 @decorators.raise_if_nothing_inferred 

2571 @decorators.path_wrapper 

2572 def _infer( 

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

2574 ) -> Generator[InferenceResult]: 

2575 if not self.has_underlying_object(): 

2576 yield util.Uninferable 

2577 else: 

2578 try: 

2579 yield from AstroidManager().infer_ast_from_something( 

2580 self.object, context=context 

2581 ) 

2582 except AstroidError: 

2583 yield util.Uninferable 

2584 

2585 

2586class ExceptHandler( 

2587 _base_nodes.MultiLineBlockNode, _base_nodes.AssignTypeNode, _base_nodes.Statement 

2588): 

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

2590 

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

2592 

2593 >>> import astroid 

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

2595 try: 

2596 do_something() 

2597 except Exception as error: 

2598 print("Error!") 

2599 ''') 

2600 >>> node 

2601 <Try l.2 at 0x7f23b2e9d908> 

2602 >>> node.handlers 

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

2604 """ 

2605 

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

2607 _multi_line_block_fields = ("body",) 

2608 

2609 type: NodeNG | None 

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

2611 

2612 name: AssignName | None 

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

2614 

2615 body: list[NodeNG] 

2616 """The contents of the block.""" 

2617 

2618 assigned_stmts = protocols.excepthandler_assigned_stmts 

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

2620 See astroid/protocols.py for actual implementation. 

2621 """ 

2622 

2623 def postinit( 

2624 self, 

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

2626 name: AssignName | None, 

2627 body: list[NodeNG], 

2628 ) -> None: 

2629 self.type = type 

2630 self.name = name 

2631 self.body = body 

2632 

2633 def get_children(self): 

2634 if self.type is not None: 

2635 yield self.type 

2636 

2637 if self.name is not None: 

2638 yield self.name 

2639 

2640 yield from self.body 

2641 

2642 @cached_property 

2643 def blockstart_tolineno(self): 

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

2645 

2646 :type: int 

2647 """ 

2648 if self.name: 

2649 return self.name.tolineno 

2650 if self.type: 

2651 return self.type.tolineno 

2652 return self.lineno 

2653 

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

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

2656 

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

2658 """ 

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

2660 return True 

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

2662 

2663 

2664class For( 

2665 _base_nodes.MultiLineWithElseBlockNode, 

2666 _base_nodes.AssignTypeNode, 

2667 _base_nodes.Statement, 

2668): 

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

2670 

2671 >>> import astroid 

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

2673 >>> node 

2674 <For l.1 at 0x7f23b2e8cf28> 

2675 """ 

2676 

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

2678 _other_other_fields = ("type_annotation",) 

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

2680 

2681 optional_assign = True 

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

2683 

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

2685 """ 

2686 

2687 target: NodeNG 

2688 """What the loop assigns to.""" 

2689 

2690 iter: NodeNG 

2691 """What the loop iterates over.""" 

2692 

2693 body: list[NodeNG] 

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

2695 

2696 orelse: list[NodeNG] 

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

2698 

2699 type_annotation: NodeNG | None 

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

2701 

2702 def postinit( 

2703 self, 

2704 target: NodeNG, 

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

2706 body: list[NodeNG], 

2707 orelse: list[NodeNG], 

2708 type_annotation: NodeNG | None, 

2709 ) -> None: 

2710 self.target = target 

2711 self.iter = iter 

2712 self.body = body 

2713 self.orelse = orelse 

2714 self.type_annotation = type_annotation 

2715 

2716 assigned_stmts = protocols.for_assigned_stmts 

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

2718 See astroid/protocols.py for actual implementation. 

2719 """ 

2720 

2721 @cached_property 

2722 def blockstart_tolineno(self): 

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

2724 

2725 :type: int 

2726 """ 

2727 return self.iter.tolineno 

2728 

2729 def get_children(self): 

2730 yield self.target 

2731 yield self.iter 

2732 

2733 yield from self.body 

2734 yield from self.orelse 

2735 

2736 

2737class AsyncFor(For): 

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

2739 

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

2741 the ``async`` keyword. 

2742 

2743 >>> import astroid 

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

2745 async def func(things): 

2746 async for thing in things: 

2747 print(thing) 

2748 ''') 

2749 >>> node 

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

2751 >>> node.body[0] 

2752 <AsyncFor l.3 at 0x7f23b2e417b8> 

2753 """ 

2754 

2755 

2756class Await(NodeNG): 

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

2758 

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

2760 

2761 >>> import astroid 

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

2763 async def func(things): 

2764 await other_func() 

2765 ''') 

2766 >>> node 

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

2768 >>> node.body[0] 

2769 <Expr l.3 at 0x7f23b2e419e8> 

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

2771 <Await l.3 at 0x7f23b2e41a20> 

2772 """ 

2773 

2774 _astroid_fields = ("value",) 

2775 

2776 value: NodeNG 

2777 """What to wait for.""" 

2778 

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

2780 self.value = value 

2781 

2782 def get_children(self): 

2783 yield self.value 

2784 

2785 

2786class ImportFrom(_base_nodes.ImportNode): 

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

2788 

2789 >>> import astroid 

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

2791 >>> node 

2792 <ImportFrom l.1 at 0x7f23b2e415c0> 

2793 """ 

2794 

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

2796 

2797 def __init__( 

2798 self, 

2799 fromname: str | None, 

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

2801 level: int | None = 0, 

2802 lineno: int | None = None, 

2803 col_offset: int | None = None, 

2804 parent: NodeNG | None = None, 

2805 *, 

2806 end_lineno: int | None = None, 

2807 end_col_offset: int | None = None, 

2808 ) -> None: 

2809 """ 

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

2811 

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

2813 

2814 :param level: The level of relative import. 

2815 

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

2817 

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

2819 source code. 

2820 

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

2822 

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

2824 

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

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

2827 """ 

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

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

2830 

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

2832 """ 

2833 

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

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

2836 

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

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

2839 """ 

2840 

2841 # TODO When is 'level' None? 

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

2843 """The level of relative import. 

2844 

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

2846 This is always 0 for absolute imports. 

2847 """ 

2848 

2849 super().__init__( 

2850 lineno=lineno, 

2851 col_offset=col_offset, 

2852 end_lineno=end_lineno, 

2853 end_col_offset=end_col_offset, 

2854 parent=parent, 

2855 ) 

2856 

2857 @decorators.raise_if_nothing_inferred 

2858 @decorators.path_wrapper 

2859 def _infer( 

2860 self, 

2861 context: InferenceContext | None = None, 

2862 asname: bool = True, 

2863 **kwargs: Any, 

2864 ) -> Generator[InferenceResult]: 

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

2866 context = context or InferenceContext() 

2867 name = context.lookupname 

2868 if name is None: 

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

2870 if asname: 

2871 try: 

2872 name = self.real_name(name) 

2873 except AttributeInferenceError as exc: 

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

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

2876 try: 

2877 module = self.do_import_module() 

2878 except AstroidBuildingError as exc: 

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

2880 

2881 try: 

2882 context = copy_context(context) 

2883 context.lookupname = name 

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

2885 return _infer_stmts(stmts, context) 

2886 except AttributeInferenceError as error: 

2887 raise InferenceError( 

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

2889 ) from error 

2890 

2891 

2892class Attribute(NodeNG): 

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

2894 

2895 expr: NodeNG 

2896 

2897 _astroid_fields = ("expr",) 

2898 _other_fields = ("attrname",) 

2899 

2900 def __init__( 

2901 self, 

2902 attrname: str, 

2903 lineno: int, 

2904 col_offset: int, 

2905 parent: NodeNG, 

2906 *, 

2907 end_lineno: int | None, 

2908 end_col_offset: int | None, 

2909 ) -> None: 

2910 self.attrname = attrname 

2911 """The name of the attribute.""" 

2912 

2913 super().__init__( 

2914 lineno=lineno, 

2915 col_offset=col_offset, 

2916 end_lineno=end_lineno, 

2917 end_col_offset=end_col_offset, 

2918 parent=parent, 

2919 ) 

2920 

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

2922 self.expr = expr 

2923 

2924 def get_children(self): 

2925 yield self.expr 

2926 

2927 @decorators.raise_if_nothing_inferred 

2928 @decorators.path_wrapper 

2929 def _infer( 

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

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

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

2933 

2934 

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

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

2937 

2938 >>> import astroid 

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

2940 >>> node 

2941 <Global l.1 at 0x7f23b2e9de10> 

2942 """ 

2943 

2944 _other_fields = ("names",) 

2945 

2946 def __init__( 

2947 self, 

2948 names: list[str], 

2949 lineno: int | None = None, 

2950 col_offset: int | None = None, 

2951 parent: NodeNG | None = None, 

2952 *, 

2953 end_lineno: int | None = None, 

2954 end_col_offset: int | None = None, 

2955 ) -> None: 

2956 """ 

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

2958 

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

2960 

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

2962 source code. 

2963 

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

2965 

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

2967 

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

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

2970 """ 

2971 self.names: list[str] = names 

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

2973 

2974 super().__init__( 

2975 lineno=lineno, 

2976 col_offset=col_offset, 

2977 end_lineno=end_lineno, 

2978 end_col_offset=end_col_offset, 

2979 parent=parent, 

2980 ) 

2981 

2982 def _infer_name(self, frame, name): 

2983 return name 

2984 

2985 @decorators.raise_if_nothing_inferred 

2986 @decorators.path_wrapper 

2987 def _infer( 

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

2989 ) -> Generator[InferenceResult]: 

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

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

2992 try: 

2993 # pylint: disable-next=no-member 

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

2995 except AttributeInferenceError as error: 

2996 raise InferenceError( 

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

2998 ) from error 

2999 

3000 

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

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

3003 

3004 >>> import astroid 

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

3006 >>> node 

3007 <If l.1 at 0x7f23b2e9dd30> 

3008 """ 

3009 

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

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

3012 

3013 test: NodeNG 

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

3015 

3016 body: list[NodeNG] 

3017 """The contents of the block.""" 

3018 

3019 orelse: list[NodeNG] 

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

3021 

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

3023 self.test = test 

3024 self.body = body 

3025 self.orelse = orelse 

3026 

3027 @cached_property 

3028 def blockstart_tolineno(self): 

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

3030 

3031 :type: int 

3032 """ 

3033 return self.test.tolineno 

3034 

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

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

3037 

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

3039 

3040 :returns: The range of line numbers that this node belongs to, 

3041 starting at the given line number. 

3042 """ 

3043 if lineno == self.body[0].fromlineno: 

3044 return lineno, lineno 

3045 if lineno <= self.body[-1].tolineno: 

3046 return lineno, self.body[-1].tolineno 

3047 return self._elsed_block_range(lineno, self.orelse, self.body[0].fromlineno - 1) 

3048 

3049 def get_children(self): 

3050 yield self.test 

3051 

3052 yield from self.body 

3053 yield from self.orelse 

3054 

3055 def has_elif_block(self) -> bool: 

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

3057 

3058 def _get_yield_nodes_skip_functions(self): 

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

3060 yield from self.test._get_yield_nodes_skip_functions() 

3061 yield from super()._get_yield_nodes_skip_functions() 

3062 

3063 def _get_yield_nodes_skip_lambdas(self): 

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

3065 yield from self.test._get_yield_nodes_skip_lambdas() 

3066 yield from super()._get_yield_nodes_skip_lambdas() 

3067 

3068 

3069class IfExp(NodeNG): 

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

3071 >>> import astroid 

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

3073 >>> node 

3074 <IfExp l.1 at 0x7f23b2e9dbe0> 

3075 """ 

3076 

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

3078 

3079 test: NodeNG 

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

3081 

3082 body: NodeNG 

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

3084 

3085 orelse: NodeNG 

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

3087 

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

3089 self.test = test 

3090 self.body = body 

3091 self.orelse = orelse 

3092 

3093 def get_children(self): 

3094 yield self.test 

3095 yield self.body 

3096 yield self.orelse 

3097 

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

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

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

3101 return False 

3102 

3103 @decorators.raise_if_nothing_inferred 

3104 def _infer( 

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

3106 ) -> Generator[InferenceResult]: 

3107 """Support IfExp inference. 

3108 

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

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

3111 depending on the condition. 

3112 """ 

3113 both_branches = False 

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

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

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

3117 

3118 context = context or InferenceContext() 

3119 lhs_context = copy_context(context) 

3120 rhs_context = copy_context(context) 

3121 try: 

3122 test = next(self.test.infer(context=context.clone())) 

3123 except (InferenceError, StopIteration): 

3124 both_branches = True 

3125 else: 

3126 if not isinstance(test, util.UninferableBase): 

3127 if test.bool_value(): 

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

3129 else: 

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

3131 else: 

3132 both_branches = True 

3133 if both_branches: 

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

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

3136 

3137 

3138class Import(_base_nodes.ImportNode): 

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

3140 >>> import astroid 

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

3142 >>> node 

3143 <Import l.1 at 0x7f23b2e4e5c0> 

3144 """ 

3145 

3146 _other_fields = ("names",) 

3147 

3148 def __init__( 

3149 self, 

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

3151 lineno: int | None = None, 

3152 col_offset: int | None = None, 

3153 parent: NodeNG | None = None, 

3154 *, 

3155 end_lineno: int | None = None, 

3156 end_col_offset: int | None = None, 

3157 ) -> None: 

3158 """ 

3159 :param names: The names being imported. 

3160 

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

3162 

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

3164 source code. 

3165 

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

3167 

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

3169 

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

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

3172 """ 

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

3174 """The names being imported. 

3175 

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

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

3178 """ 

3179 

3180 super().__init__( 

3181 lineno=lineno, 

3182 col_offset=col_offset, 

3183 end_lineno=end_lineno, 

3184 end_col_offset=end_col_offset, 

3185 parent=parent, 

3186 ) 

3187 

3188 @decorators.raise_if_nothing_inferred 

3189 @decorators.path_wrapper 

3190 def _infer( 

3191 self, 

3192 context: InferenceContext | None = None, 

3193 asname: bool = True, 

3194 **kwargs: Any, 

3195 ) -> Generator[nodes.Module]: 

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

3197 context = context or InferenceContext() 

3198 name = context.lookupname 

3199 if name is None: 

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

3201 

3202 try: 

3203 if asname: 

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

3205 else: 

3206 yield self.do_import_module(name) 

3207 except AstroidBuildingError as exc: 

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

3209 

3210 

3211class Keyword(NodeNG): 

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

3213 

3214 >>> import astroid 

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

3216 >>> node 

3217 <Call l.1 at 0x7f23b2e9e320> 

3218 >>> node.keywords 

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

3220 """ 

3221 

3222 _astroid_fields = ("value",) 

3223 _other_fields = ("arg",) 

3224 

3225 value: NodeNG 

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

3227 

3228 def __init__( 

3229 self, 

3230 arg: str | None, 

3231 lineno: int | None, 

3232 col_offset: int | None, 

3233 parent: NodeNG, 

3234 *, 

3235 end_lineno: int | None, 

3236 end_col_offset: int | None, 

3237 ) -> None: 

3238 self.arg = arg 

3239 """The argument being assigned to.""" 

3240 

3241 super().__init__( 

3242 lineno=lineno, 

3243 col_offset=col_offset, 

3244 end_lineno=end_lineno, 

3245 end_col_offset=end_col_offset, 

3246 parent=parent, 

3247 ) 

3248 

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

3250 self.value = value 

3251 

3252 def get_children(self): 

3253 yield self.value 

3254 

3255 

3256class List(BaseContainer): 

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

3258 

3259 >>> import astroid 

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

3261 >>> node 

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

3263 """ 

3264 

3265 _other_fields = ("ctx",) 

3266 

3267 def __init__( 

3268 self, 

3269 ctx: Context | None = None, 

3270 lineno: int | None = None, 

3271 col_offset: int | None = None, 

3272 parent: NodeNG | None = None, 

3273 *, 

3274 end_lineno: int | None = None, 

3275 end_col_offset: int | None = None, 

3276 ) -> None: 

3277 """ 

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

3279 

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

3281 

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

3283 source code. 

3284 

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

3286 

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

3288 

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

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

3291 """ 

3292 self.ctx: Context | None = ctx 

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

3294 

3295 super().__init__( 

3296 lineno=lineno, 

3297 col_offset=col_offset, 

3298 end_lineno=end_lineno, 

3299 end_col_offset=end_col_offset, 

3300 parent=parent, 

3301 ) 

3302 

3303 assigned_stmts = protocols.sequence_assigned_stmts 

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

3305 See astroid/protocols.py for actual implementation. 

3306 """ 

3307 

3308 infer_unary_op = protocols.list_infer_unary_op 

3309 infer_binary_op = protocols.tl_infer_binary_op 

3310 

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

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

3313 

3314 :returns: The name of the type. 

3315 """ 

3316 return "builtins.list" 

3317 

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

3319 """Get an item from this node. 

3320 

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

3322 :type index: Const or Slice 

3323 """ 

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

3325 

3326 

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

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

3329 

3330 >>> import astroid 

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

3332 def function(): 

3333 nonlocal var 

3334 ''') 

3335 >>> node 

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

3337 >>> node.body[0] 

3338 <Nonlocal l.3 at 0x7f23b2e9e908> 

3339 """ 

3340 

3341 _other_fields = ("names",) 

3342 

3343 def __init__( 

3344 self, 

3345 names: list[str], 

3346 lineno: int | None = None, 

3347 col_offset: int | None = None, 

3348 parent: NodeNG | None = None, 

3349 *, 

3350 end_lineno: int | None = None, 

3351 end_col_offset: int | None = None, 

3352 ) -> None: 

3353 """ 

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

3355 

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

3357 

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

3359 source code. 

3360 

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

3362 

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

3364 

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

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

3367 """ 

3368 self.names: list[str] = names 

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

3370 

3371 super().__init__( 

3372 lineno=lineno, 

3373 col_offset=col_offset, 

3374 end_lineno=end_lineno, 

3375 end_col_offset=end_col_offset, 

3376 parent=parent, 

3377 ) 

3378 

3379 def _infer_name(self, frame, name): 

3380 return name 

3381 

3382 

3383class ParamSpec(_base_nodes.AssignTypeNode): 

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

3385 

3386 >>> import astroid 

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

3388 >>> node.type_params[0] 

3389 <ParamSpec l.1 at 0x7f23b2e4e198> 

3390 """ 

3391 

3392 _astroid_fields = ("name",) 

3393 

3394 name: AssignName 

3395 

3396 def __init__( 

3397 self, 

3398 lineno: int, 

3399 col_offset: int, 

3400 parent: NodeNG, 

3401 *, 

3402 end_lineno: int, 

3403 end_col_offset: int, 

3404 ) -> None: 

3405 super().__init__( 

3406 lineno=lineno, 

3407 col_offset=col_offset, 

3408 end_lineno=end_lineno, 

3409 end_col_offset=end_col_offset, 

3410 parent=parent, 

3411 ) 

3412 

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

3414 self.name = name 

3415 

3416 def _infer( 

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

3418 ) -> Iterator[ParamSpec]: 

3419 yield self 

3420 

3421 assigned_stmts = protocols.generic_type_assigned_stmts 

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

3423 See astroid/protocols.py for actual implementation. 

3424 """ 

3425 

3426 

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

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

3429 

3430 >>> import astroid 

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

3432 >>> node 

3433 <Pass l.1 at 0x7f23b2e9e748> 

3434 """ 

3435 

3436 

3437class Raise(_base_nodes.Statement): 

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

3439 

3440 >>> import astroid 

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

3442 >>> node 

3443 <Raise l.1 at 0x7f23b2e9e828> 

3444 """ 

3445 

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

3447 

3448 exc: NodeNG | None 

3449 """What is being raised.""" 

3450 

3451 cause: NodeNG | None 

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

3453 

3454 def postinit( 

3455 self, 

3456 exc: NodeNG | None, 

3457 cause: NodeNG | None, 

3458 ) -> None: 

3459 self.exc = exc 

3460 self.cause = cause 

3461 

3462 def raises_not_implemented(self) -> bool: 

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

3464 

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

3466 """ 

3467 if not self.exc: 

3468 return False 

3469 return any( 

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

3471 ) 

3472 

3473 def get_children(self): 

3474 if self.exc is not None: 

3475 yield self.exc 

3476 

3477 if self.cause is not None: 

3478 yield self.cause 

3479 

3480 

3481class Return(_base_nodes.Statement): 

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

3483 

3484 >>> import astroid 

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

3486 >>> node 

3487 <Return l.1 at 0x7f23b8211908> 

3488 """ 

3489 

3490 _astroid_fields = ("value",) 

3491 

3492 value: NodeNG | None 

3493 """The value being returned.""" 

3494 

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

3496 self.value = value 

3497 

3498 def get_children(self): 

3499 if self.value is not None: 

3500 yield self.value 

3501 

3502 def is_tuple_return(self) -> bool: 

3503 return isinstance(self.value, Tuple) 

3504 

3505 def _get_return_nodes_skip_functions(self): 

3506 yield self 

3507 

3508 

3509class Set(BaseContainer): 

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

3511 

3512 >>> import astroid 

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

3514 >>> node 

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

3516 """ 

3517 

3518 infer_unary_op = protocols.set_infer_unary_op 

3519 

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

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

3522 

3523 :returns: The name of the type. 

3524 """ 

3525 return "builtins.set" 

3526 

3527 

3528class Slice(NodeNG): 

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

3530 

3531 >>> import astroid 

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

3533 >>> node 

3534 <Subscript l.1 at 0x7f23b2e71f60> 

3535 >>> node.slice 

3536 <Slice l.1 at 0x7f23b2e71e80> 

3537 """ 

3538 

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

3540 

3541 lower: NodeNG | None 

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

3543 

3544 upper: NodeNG | None 

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

3546 

3547 step: NodeNG | None 

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

3549 

3550 def postinit( 

3551 self, 

3552 lower: NodeNG | None, 

3553 upper: NodeNG | None, 

3554 step: NodeNG | None, 

3555 ) -> None: 

3556 self.lower = lower 

3557 self.upper = upper 

3558 self.step = step 

3559 

3560 def _wrap_attribute(self, attr): 

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

3562 if not attr: 

3563 const = const_factory(attr) 

3564 const.parent = self 

3565 return const 

3566 return attr 

3567 

3568 @cached_property 

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

3570 builtins = AstroidManager().builtins_module 

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

3572 

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

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

3575 

3576 :returns: The name of the type. 

3577 """ 

3578 return "builtins.slice" 

3579 

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

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

3582 

3583 :returns: The type of this node. 

3584 """ 

3585 return "Slice" 

3586 

3587 def igetattr( 

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

3589 ) -> Iterator[SuccessfulInferenceResult]: 

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

3591 

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

3593 

3594 :returns: The inferred possible values. 

3595 """ 

3596 if attrname == "start": 

3597 yield self._wrap_attribute(self.lower) 

3598 elif attrname == "stop": 

3599 yield self._wrap_attribute(self.upper) 

3600 elif attrname == "step": 

3601 yield self._wrap_attribute(self.step) 

3602 else: 

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

3604 

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

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

3607 

3608 def get_children(self): 

3609 if self.lower is not None: 

3610 yield self.lower 

3611 

3612 if self.upper is not None: 

3613 yield self.upper 

3614 

3615 if self.step is not None: 

3616 yield self.step 

3617 

3618 def _infer( 

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

3620 ) -> Iterator[Slice]: 

3621 yield self 

3622 

3623 

3624class Starred(_base_nodes.ParentAssignNode): 

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

3626 

3627 >>> import astroid 

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

3629 >>> node 

3630 <Starred l.1 at 0x7f23b2e41978> 

3631 """ 

3632 

3633 _astroid_fields = ("value",) 

3634 _other_fields = ("ctx",) 

3635 

3636 value: NodeNG 

3637 """What is being unpacked.""" 

3638 

3639 def __init__( 

3640 self, 

3641 ctx: Context, 

3642 lineno: int, 

3643 col_offset: int, 

3644 parent: NodeNG, 

3645 *, 

3646 end_lineno: int | None, 

3647 end_col_offset: int | None, 

3648 ) -> None: 

3649 self.ctx = ctx 

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

3651 

3652 super().__init__( 

3653 lineno=lineno, 

3654 col_offset=col_offset, 

3655 end_lineno=end_lineno, 

3656 end_col_offset=end_col_offset, 

3657 parent=parent, 

3658 ) 

3659 

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

3661 self.value = value 

3662 

3663 assigned_stmts = protocols.starred_assigned_stmts 

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

3665 See astroid/protocols.py for actual implementation. 

3666 """ 

3667 

3668 def get_children(self): 

3669 yield self.value 

3670 

3671 

3672class Subscript(NodeNG): 

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

3674 

3675 >>> import astroid 

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

3677 >>> node 

3678 <Subscript l.1 at 0x7f23b2e71f60> 

3679 """ 

3680 

3681 _SUBSCRIPT_SENTINEL = object() 

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

3683 _other_fields = ("ctx",) 

3684 

3685 value: NodeNG 

3686 """What is being indexed.""" 

3687 

3688 slice: NodeNG 

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

3690 

3691 def __init__( 

3692 self, 

3693 ctx: Context, 

3694 lineno: int, 

3695 col_offset: int, 

3696 parent: NodeNG, 

3697 *, 

3698 end_lineno: int | None, 

3699 end_col_offset: int | None, 

3700 ) -> None: 

3701 self.ctx = ctx 

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

3703 

3704 super().__init__( 

3705 lineno=lineno, 

3706 col_offset=col_offset, 

3707 end_lineno=end_lineno, 

3708 end_col_offset=end_col_offset, 

3709 parent=parent, 

3710 ) 

3711 

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

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

3714 self.value = value 

3715 self.slice = slice 

3716 

3717 def get_children(self): 

3718 yield self.value 

3719 yield self.slice 

3720 

3721 def _infer_subscript( 

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

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

3724 """Inference for subscripts. 

3725 

3726 We're understanding if the index is a Const 

3727 or a slice, passing the result of inference 

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

3729 handle each supported index type accordingly. 

3730 """ 

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

3732 

3733 found_one = False 

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

3735 if isinstance(value, util.UninferableBase): 

3736 yield util.Uninferable 

3737 return None 

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

3739 if isinstance(index, util.UninferableBase): 

3740 yield util.Uninferable 

3741 return None 

3742 

3743 # Try to deduce the index value. 

3744 index_value = self._SUBSCRIPT_SENTINEL 

3745 if value.__class__ == Instance: 

3746 index_value = index 

3747 elif index.__class__ == Instance: 

3748 instance_as_index = helpers.class_instance_as_index(index) 

3749 if instance_as_index: 

3750 index_value = instance_as_index 

3751 else: 

3752 index_value = index 

3753 

3754 if index_value is self._SUBSCRIPT_SENTINEL: 

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

3756 

3757 try: 

3758 assigned = value.getitem(index_value, context) 

3759 except ( 

3760 AstroidTypeError, 

3761 AstroidIndexError, 

3762 AstroidValueError, 

3763 AttributeInferenceError, 

3764 AttributeError, 

3765 ) as exc: 

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

3767 

3768 # Prevent inferring if the inferred subscript 

3769 # is the same as the original subscripted object. 

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

3771 yield util.Uninferable 

3772 return None 

3773 yield from assigned.infer(context) 

3774 found_one = True 

3775 

3776 if found_one: 

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

3778 return None 

3779 

3780 @decorators.raise_if_nothing_inferred 

3781 @decorators.path_wrapper 

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

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

3784 

3785 @decorators.raise_if_nothing_inferred 

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

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

3788 

3789 

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

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

3792 

3793 >>> import astroid 

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

3795 try: 

3796 do_something() 

3797 except Exception as error: 

3798 print("Error!") 

3799 finally: 

3800 print("Cleanup!") 

3801 ''') 

3802 >>> node 

3803 <Try l.2 at 0x7f23b2e41d68> 

3804 """ 

3805 

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

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

3808 

3809 def __init__( 

3810 self, 

3811 *, 

3812 lineno: int, 

3813 col_offset: int, 

3814 end_lineno: int, 

3815 end_col_offset: int, 

3816 parent: NodeNG, 

3817 ) -> None: 

3818 """ 

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

3820 

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

3822 source code. 

3823 

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

3825 

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

3827 

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

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

3830 """ 

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

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

3833 

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

3835 """The exception handlers.""" 

3836 

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

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

3839 

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

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

3842 

3843 super().__init__( 

3844 lineno=lineno, 

3845 col_offset=col_offset, 

3846 end_lineno=end_lineno, 

3847 end_col_offset=end_col_offset, 

3848 parent=parent, 

3849 ) 

3850 

3851 def postinit( 

3852 self, 

3853 *, 

3854 body: list[NodeNG], 

3855 handlers: list[ExceptHandler], 

3856 orelse: list[NodeNG], 

3857 finalbody: list[NodeNG], 

3858 ) -> None: 

3859 """Do some setup after initialisation. 

3860 

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

3862 

3863 :param handlers: The exception handlers. 

3864 

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

3866 

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

3868 """ 

3869 self.body = body 

3870 self.handlers = handlers 

3871 self.orelse = orelse 

3872 self.finalbody = finalbody 

3873 

3874 def _infer_name(self, frame, name): 

3875 return name 

3876 

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

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

3879 if lineno == self.fromlineno: 

3880 return lineno, lineno 

3881 if self.body and self.body[0].fromlineno <= lineno <= self.body[-1].tolineno: 

3882 # Inside try body - return from lineno till end of try body 

3883 return lineno, self.body[-1].tolineno 

3884 for exhandler in self.handlers: 

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

3886 return lineno, lineno 

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

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

3889 if self.orelse: 

3890 if self.orelse[0].fromlineno - 1 == lineno: 

3891 return lineno, lineno 

3892 if self.orelse[0].fromlineno <= lineno <= self.orelse[-1].tolineno: 

3893 return lineno, self.orelse[-1].tolineno 

3894 if self.finalbody: 

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

3896 return lineno, lineno 

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

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

3899 return lineno, self.tolineno 

3900 

3901 def get_children(self): 

3902 yield from self.body 

3903 yield from self.handlers 

3904 yield from self.orelse 

3905 yield from self.finalbody 

3906 

3907 

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

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

3910 

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

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

3913 

3914 def __init__( 

3915 self, 

3916 *, 

3917 lineno: int | None = None, 

3918 col_offset: int | None = None, 

3919 end_lineno: int | None = None, 

3920 end_col_offset: int | None = None, 

3921 parent: NodeNG | None = None, 

3922 ) -> None: 

3923 """ 

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

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

3926 source code. 

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

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

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

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

3931 """ 

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

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

3934 

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

3936 """The exception handlers.""" 

3937 

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

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

3940 

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

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

3943 

3944 super().__init__( 

3945 lineno=lineno, 

3946 col_offset=col_offset, 

3947 end_lineno=end_lineno, 

3948 end_col_offset=end_col_offset, 

3949 parent=parent, 

3950 ) 

3951 

3952 def postinit( 

3953 self, 

3954 *, 

3955 body: list[NodeNG] | None = None, 

3956 handlers: list[ExceptHandler] | None = None, 

3957 orelse: list[NodeNG] | None = None, 

3958 finalbody: list[NodeNG] | None = None, 

3959 ) -> None: 

3960 """Do some setup after initialisation. 

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

3962 :param handlers: The exception handlers. 

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

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

3965 """ 

3966 if body: 

3967 self.body = body 

3968 if handlers: 

3969 self.handlers = handlers 

3970 if orelse: 

3971 self.orelse = orelse 

3972 if finalbody: 

3973 self.finalbody = finalbody 

3974 

3975 def _infer_name(self, frame, name): 

3976 return name 

3977 

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

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

3980 if lineno == self.fromlineno: 

3981 return lineno, lineno 

3982 if self.body and self.body[0].fromlineno <= lineno <= self.body[-1].tolineno: 

3983 # Inside try body - return from lineno till end of try body 

3984 return lineno, self.body[-1].tolineno 

3985 for exhandler in self.handlers: 

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

3987 return lineno, lineno 

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

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

3990 if self.orelse: 

3991 if self.orelse[0].fromlineno - 1 == lineno: 

3992 return lineno, lineno 

3993 if self.orelse[0].fromlineno <= lineno <= self.orelse[-1].tolineno: 

3994 return lineno, self.orelse[-1].tolineno 

3995 if self.finalbody: 

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

3997 return lineno, lineno 

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

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

4000 return lineno, self.tolineno 

4001 

4002 def get_children(self): 

4003 yield from self.body 

4004 yield from self.handlers 

4005 yield from self.orelse 

4006 yield from self.finalbody 

4007 

4008 

4009class Tuple(BaseContainer): 

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

4011 

4012 >>> import astroid 

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

4014 >>> node 

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

4016 """ 

4017 

4018 _other_fields = ("ctx",) 

4019 

4020 def __init__( 

4021 self, 

4022 ctx: Context | None = None, 

4023 lineno: int | None = None, 

4024 col_offset: int | None = None, 

4025 parent: NodeNG | None = None, 

4026 *, 

4027 end_lineno: int | None = None, 

4028 end_col_offset: int | None = None, 

4029 ) -> None: 

4030 """ 

4031 :param ctx: Whether the tuple is assigned to or loaded from. 

4032 

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

4034 

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

4036 source code. 

4037 

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

4039 

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

4041 

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

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

4044 """ 

4045 self.ctx: Context | None = ctx 

4046 """Whether the tuple is assigned to or loaded from.""" 

4047 

4048 super().__init__( 

4049 lineno=lineno, 

4050 col_offset=col_offset, 

4051 end_lineno=end_lineno, 

4052 end_col_offset=end_col_offset, 

4053 parent=parent, 

4054 ) 

4055 

4056 assigned_stmts = protocols.sequence_assigned_stmts 

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

4058 See astroid/protocols.py for actual implementation. 

4059 """ 

4060 

4061 infer_unary_op = protocols.tuple_infer_unary_op 

4062 infer_binary_op = protocols.tl_infer_binary_op 

4063 

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

4065 """Get the name of the type that this node represents. 

4066 

4067 :returns: The name of the type. 

4068 """ 

4069 return "builtins.tuple" 

4070 

4071 def getitem(self, index, context: InferenceContext | None = None): 

4072 """Get an item from this node. 

4073 

4074 :param index: The node to use as a subscript index. 

4075 :type index: Const or Slice 

4076 """ 

4077 return _container_getitem(self, self.elts, index, context=context) 

4078 

4079 

4080class TypeAlias(_base_nodes.AssignTypeNode, _base_nodes.Statement): 

4081 """Class representing a :class:`ast.TypeAlias` node. 

4082 

4083 >>> import astroid 

4084 >>> node = astroid.extract_node('type Point = tuple[float, float]') 

4085 >>> node 

4086 <TypeAlias l.1 at 0x7f23b2e4e198> 

4087 """ 

4088 

4089 _astroid_fields = ("name", "type_params", "value") 

4090 

4091 name: AssignName 

4092 type_params: list[TypeVar | ParamSpec | TypeVarTuple] 

4093 value: NodeNG 

4094 

4095 def __init__( 

4096 self, 

4097 lineno: int, 

4098 col_offset: int, 

4099 parent: NodeNG, 

4100 *, 

4101 end_lineno: int, 

4102 end_col_offset: int, 

4103 ) -> None: 

4104 super().__init__( 

4105 lineno=lineno, 

4106 col_offset=col_offset, 

4107 end_lineno=end_lineno, 

4108 end_col_offset=end_col_offset, 

4109 parent=parent, 

4110 ) 

4111 

4112 def postinit( 

4113 self, 

4114 *, 

4115 name: AssignName, 

4116 type_params: list[TypeVar | ParamSpec | TypeVarTuple], 

4117 value: NodeNG, 

4118 ) -> None: 

4119 self.name = name 

4120 self.type_params = type_params 

4121 self.value = value 

4122 

4123 def _infer( 

4124 self, context: InferenceContext | None = None, **kwargs: Any 

4125 ) -> Iterator[TypeAlias]: 

4126 yield self 

4127 

4128 assigned_stmts: ClassVar[ 

4129 Callable[ 

4130 [ 

4131 TypeAlias, 

4132 AssignName, 

4133 InferenceContext | None, 

4134 None, 

4135 ], 

4136 Generator[NodeNG], 

4137 ] 

4138 ] = protocols.assign_assigned_stmts 

4139 

4140 

4141class TypeVar(_base_nodes.AssignTypeNode): 

4142 """Class representing a :class:`ast.TypeVar` node. 

4143 

4144 >>> import astroid 

4145 >>> node = astroid.extract_node('type Point[T] = tuple[float, float]') 

4146 >>> node.type_params[0] 

4147 <TypeVar l.1 at 0x7f23b2e4e198> 

4148 """ 

4149 

4150 _astroid_fields = ("name", "bound") 

4151 

4152 name: AssignName 

4153 bound: NodeNG | None 

4154 

4155 def __init__( 

4156 self, 

4157 lineno: int, 

4158 col_offset: int, 

4159 parent: NodeNG, 

4160 *, 

4161 end_lineno: int, 

4162 end_col_offset: int, 

4163 ) -> None: 

4164 super().__init__( 

4165 lineno=lineno, 

4166 col_offset=col_offset, 

4167 end_lineno=end_lineno, 

4168 end_col_offset=end_col_offset, 

4169 parent=parent, 

4170 ) 

4171 

4172 def postinit(self, *, name: AssignName, bound: NodeNG | None) -> None: 

4173 self.name = name 

4174 self.bound = bound 

4175 

4176 def _infer( 

4177 self, context: InferenceContext | None = None, **kwargs: Any 

4178 ) -> Iterator[TypeVar]: 

4179 yield self 

4180 

4181 assigned_stmts = protocols.generic_type_assigned_stmts 

4182 """Returns the assigned statement (non inferred) according to the assignment type. 

4183 See astroid/protocols.py for actual implementation. 

4184 """ 

4185 

4186 

4187class TypeVarTuple(_base_nodes.AssignTypeNode): 

4188 """Class representing a :class:`ast.TypeVarTuple` node. 

4189 

4190 >>> import astroid 

4191 >>> node = astroid.extract_node('type Alias[*Ts] = tuple[*Ts]') 

4192 >>> node.type_params[0] 

4193 <TypeVarTuple l.1 at 0x7f23b2e4e198> 

4194 """ 

4195 

4196 _astroid_fields = ("name",) 

4197 

4198 name: AssignName 

4199 

4200 def __init__( 

4201 self, 

4202 lineno: int, 

4203 col_offset: int, 

4204 parent: NodeNG, 

4205 *, 

4206 end_lineno: int, 

4207 end_col_offset: int, 

4208 ) -> None: 

4209 super().__init__( 

4210 lineno=lineno, 

4211 col_offset=col_offset, 

4212 end_lineno=end_lineno, 

4213 end_col_offset=end_col_offset, 

4214 parent=parent, 

4215 ) 

4216 

4217 def postinit(self, *, name: AssignName) -> None: 

4218 self.name = name 

4219 

4220 def _infer( 

4221 self, context: InferenceContext | None = None, **kwargs: Any 

4222 ) -> Iterator[TypeVarTuple]: 

4223 yield self 

4224 

4225 assigned_stmts = protocols.generic_type_assigned_stmts 

4226 """Returns the assigned statement (non inferred) according to the assignment type. 

4227 See astroid/protocols.py for actual implementation. 

4228 """ 

4229 

4230 

4231UNARY_OP_METHOD = { 

4232 "+": "__pos__", 

4233 "-": "__neg__", 

4234 "~": "__invert__", 

4235 "not": None, # XXX not '__nonzero__' 

4236} 

4237 

4238 

4239class UnaryOp(_base_nodes.OperatorNode): 

4240 """Class representing an :class:`ast.UnaryOp` node. 

4241 

4242 >>> import astroid 

4243 >>> node = astroid.extract_node('-5') 

4244 >>> node 

4245 <UnaryOp l.1 at 0x7f23b2e4e198> 

4246 """ 

4247 

4248 _astroid_fields = ("operand",) 

4249 _other_fields = ("op",) 

4250 

4251 operand: NodeNG 

4252 """What the unary operator is applied to.""" 

4253 

4254 def __init__( 

4255 self, 

4256 op: str, 

4257 lineno: int, 

4258 col_offset: int, 

4259 parent: NodeNG, 

4260 *, 

4261 end_lineno: int | None, 

4262 end_col_offset: int | None, 

4263 ) -> None: 

4264 self.op = op 

4265 """The operator.""" 

4266 

4267 super().__init__( 

4268 lineno=lineno, 

4269 col_offset=col_offset, 

4270 end_lineno=end_lineno, 

4271 end_col_offset=end_col_offset, 

4272 parent=parent, 

4273 ) 

4274 

4275 def postinit(self, operand: NodeNG) -> None: 

4276 self.operand = operand 

4277 

4278 def type_errors( 

4279 self, context: InferenceContext | None = None 

4280 ) -> list[util.BadUnaryOperationMessage]: 

4281 """Get a list of type errors which can occur during inference. 

4282 

4283 Each TypeError is represented by a :class:`BadUnaryOperationMessage`, 

4284 which holds the original exception. 

4285 

4286 If any inferred result is uninferable, an empty list is returned. 

4287 """ 

4288 bad = [] 

4289 try: 

4290 for result in self._infer_unaryop(context=context): 

4291 if result is util.Uninferable: 

4292 raise InferenceError 

4293 if isinstance(result, util.BadUnaryOperationMessage): 

4294 bad.append(result) 

4295 except InferenceError: 

4296 return [] 

4297 return bad 

4298 

4299 def get_children(self): 

4300 yield self.operand 

4301 

4302 def op_precedence(self) -> int: 

4303 if self.op == "not": 

4304 return OP_PRECEDENCE[self.op] 

4305 

4306 return super().op_precedence() 

4307 

4308 def _infer_unaryop( 

4309 self: nodes.UnaryOp, context: InferenceContext | None = None, **kwargs: Any 

4310 ) -> Generator[ 

4311 InferenceResult | util.BadUnaryOperationMessage, None, InferenceErrorInfo 

4312 ]: 

4313 """Infer what an UnaryOp should return when evaluated.""" 

4314 from astroid.nodes import ClassDef # pylint: disable=import-outside-toplevel 

4315 

4316 for operand in self.operand.infer(context): 

4317 try: 

4318 yield operand.infer_unary_op(self.op) 

4319 except TypeError as exc: 

4320 # The operand doesn't support this operation. 

4321 yield util.BadUnaryOperationMessage(operand, self.op, exc) 

4322 except AttributeError as exc: 

4323 meth = UNARY_OP_METHOD[self.op] 

4324 if meth is None: 

4325 # `not node`. Determine node's boolean 

4326 # value and negate its result, unless it is 

4327 # Uninferable, which will be returned as is. 

4328 bool_value = operand.bool_value() 

4329 if not isinstance(bool_value, util.UninferableBase): 

4330 yield const_factory(not bool_value) 

4331 else: 

4332 yield util.Uninferable 

4333 else: 

4334 if not isinstance(operand, (Instance, ClassDef)): 

4335 # The operation was used on something which 

4336 # doesn't support it. 

4337 yield util.BadUnaryOperationMessage(operand, self.op, exc) 

4338 continue 

4339 

4340 try: 

4341 try: 

4342 methods = dunder_lookup.lookup(operand, meth) 

4343 except AttributeInferenceError: 

4344 yield util.BadUnaryOperationMessage(operand, self.op, exc) 

4345 continue 

4346 

4347 meth = methods[0] 

4348 inferred = next(meth.infer(context=context), None) 

4349 if ( 

4350 isinstance(inferred, util.UninferableBase) 

4351 or not inferred.callable() 

4352 ): 

4353 continue 

4354 

4355 context = copy_context(context) 

4356 context.boundnode = operand 

4357 context.callcontext = CallContext(args=[], callee=inferred) 

4358 

4359 call_results = inferred.infer_call_result(self, context=context) 

4360 result = next(call_results, None) 

4361 if result is None: 

4362 # Failed to infer, return the same type. 

4363 yield operand 

4364 else: 

4365 yield result 

4366 except AttributeInferenceError as inner_exc: 

4367 # The unary operation special method was not found. 

4368 yield util.BadUnaryOperationMessage(operand, self.op, inner_exc) 

4369 except InferenceError: 

4370 yield util.Uninferable 

4371 

4372 @decorators.raise_if_nothing_inferred 

4373 @decorators.path_wrapper 

4374 def _infer( 

4375 self: nodes.UnaryOp, context: InferenceContext | None = None, **kwargs: Any 

4376 ) -> Generator[InferenceResult, None, InferenceErrorInfo]: 

4377 """Infer what an UnaryOp should return when evaluated.""" 

4378 yield from self._filter_operation_errors( 

4379 self._infer_unaryop, context, util.BadUnaryOperationMessage 

4380 ) 

4381 return InferenceErrorInfo(node=self, context=context) 

4382 

4383 

4384class While(_base_nodes.MultiLineWithElseBlockNode, _base_nodes.Statement): 

4385 """Class representing an :class:`ast.While` node. 

4386 

4387 >>> import astroid 

4388 >>> node = astroid.extract_node(''' 

4389 while condition(): 

4390 print("True") 

4391 ''') 

4392 >>> node 

4393 <While l.2 at 0x7f23b2e4e390> 

4394 """ 

4395 

4396 _astroid_fields = ("test", "body", "orelse") 

4397 _multi_line_block_fields = ("body", "orelse") 

4398 

4399 test: NodeNG 

4400 """The condition that the loop tests.""" 

4401 

4402 body: list[NodeNG] 

4403 """The contents of the loop.""" 

4404 

4405 orelse: list[NodeNG] 

4406 """The contents of the ``else`` block.""" 

4407 

4408 def postinit( 

4409 self, 

4410 test: NodeNG, 

4411 body: list[NodeNG], 

4412 orelse: list[NodeNG], 

4413 ) -> None: 

4414 self.test = test 

4415 self.body = body 

4416 self.orelse = orelse 

4417 

4418 @cached_property 

4419 def blockstart_tolineno(self): 

4420 """The line on which the beginning of this block ends. 

4421 

4422 :type: int 

4423 """ 

4424 return self.test.tolineno 

4425 

4426 def block_range(self, lineno: int) -> tuple[int, int]: 

4427 """Get a range from the given line number to where this node ends. 

4428 

4429 :param lineno: The line number to start the range at. 

4430 

4431 :returns: The range of line numbers that this node belongs to, 

4432 starting at the given line number. 

4433 """ 

4434 return self._elsed_block_range(lineno, self.orelse) 

4435 

4436 def get_children(self): 

4437 yield self.test 

4438 

4439 yield from self.body 

4440 yield from self.orelse 

4441 

4442 def _get_yield_nodes_skip_functions(self): 

4443 """A While node can contain a Yield node in the test""" 

4444 yield from self.test._get_yield_nodes_skip_functions() 

4445 yield from super()._get_yield_nodes_skip_functions() 

4446 

4447 def _get_yield_nodes_skip_lambdas(self): 

4448 """A While node can contain a Yield node in the test""" 

4449 yield from self.test._get_yield_nodes_skip_lambdas() 

4450 yield from super()._get_yield_nodes_skip_lambdas() 

4451 

4452 

4453class With( 

4454 _base_nodes.MultiLineWithElseBlockNode, 

4455 _base_nodes.AssignTypeNode, 

4456 _base_nodes.Statement, 

4457): 

4458 """Class representing an :class:`ast.With` node. 

4459 

4460 >>> import astroid 

4461 >>> node = astroid.extract_node(''' 

4462 with open(file_path) as file_: 

4463 print(file_.read()) 

4464 ''') 

4465 >>> node 

4466 <With l.2 at 0x7f23b2e4e710> 

4467 """ 

4468 

4469 _astroid_fields = ("items", "body") 

4470 _other_other_fields = ("type_annotation",) 

4471 _multi_line_block_fields = ("body",) 

4472 

4473 def __init__( 

4474 self, 

4475 lineno: int | None = None, 

4476 col_offset: int | None = None, 

4477 parent: NodeNG | None = None, 

4478 *, 

4479 end_lineno: int | None = None, 

4480 end_col_offset: int | None = None, 

4481 ) -> None: 

4482 """ 

4483 :param lineno: The line that this node appears on in the source code. 

4484 

4485 :param col_offset: The column that this node appears on in the 

4486 source code. 

4487 

4488 :param parent: The parent node in the syntax tree. 

4489 

4490 :param end_lineno: The last line this node appears on in the source code. 

4491 

4492 :param end_col_offset: The end column this node appears on in the 

4493 source code. Note: This is after the last symbol. 

4494 """ 

4495 self.items: list[tuple[NodeNG, NodeNG | None]] = [] 

4496 """The pairs of context managers and the names they are assigned to.""" 

4497 

4498 self.body: list[NodeNG] = [] 

4499 """The contents of the ``with`` block.""" 

4500 

4501 self.type_annotation: NodeNG | None = None # can be None 

4502 """If present, this will contain the type annotation passed by a type comment""" 

4503 

4504 super().__init__( 

4505 lineno=lineno, 

4506 col_offset=col_offset, 

4507 end_lineno=end_lineno, 

4508 end_col_offset=end_col_offset, 

4509 parent=parent, 

4510 ) 

4511 

4512 def postinit( 

4513 self, 

4514 items: list[tuple[NodeNG, NodeNG | None]] | None = None, 

4515 body: list[NodeNG] | None = None, 

4516 type_annotation: NodeNG | None = None, 

4517 ) -> None: 

4518 """Do some setup after initialisation. 

4519 

4520 :param items: The pairs of context managers and the names 

4521 they are assigned to. 

4522 

4523 :param body: The contents of the ``with`` block. 

4524 """ 

4525 if items is not None: 

4526 self.items = items 

4527 if body is not None: 

4528 self.body = body 

4529 self.type_annotation = type_annotation 

4530 

4531 assigned_stmts = protocols.with_assigned_stmts 

4532 """Returns the assigned statement (non inferred) according to the assignment type. 

4533 See astroid/protocols.py for actual implementation. 

4534 """ 

4535 

4536 @cached_property 

4537 def blockstart_tolineno(self): 

4538 """The line on which the beginning of this block ends. 

4539 

4540 :type: int 

4541 """ 

4542 return self.items[-1][0].tolineno 

4543 

4544 def get_children(self): 

4545 """Get the child nodes below this node. 

4546 

4547 :returns: The children. 

4548 :rtype: iterable(NodeNG) 

4549 """ 

4550 for expr, var in self.items: 

4551 yield expr 

4552 if var: 

4553 yield var 

4554 yield from self.body 

4555 

4556 

4557class AsyncWith(With): 

4558 """Asynchronous ``with`` built with the ``async`` keyword.""" 

4559 

4560 

4561class Yield(NodeNG): 

4562 """Class representing an :class:`ast.Yield` node. 

4563 

4564 >>> import astroid 

4565 >>> node = astroid.extract_node('yield True') 

4566 >>> node 

4567 <Yield l.1 at 0x7f23b2e4e5f8> 

4568 """ 

4569 

4570 _astroid_fields = ("value",) 

4571 

4572 value: NodeNG | None 

4573 """The value to yield.""" 

4574 

4575 def postinit(self, value: NodeNG | None) -> None: 

4576 self.value = value 

4577 

4578 def get_children(self): 

4579 if self.value is not None: 

4580 yield self.value 

4581 

4582 def _get_yield_nodes_skip_functions(self): 

4583 yield self 

4584 

4585 def _get_yield_nodes_skip_lambdas(self): 

4586 yield self 

4587 

4588 

4589class YieldFrom(Yield): # TODO value is required, not optional 

4590 """Class representing an :class:`ast.YieldFrom` node.""" 

4591 

4592 

4593class DictUnpack(_base_nodes.NoChildrenNode): 

4594 """Represents the unpacking of dicts into dicts using :pep:`448`.""" 

4595 

4596 

4597class FormattedValue(NodeNG): 

4598 """Class representing an :class:`ast.FormattedValue` node. 

4599 

4600 Represents a :pep:`498` format string. 

4601 

4602 >>> import astroid 

4603 >>> node = astroid.extract_node('f"Format {type_}"') 

4604 >>> node 

4605 <JoinedStr l.1 at 0x7f23b2e4ed30> 

4606 >>> node.values 

4607 [<Const.str l.1 at 0x7f23b2e4eda0>, <FormattedValue l.1 at 0x7f23b2e4edd8>] 

4608 """ 

4609 

4610 _astroid_fields = ("value", "format_spec") 

4611 _other_fields = ("conversion",) 

4612 

4613 def __init__( 

4614 self, 

4615 lineno: int | None = None, 

4616 col_offset: int | None = None, 

4617 parent: NodeNG | None = None, 

4618 *, 

4619 end_lineno: int | None = None, 

4620 end_col_offset: int | None = None, 

4621 ) -> None: 

4622 """ 

4623 :param lineno: The line that this node appears on in the source code. 

4624 

4625 :param col_offset: The column that this node appears on in the 

4626 source code. 

4627 

4628 :param parent: The parent node in the syntax tree. 

4629 

4630 :param end_lineno: The last line this node appears on in the source code. 

4631 

4632 :param end_col_offset: The end column this node appears on in the 

4633 source code. Note: This is after the last symbol. 

4634 """ 

4635 self.value: NodeNG 

4636 """The value to be formatted into the string.""" 

4637 

4638 self.conversion: int 

4639 """The type of formatting to be applied to the value. 

4640 

4641 .. seealso:: 

4642 :class:`ast.FormattedValue` 

4643 """ 

4644 

4645 self.format_spec: JoinedStr | None = None 

4646 """The formatting to be applied to the value. 

4647 

4648 .. seealso:: 

4649 :class:`ast.FormattedValue` 

4650 """ 

4651 

4652 super().__init__( 

4653 lineno=lineno, 

4654 col_offset=col_offset, 

4655 end_lineno=end_lineno, 

4656 end_col_offset=end_col_offset, 

4657 parent=parent, 

4658 ) 

4659 

4660 def postinit( 

4661 self, 

4662 *, 

4663 value: NodeNG, 

4664 conversion: int, 

4665 format_spec: JoinedStr | None = None, 

4666 ) -> None: 

4667 """Do some setup after initialisation. 

4668 

4669 :param value: The value to be formatted into the string. 

4670 

4671 :param conversion: The type of formatting to be applied to the value. 

4672 

4673 :param format_spec: The formatting to be applied to the value. 

4674 :type format_spec: JoinedStr or None 

4675 """ 

4676 self.value = value 

4677 self.conversion = conversion 

4678 self.format_spec = format_spec 

4679 

4680 def get_children(self): 

4681 yield self.value 

4682 

4683 if self.format_spec is not None: 

4684 yield self.format_spec 

4685 

4686 def _infer( 

4687 self, context: InferenceContext | None = None, **kwargs: Any 

4688 ) -> Generator[InferenceResult, None, InferenceErrorInfo | None]: 

4689 format_specs = Const("") if self.format_spec is None else self.format_spec 

4690 uninferable_already_generated = False 

4691 for format_spec in format_specs.infer(context, **kwargs): 

4692 if not isinstance(format_spec, Const): 

4693 if not uninferable_already_generated: 

4694 yield util.Uninferable 

4695 uninferable_already_generated = True 

4696 continue 

4697 for value in self.value.infer(context, **kwargs): 

4698 value_to_format = value 

4699 if isinstance(value, Const): 

4700 value_to_format = value.value 

4701 try: 

4702 formatted = format(value_to_format, format_spec.value) 

4703 yield Const( 

4704 formatted, 

4705 lineno=self.lineno, 

4706 col_offset=self.col_offset, 

4707 end_lineno=self.end_lineno, 

4708 end_col_offset=self.end_col_offset, 

4709 ) 

4710 continue 

4711 except (ValueError, TypeError): 

4712 # happens when format_spec.value is invalid 

4713 yield util.Uninferable 

4714 uninferable_already_generated = True 

4715 continue 

4716 

4717 

4718UNINFERABLE_VALUE = "{Uninferable}" 

4719 

4720 

4721class JoinedStr(NodeNG): 

4722 """Represents a list of string expressions to be joined. 

4723 

4724 >>> import astroid 

4725 >>> node = astroid.extract_node('f"Format {type_}"') 

4726 >>> node 

4727 <JoinedStr l.1 at 0x7f23b2e4ed30> 

4728 """ 

4729 

4730 _astroid_fields = ("values",) 

4731 

4732 def __init__( 

4733 self, 

4734 lineno: int | None = None, 

4735 col_offset: int | None = None, 

4736 parent: NodeNG | None = None, 

4737 *, 

4738 end_lineno: int | None = None, 

4739 end_col_offset: int | None = None, 

4740 ) -> None: 

4741 """ 

4742 :param lineno: The line that this node appears on in the source code. 

4743 

4744 :param col_offset: The column that this node appears on in the 

4745 source code. 

4746 

4747 :param parent: The parent node in the syntax tree. 

4748 

4749 :param end_lineno: The last line this node appears on in the source code. 

4750 

4751 :param end_col_offset: The end column this node appears on in the 

4752 source code. Note: This is after the last symbol. 

4753 """ 

4754 self.values: list[NodeNG] = [] 

4755 """The string expressions to be joined. 

4756 

4757 :type: list(FormattedValue or Const) 

4758 """ 

4759 

4760 super().__init__( 

4761 lineno=lineno, 

4762 col_offset=col_offset, 

4763 end_lineno=end_lineno, 

4764 end_col_offset=end_col_offset, 

4765 parent=parent, 

4766 ) 

4767 

4768 def postinit(self, values: list[NodeNG] | None = None) -> None: 

4769 """Do some setup after initialisation. 

4770 

4771 :param value: The string expressions to be joined. 

4772 

4773 :type: list(FormattedValue or Const) 

4774 """ 

4775 if values is not None: 

4776 self.values = values 

4777 

4778 def get_children(self): 

4779 yield from self.values 

4780 

4781 def _infer( 

4782 self, context: InferenceContext | None = None, **kwargs: Any 

4783 ) -> Generator[InferenceResult, None, InferenceErrorInfo | None]: 

4784 if self.values: 

4785 yield from self._infer_with_values(context) 

4786 else: 

4787 yield Const("") 

4788 

4789 def _infer_with_values( 

4790 self, context: InferenceContext | None = None, **kwargs: Any 

4791 ) -> Generator[InferenceResult, None, InferenceErrorInfo | None]: 

4792 uninferable_already_generated = False 

4793 for inferred in self._infer_from_values(self.values, context): 

4794 failed = inferred is util.Uninferable or ( 

4795 isinstance(inferred, Const) and UNINFERABLE_VALUE in inferred.value 

4796 ) 

4797 if failed: 

4798 if not uninferable_already_generated: 

4799 uninferable_already_generated = True 

4800 yield util.Uninferable 

4801 continue 

4802 yield inferred 

4803 

4804 @classmethod 

4805 def _infer_from_values( 

4806 cls, nodes: list[NodeNG], context: InferenceContext | None = None, **kwargs: Any 

4807 ) -> Generator[InferenceResult, None, InferenceErrorInfo | None]: 

4808 if not nodes: 

4809 return 

4810 if len(nodes) == 1: 

4811 for node in cls._safe_infer_from_node(nodes[0], context, **kwargs): 

4812 if isinstance(node, Const): 

4813 yield node 

4814 continue 

4815 yield Const(UNINFERABLE_VALUE) 

4816 return 

4817 for prefix in cls._safe_infer_from_node(nodes[0], context, **kwargs): 

4818 for suffix in cls._infer_from_values(nodes[1:], context, **kwargs): 

4819 result = "" 

4820 for node in (prefix, suffix): 

4821 if isinstance(node, Const): 

4822 result += str(node.value) 

4823 continue 

4824 result += UNINFERABLE_VALUE 

4825 yield Const(result) 

4826 

4827 @classmethod 

4828 def _safe_infer_from_node( 

4829 cls, node: NodeNG, context: InferenceContext | None = None, **kwargs: Any 

4830 ) -> Generator[InferenceResult, None, InferenceErrorInfo | None]: 

4831 try: 

4832 yield from node._infer(context, **kwargs) 

4833 except InferenceError: 

4834 yield util.Uninferable 

4835 

4836 

4837class NamedExpr(_base_nodes.AssignTypeNode): 

4838 """Represents the assignment from the assignment expression 

4839 

4840 >>> import astroid 

4841 >>> module = astroid.parse('if a := 1: pass') 

4842 >>> module.body[0].test 

4843 <NamedExpr l.1 at 0x7f23b2e4ed30> 

4844 """ 

4845 

4846 _astroid_fields = ("target", "value") 

4847 

4848 optional_assign = True 

4849 """Whether this node optionally assigns a variable. 

4850 

4851 Since NamedExpr are not always called they do not always assign.""" 

4852 

4853 def __init__( 

4854 self, 

4855 lineno: int | None = None, 

4856 col_offset: int | None = None, 

4857 parent: NodeNG | None = None, 

4858 *, 

4859 end_lineno: int | None = None, 

4860 end_col_offset: int | None = None, 

4861 ) -> None: 

4862 """ 

4863 :param lineno: The line that this node appears on in the source code. 

4864 

4865 :param col_offset: The column that this node appears on in the 

4866 source code. 

4867 

4868 :param parent: The parent node in the syntax tree. 

4869 

4870 :param end_lineno: The last line this node appears on in the source code. 

4871 

4872 :param end_col_offset: The end column this node appears on in the 

4873 source code. Note: This is after the last symbol. 

4874 """ 

4875 self.target: NodeNG 

4876 """The assignment target 

4877 

4878 :type: Name 

4879 """ 

4880 

4881 self.value: NodeNG 

4882 """The value that gets assigned in the expression""" 

4883 

4884 super().__init__( 

4885 lineno=lineno, 

4886 col_offset=col_offset, 

4887 end_lineno=end_lineno, 

4888 end_col_offset=end_col_offset, 

4889 parent=parent, 

4890 ) 

4891 

4892 def postinit(self, target: NodeNG, value: NodeNG) -> None: 

4893 self.target = target 

4894 self.value = value 

4895 

4896 assigned_stmts = protocols.named_expr_assigned_stmts 

4897 """Returns the assigned statement (non inferred) according to the assignment type. 

4898 See astroid/protocols.py for actual implementation. 

4899 """ 

4900 

4901 def frame( 

4902 self, *, future: Literal[None, True] = None 

4903 ) -> nodes.FunctionDef | nodes.Module | nodes.ClassDef | nodes.Lambda: 

4904 """The first parent frame node. 

4905 

4906 A frame node is a :class:`Module`, :class:`FunctionDef`, 

4907 or :class:`ClassDef`. 

4908 

4909 :returns: The first parent frame node. 

4910 """ 

4911 if future is not None: 

4912 warnings.warn( 

4913 "The future arg will be removed in astroid 4.0.", 

4914 DeprecationWarning, 

4915 stacklevel=2, 

4916 ) 

4917 if not self.parent: 

4918 raise ParentMissingError(target=self) 

4919 

4920 # For certain parents NamedExpr evaluate to the scope of the parent 

4921 if isinstance(self.parent, (Arguments, Keyword, Comprehension)): 

4922 if not self.parent.parent: 

4923 raise ParentMissingError(target=self.parent) 

4924 if not self.parent.parent.parent: 

4925 raise ParentMissingError(target=self.parent.parent) 

4926 return self.parent.parent.parent.frame() 

4927 

4928 return self.parent.frame() 

4929 

4930 def scope(self) -> LocalsDictNodeNG: 

4931 """The first parent node defining a new scope. 

4932 These can be Module, FunctionDef, ClassDef, Lambda, or GeneratorExp nodes. 

4933 

4934 :returns: The first parent scope node. 

4935 """ 

4936 if not self.parent: 

4937 raise ParentMissingError(target=self) 

4938 

4939 # For certain parents NamedExpr evaluate to the scope of the parent 

4940 if isinstance(self.parent, (Arguments, Keyword, Comprehension)): 

4941 if not self.parent.parent: 

4942 raise ParentMissingError(target=self.parent) 

4943 if not self.parent.parent.parent: 

4944 raise ParentMissingError(target=self.parent.parent) 

4945 return self.parent.parent.parent.scope() 

4946 

4947 return self.parent.scope() 

4948 

4949 def set_local(self, name: str, stmt: NodeNG) -> None: 

4950 """Define that the given name is declared in the given statement node. 

4951 NamedExpr's in Arguments, Keyword or Comprehension are evaluated in their 

4952 parent's parent scope. So we add to their frame's locals. 

4953 

4954 .. seealso:: :meth:`scope` 

4955 

4956 :param name: The name that is being defined. 

4957 

4958 :param stmt: The statement that defines the given name. 

4959 """ 

4960 self.frame().set_local(name, stmt) 

4961 

4962 

4963class Unknown(_base_nodes.AssignTypeNode): 

4964 """This node represents a node in a constructed AST where 

4965 introspection is not possible. At the moment, it's only used in 

4966 the args attribute of FunctionDef nodes where function signature 

4967 introspection failed. 

4968 """ 

4969 

4970 name = "Unknown" 

4971 

4972 def __init__( 

4973 self, 

4974 lineno: None = None, 

4975 col_offset: None = None, 

4976 parent: None = None, 

4977 *, 

4978 end_lineno: None = None, 

4979 end_col_offset: None = None, 

4980 ) -> None: 

4981 super().__init__( 

4982 lineno=lineno, 

4983 col_offset=col_offset, 

4984 end_lineno=end_lineno, 

4985 end_col_offset=end_col_offset, 

4986 parent=parent, 

4987 ) 

4988 

4989 def qname(self) -> Literal["Unknown"]: 

4990 return "Unknown" 

4991 

4992 def _infer(self, context: InferenceContext | None = None, **kwargs): 

4993 """Inference on an Unknown node immediately terminates.""" 

4994 yield util.Uninferable 

4995 

4996 

4997class EvaluatedObject(NodeNG): 

4998 """Contains an object that has already been inferred 

4999 

5000 This class is useful to pre-evaluate a particular node, 

5001 with the resulting class acting as the non-evaluated node. 

5002 """ 

5003 

5004 name = "EvaluatedObject" 

5005 _astroid_fields = ("original",) 

5006 _other_fields = ("value",) 

5007 

5008 def __init__( 

5009 self, original: SuccessfulInferenceResult, value: InferenceResult 

5010 ) -> None: 

5011 self.original: SuccessfulInferenceResult = original 

5012 """The original node that has already been evaluated""" 

5013 

5014 self.value: InferenceResult = value 

5015 """The inferred value""" 

5016 

5017 super().__init__( 

5018 lineno=self.original.lineno, 

5019 col_offset=self.original.col_offset, 

5020 parent=self.original.parent, 

5021 end_lineno=self.original.end_lineno, 

5022 end_col_offset=self.original.end_col_offset, 

5023 ) 

5024 

5025 def _infer( 

5026 self, context: InferenceContext | None = None, **kwargs: Any 

5027 ) -> Generator[NodeNG | util.UninferableBase]: 

5028 yield self.value 

5029 

5030 

5031# Pattern matching ####################################################### 

5032 

5033 

5034class Match(_base_nodes.Statement, _base_nodes.MultiLineBlockNode): 

5035 """Class representing a :class:`ast.Match` node. 

5036 

5037 >>> import astroid 

5038 >>> node = astroid.extract_node(''' 

5039 match x: 

5040 case 200: 

5041 ... 

5042 case _: 

5043 ... 

5044 ''') 

5045 >>> node 

5046 <Match l.2 at 0x10c24e170> 

5047 """ 

5048 

5049 _astroid_fields = ("subject", "cases") 

5050 _multi_line_block_fields = ("cases",) 

5051 

5052 def __init__( 

5053 self, 

5054 lineno: int | None = None, 

5055 col_offset: int | None = None, 

5056 parent: NodeNG | None = None, 

5057 *, 

5058 end_lineno: int | None = None, 

5059 end_col_offset: int | None = None, 

5060 ) -> None: 

5061 self.subject: NodeNG 

5062 self.cases: list[MatchCase] 

5063 super().__init__( 

5064 lineno=lineno, 

5065 col_offset=col_offset, 

5066 end_lineno=end_lineno, 

5067 end_col_offset=end_col_offset, 

5068 parent=parent, 

5069 ) 

5070 

5071 def postinit( 

5072 self, 

5073 *, 

5074 subject: NodeNG, 

5075 cases: list[MatchCase], 

5076 ) -> None: 

5077 self.subject = subject 

5078 self.cases = cases 

5079 

5080 

5081class Pattern(NodeNG): 

5082 """Base class for all Pattern nodes.""" 

5083 

5084 

5085class MatchCase(_base_nodes.MultiLineBlockNode): 

5086 """Class representing a :class:`ast.match_case` node. 

5087 

5088 >>> import astroid 

5089 >>> node = astroid.extract_node(''' 

5090 match x: 

5091 case 200: 

5092 ... 

5093 ''') 

5094 >>> node.cases[0] 

5095 <MatchCase l.3 at 0x10c24e590> 

5096 """ 

5097 

5098 _astroid_fields = ("pattern", "guard", "body") 

5099 _multi_line_block_fields = ("body",) 

5100 

5101 lineno: None 

5102 col_offset: None 

5103 end_lineno: None 

5104 end_col_offset: None 

5105 

5106 def __init__(self, *, parent: NodeNG | None = None) -> None: 

5107 self.pattern: Pattern 

5108 self.guard: NodeNG | None 

5109 self.body: list[NodeNG] 

5110 super().__init__( 

5111 parent=parent, 

5112 lineno=None, 

5113 col_offset=None, 

5114 end_lineno=None, 

5115 end_col_offset=None, 

5116 ) 

5117 

5118 def postinit( 

5119 self, 

5120 *, 

5121 pattern: Pattern, 

5122 guard: NodeNG | None, 

5123 body: list[NodeNG], 

5124 ) -> None: 

5125 self.pattern = pattern 

5126 self.guard = guard 

5127 self.body = body 

5128 

5129 

5130class MatchValue(Pattern): 

5131 """Class representing a :class:`ast.MatchValue` node. 

5132 

5133 >>> import astroid 

5134 >>> node = astroid.extract_node(''' 

5135 match x: 

5136 case 200: 

5137 ... 

5138 ''') 

5139 >>> node.cases[0].pattern 

5140 <MatchValue l.3 at 0x10c24e200> 

5141 """ 

5142 

5143 _astroid_fields = ("value",) 

5144 

5145 def __init__( 

5146 self, 

5147 lineno: int | None = None, 

5148 col_offset: int | None = None, 

5149 parent: NodeNG | None = None, 

5150 *, 

5151 end_lineno: int | None = None, 

5152 end_col_offset: int | None = None, 

5153 ) -> None: 

5154 self.value: NodeNG 

5155 super().__init__( 

5156 lineno=lineno, 

5157 col_offset=col_offset, 

5158 end_lineno=end_lineno, 

5159 end_col_offset=end_col_offset, 

5160 parent=parent, 

5161 ) 

5162 

5163 def postinit(self, *, value: NodeNG) -> None: 

5164 self.value = value 

5165 

5166 

5167class MatchSingleton(Pattern): 

5168 """Class representing a :class:`ast.MatchSingleton` node. 

5169 

5170 >>> import astroid 

5171 >>> node = astroid.extract_node(''' 

5172 match x: 

5173 case True: 

5174 ... 

5175 case False: 

5176 ... 

5177 case None: 

5178 ... 

5179 ''') 

5180 >>> node.cases[0].pattern 

5181 <MatchSingleton l.3 at 0x10c2282e0> 

5182 >>> node.cases[1].pattern 

5183 <MatchSingleton l.5 at 0x10c228af0> 

5184 >>> node.cases[2].pattern 

5185 <MatchSingleton l.7 at 0x10c229f90> 

5186 """ 

5187 

5188 _other_fields = ("value",) 

5189 

5190 def __init__( 

5191 self, 

5192 *, 

5193 value: Literal[True, False, None], 

5194 lineno: int | None = None, 

5195 col_offset: int | None = None, 

5196 end_lineno: int | None = None, 

5197 end_col_offset: int | None = None, 

5198 parent: NodeNG | None = None, 

5199 ) -> None: 

5200 self.value = value 

5201 super().__init__( 

5202 lineno=lineno, 

5203 col_offset=col_offset, 

5204 end_lineno=end_lineno, 

5205 end_col_offset=end_col_offset, 

5206 parent=parent, 

5207 ) 

5208 

5209 

5210class MatchSequence(Pattern): 

5211 """Class representing a :class:`ast.MatchSequence` node. 

5212 

5213 >>> import astroid 

5214 >>> node = astroid.extract_node(''' 

5215 match x: 

5216 case [1, 2]: 

5217 ... 

5218 case (1, 2, *_): 

5219 ... 

5220 ''') 

5221 >>> node.cases[0].pattern 

5222 <MatchSequence l.3 at 0x10ca80d00> 

5223 >>> node.cases[1].pattern 

5224 <MatchSequence l.5 at 0x10ca80b20> 

5225 """ 

5226 

5227 _astroid_fields = ("patterns",) 

5228 

5229 def __init__( 

5230 self, 

5231 lineno: int | None = None, 

5232 col_offset: int | None = None, 

5233 parent: NodeNG | None = None, 

5234 *, 

5235 end_lineno: int | None = None, 

5236 end_col_offset: int | None = None, 

5237 ) -> None: 

5238 self.patterns: list[Pattern] 

5239 super().__init__( 

5240 lineno=lineno, 

5241 col_offset=col_offset, 

5242 end_lineno=end_lineno, 

5243 end_col_offset=end_col_offset, 

5244 parent=parent, 

5245 ) 

5246 

5247 def postinit(self, *, patterns: list[Pattern]) -> None: 

5248 self.patterns = patterns 

5249 

5250 

5251class MatchMapping(_base_nodes.AssignTypeNode, Pattern): 

5252 """Class representing a :class:`ast.MatchMapping` node. 

5253 

5254 >>> import astroid 

5255 >>> node = astroid.extract_node(''' 

5256 match x: 

5257 case {1: "Hello", 2: "World", 3: _, **rest}: 

5258 ... 

5259 ''') 

5260 >>> node.cases[0].pattern 

5261 <MatchMapping l.3 at 0x10c8a8850> 

5262 """ 

5263 

5264 _astroid_fields = ("keys", "patterns", "rest") 

5265 

5266 def __init__( 

5267 self, 

5268 lineno: int | None = None, 

5269 col_offset: int | None = None, 

5270 parent: NodeNG | None = None, 

5271 *, 

5272 end_lineno: int | None = None, 

5273 end_col_offset: int | None = None, 

5274 ) -> None: 

5275 self.keys: list[NodeNG] 

5276 self.patterns: list[Pattern] 

5277 self.rest: AssignName | None 

5278 super().__init__( 

5279 lineno=lineno, 

5280 col_offset=col_offset, 

5281 end_lineno=end_lineno, 

5282 end_col_offset=end_col_offset, 

5283 parent=parent, 

5284 ) 

5285 

5286 def postinit( 

5287 self, 

5288 *, 

5289 keys: list[NodeNG], 

5290 patterns: list[Pattern], 

5291 rest: AssignName | None, 

5292 ) -> None: 

5293 self.keys = keys 

5294 self.patterns = patterns 

5295 self.rest = rest 

5296 

5297 assigned_stmts = protocols.match_mapping_assigned_stmts 

5298 """Returns the assigned statement (non inferred) according to the assignment type. 

5299 See astroid/protocols.py for actual implementation. 

5300 """ 

5301 

5302 

5303class MatchClass(Pattern): 

5304 """Class representing a :class:`ast.MatchClass` node. 

5305 

5306 >>> import astroid 

5307 >>> node = astroid.extract_node(''' 

5308 match x: 

5309 case Point2D(0, 0): 

5310 ... 

5311 case Point3D(x=0, y=0, z=0): 

5312 ... 

5313 ''') 

5314 >>> node.cases[0].pattern 

5315 <MatchClass l.3 at 0x10ca83940> 

5316 >>> node.cases[1].pattern 

5317 <MatchClass l.5 at 0x10ca80880> 

5318 """ 

5319 

5320 _astroid_fields = ("cls", "patterns", "kwd_patterns") 

5321 _other_fields = ("kwd_attrs",) 

5322 

5323 def __init__( 

5324 self, 

5325 lineno: int | None = None, 

5326 col_offset: int | None = None, 

5327 parent: NodeNG | None = None, 

5328 *, 

5329 end_lineno: int | None = None, 

5330 end_col_offset: int | None = None, 

5331 ) -> None: 

5332 self.cls: NodeNG 

5333 self.patterns: list[Pattern] 

5334 self.kwd_attrs: list[str] 

5335 self.kwd_patterns: list[Pattern] 

5336 super().__init__( 

5337 lineno=lineno, 

5338 col_offset=col_offset, 

5339 end_lineno=end_lineno, 

5340 end_col_offset=end_col_offset, 

5341 parent=parent, 

5342 ) 

5343 

5344 def postinit( 

5345 self, 

5346 *, 

5347 cls: NodeNG, 

5348 patterns: list[Pattern], 

5349 kwd_attrs: list[str], 

5350 kwd_patterns: list[Pattern], 

5351 ) -> None: 

5352 self.cls = cls 

5353 self.patterns = patterns 

5354 self.kwd_attrs = kwd_attrs 

5355 self.kwd_patterns = kwd_patterns 

5356 

5357 

5358class MatchStar(_base_nodes.AssignTypeNode, Pattern): 

5359 """Class representing a :class:`ast.MatchStar` node. 

5360 

5361 >>> import astroid 

5362 >>> node = astroid.extract_node(''' 

5363 match x: 

5364 case [1, *_]: 

5365 ... 

5366 ''') 

5367 >>> node.cases[0].pattern.patterns[1] 

5368 <MatchStar l.3 at 0x10ca809a0> 

5369 """ 

5370 

5371 _astroid_fields = ("name",) 

5372 

5373 def __init__( 

5374 self, 

5375 lineno: int | None = None, 

5376 col_offset: int | None = None, 

5377 parent: NodeNG | None = None, 

5378 *, 

5379 end_lineno: int | None = None, 

5380 end_col_offset: int | None = None, 

5381 ) -> None: 

5382 self.name: AssignName | None 

5383 super().__init__( 

5384 lineno=lineno, 

5385 col_offset=col_offset, 

5386 end_lineno=end_lineno, 

5387 end_col_offset=end_col_offset, 

5388 parent=parent, 

5389 ) 

5390 

5391 def postinit(self, *, name: AssignName | None) -> None: 

5392 self.name = name 

5393 

5394 assigned_stmts = protocols.match_star_assigned_stmts 

5395 """Returns the assigned statement (non inferred) according to the assignment type. 

5396 See astroid/protocols.py for actual implementation. 

5397 """ 

5398 

5399 

5400class MatchAs(_base_nodes.AssignTypeNode, Pattern): 

5401 """Class representing a :class:`ast.MatchAs` node. 

5402 

5403 >>> import astroid 

5404 >>> node = astroid.extract_node(''' 

5405 match x: 

5406 case [1, a]: 

5407 ... 

5408 case {'key': b}: 

5409 ... 

5410 case Point2D(0, 0) as c: 

5411 ... 

5412 case d: 

5413 ... 

5414 ''') 

5415 >>> node.cases[0].pattern.patterns[1] 

5416 <MatchAs l.3 at 0x10d0b2da0> 

5417 >>> node.cases[1].pattern.patterns[0] 

5418 <MatchAs l.5 at 0x10d0b2920> 

5419 >>> node.cases[2].pattern 

5420 <MatchAs l.7 at 0x10d0b06a0> 

5421 >>> node.cases[3].pattern 

5422 <MatchAs l.9 at 0x10d09b880> 

5423 """ 

5424 

5425 _astroid_fields = ("pattern", "name") 

5426 

5427 def __init__( 

5428 self, 

5429 lineno: int | None = None, 

5430 col_offset: int | None = None, 

5431 parent: NodeNG | None = None, 

5432 *, 

5433 end_lineno: int | None = None, 

5434 end_col_offset: int | None = None, 

5435 ) -> None: 

5436 self.pattern: Pattern | None 

5437 self.name: AssignName | None 

5438 super().__init__( 

5439 lineno=lineno, 

5440 col_offset=col_offset, 

5441 end_lineno=end_lineno, 

5442 end_col_offset=end_col_offset, 

5443 parent=parent, 

5444 ) 

5445 

5446 def postinit( 

5447 self, 

5448 *, 

5449 pattern: Pattern | None, 

5450 name: AssignName | None, 

5451 ) -> None: 

5452 self.pattern = pattern 

5453 self.name = name 

5454 

5455 assigned_stmts = protocols.match_as_assigned_stmts 

5456 """Returns the assigned statement (non inferred) according to the assignment type. 

5457 See astroid/protocols.py for actual implementation. 

5458 """ 

5459 

5460 

5461class MatchOr(Pattern): 

5462 """Class representing a :class:`ast.MatchOr` node. 

5463 

5464 >>> import astroid 

5465 >>> node = astroid.extract_node(''' 

5466 match x: 

5467 case 400 | 401 | 402: 

5468 ... 

5469 ''') 

5470 >>> node.cases[0].pattern 

5471 <MatchOr l.3 at 0x10d0b0b50> 

5472 """ 

5473 

5474 _astroid_fields = ("patterns",) 

5475 

5476 def __init__( 

5477 self, 

5478 lineno: int | None = None, 

5479 col_offset: int | None = None, 

5480 parent: NodeNG | None = None, 

5481 *, 

5482 end_lineno: int | None = None, 

5483 end_col_offset: int | None = None, 

5484 ) -> None: 

5485 self.patterns: list[Pattern] 

5486 super().__init__( 

5487 lineno=lineno, 

5488 col_offset=col_offset, 

5489 end_lineno=end_lineno, 

5490 end_col_offset=end_col_offset, 

5491 parent=parent, 

5492 ) 

5493 

5494 def postinit(self, *, patterns: list[Pattern]) -> None: 

5495 self.patterns = patterns 

5496 

5497 

5498# constants ############################################################## 

5499 

5500# The _proxied attribute of all container types (List, Tuple, etc.) 

5501# are set during bootstrapping by _astroid_bootstrapping(). 

5502CONST_CLS: dict[type, type[NodeNG]] = { 

5503 list: List, 

5504 tuple: Tuple, 

5505 dict: Dict, 

5506 set: Set, 

5507 type(None): Const, 

5508 type(NotImplemented): Const, 

5509 type(...): Const, 

5510 bool: Const, 

5511 int: Const, 

5512 float: Const, 

5513 complex: Const, 

5514 str: Const, 

5515 bytes: Const, 

5516} 

5517 

5518 

5519def _create_basic_elements( 

5520 value: Iterable[Any], node: List | Set | Tuple 

5521) -> list[NodeNG]: 

5522 """Create a list of nodes to function as the elements of a new node.""" 

5523 elements: list[NodeNG] = [] 

5524 for element in value: 

5525 element_node = const_factory(element) 

5526 element_node.parent = node 

5527 elements.append(element_node) 

5528 return elements 

5529 

5530 

5531def _create_dict_items( 

5532 values: Mapping[Any, Any], node: Dict 

5533) -> list[tuple[SuccessfulInferenceResult, SuccessfulInferenceResult]]: 

5534 """Create a list of node pairs to function as the items of a new dict node.""" 

5535 elements: list[tuple[SuccessfulInferenceResult, SuccessfulInferenceResult]] = [] 

5536 for key, value in values.items(): 

5537 key_node = const_factory(key) 

5538 key_node.parent = node 

5539 value_node = const_factory(value) 

5540 value_node.parent = node 

5541 elements.append((key_node, value_node)) 

5542 return elements 

5543 

5544 

5545def const_factory(value: Any) -> ConstFactoryResult: 

5546 """Return an astroid node for a python value.""" 

5547 assert not isinstance(value, NodeNG) 

5548 

5549 # This only handles instances of the CONST types. Any 

5550 # subclasses get inferred as EmptyNode. 

5551 # TODO: See if we should revisit these with the normal builder. 

5552 if value.__class__ not in CONST_CLS: 

5553 node = EmptyNode() 

5554 node.object = value 

5555 return node 

5556 

5557 instance: List | Set | Tuple | Dict 

5558 initializer_cls = CONST_CLS[value.__class__] 

5559 if issubclass(initializer_cls, (List, Set, Tuple)): 

5560 instance = initializer_cls( 

5561 lineno=None, 

5562 col_offset=None, 

5563 parent=SYNTHETIC_ROOT, 

5564 end_lineno=None, 

5565 end_col_offset=None, 

5566 ) 

5567 instance.postinit(_create_basic_elements(value, instance)) 

5568 return instance 

5569 if issubclass(initializer_cls, Dict): 

5570 instance = initializer_cls( 

5571 lineno=None, 

5572 col_offset=None, 

5573 parent=SYNTHETIC_ROOT, 

5574 end_lineno=None, 

5575 end_col_offset=None, 

5576 ) 

5577 instance.postinit(_create_dict_items(value, instance)) 

5578 return instance 

5579 return Const(value)