mixed.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. """
  2. Used only for REPL Completion.
  3. """
  4. import inspect
  5. from pathlib import Path
  6. from jedi.parser_utils import get_cached_code_lines
  7. from jedi import settings
  8. from jedi.cache import memoize_method
  9. from jedi.inference import compiled
  10. from jedi.file_io import FileIO
  11. from jedi.inference.names import NameWrapper
  12. from jedi.inference.base_value import ValueSet, ValueWrapper, NO_VALUES
  13. from jedi.inference.value import ModuleValue
  14. from jedi.inference.cache import inference_state_function_cache, \
  15. inference_state_method_cache
  16. from jedi.inference.compiled.access import ALLOWED_GETITEM_TYPES, get_api_type
  17. from jedi.inference.gradual.conversion import to_stub
  18. from jedi.inference.context import CompiledContext, CompiledModuleContext, \
  19. TreeContextMixin
  20. _sentinel = object()
  21. class MixedObject(ValueWrapper):
  22. """
  23. A ``MixedObject`` is used in two ways:
  24. 1. It uses the default logic of ``parser.python.tree`` objects,
  25. 2. except for getattr calls and signatures. The names dicts are generated
  26. in a fashion like ``CompiledValue``.
  27. This combined logic makes it possible to provide more powerful REPL
  28. completion. It allows side effects that are not noticable with the default
  29. parser structure to still be completable.
  30. The biggest difference from CompiledValue to MixedObject is that we are
  31. generally dealing with Python code and not with C code. This will generate
  32. fewer special cases, because we in Python you don't have the same freedoms
  33. to modify the runtime.
  34. """
  35. def __init__(self, compiled_value, tree_value):
  36. super().__init__(tree_value)
  37. self.compiled_value = compiled_value
  38. self.access_handle = compiled_value.access_handle
  39. def get_filters(self, *args, **kwargs):
  40. yield MixedObjectFilter(
  41. self.inference_state, self.compiled_value, self._wrapped_value)
  42. def get_signatures(self):
  43. # Prefer `inspect.signature` over somehow analyzing Python code. It
  44. # should be very precise, especially for stuff like `partial`.
  45. return self.compiled_value.get_signatures()
  46. @inference_state_method_cache(default=NO_VALUES)
  47. def py__call__(self, arguments):
  48. # Fallback to the wrapped value if to stub returns no values.
  49. values = to_stub(self._wrapped_value)
  50. if not values:
  51. values = self._wrapped_value
  52. return values.py__call__(arguments)
  53. def get_safe_value(self, default=_sentinel):
  54. if default is _sentinel:
  55. return self.compiled_value.get_safe_value()
  56. else:
  57. return self.compiled_value.get_safe_value(default)
  58. @property
  59. def array_type(self):
  60. return self.compiled_value.array_type
  61. def get_key_values(self):
  62. return self.compiled_value.get_key_values()
  63. def py__simple_getitem__(self, index):
  64. python_object = self.compiled_value.access_handle.access._obj
  65. if type(python_object) in ALLOWED_GETITEM_TYPES:
  66. return self.compiled_value.py__simple_getitem__(index)
  67. return self._wrapped_value.py__simple_getitem__(index)
  68. def negate(self):
  69. return self.compiled_value.negate()
  70. def _as_context(self):
  71. if self.parent_context is None:
  72. return MixedModuleContext(self)
  73. return MixedContext(self)
  74. def __repr__(self):
  75. return '<%s: %s; %s>' % (
  76. type(self).__name__,
  77. self.access_handle.get_repr(),
  78. self._wrapped_value,
  79. )
  80. class MixedContext(CompiledContext, TreeContextMixin):
  81. @property
  82. def compiled_value(self):
  83. return self._value.compiled_value
  84. class MixedModuleContext(CompiledModuleContext, MixedContext):
  85. pass
  86. class MixedName(NameWrapper):
  87. """
  88. The ``CompiledName._compiled_value`` is our MixedObject.
  89. """
  90. def __init__(self, wrapped_name, parent_tree_value):
  91. super().__init__(wrapped_name)
  92. self._parent_tree_value = parent_tree_value
  93. @property
  94. def start_pos(self):
  95. values = list(self.infer())
  96. if not values:
  97. # This means a start_pos that doesn't exist (compiled objects).
  98. return 0, 0
  99. return values[0].name.start_pos
  100. @memoize_method
  101. def infer(self):
  102. compiled_value = self._wrapped_name.infer_compiled_value()
  103. tree_value = self._parent_tree_value
  104. if tree_value.is_instance() or tree_value.is_class():
  105. tree_values = tree_value.py__getattribute__(self.string_name)
  106. if compiled_value.is_function():
  107. return ValueSet({MixedObject(compiled_value, v) for v in tree_values})
  108. module_context = tree_value.get_root_context()
  109. return _create(self._inference_state, compiled_value, module_context)
  110. class MixedObjectFilter(compiled.CompiledValueFilter):
  111. def __init__(self, inference_state, compiled_value, tree_value):
  112. super().__init__(inference_state, compiled_value)
  113. self._tree_value = tree_value
  114. def _create_name(self, *args, **kwargs):
  115. return MixedName(
  116. super()._create_name(*args, **kwargs),
  117. self._tree_value,
  118. )
  119. @inference_state_function_cache()
  120. def _load_module(inference_state, path):
  121. return inference_state.parse(
  122. path=path,
  123. cache=True,
  124. diff_cache=settings.fast_parser,
  125. cache_path=settings.cache_directory
  126. ).get_root_node()
  127. def _get_object_to_check(python_object):
  128. """Check if inspect.getfile has a chance to find the source."""
  129. try:
  130. python_object = inspect.unwrap(python_object)
  131. except ValueError:
  132. # Can return a ValueError when it wraps around
  133. pass
  134. if (inspect.ismodule(python_object)
  135. or inspect.isclass(python_object)
  136. or inspect.ismethod(python_object)
  137. or inspect.isfunction(python_object)
  138. or inspect.istraceback(python_object)
  139. or inspect.isframe(python_object)
  140. or inspect.iscode(python_object)):
  141. return python_object
  142. try:
  143. return python_object.__class__
  144. except AttributeError:
  145. raise TypeError # Prevents computation of `repr` within inspect.
  146. def _find_syntax_node_name(inference_state, python_object):
  147. original_object = python_object
  148. try:
  149. python_object = _get_object_to_check(python_object)
  150. path = inspect.getsourcefile(python_object)
  151. except (OSError, TypeError):
  152. # The type might not be known (e.g. class_with_dict.__weakref__)
  153. return None
  154. path = None if path is None else Path(path)
  155. try:
  156. if path is None or not path.exists():
  157. # The path might not exist or be e.g. <stdin>.
  158. return None
  159. except OSError:
  160. # Might raise an OSError on Windows:
  161. #
  162. # [WinError 123] The filename, directory name, or volume label
  163. # syntax is incorrect: '<string>'
  164. return None
  165. file_io = FileIO(path)
  166. module_node = _load_module(inference_state, path)
  167. if inspect.ismodule(python_object):
  168. # We don't need to check names for modules, because there's not really
  169. # a way to write a module in a module in Python (and also __name__ can
  170. # be something like ``email.utils``).
  171. code_lines = get_cached_code_lines(inference_state.grammar, path)
  172. return module_node, module_node, file_io, code_lines
  173. try:
  174. name_str = python_object.__name__
  175. except AttributeError:
  176. # Stuff like python_function.__code__.
  177. return None
  178. if name_str == '<lambda>':
  179. return None # It's too hard to find lambdas.
  180. # Doesn't always work (e.g. os.stat_result)
  181. names = module_node.get_used_names().get(name_str, [])
  182. # Only functions and classes are relevant. If a name e.g. points to an
  183. # import, it's probably a builtin (like collections.deque) and needs to be
  184. # ignored.
  185. names = [
  186. n for n in names
  187. if n.parent.type in ('funcdef', 'classdef') and n.parent.name == n
  188. ]
  189. if not names:
  190. return None
  191. try:
  192. code = python_object.__code__
  193. # By using the line number of a code object we make the lookup in a
  194. # file pretty easy. There's still a possibility of people defining
  195. # stuff like ``a = 3; foo(a); a = 4`` on the same line, but if people
  196. # do so we just don't care.
  197. line_nr = code.co_firstlineno
  198. except AttributeError:
  199. pass
  200. else:
  201. line_names = [name for name in names if name.start_pos[0] == line_nr]
  202. # There's a chance that the object is not available anymore, because
  203. # the code has changed in the background.
  204. if line_names:
  205. names = line_names
  206. code_lines = get_cached_code_lines(inference_state.grammar, path)
  207. # It's really hard to actually get the right definition, here as a last
  208. # resort we just return the last one. This chance might lead to odd
  209. # completions at some points but will lead to mostly correct type
  210. # inference, because people tend to define a public name in a module only
  211. # once.
  212. tree_node = names[-1].parent
  213. if tree_node.type == 'funcdef' and get_api_type(original_object) == 'instance':
  214. # If an instance is given and we're landing on a function (e.g.
  215. # partial in 3.5), something is completely wrong and we should not
  216. # return that.
  217. return None
  218. return module_node, tree_node, file_io, code_lines
  219. @inference_state_function_cache()
  220. def _create(inference_state, compiled_value, module_context):
  221. # TODO accessing this is bad, but it probably doesn't matter that much,
  222. # because we're working with interpreters only here.
  223. python_object = compiled_value.access_handle.access._obj
  224. result = _find_syntax_node_name(inference_state, python_object)
  225. if result is None:
  226. # TODO Care about generics from stuff like `[1]` and don't return like this.
  227. if type(python_object) in (dict, list, tuple):
  228. return ValueSet({compiled_value})
  229. tree_values = to_stub(compiled_value)
  230. if not tree_values:
  231. return ValueSet({compiled_value})
  232. else:
  233. module_node, tree_node, file_io, code_lines = result
  234. if module_context is None or module_context.tree_node != module_node:
  235. root_compiled_value = compiled_value.get_root_context().get_value()
  236. # TODO this __name__ might be wrong.
  237. name = root_compiled_value.py__name__()
  238. string_names = tuple(name.split('.'))
  239. module_value = ModuleValue(
  240. inference_state, module_node,
  241. file_io=file_io,
  242. string_names=string_names,
  243. code_lines=code_lines,
  244. is_package=root_compiled_value.is_package(),
  245. )
  246. if name is not None:
  247. inference_state.module_cache.add(string_names, ValueSet([module_value]))
  248. module_context = module_value.as_context()
  249. tree_values = ValueSet({module_context.create_value(tree_node)})
  250. if tree_node.type == 'classdef':
  251. if not compiled_value.is_class():
  252. # Is an instance, not a class.
  253. tree_values = tree_values.execute_with_values()
  254. return ValueSet(
  255. MixedObject(compiled_value, tree_value=tree_value)
  256. for tree_value in tree_values
  257. )