helpers.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. import copy
  2. import sys
  3. import re
  4. import os
  5. from itertools import chain
  6. from contextlib import contextmanager
  7. from parso.python import tree
  8. def is_stdlib_path(path):
  9. # Python standard library paths look like this:
  10. # /usr/lib/python3.9/...
  11. # TODO The implementation below is probably incorrect and not complete.
  12. parts = path.parts
  13. if 'dist-packages' in parts or 'site-packages' in parts:
  14. return False
  15. base_path = os.path.join(sys.prefix, 'lib', 'python')
  16. return bool(re.match(re.escape(base_path) + r'\d.\d', str(path)))
  17. def deep_ast_copy(obj):
  18. """
  19. Much, much faster than copy.deepcopy, but just for parser tree nodes.
  20. """
  21. # If it's already in the cache, just return it.
  22. new_obj = copy.copy(obj)
  23. # Copy children
  24. new_children = []
  25. for child in obj.children:
  26. if isinstance(child, tree.Leaf):
  27. new_child = copy.copy(child)
  28. new_child.parent = new_obj
  29. else:
  30. new_child = deep_ast_copy(child)
  31. new_child.parent = new_obj
  32. new_children.append(new_child)
  33. new_obj.children = new_children
  34. return new_obj
  35. def infer_call_of_leaf(context, leaf, cut_own_trailer=False):
  36. """
  37. Creates a "call" node that consist of all ``trailer`` and ``power``
  38. objects. E.g. if you call it with ``append``::
  39. list([]).append(3) or None
  40. You would get a node with the content ``list([]).append`` back.
  41. This generates a copy of the original ast node.
  42. If you're using the leaf, e.g. the bracket `)` it will return ``list([])``.
  43. We use this function for two purposes. Given an expression ``bar.foo``,
  44. we may want to
  45. - infer the type of ``foo`` to offer completions after foo
  46. - infer the type of ``bar`` to be able to jump to the definition of foo
  47. The option ``cut_own_trailer`` must be set to true for the second purpose.
  48. """
  49. trailer = leaf.parent
  50. if trailer.type == 'fstring':
  51. from jedi.inference import compiled
  52. return compiled.get_string_value_set(context.inference_state)
  53. # The leaf may not be the last or first child, because there exist three
  54. # different trailers: `( x )`, `[ x ]` and `.x`. In the first two examples
  55. # we should not match anything more than x.
  56. if trailer.type != 'trailer' or leaf not in (trailer.children[0], trailer.children[-1]):
  57. if leaf == ':':
  58. # Basically happens with foo[:] when the cursor is on the colon
  59. from jedi.inference.base_value import NO_VALUES
  60. return NO_VALUES
  61. if trailer.type == 'atom':
  62. return context.infer_node(trailer)
  63. return context.infer_node(leaf)
  64. power = trailer.parent
  65. index = power.children.index(trailer)
  66. if cut_own_trailer:
  67. cut = index
  68. else:
  69. cut = index + 1
  70. if power.type == 'error_node':
  71. start = index
  72. while True:
  73. start -= 1
  74. base = power.children[start]
  75. if base.type != 'trailer':
  76. break
  77. trailers = power.children[start + 1:cut]
  78. else:
  79. base = power.children[0]
  80. trailers = power.children[1:cut]
  81. if base == 'await':
  82. base = trailers[0]
  83. trailers = trailers[1:]
  84. values = context.infer_node(base)
  85. from jedi.inference.syntax_tree import infer_trailer
  86. for trailer in trailers:
  87. values = infer_trailer(context, values, trailer)
  88. return values
  89. def get_names_of_node(node):
  90. try:
  91. children = node.children
  92. except AttributeError:
  93. if node.type == 'name':
  94. return [node]
  95. else:
  96. return []
  97. else:
  98. return list(chain.from_iterable(get_names_of_node(c) for c in children))
  99. def is_string(value):
  100. return value.is_compiled() and isinstance(value.get_safe_value(default=None), str)
  101. def is_literal(value):
  102. return is_number(value) or is_string(value)
  103. def _get_safe_value_or_none(value, accept):
  104. value = value.get_safe_value(default=None)
  105. if isinstance(value, accept):
  106. return value
  107. def get_int_or_none(value):
  108. return _get_safe_value_or_none(value, int)
  109. def get_str_or_none(value):
  110. return _get_safe_value_or_none(value, str)
  111. def is_number(value):
  112. return _get_safe_value_or_none(value, (int, float)) is not None
  113. class SimpleGetItemNotFound(Exception):
  114. pass
  115. @contextmanager
  116. def reraise_getitem_errors(*exception_classes):
  117. try:
  118. yield
  119. except exception_classes as e:
  120. raise SimpleGetItemNotFound(e)
  121. def parse_dotted_names(nodes, is_import_from, until_node=None):
  122. level = 0
  123. names = []
  124. for node in nodes[1:]:
  125. if node in ('.', '...'):
  126. if not names:
  127. level += len(node.value)
  128. elif node.type == 'dotted_name':
  129. for n in node.children[::2]:
  130. names.append(n)
  131. if n is until_node:
  132. break
  133. else:
  134. continue
  135. break
  136. elif node.type == 'name':
  137. names.append(node)
  138. if node is until_node:
  139. break
  140. elif node == ',':
  141. if not is_import_from:
  142. names = []
  143. else:
  144. # Here if the keyword `import` comes along it stops checking
  145. # for names.
  146. break
  147. return level, names
  148. def values_from_qualified_names(inference_state, *names):
  149. return inference_state.import_module(names[:-1]).py__getattribute__(names[-1])
  150. def is_big_annoying_library(context):
  151. string_names = context.get_root_context().string_names
  152. if string_names is None:
  153. return False
  154. # Especially pandas and tensorflow are huge complicated Python libraries
  155. # that get even slower than they already are when Jedi tries to undrstand
  156. # dynamic features like decorators, ifs and other stuff.
  157. return string_names[0] in ('pandas', 'numpy', 'tensorflow', 'matplotlib')