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
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
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
5"""This module contains base classes and functions for the nodes and some
6inference utils.
7"""
8from __future__ import annotations
10import collections
11import collections.abc
12from collections.abc import Iterable, Iterator
13from typing import TYPE_CHECKING, Any, Literal
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
37if TYPE_CHECKING:
38 from astroid.constraint import Constraint
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")
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}
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
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
108 return False
111class Proxy:
112 """A simple proxy object.
114 Note:
116 Subclasses of this object will need a custom __getattr__
117 if new instance attributes are created. See the Const class
118 """
120 _proxied: nodes.ClassDef | nodes.FunctionDef | nodes.Lambda | UnboundMethod
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
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)
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
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()
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
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 )
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
231class BaseInstance(Proxy):
232 """An instance base class, which provides lookup methods for potential
233 instances.
234 """
236 _proxied: nodes.ClassDef
238 special_attributes: objectmodel.ObjectModel
240 def display_type(self) -> str:
241 return "Instance of"
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]
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)
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
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
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
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
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
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)
350class Instance(BaseInstance):
351 """A special node representing a class instance."""
353 special_attributes = objectmodel.InstanceModel()
355 def __init__(self, proxied: nodes.ClassDef | None) -> None:
356 super().__init__(proxied)
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)
369 def __repr__(self) -> str:
370 return "<Instance of {}.{} at 0x{}>".format(
371 self._proxied.root().name, self._proxied.name, id(self)
372 )
374 def __str__(self) -> str:
375 return f"Instance of {self._proxied.root().name}.{self._proxied.name}"
377 def callable(self) -> bool:
378 try:
379 self._proxied.getattr("__call__", class_context=False)
380 return True
381 except AttributeInferenceError:
382 return False
384 def pytype(self) -> str:
385 return self._proxied.qname()
387 def display_type(self) -> str:
388 return "Instance of"
390 def bool_value(
391 self, context: InferenceContext | None = None
392 ) -> bool | UninferableBase:
393 """Infer the truth value for an Instance.
395 The truth value of an instance is determined by these conditions:
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
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
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)
440class UnboundMethod(Proxy):
441 """A special node representing a method not bound to an instance."""
443 _proxied: nodes.FunctionDef | UnboundMethod
445 special_attributes: (
446 objectmodel.BoundMethodModel | objectmodel.UnboundMethodModel
447 ) = objectmodel.UnboundMethodModel()
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 )
456 def implicit_parameters(self) -> Literal[0, 1]:
457 return 0
459 def is_bound(self) -> bool:
460 return False
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)
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)
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 """
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)
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
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
531 def bool_value(self, context: InferenceContext | None = None) -> Literal[True]:
532 return True
535class BoundMethod(UnboundMethod):
536 """A special node representing a method bound to an instance."""
538 special_attributes = objectmodel.BoundMethodModel()
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
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
554 def is_bound(self) -> Literal[True]:
555 return True
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.
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
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 )
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 )
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 )
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)
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
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,))
694 return super().infer_call_result(caller, context)
696 def bool_value(self, context: InferenceContext | None = None) -> Literal[True]:
697 return True
700class Generator(BaseInstance):
701 """A special node representing a generator.
703 Proxied class is set once for all in raw_building.
704 """
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
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)
720 # See comment above: this is a deferred initialization.
721 Generator.special_attributes = objectmodel.GeneratorModel()
723 def infer_yield_types(self) -> Iterator[InferenceResult]:
724 yield from self.parent.infer_yield_result(self._call_context)
726 def callable(self) -> Literal[False]:
727 return False
729 def pytype(self) -> str:
730 return "builtins.generator"
732 def display_type(self) -> str:
733 return "Generator"
735 def bool_value(self, context: InferenceContext | None = None) -> Literal[True]:
736 return True
738 def __repr__(self) -> str:
739 return f"<Generator({self._proxied.name}) l.{self.lineno} at 0x{id(self)}>"
741 def __str__(self) -> str:
742 return f"Generator({self._proxied.name})"
745class AsyncGenerator(Generator):
746 """Special node representing an async generator."""
748 def __init__(self, *args, **kwargs):
749 super().__init__(*args, **kwargs)
750 AsyncGenerator.special_attributes = objectmodel.AsyncGeneratorModel()
752 def pytype(self) -> Literal["builtins.async_generator"]:
753 return "builtins.async_generator"
755 def display_type(self) -> str:
756 return "AsyncGenerator"
758 def __repr__(self) -> str:
759 return f"<AsyncGenerator({self._proxied.name}) l.{self.lineno} at 0x{id(self)}>"
761 def __str__(self) -> str:
762 return f"AsyncGenerator({self._proxied.name})"
765class UnionType(BaseInstance):
766 """Special node representing new style typing unions.
768 Proxied class is set once for all in raw_building.
769 """
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
782 def callable(self) -> Literal[False]:
783 return False
785 def bool_value(self, context: InferenceContext | None = None) -> Literal[True]:
786 return True
788 def pytype(self) -> Literal["types.UnionType"]:
789 return "types.UnionType"
791 def display_type(self) -> str:
792 return "UnionType"
794 def __repr__(self) -> str:
795 return f"<UnionType({self._proxied.name}) l.{self.lineno} at 0x{id(self)}>"
797 def __str__(self) -> str:
798 return f"UnionType({self._proxied.name})"