conversion.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. from jedi import debug
  2. from jedi.inference.base_value import ValueSet, \
  3. NO_VALUES
  4. from jedi.inference.utils import to_list
  5. from jedi.inference.gradual.stub_value import StubModuleValue
  6. from jedi.inference.gradual.typeshed import try_to_load_stub_cached
  7. from jedi.inference.value.decorator import Decoratee
  8. def _stub_to_python_value_set(stub_value, ignore_compiled=False):
  9. stub_module_context = stub_value.get_root_context()
  10. if not stub_module_context.is_stub():
  11. return ValueSet([stub_value])
  12. decorates = None
  13. if isinstance(stub_value, Decoratee):
  14. decorates = stub_value._original_value
  15. was_instance = stub_value.is_instance()
  16. if was_instance:
  17. arguments = getattr(stub_value, '_arguments', None)
  18. stub_value = stub_value.py__class__()
  19. qualified_names = stub_value.get_qualified_names()
  20. if qualified_names is None:
  21. return NO_VALUES
  22. was_bound_method = stub_value.is_bound_method()
  23. if was_bound_method:
  24. # Infer the object first. We can infer the method later.
  25. method_name = qualified_names[-1]
  26. qualified_names = qualified_names[:-1]
  27. was_instance = True
  28. arguments = None
  29. values = _infer_from_stub(stub_module_context, qualified_names, ignore_compiled)
  30. if was_instance:
  31. values = ValueSet.from_sets(
  32. c.execute_with_values() if arguments is None else c.execute(arguments)
  33. for c in values
  34. if c.is_class()
  35. )
  36. if was_bound_method:
  37. # Now that the instance has been properly created, we can simply get
  38. # the method.
  39. values = values.py__getattribute__(method_name)
  40. if decorates is not None:
  41. values = ValueSet(Decoratee(v, decorates) for v in values)
  42. return values
  43. def _infer_from_stub(stub_module_context, qualified_names, ignore_compiled):
  44. from jedi.inference.compiled.mixed import MixedObject
  45. stub_module = stub_module_context.get_value()
  46. assert isinstance(stub_module, (StubModuleValue, MixedObject)), stub_module_context
  47. non_stubs = stub_module.non_stub_value_set
  48. if ignore_compiled:
  49. non_stubs = non_stubs.filter(lambda c: not c.is_compiled())
  50. for name in qualified_names:
  51. non_stubs = non_stubs.py__getattribute__(name)
  52. return non_stubs
  53. @to_list
  54. def _try_stub_to_python_names(names, prefer_stub_to_compiled=False):
  55. for name in names:
  56. module_context = name.get_root_context()
  57. if not module_context.is_stub():
  58. yield name
  59. continue
  60. if name.api_type == 'module':
  61. values = convert_values(name.infer(), ignore_compiled=prefer_stub_to_compiled)
  62. if values:
  63. for v in values:
  64. yield v.name
  65. continue
  66. else:
  67. v = name.get_defining_qualified_value()
  68. if v is not None:
  69. converted = _stub_to_python_value_set(v, ignore_compiled=prefer_stub_to_compiled)
  70. if converted:
  71. converted_names = converted.goto(name.get_public_name())
  72. if converted_names:
  73. for n in converted_names:
  74. if n.get_root_context().is_stub():
  75. # If it's a stub again, it means we're going in
  76. # a circle. Probably some imports make it a
  77. # stub again.
  78. yield name
  79. else:
  80. yield n
  81. continue
  82. yield name
  83. def _load_stub_module(module):
  84. if module.is_stub():
  85. return module
  86. return try_to_load_stub_cached(
  87. module.inference_state,
  88. import_names=module.string_names,
  89. python_value_set=ValueSet([module]),
  90. parent_module_value=None,
  91. sys_path=module.inference_state.get_sys_path(),
  92. )
  93. @to_list
  94. def _python_to_stub_names(names, fallback_to_python=False):
  95. for name in names:
  96. module_context = name.get_root_context()
  97. if module_context.is_stub():
  98. yield name
  99. continue
  100. if name.api_type == 'module':
  101. found_name = False
  102. for n in name.goto():
  103. if n.api_type == 'module':
  104. values = convert_values(n.infer(), only_stubs=True)
  105. for v in values:
  106. yield v.name
  107. found_name = True
  108. else:
  109. for x in _python_to_stub_names([n], fallback_to_python=fallback_to_python):
  110. yield x
  111. found_name = True
  112. if found_name:
  113. continue
  114. else:
  115. v = name.get_defining_qualified_value()
  116. if v is not None:
  117. converted = to_stub(v)
  118. if converted:
  119. converted_names = converted.goto(name.get_public_name())
  120. if converted_names:
  121. yield from converted_names
  122. continue
  123. if fallback_to_python:
  124. # This is the part where if we haven't found anything, just return
  125. # the stub name.
  126. yield name
  127. def convert_names(names, only_stubs=False, prefer_stubs=False, prefer_stub_to_compiled=True):
  128. if only_stubs and prefer_stubs:
  129. raise ValueError("You cannot use both of only_stubs and prefer_stubs.")
  130. with debug.increase_indent_cm('convert names'):
  131. if only_stubs or prefer_stubs:
  132. return _python_to_stub_names(names, fallback_to_python=prefer_stubs)
  133. else:
  134. return _try_stub_to_python_names(
  135. names, prefer_stub_to_compiled=prefer_stub_to_compiled)
  136. def convert_values(values, only_stubs=False, prefer_stubs=False, ignore_compiled=True):
  137. assert not (only_stubs and prefer_stubs)
  138. with debug.increase_indent_cm('convert values'):
  139. if only_stubs or prefer_stubs:
  140. return ValueSet.from_sets(
  141. to_stub(value)
  142. or (ValueSet({value}) if prefer_stubs else NO_VALUES)
  143. for value in values
  144. )
  145. else:
  146. return ValueSet.from_sets(
  147. _stub_to_python_value_set(stub_value, ignore_compiled=ignore_compiled)
  148. or ValueSet({stub_value})
  149. for stub_value in values
  150. )
  151. def to_stub(value):
  152. if value.is_stub():
  153. return ValueSet([value])
  154. was_instance = value.is_instance()
  155. if was_instance:
  156. value = value.py__class__()
  157. qualified_names = value.get_qualified_names()
  158. stub_module = _load_stub_module(value.get_root_context().get_value())
  159. if stub_module is None or qualified_names is None:
  160. return NO_VALUES
  161. was_bound_method = value.is_bound_method()
  162. if was_bound_method:
  163. # Infer the object first. We can infer the method later.
  164. method_name = qualified_names[-1]
  165. qualified_names = qualified_names[:-1]
  166. was_instance = True
  167. stub_values = ValueSet([stub_module])
  168. for name in qualified_names:
  169. stub_values = stub_values.py__getattribute__(name)
  170. if was_instance:
  171. stub_values = ValueSet.from_sets(
  172. c.execute_with_values()
  173. for c in stub_values
  174. if c.is_class()
  175. )
  176. if was_bound_method:
  177. # Now that the instance has been properly created, we can simply get
  178. # the method.
  179. stub_values = stub_values.py__getattribute__(method_name)
  180. return stub_values