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

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

412 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""" 

8 

9from __future__ import annotations 

10 

11import collections 

12import collections.abc 

13from collections.abc import Iterable, Iterator 

14from typing import TYPE_CHECKING, Any, Literal 

15 

16from astroid import decorators, nodes 

17from astroid.const import PY311_PLUS 

18from astroid.context import ( 

19 CallContext, 

20 InferenceContext, 

21 bind_context_to_node, 

22 copy_context, 

23) 

24from astroid.exceptions import ( 

25 AstroidTypeError, 

26 AttributeInferenceError, 

27 InferenceError, 

28 NameInferenceError, 

29) 

30from astroid.interpreter import objectmodel 

31from astroid.typing import ( 

32 InferenceErrorInfo, 

33 InferenceResult, 

34 SuccessfulInferenceResult, 

35) 

36from astroid.util import Uninferable, UninferableBase, safe_infer 

37 

38if TYPE_CHECKING: 

39 from astroid.constraint import Constraint 

40 

41 

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

43# enum.property was added in Python 3.11 

44if PY311_PLUS: 

45 PROPERTIES.add("enum.property") 

46 

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

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

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

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

51# can be too complicated. 

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

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

54# property-like decorator! 

55POSSIBLE_PROPERTIES = { 

56 "cached_property", 

57 "cachedproperty", 

58 "lazyproperty", 

59 "lazy_property", 

60 "reify", 

61 "lazyattribute", 

62 "lazy_attribute", 

63 "LazyProperty", 

64 "lazy", 

65 "cache_readonly", 

66 "DynamicClassAttribute", 

67} 

68 

69 

70def _is_property( 

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

72) -> bool: 

73 decoratornames = meth.decoratornames(context=context) 

74 if PROPERTIES.intersection(decoratornames): 

75 return True 

76 stripped = { 

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

78 for name in decoratornames 

79 if not isinstance(name, UninferableBase) 

80 } 

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

82 return True 

83 

84 if not meth.decorators: 

85 return False 

86 # Lookup for subclasses of *property* 

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

88 inferred = safe_infer(decorator, context=context) 

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

90 continue 

91 if isinstance(inferred, nodes.ClassDef): 

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

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

94 return True 

95 for base_class in inferred.bases: 

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

97 # and includes a subscripted type annotation 

98 if isinstance(base_class, nodes.Subscript): 

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

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

101 continue 

102 if value.name != "cached_property": 

103 continue 

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

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

106 return True 

107 continue 

108 

109 return False 

110 

111 

112class Proxy: 

113 """A simple proxy object. 

114 

115 Note: 

116 

117 Subclasses of this object will need a custom __getattr__ 

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

119 """ 

120 

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

122 

123 def __init__( 

124 self, 

125 proxied: ( 

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

127 ) = None, 

128 ) -> None: 

129 if proxied is None: 

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

131 # builtin classes and their docstrings. 

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

133 # is set during bootstrapping 

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

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

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

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

138 else: 

139 self._proxied = proxied 

140 

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

142 if name == "_proxied": 

143 return self.__class__._proxied 

144 if name in self.__dict__: 

145 return self.__dict__[name] 

146 return getattr(self._proxied, name) 

147 

148 def infer( # type: ignore[return] 

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

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

151 yield self 

152 

153 

154def _infer_stmts( 

155 stmts: Iterable[InferenceResult], 

156 context: InferenceContext | None, 

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

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

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

160 inferred = False 

161 constraint_failed = False 

162 if context is not None: 

163 name = context.lookupname 

164 context = context.clone() 

165 if name is not None: 

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

167 else: 

168 constraints = {} 

169 else: 

170 name = None 

171 constraints = {} 

172 context = InferenceContext() 

173 

174 for stmt in stmts: 

175 if isinstance(stmt, UninferableBase): 

176 yield stmt 

177 inferred = True 

178 continue 

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

180 try: 

181 stmt_constraints: set[Constraint] = set() 

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

183 if not constraint_stmt.parent_of(stmt): 

184 stmt_constraints.update(potential_constraints) 

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

186 if all( 

187 constraint.satisfied_by(inf, context) 

188 for constraint in stmt_constraints 

189 ): 

190 yield inf 

191 inferred = True 

192 else: 

193 constraint_failed = True 

194 except NameInferenceError: 

195 continue 

196 except InferenceError: 

197 yield Uninferable 

198 inferred = True 

199 

200 if not inferred and constraint_failed: 

201 yield Uninferable 

202 elif not inferred: 

203 raise InferenceError( 

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

205 stmts=stmts, 

206 frame=frame, 

207 context=context, 

208 ) 

209 

210 

211def _infer_method_result_truth( 

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

213) -> bool | UninferableBase: 

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

215 # its return's truth value. 

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

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

218 if not meth.callable(): 

219 return Uninferable 

220 try: 

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

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

223 if isinstance(value, UninferableBase): 

224 return value 

225 try: 

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

227 except StopIteration as e: 

228 raise InferenceError(context=context) from e 

229 return inferred.bool_value() 

230 except InferenceError: 

231 pass 

232 return Uninferable 

233 

234 

235class BaseInstance(Proxy): 

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

237 instances. 

238 """ 

239 

240 _proxied: nodes.ClassDef 

241 

242 special_attributes: objectmodel.ObjectModel 

243 

244 def display_type(self) -> str: 

245 return "Instance of" 

246 

247 def getattr( 

248 self, 

249 name: str, 

250 context: InferenceContext | None = None, 

251 lookupclass: bool = True, 

252 ) -> list[InferenceResult]: 

253 try: 

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

255 except AttributeInferenceError as exc: 

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

257 special_attr = self.special_attributes.lookup(name) 

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

259 return [special_attr] 

260 

261 if lookupclass: 

262 # Class attributes not available through the instance 

263 # unless they are explicitly defined. 

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

265 

266 raise AttributeInferenceError( 

267 target=self, attribute=name, context=context 

268 ) from exc 

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

270 # well 

271 if lookupclass: 

272 try: 

273 return values + self._proxied.getattr( 

274 name, context, class_context=False 

275 ) 

276 except AttributeInferenceError: 

277 pass 

278 return values 

279 

280 def igetattr( 

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

282 ) -> Iterator[InferenceResult]: 

283 """Inferred getattr.""" 

284 if not context: 

285 context = InferenceContext() 

286 try: 

287 context.lookupname = name 

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

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

290 yield from _infer_stmts( 

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

292 ) 

293 except AttributeInferenceError: 

294 try: 

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

296 # descriptors 

297 # But only if the _proxied is the Class. 

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

299 raise 

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

301 yield from self._wrap_attr(attrs, context) 

302 except AttributeInferenceError as error: 

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

304 

305 def _wrap_attr( 

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

307 ) -> Iterator[InferenceResult]: 

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

309 for attr in attrs: 

310 if isinstance(attr, UnboundMethod): 

311 if _is_property(attr): 

312 yield from attr.infer_call_result(self, context) 

313 else: 

314 yield BoundMethod(attr, self) 

315 elif isinstance(attr, nodes.Lambda): 

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

317 yield BoundMethod(attr, self) 

318 continue 

319 yield attr 

320 else: 

321 yield attr 

322 

323 def infer_call_result( 

324 self, 

325 caller: SuccessfulInferenceResult | None, 

326 context: InferenceContext | None = None, 

327 ) -> Iterator[InferenceResult]: 

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

329 context = bind_context_to_node(context, self) 

330 inferred = False 

331 

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

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

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

335 inferred = True 

336 yield res 

337 

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

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

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

341 continue 

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

343 inferred = True 

344 yield node 

345 # Prevent recursion. 

346 continue 

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

348 inferred = True 

349 yield res 

350 if not inferred: 

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

352 

353 

354class Instance(BaseInstance): 

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

356 

357 special_attributes = objectmodel.InstanceModel() 

358 

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

360 super().__init__(proxied) 

361 

362 @decorators.yes_if_nothing_inferred 

363 def infer_binary_op( 

364 self, 

365 opnode: nodes.AugAssign | nodes.BinOp, 

366 operator: str, 

367 other: InferenceResult, 

368 context: InferenceContext, 

369 method: SuccessfulInferenceResult, 

370 ) -> Generator[InferenceResult]: 

371 return method.infer_call_result(self, context) 

372 

373 def __repr__(self) -> str: 

374 return f"<Instance of {self._proxied.root().name}.{self._proxied.name} at 0x{id(self)}>" 

375 

376 def __str__(self) -> str: 

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

378 

379 def callable(self) -> bool: 

380 try: 

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

382 return True 

383 except AttributeInferenceError: 

384 return False 

385 

386 def pytype(self) -> str: 

387 return self._proxied.qname() 

388 

389 def display_type(self) -> str: 

390 return "Instance of" 

391 

392 def bool_value( 

393 self, context: InferenceContext | None = None 

394 ) -> bool | UninferableBase: 

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

396 

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

398 

399 * if it implements __bool__ on Python 3 or __nonzero__ 

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

401 calling this special method and checking its result. 

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

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

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

405 all its instances are considered true. 

406 """ 

407 context = context or InferenceContext() 

408 context.boundnode = self 

409 

410 try: 

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

412 except (InferenceError, AttributeInferenceError): 

413 # Fallback to __len__. 

414 try: 

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

416 except (AttributeInferenceError, InferenceError): 

417 return True 

418 return result 

419 

420 def getitem( 

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

422 ) -> InferenceResult | None: 

423 new_context = bind_context_to_node(context, self) 

424 if not context: 

425 context = new_context 

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

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

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

429 if not isinstance(method, BoundMethod): 

430 raise InferenceError( 

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

432 ) 

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

434 raise AstroidTypeError( 

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

436 node=self, 

437 context=context, 

438 ) 

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

440 

441 

442class UnboundMethod(Proxy): 

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

444 

445 _proxied: nodes.FunctionDef | UnboundMethod 

446 

447 special_attributes: ( 

448 objectmodel.BoundMethodModel | objectmodel.UnboundMethodModel 

449 ) = objectmodel.UnboundMethodModel() 

450 

451 def __repr__(self) -> str: 

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

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

454 return f"<{self.__class__.__name__} {self._proxied.name} of {frame.qname()} at 0x{id(self)}" 

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 special_attr = self.special_attributes.lookup(name) 

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

466 return [special_attr] 

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

468 

469 def igetattr( 

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

471 ) -> Iterator[InferenceResult]: 

472 if name in self.special_attributes: 

473 special_attr = self.special_attributes.lookup(name) 

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

475 return iter((special_attr,)) 

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

477 

478 def infer_call_result( 

479 self, 

480 caller: SuccessfulInferenceResult | None, 

481 context: InferenceContext | None = None, 

482 ) -> Iterator[InferenceResult]: 

483 """ 

484 The boundnode of the regular context with a function called 

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

486 which is incorrect for the argument in general. 

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

488 be correctly inferred except when inside a call that requires 

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

490 to determine which class the method was called from 

491 """ 

492 

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

494 # instance of the class given as first argument. 

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

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

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

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

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

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

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

502 

503 def _infer_builtin_new( 

504 self, 

505 caller: SuccessfulInferenceResult | None, 

506 context: InferenceContext, 

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

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

509 return 

510 if not caller.args: 

511 return 

512 # Attempt to create a constant 

513 if len(caller.args) > 1: 

514 value = None 

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

516 value = caller.args[1].value 

517 else: 

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

519 if isinstance(inferred_arg, nodes.Const): 

520 value = inferred_arg.value 

521 if value is not None: 

522 const = nodes.const_factory(value) 

523 assert not isinstance(const, nodes.EmptyNode) 

524 yield const 

525 return 

526 

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

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

529 if isinstance(inferred, UninferableBase): 

530 yield inferred 

531 if isinstance(inferred, nodes.ClassDef): 

532 yield Instance(inferred) 

533 raise InferenceError 

534 

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

536 return True 

537 

538 

539class BoundMethod(UnboundMethod): 

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

541 

542 special_attributes = objectmodel.BoundMethodModel() 

543 

544 def __init__( 

545 self, 

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

547 bound: SuccessfulInferenceResult, 

548 original_caller: SuccessfulInferenceResult | None = None, 

549 ) -> None: 

550 super().__init__(proxy) 

551 self.bound = bound 

552 # For super() calls: the actual instance/class that called super() 

553 # Used to correctly infer return type of methods returning Self 

554 self.original_caller = original_caller 

555 

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

557 if self.name == "__new__": 

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

559 return 0 

560 return 1 

561 

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

563 return True 

564 

565 def _infer_type_new_call( 

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

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

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

569 

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

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

572 needs to be a tuple of classes 

573 """ 

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

575 from astroid.nodes import Pass 

576 

577 # Verify the metaclass 

578 try: 

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

580 except StopIteration as e: 

581 raise InferenceError(context=context) from e 

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

583 # Not a valid first argument. 

584 raise InferenceError( 

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

586 ) 

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

588 # Not a valid metaclass. 

589 raise InferenceError( 

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

591 ) 

592 

593 # Verify the name 

594 try: 

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

596 except StopIteration as e: 

597 raise InferenceError(context=context) from e 

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

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

600 raise InferenceError( 

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

602 ) 

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

604 # Needs to be a string. 

605 raise InferenceError( 

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

607 ) 

608 

609 # Verify the bases 

610 try: 

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

612 except StopIteration as e: 

613 raise InferenceError(context=context) from e 

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

615 # Needs to be a tuple. 

616 raise InferenceError( 

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

618 ) 

619 try: 

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

621 except StopIteration as e: 

622 raise InferenceError(context=context) from e 

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

624 # All the bases needs to be Classes 

625 raise InferenceError( 

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

627 ) 

628 

629 # Verify the attributes. 

630 try: 

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

632 except StopIteration as e: 

633 raise InferenceError(context=context) from e 

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

635 # Needs to be a dictionary. 

636 raise InferenceError( 

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

638 ) 

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

640 for key, value in attrs.items: 

641 try: 

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

643 except StopIteration as e: 

644 raise InferenceError(context=context) from e 

645 try: 

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

647 except StopIteration as e: 

648 raise InferenceError(context=context) from e 

649 # Ignore non string keys 

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

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

652 

653 # Build the class from now. 

654 cls = mcs.__class__( 

655 name=name.value, 

656 lineno=caller.lineno or 0, 

657 col_offset=caller.col_offset or 0, 

658 parent=caller, 

659 end_lineno=caller.end_lineno, 

660 end_col_offset=caller.end_col_offset, 

661 ) 

662 empty = Pass( 

663 parent=cls, 

664 lineno=caller.lineno, 

665 col_offset=caller.col_offset, 

666 end_lineno=caller.end_lineno, 

667 end_col_offset=caller.end_col_offset, 

668 ) 

669 cls.postinit( 

670 bases=bases.elts, 

671 body=[empty], 

672 decorators=None, 

673 newstyle=True, 

674 metaclass=mcs, 

675 keywords=[], 

676 ) 

677 cls.locals = cls_locals 

678 return cls 

679 

680 def infer_call_result( 

681 self, 

682 caller: SuccessfulInferenceResult | None, 

683 context: InferenceContext | None = None, 

684 ) -> Iterator[InferenceResult]: 

685 # For super() calls, use original_caller to correctly infer Self return type 

686 bound_node = self.original_caller if self.original_caller else self.bound 

687 context = bind_context_to_node(context, bound_node) 

688 if ( 

689 isinstance(self.bound, nodes.ClassDef) 

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

691 and self.name == "__new__" 

692 and isinstance(caller, nodes.Call) 

693 ): 

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

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

696 raise InferenceError( 

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

698 context=context, 

699 ) 

700 new_cls = self._infer_type_new_call(caller, context) 

701 if new_cls: 

702 return iter((new_cls,)) 

703 

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

705 

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

707 return True 

708 

709 

710class Generator(BaseInstance): 

711 """A special node representing a generator. 

712 

713 Proxied class is set once for all in raw_building. 

714 """ 

715 

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

717 # of GeneratorModel requires the raw_building to be complete 

718 # TODO: This should probably be refactored. 

719 special_attributes: objectmodel.GeneratorBaseModel 

720 

721 def __init__( 

722 self, 

723 parent: nodes.FunctionDef, 

724 generator_initial_context: InferenceContext | None = None, 

725 ) -> None: 

726 super().__init__() 

727 self.parent = parent 

728 self._call_context = copy_context(generator_initial_context) 

729 

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

731 Generator.special_attributes = objectmodel.GeneratorModel() 

732 

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

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

735 

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

737 return False 

738 

739 def pytype(self) -> str: 

740 return "builtins.generator" 

741 

742 def display_type(self) -> str: 

743 return "Generator" 

744 

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

746 return True 

747 

748 def __repr__(self) -> str: 

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

750 

751 def __str__(self) -> str: 

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

753 

754 

755class AsyncGenerator(Generator): 

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

757 

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

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

760 AsyncGenerator.special_attributes = objectmodel.AsyncGeneratorModel() 

761 

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

763 return "builtins.async_generator" 

764 

765 def display_type(self) -> str: 

766 return "AsyncGenerator" 

767 

768 def __repr__(self) -> str: 

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

770 

771 def __str__(self) -> str: 

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

773 

774 

775class UnionType(BaseInstance): 

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

777 

778 Proxied class is set once for all in raw_building. 

779 """ 

780 

781 def __init__( 

782 self, 

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

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

785 parent: nodes.NodeNG | None = None, 

786 ) -> None: 

787 super().__init__() 

788 self.parent = parent 

789 self.left = left 

790 self.right = right 

791 

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

793 return False 

794 

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

796 return True 

797 

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

799 return "types.UnionType" 

800 

801 def display_type(self) -> str: 

802 return "UnionType" 

803 

804 def __repr__(self) -> str: 

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

806 

807 def __str__(self) -> str: 

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