base.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. from jedi.inference.cache import inference_state_method_cache
  2. from jedi.inference.base_value import ValueSet, NO_VALUES, Value, \
  3. iterator_to_value_set, LazyValueWrapper, ValueWrapper
  4. from jedi.inference.compiled import builtin_from_name
  5. from jedi.inference.value.klass import ClassFilter
  6. from jedi.inference.value.klass import ClassMixin
  7. from jedi.inference.utils import to_list
  8. from jedi.inference.names import AbstractNameDefinition, ValueName
  9. from jedi.inference.context import ClassContext
  10. from jedi.inference.gradual.generics import TupleGenericManager
  11. class _BoundTypeVarName(AbstractNameDefinition):
  12. """
  13. This type var was bound to a certain type, e.g. int.
  14. """
  15. def __init__(self, type_var, value_set):
  16. self._type_var = type_var
  17. self.parent_context = type_var.parent_context
  18. self._value_set = value_set
  19. def infer(self):
  20. def iter_():
  21. for value in self._value_set:
  22. # Replace any with the constraints if they are there.
  23. from jedi.inference.gradual.typing import AnyClass
  24. if isinstance(value, AnyClass):
  25. yield from self._type_var.constraints
  26. else:
  27. yield value
  28. return ValueSet(iter_())
  29. def py__name__(self):
  30. return self._type_var.py__name__()
  31. def __repr__(self):
  32. return '<%s %s -> %s>' % (self.__class__.__name__, self.py__name__(), self._value_set)
  33. class _TypeVarFilter:
  34. """
  35. A filter for all given variables in a class.
  36. A = TypeVar('A')
  37. B = TypeVar('B')
  38. class Foo(Mapping[A, B]):
  39. ...
  40. In this example we would have two type vars given: A and B
  41. """
  42. def __init__(self, generics, type_vars):
  43. self._generics = generics
  44. self._type_vars = type_vars
  45. def get(self, name):
  46. for i, type_var in enumerate(self._type_vars):
  47. if type_var.py__name__() == name:
  48. try:
  49. return [_BoundTypeVarName(type_var, self._generics[i])]
  50. except IndexError:
  51. return [type_var.name]
  52. return []
  53. def values(self):
  54. # The values are not relevant. If it's not searched exactly, the type
  55. # vars are just global and should be looked up as that.
  56. return []
  57. class _AnnotatedClassContext(ClassContext):
  58. def get_filters(self, *args, **kwargs):
  59. filters = super().get_filters(
  60. *args, **kwargs
  61. )
  62. yield from filters
  63. # The type vars can only be looked up if it's a global search and
  64. # not a direct lookup on the class.
  65. yield self._value.get_type_var_filter()
  66. class DefineGenericBaseClass(LazyValueWrapper):
  67. def __init__(self, generics_manager):
  68. self._generics_manager = generics_manager
  69. def _create_instance_with_generics(self, generics_manager):
  70. raise NotImplementedError
  71. @inference_state_method_cache()
  72. def get_generics(self):
  73. return self._generics_manager.to_tuple()
  74. def define_generics(self, type_var_dict):
  75. from jedi.inference.gradual.type_var import TypeVar
  76. changed = False
  77. new_generics = []
  78. for generic_set in self.get_generics():
  79. values = NO_VALUES
  80. for generic in generic_set:
  81. if isinstance(generic, (DefineGenericBaseClass, TypeVar)):
  82. result = generic.define_generics(type_var_dict)
  83. values |= result
  84. if result != ValueSet({generic}):
  85. changed = True
  86. else:
  87. values |= ValueSet([generic])
  88. new_generics.append(values)
  89. if not changed:
  90. # There might not be any type vars that change. In that case just
  91. # return itself, because it does not make sense to potentially lose
  92. # cached results.
  93. return ValueSet([self])
  94. return ValueSet([self._create_instance_with_generics(
  95. TupleGenericManager(tuple(new_generics))
  96. )])
  97. def is_same_class(self, other):
  98. if not isinstance(other, DefineGenericBaseClass):
  99. return False
  100. if self.tree_node != other.tree_node:
  101. # TODO not sure if this is nice.
  102. return False
  103. given_params1 = self.get_generics()
  104. given_params2 = other.get_generics()
  105. if len(given_params1) != len(given_params2):
  106. # If the amount of type vars doesn't match, the class doesn't
  107. # match.
  108. return False
  109. # Now compare generics
  110. return all(
  111. any(
  112. # TODO why is this ordering the correct one?
  113. cls2.is_same_class(cls1)
  114. # TODO I'm still not sure gather_annotation_classes is a good
  115. # idea. They are essentially here to avoid comparing Tuple <=>
  116. # tuple and instead compare tuple <=> tuple, but at the moment
  117. # the whole `is_same_class` and `is_sub_class` matching is just
  118. # not in the best shape.
  119. for cls1 in class_set1.gather_annotation_classes()
  120. for cls2 in class_set2.gather_annotation_classes()
  121. ) for class_set1, class_set2 in zip(given_params1, given_params2)
  122. )
  123. def get_signatures(self):
  124. return []
  125. def __repr__(self):
  126. return '<%s: %s%s>' % (
  127. self.__class__.__name__,
  128. self._wrapped_value,
  129. list(self.get_generics()),
  130. )
  131. class GenericClass(DefineGenericBaseClass, ClassMixin):
  132. """
  133. A class that is defined with generics, might be something simple like:
  134. class Foo(Generic[T]): ...
  135. my_foo_int_cls = Foo[int]
  136. """
  137. def __init__(self, class_value, generics_manager):
  138. super().__init__(generics_manager)
  139. self._class_value = class_value
  140. def _get_wrapped_value(self):
  141. return self._class_value
  142. def get_type_hint(self, add_class_info=True):
  143. n = self.py__name__()
  144. # Not sure if this is the best way to do this, but all of these types
  145. # are a bit special in that they have type aliases and other ways to
  146. # become lower case. It's probably better to make them upper case,
  147. # because that's what you can use in annotations.
  148. n = dict(list="List", dict="Dict", set="Set", tuple="Tuple").get(n, n)
  149. s = n + self._generics_manager.get_type_hint()
  150. if add_class_info:
  151. return 'Type[%s]' % s
  152. return s
  153. def get_type_var_filter(self):
  154. return _TypeVarFilter(self.get_generics(), self.list_type_vars())
  155. def py__call__(self, arguments):
  156. instance, = super().py__call__(arguments)
  157. return ValueSet([_GenericInstanceWrapper(instance)])
  158. def _as_context(self):
  159. return _AnnotatedClassContext(self)
  160. @to_list
  161. def py__bases__(self):
  162. for base in self._wrapped_value.py__bases__():
  163. yield _LazyGenericBaseClass(self, base, self._generics_manager)
  164. def _create_instance_with_generics(self, generics_manager):
  165. return GenericClass(self._class_value, generics_manager)
  166. def is_sub_class_of(self, class_value):
  167. if super().is_sub_class_of(class_value):
  168. return True
  169. return self._class_value.is_sub_class_of(class_value)
  170. def with_generics(self, generics_tuple):
  171. return self._class_value.with_generics(generics_tuple)
  172. def infer_type_vars(self, value_set):
  173. # Circular
  174. from jedi.inference.gradual.annotation import merge_pairwise_generics, merge_type_var_dicts
  175. annotation_name = self.py__name__()
  176. type_var_dict = {}
  177. if annotation_name == 'Iterable':
  178. annotation_generics = self.get_generics()
  179. if annotation_generics:
  180. return annotation_generics[0].infer_type_vars(
  181. value_set.merge_types_of_iterate(),
  182. )
  183. else:
  184. # Note: we need to handle the MRO _in order_, so we need to extract
  185. # the elements from the set first, then handle them, even if we put
  186. # them back in a set afterwards.
  187. for py_class in value_set:
  188. if py_class.is_instance() and not py_class.is_compiled():
  189. py_class = py_class.get_annotated_class_object()
  190. else:
  191. continue
  192. if py_class.api_type != 'class':
  193. # Functions & modules don't have an MRO and we're not
  194. # expecting a Callable (those are handled separately within
  195. # TypingClassValueWithIndex).
  196. continue
  197. for parent_class in py_class.py__mro__():
  198. class_name = parent_class.py__name__()
  199. if annotation_name == class_name:
  200. merge_type_var_dicts(
  201. type_var_dict,
  202. merge_pairwise_generics(self, parent_class),
  203. )
  204. break
  205. return type_var_dict
  206. class _LazyGenericBaseClass:
  207. def __init__(self, class_value, lazy_base_class, generics_manager):
  208. self._class_value = class_value
  209. self._lazy_base_class = lazy_base_class
  210. self._generics_manager = generics_manager
  211. @iterator_to_value_set
  212. def infer(self):
  213. for base in self._lazy_base_class.infer():
  214. if isinstance(base, GenericClass):
  215. # Here we have to recalculate the given types.
  216. yield GenericClass.create_cached(
  217. base.inference_state,
  218. base._wrapped_value,
  219. TupleGenericManager(tuple(self._remap_type_vars(base))),
  220. )
  221. else:
  222. if base.is_class_mixin():
  223. # This case basically allows classes like `class Foo(List)`
  224. # to be used like `Foo[int]`. The generics are not
  225. # necessary and can be used later.
  226. yield GenericClass.create_cached(
  227. base.inference_state,
  228. base,
  229. self._generics_manager,
  230. )
  231. else:
  232. yield base
  233. def _remap_type_vars(self, base):
  234. from jedi.inference.gradual.type_var import TypeVar
  235. filter = self._class_value.get_type_var_filter()
  236. for type_var_set in base.get_generics():
  237. new = NO_VALUES
  238. for type_var in type_var_set:
  239. if isinstance(type_var, TypeVar):
  240. names = filter.get(type_var.py__name__())
  241. new |= ValueSet.from_sets(
  242. name.infer() for name in names
  243. )
  244. else:
  245. # Mostly will be type vars, except if in some cases
  246. # a concrete type will already be there. In that
  247. # case just add it to the value set.
  248. new |= ValueSet([type_var])
  249. yield new
  250. def __repr__(self):
  251. return '<%s: %s>' % (self.__class__.__name__, self._lazy_base_class)
  252. class _GenericInstanceWrapper(ValueWrapper):
  253. def py__stop_iteration_returns(self):
  254. for cls in self._wrapped_value.class_value.py__mro__():
  255. if cls.py__name__() == 'Generator':
  256. generics = cls.get_generics()
  257. try:
  258. return generics[2].execute_annotation()
  259. except IndexError:
  260. pass
  261. elif cls.py__name__() == 'Iterator':
  262. return ValueSet([builtin_from_name(self.inference_state, 'None')])
  263. return self._wrapped_value.py__stop_iteration_returns()
  264. def get_type_hint(self, add_class_info=True):
  265. return self._wrapped_value.class_value.get_type_hint(add_class_info=False)
  266. class _PseudoTreeNameClass(Value):
  267. """
  268. In typeshed, some classes are defined like this:
  269. Tuple: _SpecialForm = ...
  270. Now this is not a real class, therefore we have to do some workarounds like
  271. this class. Essentially this class makes it possible to goto that `Tuple`
  272. name, without affecting anything else negatively.
  273. """
  274. api_type = 'class'
  275. def __init__(self, parent_context, tree_name):
  276. super().__init__(
  277. parent_context.inference_state,
  278. parent_context
  279. )
  280. self._tree_name = tree_name
  281. @property
  282. def tree_node(self):
  283. return self._tree_name
  284. def get_filters(self, *args, **kwargs):
  285. # TODO this is obviously wrong. Is it though?
  286. class EmptyFilter(ClassFilter):
  287. def __init__(self):
  288. pass
  289. def get(self, name, **kwargs):
  290. return []
  291. def values(self, **kwargs):
  292. return []
  293. yield EmptyFilter()
  294. def py__class__(self):
  295. # This might not be 100% correct, but it is good enough. The details of
  296. # the typing library are not really an issue for Jedi.
  297. return builtin_from_name(self.inference_state, 'type')
  298. @property
  299. def name(self):
  300. return ValueName(self, self._tree_name)
  301. def get_qualified_names(self):
  302. return (self._tree_name.value,)
  303. def __repr__(self):
  304. return '%s(%s)' % (self.__class__.__name__, self._tree_name.value)
  305. class BaseTypingValue(LazyValueWrapper):
  306. def __init__(self, parent_context, tree_name):
  307. self.inference_state = parent_context.inference_state
  308. self.parent_context = parent_context
  309. self._tree_name = tree_name
  310. @property
  311. def name(self):
  312. return ValueName(self, self._tree_name)
  313. def _get_wrapped_value(self):
  314. return _PseudoTreeNameClass(self.parent_context, self._tree_name)
  315. def get_signatures(self):
  316. return self._wrapped_value.get_signatures()
  317. def __repr__(self):
  318. return '%s(%s)' % (self.__class__.__name__, self._tree_name.value)
  319. class BaseTypingClassWithGenerics(DefineGenericBaseClass):
  320. def __init__(self, parent_context, tree_name, generics_manager):
  321. super().__init__(generics_manager)
  322. self.inference_state = parent_context.inference_state
  323. self.parent_context = parent_context
  324. self._tree_name = tree_name
  325. def _get_wrapped_value(self):
  326. return _PseudoTreeNameClass(self.parent_context, self._tree_name)
  327. def __repr__(self):
  328. return '%s(%s%s)' % (self.__class__.__name__, self._tree_name.value,
  329. self._generics_manager)
  330. class BaseTypingInstance(LazyValueWrapper):
  331. def __init__(self, parent_context, class_value, tree_name, generics_manager):
  332. self.inference_state = class_value.inference_state
  333. self.parent_context = parent_context
  334. self._class_value = class_value
  335. self._tree_name = tree_name
  336. self._generics_manager = generics_manager
  337. def py__class__(self):
  338. return self._class_value
  339. def get_annotated_class_object(self):
  340. return self._class_value
  341. def get_qualified_names(self):
  342. return (self.py__name__(),)
  343. @property
  344. def name(self):
  345. return ValueName(self, self._tree_name)
  346. def _get_wrapped_value(self):
  347. object_, = builtin_from_name(self.inference_state, 'object').execute_annotation()
  348. return object_
  349. def __repr__(self):
  350. return '<%s: %s>' % (self.__class__.__name__, self._generics_manager)