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

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

1859 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 Generator, Iterable, Iterator, Mapping 

17from functools import cached_property 

18from typing import ( 

19 TYPE_CHECKING, 

20 Any, 

21 Callable, 

22 ClassVar, 

23 Literal, 

24 Optional, 

25 Union, 

26) 

27 

28from astroid import decorators, protocols, util 

29from astroid.bases import Instance, _infer_stmts 

30from astroid.const import _EMPTY_OBJECT_MARKER, Context 

31from astroid.context import CallContext, InferenceContext, copy_context 

32from astroid.exceptions import ( 

33 AstroidBuildingError, 

34 AstroidError, 

35 AstroidIndexError, 

36 AstroidTypeError, 

37 AstroidValueError, 

38 AttributeInferenceError, 

39 InferenceError, 

40 NameInferenceError, 

41 NoDefault, 

42 ParentMissingError, 

43 _NonDeducibleTypeHierarchy, 

44) 

45from astroid.interpreter import dunder_lookup 

46from astroid.manager import AstroidManager 

47from astroid.nodes import _base_nodes 

48from astroid.nodes.const import OP_PRECEDENCE 

49from astroid.nodes.node_ng import NodeNG 

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[typing.List[int]], 

81 ], 

82 Any, 

83] 

84InferBinaryOperation = Callable[ 

85 [_NodesT, Optional[InferenceContext]], 

86 typing.Generator[Union[InferenceResult, _BadOpMessageT], None, None], 

87] 

88InferLHS = Callable[ 

89 [_NodesT, Optional[InferenceContext]], 

90 typing.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 

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, None, None]: 

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, None, None]: 

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, None, None]: 

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

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, None, None]: 

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, None, None]: 

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

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, None, None]: 

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 | None = None, 

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 self.value: Any = value 

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

2067 

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

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

2070 

2071 super().__init__( 

2072 lineno=lineno, 

2073 col_offset=col_offset, 

2074 end_lineno=end_lineno, 

2075 end_col_offset=end_col_offset, 

2076 parent=parent, 

2077 ) 

2078 

2079 Instance.__init__(self, None) 

2080 

2081 infer_unary_op = protocols.const_infer_unary_op 

2082 infer_binary_op = protocols.const_infer_binary_op 

2083 

2084 def __getattr__(self, name): 

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

2086 # Calling object.__new__ on this class without calling 

2087 # __init__ would result in an infinite loop otherwise 

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

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

2090 # and Proxy __getattr__ calls self.value 

2091 if name == "value": 

2092 raise AttributeError 

2093 return super().__getattr__(name) 

2094 

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

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

2097 

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

2099 :type index: Const or Slice 

2100 

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

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

2103 """ 

2104 if isinstance(index, Const): 

2105 index_value = index.value 

2106 elif isinstance(index, Slice): 

2107 index_value = _infer_slice(index, context=context) 

2108 

2109 else: 

2110 raise AstroidTypeError( 

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

2112 ) 

2113 

2114 try: 

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

2116 return Const(self.value[index_value]) 

2117 except ValueError as exc: 

2118 raise AstroidValueError( 

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

2120 ) from exc 

2121 except IndexError as exc: 

2122 raise AstroidIndexError( 

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

2124 node=self, 

2125 index=index, 

2126 context=context, 

2127 ) from exc 

2128 except TypeError as exc: 

2129 raise AstroidTypeError( 

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

2131 ) from exc 

2132 

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

2134 

2135 def has_dynamic_getattr(self) -> bool: 

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

2137 

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

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

2140 """ 

2141 return False 

2142 

2143 def itered(self): 

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

2145 

2146 :returns: The contents of this node. 

2147 :rtype: iterable(Const) 

2148 

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

2150 """ 

2151 if isinstance(self.value, str): 

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

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

2154 

2155 def pytype(self) -> str: 

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

2157 

2158 :returns: The name of the type. 

2159 """ 

2160 return self._proxied.qname() 

2161 

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

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

2164 

2165 :returns: The boolean value of this node. 

2166 :rtype: bool 

2167 """ 

2168 return bool(self.value) 

2169 

2170 def _infer( 

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

2172 ) -> Iterator[Const]: 

2173 yield self 

2174 

2175 

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

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

2178 

2179 >>> import astroid 

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

2181 >>> node 

2182 <Continue l.1 at 0x7f23b2e35588> 

2183 """ 

2184 

2185 

2186class Decorators(NodeNG): 

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

2188 

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

2190 a method or function. 

2191 

2192 >>> import astroid 

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

2194 @property 

2195 def my_property(self): 

2196 return 3 

2197 ''') 

2198 >>> node 

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

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

2201 <Decorators l.1 at 0x7f23b2e35d68> 

2202 """ 

2203 

2204 _astroid_fields = ("nodes",) 

2205 

2206 nodes: list[NodeNG] 

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

2208 

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

2210 self.nodes = nodes 

2211 

2212 def scope(self) -> LocalsDictNodeNG: 

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

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

2215 

2216 :returns: The first parent scope node. 

2217 """ 

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

2219 if not self.parent: 

2220 raise ParentMissingError(target=self) 

2221 if not self.parent.parent: 

2222 raise ParentMissingError(target=self.parent) 

2223 return self.parent.parent.scope() 

2224 

2225 def get_children(self): 

2226 yield from self.nodes 

2227 

2228 

2229class DelAttr(_base_nodes.ParentAssignNode): 

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

2231 

2232 >>> import astroid 

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

2234 >>> node 

2235 <Delete l.1 at 0x7f23b2e35f60> 

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

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

2238 """ 

2239 

2240 _astroid_fields = ("expr",) 

2241 _other_fields = ("attrname",) 

2242 

2243 expr: NodeNG 

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

2245 

2246 def __init__( 

2247 self, 

2248 attrname: str, 

2249 lineno: int, 

2250 col_offset: int, 

2251 parent: NodeNG, 

2252 *, 

2253 end_lineno: int | None, 

2254 end_col_offset: int | None, 

2255 ) -> None: 

2256 self.attrname = attrname 

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

2258 

2259 super().__init__( 

2260 lineno=lineno, 

2261 col_offset=col_offset, 

2262 end_lineno=end_lineno, 

2263 end_col_offset=end_col_offset, 

2264 parent=parent, 

2265 ) 

2266 

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

2268 self.expr = expr 

2269 

2270 def get_children(self): 

2271 yield self.expr 

2272 

2273 

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

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

2276 

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

2278 

2279 >>> import astroid 

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

2281 >>> node 

2282 <Delete l.1 at 0x7f23b2e35f60> 

2283 """ 

2284 

2285 _astroid_fields = ("targets",) 

2286 

2287 def __init__( 

2288 self, 

2289 lineno: int, 

2290 col_offset: int, 

2291 parent: NodeNG, 

2292 *, 

2293 end_lineno: int | None, 

2294 end_col_offset: int | None, 

2295 ) -> None: 

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

2297 """What is being deleted.""" 

2298 

2299 super().__init__( 

2300 lineno=lineno, 

2301 col_offset=col_offset, 

2302 end_lineno=end_lineno, 

2303 end_col_offset=end_col_offset, 

2304 parent=parent, 

2305 ) 

2306 

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

2308 self.targets = targets 

2309 

2310 def get_children(self): 

2311 yield from self.targets 

2312 

2313 

2314class Dict(NodeNG, Instance): 

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

2316 

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

2318 

2319 >>> import astroid 

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

2321 >>> node 

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

2323 """ 

2324 

2325 _astroid_fields = ("items",) 

2326 

2327 def __init__( 

2328 self, 

2329 lineno: int | None, 

2330 col_offset: int | None, 

2331 parent: NodeNG | None, 

2332 *, 

2333 end_lineno: int | None, 

2334 end_col_offset: int | None, 

2335 ) -> None: 

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

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

2338 

2339 super().__init__( 

2340 lineno=lineno, 

2341 col_offset=col_offset, 

2342 end_lineno=end_lineno, 

2343 end_col_offset=end_col_offset, 

2344 parent=parent, 

2345 ) 

2346 

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

2348 """Do some setup after initialisation. 

2349 

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

2351 """ 

2352 self.items = items 

2353 

2354 infer_unary_op = protocols.dict_infer_unary_op 

2355 

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

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

2358 

2359 :returns: The name of the type. 

2360 """ 

2361 return "builtins.dict" 

2362 

2363 def get_children(self): 

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

2365 

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

2367 code, key first then the value. 

2368 

2369 :returns: The children. 

2370 :rtype: iterable(NodeNG) 

2371 """ 

2372 for key, value in self.items: 

2373 yield key 

2374 yield value 

2375 

2376 def last_child(self): 

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

2378 

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

2380 :rtype: NodeNG or None 

2381 """ 

2382 if self.items: 

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

2384 return None 

2385 

2386 def itered(self): 

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

2388 

2389 :returns: The keys of this node. 

2390 :rtype: iterable(NodeNG) 

2391 """ 

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

2393 

2394 def getitem( 

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

2396 ) -> NodeNG: 

2397 """Get an item from this node. 

2398 

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

2400 

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

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

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

2404 dictionary. 

2405 """ 

2406 for key, value in self.items: 

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

2408 if isinstance(key, DictUnpack): 

2409 inferred_value = util.safe_infer(value, context) 

2410 if not isinstance(inferred_value, Dict): 

2411 continue 

2412 

2413 try: 

2414 return inferred_value.getitem(index, context) 

2415 except (AstroidTypeError, AstroidIndexError): 

2416 continue 

2417 

2418 for inferredkey in key.infer(context): 

2419 if isinstance(inferredkey, util.UninferableBase): 

2420 continue 

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

2422 if inferredkey.value == index.value: 

2423 return value 

2424 

2425 raise AstroidIndexError(index) 

2426 

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

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

2429 

2430 :returns: The boolean value of this node. 

2431 :rtype: bool 

2432 """ 

2433 return bool(self.items) 

2434 

2435 def _infer( 

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

2437 ) -> Iterator[nodes.Dict]: 

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

2439 yield self 

2440 else: 

2441 items = self._infer_map(context) 

2442 new_seq = type(self)( 

2443 lineno=self.lineno, 

2444 col_offset=self.col_offset, 

2445 parent=self.parent, 

2446 end_lineno=self.end_lineno, 

2447 end_col_offset=self.end_col_offset, 

2448 ) 

2449 new_seq.postinit(list(items.items())) 

2450 yield new_seq 

2451 

2452 @staticmethod 

2453 def _update_with_replacement( 

2454 lhs_dict: dict[SuccessfulInferenceResult, SuccessfulInferenceResult], 

2455 rhs_dict: dict[SuccessfulInferenceResult, SuccessfulInferenceResult], 

2456 ) -> dict[SuccessfulInferenceResult, SuccessfulInferenceResult]: 

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

2458 

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

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

2461 don't get through 

2462 

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

2464 

2465 Fixes issue with DictUnpack causing duplicate keys 

2466 in inferred Dict items 

2467 

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

2469 :param rhs_dict: Dictionary with nodes to pull from 

2470 :return : merged dictionary of nodes 

2471 """ 

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

2473 # Overwrite keys which have the same string values 

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

2475 # Return to dictionary 

2476 return dict(string_map.values()) 

2477 

2478 def _infer_map( 

2479 self, context: InferenceContext | None 

2480 ) -> dict[SuccessfulInferenceResult, SuccessfulInferenceResult]: 

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

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

2483 for name, value in self.items: 

2484 if isinstance(name, DictUnpack): 

2485 double_starred = util.safe_infer(value, context) 

2486 if not double_starred: 

2487 raise InferenceError 

2488 if not isinstance(double_starred, Dict): 

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

2490 unpack_items = double_starred._infer_map(context) 

2491 values = self._update_with_replacement(values, unpack_items) 

2492 else: 

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

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

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

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

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

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

2499 return values 

2500 

2501 

2502class Expr(_base_nodes.Statement): 

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

2504 

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

2506 stored. 

2507 

2508 >>> import astroid 

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

2510 >>> node 

2511 <Call l.1 at 0x7f23b2e352b0> 

2512 >>> node.parent 

2513 <Expr l.1 at 0x7f23b2e35278> 

2514 """ 

2515 

2516 _astroid_fields = ("value",) 

2517 

2518 value: NodeNG 

2519 """What the expression does.""" 

2520 

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

2522 self.value = value 

2523 

2524 def get_children(self): 

2525 yield self.value 

2526 

2527 def _get_yield_nodes_skip_functions(self): 

2528 if not self.value.is_function: 

2529 yield from self.value._get_yield_nodes_skip_functions() 

2530 

2531 def _get_yield_nodes_skip_lambdas(self): 

2532 if not self.value.is_lambda: 

2533 yield from self.value._get_yield_nodes_skip_lambdas() 

2534 

2535 

2536class EmptyNode(_base_nodes.NoChildrenNode): 

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

2538 

2539 object = None 

2540 

2541 def __init__( 

2542 self, 

2543 lineno: None = None, 

2544 col_offset: None = None, 

2545 parent: None = None, 

2546 *, 

2547 end_lineno: None = None, 

2548 end_col_offset: None = None, 

2549 ) -> None: 

2550 super().__init__( 

2551 lineno=lineno, 

2552 col_offset=col_offset, 

2553 end_lineno=end_lineno, 

2554 end_col_offset=end_col_offset, 

2555 parent=parent, 

2556 ) 

2557 

2558 def has_underlying_object(self) -> bool: 

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

2560 

2561 @decorators.raise_if_nothing_inferred 

2562 @decorators.path_wrapper 

2563 def _infer( 

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

2565 ) -> Generator[InferenceResult, None, None]: 

2566 if not self.has_underlying_object(): 

2567 yield util.Uninferable 

2568 else: 

2569 try: 

2570 yield from AstroidManager().infer_ast_from_something( 

2571 self.object, context=context 

2572 ) 

2573 except AstroidError: 

2574 yield util.Uninferable 

2575 

2576 

2577class ExceptHandler( 

2578 _base_nodes.MultiLineBlockNode, _base_nodes.AssignTypeNode, _base_nodes.Statement 

2579): 

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

2581 

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

2583 

2584 >>> import astroid 

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

2586 try: 

2587 do_something() 

2588 except Exception as error: 

2589 print("Error!") 

2590 ''') 

2591 >>> node 

2592 <Try l.2 at 0x7f23b2e9d908> 

2593 >>> node.handlers 

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

2595 """ 

2596 

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

2598 _multi_line_block_fields = ("body",) 

2599 

2600 type: NodeNG | None 

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

2602 

2603 name: AssignName | None 

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

2605 

2606 body: list[NodeNG] 

2607 """The contents of the block.""" 

2608 

2609 assigned_stmts = protocols.excepthandler_assigned_stmts 

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

2611 See astroid/protocols.py for actual implementation. 

2612 """ 

2613 

2614 def postinit( 

2615 self, 

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

2617 name: AssignName | None, 

2618 body: list[NodeNG], 

2619 ) -> None: 

2620 self.type = type 

2621 self.name = name 

2622 self.body = body 

2623 

2624 def get_children(self): 

2625 if self.type is not None: 

2626 yield self.type 

2627 

2628 if self.name is not None: 

2629 yield self.name 

2630 

2631 yield from self.body 

2632 

2633 @cached_property 

2634 def blockstart_tolineno(self): 

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

2636 

2637 :type: int 

2638 """ 

2639 if self.name: 

2640 return self.name.tolineno 

2641 if self.type: 

2642 return self.type.tolineno 

2643 return self.lineno 

2644 

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

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

2647 

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

2649 """ 

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

2651 return True 

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

2653 

2654 

2655class For( 

2656 _base_nodes.MultiLineWithElseBlockNode, 

2657 _base_nodes.AssignTypeNode, 

2658 _base_nodes.Statement, 

2659): 

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

2661 

2662 >>> import astroid 

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

2664 >>> node 

2665 <For l.1 at 0x7f23b2e8cf28> 

2666 """ 

2667 

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

2669 _other_other_fields = ("type_annotation",) 

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

2671 

2672 optional_assign = True 

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

2674 

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

2676 """ 

2677 

2678 target: NodeNG 

2679 """What the loop assigns to.""" 

2680 

2681 iter: NodeNG 

2682 """What the loop iterates over.""" 

2683 

2684 body: list[NodeNG] 

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

2686 

2687 orelse: list[NodeNG] 

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

2689 

2690 type_annotation: NodeNG | None 

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

2692 

2693 def postinit( 

2694 self, 

2695 target: NodeNG, 

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

2697 body: list[NodeNG], 

2698 orelse: list[NodeNG], 

2699 type_annotation: NodeNG | None, 

2700 ) -> None: 

2701 self.target = target 

2702 self.iter = iter 

2703 self.body = body 

2704 self.orelse = orelse 

2705 self.type_annotation = type_annotation 

2706 

2707 assigned_stmts = protocols.for_assigned_stmts 

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

2709 See astroid/protocols.py for actual implementation. 

2710 """ 

2711 

2712 @cached_property 

2713 def blockstart_tolineno(self): 

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

2715 

2716 :type: int 

2717 """ 

2718 return self.iter.tolineno 

2719 

2720 def get_children(self): 

2721 yield self.target 

2722 yield self.iter 

2723 

2724 yield from self.body 

2725 yield from self.orelse 

2726 

2727 

2728class AsyncFor(For): 

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

2730 

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

2732 the ``async`` keyword. 

2733 

2734 >>> import astroid 

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

2736 async def func(things): 

2737 async for thing in things: 

2738 print(thing) 

2739 ''') 

2740 >>> node 

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

2742 >>> node.body[0] 

2743 <AsyncFor l.3 at 0x7f23b2e417b8> 

2744 """ 

2745 

2746 

2747class Await(NodeNG): 

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

2749 

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

2751 

2752 >>> import astroid 

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

2754 async def func(things): 

2755 await other_func() 

2756 ''') 

2757 >>> node 

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

2759 >>> node.body[0] 

2760 <Expr l.3 at 0x7f23b2e419e8> 

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

2762 <Await l.3 at 0x7f23b2e41a20> 

2763 """ 

2764 

2765 _astroid_fields = ("value",) 

2766 

2767 value: NodeNG 

2768 """What to wait for.""" 

2769 

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

2771 self.value = value 

2772 

2773 def get_children(self): 

2774 yield self.value 

2775 

2776 

2777class ImportFrom(_base_nodes.ImportNode): 

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

2779 

2780 >>> import astroid 

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

2782 >>> node 

2783 <ImportFrom l.1 at 0x7f23b2e415c0> 

2784 """ 

2785 

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

2787 

2788 def __init__( 

2789 self, 

2790 fromname: str | None, 

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

2792 level: int | None = 0, 

2793 lineno: int | None = None, 

2794 col_offset: int | None = None, 

2795 parent: NodeNG | None = None, 

2796 *, 

2797 end_lineno: int | None = None, 

2798 end_col_offset: int | None = None, 

2799 ) -> None: 

2800 """ 

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

2802 

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

2804 

2805 :param level: The level of relative import. 

2806 

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

2808 

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

2810 source code. 

2811 

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

2813 

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

2815 

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

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

2818 """ 

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

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

2821 

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

2823 """ 

2824 

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

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

2827 

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

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

2830 """ 

2831 

2832 # TODO When is 'level' None? 

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

2834 """The level of relative import. 

2835 

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

2837 This is always 0 for absolute imports. 

2838 """ 

2839 

2840 super().__init__( 

2841 lineno=lineno, 

2842 col_offset=col_offset, 

2843 end_lineno=end_lineno, 

2844 end_col_offset=end_col_offset, 

2845 parent=parent, 

2846 ) 

2847 

2848 @decorators.raise_if_nothing_inferred 

2849 @decorators.path_wrapper 

2850 def _infer( 

2851 self, 

2852 context: InferenceContext | None = None, 

2853 asname: bool = True, 

2854 **kwargs: Any, 

2855 ) -> Generator[InferenceResult, None, None]: 

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

2857 context = context or InferenceContext() 

2858 name = context.lookupname 

2859 if name is None: 

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

2861 if asname: 

2862 try: 

2863 name = self.real_name(name) 

2864 except AttributeInferenceError as exc: 

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

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

2867 try: 

2868 module = self.do_import_module() 

2869 except AstroidBuildingError as exc: 

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

2871 

2872 try: 

2873 context = copy_context(context) 

2874 context.lookupname = name 

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

2876 return _infer_stmts(stmts, context) 

2877 except AttributeInferenceError as error: 

2878 raise InferenceError( 

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

2880 ) from error 

2881 

2882 

2883class Attribute(NodeNG): 

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

2885 

2886 expr: NodeNG 

2887 

2888 _astroid_fields = ("expr",) 

2889 _other_fields = ("attrname",) 

2890 

2891 def __init__( 

2892 self, 

2893 attrname: str, 

2894 lineno: int, 

2895 col_offset: int, 

2896 parent: NodeNG, 

2897 *, 

2898 end_lineno: int | None, 

2899 end_col_offset: int | None, 

2900 ) -> None: 

2901 self.attrname = attrname 

2902 """The name of the attribute.""" 

2903 

2904 super().__init__( 

2905 lineno=lineno, 

2906 col_offset=col_offset, 

2907 end_lineno=end_lineno, 

2908 end_col_offset=end_col_offset, 

2909 parent=parent, 

2910 ) 

2911 

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

2913 self.expr = expr 

2914 

2915 def get_children(self): 

2916 yield self.expr 

2917 

2918 @decorators.raise_if_nothing_inferred 

2919 @decorators.path_wrapper 

2920 def _infer( 

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

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

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

2924 

2925 

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

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

2928 

2929 >>> import astroid 

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

2931 >>> node 

2932 <Global l.1 at 0x7f23b2e9de10> 

2933 """ 

2934 

2935 _other_fields = ("names",) 

2936 

2937 def __init__( 

2938 self, 

2939 names: list[str], 

2940 lineno: int | None = None, 

2941 col_offset: int | None = None, 

2942 parent: NodeNG | None = None, 

2943 *, 

2944 end_lineno: int | None = None, 

2945 end_col_offset: int | None = None, 

2946 ) -> None: 

2947 """ 

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

2949 

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

2951 

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

2953 source code. 

2954 

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

2956 

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

2958 

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

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

2961 """ 

2962 self.names: list[str] = names 

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

2964 

2965 super().__init__( 

2966 lineno=lineno, 

2967 col_offset=col_offset, 

2968 end_lineno=end_lineno, 

2969 end_col_offset=end_col_offset, 

2970 parent=parent, 

2971 ) 

2972 

2973 def _infer_name(self, frame, name): 

2974 return name 

2975 

2976 @decorators.raise_if_nothing_inferred 

2977 @decorators.path_wrapper 

2978 def _infer( 

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

2980 ) -> Generator[InferenceResult, None, None]: 

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

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

2983 try: 

2984 # pylint: disable-next=no-member 

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

2986 except AttributeInferenceError as error: 

2987 raise InferenceError( 

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

2989 ) from error 

2990 

2991 

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

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

2994 

2995 >>> import astroid 

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

2997 >>> node 

2998 <If l.1 at 0x7f23b2e9dd30> 

2999 """ 

3000 

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

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

3003 

3004 test: NodeNG 

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

3006 

3007 body: list[NodeNG] 

3008 """The contents of the block.""" 

3009 

3010 orelse: list[NodeNG] 

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

3012 

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

3014 self.test = test 

3015 self.body = body 

3016 self.orelse = orelse 

3017 

3018 @cached_property 

3019 def blockstart_tolineno(self): 

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

3021 

3022 :type: int 

3023 """ 

3024 return self.test.tolineno 

3025 

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

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

3028 

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

3030 

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

3032 starting at the given line number. 

3033 """ 

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

3035 return lineno, lineno 

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

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

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

3039 

3040 def get_children(self): 

3041 yield self.test 

3042 

3043 yield from self.body 

3044 yield from self.orelse 

3045 

3046 def has_elif_block(self): 

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

3048 

3049 def _get_yield_nodes_skip_functions(self): 

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

3051 yield from self.test._get_yield_nodes_skip_functions() 

3052 yield from super()._get_yield_nodes_skip_functions() 

3053 

3054 def _get_yield_nodes_skip_lambdas(self): 

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

3056 yield from self.test._get_yield_nodes_skip_lambdas() 

3057 yield from super()._get_yield_nodes_skip_lambdas() 

3058 

3059 

3060class IfExp(NodeNG): 

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

3062 >>> import astroid 

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

3064 >>> node 

3065 <IfExp l.1 at 0x7f23b2e9dbe0> 

3066 """ 

3067 

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

3069 

3070 test: NodeNG 

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

3072 

3073 body: NodeNG 

3074 """The contents of the block.""" 

3075 

3076 orelse: NodeNG 

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

3078 

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

3080 self.test = test 

3081 self.body = body 

3082 self.orelse = orelse 

3083 

3084 def get_children(self): 

3085 yield self.test 

3086 yield self.body 

3087 yield self.orelse 

3088 

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

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

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

3092 return False 

3093 

3094 @decorators.raise_if_nothing_inferred 

3095 def _infer( 

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

3097 ) -> Generator[InferenceResult, None, None]: 

3098 """Support IfExp inference. 

3099 

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

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

3102 depending on the condition. 

3103 """ 

3104 both_branches = False 

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

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

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

3108 

3109 context = context or InferenceContext() 

3110 lhs_context = copy_context(context) 

3111 rhs_context = copy_context(context) 

3112 try: 

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

3114 except (InferenceError, StopIteration): 

3115 both_branches = True 

3116 else: 

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

3118 if test.bool_value(): 

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

3120 else: 

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

3122 else: 

3123 both_branches = True 

3124 if both_branches: 

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

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

3127 

3128 

3129class Import(_base_nodes.ImportNode): 

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

3131 >>> import astroid 

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

3133 >>> node 

3134 <Import l.1 at 0x7f23b2e4e5c0> 

3135 """ 

3136 

3137 _other_fields = ("names",) 

3138 

3139 def __init__( 

3140 self, 

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

3142 lineno: int | None = None, 

3143 col_offset: int | None = None, 

3144 parent: NodeNG | None = None, 

3145 *, 

3146 end_lineno: int | None = None, 

3147 end_col_offset: int | None = None, 

3148 ) -> None: 

3149 """ 

3150 :param names: The names being imported. 

3151 

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

3153 

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

3155 source code. 

3156 

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

3158 

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

3160 

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

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

3163 """ 

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

3165 """The names being imported. 

3166 

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

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

3169 """ 

3170 

3171 super().__init__( 

3172 lineno=lineno, 

3173 col_offset=col_offset, 

3174 end_lineno=end_lineno, 

3175 end_col_offset=end_col_offset, 

3176 parent=parent, 

3177 ) 

3178 

3179 @decorators.raise_if_nothing_inferred 

3180 @decorators.path_wrapper 

3181 def _infer( 

3182 self, 

3183 context: InferenceContext | None = None, 

3184 asname: bool = True, 

3185 **kwargs: Any, 

3186 ) -> Generator[nodes.Module, None, None]: 

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

3188 context = context or InferenceContext() 

3189 name = context.lookupname 

3190 if name is None: 

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

3192 

3193 try: 

3194 if asname: 

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

3196 else: 

3197 yield self.do_import_module(name) 

3198 except AstroidBuildingError as exc: 

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

3200 

3201 

3202class Keyword(NodeNG): 

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

3204 

3205 >>> import astroid 

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

3207 >>> node 

3208 <Call l.1 at 0x7f23b2e9e320> 

3209 >>> node.keywords 

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

3211 """ 

3212 

3213 _astroid_fields = ("value",) 

3214 _other_fields = ("arg",) 

3215 

3216 value: NodeNG 

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

3218 

3219 def __init__( 

3220 self, 

3221 arg: str | None, 

3222 lineno: int | None, 

3223 col_offset: int | None, 

3224 parent: NodeNG, 

3225 *, 

3226 end_lineno: int | None, 

3227 end_col_offset: int | None, 

3228 ) -> None: 

3229 self.arg = arg 

3230 """The argument being assigned to.""" 

3231 

3232 super().__init__( 

3233 lineno=lineno, 

3234 col_offset=col_offset, 

3235 end_lineno=end_lineno, 

3236 end_col_offset=end_col_offset, 

3237 parent=parent, 

3238 ) 

3239 

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

3241 self.value = value 

3242 

3243 def get_children(self): 

3244 yield self.value 

3245 

3246 

3247class List(BaseContainer): 

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

3249 

3250 >>> import astroid 

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

3252 >>> node 

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

3254 """ 

3255 

3256 _other_fields = ("ctx",) 

3257 

3258 def __init__( 

3259 self, 

3260 ctx: Context | None = None, 

3261 lineno: int | None = None, 

3262 col_offset: int | None = None, 

3263 parent: NodeNG | None = None, 

3264 *, 

3265 end_lineno: int | None = None, 

3266 end_col_offset: int | None = None, 

3267 ) -> None: 

3268 """ 

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

3270 

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

3272 

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

3274 source code. 

3275 

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

3277 

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

3279 

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

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

3282 """ 

3283 self.ctx: Context | None = ctx 

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

3285 

3286 super().__init__( 

3287 lineno=lineno, 

3288 col_offset=col_offset, 

3289 end_lineno=end_lineno, 

3290 end_col_offset=end_col_offset, 

3291 parent=parent, 

3292 ) 

3293 

3294 assigned_stmts = protocols.sequence_assigned_stmts 

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

3296 See astroid/protocols.py for actual implementation. 

3297 """ 

3298 

3299 infer_unary_op = protocols.list_infer_unary_op 

3300 infer_binary_op = protocols.tl_infer_binary_op 

3301 

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

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

3304 

3305 :returns: The name of the type. 

3306 """ 

3307 return "builtins.list" 

3308 

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

3310 """Get an item from this node. 

3311 

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

3313 :type index: Const or Slice 

3314 """ 

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

3316 

3317 

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

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

3320 

3321 >>> import astroid 

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

3323 def function(): 

3324 nonlocal var 

3325 ''') 

3326 >>> node 

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

3328 >>> node.body[0] 

3329 <Nonlocal l.3 at 0x7f23b2e9e908> 

3330 """ 

3331 

3332 _other_fields = ("names",) 

3333 

3334 def __init__( 

3335 self, 

3336 names: list[str], 

3337 lineno: int | None = None, 

3338 col_offset: int | None = None, 

3339 parent: NodeNG | None = None, 

3340 *, 

3341 end_lineno: int | None = None, 

3342 end_col_offset: int | None = None, 

3343 ) -> None: 

3344 """ 

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

3346 

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

3348 

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

3350 source code. 

3351 

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

3353 

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

3355 

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

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

3358 """ 

3359 self.names: list[str] = names 

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

3361 

3362 super().__init__( 

3363 lineno=lineno, 

3364 col_offset=col_offset, 

3365 end_lineno=end_lineno, 

3366 end_col_offset=end_col_offset, 

3367 parent=parent, 

3368 ) 

3369 

3370 def _infer_name(self, frame, name): 

3371 return name 

3372 

3373 

3374class ParamSpec(_base_nodes.AssignTypeNode): 

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

3376 

3377 >>> import astroid 

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

3379 >>> node.type_params[0] 

3380 <ParamSpec l.1 at 0x7f23b2e4e198> 

3381 """ 

3382 

3383 _astroid_fields = ("name",) 

3384 

3385 name: AssignName 

3386 

3387 def __init__( 

3388 self, 

3389 lineno: int, 

3390 col_offset: int, 

3391 parent: NodeNG, 

3392 *, 

3393 end_lineno: int, 

3394 end_col_offset: int, 

3395 ) -> None: 

3396 super().__init__( 

3397 lineno=lineno, 

3398 col_offset=col_offset, 

3399 end_lineno=end_lineno, 

3400 end_col_offset=end_col_offset, 

3401 parent=parent, 

3402 ) 

3403 

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

3405 self.name = name 

3406 

3407 def _infer( 

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

3409 ) -> Iterator[ParamSpec]: 

3410 yield self 

3411 

3412 assigned_stmts = protocols.generic_type_assigned_stmts 

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

3414 See astroid/protocols.py for actual implementation. 

3415 """ 

3416 

3417 

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

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

3420 

3421 >>> import astroid 

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

3423 >>> node 

3424 <Pass l.1 at 0x7f23b2e9e748> 

3425 """ 

3426 

3427 

3428class Raise(_base_nodes.Statement): 

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

3430 

3431 >>> import astroid 

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

3433 >>> node 

3434 <Raise l.1 at 0x7f23b2e9e828> 

3435 """ 

3436 

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

3438 

3439 exc: NodeNG | None 

3440 """What is being raised.""" 

3441 

3442 cause: NodeNG | None 

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

3444 

3445 def postinit( 

3446 self, 

3447 exc: NodeNG | None, 

3448 cause: NodeNG | None, 

3449 ) -> None: 

3450 self.exc = exc 

3451 self.cause = cause 

3452 

3453 def raises_not_implemented(self) -> bool: 

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

3455 

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

3457 """ 

3458 if not self.exc: 

3459 return False 

3460 return any( 

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

3462 ) 

3463 

3464 def get_children(self): 

3465 if self.exc is not None: 

3466 yield self.exc 

3467 

3468 if self.cause is not None: 

3469 yield self.cause 

3470 

3471 

3472class Return(_base_nodes.Statement): 

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

3474 

3475 >>> import astroid 

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

3477 >>> node 

3478 <Return l.1 at 0x7f23b8211908> 

3479 """ 

3480 

3481 _astroid_fields = ("value",) 

3482 

3483 value: NodeNG | None 

3484 """The value being returned.""" 

3485 

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

3487 self.value = value 

3488 

3489 def get_children(self): 

3490 if self.value is not None: 

3491 yield self.value 

3492 

3493 def is_tuple_return(self): 

3494 return isinstance(self.value, Tuple) 

3495 

3496 def _get_return_nodes_skip_functions(self): 

3497 yield self 

3498 

3499 

3500class Set(BaseContainer): 

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

3502 

3503 >>> import astroid 

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

3505 >>> node 

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

3507 """ 

3508 

3509 infer_unary_op = protocols.set_infer_unary_op 

3510 

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

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

3513 

3514 :returns: The name of the type. 

3515 """ 

3516 return "builtins.set" 

3517 

3518 

3519class Slice(NodeNG): 

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

3521 

3522 >>> import astroid 

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

3524 >>> node 

3525 <Subscript l.1 at 0x7f23b2e71f60> 

3526 >>> node.slice 

3527 <Slice l.1 at 0x7f23b2e71e80> 

3528 """ 

3529 

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

3531 

3532 lower: NodeNG | None 

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

3534 

3535 upper: NodeNG | None 

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

3537 

3538 step: NodeNG | None 

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

3540 

3541 def postinit( 

3542 self, 

3543 lower: NodeNG | None, 

3544 upper: NodeNG | None, 

3545 step: NodeNG | None, 

3546 ) -> None: 

3547 self.lower = lower 

3548 self.upper = upper 

3549 self.step = step 

3550 

3551 def _wrap_attribute(self, attr): 

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

3553 if not attr: 

3554 const = const_factory(attr) 

3555 const.parent = self 

3556 return const 

3557 return attr 

3558 

3559 @cached_property 

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

3561 builtins = AstroidManager().builtins_module 

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

3563 

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

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

3566 

3567 :returns: The name of the type. 

3568 """ 

3569 return "builtins.slice" 

3570 

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

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

3573 

3574 :returns: The type of this node. 

3575 """ 

3576 return "Slice" 

3577 

3578 def igetattr( 

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

3580 ) -> Iterator[SuccessfulInferenceResult]: 

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

3582 

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

3584 

3585 :returns: The inferred possible values. 

3586 """ 

3587 if attrname == "start": 

3588 yield self._wrap_attribute(self.lower) 

3589 elif attrname == "stop": 

3590 yield self._wrap_attribute(self.upper) 

3591 elif attrname == "step": 

3592 yield self._wrap_attribute(self.step) 

3593 else: 

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

3595 

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

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

3598 

3599 def get_children(self): 

3600 if self.lower is not None: 

3601 yield self.lower 

3602 

3603 if self.upper is not None: 

3604 yield self.upper 

3605 

3606 if self.step is not None: 

3607 yield self.step 

3608 

3609 def _infer( 

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

3611 ) -> Iterator[Slice]: 

3612 yield self 

3613 

3614 

3615class Starred(_base_nodes.ParentAssignNode): 

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

3617 

3618 >>> import astroid 

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

3620 >>> node 

3621 <Starred l.1 at 0x7f23b2e41978> 

3622 """ 

3623 

3624 _astroid_fields = ("value",) 

3625 _other_fields = ("ctx",) 

3626 

3627 value: NodeNG 

3628 """What is being unpacked.""" 

3629 

3630 def __init__( 

3631 self, 

3632 ctx: Context, 

3633 lineno: int, 

3634 col_offset: int, 

3635 parent: NodeNG, 

3636 *, 

3637 end_lineno: int | None, 

3638 end_col_offset: int | None, 

3639 ) -> None: 

3640 self.ctx = ctx 

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

3642 

3643 super().__init__( 

3644 lineno=lineno, 

3645 col_offset=col_offset, 

3646 end_lineno=end_lineno, 

3647 end_col_offset=end_col_offset, 

3648 parent=parent, 

3649 ) 

3650 

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

3652 self.value = value 

3653 

3654 assigned_stmts = protocols.starred_assigned_stmts 

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

3656 See astroid/protocols.py for actual implementation. 

3657 """ 

3658 

3659 def get_children(self): 

3660 yield self.value 

3661 

3662 

3663class Subscript(NodeNG): 

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

3665 

3666 >>> import astroid 

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

3668 >>> node 

3669 <Subscript l.1 at 0x7f23b2e71f60> 

3670 """ 

3671 

3672 _SUBSCRIPT_SENTINEL = object() 

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

3674 _other_fields = ("ctx",) 

3675 

3676 value: NodeNG 

3677 """What is being indexed.""" 

3678 

3679 slice: NodeNG 

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

3681 

3682 def __init__( 

3683 self, 

3684 ctx: Context, 

3685 lineno: int, 

3686 col_offset: int, 

3687 parent: NodeNG, 

3688 *, 

3689 end_lineno: int | None, 

3690 end_col_offset: int | None, 

3691 ) -> None: 

3692 self.ctx = ctx 

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

3694 

3695 super().__init__( 

3696 lineno=lineno, 

3697 col_offset=col_offset, 

3698 end_lineno=end_lineno, 

3699 end_col_offset=end_col_offset, 

3700 parent=parent, 

3701 ) 

3702 

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

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

3705 self.value = value 

3706 self.slice = slice 

3707 

3708 def get_children(self): 

3709 yield self.value 

3710 yield self.slice 

3711 

3712 def _infer_subscript( 

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

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

3715 """Inference for subscripts. 

3716 

3717 We're understanding if the index is a Const 

3718 or a slice, passing the result of inference 

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

3720 handle each supported index type accordingly. 

3721 """ 

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

3723 

3724 found_one = False 

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

3726 if isinstance(value, util.UninferableBase): 

3727 yield util.Uninferable 

3728 return None 

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

3730 if isinstance(index, util.UninferableBase): 

3731 yield util.Uninferable 

3732 return None 

3733 

3734 # Try to deduce the index value. 

3735 index_value = self._SUBSCRIPT_SENTINEL 

3736 if value.__class__ == Instance: 

3737 index_value = index 

3738 elif index.__class__ == Instance: 

3739 instance_as_index = helpers.class_instance_as_index(index) 

3740 if instance_as_index: 

3741 index_value = instance_as_index 

3742 else: 

3743 index_value = index 

3744 

3745 if index_value is self._SUBSCRIPT_SENTINEL: 

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

3747 

3748 try: 

3749 assigned = value.getitem(index_value, context) 

3750 except ( 

3751 AstroidTypeError, 

3752 AstroidIndexError, 

3753 AstroidValueError, 

3754 AttributeInferenceError, 

3755 AttributeError, 

3756 ) as exc: 

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

3758 

3759 # Prevent inferring if the inferred subscript 

3760 # is the same as the original subscripted object. 

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

3762 yield util.Uninferable 

3763 return None 

3764 yield from assigned.infer(context) 

3765 found_one = True 

3766 

3767 if found_one: 

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

3769 return None 

3770 

3771 @decorators.raise_if_nothing_inferred 

3772 @decorators.path_wrapper 

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

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

3775 

3776 @decorators.raise_if_nothing_inferred 

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

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

3779 

3780 

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

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

3783 

3784 >>> import astroid 

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

3786 try: 

3787 do_something() 

3788 except Exception as error: 

3789 print("Error!") 

3790 finally: 

3791 print("Cleanup!") 

3792 ''') 

3793 >>> node 

3794 <Try l.2 at 0x7f23b2e41d68> 

3795 """ 

3796 

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

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

3799 

3800 def __init__( 

3801 self, 

3802 *, 

3803 lineno: int, 

3804 col_offset: int, 

3805 end_lineno: int, 

3806 end_col_offset: int, 

3807 parent: NodeNG, 

3808 ) -> None: 

3809 """ 

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

3811 

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

3813 source code. 

3814 

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

3816 

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

3818 

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

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

3821 """ 

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

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

3824 

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

3826 """The exception handlers.""" 

3827 

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

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

3830 

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

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

3833 

3834 super().__init__( 

3835 lineno=lineno, 

3836 col_offset=col_offset, 

3837 end_lineno=end_lineno, 

3838 end_col_offset=end_col_offset, 

3839 parent=parent, 

3840 ) 

3841 

3842 def postinit( 

3843 self, 

3844 *, 

3845 body: list[NodeNG], 

3846 handlers: list[ExceptHandler], 

3847 orelse: list[NodeNG], 

3848 finalbody: list[NodeNG], 

3849 ) -> None: 

3850 """Do some setup after initialisation. 

3851 

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

3853 

3854 :param handlers: The exception handlers. 

3855 

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

3857 

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

3859 """ 

3860 self.body = body 

3861 self.handlers = handlers 

3862 self.orelse = orelse 

3863 self.finalbody = finalbody 

3864 

3865 def _infer_name(self, frame, name): 

3866 return name 

3867 

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

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

3870 if lineno == self.fromlineno: 

3871 return lineno, lineno 

3872 if self.body and self.body[0].fromlineno <= lineno <= self.body[-1].tolineno: 

3873 # Inside try body - return from lineno till end of try body 

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

3875 for exhandler in self.handlers: 

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

3877 return lineno, lineno 

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

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

3880 if self.orelse: 

3881 if self.orelse[0].fromlineno - 1 == lineno: 

3882 return lineno, lineno 

3883 if self.orelse[0].fromlineno <= lineno <= self.orelse[-1].tolineno: 

3884 return lineno, self.orelse[-1].tolineno 

3885 if self.finalbody: 

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

3887 return lineno, lineno 

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

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

3890 return lineno, self.tolineno 

3891 

3892 def get_children(self): 

3893 yield from self.body 

3894 yield from self.handlers 

3895 yield from self.orelse 

3896 yield from self.finalbody 

3897 

3898 

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

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

3901 

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

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

3904 

3905 def __init__( 

3906 self, 

3907 *, 

3908 lineno: int | None = None, 

3909 col_offset: int | None = None, 

3910 end_lineno: int | None = None, 

3911 end_col_offset: int | None = None, 

3912 parent: NodeNG | None = None, 

3913 ) -> None: 

3914 """ 

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

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

3917 source code. 

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

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

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

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

3922 """ 

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

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

3925 

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

3927 """The exception handlers.""" 

3928 

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

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

3931 

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

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

3934 

3935 super().__init__( 

3936 lineno=lineno, 

3937 col_offset=col_offset, 

3938 end_lineno=end_lineno, 

3939 end_col_offset=end_col_offset, 

3940 parent=parent, 

3941 ) 

3942 

3943 def postinit( 

3944 self, 

3945 *, 

3946 body: list[NodeNG] | None = None, 

3947 handlers: list[ExceptHandler] | None = None, 

3948 orelse: list[NodeNG] | None = None, 

3949 finalbody: list[NodeNG] | None = None, 

3950 ) -> None: 

3951 """Do some setup after initialisation. 

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

3953 :param handlers: The exception handlers. 

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

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

3956 """ 

3957 if body: 

3958 self.body = body 

3959 if handlers: 

3960 self.handlers = handlers 

3961 if orelse: 

3962 self.orelse = orelse 

3963 if finalbody: 

3964 self.finalbody = finalbody 

3965 

3966 def _infer_name(self, frame, name): 

3967 return name 

3968 

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

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

3971 if lineno == self.fromlineno: 

3972 return lineno, lineno 

3973 if self.body and self.body[0].fromlineno <= lineno <= self.body[-1].tolineno: 

3974 # Inside try body - return from lineno till end of try body 

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

3976 for exhandler in self.handlers: 

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

3978 return lineno, lineno 

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

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

3981 if self.orelse: 

3982 if self.orelse[0].fromlineno - 1 == lineno: 

3983 return lineno, lineno 

3984 if self.orelse[0].fromlineno <= lineno <= self.orelse[-1].tolineno: 

3985 return lineno, self.orelse[-1].tolineno 

3986 if self.finalbody: 

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

3988 return lineno, lineno 

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

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

3991 return lineno, self.tolineno 

3992 

3993 def get_children(self): 

3994 yield from self.body 

3995 yield from self.handlers 

3996 yield from self.orelse 

3997 yield from self.finalbody 

3998 

3999 

4000class Tuple(BaseContainer): 

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

4002 

4003 >>> import astroid 

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

4005 >>> node 

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

4007 """ 

4008 

4009 _other_fields = ("ctx",) 

4010 

4011 def __init__( 

4012 self, 

4013 ctx: Context | None = None, 

4014 lineno: int | None = None, 

4015 col_offset: int | None = None, 

4016 parent: NodeNG | None = None, 

4017 *, 

4018 end_lineno: int | None = None, 

4019 end_col_offset: int | None = None, 

4020 ) -> None: 

4021 """ 

4022 :param ctx: Whether the tuple is assigned to or loaded from. 

4023 

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

4025 

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

4027 source code. 

4028 

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

4030 

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

4032 

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

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

4035 """ 

4036 self.ctx: Context | None = ctx 

4037 """Whether the tuple is assigned to or loaded from.""" 

4038 

4039 super().__init__( 

4040 lineno=lineno, 

4041 col_offset=col_offset, 

4042 end_lineno=end_lineno, 

4043 end_col_offset=end_col_offset, 

4044 parent=parent, 

4045 ) 

4046 

4047 assigned_stmts = protocols.sequence_assigned_stmts 

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

4049 See astroid/protocols.py for actual implementation. 

4050 """ 

4051 

4052 infer_unary_op = protocols.tuple_infer_unary_op 

4053 infer_binary_op = protocols.tl_infer_binary_op 

4054 

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

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

4057 

4058 :returns: The name of the type. 

4059 """ 

4060 return "builtins.tuple" 

4061 

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

4063 """Get an item from this node. 

4064 

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

4066 :type index: Const or Slice 

4067 """ 

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

4069 

4070 

4071class TypeAlias(_base_nodes.AssignTypeNode, _base_nodes.Statement): 

4072 """Class representing a :class:`ast.TypeAlias` node. 

4073 

4074 >>> import astroid 

4075 >>> node = astroid.extract_node('type Point = tuple[float, float]') 

4076 >>> node 

4077 <TypeAlias l.1 at 0x7f23b2e4e198> 

4078 """ 

4079 

4080 _astroid_fields = ("name", "type_params", "value") 

4081 

4082 name: AssignName 

4083 type_params: list[TypeVar | ParamSpec | TypeVarTuple] 

4084 value: NodeNG 

4085 

4086 def __init__( 

4087 self, 

4088 lineno: int, 

4089 col_offset: int, 

4090 parent: NodeNG, 

4091 *, 

4092 end_lineno: int, 

4093 end_col_offset: int, 

4094 ) -> None: 

4095 super().__init__( 

4096 lineno=lineno, 

4097 col_offset=col_offset, 

4098 end_lineno=end_lineno, 

4099 end_col_offset=end_col_offset, 

4100 parent=parent, 

4101 ) 

4102 

4103 def postinit( 

4104 self, 

4105 *, 

4106 name: AssignName, 

4107 type_params: list[TypeVar | ParamSpec | TypeVarTuple], 

4108 value: NodeNG, 

4109 ) -> None: 

4110 self.name = name 

4111 self.type_params = type_params 

4112 self.value = value 

4113 

4114 def _infer( 

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

4116 ) -> Iterator[TypeAlias]: 

4117 yield self 

4118 

4119 assigned_stmts: ClassVar[ 

4120 Callable[ 

4121 [ 

4122 TypeAlias, 

4123 AssignName, 

4124 InferenceContext | None, 

4125 None, 

4126 ], 

4127 Generator[NodeNG, None, None], 

4128 ] 

4129 ] = protocols.assign_assigned_stmts 

4130 

4131 

4132class TypeVar(_base_nodes.AssignTypeNode): 

4133 """Class representing a :class:`ast.TypeVar` node. 

4134 

4135 >>> import astroid 

4136 >>> node = astroid.extract_node('type Point[T] = tuple[float, float]') 

4137 >>> node.type_params[0] 

4138 <TypeVar l.1 at 0x7f23b2e4e198> 

4139 """ 

4140 

4141 _astroid_fields = ("name", "bound") 

4142 

4143 name: AssignName 

4144 bound: NodeNG | None 

4145 

4146 def __init__( 

4147 self, 

4148 lineno: int, 

4149 col_offset: int, 

4150 parent: NodeNG, 

4151 *, 

4152 end_lineno: int, 

4153 end_col_offset: int, 

4154 ) -> None: 

4155 super().__init__( 

4156 lineno=lineno, 

4157 col_offset=col_offset, 

4158 end_lineno=end_lineno, 

4159 end_col_offset=end_col_offset, 

4160 parent=parent, 

4161 ) 

4162 

4163 def postinit(self, *, name: AssignName, bound: NodeNG | None) -> None: 

4164 self.name = name 

4165 self.bound = bound 

4166 

4167 def _infer( 

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

4169 ) -> Iterator[TypeVar]: 

4170 yield self 

4171 

4172 assigned_stmts = protocols.generic_type_assigned_stmts 

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

4174 See astroid/protocols.py for actual implementation. 

4175 """ 

4176 

4177 

4178class TypeVarTuple(_base_nodes.AssignTypeNode): 

4179 """Class representing a :class:`ast.TypeVarTuple` node. 

4180 

4181 >>> import astroid 

4182 >>> node = astroid.extract_node('type Alias[*Ts] = tuple[*Ts]') 

4183 >>> node.type_params[0] 

4184 <TypeVarTuple l.1 at 0x7f23b2e4e198> 

4185 """ 

4186 

4187 _astroid_fields = ("name",) 

4188 

4189 name: AssignName 

4190 

4191 def __init__( 

4192 self, 

4193 lineno: int, 

4194 col_offset: int, 

4195 parent: NodeNG, 

4196 *, 

4197 end_lineno: int, 

4198 end_col_offset: int, 

4199 ) -> None: 

4200 super().__init__( 

4201 lineno=lineno, 

4202 col_offset=col_offset, 

4203 end_lineno=end_lineno, 

4204 end_col_offset=end_col_offset, 

4205 parent=parent, 

4206 ) 

4207 

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

4209 self.name = name 

4210 

4211 def _infer( 

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

4213 ) -> Iterator[TypeVarTuple]: 

4214 yield self 

4215 

4216 assigned_stmts = protocols.generic_type_assigned_stmts 

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

4218 See astroid/protocols.py for actual implementation. 

4219 """ 

4220 

4221 

4222UNARY_OP_METHOD = { 

4223 "+": "__pos__", 

4224 "-": "__neg__", 

4225 "~": "__invert__", 

4226 "not": None, # XXX not '__nonzero__' 

4227} 

4228 

4229 

4230class UnaryOp(_base_nodes.OperatorNode): 

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

4232 

4233 >>> import astroid 

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

4235 >>> node 

4236 <UnaryOp l.1 at 0x7f23b2e4e198> 

4237 """ 

4238 

4239 _astroid_fields = ("operand",) 

4240 _other_fields = ("op",) 

4241 

4242 operand: NodeNG 

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

4244 

4245 def __init__( 

4246 self, 

4247 op: str, 

4248 lineno: int, 

4249 col_offset: int, 

4250 parent: NodeNG, 

4251 *, 

4252 end_lineno: int | None, 

4253 end_col_offset: int | None, 

4254 ) -> None: 

4255 self.op = op 

4256 """The operator.""" 

4257 

4258 super().__init__( 

4259 lineno=lineno, 

4260 col_offset=col_offset, 

4261 end_lineno=end_lineno, 

4262 end_col_offset=end_col_offset, 

4263 parent=parent, 

4264 ) 

4265 

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

4267 self.operand = operand 

4268 

4269 def type_errors( 

4270 self, context: InferenceContext | None = None 

4271 ) -> list[util.BadUnaryOperationMessage]: 

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

4273 

4274 Each TypeError is represented by a :class:`BadUnaryOperationMessage`, 

4275 which holds the original exception. 

4276 

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

4278 """ 

4279 bad = [] 

4280 try: 

4281 for result in self._infer_unaryop(context=context): 

4282 if result is util.Uninferable: 

4283 raise InferenceError 

4284 if isinstance(result, util.BadUnaryOperationMessage): 

4285 bad.append(result) 

4286 except InferenceError: 

4287 return [] 

4288 return bad 

4289 

4290 def get_children(self): 

4291 yield self.operand 

4292 

4293 def op_precedence(self): 

4294 if self.op == "not": 

4295 return OP_PRECEDENCE[self.op] 

4296 

4297 return super().op_precedence() 

4298 

4299 def _infer_unaryop( 

4300 self: nodes.UnaryOp, context: InferenceContext | None = None, **kwargs: Any 

4301 ) -> Generator[ 

4302 InferenceResult | util.BadUnaryOperationMessage, None, InferenceErrorInfo 

4303 ]: 

4304 """Infer what an UnaryOp should return when evaluated.""" 

4305 from astroid.nodes import ClassDef # pylint: disable=import-outside-toplevel 

4306 

4307 for operand in self.operand.infer(context): 

4308 try: 

4309 yield operand.infer_unary_op(self.op) 

4310 except TypeError as exc: 

4311 # The operand doesn't support this operation. 

4312 yield util.BadUnaryOperationMessage(operand, self.op, exc) 

4313 except AttributeError as exc: 

4314 meth = UNARY_OP_METHOD[self.op] 

4315 if meth is None: 

4316 # `not node`. Determine node's boolean 

4317 # value and negate its result, unless it is 

4318 # Uninferable, which will be returned as is. 

4319 bool_value = operand.bool_value() 

4320 if not isinstance(bool_value, util.UninferableBase): 

4321 yield const_factory(not bool_value) 

4322 else: 

4323 yield util.Uninferable 

4324 else: 

4325 if not isinstance(operand, (Instance, ClassDef)): 

4326 # The operation was used on something which 

4327 # doesn't support it. 

4328 yield util.BadUnaryOperationMessage(operand, self.op, exc) 

4329 continue 

4330 

4331 try: 

4332 try: 

4333 methods = dunder_lookup.lookup(operand, meth) 

4334 except AttributeInferenceError: 

4335 yield util.BadUnaryOperationMessage(operand, self.op, exc) 

4336 continue 

4337 

4338 meth = methods[0] 

4339 inferred = next(meth.infer(context=context), None) 

4340 if ( 

4341 isinstance(inferred, util.UninferableBase) 

4342 or not inferred.callable() 

4343 ): 

4344 continue 

4345 

4346 context = copy_context(context) 

4347 context.boundnode = operand 

4348 context.callcontext = CallContext(args=[], callee=inferred) 

4349 

4350 call_results = inferred.infer_call_result(self, context=context) 

4351 result = next(call_results, None) 

4352 if result is None: 

4353 # Failed to infer, return the same type. 

4354 yield operand 

4355 else: 

4356 yield result 

4357 except AttributeInferenceError as inner_exc: 

4358 # The unary operation special method was not found. 

4359 yield util.BadUnaryOperationMessage(operand, self.op, inner_exc) 

4360 except InferenceError: 

4361 yield util.Uninferable 

4362 

4363 @decorators.raise_if_nothing_inferred 

4364 @decorators.path_wrapper 

4365 def _infer( 

4366 self: nodes.UnaryOp, context: InferenceContext | None = None, **kwargs: Any 

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

4368 """Infer what an UnaryOp should return when evaluated.""" 

4369 yield from self._filter_operation_errors( 

4370 self._infer_unaryop, context, util.BadUnaryOperationMessage 

4371 ) 

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

4373 

4374 

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

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

4377 

4378 >>> import astroid 

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

4380 while condition(): 

4381 print("True") 

4382 ''') 

4383 >>> node 

4384 <While l.2 at 0x7f23b2e4e390> 

4385 """ 

4386 

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

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

4389 

4390 test: NodeNG 

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

4392 

4393 body: list[NodeNG] 

4394 """The contents of the loop.""" 

4395 

4396 orelse: list[NodeNG] 

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

4398 

4399 def postinit( 

4400 self, 

4401 test: NodeNG, 

4402 body: list[NodeNG], 

4403 orelse: list[NodeNG], 

4404 ) -> None: 

4405 self.test = test 

4406 self.body = body 

4407 self.orelse = orelse 

4408 

4409 @cached_property 

4410 def blockstart_tolineno(self): 

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

4412 

4413 :type: int 

4414 """ 

4415 return self.test.tolineno 

4416 

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

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

4419 

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

4421 

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

4423 starting at the given line number. 

4424 """ 

4425 return self._elsed_block_range(lineno, self.orelse) 

4426 

4427 def get_children(self): 

4428 yield self.test 

4429 

4430 yield from self.body 

4431 yield from self.orelse 

4432 

4433 def _get_yield_nodes_skip_functions(self): 

4434 """A While node can contain a Yield node in the test""" 

4435 yield from self.test._get_yield_nodes_skip_functions() 

4436 yield from super()._get_yield_nodes_skip_functions() 

4437 

4438 def _get_yield_nodes_skip_lambdas(self): 

4439 """A While node can contain a Yield node in the test""" 

4440 yield from self.test._get_yield_nodes_skip_lambdas() 

4441 yield from super()._get_yield_nodes_skip_lambdas() 

4442 

4443 

4444class With( 

4445 _base_nodes.MultiLineWithElseBlockNode, 

4446 _base_nodes.AssignTypeNode, 

4447 _base_nodes.Statement, 

4448): 

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

4450 

4451 >>> import astroid 

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

4453 with open(file_path) as file_: 

4454 print(file_.read()) 

4455 ''') 

4456 >>> node 

4457 <With l.2 at 0x7f23b2e4e710> 

4458 """ 

4459 

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

4461 _other_other_fields = ("type_annotation",) 

4462 _multi_line_block_fields = ("body",) 

4463 

4464 def __init__( 

4465 self, 

4466 lineno: int | None = None, 

4467 col_offset: int | None = None, 

4468 parent: NodeNG | None = None, 

4469 *, 

4470 end_lineno: int | None = None, 

4471 end_col_offset: int | None = None, 

4472 ) -> None: 

4473 """ 

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

4475 

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

4477 source code. 

4478 

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

4480 

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

4482 

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

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

4485 """ 

4486 self.items: list[tuple[NodeNG, NodeNG | None]] = [] 

4487 """The pairs of context managers and the names they are assigned to.""" 

4488 

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

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

4491 

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

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

4494 

4495 super().__init__( 

4496 lineno=lineno, 

4497 col_offset=col_offset, 

4498 end_lineno=end_lineno, 

4499 end_col_offset=end_col_offset, 

4500 parent=parent, 

4501 ) 

4502 

4503 def postinit( 

4504 self, 

4505 items: list[tuple[NodeNG, NodeNG | None]] | None = None, 

4506 body: list[NodeNG] | None = None, 

4507 type_annotation: NodeNG | None = None, 

4508 ) -> None: 

4509 """Do some setup after initialisation. 

4510 

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

4512 they are assigned to. 

4513 

4514 :param body: The contents of the ``with`` block. 

4515 """ 

4516 if items is not None: 

4517 self.items = items 

4518 if body is not None: 

4519 self.body = body 

4520 self.type_annotation = type_annotation 

4521 

4522 assigned_stmts = protocols.with_assigned_stmts 

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

4524 See astroid/protocols.py for actual implementation. 

4525 """ 

4526 

4527 @cached_property 

4528 def blockstart_tolineno(self): 

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

4530 

4531 :type: int 

4532 """ 

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

4534 

4535 def get_children(self): 

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

4537 

4538 :returns: The children. 

4539 :rtype: iterable(NodeNG) 

4540 """ 

4541 for expr, var in self.items: 

4542 yield expr 

4543 if var: 

4544 yield var 

4545 yield from self.body 

4546 

4547 

4548class AsyncWith(With): 

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

4550 

4551 

4552class Yield(NodeNG): 

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

4554 

4555 >>> import astroid 

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

4557 >>> node 

4558 <Yield l.1 at 0x7f23b2e4e5f8> 

4559 """ 

4560 

4561 _astroid_fields = ("value",) 

4562 

4563 value: NodeNG | None 

4564 """The value to yield.""" 

4565 

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

4567 self.value = value 

4568 

4569 def get_children(self): 

4570 if self.value is not None: 

4571 yield self.value 

4572 

4573 def _get_yield_nodes_skip_functions(self): 

4574 yield self 

4575 

4576 def _get_yield_nodes_skip_lambdas(self): 

4577 yield self 

4578 

4579 

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

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

4582 

4583 

4584class DictUnpack(_base_nodes.NoChildrenNode): 

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

4586 

4587 

4588class FormattedValue(NodeNG): 

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

4590 

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

4592 

4593 >>> import astroid 

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

4595 >>> node 

4596 <JoinedStr l.1 at 0x7f23b2e4ed30> 

4597 >>> node.values 

4598 [<Const.str l.1 at 0x7f23b2e4eda0>, <FormattedValue l.1 at 0x7f23b2e4edd8>] 

4599 """ 

4600 

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

4602 _other_fields = ("conversion",) 

4603 

4604 def __init__( 

4605 self, 

4606 lineno: int | None = None, 

4607 col_offset: int | None = None, 

4608 parent: NodeNG | None = None, 

4609 *, 

4610 end_lineno: int | None = None, 

4611 end_col_offset: int | None = None, 

4612 ) -> None: 

4613 """ 

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

4615 

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

4617 source code. 

4618 

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

4620 

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

4622 

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

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

4625 """ 

4626 self.value: NodeNG 

4627 """The value to be formatted into the string.""" 

4628 

4629 self.conversion: int 

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

4631 

4632 .. seealso:: 

4633 :class:`ast.FormattedValue` 

4634 """ 

4635 

4636 self.format_spec: JoinedStr | None = None 

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

4638 

4639 .. seealso:: 

4640 :class:`ast.FormattedValue` 

4641 """ 

4642 

4643 super().__init__( 

4644 lineno=lineno, 

4645 col_offset=col_offset, 

4646 end_lineno=end_lineno, 

4647 end_col_offset=end_col_offset, 

4648 parent=parent, 

4649 ) 

4650 

4651 def postinit( 

4652 self, 

4653 *, 

4654 value: NodeNG, 

4655 conversion: int, 

4656 format_spec: JoinedStr | None = None, 

4657 ) -> None: 

4658 """Do some setup after initialisation. 

4659 

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

4661 

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

4663 

4664 :param format_spec: The formatting to be applied to the value. 

4665 :type format_spec: JoinedStr or None 

4666 """ 

4667 self.value = value 

4668 self.conversion = conversion 

4669 self.format_spec = format_spec 

4670 

4671 def get_children(self): 

4672 yield self.value 

4673 

4674 if self.format_spec is not None: 

4675 yield self.format_spec 

4676 

4677 

4678class JoinedStr(NodeNG): 

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

4680 

4681 >>> import astroid 

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

4683 >>> node 

4684 <JoinedStr l.1 at 0x7f23b2e4ed30> 

4685 """ 

4686 

4687 _astroid_fields = ("values",) 

4688 

4689 def __init__( 

4690 self, 

4691 lineno: int | None = None, 

4692 col_offset: int | None = None, 

4693 parent: NodeNG | None = None, 

4694 *, 

4695 end_lineno: int | None = None, 

4696 end_col_offset: int | None = None, 

4697 ) -> None: 

4698 """ 

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

4700 

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

4702 source code. 

4703 

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

4705 

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

4707 

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

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

4710 """ 

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

4712 """The string expressions to be joined. 

4713 

4714 :type: list(FormattedValue or Const) 

4715 """ 

4716 

4717 super().__init__( 

4718 lineno=lineno, 

4719 col_offset=col_offset, 

4720 end_lineno=end_lineno, 

4721 end_col_offset=end_col_offset, 

4722 parent=parent, 

4723 ) 

4724 

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

4726 """Do some setup after initialisation. 

4727 

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

4729 

4730 :type: list(FormattedValue or Const) 

4731 """ 

4732 if values is not None: 

4733 self.values = values 

4734 

4735 def get_children(self): 

4736 yield from self.values 

4737 

4738 

4739class NamedExpr(_base_nodes.AssignTypeNode): 

4740 """Represents the assignment from the assignment expression 

4741 

4742 >>> import astroid 

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

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

4745 <NamedExpr l.1 at 0x7f23b2e4ed30> 

4746 """ 

4747 

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

4749 

4750 optional_assign = True 

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

4752 

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

4754 

4755 def __init__( 

4756 self, 

4757 lineno: int | None = None, 

4758 col_offset: int | None = None, 

4759 parent: NodeNG | None = None, 

4760 *, 

4761 end_lineno: int | None = None, 

4762 end_col_offset: int | None = None, 

4763 ) -> None: 

4764 """ 

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

4766 

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

4768 source code. 

4769 

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

4771 

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

4773 

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

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

4776 """ 

4777 self.target: NodeNG 

4778 """The assignment target 

4779 

4780 :type: Name 

4781 """ 

4782 

4783 self.value: NodeNG 

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

4785 

4786 super().__init__( 

4787 lineno=lineno, 

4788 col_offset=col_offset, 

4789 end_lineno=end_lineno, 

4790 end_col_offset=end_col_offset, 

4791 parent=parent, 

4792 ) 

4793 

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

4795 self.target = target 

4796 self.value = value 

4797 

4798 assigned_stmts = protocols.named_expr_assigned_stmts 

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

4800 See astroid/protocols.py for actual implementation. 

4801 """ 

4802 

4803 def frame( 

4804 self, *, future: Literal[None, True] = None 

4805 ) -> nodes.FunctionDef | nodes.Module | nodes.ClassDef | nodes.Lambda: 

4806 """The first parent frame node. 

4807 

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

4809 or :class:`ClassDef`. 

4810 

4811 :returns: The first parent frame node. 

4812 """ 

4813 if future is not None: 

4814 warnings.warn( 

4815 "The future arg will be removed in astroid 4.0.", 

4816 DeprecationWarning, 

4817 stacklevel=2, 

4818 ) 

4819 if not self.parent: 

4820 raise ParentMissingError(target=self) 

4821 

4822 # For certain parents NamedExpr evaluate to the scope of the parent 

4823 if isinstance(self.parent, (Arguments, Keyword, Comprehension)): 

4824 if not self.parent.parent: 

4825 raise ParentMissingError(target=self.parent) 

4826 if not self.parent.parent.parent: 

4827 raise ParentMissingError(target=self.parent.parent) 

4828 return self.parent.parent.parent.frame() 

4829 

4830 return self.parent.frame() 

4831 

4832 def scope(self) -> LocalsDictNodeNG: 

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

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

4835 

4836 :returns: The first parent scope node. 

4837 """ 

4838 if not self.parent: 

4839 raise ParentMissingError(target=self) 

4840 

4841 # For certain parents NamedExpr evaluate to the scope of the parent 

4842 if isinstance(self.parent, (Arguments, Keyword, Comprehension)): 

4843 if not self.parent.parent: 

4844 raise ParentMissingError(target=self.parent) 

4845 if not self.parent.parent.parent: 

4846 raise ParentMissingError(target=self.parent.parent) 

4847 return self.parent.parent.parent.scope() 

4848 

4849 return self.parent.scope() 

4850 

4851 def set_local(self, name: str, stmt: NodeNG) -> None: 

4852 """Define that the given name is declared in the given statement node. 

4853 NamedExpr's in Arguments, Keyword or Comprehension are evaluated in their 

4854 parent's parent scope. So we add to their frame's locals. 

4855 

4856 .. seealso:: :meth:`scope` 

4857 

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

4859 

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

4861 """ 

4862 self.frame().set_local(name, stmt) 

4863 

4864 

4865class Unknown(_base_nodes.AssignTypeNode): 

4866 """This node represents a node in a constructed AST where 

4867 introspection is not possible. At the moment, it's only used in 

4868 the args attribute of FunctionDef nodes where function signature 

4869 introspection failed. 

4870 """ 

4871 

4872 name = "Unknown" 

4873 

4874 def __init__( 

4875 self, 

4876 lineno: None = None, 

4877 col_offset: None = None, 

4878 parent: None = None, 

4879 *, 

4880 end_lineno: None = None, 

4881 end_col_offset: None = None, 

4882 ) -> None: 

4883 super().__init__( 

4884 lineno=lineno, 

4885 col_offset=col_offset, 

4886 end_lineno=end_lineno, 

4887 end_col_offset=end_col_offset, 

4888 parent=parent, 

4889 ) 

4890 

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

4892 return "Unknown" 

4893 

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

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

4896 yield util.Uninferable 

4897 

4898 

4899class EvaluatedObject(NodeNG): 

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

4901 

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

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

4904 """ 

4905 

4906 name = "EvaluatedObject" 

4907 _astroid_fields = ("original",) 

4908 _other_fields = ("value",) 

4909 

4910 def __init__( 

4911 self, original: SuccessfulInferenceResult, value: InferenceResult 

4912 ) -> None: 

4913 self.original: SuccessfulInferenceResult = original 

4914 """The original node that has already been evaluated""" 

4915 

4916 self.value: InferenceResult = value 

4917 """The inferred value""" 

4918 

4919 super().__init__( 

4920 lineno=self.original.lineno, 

4921 col_offset=self.original.col_offset, 

4922 parent=self.original.parent, 

4923 end_lineno=self.original.end_lineno, 

4924 end_col_offset=self.original.end_col_offset, 

4925 ) 

4926 

4927 def _infer( 

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

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

4930 yield self.value 

4931 

4932 

4933# Pattern matching ####################################################### 

4934 

4935 

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

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

4938 

4939 >>> import astroid 

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

4941 match x: 

4942 case 200: 

4943 ... 

4944 case _: 

4945 ... 

4946 ''') 

4947 >>> node 

4948 <Match l.2 at 0x10c24e170> 

4949 """ 

4950 

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

4952 _multi_line_block_fields = ("cases",) 

4953 

4954 def __init__( 

4955 self, 

4956 lineno: int | None = None, 

4957 col_offset: int | None = None, 

4958 parent: NodeNG | None = None, 

4959 *, 

4960 end_lineno: int | None = None, 

4961 end_col_offset: int | None = None, 

4962 ) -> None: 

4963 self.subject: NodeNG 

4964 self.cases: list[MatchCase] 

4965 super().__init__( 

4966 lineno=lineno, 

4967 col_offset=col_offset, 

4968 end_lineno=end_lineno, 

4969 end_col_offset=end_col_offset, 

4970 parent=parent, 

4971 ) 

4972 

4973 def postinit( 

4974 self, 

4975 *, 

4976 subject: NodeNG, 

4977 cases: list[MatchCase], 

4978 ) -> None: 

4979 self.subject = subject 

4980 self.cases = cases 

4981 

4982 

4983class Pattern(NodeNG): 

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

4985 

4986 

4987class MatchCase(_base_nodes.MultiLineBlockNode): 

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

4989 

4990 >>> import astroid 

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

4992 match x: 

4993 case 200: 

4994 ... 

4995 ''') 

4996 >>> node.cases[0] 

4997 <MatchCase l.3 at 0x10c24e590> 

4998 """ 

4999 

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

5001 _multi_line_block_fields = ("body",) 

5002 

5003 lineno: None 

5004 col_offset: None 

5005 end_lineno: None 

5006 end_col_offset: None 

5007 

5008 def __init__(self, *, parent: NodeNG | None = None) -> None: 

5009 self.pattern: Pattern 

5010 self.guard: NodeNG | None 

5011 self.body: list[NodeNG] 

5012 super().__init__( 

5013 parent=parent, 

5014 lineno=None, 

5015 col_offset=None, 

5016 end_lineno=None, 

5017 end_col_offset=None, 

5018 ) 

5019 

5020 def postinit( 

5021 self, 

5022 *, 

5023 pattern: Pattern, 

5024 guard: NodeNG | None, 

5025 body: list[NodeNG], 

5026 ) -> None: 

5027 self.pattern = pattern 

5028 self.guard = guard 

5029 self.body = body 

5030 

5031 

5032class MatchValue(Pattern): 

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

5034 

5035 >>> import astroid 

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

5037 match x: 

5038 case 200: 

5039 ... 

5040 ''') 

5041 >>> node.cases[0].pattern 

5042 <MatchValue l.3 at 0x10c24e200> 

5043 """ 

5044 

5045 _astroid_fields = ("value",) 

5046 

5047 def __init__( 

5048 self, 

5049 lineno: int | None = None, 

5050 col_offset: int | None = None, 

5051 parent: NodeNG | None = None, 

5052 *, 

5053 end_lineno: int | None = None, 

5054 end_col_offset: int | None = None, 

5055 ) -> None: 

5056 self.value: NodeNG 

5057 super().__init__( 

5058 lineno=lineno, 

5059 col_offset=col_offset, 

5060 end_lineno=end_lineno, 

5061 end_col_offset=end_col_offset, 

5062 parent=parent, 

5063 ) 

5064 

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

5066 self.value = value 

5067 

5068 

5069class MatchSingleton(Pattern): 

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

5071 

5072 >>> import astroid 

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

5074 match x: 

5075 case True: 

5076 ... 

5077 case False: 

5078 ... 

5079 case None: 

5080 ... 

5081 ''') 

5082 >>> node.cases[0].pattern 

5083 <MatchSingleton l.3 at 0x10c2282e0> 

5084 >>> node.cases[1].pattern 

5085 <MatchSingleton l.5 at 0x10c228af0> 

5086 >>> node.cases[2].pattern 

5087 <MatchSingleton l.7 at 0x10c229f90> 

5088 """ 

5089 

5090 _other_fields = ("value",) 

5091 

5092 def __init__( 

5093 self, 

5094 *, 

5095 value: Literal[True, False, None], 

5096 lineno: int | None = None, 

5097 col_offset: int | None = None, 

5098 end_lineno: int | None = None, 

5099 end_col_offset: int | None = None, 

5100 parent: NodeNG | None = None, 

5101 ) -> None: 

5102 self.value = value 

5103 super().__init__( 

5104 lineno=lineno, 

5105 col_offset=col_offset, 

5106 end_lineno=end_lineno, 

5107 end_col_offset=end_col_offset, 

5108 parent=parent, 

5109 ) 

5110 

5111 

5112class MatchSequence(Pattern): 

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

5114 

5115 >>> import astroid 

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

5117 match x: 

5118 case [1, 2]: 

5119 ... 

5120 case (1, 2, *_): 

5121 ... 

5122 ''') 

5123 >>> node.cases[0].pattern 

5124 <MatchSequence l.3 at 0x10ca80d00> 

5125 >>> node.cases[1].pattern 

5126 <MatchSequence l.5 at 0x10ca80b20> 

5127 """ 

5128 

5129 _astroid_fields = ("patterns",) 

5130 

5131 def __init__( 

5132 self, 

5133 lineno: int | None = None, 

5134 col_offset: int | None = None, 

5135 parent: NodeNG | None = None, 

5136 *, 

5137 end_lineno: int | None = None, 

5138 end_col_offset: int | None = None, 

5139 ) -> None: 

5140 self.patterns: list[Pattern] 

5141 super().__init__( 

5142 lineno=lineno, 

5143 col_offset=col_offset, 

5144 end_lineno=end_lineno, 

5145 end_col_offset=end_col_offset, 

5146 parent=parent, 

5147 ) 

5148 

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

5150 self.patterns = patterns 

5151 

5152 

5153class MatchMapping(_base_nodes.AssignTypeNode, Pattern): 

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

5155 

5156 >>> import astroid 

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

5158 match x: 

5159 case {1: "Hello", 2: "World", 3: _, **rest}: 

5160 ... 

5161 ''') 

5162 >>> node.cases[0].pattern 

5163 <MatchMapping l.3 at 0x10c8a8850> 

5164 """ 

5165 

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

5167 

5168 def __init__( 

5169 self, 

5170 lineno: int | None = None, 

5171 col_offset: int | None = None, 

5172 parent: NodeNG | None = None, 

5173 *, 

5174 end_lineno: int | None = None, 

5175 end_col_offset: int | None = None, 

5176 ) -> None: 

5177 self.keys: list[NodeNG] 

5178 self.patterns: list[Pattern] 

5179 self.rest: AssignName | None 

5180 super().__init__( 

5181 lineno=lineno, 

5182 col_offset=col_offset, 

5183 end_lineno=end_lineno, 

5184 end_col_offset=end_col_offset, 

5185 parent=parent, 

5186 ) 

5187 

5188 def postinit( 

5189 self, 

5190 *, 

5191 keys: list[NodeNG], 

5192 patterns: list[Pattern], 

5193 rest: AssignName | None, 

5194 ) -> None: 

5195 self.keys = keys 

5196 self.patterns = patterns 

5197 self.rest = rest 

5198 

5199 assigned_stmts = protocols.match_mapping_assigned_stmts 

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

5201 See astroid/protocols.py for actual implementation. 

5202 """ 

5203 

5204 

5205class MatchClass(Pattern): 

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

5207 

5208 >>> import astroid 

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

5210 match x: 

5211 case Point2D(0, 0): 

5212 ... 

5213 case Point3D(x=0, y=0, z=0): 

5214 ... 

5215 ''') 

5216 >>> node.cases[0].pattern 

5217 <MatchClass l.3 at 0x10ca83940> 

5218 >>> node.cases[1].pattern 

5219 <MatchClass l.5 at 0x10ca80880> 

5220 """ 

5221 

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

5223 _other_fields = ("kwd_attrs",) 

5224 

5225 def __init__( 

5226 self, 

5227 lineno: int | None = None, 

5228 col_offset: int | None = None, 

5229 parent: NodeNG | None = None, 

5230 *, 

5231 end_lineno: int | None = None, 

5232 end_col_offset: int | None = None, 

5233 ) -> None: 

5234 self.cls: NodeNG 

5235 self.patterns: list[Pattern] 

5236 self.kwd_attrs: list[str] 

5237 self.kwd_patterns: list[Pattern] 

5238 super().__init__( 

5239 lineno=lineno, 

5240 col_offset=col_offset, 

5241 end_lineno=end_lineno, 

5242 end_col_offset=end_col_offset, 

5243 parent=parent, 

5244 ) 

5245 

5246 def postinit( 

5247 self, 

5248 *, 

5249 cls: NodeNG, 

5250 patterns: list[Pattern], 

5251 kwd_attrs: list[str], 

5252 kwd_patterns: list[Pattern], 

5253 ) -> None: 

5254 self.cls = cls 

5255 self.patterns = patterns 

5256 self.kwd_attrs = kwd_attrs 

5257 self.kwd_patterns = kwd_patterns 

5258 

5259 

5260class MatchStar(_base_nodes.AssignTypeNode, Pattern): 

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

5262 

5263 >>> import astroid 

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

5265 match x: 

5266 case [1, *_]: 

5267 ... 

5268 ''') 

5269 >>> node.cases[0].pattern.patterns[1] 

5270 <MatchStar l.3 at 0x10ca809a0> 

5271 """ 

5272 

5273 _astroid_fields = ("name",) 

5274 

5275 def __init__( 

5276 self, 

5277 lineno: int | None = None, 

5278 col_offset: int | None = None, 

5279 parent: NodeNG | None = None, 

5280 *, 

5281 end_lineno: int | None = None, 

5282 end_col_offset: int | None = None, 

5283 ) -> None: 

5284 self.name: AssignName | None 

5285 super().__init__( 

5286 lineno=lineno, 

5287 col_offset=col_offset, 

5288 end_lineno=end_lineno, 

5289 end_col_offset=end_col_offset, 

5290 parent=parent, 

5291 ) 

5292 

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

5294 self.name = name 

5295 

5296 assigned_stmts = protocols.match_star_assigned_stmts 

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

5298 See astroid/protocols.py for actual implementation. 

5299 """ 

5300 

5301 

5302class MatchAs(_base_nodes.AssignTypeNode, Pattern): 

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

5304 

5305 >>> import astroid 

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

5307 match x: 

5308 case [1, a]: 

5309 ... 

5310 case {'key': b}: 

5311 ... 

5312 case Point2D(0, 0) as c: 

5313 ... 

5314 case d: 

5315 ... 

5316 ''') 

5317 >>> node.cases[0].pattern.patterns[1] 

5318 <MatchAs l.3 at 0x10d0b2da0> 

5319 >>> node.cases[1].pattern.patterns[0] 

5320 <MatchAs l.5 at 0x10d0b2920> 

5321 >>> node.cases[2].pattern 

5322 <MatchAs l.7 at 0x10d0b06a0> 

5323 >>> node.cases[3].pattern 

5324 <MatchAs l.9 at 0x10d09b880> 

5325 """ 

5326 

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

5328 

5329 def __init__( 

5330 self, 

5331 lineno: int | None = None, 

5332 col_offset: int | None = None, 

5333 parent: NodeNG | None = None, 

5334 *, 

5335 end_lineno: int | None = None, 

5336 end_col_offset: int | None = None, 

5337 ) -> None: 

5338 self.pattern: Pattern | None 

5339 self.name: AssignName | None 

5340 super().__init__( 

5341 lineno=lineno, 

5342 col_offset=col_offset, 

5343 end_lineno=end_lineno, 

5344 end_col_offset=end_col_offset, 

5345 parent=parent, 

5346 ) 

5347 

5348 def postinit( 

5349 self, 

5350 *, 

5351 pattern: Pattern | None, 

5352 name: AssignName | None, 

5353 ) -> None: 

5354 self.pattern = pattern 

5355 self.name = name 

5356 

5357 assigned_stmts = protocols.match_as_assigned_stmts 

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

5359 See astroid/protocols.py for actual implementation. 

5360 """ 

5361 

5362 

5363class MatchOr(Pattern): 

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

5365 

5366 >>> import astroid 

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

5368 match x: 

5369 case 400 | 401 | 402: 

5370 ... 

5371 ''') 

5372 >>> node.cases[0].pattern 

5373 <MatchOr l.3 at 0x10d0b0b50> 

5374 """ 

5375 

5376 _astroid_fields = ("patterns",) 

5377 

5378 def __init__( 

5379 self, 

5380 lineno: int | None = None, 

5381 col_offset: int | None = None, 

5382 parent: NodeNG | None = None, 

5383 *, 

5384 end_lineno: int | None = None, 

5385 end_col_offset: int | None = None, 

5386 ) -> None: 

5387 self.patterns: list[Pattern] 

5388 super().__init__( 

5389 lineno=lineno, 

5390 col_offset=col_offset, 

5391 end_lineno=end_lineno, 

5392 end_col_offset=end_col_offset, 

5393 parent=parent, 

5394 ) 

5395 

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

5397 self.patterns = patterns 

5398 

5399 

5400# constants ############################################################## 

5401 

5402# The _proxied attribute of all container types (List, Tuple, etc.) 

5403# are set during bootstrapping by _astroid_bootstrapping(). 

5404CONST_CLS: dict[type, type[NodeNG]] = { 

5405 list: List, 

5406 tuple: Tuple, 

5407 dict: Dict, 

5408 set: Set, 

5409 type(None): Const, 

5410 type(NotImplemented): Const, 

5411 type(...): Const, 

5412 bool: Const, 

5413 int: Const, 

5414 float: Const, 

5415 complex: Const, 

5416 str: Const, 

5417 bytes: Const, 

5418} 

5419 

5420 

5421def _create_basic_elements( 

5422 value: Iterable[Any], node: List | Set | Tuple 

5423) -> list[NodeNG]: 

5424 """Create a list of nodes to function as the elements of a new node.""" 

5425 elements: list[NodeNG] = [] 

5426 for element in value: 

5427 element_node = const_factory(element) 

5428 element_node.parent = node 

5429 elements.append(element_node) 

5430 return elements 

5431 

5432 

5433def _create_dict_items( 

5434 values: Mapping[Any, Any], node: Dict 

5435) -> list[tuple[SuccessfulInferenceResult, SuccessfulInferenceResult]]: 

5436 """Create a list of node pairs to function as the items of a new dict node.""" 

5437 elements: list[tuple[SuccessfulInferenceResult, SuccessfulInferenceResult]] = [] 

5438 for key, value in values.items(): 

5439 key_node = const_factory(key) 

5440 key_node.parent = node 

5441 value_node = const_factory(value) 

5442 value_node.parent = node 

5443 elements.append((key_node, value_node)) 

5444 return elements 

5445 

5446 

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

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

5449 assert not isinstance(value, NodeNG) 

5450 

5451 # This only handles instances of the CONST types. Any 

5452 # subclasses get inferred as EmptyNode. 

5453 # TODO: See if we should revisit these with the normal builder. 

5454 if value.__class__ not in CONST_CLS: 

5455 node = EmptyNode() 

5456 node.object = value 

5457 return node 

5458 

5459 instance: List | Set | Tuple | Dict 

5460 initializer_cls = CONST_CLS[value.__class__] 

5461 if issubclass(initializer_cls, (List, Set, Tuple)): 

5462 instance = initializer_cls( 

5463 lineno=None, 

5464 col_offset=None, 

5465 parent=None, 

5466 end_lineno=None, 

5467 end_col_offset=None, 

5468 ) 

5469 instance.postinit(_create_basic_elements(value, instance)) 

5470 return instance 

5471 if issubclass(initializer_cls, Dict): 

5472 instance = initializer_cls( 

5473 lineno=None, 

5474 col_offset=None, 

5475 parent=None, 

5476 end_lineno=None, 

5477 end_col_offset=None, 

5478 ) 

5479 instance.postinit(_create_dict_items(value, instance)) 

5480 return instance 

5481 return Const(value)