Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/astroid/bases.py: 22%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

406 statements  

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

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

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

4 

5"""This module contains base classes and functions for the nodes and some 

6inference utils. 

7""" 

8from __future__ import annotations 

9 

10import collections 

11import collections.abc 

12from collections.abc import Iterable, Iterator 

13from typing import TYPE_CHECKING, Any, Literal 

14 

15from astroid import decorators, nodes 

16from astroid.const import PY311_PLUS 

17from astroid.context import ( 

18 CallContext, 

19 InferenceContext, 

20 bind_context_to_node, 

21 copy_context, 

22) 

23from astroid.exceptions import ( 

24 AstroidTypeError, 

25 AttributeInferenceError, 

26 InferenceError, 

27 NameInferenceError, 

28) 

29from astroid.interpreter import objectmodel 

30from astroid.typing import ( 

31 InferenceErrorInfo, 

32 InferenceResult, 

33 SuccessfulInferenceResult, 

34) 

35from astroid.util import Uninferable, UninferableBase, safe_infer 

36 

37if TYPE_CHECKING: 

38 from astroid.constraint import Constraint 

39 

40 

41PROPERTIES = {"builtins.property", "abc.abstractproperty", "functools.cached_property"} 

42# enum.property was added in Python 3.11 

43if PY311_PLUS: 

44 PROPERTIES.add("enum.property") 

45 

46# List of possible property names. We use this list in order 

47# to see if a method is a property or not. This should be 

48# pretty reliable and fast, the alternative being to check each 

49# decorator to see if its a real property-like descriptor, which 

50# can be too complicated. 

51# Also, these aren't qualified, because each project can 

52# define them, we shouldn't expect to know every possible 

53# property-like decorator! 

54POSSIBLE_PROPERTIES = { 

55 "cached_property", 

56 "cachedproperty", 

57 "lazyproperty", 

58 "lazy_property", 

59 "reify", 

60 "lazyattribute", 

61 "lazy_attribute", 

62 "LazyProperty", 

63 "lazy", 

64 "cache_readonly", 

65 "DynamicClassAttribute", 

66} 

67 

68 

69def _is_property( 

70 meth: nodes.FunctionDef | UnboundMethod, context: InferenceContext | None = None 

71) -> bool: 

72 decoratornames = meth.decoratornames(context=context) 

73 if PROPERTIES.intersection(decoratornames): 

74 return True 

75 stripped = { 

76 name.split(".")[-1] 

77 for name in decoratornames 

78 if not isinstance(name, UninferableBase) 

79 } 

80 if any(name in stripped for name in POSSIBLE_PROPERTIES): 

81 return True 

82 

83 if not meth.decorators: 

84 return False 

85 # Lookup for subclasses of *property* 

86 for decorator in meth.decorators.nodes or (): 

87 inferred = safe_infer(decorator, context=context) 

88 if inferred is None or isinstance(inferred, UninferableBase): 

89 continue 

90 if isinstance(inferred, nodes.ClassDef): 

91 # Check for a class which inherits from a standard property type 

92 if any(inferred.is_subtype_of(pclass) for pclass in PROPERTIES): 

93 return True 

94 for base_class in inferred.bases: 

95 # Check for a class which inherits from functools.cached_property 

96 # and includes a subscripted type annotation 

97 if isinstance(base_class, nodes.Subscript): 

98 value = safe_infer(base_class.value, context=context) 

99 if not isinstance(value, nodes.ClassDef): 

100 continue 

101 if value.name != "cached_property": 

102 continue 

103 module, _ = value.lookup(value.name) 

104 if isinstance(module, nodes.Module) and module.name == "functools": 

105 return True 

106 continue 

107 

108 return False 

109 

110 

111class Proxy: 

112 """A simple proxy object. 

113 

114 Note: 

115 

116 Subclasses of this object will need a custom __getattr__ 

117 if new instance attributes are created. See the Const class 

118 """ 

119 

120 _proxied: nodes.ClassDef | nodes.FunctionDef | nodes.Lambda | UnboundMethod 

121 

122 def __init__( 

123 self, 

124 proxied: ( 

125 nodes.ClassDef | nodes.FunctionDef | nodes.Lambda | UnboundMethod | None 

126 ) = None, 

127 ) -> None: 

128 if proxied is None: 

129 # This is a hack to allow calling this __init__ during bootstrapping of 

130 # builtin classes and their docstrings. 

131 # For Const, Generator, and UnionType nodes the _proxied attribute 

132 # is set during bootstrapping 

133 # as we first need to build the ClassDef that they can proxy. 

134 # Thus, if proxied is None self should be a Const or Generator 

135 # as that is the only way _proxied will be correctly set as a ClassDef. 

136 assert isinstance(self, (nodes.Const, Generator, UnionType)) 

137 else: 

138 self._proxied = proxied 

139 

140 def __getattr__(self, name: str) -> Any: 

141 if name == "_proxied": 

142 return self.__class__._proxied 

143 if name in self.__dict__: 

144 return self.__dict__[name] 

145 return getattr(self._proxied, name) 

146 

147 def infer( # type: ignore[return] 

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

149 ) -> collections.abc.Generator[InferenceResult, None, InferenceErrorInfo | None]: 

150 yield self 

151 

152 

153def _infer_stmts( 

154 stmts: Iterable[InferenceResult], 

155 context: InferenceContext | None, 

156 frame: nodes.NodeNG | BaseInstance | None = None, 

157) -> collections.abc.Generator[InferenceResult]: 

158 """Return an iterator on statements inferred by each statement in *stmts*.""" 

159 inferred = False 

160 constraint_failed = False 

161 if context is not None: 

162 name = context.lookupname 

163 context = context.clone() 

164 if name is not None: 

165 constraints = context.constraints.get(name, {}) 

166 else: 

167 constraints = {} 

168 else: 

169 name = None 

170 constraints = {} 

171 context = InferenceContext() 

172 

173 for stmt in stmts: 

174 if isinstance(stmt, UninferableBase): 

175 yield stmt 

176 inferred = True 

177 continue 

178 context.lookupname = stmt._infer_name(frame, name) 

179 try: 

180 stmt_constraints: set[Constraint] = set() 

181 for constraint_stmt, potential_constraints in constraints.items(): 

182 if not constraint_stmt.parent_of(stmt): 

183 stmt_constraints.update(potential_constraints) 

184 for inf in stmt.infer(context=context): 

185 if all(constraint.satisfied_by(inf) for constraint in stmt_constraints): 

186 yield inf 

187 inferred = True 

188 else: 

189 constraint_failed = True 

190 except NameInferenceError: 

191 continue 

192 except InferenceError: 

193 yield Uninferable 

194 inferred = True 

195 

196 if not inferred and constraint_failed: 

197 yield Uninferable 

198 elif not inferred: 

199 raise InferenceError( 

200 "Inference failed for all members of {stmts!r}.", 

201 stmts=stmts, 

202 frame=frame, 

203 context=context, 

204 ) 

205 

206 

207def _infer_method_result_truth( 

208 instance: Instance, method_name: str, context: InferenceContext 

209) -> bool | UninferableBase: 

210 # Get the method from the instance and try to infer 

211 # its return's truth value. 

212 meth = next(instance.igetattr(method_name, context=context), None) 

213 if meth and hasattr(meth, "infer_call_result"): 

214 if not meth.callable(): 

215 return Uninferable 

216 try: 

217 context.callcontext = CallContext(args=[], callee=meth) 

218 for value in meth.infer_call_result(instance, context=context): 

219 if isinstance(value, UninferableBase): 

220 return value 

221 try: 

222 inferred = next(value.infer(context=context)) 

223 except StopIteration as e: 

224 raise InferenceError(context=context) from e 

225 return inferred.bool_value() 

226 except InferenceError: 

227 pass 

228 return Uninferable 

229 

230 

231class BaseInstance(Proxy): 

232 """An instance base class, which provides lookup methods for potential 

233 instances. 

234 """ 

235 

236 _proxied: nodes.ClassDef 

237 

238 special_attributes: objectmodel.ObjectModel 

239 

240 def display_type(self) -> str: 

241 return "Instance of" 

242 

243 def getattr( 

244 self, 

245 name: str, 

246 context: InferenceContext | None = None, 

247 lookupclass: bool = True, 

248 ) -> list[InferenceResult]: 

249 try: 

250 values = self._proxied.instance_attr(name, context) 

251 except AttributeInferenceError as exc: 

252 if self.special_attributes and name in self.special_attributes: 

253 special_attr = self.special_attributes.lookup(name) 

254 if not isinstance(special_attr, nodes.Unknown): 

255 return [special_attr] 

256 

257 if lookupclass: 

258 # Class attributes not available through the instance 

259 # unless they are explicitly defined. 

260 return self._proxied.getattr(name, context, class_context=False) 

261 

262 raise AttributeInferenceError( 

263 target=self, attribute=name, context=context 

264 ) from exc 

265 # since we've no context information, return matching class members as 

266 # well 

267 if lookupclass: 

268 try: 

269 return values + self._proxied.getattr( 

270 name, context, class_context=False 

271 ) 

272 except AttributeInferenceError: 

273 pass 

274 return values 

275 

276 def igetattr( 

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

278 ) -> Iterator[InferenceResult]: 

279 """Inferred getattr.""" 

280 if not context: 

281 context = InferenceContext() 

282 try: 

283 context.lookupname = name 

284 # XXX frame should be self._proxied, or not ? 

285 get_attr = self.getattr(name, context, lookupclass=False) 

286 yield from _infer_stmts( 

287 self._wrap_attr(get_attr, context), context, frame=self 

288 ) 

289 except AttributeInferenceError: 

290 try: 

291 # fallback to class.igetattr since it has some logic to handle 

292 # descriptors 

293 # But only if the _proxied is the Class. 

294 if self._proxied.__class__.__name__ != "ClassDef": 

295 raise 

296 attrs = self._proxied.igetattr(name, context, class_context=False) 

297 yield from self._wrap_attr(attrs, context) 

298 except AttributeInferenceError as error: 

299 raise InferenceError(**vars(error)) from error 

300 

301 def _wrap_attr( 

302 self, attrs: Iterable[InferenceResult], context: InferenceContext | None = None 

303 ) -> Iterator[InferenceResult]: 

304 """Wrap bound methods of attrs in a InstanceMethod proxies.""" 

305 for attr in attrs: 

306 if isinstance(attr, UnboundMethod): 

307 if _is_property(attr): 

308 yield from attr.infer_call_result(self, context) 

309 else: 

310 yield BoundMethod(attr, self) 

311 elif isinstance(attr, nodes.Lambda): 

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

313 yield BoundMethod(attr, self) 

314 continue 

315 yield attr 

316 else: 

317 yield attr 

318 

319 def infer_call_result( 

320 self, 

321 caller: SuccessfulInferenceResult | None, 

322 context: InferenceContext | None = None, 

323 ) -> Iterator[InferenceResult]: 

324 """Infer what a class instance is returning when called.""" 

325 context = bind_context_to_node(context, self) 

326 inferred = False 

327 

328 # If the call is an attribute on the instance, we infer the attribute itself 

329 if isinstance(caller, nodes.Call) and isinstance(caller.func, nodes.Attribute): 

330 for res in self.igetattr(caller.func.attrname, context): 

331 inferred = True 

332 yield res 

333 

334 # Otherwise we infer the call to the __call__ dunder normally 

335 for node in self._proxied.igetattr("__call__", context): 

336 if isinstance(node, UninferableBase) or not node.callable(): 

337 continue 

338 if isinstance(node, BaseInstance) and node._proxied is self._proxied: 

339 inferred = True 

340 yield node 

341 # Prevent recursion. 

342 continue 

343 for res in node.infer_call_result(caller, context): 

344 inferred = True 

345 yield res 

346 if not inferred: 

347 raise InferenceError(node=self, caller=caller, context=context) 

348 

349 

350class Instance(BaseInstance): 

351 """A special node representing a class instance.""" 

352 

353 special_attributes = objectmodel.InstanceModel() 

354 

355 def __init__(self, proxied: nodes.ClassDef | None) -> None: 

356 super().__init__(proxied) 

357 

358 @decorators.yes_if_nothing_inferred 

359 def infer_binary_op( 

360 self, 

361 opnode: nodes.AugAssign | nodes.BinOp, 

362 operator: str, 

363 other: InferenceResult, 

364 context: InferenceContext, 

365 method: SuccessfulInferenceResult, 

366 ) -> Generator[InferenceResult]: 

367 return method.infer_call_result(self, context) 

368 

369 def __repr__(self) -> str: 

370 return "<Instance of {}.{} at 0x{}>".format( 

371 self._proxied.root().name, self._proxied.name, id(self) 

372 ) 

373 

374 def __str__(self) -> str: 

375 return f"Instance of {self._proxied.root().name}.{self._proxied.name}" 

376 

377 def callable(self) -> bool: 

378 try: 

379 self._proxied.getattr("__call__", class_context=False) 

380 return True 

381 except AttributeInferenceError: 

382 return False 

383 

384 def pytype(self) -> str: 

385 return self._proxied.qname() 

386 

387 def display_type(self) -> str: 

388 return "Instance of" 

389 

390 def bool_value( 

391 self, context: InferenceContext | None = None 

392 ) -> bool | UninferableBase: 

393 """Infer the truth value for an Instance. 

394 

395 The truth value of an instance is determined by these conditions: 

396 

397 * if it implements __bool__ on Python 3 or __nonzero__ 

398 on Python 2, then its bool value will be determined by 

399 calling this special method and checking its result. 

400 * when this method is not defined, __len__() is called, if it 

401 is defined, and the object is considered true if its result is 

402 nonzero. If a class defines neither __len__() nor __bool__(), 

403 all its instances are considered true. 

404 """ 

405 context = context or InferenceContext() 

406 context.boundnode = self 

407 

408 try: 

409 result = _infer_method_result_truth(self, "__bool__", context) 

410 except (InferenceError, AttributeInferenceError): 

411 # Fallback to __len__. 

412 try: 

413 result = _infer_method_result_truth(self, "__len__", context) 

414 except (AttributeInferenceError, InferenceError): 

415 return True 

416 return result 

417 

418 def getitem( 

419 self, index: nodes.Const, context: InferenceContext | None = None 

420 ) -> InferenceResult | None: 

421 new_context = bind_context_to_node(context, self) 

422 if not context: 

423 context = new_context 

424 method = next(self.igetattr("__getitem__", context=context), None) 

425 # Create a new CallContext for providing index as an argument. 

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

427 if not isinstance(method, BoundMethod): 

428 raise InferenceError( 

429 "Could not find __getitem__ for {node!r}.", node=self, context=context 

430 ) 

431 if len(method.args.arguments) != 2: # (self, index) 

432 raise AstroidTypeError( 

433 "__getitem__ for {node!r} does not have correct signature", 

434 node=self, 

435 context=context, 

436 ) 

437 return next(method.infer_call_result(self, new_context), None) 

438 

439 

440class UnboundMethod(Proxy): 

441 """A special node representing a method not bound to an instance.""" 

442 

443 _proxied: nodes.FunctionDef | UnboundMethod 

444 

445 special_attributes: ( 

446 objectmodel.BoundMethodModel | objectmodel.UnboundMethodModel 

447 ) = objectmodel.UnboundMethodModel() 

448 

449 def __repr__(self) -> str: 

450 assert self._proxied.parent, "Expected a parent node" 

451 frame = self._proxied.parent.frame() 

452 return "<{} {} of {} at 0x{}".format( 

453 self.__class__.__name__, self._proxied.name, frame.qname(), id(self) 

454 ) 

455 

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

457 return 0 

458 

459 def is_bound(self) -> bool: 

460 return False 

461 

462 def getattr(self, name: str, context: InferenceContext | None = None): 

463 if name in self.special_attributes: 

464 return [self.special_attributes.lookup(name)] 

465 return self._proxied.getattr(name, context) 

466 

467 def igetattr( 

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

469 ) -> Iterator[InferenceResult]: 

470 if name in self.special_attributes: 

471 return iter((self.special_attributes.lookup(name),)) 

472 return self._proxied.igetattr(name, context) 

473 

474 def infer_call_result( 

475 self, 

476 caller: SuccessfulInferenceResult | None, 

477 context: InferenceContext | None = None, 

478 ) -> Iterator[InferenceResult]: 

479 """ 

480 The boundnode of the regular context with a function called 

481 on ``object.__new__`` will be of type ``object``, 

482 which is incorrect for the argument in general. 

483 If no context is given the ``object.__new__`` call argument will 

484 be correctly inferred except when inside a call that requires 

485 the additional context (such as a classmethod) of the boundnode 

486 to determine which class the method was called from 

487 """ 

488 

489 # If we're unbound method __new__ of a builtin, the result is an 

490 # instance of the class given as first argument. 

491 if self._proxied.name == "__new__": 

492 assert self._proxied.parent, "Expected a parent node" 

493 qname = self._proxied.parent.frame().qname() 

494 # Avoid checking builtins.type: _infer_type_new_call() does more validation 

495 if qname.startswith("builtins.") and qname != "builtins.type": 

496 return self._infer_builtin_new(caller, context or InferenceContext()) 

497 return self._proxied.infer_call_result(caller, context) 

498 

499 def _infer_builtin_new( 

500 self, 

501 caller: SuccessfulInferenceResult | None, 

502 context: InferenceContext, 

503 ) -> collections.abc.Generator[nodes.Const | Instance | UninferableBase]: 

504 if not isinstance(caller, nodes.Call): 

505 return 

506 if not caller.args: 

507 return 

508 # Attempt to create a constant 

509 if len(caller.args) > 1: 

510 value = None 

511 if isinstance(caller.args[1], nodes.Const): 

512 value = caller.args[1].value 

513 else: 

514 inferred_arg = next(caller.args[1].infer(), None) 

515 if isinstance(inferred_arg, nodes.Const): 

516 value = inferred_arg.value 

517 if value is not None: 

518 const = nodes.const_factory(value) 

519 assert not isinstance(const, nodes.EmptyNode) 

520 yield const 

521 return 

522 

523 node_context = context.extra_context.get(caller.args[0]) 

524 for inferred in caller.args[0].infer(context=node_context): 

525 if isinstance(inferred, UninferableBase): 

526 yield inferred 

527 if isinstance(inferred, nodes.ClassDef): 

528 yield Instance(inferred) 

529 raise InferenceError 

530 

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

532 return True 

533 

534 

535class BoundMethod(UnboundMethod): 

536 """A special node representing a method bound to an instance.""" 

537 

538 special_attributes = objectmodel.BoundMethodModel() 

539 

540 def __init__( 

541 self, 

542 proxy: nodes.FunctionDef | nodes.Lambda | UnboundMethod, 

543 bound: SuccessfulInferenceResult, 

544 ) -> None: 

545 super().__init__(proxy) 

546 self.bound = bound 

547 

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

549 if self.name == "__new__": 

550 # __new__ acts as a classmethod but the class argument is not implicit. 

551 return 0 

552 return 1 

553 

554 def is_bound(self) -> Literal[True]: 

555 return True 

556 

557 def _infer_type_new_call( 

558 self, caller: nodes.Call, context: InferenceContext 

559 ) -> nodes.ClassDef | None: # noqa: C901 

560 """Try to infer what type.__new__(mcs, name, bases, attrs) returns. 

561 

562 In order for such call to be valid, the metaclass needs to be 

563 a subtype of ``type``, the name needs to be a string, the bases 

564 needs to be a tuple of classes 

565 """ 

566 # pylint: disable=import-outside-toplevel; circular import 

567 from astroid.nodes import Pass 

568 

569 # Verify the metaclass 

570 try: 

571 mcs = next(caller.args[0].infer(context=context)) 

572 except StopIteration as e: 

573 raise InferenceError(context=context) from e 

574 if not isinstance(mcs, nodes.ClassDef): 

575 # Not a valid first argument. 

576 raise InferenceError( 

577 "type.__new__() requires a class for metaclass", context=context 

578 ) 

579 if not mcs.is_subtype_of("builtins.type"): 

580 # Not a valid metaclass. 

581 raise InferenceError( 

582 "type.__new__() metaclass must be a subclass of type", context=context 

583 ) 

584 

585 # Verify the name 

586 try: 

587 name = next(caller.args[1].infer(context=context)) 

588 except StopIteration as e: 

589 raise InferenceError(context=context) from e 

590 if not isinstance(name, nodes.Const): 

591 # Not a valid name, needs to be a const. 

592 raise InferenceError( 

593 "type.__new__() requires a constant for name", context=context 

594 ) 

595 if not isinstance(name.value, str): 

596 # Needs to be a string. 

597 raise InferenceError( 

598 "type.__new__() requires a string for name", context=context 

599 ) 

600 

601 # Verify the bases 

602 try: 

603 bases = next(caller.args[2].infer(context=context)) 

604 except StopIteration as e: 

605 raise InferenceError(context=context) from e 

606 if not isinstance(bases, nodes.Tuple): 

607 # Needs to be a tuple. 

608 raise InferenceError( 

609 "type.__new__() requires a tuple for bases", context=context 

610 ) 

611 try: 

612 inferred_bases = [next(elt.infer(context=context)) for elt in bases.elts] 

613 except StopIteration as e: 

614 raise InferenceError(context=context) from e 

615 if any(not isinstance(base, nodes.ClassDef) for base in inferred_bases): 

616 # All the bases needs to be Classes 

617 raise InferenceError( 

618 "type.__new__() requires classes for bases", context=context 

619 ) 

620 

621 # Verify the attributes. 

622 try: 

623 attrs = next(caller.args[3].infer(context=context)) 

624 except StopIteration as e: 

625 raise InferenceError(context=context) from e 

626 if not isinstance(attrs, nodes.Dict): 

627 # Needs to be a dictionary. 

628 raise InferenceError( 

629 "type.__new__() requires a dict for attrs", context=context 

630 ) 

631 cls_locals: dict[str, list[InferenceResult]] = collections.defaultdict(list) 

632 for key, value in attrs.items: 

633 try: 

634 key = next(key.infer(context=context)) 

635 except StopIteration as e: 

636 raise InferenceError(context=context) from e 

637 try: 

638 value = next(value.infer(context=context)) 

639 except StopIteration as e: 

640 raise InferenceError(context=context) from e 

641 # Ignore non string keys 

642 if isinstance(key, nodes.Const) and isinstance(key.value, str): 

643 cls_locals[key.value].append(value) 

644 

645 # Build the class from now. 

646 cls = mcs.__class__( 

647 name=name.value, 

648 lineno=caller.lineno or 0, 

649 col_offset=caller.col_offset or 0, 

650 parent=caller, 

651 end_lineno=caller.end_lineno, 

652 end_col_offset=caller.end_col_offset, 

653 ) 

654 empty = Pass( 

655 parent=cls, 

656 lineno=caller.lineno, 

657 col_offset=caller.col_offset, 

658 end_lineno=caller.end_lineno, 

659 end_col_offset=caller.end_col_offset, 

660 ) 

661 cls.postinit( 

662 bases=bases.elts, 

663 body=[empty], 

664 decorators=None, 

665 newstyle=True, 

666 metaclass=mcs, 

667 keywords=[], 

668 ) 

669 cls.locals = cls_locals 

670 return cls 

671 

672 def infer_call_result( 

673 self, 

674 caller: SuccessfulInferenceResult | None, 

675 context: InferenceContext | None = None, 

676 ) -> Iterator[InferenceResult]: 

677 context = bind_context_to_node(context, self.bound) 

678 if ( 

679 isinstance(self.bound, nodes.ClassDef) 

680 and self.bound.name == "type" 

681 and self.name == "__new__" 

682 and isinstance(caller, nodes.Call) 

683 ): 

684 # Check if we have a ``type.__new__(mcs, name, bases, attrs)`` call. 

685 if len(caller.args) != 4: 

686 raise InferenceError( 

687 f"type.__new__() requires 4 arguments, got {len(caller.args)}", 

688 context=context, 

689 ) 

690 new_cls = self._infer_type_new_call(caller, context) 

691 if new_cls: 

692 return iter((new_cls,)) 

693 

694 return super().infer_call_result(caller, context) 

695 

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

697 return True 

698 

699 

700class Generator(BaseInstance): 

701 """A special node representing a generator. 

702 

703 Proxied class is set once for all in raw_building. 

704 """ 

705 

706 # We defer initialization of special_attributes to the __init__ method since the constructor 

707 # of GeneratorModel requires the raw_building to be complete 

708 # TODO: This should probably be refactored. 

709 special_attributes: objectmodel.GeneratorBaseModel 

710 

711 def __init__( 

712 self, 

713 parent: nodes.FunctionDef, 

714 generator_initial_context: InferenceContext | None = None, 

715 ) -> None: 

716 super().__init__() 

717 self.parent = parent 

718 self._call_context = copy_context(generator_initial_context) 

719 

720 # See comment above: this is a deferred initialization. 

721 Generator.special_attributes = objectmodel.GeneratorModel() 

722 

723 def infer_yield_types(self) -> Iterator[InferenceResult]: 

724 yield from self.parent.infer_yield_result(self._call_context) 

725 

726 def callable(self) -> Literal[False]: 

727 return False 

728 

729 def pytype(self) -> str: 

730 return "builtins.generator" 

731 

732 def display_type(self) -> str: 

733 return "Generator" 

734 

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

736 return True 

737 

738 def __repr__(self) -> str: 

739 return f"<Generator({self._proxied.name}) l.{self.lineno} at 0x{id(self)}>" 

740 

741 def __str__(self) -> str: 

742 return f"Generator({self._proxied.name})" 

743 

744 

745class AsyncGenerator(Generator): 

746 """Special node representing an async generator.""" 

747 

748 def __init__(self, *args, **kwargs): 

749 super().__init__(*args, **kwargs) 

750 AsyncGenerator.special_attributes = objectmodel.AsyncGeneratorModel() 

751 

752 def pytype(self) -> Literal["builtins.async_generator"]: 

753 return "builtins.async_generator" 

754 

755 def display_type(self) -> str: 

756 return "AsyncGenerator" 

757 

758 def __repr__(self) -> str: 

759 return f"<AsyncGenerator({self._proxied.name}) l.{self.lineno} at 0x{id(self)}>" 

760 

761 def __str__(self) -> str: 

762 return f"AsyncGenerator({self._proxied.name})" 

763 

764 

765class UnionType(BaseInstance): 

766 """Special node representing new style typing unions. 

767 

768 Proxied class is set once for all in raw_building. 

769 """ 

770 

771 def __init__( 

772 self, 

773 left: UnionType | nodes.ClassDef | nodes.Const, 

774 right: UnionType | nodes.ClassDef | nodes.Const, 

775 parent: nodes.NodeNG | None = None, 

776 ) -> None: 

777 super().__init__() 

778 self.parent = parent 

779 self.left = left 

780 self.right = right 

781 

782 def callable(self) -> Literal[False]: 

783 return False 

784 

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

786 return True 

787 

788 def pytype(self) -> Literal["types.UnionType"]: 

789 return "types.UnionType" 

790 

791 def display_type(self) -> str: 

792 return "UnionType" 

793 

794 def __repr__(self) -> str: 

795 return f"<UnionType({self._proxied.name}) l.{self.lineno} at 0x{id(self)}>" 

796 

797 def __str__(self) -> str: 

798 return f"UnionType({self._proxied.name})"