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

1230 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-07 06:53 +0000

1# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html 

2# For details: https://github.com/pylint-dev/astroid/blob/main/LICENSE 

3# Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt 

4 

5""" 

6This module contains the classes for "scoped" node, i.e. which are opening a 

7new local scope in the language definition : Module, ClassDef, FunctionDef (and 

8Lambda, GeneratorExp, DictComp and SetComp to some extent). 

9""" 

10 

11from __future__ import annotations 

12 

13import io 

14import itertools 

15import os 

16import warnings 

17from collections.abc import Generator, Iterable, Iterator, Sequence 

18from functools import cached_property, lru_cache 

19from typing import TYPE_CHECKING, ClassVar, Literal, NoReturn, TypeVar, overload 

20 

21from astroid import bases, util 

22from astroid.const import IS_PYPY, PY38, PY39_PLUS, PYPY_7_3_11_PLUS 

23from astroid.context import ( 

24 CallContext, 

25 InferenceContext, 

26 bind_context_to_node, 

27 copy_context, 

28) 

29from astroid.exceptions import ( 

30 AstroidBuildingError, 

31 AstroidTypeError, 

32 AttributeInferenceError, 

33 DuplicateBasesError, 

34 InconsistentMroError, 

35 InferenceError, 

36 MroError, 

37 StatementMissing, 

38 TooManyLevelsError, 

39) 

40from astroid.interpreter.dunder_lookup import lookup 

41from astroid.interpreter.objectmodel import ClassModel, FunctionModel, ModuleModel 

42from astroid.manager import AstroidManager 

43from astroid.nodes import Arguments, Const, NodeNG, Unknown, _base_nodes, node_classes 

44from astroid.nodes.scoped_nodes.mixin import ComprehensionScope, LocalsDictNodeNG 

45from astroid.nodes.scoped_nodes.utils import builtin_lookup 

46from astroid.nodes.utils import Position 

47from astroid.typing import InferBinaryOp, InferenceResult, SuccessfulInferenceResult 

48 

49if TYPE_CHECKING: 

50 from astroid import nodes 

51 

52 

53ITER_METHODS = ("__iter__", "__getitem__") 

54EXCEPTION_BASE_CLASSES = frozenset({"Exception", "BaseException"}) 

55BUILTIN_DESCRIPTORS = frozenset( 

56 {"classmethod", "staticmethod", "builtins.classmethod", "builtins.staticmethod"} 

57) 

58 

59_T = TypeVar("_T") 

60 

61 

62def _c3_merge(sequences, cls, context): 

63 """Merges MROs in *sequences* to a single MRO using the C3 algorithm. 

64 

65 Adapted from http://www.python.org/download/releases/2.3/mro/. 

66 

67 """ 

68 result = [] 

69 while True: 

70 sequences = [s for s in sequences if s] # purge empty sequences 

71 if not sequences: 

72 return result 

73 for s1 in sequences: # find merge candidates among seq heads 

74 candidate = s1[0] 

75 for s2 in sequences: 

76 if candidate in s2[1:]: 

77 candidate = None 

78 break # reject the current head, it appears later 

79 else: 

80 break 

81 if not candidate: 

82 # Show all the remaining bases, which were considered as 

83 # candidates for the next mro sequence. 

84 raise InconsistentMroError( 

85 message="Cannot create a consistent method resolution order " 

86 "for MROs {mros} of class {cls!r}.", 

87 mros=sequences, 

88 cls=cls, 

89 context=context, 

90 ) 

91 

92 result.append(candidate) 

93 # remove the chosen candidate 

94 for seq in sequences: 

95 if seq[0] == candidate: 

96 del seq[0] 

97 return None 

98 

99 

100def clean_typing_generic_mro(sequences: list[list[ClassDef]]) -> None: 

101 """A class can inherit from typing.Generic directly, as base, 

102 and as base of bases. The merged MRO must however only contain the last entry. 

103 To prepare for _c3_merge, remove some typing.Generic entries from 

104 sequences if multiple are present. 

105 

106 This method will check if Generic is in inferred_bases and also 

107 part of bases_mro. If true, remove it from inferred_bases 

108 as well as its entry the bases_mro. 

109 

110 Format sequences: [[self]] + bases_mro + [inferred_bases] 

111 """ 

112 bases_mro = sequences[1:-1] 

113 inferred_bases = sequences[-1] 

114 # Check if Generic is part of inferred_bases 

115 for i, base in enumerate(inferred_bases): 

116 if base.qname() == "typing.Generic": 

117 position_in_inferred_bases = i 

118 break 

119 else: 

120 return 

121 # Check if also part of bases_mro 

122 # Ignore entry for typing.Generic 

123 for i, seq in enumerate(bases_mro): 

124 if i == position_in_inferred_bases: 

125 continue 

126 if any(base.qname() == "typing.Generic" for base in seq): 

127 break 

128 else: 

129 return 

130 # Found multiple Generics in mro, remove entry from inferred_bases 

131 # and the corresponding one from bases_mro 

132 inferred_bases.pop(position_in_inferred_bases) 

133 bases_mro.pop(position_in_inferred_bases) 

134 

135 

136def clean_duplicates_mro( 

137 sequences: Iterable[Iterable[ClassDef]], 

138 cls: ClassDef, 

139 context: InferenceContext | None, 

140) -> Iterable[Iterable[ClassDef]]: 

141 for sequence in sequences: 

142 seen = set() 

143 for node in sequence: 

144 lineno_and_qname = (node.lineno, node.qname()) 

145 if lineno_and_qname in seen: 

146 raise DuplicateBasesError( 

147 message="Duplicates found in MROs {mros} for {cls!r}.", 

148 mros=sequences, 

149 cls=cls, 

150 context=context, 

151 ) 

152 seen.add(lineno_and_qname) 

153 return sequences 

154 

155 

156def function_to_method(n, klass): 

157 if isinstance(n, FunctionDef): 

158 if n.type == "classmethod": 

159 return bases.BoundMethod(n, klass) 

160 if n.type == "property": 

161 return n 

162 if n.type != "staticmethod": 

163 return bases.UnboundMethod(n) 

164 return n 

165 

166 

167class Module(LocalsDictNodeNG): 

168 """Class representing an :class:`ast.Module` node. 

169 

170 >>> import astroid 

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

172 >>> node 

173 <Import l.1 at 0x7f23b2e4e5c0> 

174 >>> node.parent 

175 <Module l.0 at 0x7f23b2e4eda0> 

176 """ 

177 

178 _astroid_fields = ("doc_node", "body") 

179 

180 doc_node: Const | None 

181 """The doc node associated with this node.""" 

182 

183 # attributes below are set by the builder module or by raw factories 

184 

185 file_bytes: str | bytes | None = None 

186 """The string/bytes that this ast was built from.""" 

187 

188 file_encoding: str | None = None 

189 """The encoding of the source file. 

190 

191 This is used to get unicode out of a source file. 

192 Python 2 only. 

193 """ 

194 

195 special_attributes = ModuleModel() 

196 """The names of special attributes that this module has.""" 

197 

198 # names of module attributes available through the global scope 

199 scope_attrs = {"__name__", "__doc__", "__file__", "__path__", "__package__"} 

200 """The names of module attributes available through the global scope.""" 

201 

202 _other_fields = ( 

203 "name", 

204 "file", 

205 "path", 

206 "package", 

207 "pure_python", 

208 "future_imports", 

209 ) 

210 _other_other_fields = ("locals", "globals") 

211 

212 def __init__( 

213 self, 

214 name: str, 

215 file: str | None = None, 

216 path: Sequence[str] | None = None, 

217 package: bool = False, 

218 pure_python: bool = True, 

219 ) -> None: 

220 self.name = name 

221 """The name of the module.""" 

222 

223 self.file = file 

224 """The path to the file that this ast has been extracted from. 

225 

226 This will be ``None`` when the representation has been built from a 

227 built-in module. 

228 """ 

229 

230 self.path = path 

231 

232 self.package = package 

233 """Whether the node represents a package or a module.""" 

234 

235 self.pure_python = pure_python 

236 """Whether the ast was built from source.""" 

237 

238 self.globals: dict[str, list[SuccessfulInferenceResult]] 

239 """A map of the name of a global variable to the node defining the global.""" 

240 

241 self.locals = self.globals = {} 

242 """A map of the name of a local variable to the node defining the local.""" 

243 

244 self.body: list[node_classes.NodeNG] = [] 

245 """The contents of the module.""" 

246 

247 self.future_imports: set[str] = set() 

248 """The imports from ``__future__``.""" 

249 

250 super().__init__( 

251 lineno=0, parent=None, col_offset=0, end_lineno=None, end_col_offset=None 

252 ) 

253 

254 # pylint: enable=redefined-builtin 

255 

256 def postinit( 

257 self, body: list[node_classes.NodeNG], *, doc_node: Const | None = None 

258 ): 

259 self.body = body 

260 self.doc_node = doc_node 

261 

262 def _get_stream(self): 

263 if self.file_bytes is not None: 

264 return io.BytesIO(self.file_bytes) 

265 if self.file is not None: 

266 # pylint: disable=consider-using-with 

267 stream = open(self.file, "rb") 

268 return stream 

269 return None 

270 

271 def stream(self): 

272 """Get a stream to the underlying file or bytes. 

273 

274 :type: file or io.BytesIO or None 

275 """ 

276 return self._get_stream() 

277 

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

279 """Get a range from where this node starts to where this node ends. 

280 

281 :param lineno: Unused. 

282 

283 :returns: The range of line numbers that this node belongs to. 

284 """ 

285 return self.fromlineno, self.tolineno 

286 

287 def scope_lookup( 

288 self, node: node_classes.LookupMixIn, name: str, offset: int = 0 

289 ) -> tuple[LocalsDictNodeNG, list[node_classes.NodeNG]]: 

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

291 

292 :param node: The node to look for assignments up to. 

293 Any assignments after the given node are ignored. 

294 

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

296 

297 :param offset: The line offset to filter statements up to. 

298 

299 :returns: This scope node and the list of assignments associated to the 

300 given name according to the scope where it has been found (locals, 

301 globals or builtin). 

302 """ 

303 if name in self.scope_attrs and name not in self.locals: 

304 try: 

305 return self, self.getattr(name) 

306 except AttributeInferenceError: 

307 return self, [] 

308 return self._scope_lookup(node, name, offset) 

309 

310 def pytype(self) -> Literal["builtins.module"]: 

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

312 

313 :returns: The name of the type. 

314 """ 

315 return "builtins.module" 

316 

317 def display_type(self) -> str: 

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

319 

320 :returns: The type of this node. 

321 :rtype: str 

322 """ 

323 return "Module" 

324 

325 def getattr( 

326 self, name, context: InferenceContext | None = None, ignore_locals=False 

327 ): 

328 if not name: 

329 raise AttributeInferenceError(target=self, attribute=name, context=context) 

330 

331 result = [] 

332 name_in_locals = name in self.locals 

333 

334 if name in self.special_attributes and not ignore_locals and not name_in_locals: 

335 result = [self.special_attributes.lookup(name)] 

336 elif not ignore_locals and name_in_locals: 

337 result = self.locals[name] 

338 elif self.package: 

339 try: 

340 result = [self.import_module(name, relative_only=True)] 

341 except (AstroidBuildingError, SyntaxError) as exc: 

342 raise AttributeInferenceError( 

343 target=self, attribute=name, context=context 

344 ) from exc 

345 result = [n for n in result if not isinstance(n, node_classes.DelName)] 

346 if result: 

347 return result 

348 raise AttributeInferenceError(target=self, attribute=name, context=context) 

349 

350 def igetattr( 

351 self, name: str, context: InferenceContext | None = None 

352 ) -> Iterator[InferenceResult]: 

353 """Infer the possible values of the given variable. 

354 

355 :param name: The name of the variable to infer. 

356 

357 :returns: The inferred possible values. 

358 """ 

359 # set lookup name since this is necessary to infer on import nodes for 

360 # instance 

361 context = copy_context(context) 

362 context.lookupname = name 

363 try: 

364 return bases._infer_stmts(self.getattr(name, context), context, frame=self) 

365 except AttributeInferenceError as error: 

366 raise InferenceError( 

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

368 ) from error 

369 

370 def fully_defined(self) -> bool: 

371 """Check if this module has been build from a .py file. 

372 

373 If so, the module contains a complete representation, 

374 including the code. 

375 

376 :returns: Whether the module has been built from a .py file. 

377 """ 

378 return self.file is not None and self.file.endswith(".py") 

379 

380 @overload 

381 def statement(self, *, future: None = ...) -> Module: 

382 ... 

383 

384 @overload 

385 def statement(self, *, future: Literal[True]) -> NoReturn: 

386 ... 

387 

388 def statement(self, *, future: Literal[None, True] = None) -> Module | NoReturn: 

389 """The first parent node, including self, marked as statement node. 

390 

391 When called on a :class:`Module` with the future parameter this raises an error. 

392 

393 TODO: Deprecate the future parameter and only raise StatementMissing 

394 

395 :raises StatementMissing: If no self has no parent attribute and future is True 

396 """ 

397 if future: 

398 raise StatementMissing(target=self) 

399 warnings.warn( 

400 "In astroid 3.0.0 NodeNG.statement() will return either a nodes.Statement " 

401 "or raise a StatementMissing exception. nodes.Module will no longer be " 

402 "considered a statement. This behaviour can already be triggered " 

403 "by passing 'future=True' to a statement() call.", 

404 DeprecationWarning, 

405 stacklevel=2, 

406 ) 

407 return self 

408 

409 def previous_sibling(self): 

410 """The previous sibling statement. 

411 

412 :returns: The previous sibling statement node. 

413 :rtype: NodeNG or None 

414 """ 

415 

416 def next_sibling(self): 

417 """The next sibling statement node. 

418 

419 :returns: The next sibling statement node. 

420 :rtype: NodeNG or None 

421 """ 

422 

423 _absolute_import_activated = True 

424 

425 def absolute_import_activated(self) -> bool: 

426 """Whether :pep:`328` absolute import behaviour has been enabled. 

427 

428 :returns: Whether :pep:`328` has been enabled. 

429 """ 

430 return self._absolute_import_activated 

431 

432 def import_module( 

433 self, 

434 modname: str, 

435 relative_only: bool = False, 

436 level: int | None = None, 

437 use_cache: bool = True, 

438 ) -> Module: 

439 """Get the ast for a given module as if imported from this module. 

440 

441 :param modname: The name of the module to "import". 

442 

443 :param relative_only: Whether to only consider relative imports. 

444 

445 :param level: The level of relative import. 

446 

447 :param use_cache: Whether to use the astroid_cache of modules. 

448 

449 :returns: The imported module ast. 

450 """ 

451 if relative_only and level is None: 

452 level = 0 

453 absmodname = self.relative_to_absolute_name(modname, level) 

454 

455 try: 

456 return AstroidManager().ast_from_module_name( 

457 absmodname, use_cache=use_cache 

458 ) 

459 except AstroidBuildingError: 

460 # we only want to import a sub module or package of this module, 

461 # skip here 

462 if relative_only: 

463 raise 

464 return AstroidManager().ast_from_module_name(modname) 

465 

466 def relative_to_absolute_name(self, modname: str, level: int | None) -> str: 

467 """Get the absolute module name for a relative import. 

468 

469 The relative import can be implicit or explicit. 

470 

471 :param modname: The module name to convert. 

472 

473 :param level: The level of relative import. 

474 

475 :returns: The absolute module name. 

476 

477 :raises TooManyLevelsError: When the relative import refers to a 

478 module too far above this one. 

479 """ 

480 # XXX this returns non sens when called on an absolute import 

481 # like 'pylint.checkers.astroid.utils' 

482 # XXX doesn't return absolute name if self.name isn't absolute name 

483 if self.absolute_import_activated() and level is None: 

484 return modname 

485 if level: 

486 if self.package: 

487 level = level - 1 

488 package_name = self.name.rsplit(".", level)[0] 

489 elif ( 

490 self.path 

491 and not os.path.exists(os.path.dirname(self.path[0]) + "/__init__.py") 

492 and os.path.exists( 

493 os.path.dirname(self.path[0]) + "/" + modname.split(".")[0] 

494 ) 

495 ): 

496 level = level - 1 

497 package_name = "" 

498 else: 

499 package_name = self.name.rsplit(".", level)[0] 

500 if level and self.name.count(".") < level: 

501 raise TooManyLevelsError(level=level, name=self.name) 

502 

503 elif self.package: 

504 package_name = self.name 

505 else: 

506 package_name = self.name.rsplit(".", 1)[0] 

507 

508 if package_name: 

509 if not modname: 

510 return package_name 

511 return f"{package_name}.{modname}" 

512 return modname 

513 

514 def wildcard_import_names(self): 

515 """The list of imported names when this module is 'wildcard imported'. 

516 

517 It doesn't include the '__builtins__' name which is added by the 

518 current CPython implementation of wildcard imports. 

519 

520 :returns: The list of imported names. 

521 :rtype: list(str) 

522 """ 

523 # We separate the different steps of lookup in try/excepts 

524 # to avoid catching too many Exceptions 

525 default = [name for name in self.keys() if not name.startswith("_")] 

526 try: 

527 all_values = self["__all__"] 

528 except KeyError: 

529 return default 

530 

531 try: 

532 explicit = next(all_values.assigned_stmts()) 

533 except (InferenceError, StopIteration): 

534 return default 

535 except AttributeError: 

536 # not an assignment node 

537 # XXX infer? 

538 return default 

539 

540 # Try our best to detect the exported name. 

541 inferred = [] 

542 try: 

543 explicit = next(explicit.infer()) 

544 except (InferenceError, StopIteration): 

545 return default 

546 if not isinstance(explicit, (node_classes.Tuple, node_classes.List)): 

547 return default 

548 

549 def str_const(node) -> bool: 

550 return isinstance(node, node_classes.Const) and isinstance(node.value, str) 

551 

552 for node in explicit.elts: 

553 if str_const(node): 

554 inferred.append(node.value) 

555 else: 

556 try: 

557 inferred_node = next(node.infer()) 

558 except (InferenceError, StopIteration): 

559 continue 

560 if str_const(inferred_node): 

561 inferred.append(inferred_node.value) 

562 return inferred 

563 

564 def public_names(self): 

565 """The list of the names that are publicly available in this module. 

566 

567 :returns: The list of public names. 

568 :rtype: list(str) 

569 """ 

570 return [name for name in self.keys() if not name.startswith("_")] 

571 

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

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

574 

575 :returns: The boolean value of this node. 

576 For a :class:`Module` this is always ``True``. 

577 """ 

578 return True 

579 

580 def get_children(self): 

581 yield from self.body 

582 

583 def frame(self: _T, *, future: Literal[None, True] = None) -> _T: 

584 """The node's frame node. 

585 

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

587 :class:`ClassDef` or :class:`Lambda`. 

588 

589 :returns: The node itself. 

590 """ 

591 return self 

592 

593 

594class GeneratorExp(ComprehensionScope): 

595 """Class representing an :class:`ast.GeneratorExp` node. 

596 

597 >>> import astroid 

598 >>> node = astroid.extract_node('(thing for thing in things if thing)') 

599 >>> node 

600 <GeneratorExp l.1 at 0x7f23b2e4e400> 

601 """ 

602 

603 _astroid_fields = ("elt", "generators") 

604 _other_other_fields = ("locals",) 

605 elt: NodeNG 

606 """The element that forms the output of the expression.""" 

607 

608 def __init__( 

609 self, 

610 lineno: int, 

611 col_offset: int, 

612 parent: NodeNG, 

613 *, 

614 end_lineno: int | None, 

615 end_col_offset: int | None, 

616 ) -> None: 

617 self.locals = {} 

618 """A map of the name of a local variable to the node defining the local.""" 

619 

620 self.generators: list[nodes.Comprehension] = [] 

621 """The generators that are looped through.""" 

622 

623 super().__init__( 

624 lineno=lineno, 

625 col_offset=col_offset, 

626 end_lineno=end_lineno, 

627 end_col_offset=end_col_offset, 

628 parent=parent, 

629 ) 

630 

631 def postinit(self, elt: NodeNG, generators: list[nodes.Comprehension]) -> None: 

632 self.elt = elt 

633 self.generators = generators 

634 

635 def bool_value(self, context: InferenceContext | None = None) -> Literal[True]: 

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

637 

638 :returns: The boolean value of this node. 

639 For a :class:`GeneratorExp` this is always ``True``. 

640 """ 

641 return True 

642 

643 def get_children(self): 

644 yield self.elt 

645 

646 yield from self.generators 

647 

648 

649class DictComp(ComprehensionScope): 

650 """Class representing an :class:`ast.DictComp` node. 

651 

652 >>> import astroid 

653 >>> node = astroid.extract_node('{k:v for k, v in things if k > v}') 

654 >>> node 

655 <DictComp l.1 at 0x7f23b2e41d68> 

656 """ 

657 

658 _astroid_fields = ("key", "value", "generators") 

659 _other_other_fields = ("locals",) 

660 key: NodeNG 

661 """What produces the keys.""" 

662 

663 value: NodeNG 

664 """What produces the values.""" 

665 

666 def __init__( 

667 self, 

668 lineno: int, 

669 col_offset: int, 

670 parent: NodeNG, 

671 *, 

672 end_lineno: int | None, 

673 end_col_offset: int | None, 

674 ) -> None: 

675 self.locals = {} 

676 """A map of the name of a local variable to the node defining the local.""" 

677 

678 super().__init__( 

679 lineno=lineno, 

680 col_offset=col_offset, 

681 end_lineno=end_lineno, 

682 end_col_offset=end_col_offset, 

683 parent=parent, 

684 ) 

685 

686 def postinit( 

687 self, key: NodeNG, value: NodeNG, generators: list[nodes.Comprehension] 

688 ) -> None: 

689 self.key = key 

690 self.value = value 

691 self.generators = generators 

692 

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

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

695 

696 :returns: The boolean value of this node. 

697 For a :class:`DictComp` this is always :class:`Uninferable`. 

698 :rtype: Uninferable 

699 """ 

700 return util.Uninferable 

701 

702 def get_children(self): 

703 yield self.key 

704 yield self.value 

705 

706 yield from self.generators 

707 

708 

709class SetComp(ComprehensionScope): 

710 """Class representing an :class:`ast.SetComp` node. 

711 

712 >>> import astroid 

713 >>> node = astroid.extract_node('{thing for thing in things if thing}') 

714 >>> node 

715 <SetComp l.1 at 0x7f23b2e41898> 

716 """ 

717 

718 _astroid_fields = ("elt", "generators") 

719 _other_other_fields = ("locals",) 

720 elt: NodeNG 

721 """The element that forms the output of the expression.""" 

722 

723 def __init__( 

724 self, 

725 lineno: int, 

726 col_offset: int, 

727 parent: NodeNG, 

728 *, 

729 end_lineno: int | None, 

730 end_col_offset: int | None, 

731 ) -> None: 

732 self.locals = {} 

733 """A map of the name of a local variable to the node defining the local.""" 

734 

735 self.generators: list[nodes.Comprehension] = [] 

736 """The generators that are looped through.""" 

737 

738 super().__init__( 

739 lineno=lineno, 

740 col_offset=col_offset, 

741 end_lineno=end_lineno, 

742 end_col_offset=end_col_offset, 

743 parent=parent, 

744 ) 

745 

746 def postinit(self, elt: NodeNG, generators: list[nodes.Comprehension]) -> None: 

747 self.elt = elt 

748 self.generators = generators 

749 

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

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

752 

753 :returns: The boolean value of this node. 

754 For a :class:`SetComp` this is always :class:`Uninferable`. 

755 :rtype: Uninferable 

756 """ 

757 return util.Uninferable 

758 

759 def get_children(self): 

760 yield self.elt 

761 

762 yield from self.generators 

763 

764 

765class ListComp(ComprehensionScope): 

766 """Class representing an :class:`ast.ListComp` node. 

767 

768 >>> import astroid 

769 >>> node = astroid.extract_node('[thing for thing in things if thing]') 

770 >>> node 

771 <ListComp l.1 at 0x7f23b2e418d0> 

772 """ 

773 

774 _astroid_fields = ("elt", "generators") 

775 _other_other_fields = ("locals",) 

776 

777 elt: NodeNG 

778 """The element that forms the output of the expression.""" 

779 

780 def __init__( 

781 self, 

782 lineno: int, 

783 col_offset: int, 

784 parent: NodeNG, 

785 *, 

786 end_lineno: int | None, 

787 end_col_offset: int | None, 

788 ) -> None: 

789 self.locals = {} 

790 """A map of the name of a local variable to the node defining it.""" 

791 

792 self.generators: list[nodes.Comprehension] = [] 

793 """The generators that are looped through.""" 

794 

795 super().__init__( 

796 lineno=lineno, 

797 col_offset=col_offset, 

798 end_lineno=end_lineno, 

799 end_col_offset=end_col_offset, 

800 parent=parent, 

801 ) 

802 

803 def postinit(self, elt: NodeNG, generators: list[nodes.Comprehension]): 

804 self.elt = elt 

805 self.generators = generators 

806 

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

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

809 

810 :returns: The boolean value of this node. 

811 For a :class:`ListComp` this is always :class:`Uninferable`. 

812 :rtype: Uninferable 

813 """ 

814 return util.Uninferable 

815 

816 def get_children(self): 

817 yield self.elt 

818 

819 yield from self.generators 

820 

821 

822def _infer_decorator_callchain(node): 

823 """Detect decorator call chaining and see if the end result is a 

824 static or a classmethod. 

825 """ 

826 if not isinstance(node, FunctionDef): 

827 return None 

828 if not node.parent: 

829 return None 

830 try: 

831 result = next(node.infer_call_result(node.parent), None) 

832 except InferenceError: 

833 return None 

834 if isinstance(result, bases.Instance): 

835 result = result._proxied 

836 if isinstance(result, ClassDef): 

837 if result.is_subtype_of("builtins.classmethod"): 

838 return "classmethod" 

839 if result.is_subtype_of("builtins.staticmethod"): 

840 return "staticmethod" 

841 if isinstance(result, FunctionDef): 

842 if not result.decorators: 

843 return None 

844 # Determine if this function is decorated with one of the builtin descriptors we want. 

845 for decorator in result.decorators.nodes: 

846 if isinstance(decorator, node_classes.Name): 

847 if decorator.name in BUILTIN_DESCRIPTORS: 

848 return decorator.name 

849 if ( 

850 isinstance(decorator, node_classes.Attribute) 

851 and isinstance(decorator.expr, node_classes.Name) 

852 and decorator.expr.name == "builtins" 

853 and decorator.attrname in BUILTIN_DESCRIPTORS 

854 ): 

855 return decorator.attrname 

856 return None 

857 

858 

859class Lambda(_base_nodes.FilterStmtsBaseNode, LocalsDictNodeNG): 

860 """Class representing an :class:`ast.Lambda` node. 

861 

862 >>> import astroid 

863 >>> node = astroid.extract_node('lambda arg: arg + 1') 

864 >>> node 

865 <Lambda.<lambda> l.1 at 0x7f23b2e41518> 

866 """ 

867 

868 _astroid_fields: ClassVar[tuple[str, ...]] = ("args", "body") 

869 _other_other_fields: ClassVar[tuple[str, ...]] = ("locals",) 

870 name = "<lambda>" 

871 is_lambda = True 

872 special_attributes = FunctionModel() 

873 """The names of special attributes that this function has.""" 

874 

875 args: Arguments 

876 """The arguments that the function takes.""" 

877 

878 body: NodeNG 

879 """The contents of the function body.""" 

880 

881 def implicit_parameters(self) -> Literal[0]: 

882 return 0 

883 

884 @property 

885 def type(self) -> Literal["method", "function"]: 

886 """Whether this is a method or function. 

887 

888 :returns: 'method' if this is a method, 'function' otherwise. 

889 """ 

890 if self.args.arguments and self.args.arguments[0].name == "self": 

891 if isinstance(self.parent.scope(), ClassDef): 

892 return "method" 

893 return "function" 

894 

895 def __init__( 

896 self, 

897 lineno: int, 

898 col_offset: int, 

899 parent: NodeNG, 

900 *, 

901 end_lineno: int | None, 

902 end_col_offset: int | None, 

903 ): 

904 self.locals = {} 

905 """A map of the name of a local variable to the node defining it.""" 

906 

907 self.instance_attrs: dict[str, list[NodeNG]] = {} 

908 

909 super().__init__( 

910 lineno=lineno, 

911 col_offset=col_offset, 

912 end_lineno=end_lineno, 

913 end_col_offset=end_col_offset, 

914 parent=parent, 

915 ) 

916 

917 def postinit(self, args: Arguments, body: NodeNG) -> None: 

918 self.args = args 

919 self.body = body 

920 

921 def pytype(self) -> Literal["builtins.instancemethod", "builtins.function"]: 

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

923 

924 :returns: The name of the type. 

925 """ 

926 if "method" in self.type: 

927 return "builtins.instancemethod" 

928 return "builtins.function" 

929 

930 def display_type(self) -> str: 

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

932 

933 :returns: The type of this node. 

934 :rtype: str 

935 """ 

936 if "method" in self.type: 

937 return "Method" 

938 return "Function" 

939 

940 def callable(self) -> Literal[True]: 

941 """Whether this node defines something that is callable. 

942 

943 :returns: Whether this defines something that is callable 

944 For a :class:`Lambda` this is always ``True``. 

945 """ 

946 return True 

947 

948 def argnames(self) -> list[str]: 

949 """Get the names of each of the arguments, including that 

950 of the collections of variable-length arguments ("args", "kwargs", 

951 etc.), as well as positional-only and keyword-only arguments. 

952 

953 :returns: The names of the arguments. 

954 :rtype: list(str) 

955 """ 

956 if self.args.arguments: # maybe None with builtin functions 

957 names = _rec_get_names(self.args.arguments) 

958 else: 

959 names = [] 

960 if self.args.vararg: 

961 names.append(self.args.vararg) 

962 names += [elt.name for elt in self.args.kwonlyargs] 

963 if self.args.kwarg: 

964 names.append(self.args.kwarg) 

965 return names 

966 

967 def infer_call_result( 

968 self, 

969 caller: SuccessfulInferenceResult | None, 

970 context: InferenceContext | None = None, 

971 ) -> Iterator[InferenceResult]: 

972 """Infer what the function returns when called.""" 

973 return self.body.infer(context) 

974 

975 def scope_lookup( 

976 self, node: node_classes.LookupMixIn, name: str, offset: int = 0 

977 ) -> tuple[LocalsDictNodeNG, list[NodeNG]]: 

978 """Lookup where the given names is assigned. 

979 

980 :param node: The node to look for assignments up to. 

981 Any assignments after the given node are ignored. 

982 

983 :param name: The name to find assignments for. 

984 

985 :param offset: The line offset to filter statements up to. 

986 

987 :returns: This scope node and the list of assignments associated to the 

988 given name according to the scope where it has been found (locals, 

989 globals or builtin). 

990 """ 

991 if (self.args.defaults and node in self.args.defaults) or ( 

992 self.args.kw_defaults and node in self.args.kw_defaults 

993 ): 

994 frame = self.parent.frame(future=True) 

995 # line offset to avoid that def func(f=func) resolve the default 

996 # value to the defined function 

997 offset = -1 

998 else: 

999 # check this is not used in function decorators 

1000 frame = self 

1001 return frame._scope_lookup(node, name, offset) 

1002 

1003 def bool_value(self, context: InferenceContext | None = None) -> Literal[True]: 

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

1005 

1006 :returns: The boolean value of this node. 

1007 For a :class:`Lambda` this is always ``True``. 

1008 """ 

1009 return True 

1010 

1011 def get_children(self): 

1012 yield self.args 

1013 yield self.body 

1014 

1015 def frame(self: _T, *, future: Literal[None, True] = None) -> _T: 

1016 """The node's frame node. 

1017 

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

1019 :class:`ClassDef` or :class:`Lambda`. 

1020 

1021 :returns: The node itself. 

1022 """ 

1023 return self 

1024 

1025 def getattr( 

1026 self, name: str, context: InferenceContext | None = None 

1027 ) -> list[NodeNG]: 

1028 if not name: 

1029 raise AttributeInferenceError(target=self, attribute=name, context=context) 

1030 

1031 found_attrs = [] 

1032 if name in self.instance_attrs: 

1033 found_attrs = self.instance_attrs[name] 

1034 if name in self.special_attributes: 

1035 found_attrs.append(self.special_attributes.lookup(name)) 

1036 if found_attrs: 

1037 return found_attrs 

1038 raise AttributeInferenceError(target=self, attribute=name) 

1039 

1040 

1041class FunctionDef( 

1042 _base_nodes.MultiLineBlockNode, 

1043 _base_nodes.FilterStmtsBaseNode, 

1044 _base_nodes.Statement, 

1045 LocalsDictNodeNG, 

1046): 

1047 """Class representing an :class:`ast.FunctionDef`. 

1048 

1049 >>> import astroid 

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

1051 ... def my_func(arg): 

1052 ... return arg + 1 

1053 ... ''') 

1054 >>> node 

1055 <FunctionDef.my_func l.2 at 0x7f23b2e71e10> 

1056 """ 

1057 

1058 _astroid_fields = ("decorators", "args", "returns", "doc_node", "body") 

1059 _multi_line_block_fields = ("body",) 

1060 returns = None 

1061 

1062 decorators: node_classes.Decorators | None 

1063 """The decorators that are applied to this method or function.""" 

1064 

1065 doc_node: Const | None 

1066 """The doc node associated with this node.""" 

1067 

1068 args: Arguments 

1069 """The arguments that the function takes.""" 

1070 

1071 is_function = True 

1072 """Whether this node indicates a function. 

1073 

1074 For a :class:`FunctionDef` this is always ``True``. 

1075 

1076 :type: bool 

1077 """ 

1078 type_annotation = None 

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

1080 

1081 :type: NodeNG or None 

1082 """ 

1083 type_comment_args = None 

1084 """ 

1085 If present, this will contain the type annotation for arguments 

1086 passed by a type comment 

1087 """ 

1088 type_comment_returns = None 

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

1090 # attributes below are set by the builder module or by raw factories 

1091 _other_fields = ("name", "position") 

1092 _other_other_fields = ( 

1093 "locals", 

1094 "_type", 

1095 "type_comment_returns", 

1096 "type_comment_args", 

1097 ) 

1098 _type = None 

1099 

1100 name = "<functiondef>" 

1101 

1102 is_lambda = True 

1103 

1104 special_attributes = FunctionModel() 

1105 """The names of special attributes that this function has.""" 

1106 

1107 def __init__( 

1108 self, 

1109 name: str, 

1110 lineno: int, 

1111 col_offset: int, 

1112 parent: NodeNG, 

1113 *, 

1114 end_lineno: int | None, 

1115 end_col_offset: int | None, 

1116 ) -> None: 

1117 self.name = name 

1118 """The name of the function.""" 

1119 

1120 self.locals = {} 

1121 """A map of the name of a local variable to the node defining it.""" 

1122 

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

1124 """The contents of the function body.""" 

1125 

1126 self.instance_attrs: dict[str, list[NodeNG]] = {} 

1127 

1128 super().__init__( 

1129 lineno=lineno, 

1130 col_offset=col_offset, 

1131 end_lineno=end_lineno, 

1132 end_col_offset=end_col_offset, 

1133 parent=parent, 

1134 ) 

1135 if parent and not isinstance(parent, Unknown): 

1136 frame = parent.frame(future=True) 

1137 frame.set_local(name, self) 

1138 

1139 def postinit( 

1140 self, 

1141 args: Arguments, 

1142 body: list[NodeNG], 

1143 decorators: node_classes.Decorators | None = None, 

1144 returns=None, 

1145 type_comment_returns=None, 

1146 type_comment_args=None, 

1147 *, 

1148 position: Position | None = None, 

1149 doc_node: Const | None = None, 

1150 ): 

1151 """Do some setup after initialisation. 

1152 

1153 :param args: The arguments that the function takes. 

1154 

1155 :param body: The contents of the function body. 

1156 

1157 :param decorators: The decorators that are applied to this 

1158 method or function. 

1159 :params type_comment_returns: 

1160 The return type annotation passed via a type comment. 

1161 :params type_comment_args: 

1162 The args type annotation passed via a type comment. 

1163 :params position: 

1164 Position of function keyword(s) and name. 

1165 :param doc_node: 

1166 The doc node associated with this node. 

1167 """ 

1168 self.args = args 

1169 self.body = body 

1170 self.decorators = decorators 

1171 self.returns = returns 

1172 self.type_comment_returns = type_comment_returns 

1173 self.type_comment_args = type_comment_args 

1174 self.position = position 

1175 self.doc_node = doc_node 

1176 

1177 @cached_property 

1178 def extra_decorators(self) -> list[node_classes.Call]: 

1179 """The extra decorators that this function can have. 

1180 

1181 Additional decorators are considered when they are used as 

1182 assignments, as in ``method = staticmethod(method)``. 

1183 The property will return all the callables that are used for 

1184 decoration. 

1185 """ 

1186 frame = self.parent.frame(future=True) 

1187 if not isinstance(frame, ClassDef): 

1188 return [] 

1189 

1190 decorators: list[node_classes.Call] = [] 

1191 for assign in frame._assign_nodes_in_scope: 

1192 if isinstance(assign.value, node_classes.Call) and isinstance( 

1193 assign.value.func, node_classes.Name 

1194 ): 

1195 for assign_node in assign.targets: 

1196 if not isinstance(assign_node, node_classes.AssignName): 

1197 # Support only `name = callable(name)` 

1198 continue 

1199 

1200 if assign_node.name != self.name: 

1201 # Interested only in the assignment nodes that 

1202 # decorates the current method. 

1203 continue 

1204 try: 

1205 meth = frame[self.name] 

1206 except KeyError: 

1207 continue 

1208 else: 

1209 # Must be a function and in the same frame as the 

1210 # original method. 

1211 if ( 

1212 isinstance(meth, FunctionDef) 

1213 and assign_node.frame(future=True) == frame 

1214 ): 

1215 decorators.append(assign.value) 

1216 return decorators 

1217 

1218 def pytype(self) -> Literal["builtins.instancemethod", "builtins.function"]: 

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

1220 

1221 :returns: The name of the type. 

1222 """ 

1223 if "method" in self.type: 

1224 return "builtins.instancemethod" 

1225 return "builtins.function" 

1226 

1227 def display_type(self) -> str: 

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

1229 

1230 :returns: The type of this node. 

1231 :rtype: str 

1232 """ 

1233 if "method" in self.type: 

1234 return "Method" 

1235 return "Function" 

1236 

1237 def callable(self) -> Literal[True]: 

1238 return True 

1239 

1240 def argnames(self) -> list[str]: 

1241 """Get the names of each of the arguments, including that 

1242 of the collections of variable-length arguments ("args", "kwargs", 

1243 etc.), as well as positional-only and keyword-only arguments. 

1244 

1245 :returns: The names of the arguments. 

1246 :rtype: list(str) 

1247 """ 

1248 if self.args.arguments: # maybe None with builtin functions 

1249 names = _rec_get_names(self.args.arguments) 

1250 else: 

1251 names = [] 

1252 if self.args.vararg: 

1253 names.append(self.args.vararg) 

1254 names += [elt.name for elt in self.args.kwonlyargs] 

1255 if self.args.kwarg: 

1256 names.append(self.args.kwarg) 

1257 return names 

1258 

1259 def getattr( 

1260 self, name: str, context: InferenceContext | None = None 

1261 ) -> list[NodeNG]: 

1262 if not name: 

1263 raise AttributeInferenceError(target=self, attribute=name, context=context) 

1264 

1265 found_attrs = [] 

1266 if name in self.instance_attrs: 

1267 found_attrs = self.instance_attrs[name] 

1268 if name in self.special_attributes: 

1269 found_attrs.append(self.special_attributes.lookup(name)) 

1270 if found_attrs: 

1271 return found_attrs 

1272 raise AttributeInferenceError(target=self, attribute=name) 

1273 

1274 @cached_property 

1275 def type(self) -> str: # pylint: disable=too-many-return-statements # noqa: C901 

1276 """The function type for this node. 

1277 

1278 Possible values are: method, function, staticmethod, classmethod. 

1279 """ 

1280 for decorator in self.extra_decorators: 

1281 if decorator.func.name in BUILTIN_DESCRIPTORS: 

1282 return decorator.func.name 

1283 

1284 frame = self.parent.frame(future=True) 

1285 type_name = "function" 

1286 if isinstance(frame, ClassDef): 

1287 if self.name == "__new__": 

1288 return "classmethod" 

1289 if self.name == "__init_subclass__": 

1290 return "classmethod" 

1291 if self.name == "__class_getitem__": 

1292 return "classmethod" 

1293 

1294 type_name = "method" 

1295 

1296 if not self.decorators: 

1297 return type_name 

1298 

1299 for node in self.decorators.nodes: 

1300 if isinstance(node, node_classes.Name): 

1301 if node.name in BUILTIN_DESCRIPTORS: 

1302 return node.name 

1303 if ( 

1304 isinstance(node, node_classes.Attribute) 

1305 and isinstance(node.expr, node_classes.Name) 

1306 and node.expr.name == "builtins" 

1307 and node.attrname in BUILTIN_DESCRIPTORS 

1308 ): 

1309 return node.attrname 

1310 

1311 if isinstance(node, node_classes.Call): 

1312 # Handle the following case: 

1313 # @some_decorator(arg1, arg2) 

1314 # def func(...) 

1315 # 

1316 try: 

1317 current = next(node.func.infer()) 

1318 except (InferenceError, StopIteration): 

1319 continue 

1320 _type = _infer_decorator_callchain(current) 

1321 if _type is not None: 

1322 return _type 

1323 

1324 try: 

1325 for inferred in node.infer(): 

1326 # Check to see if this returns a static or a class method. 

1327 _type = _infer_decorator_callchain(inferred) 

1328 if _type is not None: 

1329 return _type 

1330 

1331 if not isinstance(inferred, ClassDef): 

1332 continue 

1333 for ancestor in inferred.ancestors(): 

1334 if not isinstance(ancestor, ClassDef): 

1335 continue 

1336 if ancestor.is_subtype_of("builtins.classmethod"): 

1337 return "classmethod" 

1338 if ancestor.is_subtype_of("builtins.staticmethod"): 

1339 return "staticmethod" 

1340 except InferenceError: 

1341 pass 

1342 return type_name 

1343 

1344 @cached_property 

1345 def fromlineno(self) -> int: 

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

1347 

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

1349 """ 

1350 # lineno is the line number of the first decorator, we want the def 

1351 # statement lineno. Similar to 'ClassDef.fromlineno' 

1352 lineno = self.lineno or 0 

1353 if self.decorators is not None: 

1354 lineno += sum( 

1355 node.tolineno - (node.lineno or 0) + 1 for node in self.decorators.nodes 

1356 ) 

1357 

1358 return lineno or 0 

1359 

1360 @cached_property 

1361 def blockstart_tolineno(self): 

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

1363 

1364 :type: int 

1365 """ 

1366 return self.args.tolineno 

1367 

1368 def implicit_parameters(self) -> Literal[0, 1]: 

1369 return 1 if self.is_bound() else 0 

1370 

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

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

1373 

1374 :param lineno: Unused. 

1375 

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

1377 """ 

1378 return self.fromlineno, self.tolineno 

1379 

1380 def igetattr( 

1381 self, name: str, context: InferenceContext | None = None 

1382 ) -> Iterator[InferenceResult]: 

1383 """Inferred getattr, which returns an iterator of inferred statements.""" 

1384 try: 

1385 return bases._infer_stmts(self.getattr(name, context), context, frame=self) 

1386 except AttributeInferenceError as error: 

1387 raise InferenceError( 

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

1389 ) from error 

1390 

1391 def is_method(self) -> bool: 

1392 """Check if this function node represents a method. 

1393 

1394 :returns: Whether this is a method. 

1395 """ 

1396 # check we are defined in a ClassDef, because this is usually expected 

1397 # (e.g. pylint...) when is_method() return True 

1398 return self.type != "function" and isinstance( 

1399 self.parent.frame(future=True), ClassDef 

1400 ) 

1401 

1402 def decoratornames(self, context: InferenceContext | None = None) -> set[str]: 

1403 """Get the qualified names of each of the decorators on this function. 

1404 

1405 :param context: 

1406 An inference context that can be passed to inference functions 

1407 :returns: The names of the decorators. 

1408 """ 

1409 result = set() 

1410 decoratornodes = [] 

1411 if self.decorators is not None: 

1412 decoratornodes += self.decorators.nodes 

1413 decoratornodes += self.extra_decorators 

1414 for decnode in decoratornodes: 

1415 try: 

1416 for infnode in decnode.infer(context=context): 

1417 result.add(infnode.qname()) 

1418 except InferenceError: 

1419 continue 

1420 return result 

1421 

1422 def is_bound(self) -> bool: 

1423 """Check if the function is bound to an instance or class. 

1424 

1425 :returns: Whether the function is bound to an instance or class. 

1426 """ 

1427 return self.type in {"method", "classmethod"} 

1428 

1429 def is_abstract(self, pass_is_abstract=True, any_raise_is_abstract=False) -> bool: 

1430 """Check if the method is abstract. 

1431 

1432 A method is considered abstract if any of the following is true: 

1433 * The only statement is 'raise NotImplementedError' 

1434 * The only statement is 'raise <SomeException>' and any_raise_is_abstract is True 

1435 * The only statement is 'pass' and pass_is_abstract is True 

1436 * The method is annotated with abc.astractproperty/abc.abstractmethod 

1437 

1438 :returns: Whether the method is abstract. 

1439 """ 

1440 if self.decorators: 

1441 for node in self.decorators.nodes: 

1442 try: 

1443 inferred = next(node.infer()) 

1444 except (InferenceError, StopIteration): 

1445 continue 

1446 if inferred and inferred.qname() in { 

1447 "abc.abstractproperty", 

1448 "abc.abstractmethod", 

1449 }: 

1450 return True 

1451 

1452 for child_node in self.body: 

1453 if isinstance(child_node, node_classes.Raise): 

1454 if any_raise_is_abstract: 

1455 return True 

1456 if child_node.raises_not_implemented(): 

1457 return True 

1458 return pass_is_abstract and isinstance(child_node, node_classes.Pass) 

1459 # empty function is the same as function with a single "pass" statement 

1460 if pass_is_abstract: 

1461 return True 

1462 

1463 return False 

1464 

1465 def is_generator(self) -> bool: 

1466 """Check if this is a generator function. 

1467 

1468 :returns: Whether this is a generator function. 

1469 """ 

1470 return bool(next(self._get_yield_nodes_skip_lambdas(), False)) 

1471 

1472 def infer_yield_result(self, context: InferenceContext | None = None): 

1473 """Infer what the function yields when called 

1474 

1475 :returns: What the function yields 

1476 :rtype: iterable(NodeNG or Uninferable) or None 

1477 """ 

1478 # pylint: disable=not-an-iterable 

1479 # https://github.com/pylint-dev/astroid/issues/1015 

1480 for yield_ in self.nodes_of_class(node_classes.Yield): 

1481 if yield_.value is None: 

1482 const = node_classes.Const(None) 

1483 const.parent = yield_ 

1484 const.lineno = yield_.lineno 

1485 yield const 

1486 elif yield_.scope() == self: 

1487 yield from yield_.value.infer(context=context) 

1488 

1489 def infer_call_result( 

1490 self, 

1491 caller: SuccessfulInferenceResult | None, 

1492 context: InferenceContext | None = None, 

1493 ) -> Iterator[InferenceResult]: 

1494 """Infer what the function returns when called.""" 

1495 if self.is_generator(): 

1496 if isinstance(self, AsyncFunctionDef): 

1497 generator_cls: type[bases.Generator] = bases.AsyncGenerator 

1498 else: 

1499 generator_cls = bases.Generator 

1500 result = generator_cls(self, generator_initial_context=context) 

1501 yield result 

1502 return 

1503 # This is really a gigantic hack to work around metaclass generators 

1504 # that return transient class-generating functions. Pylint's AST structure 

1505 # cannot handle a base class object that is only used for calling __new__, 

1506 # but does not contribute to the inheritance structure itself. We inject 

1507 # a fake class into the hierarchy here for several well-known metaclass 

1508 # generators, and filter it out later. 

1509 if ( 

1510 self.name == "with_metaclass" 

1511 and caller is not None 

1512 and self.args.args 

1513 and len(self.args.args) == 1 

1514 and self.args.vararg is not None 

1515 ): 

1516 if isinstance(caller.args, Arguments): 

1517 assert caller.args.args is not None 

1518 metaclass = next(caller.args.args[0].infer(context), None) 

1519 elif isinstance(caller.args, list): 

1520 metaclass = next(caller.args[0].infer(context), None) 

1521 else: 

1522 raise TypeError( # pragma: no cover 

1523 f"caller.args was neither Arguments nor list; got {type(caller.args)}" 

1524 ) 

1525 if isinstance(metaclass, ClassDef): 

1526 try: 

1527 class_bases = [ 

1528 # Find the first non-None inferred base value 

1529 next( 

1530 b 

1531 for b in arg.infer( 

1532 context=context.clone() if context else context 

1533 ) 

1534 if not (isinstance(b, Const) and b.value is None) 

1535 ) 

1536 for arg in caller.args[1:] 

1537 ] 

1538 except StopIteration as e: 

1539 raise InferenceError(node=caller.args[1:], context=context) from e 

1540 new_class = ClassDef( 

1541 name="temporary_class", 

1542 lineno=0, 

1543 col_offset=0, 

1544 end_lineno=0, 

1545 end_col_offset=0, 

1546 parent=self, 

1547 ) 

1548 new_class.hide = True 

1549 new_class.postinit( 

1550 bases=[ 

1551 base 

1552 for base in class_bases 

1553 if not isinstance(base, util.UninferableBase) 

1554 ], 

1555 body=[], 

1556 decorators=None, 

1557 metaclass=metaclass, 

1558 ) 

1559 yield new_class 

1560 return 

1561 returns = self._get_return_nodes_skip_functions() 

1562 

1563 first_return = next(returns, None) 

1564 if not first_return: 

1565 if self.body: 

1566 if self.is_abstract(pass_is_abstract=True, any_raise_is_abstract=True): 

1567 yield util.Uninferable 

1568 else: 

1569 yield node_classes.Const(None) 

1570 return 

1571 

1572 raise InferenceError("The function does not have any return statements") 

1573 

1574 for returnnode in itertools.chain((first_return,), returns): 

1575 if returnnode.value is None: 

1576 yield node_classes.Const(None) 

1577 else: 

1578 try: 

1579 yield from returnnode.value.infer(context) 

1580 except InferenceError: 

1581 yield util.Uninferable 

1582 

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

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

1585 

1586 :returns: The boolean value of this node. 

1587 For a :class:`FunctionDef` this is always ``True``. 

1588 """ 

1589 return True 

1590 

1591 def get_children(self): 

1592 if self.decorators is not None: 

1593 yield self.decorators 

1594 

1595 yield self.args 

1596 

1597 if self.returns is not None: 

1598 yield self.returns 

1599 

1600 yield from self.body 

1601 

1602 def scope_lookup( 

1603 self, node: node_classes.LookupMixIn, name: str, offset: int = 0 

1604 ) -> tuple[LocalsDictNodeNG, list[nodes.NodeNG]]: 

1605 """Lookup where the given name is assigned.""" 

1606 if name == "__class__": 

1607 # __class__ is an implicit closure reference created by the compiler 

1608 # if any methods in a class body refer to either __class__ or super. 

1609 # In our case, we want to be able to look it up in the current scope 

1610 # when `__class__` is being used. 

1611 frame = self.parent.frame(future=True) 

1612 if isinstance(frame, ClassDef): 

1613 return self, [frame] 

1614 

1615 if (self.args.defaults and node in self.args.defaults) or ( 

1616 self.args.kw_defaults and node in self.args.kw_defaults 

1617 ): 

1618 frame = self.parent.frame(future=True) 

1619 # line offset to avoid that def func(f=func) resolve the default 

1620 # value to the defined function 

1621 offset = -1 

1622 else: 

1623 # check this is not used in function decorators 

1624 frame = self 

1625 return frame._scope_lookup(node, name, offset) 

1626 

1627 def frame(self: _T, *, future: Literal[None, True] = None) -> _T: 

1628 """The node's frame node. 

1629 

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

1631 :class:`ClassDef` or :class:`Lambda`. 

1632 

1633 :returns: The node itself. 

1634 """ 

1635 return self 

1636 

1637 

1638class AsyncFunctionDef(FunctionDef): 

1639 """Class representing an :class:`ast.FunctionDef` node. 

1640 

1641 A :class:`AsyncFunctionDef` is an asynchronous function 

1642 created with the `async` keyword. 

1643 

1644 >>> import astroid 

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

1646 async def func(things): 

1647 async for thing in things: 

1648 print(thing) 

1649 ''') 

1650 >>> node 

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

1652 >>> node.body[0] 

1653 <AsyncFor l.3 at 0x7f23b2e417b8> 

1654 """ 

1655 

1656 

1657def _rec_get_names(args, names: list[str] | None = None) -> list[str]: 

1658 """return a list of all argument names""" 

1659 if names is None: 

1660 names = [] 

1661 for arg in args: 

1662 if isinstance(arg, node_classes.Tuple): 

1663 _rec_get_names(arg.elts, names) 

1664 else: 

1665 names.append(arg.name) 

1666 return names 

1667 

1668 

1669def _is_metaclass(klass, seen=None) -> bool: 

1670 """Return if the given class can be 

1671 used as a metaclass. 

1672 """ 

1673 if klass.name == "type": 

1674 return True 

1675 if seen is None: 

1676 seen = set() 

1677 for base in klass.bases: 

1678 try: 

1679 for baseobj in base.infer(): 

1680 baseobj_name = baseobj.qname() 

1681 if baseobj_name in seen: 

1682 continue 

1683 

1684 seen.add(baseobj_name) 

1685 if isinstance(baseobj, bases.Instance): 

1686 # not abstract 

1687 return False 

1688 if baseobj is klass: 

1689 continue 

1690 if not isinstance(baseobj, ClassDef): 

1691 continue 

1692 if baseobj._type == "metaclass": 

1693 return True 

1694 if _is_metaclass(baseobj, seen): 

1695 return True 

1696 except InferenceError: 

1697 continue 

1698 return False 

1699 

1700 

1701def _class_type(klass, ancestors=None): 

1702 """return a ClassDef node type to differ metaclass and exception 

1703 from 'regular' classes 

1704 """ 

1705 # XXX we have to store ancestors in case we have an ancestor loop 

1706 if klass._type is not None: 

1707 return klass._type 

1708 if _is_metaclass(klass): 

1709 klass._type = "metaclass" 

1710 elif klass.name.endswith("Exception"): 

1711 klass._type = "exception" 

1712 else: 

1713 if ancestors is None: 

1714 ancestors = set() 

1715 klass_name = klass.qname() 

1716 if klass_name in ancestors: 

1717 # XXX we are in loop ancestors, and have found no type 

1718 klass._type = "class" 

1719 return "class" 

1720 ancestors.add(klass_name) 

1721 for base in klass.ancestors(recurs=False): 

1722 name = _class_type(base, ancestors) 

1723 if name != "class": 

1724 if name == "metaclass" and not _is_metaclass(klass): 

1725 # don't propagate it if the current class 

1726 # can't be a metaclass 

1727 continue 

1728 klass._type = base.type 

1729 break 

1730 if klass._type is None: 

1731 klass._type = "class" 

1732 return klass._type 

1733 

1734 

1735def get_wrapping_class(node): 

1736 """Get the class that wraps the given node. 

1737 

1738 We consider that a class wraps a node if the class 

1739 is a parent for the said node. 

1740 

1741 :returns: The class that wraps the given node 

1742 :rtype: ClassDef or None 

1743 """ 

1744 

1745 klass = node.frame(future=True) 

1746 while klass is not None and not isinstance(klass, ClassDef): 

1747 if klass.parent is None: 

1748 klass = None 

1749 else: 

1750 klass = klass.parent.frame(future=True) 

1751 return klass 

1752 

1753 

1754class ClassDef( 

1755 _base_nodes.FilterStmtsBaseNode, LocalsDictNodeNG, _base_nodes.Statement 

1756): 

1757 """Class representing an :class:`ast.ClassDef` node. 

1758 

1759 >>> import astroid 

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

1761 class Thing: 

1762 def my_meth(self, arg): 

1763 return arg + self.offset 

1764 ''') 

1765 >>> node 

1766 <ClassDef.Thing l.2 at 0x7f23b2e9e748> 

1767 """ 

1768 

1769 # some of the attributes below are set by the builder module or 

1770 # by a raw factories 

1771 

1772 # a dictionary of class instances attributes 

1773 _astroid_fields = ("decorators", "bases", "keywords", "doc_node", "body") # name 

1774 

1775 decorators = None 

1776 """The decorators that are applied to this class. 

1777 

1778 :type: Decorators or None 

1779 """ 

1780 special_attributes = ClassModel() 

1781 """The names of special attributes that this class has. 

1782 

1783 :type: objectmodel.ClassModel 

1784 """ 

1785 

1786 _type = None 

1787 _metaclass: NodeNG | None = None 

1788 _metaclass_hack = False 

1789 hide = False 

1790 type = property( 

1791 _class_type, 

1792 doc=( 

1793 "The class type for this node.\n\n" 

1794 "Possible values are: class, metaclass, exception.\n\n" 

1795 ":type: str" 

1796 ), 

1797 ) 

1798 _other_fields = ("name", "is_dataclass", "position") 

1799 _other_other_fields = ("locals", "_newstyle") 

1800 _newstyle: bool | None = None 

1801 

1802 def __init__( 

1803 self, 

1804 name: str, 

1805 lineno: int, 

1806 col_offset: int, 

1807 parent: NodeNG, 

1808 *, 

1809 end_lineno: int | None, 

1810 end_col_offset: int | None, 

1811 ) -> None: 

1812 self.instance_attrs: dict[str, NodeNG] = {} 

1813 self.locals = {} 

1814 """A map of the name of a local variable to the node defining it.""" 

1815 

1816 self.keywords: list[node_classes.Keyword] = [] 

1817 """The keywords given to the class definition. 

1818 

1819 This is usually for :pep:`3115` style metaclass declaration. 

1820 """ 

1821 

1822 self.bases: list[SuccessfulInferenceResult] = [] 

1823 """What the class inherits from.""" 

1824 

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

1826 """The contents of the class body.""" 

1827 

1828 self.name = name 

1829 """The name of the class.""" 

1830 

1831 self.decorators = None 

1832 """The decorators that are applied to this class.""" 

1833 

1834 self.doc_node: Const | None = None 

1835 """The doc node associated with this node.""" 

1836 

1837 self.is_dataclass: bool = False 

1838 """Whether this class is a dataclass.""" 

1839 

1840 super().__init__( 

1841 lineno=lineno, 

1842 col_offset=col_offset, 

1843 end_lineno=end_lineno, 

1844 end_col_offset=end_col_offset, 

1845 parent=parent, 

1846 ) 

1847 if parent and not isinstance(parent, Unknown): 

1848 parent.frame(future=True).set_local(name, self) 

1849 

1850 for local_name, node in self.implicit_locals(): 

1851 self.add_local_node(node, local_name) 

1852 

1853 infer_binary_op: ClassVar[InferBinaryOp[ClassDef]] 

1854 

1855 def implicit_parameters(self) -> Literal[1]: 

1856 return 1 

1857 

1858 def implicit_locals(self): 

1859 """Get implicitly defined class definition locals. 

1860 

1861 :returns: the the name and Const pair for each local 

1862 :rtype: tuple(tuple(str, node_classes.Const), ...) 

1863 """ 

1864 locals_ = (("__module__", self.special_attributes.attr___module__),) 

1865 # __qualname__ is defined in PEP3155 

1866 locals_ += (("__qualname__", self.special_attributes.attr___qualname__),) 

1867 return locals_ 

1868 

1869 # pylint: disable=redefined-outer-name 

1870 def postinit( 

1871 self, 

1872 bases: list[SuccessfulInferenceResult], 

1873 body: list[NodeNG], 

1874 decorators: node_classes.Decorators | None, 

1875 newstyle: bool | None = None, 

1876 metaclass: NodeNG | None = None, 

1877 keywords: list[node_classes.Keyword] | None = None, 

1878 *, 

1879 position: Position | None = None, 

1880 doc_node: Const | None = None, 

1881 ) -> None: 

1882 if keywords is not None: 

1883 self.keywords = keywords 

1884 self.bases = bases 

1885 self.body = body 

1886 self.decorators = decorators 

1887 self._newstyle = newstyle 

1888 self._metaclass = metaclass 

1889 self.position = position 

1890 self.doc_node = doc_node 

1891 

1892 def _newstyle_impl(self, context: InferenceContext | None = None): 

1893 if context is None: 

1894 context = InferenceContext() 

1895 if self._newstyle is not None: 

1896 return self._newstyle 

1897 for base in self.ancestors(recurs=False, context=context): 

1898 if base._newstyle_impl(context): 

1899 self._newstyle = True 

1900 break 

1901 klass = self.declared_metaclass() 

1902 # could be any callable, we'd need to infer the result of klass(name, 

1903 # bases, dict). punt if it's not a class node. 

1904 if klass is not None and isinstance(klass, ClassDef): 

1905 self._newstyle = klass._newstyle_impl(context) 

1906 if self._newstyle is None: 

1907 self._newstyle = False 

1908 return self._newstyle 

1909 

1910 _newstyle = None 

1911 newstyle = property( 

1912 _newstyle_impl, 

1913 doc=("Whether this is a new style class or not\n\n" ":type: bool or None"), 

1914 ) 

1915 

1916 @cached_property 

1917 def fromlineno(self) -> int: 

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

1919 

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

1921 """ 

1922 if IS_PYPY and PY38 and not PYPY_7_3_11_PLUS: 

1923 # For Python < 3.8 the lineno is the line number of the first decorator. 

1924 # We want the class statement lineno. Similar to 'FunctionDef.fromlineno' 

1925 # PyPy (3.8): Fixed with version v7.3.11 

1926 lineno = self.lineno or 0 

1927 if self.decorators is not None: 

1928 lineno += sum( 

1929 node.tolineno - (node.lineno or 0) + 1 

1930 for node in self.decorators.nodes 

1931 ) 

1932 

1933 return lineno or 0 

1934 return super().fromlineno 

1935 

1936 @cached_property 

1937 def blockstart_tolineno(self): 

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

1939 

1940 :type: int 

1941 """ 

1942 if self.bases: 

1943 return self.bases[-1].tolineno 

1944 

1945 return self.fromlineno 

1946 

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

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

1949 

1950 :param lineno: Unused. 

1951 

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

1953 """ 

1954 return self.fromlineno, self.tolineno 

1955 

1956 def pytype(self) -> Literal["builtins.type", "builtins.classobj"]: 

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

1958 

1959 :returns: The name of the type. 

1960 """ 

1961 if self.newstyle: 

1962 return "builtins.type" 

1963 return "builtins.classobj" 

1964 

1965 def display_type(self) -> str: 

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

1967 

1968 :returns: The type of this node. 

1969 :rtype: str 

1970 """ 

1971 return "Class" 

1972 

1973 def callable(self) -> bool: 

1974 """Whether this node defines something that is callable. 

1975 

1976 :returns: Whether this defines something that is callable. 

1977 For a :class:`ClassDef` this is always ``True``. 

1978 """ 

1979 return True 

1980 

1981 def is_subtype_of(self, type_name, context: InferenceContext | None = None) -> bool: 

1982 """Whether this class is a subtype of the given type. 

1983 

1984 :param type_name: The name of the type of check against. 

1985 :type type_name: str 

1986 

1987 :returns: Whether this class is a subtype of the given type. 

1988 """ 

1989 if self.qname() == type_name: 

1990 return True 

1991 

1992 return any(anc.qname() == type_name for anc in self.ancestors(context=context)) 

1993 

1994 def _infer_type_call(self, caller, context): 

1995 try: 

1996 name_node = next(caller.args[0].infer(context)) 

1997 except StopIteration as e: 

1998 raise InferenceError(node=caller.args[0], context=context) from e 

1999 if isinstance(name_node, node_classes.Const) and isinstance( 

2000 name_node.value, str 

2001 ): 

2002 name = name_node.value 

2003 else: 

2004 return util.Uninferable 

2005 

2006 result = ClassDef( 

2007 name, 

2008 lineno=0, 

2009 col_offset=0, 

2010 end_lineno=0, 

2011 end_col_offset=0, 

2012 parent=Unknown(), 

2013 ) 

2014 

2015 # Get the bases of the class. 

2016 try: 

2017 class_bases = next(caller.args[1].infer(context)) 

2018 except StopIteration as e: 

2019 raise InferenceError(node=caller.args[1], context=context) from e 

2020 if isinstance(class_bases, (node_classes.Tuple, node_classes.List)): 

2021 bases = [] 

2022 for base in class_bases.itered(): 

2023 inferred = next(base.infer(context=context), None) 

2024 if inferred: 

2025 bases.append( 

2026 node_classes.EvaluatedObject(original=base, value=inferred) 

2027 ) 

2028 result.bases = bases 

2029 else: 

2030 # There is currently no AST node that can represent an 'unknown' 

2031 # node (Uninferable is not an AST node), therefore we simply return Uninferable here 

2032 # although we know at least the name of the class. 

2033 return util.Uninferable 

2034 

2035 # Get the members of the class 

2036 try: 

2037 members = next(caller.args[2].infer(context)) 

2038 except (InferenceError, StopIteration): 

2039 members = None 

2040 

2041 if members and isinstance(members, node_classes.Dict): 

2042 for attr, value in members.items: 

2043 if isinstance(attr, node_classes.Const) and isinstance(attr.value, str): 

2044 result.locals[attr.value] = [value] 

2045 

2046 result.parent = caller.parent 

2047 return result 

2048 

2049 def infer_call_result( 

2050 self, 

2051 caller: SuccessfulInferenceResult | None, 

2052 context: InferenceContext | None = None, 

2053 ) -> Iterator[InferenceResult]: 

2054 """infer what a class is returning when called""" 

2055 if self.is_subtype_of("builtins.type", context) and len(caller.args) == 3: 

2056 result = self._infer_type_call(caller, context) 

2057 yield result 

2058 return 

2059 

2060 dunder_call = None 

2061 try: 

2062 metaclass = self.metaclass(context=context) 

2063 if metaclass is not None: 

2064 # Only get __call__ if it's defined locally for the metaclass. 

2065 # Otherwise we will find ObjectModel.__call__ which will 

2066 # return an instance of the metaclass. Instantiating the class is 

2067 # handled later. 

2068 if "__call__" in metaclass.locals: 

2069 dunder_call = next(metaclass.igetattr("__call__", context)) 

2070 except (AttributeInferenceError, StopIteration): 

2071 pass 

2072 

2073 if dunder_call and dunder_call.qname() != "builtins.type.__call__": 

2074 # Call type.__call__ if not set metaclass 

2075 # (since type is the default metaclass) 

2076 context = bind_context_to_node(context, self) 

2077 context.callcontext.callee = dunder_call 

2078 yield from dunder_call.infer_call_result(caller, context) 

2079 else: 

2080 yield self.instantiate_class() 

2081 

2082 def scope_lookup( 

2083 self, node: node_classes.LookupMixIn, name: str, offset: int = 0 

2084 ) -> tuple[LocalsDictNodeNG, list[nodes.NodeNG]]: 

2085 """Lookup where the given name is assigned. 

2086 

2087 :param node: The node to look for assignments up to. 

2088 Any assignments after the given node are ignored. 

2089 

2090 :param name: The name to find assignments for. 

2091 

2092 :param offset: The line offset to filter statements up to. 

2093 

2094 :returns: This scope node and the list of assignments associated to the 

2095 given name according to the scope where it has been found (locals, 

2096 globals or builtin). 

2097 """ 

2098 # If the name looks like a builtin name, just try to look 

2099 # into the upper scope of this class. We might have a 

2100 # decorator that it's poorly named after a builtin object 

2101 # inside this class. 

2102 lookup_upper_frame = ( 

2103 isinstance(node.parent, node_classes.Decorators) 

2104 and name in AstroidManager().builtins_module 

2105 ) 

2106 if ( 

2107 any(node == base or base.parent_of(node) for base in self.bases) 

2108 or lookup_upper_frame 

2109 ): 

2110 # Handle the case where we have either a name 

2111 # in the bases of a class, which exists before 

2112 # the actual definition or the case where we have 

2113 # a Getattr node, with that name. 

2114 # 

2115 # name = ... 

2116 # class A(name): 

2117 # def name(self): ... 

2118 # 

2119 # import name 

2120 # class A(name.Name): 

2121 # def name(self): ... 

2122 

2123 frame = self.parent.frame(future=True) 

2124 # line offset to avoid that class A(A) resolve the ancestor to 

2125 # the defined class 

2126 offset = -1 

2127 else: 

2128 frame = self 

2129 return frame._scope_lookup(node, name, offset) 

2130 

2131 @property 

2132 def basenames(self): 

2133 """The names of the parent classes 

2134 

2135 Names are given in the order they appear in the class definition. 

2136 

2137 :type: list(str) 

2138 """ 

2139 return [bnode.as_string() for bnode in self.bases] 

2140 

2141 def ancestors( 

2142 self, recurs: bool = True, context: InferenceContext | None = None 

2143 ) -> Generator[ClassDef, None, None]: 

2144 """Iterate over the base classes in prefixed depth first order. 

2145 

2146 :param recurs: Whether to recurse or return direct ancestors only. 

2147 

2148 :returns: The base classes 

2149 """ 

2150 # FIXME: should be possible to choose the resolution order 

2151 # FIXME: inference make infinite loops possible here 

2152 yielded = {self} 

2153 if context is None: 

2154 context = InferenceContext() 

2155 if not self.bases and self.qname() != "builtins.object": 

2156 yield builtin_lookup("object")[1][0] 

2157 return 

2158 

2159 for stmt in self.bases: 

2160 with context.restore_path(): 

2161 try: 

2162 for baseobj in stmt.infer(context): 

2163 if not isinstance(baseobj, ClassDef): 

2164 if isinstance(baseobj, bases.Instance): 

2165 baseobj = baseobj._proxied 

2166 else: 

2167 continue 

2168 if not baseobj.hide: 

2169 if baseobj in yielded: 

2170 continue 

2171 yielded.add(baseobj) 

2172 yield baseobj 

2173 if not recurs: 

2174 continue 

2175 for grandpa in baseobj.ancestors(recurs=True, context=context): 

2176 if grandpa is self: 

2177 # This class is the ancestor of itself. 

2178 break 

2179 if grandpa in yielded: 

2180 continue 

2181 yielded.add(grandpa) 

2182 yield grandpa 

2183 except InferenceError: 

2184 continue 

2185 

2186 def local_attr_ancestors(self, name, context: InferenceContext | None = None): 

2187 """Iterate over the parents that define the given name. 

2188 

2189 :param name: The name to find definitions for. 

2190 :type name: str 

2191 

2192 :returns: The parents that define the given name. 

2193 :rtype: iterable(NodeNG) 

2194 """ 

2195 # Look up in the mro if we can. This will result in the 

2196 # attribute being looked up just as Python does it. 

2197 try: 

2198 ancestors: Iterable[ClassDef] = self.mro(context)[1:] 

2199 except MroError: 

2200 # Fallback to use ancestors, we can't determine 

2201 # a sane MRO. 

2202 ancestors = self.ancestors(context=context) 

2203 for astroid in ancestors: 

2204 if name in astroid: 

2205 yield astroid 

2206 

2207 def instance_attr_ancestors(self, name, context: InferenceContext | None = None): 

2208 """Iterate over the parents that define the given name as an attribute. 

2209 

2210 :param name: The name to find definitions for. 

2211 :type name: str 

2212 

2213 :returns: The parents that define the given name as 

2214 an instance attribute. 

2215 :rtype: iterable(NodeNG) 

2216 """ 

2217 for astroid in self.ancestors(context=context): 

2218 if name in astroid.instance_attrs: 

2219 yield astroid 

2220 

2221 def has_base(self, node) -> bool: 

2222 """Whether this class directly inherits from the given node. 

2223 

2224 :param node: The node to check for. 

2225 :type node: NodeNG 

2226 

2227 :returns: Whether this class directly inherits from the given node. 

2228 """ 

2229 return node in self.bases 

2230 

2231 def local_attr(self, name, context: InferenceContext | None = None): 

2232 """Get the list of assign nodes associated to the given name. 

2233 

2234 Assignments are looked for in both this class and in parents. 

2235 

2236 :returns: The list of assignments to the given name. 

2237 :rtype: list(NodeNG) 

2238 

2239 :raises AttributeInferenceError: If no attribute with this name 

2240 can be found in this class or parent classes. 

2241 """ 

2242 result = [] 

2243 if name in self.locals: 

2244 result = self.locals[name] 

2245 else: 

2246 class_node = next(self.local_attr_ancestors(name, context), None) 

2247 if class_node: 

2248 result = class_node.locals[name] 

2249 result = [n for n in result if not isinstance(n, node_classes.DelAttr)] 

2250 if result: 

2251 return result 

2252 raise AttributeInferenceError(target=self, attribute=name, context=context) 

2253 

2254 def instance_attr(self, name, context: InferenceContext | None = None): 

2255 """Get the list of nodes associated to the given attribute name. 

2256 

2257 Assignments are looked for in both this class and in parents. 

2258 

2259 :returns: The list of assignments to the given name. 

2260 :rtype: list(NodeNG) 

2261 

2262 :raises AttributeInferenceError: If no attribute with this name 

2263 can be found in this class or parent classes. 

2264 """ 

2265 # Return a copy, so we don't modify self.instance_attrs, 

2266 # which could lead to infinite loop. 

2267 values = list(self.instance_attrs.get(name, [])) 

2268 # get all values from parents 

2269 for class_node in self.instance_attr_ancestors(name, context): 

2270 values += class_node.instance_attrs[name] 

2271 values = [n for n in values if not isinstance(n, node_classes.DelAttr)] 

2272 if values: 

2273 return values 

2274 raise AttributeInferenceError(target=self, attribute=name, context=context) 

2275 

2276 def instantiate_class(self) -> bases.Instance: 

2277 """Get an :class:`Instance` of the :class:`ClassDef` node. 

2278 

2279 :returns: An :class:`Instance` of the :class:`ClassDef` node 

2280 """ 

2281 from astroid import objects # pylint: disable=import-outside-toplevel 

2282 

2283 try: 

2284 if any(cls.name in EXCEPTION_BASE_CLASSES for cls in self.mro()): 

2285 # Subclasses of exceptions can be exception instances 

2286 return objects.ExceptionInstance(self) 

2287 except MroError: 

2288 pass 

2289 return bases.Instance(self) 

2290 

2291 def getattr( 

2292 self, 

2293 name: str, 

2294 context: InferenceContext | None = None, 

2295 class_context: bool = True, 

2296 ) -> list[SuccessfulInferenceResult]: 

2297 """Get an attribute from this class, using Python's attribute semantic. 

2298 

2299 This method doesn't look in the :attr:`instance_attrs` dictionary 

2300 since it is done by an :class:`Instance` proxy at inference time. 

2301 It may return an :class:`Uninferable` object if 

2302 the attribute has not been 

2303 found, but a ``__getattr__`` or ``__getattribute__`` method is defined. 

2304 If ``class_context`` is given, then it is considered that the 

2305 attribute is accessed from a class context, 

2306 e.g. ClassDef.attribute, otherwise it might have been accessed 

2307 from an instance as well. If ``class_context`` is used in that 

2308 case, then a lookup in the implicit metaclass and the explicit 

2309 metaclass will be done. 

2310 

2311 :param name: The attribute to look for. 

2312 

2313 :param class_context: Whether the attribute can be accessed statically. 

2314 

2315 :returns: The attribute. 

2316 

2317 :raises AttributeInferenceError: If the attribute cannot be inferred. 

2318 """ 

2319 if not name: 

2320 raise AttributeInferenceError(target=self, attribute=name, context=context) 

2321 

2322 # don't modify the list in self.locals! 

2323 values: list[SuccessfulInferenceResult] = list(self.locals.get(name, [])) 

2324 for classnode in self.ancestors(recurs=True, context=context): 

2325 values += classnode.locals.get(name, []) 

2326 

2327 if name in self.special_attributes and class_context and not values: 

2328 result = [self.special_attributes.lookup(name)] 

2329 if name == "__bases__": 

2330 # Need special treatment, since they are mutable 

2331 # and we need to return all the values. 

2332 result += values 

2333 return result 

2334 

2335 if class_context: 

2336 values += self._metaclass_lookup_attribute(name, context) 

2337 

2338 # Remove AnnAssigns without value, which are not attributes in the purest sense. 

2339 for value in values.copy(): 

2340 if isinstance(value, node_classes.AssignName): 

2341 stmt = value.statement(future=True) 

2342 if isinstance(stmt, node_classes.AnnAssign) and stmt.value is None: 

2343 values.pop(values.index(value)) 

2344 

2345 if not values: 

2346 raise AttributeInferenceError(target=self, attribute=name, context=context) 

2347 

2348 return values 

2349 

2350 @lru_cache(maxsize=1024) # noqa 

2351 def _metaclass_lookup_attribute(self, name, context): 

2352 """Search the given name in the implicit and the explicit metaclass.""" 

2353 attrs = set() 

2354 implicit_meta = self.implicit_metaclass() 

2355 context = copy_context(context) 

2356 metaclass = self.metaclass(context=context) 

2357 for cls in (implicit_meta, metaclass): 

2358 if cls and cls != self and isinstance(cls, ClassDef): 

2359 cls_attributes = self._get_attribute_from_metaclass(cls, name, context) 

2360 attrs.update(set(cls_attributes)) 

2361 return attrs 

2362 

2363 def _get_attribute_from_metaclass(self, cls, name, context): 

2364 from astroid import objects # pylint: disable=import-outside-toplevel 

2365 

2366 try: 

2367 attrs = cls.getattr(name, context=context, class_context=True) 

2368 except AttributeInferenceError: 

2369 return 

2370 

2371 for attr in bases._infer_stmts(attrs, context, frame=cls): 

2372 if not isinstance(attr, FunctionDef): 

2373 yield attr 

2374 continue 

2375 

2376 if isinstance(attr, objects.Property): 

2377 yield attr 

2378 continue 

2379 if attr.type == "classmethod": 

2380 # If the method is a classmethod, then it will 

2381 # be bound to the metaclass, not to the class 

2382 # from where the attribute is retrieved. 

2383 # get_wrapping_class could return None, so just 

2384 # default to the current class. 

2385 frame = get_wrapping_class(attr) or self 

2386 yield bases.BoundMethod(attr, frame) 

2387 elif attr.type == "staticmethod": 

2388 yield attr 

2389 else: 

2390 yield bases.BoundMethod(attr, self) 

2391 

2392 def igetattr( 

2393 self, 

2394 name: str, 

2395 context: InferenceContext | None = None, 

2396 class_context: bool = True, 

2397 ) -> Iterator[InferenceResult]: 

2398 """Infer the possible values of the given variable. 

2399 

2400 :param name: The name of the variable to infer. 

2401 

2402 :returns: The inferred possible values. 

2403 """ 

2404 from astroid import objects # pylint: disable=import-outside-toplevel 

2405 

2406 # set lookup name since this is necessary to infer on import nodes for 

2407 # instance 

2408 context = copy_context(context) 

2409 context.lookupname = name 

2410 

2411 metaclass = self.metaclass(context=context) 

2412 try: 

2413 attributes = self.getattr(name, context, class_context=class_context) 

2414 # If we have more than one attribute, make sure that those starting from 

2415 # the second one are from the same scope. This is to account for modifications 

2416 # to the attribute happening *after* the attribute's definition (e.g. AugAssigns on lists) 

2417 if len(attributes) > 1: 

2418 first_attr, attributes = attributes[0], attributes[1:] 

2419 first_scope = first_attr.scope() 

2420 attributes = [first_attr] + [ 

2421 attr 

2422 for attr in attributes 

2423 if attr.parent and attr.parent.scope() == first_scope 

2424 ] 

2425 

2426 for inferred in bases._infer_stmts(attributes, context, frame=self): 

2427 # yield Uninferable object instead of descriptors when necessary 

2428 if not isinstance(inferred, node_classes.Const) and isinstance( 

2429 inferred, bases.Instance 

2430 ): 

2431 try: 

2432 inferred._proxied.getattr("__get__", context) 

2433 except AttributeInferenceError: 

2434 yield inferred 

2435 else: 

2436 yield util.Uninferable 

2437 elif isinstance(inferred, objects.Property): 

2438 function = inferred.function 

2439 if not class_context: 

2440 # Through an instance so we can solve the property 

2441 yield from function.infer_call_result( 

2442 caller=self, context=context 

2443 ) 

2444 # If we're in a class context, we need to determine if the property 

2445 # was defined in the metaclass (a derived class must be a subclass of 

2446 # the metaclass of all its bases), in which case we can resolve the 

2447 # property. If not, i.e. the property is defined in some base class 

2448 # instead, then we return the property object 

2449 elif metaclass and function.parent.scope() is metaclass: 

2450 # Resolve a property as long as it is not accessed through 

2451 # the class itself. 

2452 yield from function.infer_call_result( 

2453 caller=self, context=context 

2454 ) 

2455 else: 

2456 yield inferred 

2457 else: 

2458 yield function_to_method(inferred, self) 

2459 except AttributeInferenceError as error: 

2460 if not name.startswith("__") and self.has_dynamic_getattr(context): 

2461 # class handle some dynamic attributes, return a Uninferable object 

2462 yield util.Uninferable 

2463 else: 

2464 raise InferenceError( 

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

2466 ) from error 

2467 

2468 def has_dynamic_getattr(self, context: InferenceContext | None = None) -> bool: 

2469 """Check if the class has a custom __getattr__ or __getattribute__. 

2470 

2471 If any such method is found and it is not from 

2472 builtins, nor from an extension module, then the function 

2473 will return True. 

2474 

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

2476 """ 

2477 

2478 def _valid_getattr(node): 

2479 root = node.root() 

2480 return root.name != "builtins" and getattr(root, "pure_python", None) 

2481 

2482 try: 

2483 return _valid_getattr(self.getattr("__getattr__", context)[0]) 

2484 except AttributeInferenceError: 

2485 # if self.newstyle: XXX cause an infinite recursion error 

2486 try: 

2487 getattribute = self.getattr("__getattribute__", context)[0] 

2488 return _valid_getattr(getattribute) 

2489 except AttributeInferenceError: 

2490 pass 

2491 return False 

2492 

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

2494 """Return the inference of a subscript. 

2495 

2496 This is basically looking up the method in the metaclass and calling it. 

2497 

2498 :returns: The inferred value of a subscript to this class. 

2499 :rtype: NodeNG 

2500 

2501 :raises AstroidTypeError: If this class does not define a 

2502 ``__getitem__`` method. 

2503 """ 

2504 try: 

2505 methods = lookup(self, "__getitem__") 

2506 except AttributeInferenceError as exc: 

2507 if isinstance(self, ClassDef): 

2508 # subscripting a class definition may be 

2509 # achieved thanks to __class_getitem__ method 

2510 # which is a classmethod defined in the class 

2511 # that supports subscript and not in the metaclass 

2512 try: 

2513 methods = self.getattr("__class_getitem__") 

2514 # Here it is assumed that the __class_getitem__ node is 

2515 # a FunctionDef. One possible improvement would be to deal 

2516 # with more generic inference. 

2517 except AttributeInferenceError: 

2518 raise AstroidTypeError(node=self, context=context) from exc 

2519 else: 

2520 raise AstroidTypeError(node=self, context=context) from exc 

2521 

2522 method = methods[0] 

2523 

2524 # Create a new callcontext for providing index as an argument. 

2525 new_context = bind_context_to_node(context, self) 

2526 new_context.callcontext = CallContext(args=[index], callee=method) 

2527 

2528 try: 

2529 return next(method.infer_call_result(self, new_context), util.Uninferable) 

2530 except AttributeError: 

2531 # Starting with python3.9, builtin types list, dict etc... 

2532 # are subscriptable thanks to __class_getitem___ classmethod. 

2533 # However in such case the method is bound to an EmptyNode and 

2534 # EmptyNode doesn't have infer_call_result method yielding to 

2535 # AttributeError 

2536 if ( 

2537 isinstance(method, node_classes.EmptyNode) 

2538 and self.pytype() == "builtins.type" 

2539 and PY39_PLUS 

2540 ): 

2541 return self 

2542 raise 

2543 except InferenceError: 

2544 return util.Uninferable 

2545 

2546 def methods(self): 

2547 """Iterate over all of the method defined in this class and its parents. 

2548 

2549 :returns: The methods defined on the class. 

2550 :rtype: iterable(FunctionDef) 

2551 """ 

2552 done = {} 

2553 for astroid in itertools.chain(iter((self,)), self.ancestors()): 

2554 for meth in astroid.mymethods(): 

2555 if meth.name in done: 

2556 continue 

2557 done[meth.name] = None 

2558 yield meth 

2559 

2560 def mymethods(self): 

2561 """Iterate over all of the method defined in this class only. 

2562 

2563 :returns: The methods defined on the class. 

2564 :rtype: iterable(FunctionDef) 

2565 """ 

2566 for member in self.values(): 

2567 if isinstance(member, FunctionDef): 

2568 yield member 

2569 

2570 def implicit_metaclass(self): 

2571 """Get the implicit metaclass of the current class. 

2572 

2573 For newstyle classes, this will return an instance of builtins.type. 

2574 For oldstyle classes, it will simply return None, since there's 

2575 no implicit metaclass there. 

2576 

2577 :returns: The metaclass. 

2578 :rtype: builtins.type or None 

2579 """ 

2580 if self.newstyle: 

2581 return builtin_lookup("type")[1][0] 

2582 return None 

2583 

2584 def declared_metaclass( 

2585 self, context: InferenceContext | None = None 

2586 ) -> SuccessfulInferenceResult | None: 

2587 """Return the explicit declared metaclass for the current class. 

2588 

2589 An explicit declared metaclass is defined 

2590 either by passing the ``metaclass`` keyword argument 

2591 in the class definition line (Python 3) or (Python 2) by 

2592 having a ``__metaclass__`` class attribute, or if there are 

2593 no explicit bases but there is a global ``__metaclass__`` variable. 

2594 

2595 :returns: The metaclass of this class, 

2596 or None if one could not be found. 

2597 """ 

2598 for base in self.bases: 

2599 try: 

2600 for baseobj in base.infer(context=context): 

2601 if isinstance(baseobj, ClassDef) and baseobj.hide: 

2602 self._metaclass = baseobj._metaclass 

2603 self._metaclass_hack = True 

2604 break 

2605 except InferenceError: 

2606 pass 

2607 

2608 if self._metaclass: 

2609 # Expects this from Py3k TreeRebuilder 

2610 try: 

2611 return next( 

2612 node 

2613 for node in self._metaclass.infer(context=context) 

2614 if not isinstance(node, util.UninferableBase) 

2615 ) 

2616 except (InferenceError, StopIteration): 

2617 return None 

2618 

2619 return None 

2620 

2621 def _find_metaclass( 

2622 self, seen: set[ClassDef] | None = None, context: InferenceContext | None = None 

2623 ) -> SuccessfulInferenceResult | None: 

2624 if seen is None: 

2625 seen = set() 

2626 seen.add(self) 

2627 

2628 klass = self.declared_metaclass(context=context) 

2629 if klass is None: 

2630 for parent in self.ancestors(context=context): 

2631 if parent not in seen: 

2632 klass = parent._find_metaclass(seen) 

2633 if klass is not None: 

2634 break 

2635 return klass 

2636 

2637 def metaclass( 

2638 self, context: InferenceContext | None = None 

2639 ) -> SuccessfulInferenceResult | None: 

2640 """Get the metaclass of this class. 

2641 

2642 If this class does not define explicitly a metaclass, 

2643 then the first defined metaclass in ancestors will be used 

2644 instead. 

2645 

2646 :returns: The metaclass of this class. 

2647 """ 

2648 return self._find_metaclass(context=context) 

2649 

2650 def has_metaclass_hack(self): 

2651 return self._metaclass_hack 

2652 

2653 def _islots(self): 

2654 """Return an iterator with the inferred slots.""" 

2655 if "__slots__" not in self.locals: 

2656 return None 

2657 for slots in self.igetattr("__slots__"): 

2658 # check if __slots__ is a valid type 

2659 for meth in ITER_METHODS: 

2660 try: 

2661 slots.getattr(meth) 

2662 break 

2663 except AttributeInferenceError: 

2664 continue 

2665 else: 

2666 continue 

2667 

2668 if isinstance(slots, node_classes.Const): 

2669 # a string. Ignore the following checks, 

2670 # but yield the node, only if it has a value 

2671 if slots.value: 

2672 yield slots 

2673 continue 

2674 if not hasattr(slots, "itered"): 

2675 # we can't obtain the values, maybe a .deque? 

2676 continue 

2677 

2678 if isinstance(slots, node_classes.Dict): 

2679 values = [item[0] for item in slots.items] 

2680 else: 

2681 values = slots.itered() 

2682 if isinstance(values, util.UninferableBase): 

2683 continue 

2684 if not values: 

2685 # Stop the iteration, because the class 

2686 # has an empty list of slots. 

2687 return values 

2688 

2689 for elt in values: 

2690 try: 

2691 for inferred in elt.infer(): 

2692 if not isinstance( 

2693 inferred, node_classes.Const 

2694 ) or not isinstance(inferred.value, str): 

2695 continue 

2696 if not inferred.value: 

2697 continue 

2698 yield inferred 

2699 except InferenceError: 

2700 continue 

2701 

2702 return None 

2703 

2704 def _slots(self): 

2705 if not self.newstyle: 

2706 raise NotImplementedError( 

2707 "The concept of slots is undefined for old-style classes." 

2708 ) 

2709 

2710 slots = self._islots() 

2711 try: 

2712 first = next(slots) 

2713 except StopIteration as exc: 

2714 # The class doesn't have a __slots__ definition or empty slots. 

2715 if exc.args and exc.args[0] not in ("", None): 

2716 return exc.args[0] 

2717 return None 

2718 return [first, *slots] 

2719 

2720 # Cached, because inferring them all the time is expensive 

2721 @cached_property 

2722 def _all_slots(self): 

2723 """Get all the slots for this node. 

2724 

2725 :returns: The names of slots for this class. 

2726 If the class doesn't define any slot, through the ``__slots__`` 

2727 variable, then this function will return a None. 

2728 Also, it will return None in the case the slots were not inferred. 

2729 :rtype: list(str) or None 

2730 """ 

2731 

2732 def grouped_slots( 

2733 mro: list[ClassDef], 

2734 ) -> Iterator[node_classes.NodeNG | None]: 

2735 for cls in mro: 

2736 # Not interested in object, since it can't have slots. 

2737 if cls.qname() == "builtins.object": 

2738 continue 

2739 try: 

2740 cls_slots = cls._slots() 

2741 except NotImplementedError: 

2742 continue 

2743 if cls_slots is not None: 

2744 yield from cls_slots 

2745 else: 

2746 yield None 

2747 

2748 if not self.newstyle: 

2749 raise NotImplementedError( 

2750 "The concept of slots is undefined for old-style classes." 

2751 ) 

2752 

2753 try: 

2754 mro = self.mro() 

2755 except MroError as e: 

2756 raise NotImplementedError( 

2757 "Cannot get slots while parsing mro fails." 

2758 ) from e 

2759 

2760 slots = list(grouped_slots(mro)) 

2761 if not all(slot is not None for slot in slots): 

2762 return None 

2763 

2764 return sorted(set(slots), key=lambda item: item.value) 

2765 

2766 def slots(self): 

2767 return self._all_slots 

2768 

2769 def _inferred_bases(self, context: InferenceContext | None = None): 

2770 # Similar with .ancestors, but the difference is when one base is inferred, 

2771 # only the first object is wanted. That's because 

2772 # we aren't interested in superclasses, as in the following 

2773 # example: 

2774 # 

2775 # class SomeSuperClass(object): pass 

2776 # class SomeClass(SomeSuperClass): pass 

2777 # class Test(SomeClass): pass 

2778 # 

2779 # Inferring SomeClass from the Test's bases will give 

2780 # us both SomeClass and SomeSuperClass, but we are interested 

2781 # only in SomeClass. 

2782 

2783 if context is None: 

2784 context = InferenceContext() 

2785 if not self.bases and self.qname() != "builtins.object": 

2786 yield builtin_lookup("object")[1][0] 

2787 return 

2788 

2789 for stmt in self.bases: 

2790 try: 

2791 # Find the first non-None inferred base value 

2792 baseobj = next( 

2793 b 

2794 for b in stmt.infer(context=context.clone()) 

2795 if not (isinstance(b, Const) and b.value is None) 

2796 ) 

2797 except (InferenceError, StopIteration): 

2798 continue 

2799 if isinstance(baseobj, bases.Instance): 

2800 baseobj = baseobj._proxied 

2801 if not isinstance(baseobj, ClassDef): 

2802 continue 

2803 if not baseobj.hide: 

2804 yield baseobj 

2805 else: 

2806 yield from baseobj.bases 

2807 

2808 def _compute_mro(self, context: InferenceContext | None = None): 

2809 if self.qname() == "builtins.object": 

2810 return [self] 

2811 

2812 inferred_bases = list(self._inferred_bases(context=context)) 

2813 bases_mro = [] 

2814 for base in inferred_bases: 

2815 if base is self: 

2816 continue 

2817 

2818 try: 

2819 mro = base._compute_mro(context=context) 

2820 bases_mro.append(mro) 

2821 except NotImplementedError: 

2822 # Some classes have in their ancestors both newstyle and 

2823 # old style classes. For these we can't retrieve the .mro, 

2824 # although in Python it's possible, since the class we are 

2825 # currently working is in fact new style. 

2826 # So, we fallback to ancestors here. 

2827 ancestors = list(base.ancestors(context=context)) 

2828 bases_mro.append(ancestors) 

2829 

2830 unmerged_mro = [[self], *bases_mro, inferred_bases] 

2831 unmerged_mro = clean_duplicates_mro(unmerged_mro, self, context) 

2832 clean_typing_generic_mro(unmerged_mro) 

2833 return _c3_merge(unmerged_mro, self, context) 

2834 

2835 def mro(self, context: InferenceContext | None = None) -> list[ClassDef]: 

2836 """Get the method resolution order, using C3 linearization. 

2837 

2838 :returns: The list of ancestors, sorted by the mro. 

2839 :rtype: list(NodeNG) 

2840 :raises DuplicateBasesError: Duplicate bases in the same class base 

2841 :raises InconsistentMroError: A class' MRO is inconsistent 

2842 """ 

2843 return self._compute_mro(context=context) 

2844 

2845 def bool_value(self, context: InferenceContext | None = None) -> Literal[True]: 

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

2847 

2848 :returns: The boolean value of this node. 

2849 For a :class:`ClassDef` this is always ``True``. 

2850 """ 

2851 return True 

2852 

2853 def get_children(self): 

2854 if self.decorators is not None: 

2855 yield self.decorators 

2856 

2857 yield from self.bases 

2858 if self.keywords is not None: 

2859 yield from self.keywords 

2860 yield from self.body 

2861 

2862 @cached_property 

2863 def _assign_nodes_in_scope(self): 

2864 children_assign_nodes = ( 

2865 child_node._assign_nodes_in_scope for child_node in self.body 

2866 ) 

2867 return list(itertools.chain.from_iterable(children_assign_nodes)) 

2868 

2869 def frame(self: _T, *, future: Literal[None, True] = None) -> _T: 

2870 """The node's frame node. 

2871 

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

2873 :class:`ClassDef` or :class:`Lambda`. 

2874 

2875 :returns: The node itself. 

2876 """ 

2877 return self