bases.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  1. # Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
  2. # For details: https://github.com/PyCQA/astroid/blob/main/LICENSE
  3. # Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt
  4. """This module contains base classes and functions for the nodes and some
  5. inference utils.
  6. """
  7. from __future__ import annotations
  8. import collections
  9. import collections.abc
  10. import sys
  11. from collections.abc import Sequence
  12. from typing import TYPE_CHECKING, Any, ClassVar
  13. from astroid import decorators, nodes
  14. from astroid.const import PY310_PLUS
  15. from astroid.context import (
  16. CallContext,
  17. InferenceContext,
  18. bind_context_to_node,
  19. copy_context,
  20. )
  21. from astroid.exceptions import (
  22. AstroidTypeError,
  23. AttributeInferenceError,
  24. InferenceError,
  25. NameInferenceError,
  26. )
  27. from astroid.typing import InferBinaryOp, InferenceErrorInfo, InferenceResult
  28. from astroid.util import Uninferable, UninferableBase, lazy_descriptor, lazy_import
  29. if sys.version_info >= (3, 8):
  30. from typing import Literal
  31. else:
  32. from typing_extensions import Literal
  33. if TYPE_CHECKING:
  34. from astroid.constraint import Constraint
  35. objectmodel = lazy_import("interpreter.objectmodel")
  36. helpers = lazy_import("helpers")
  37. manager = lazy_import("manager")
  38. # TODO: check if needs special treatment
  39. BOOL_SPECIAL_METHOD = "__bool__"
  40. BUILTINS = "builtins" # TODO Remove in 2.8
  41. PROPERTIES = {"builtins.property", "abc.abstractproperty"}
  42. if PY310_PLUS:
  43. PROPERTIES.add("enum.property")
  44. # List of possible property names. We use this list in order
  45. # to see if a method is a property or not. This should be
  46. # pretty reliable and fast, the alternative being to check each
  47. # decorator to see if its a real property-like descriptor, which
  48. # can be too complicated.
  49. # Also, these aren't qualified, because each project can
  50. # define them, we shouldn't expect to know every possible
  51. # property-like decorator!
  52. POSSIBLE_PROPERTIES = {
  53. "cached_property",
  54. "cachedproperty",
  55. "lazyproperty",
  56. "lazy_property",
  57. "reify",
  58. "lazyattribute",
  59. "lazy_attribute",
  60. "LazyProperty",
  61. "lazy",
  62. "cache_readonly",
  63. "DynamicClassAttribute",
  64. }
  65. def _is_property(meth, context: InferenceContext | None = None) -> bool:
  66. decoratornames = meth.decoratornames(context=context)
  67. if PROPERTIES.intersection(decoratornames):
  68. return True
  69. stripped = {
  70. name.split(".")[-1]
  71. for name in decoratornames
  72. if not isinstance(name, UninferableBase)
  73. }
  74. if any(name in stripped for name in POSSIBLE_PROPERTIES):
  75. return True
  76. # Lookup for subclasses of *property*
  77. if not meth.decorators:
  78. return False
  79. for decorator in meth.decorators.nodes or ():
  80. inferred = helpers.safe_infer(decorator, context=context)
  81. if inferred is None or isinstance(inferred, UninferableBase):
  82. continue
  83. if inferred.__class__.__name__ == "ClassDef":
  84. for base_class in inferred.bases:
  85. if base_class.__class__.__name__ != "Name":
  86. continue
  87. module, _ = base_class.lookup(base_class.name)
  88. if module.name == "builtins" and base_class.name == "property":
  89. return True
  90. return False
  91. class Proxy:
  92. """A simple proxy object.
  93. Note:
  94. Subclasses of this object will need a custom __getattr__
  95. if new instance attributes are created. See the Const class
  96. """
  97. _proxied: nodes.ClassDef | nodes.Lambda | Proxy | None = (
  98. None # proxied object may be set by class or by instance
  99. )
  100. def __init__(
  101. self, proxied: nodes.ClassDef | nodes.Lambda | Proxy | None = None
  102. ) -> None:
  103. if proxied is None:
  104. # This is a hack to allow calling this __init__ during bootstrapping of
  105. # builtin classes and their docstrings.
  106. # For Const, Generator, and UnionType nodes the _proxied attribute
  107. # is set during bootstrapping
  108. # as we first need to build the ClassDef that they can proxy.
  109. # Thus, if proxied is None self should be a Const or Generator
  110. # as that is the only way _proxied will be correctly set as a ClassDef.
  111. assert isinstance(self, (nodes.Const, Generator, UnionType))
  112. else:
  113. self._proxied = proxied
  114. def __getattr__(self, name):
  115. if name == "_proxied":
  116. return self.__class__._proxied
  117. if name in self.__dict__:
  118. return self.__dict__[name]
  119. return getattr(self._proxied, name)
  120. def infer( # type: ignore[return]
  121. self, context: InferenceContext | None = None, **kwargs: Any
  122. ) -> collections.abc.Generator[InferenceResult, None, InferenceErrorInfo | None]:
  123. yield self
  124. def _infer_stmts(
  125. stmts: Sequence[nodes.NodeNG | UninferableBase | Instance],
  126. context: InferenceContext | None,
  127. frame: nodes.NodeNG | Instance | None = None,
  128. ) -> collections.abc.Generator[InferenceResult, None, None]:
  129. """Return an iterator on statements inferred by each statement in *stmts*."""
  130. inferred = False
  131. constraint_failed = False
  132. if context is not None:
  133. name = context.lookupname
  134. context = context.clone()
  135. constraints = context.constraints.get(name, {})
  136. else:
  137. name = None
  138. constraints = {}
  139. context = InferenceContext()
  140. for stmt in stmts:
  141. if isinstance(stmt, UninferableBase):
  142. yield stmt
  143. inferred = True
  144. continue
  145. # 'context' is always InferenceContext and Instances get '_infer_name' from ClassDef
  146. context.lookupname = stmt._infer_name(frame, name) # type: ignore[union-attr]
  147. try:
  148. stmt_constraints: set[Constraint] = set()
  149. for constraint_stmt, potential_constraints in constraints.items():
  150. if not constraint_stmt.parent_of(stmt):
  151. stmt_constraints.update(potential_constraints)
  152. for inf in stmt.infer(context=context):
  153. if all(constraint.satisfied_by(inf) for constraint in stmt_constraints):
  154. yield inf
  155. inferred = True
  156. else:
  157. constraint_failed = True
  158. except NameInferenceError:
  159. continue
  160. except InferenceError:
  161. yield Uninferable
  162. inferred = True
  163. if not inferred and constraint_failed:
  164. yield Uninferable
  165. elif not inferred:
  166. raise InferenceError(
  167. "Inference failed for all members of {stmts!r}.",
  168. stmts=stmts,
  169. frame=frame,
  170. context=context,
  171. )
  172. def _infer_method_result_truth(instance, method_name, context):
  173. # Get the method from the instance and try to infer
  174. # its return's truth value.
  175. meth = next(instance.igetattr(method_name, context=context), None)
  176. if meth and hasattr(meth, "infer_call_result"):
  177. if not meth.callable():
  178. return Uninferable
  179. try:
  180. context.callcontext = CallContext(args=[], callee=meth)
  181. for value in meth.infer_call_result(instance, context=context):
  182. if isinstance(value, UninferableBase):
  183. return value
  184. try:
  185. inferred = next(value.infer(context=context))
  186. except StopIteration as e:
  187. raise InferenceError(context=context) from e
  188. return inferred.bool_value()
  189. except InferenceError:
  190. pass
  191. return Uninferable
  192. class BaseInstance(Proxy):
  193. """An instance base class, which provides lookup methods for potential
  194. instances.
  195. """
  196. special_attributes = None
  197. def display_type(self) -> str:
  198. return "Instance of"
  199. def getattr(self, name, context: InferenceContext | None = None, lookupclass=True):
  200. try:
  201. values = self._proxied.instance_attr(name, context)
  202. except AttributeInferenceError as exc:
  203. if self.special_attributes and name in self.special_attributes:
  204. return [self.special_attributes.lookup(name)]
  205. if lookupclass:
  206. # Class attributes not available through the instance
  207. # unless they are explicitly defined.
  208. return self._proxied.getattr(name, context, class_context=False)
  209. raise AttributeInferenceError(
  210. target=self, attribute=name, context=context
  211. ) from exc
  212. # since we've no context information, return matching class members as
  213. # well
  214. if lookupclass:
  215. try:
  216. return values + self._proxied.getattr(
  217. name, context, class_context=False
  218. )
  219. except AttributeInferenceError:
  220. pass
  221. return values
  222. def igetattr(self, name, context: InferenceContext | None = None):
  223. """Inferred getattr."""
  224. if not context:
  225. context = InferenceContext()
  226. try:
  227. context.lookupname = name
  228. # avoid recursively inferring the same attr on the same class
  229. if context.push(self._proxied):
  230. raise InferenceError(
  231. message="Cannot infer the same attribute again",
  232. node=self,
  233. context=context,
  234. )
  235. # XXX frame should be self._proxied, or not ?
  236. get_attr = self.getattr(name, context, lookupclass=False)
  237. yield from _infer_stmts(
  238. self._wrap_attr(get_attr, context), context, frame=self
  239. )
  240. except AttributeInferenceError:
  241. try:
  242. # fallback to class.igetattr since it has some logic to handle
  243. # descriptors
  244. # But only if the _proxied is the Class.
  245. if self._proxied.__class__.__name__ != "ClassDef":
  246. raise
  247. attrs = self._proxied.igetattr(name, context, class_context=False)
  248. yield from self._wrap_attr(attrs, context)
  249. except AttributeInferenceError as error:
  250. raise InferenceError(**vars(error)) from error
  251. def _wrap_attr(self, attrs, context: InferenceContext | None = None):
  252. """Wrap bound methods of attrs in a InstanceMethod proxies."""
  253. for attr in attrs:
  254. if isinstance(attr, UnboundMethod):
  255. if _is_property(attr):
  256. yield from attr.infer_call_result(self, context)
  257. else:
  258. yield BoundMethod(attr, self)
  259. elif hasattr(attr, "name") and attr.name == "<lambda>":
  260. if attr.args.arguments and attr.args.arguments[0].name == "self":
  261. yield BoundMethod(attr, self)
  262. continue
  263. yield attr
  264. else:
  265. yield attr
  266. def infer_call_result(
  267. self, caller: nodes.Call | Proxy, context: InferenceContext | None = None
  268. ):
  269. """Infer what a class instance is returning when called."""
  270. context = bind_context_to_node(context, self)
  271. inferred = False
  272. # If the call is an attribute on the instance, we infer the attribute itself
  273. if isinstance(caller, nodes.Call) and isinstance(caller.func, nodes.Attribute):
  274. for res in self.igetattr(caller.func.attrname, context):
  275. inferred = True
  276. yield res
  277. # Otherwise we infer the call to the __call__ dunder normally
  278. for node in self._proxied.igetattr("__call__", context):
  279. if isinstance(node, UninferableBase) or not node.callable():
  280. continue
  281. for res in node.infer_call_result(caller, context):
  282. inferred = True
  283. yield res
  284. if not inferred:
  285. raise InferenceError(node=self, caller=caller, context=context)
  286. class Instance(BaseInstance):
  287. """A special node representing a class instance."""
  288. _proxied: nodes.ClassDef
  289. # pylint: disable=unnecessary-lambda
  290. special_attributes = lazy_descriptor(lambda: objectmodel.InstanceModel())
  291. def __init__(self, proxied: nodes.ClassDef | None) -> None:
  292. super().__init__(proxied)
  293. infer_binary_op: ClassVar[InferBinaryOp[Instance]]
  294. def __repr__(self) -> str:
  295. return "<Instance of {}.{} at 0x{}>".format(
  296. self._proxied.root().name, self._proxied.name, id(self)
  297. )
  298. def __str__(self) -> str:
  299. return f"Instance of {self._proxied.root().name}.{self._proxied.name}"
  300. def callable(self) -> bool:
  301. try:
  302. self._proxied.getattr("__call__", class_context=False)
  303. return True
  304. except AttributeInferenceError:
  305. return False
  306. def pytype(self) -> str:
  307. return self._proxied.qname()
  308. def display_type(self) -> str:
  309. return "Instance of"
  310. def bool_value(self, context: InferenceContext | None = None):
  311. """Infer the truth value for an Instance.
  312. The truth value of an instance is determined by these conditions:
  313. * if it implements __bool__ on Python 3 or __nonzero__
  314. on Python 2, then its bool value will be determined by
  315. calling this special method and checking its result.
  316. * when this method is not defined, __len__() is called, if it
  317. is defined, and the object is considered true if its result is
  318. nonzero. If a class defines neither __len__() nor __bool__(),
  319. all its instances are considered true.
  320. """
  321. context = context or InferenceContext()
  322. context.boundnode = self
  323. try:
  324. result = _infer_method_result_truth(self, BOOL_SPECIAL_METHOD, context)
  325. except (InferenceError, AttributeInferenceError):
  326. # Fallback to __len__.
  327. try:
  328. result = _infer_method_result_truth(self, "__len__", context)
  329. except (AttributeInferenceError, InferenceError):
  330. return True
  331. return result
  332. def getitem(self, index, context: InferenceContext | None = None):
  333. new_context = bind_context_to_node(context, self)
  334. if not context:
  335. context = new_context
  336. method = next(self.igetattr("__getitem__", context=context), None)
  337. # Create a new CallContext for providing index as an argument.
  338. new_context.callcontext = CallContext(args=[index], callee=method)
  339. if not isinstance(method, BoundMethod):
  340. raise InferenceError(
  341. "Could not find __getitem__ for {node!r}.", node=self, context=context
  342. )
  343. if len(method.args.arguments) != 2: # (self, index)
  344. raise AstroidTypeError(
  345. "__getitem__ for {node!r} does not have correct signature",
  346. node=self,
  347. context=context,
  348. )
  349. return next(method.infer_call_result(self, new_context), None)
  350. class UnboundMethod(Proxy):
  351. """A special node representing a method not bound to an instance."""
  352. # pylint: disable=unnecessary-lambda
  353. special_attributes = lazy_descriptor(lambda: objectmodel.UnboundMethodModel())
  354. def __repr__(self) -> str:
  355. frame = self._proxied.parent.frame(future=True)
  356. return "<{} {} of {} at 0x{}".format(
  357. self.__class__.__name__, self._proxied.name, frame.qname(), id(self)
  358. )
  359. def implicit_parameters(self) -> Literal[0]:
  360. return 0
  361. def is_bound(self) -> Literal[False]:
  362. return False
  363. def getattr(self, name, context: InferenceContext | None = None):
  364. if name in self.special_attributes:
  365. return [self.special_attributes.lookup(name)]
  366. return self._proxied.getattr(name, context)
  367. def igetattr(self, name, context: InferenceContext | None = None):
  368. if name in self.special_attributes:
  369. return iter((self.special_attributes.lookup(name),))
  370. return self._proxied.igetattr(name, context)
  371. def infer_call_result(self, caller, context):
  372. """
  373. The boundnode of the regular context with a function called
  374. on ``object.__new__`` will be of type ``object``,
  375. which is incorrect for the argument in general.
  376. If no context is given the ``object.__new__`` call argument will
  377. be correctly inferred except when inside a call that requires
  378. the additional context (such as a classmethod) of the boundnode
  379. to determine which class the method was called from
  380. """
  381. # If we're unbound method __new__ of a builtin, the result is an
  382. # instance of the class given as first argument.
  383. if self._proxied.name == "__new__":
  384. qname = self._proxied.parent.frame(future=True).qname()
  385. # Avoid checking builtins.type: _infer_type_new_call() does more validation
  386. if qname.startswith("builtins.") and qname != "builtins.type":
  387. return self._infer_builtin_new(caller, context)
  388. return self._proxied.infer_call_result(caller, context)
  389. def _infer_builtin_new(
  390. self,
  391. caller: nodes.Call,
  392. context: InferenceContext,
  393. ) -> collections.abc.Generator[
  394. nodes.Const | Instance | UninferableBase, None, None
  395. ]:
  396. if not caller.args:
  397. return
  398. # Attempt to create a constant
  399. if len(caller.args) > 1:
  400. value = None
  401. if isinstance(caller.args[1], nodes.Const):
  402. value = caller.args[1].value
  403. else:
  404. inferred_arg = next(caller.args[1].infer(), None)
  405. if isinstance(inferred_arg, nodes.Const):
  406. value = inferred_arg.value
  407. if value is not None:
  408. yield nodes.const_factory(value)
  409. return
  410. node_context = context.extra_context.get(caller.args[0])
  411. for inferred in caller.args[0].infer(context=node_context):
  412. if isinstance(inferred, UninferableBase):
  413. yield inferred
  414. if isinstance(inferred, nodes.ClassDef):
  415. yield Instance(inferred)
  416. raise InferenceError
  417. def bool_value(self, context: InferenceContext | None = None) -> Literal[True]:
  418. return True
  419. class BoundMethod(UnboundMethod):
  420. """A special node representing a method bound to an instance."""
  421. # pylint: disable=unnecessary-lambda
  422. special_attributes = lazy_descriptor(lambda: objectmodel.BoundMethodModel())
  423. def __init__(self, proxy, bound):
  424. super().__init__(proxy)
  425. self.bound = bound
  426. def implicit_parameters(self) -> Literal[0, 1]:
  427. if self.name == "__new__":
  428. # __new__ acts as a classmethod but the class argument is not implicit.
  429. return 0
  430. return 1
  431. def is_bound(self) -> Literal[True]:
  432. return True
  433. def _infer_type_new_call(self, caller, context): # noqa: C901
  434. """Try to infer what type.__new__(mcs, name, bases, attrs) returns.
  435. In order for such call to be valid, the metaclass needs to be
  436. a subtype of ``type``, the name needs to be a string, the bases
  437. needs to be a tuple of classes
  438. """
  439. # pylint: disable=import-outside-toplevel; circular import
  440. from astroid.nodes import Pass
  441. # Verify the metaclass
  442. try:
  443. mcs = next(caller.args[0].infer(context=context))
  444. except StopIteration as e:
  445. raise InferenceError(context=context) from e
  446. if mcs.__class__.__name__ != "ClassDef":
  447. # Not a valid first argument.
  448. return None
  449. if not mcs.is_subtype_of("builtins.type"):
  450. # Not a valid metaclass.
  451. return None
  452. # Verify the name
  453. try:
  454. name = next(caller.args[1].infer(context=context))
  455. except StopIteration as e:
  456. raise InferenceError(context=context) from e
  457. if name.__class__.__name__ != "Const":
  458. # Not a valid name, needs to be a const.
  459. return None
  460. if not isinstance(name.value, str):
  461. # Needs to be a string.
  462. return None
  463. # Verify the bases
  464. try:
  465. bases = next(caller.args[2].infer(context=context))
  466. except StopIteration as e:
  467. raise InferenceError(context=context) from e
  468. if bases.__class__.__name__ != "Tuple":
  469. # Needs to be a tuple.
  470. return None
  471. try:
  472. inferred_bases = [next(elt.infer(context=context)) for elt in bases.elts]
  473. except StopIteration as e:
  474. raise InferenceError(context=context) from e
  475. if any(base.__class__.__name__ != "ClassDef" for base in inferred_bases):
  476. # All the bases needs to be Classes
  477. return None
  478. # Verify the attributes.
  479. try:
  480. attrs = next(caller.args[3].infer(context=context))
  481. except StopIteration as e:
  482. raise InferenceError(context=context) from e
  483. if attrs.__class__.__name__ != "Dict":
  484. # Needs to be a dictionary.
  485. return None
  486. cls_locals = collections.defaultdict(list)
  487. for key, value in attrs.items:
  488. try:
  489. key = next(key.infer(context=context))
  490. except StopIteration as e:
  491. raise InferenceError(context=context) from e
  492. try:
  493. value = next(value.infer(context=context))
  494. except StopIteration as e:
  495. raise InferenceError(context=context) from e
  496. # Ignore non string keys
  497. if key.__class__.__name__ == "Const" and isinstance(key.value, str):
  498. cls_locals[key.value].append(value)
  499. # Build the class from now.
  500. cls = mcs.__class__(
  501. name=name.value,
  502. lineno=caller.lineno,
  503. col_offset=caller.col_offset,
  504. parent=caller,
  505. )
  506. empty = Pass()
  507. cls.postinit(
  508. bases=bases.elts,
  509. body=[empty],
  510. decorators=[],
  511. newstyle=True,
  512. metaclass=mcs,
  513. keywords=[],
  514. )
  515. cls.locals = cls_locals
  516. return cls
  517. def infer_call_result(self, caller, context: InferenceContext | None = None):
  518. context = bind_context_to_node(context, self.bound)
  519. if (
  520. self.bound.__class__.__name__ == "ClassDef"
  521. and self.bound.name == "type"
  522. and self.name == "__new__"
  523. and len(caller.args) == 4
  524. ):
  525. # Check if we have a ``type.__new__(mcs, name, bases, attrs)`` call.
  526. new_cls = self._infer_type_new_call(caller, context)
  527. if new_cls:
  528. return iter((new_cls,))
  529. return super().infer_call_result(caller, context)
  530. def bool_value(self, context: InferenceContext | None = None) -> Literal[True]:
  531. return True
  532. class Generator(BaseInstance):
  533. """A special node representing a generator.
  534. Proxied class is set once for all in raw_building.
  535. """
  536. _proxied: nodes.ClassDef
  537. special_attributes = lazy_descriptor(objectmodel.GeneratorModel)
  538. def __init__(
  539. self, parent=None, generator_initial_context: InferenceContext | None = None
  540. ):
  541. super().__init__()
  542. self.parent = parent
  543. self._call_context = copy_context(generator_initial_context)
  544. @decorators.cached
  545. def infer_yield_types(self):
  546. yield from self.parent.infer_yield_result(self._call_context)
  547. def callable(self) -> Literal[False]:
  548. return False
  549. def pytype(self) -> Literal["builtins.generator"]:
  550. return "builtins.generator"
  551. def display_type(self) -> str:
  552. return "Generator"
  553. def bool_value(self, context: InferenceContext | None = None) -> Literal[True]:
  554. return True
  555. def __repr__(self) -> str:
  556. return f"<Generator({self._proxied.name}) l.{self.lineno} at 0x{id(self)}>"
  557. def __str__(self) -> str:
  558. return f"Generator({self._proxied.name})"
  559. class AsyncGenerator(Generator):
  560. """Special node representing an async generator."""
  561. def pytype(self) -> Literal["builtins.async_generator"]:
  562. return "builtins.async_generator"
  563. def display_type(self) -> str:
  564. return "AsyncGenerator"
  565. def __repr__(self) -> str:
  566. return f"<AsyncGenerator({self._proxied.name}) l.{self.lineno} at 0x{id(self)}>"
  567. def __str__(self) -> str:
  568. return f"AsyncGenerator({self._proxied.name})"
  569. class UnionType(BaseInstance):
  570. """Special node representing new style typing unions.
  571. Proxied class is set once for all in raw_building.
  572. """
  573. _proxied: nodes.ClassDef
  574. def __init__(
  575. self,
  576. left: UnionType | nodes.ClassDef | nodes.Const,
  577. right: UnionType | nodes.ClassDef | nodes.Const,
  578. parent: nodes.NodeNG | None = None,
  579. ) -> None:
  580. super().__init__()
  581. self.parent = parent
  582. self.left = left
  583. self.right = right
  584. def callable(self) -> Literal[False]:
  585. return False
  586. def bool_value(self, context: InferenceContext | None = None) -> Literal[True]:
  587. return True
  588. def pytype(self) -> Literal["types.UnionType"]:
  589. return "types.UnionType"
  590. def display_type(self) -> str:
  591. return "UnionType"
  592. def __repr__(self) -> str:
  593. return f"<UnionType({self._proxied.name}) l.{self.lineno} at 0x{id(self)}>"
  594. def __str__(self) -> str:
  595. return f"UnionType({self._proxied.name})"