functions.py 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. import sys
  2. import os
  3. import inspect
  4. import importlib
  5. from pathlib import Path
  6. from zipfile import ZipFile
  7. from zipimport import zipimporter, ZipImportError
  8. from importlib.machinery import all_suffixes
  9. from jedi.inference.compiled import access
  10. from jedi import debug
  11. from jedi import parser_utils
  12. from jedi.file_io import KnownContentFileIO, ZipFileIO
  13. def get_sys_path():
  14. return sys.path
  15. def load_module(inference_state, **kwargs):
  16. return access.load_module(inference_state, **kwargs)
  17. def get_compiled_method_return(inference_state, id, attribute, *args, **kwargs):
  18. handle = inference_state.compiled_subprocess.get_access_handle(id)
  19. return getattr(handle.access, attribute)(*args, **kwargs)
  20. def create_simple_object(inference_state, obj):
  21. return access.create_access_path(inference_state, obj)
  22. def get_module_info(inference_state, sys_path=None, full_name=None, **kwargs):
  23. """
  24. Returns Tuple[Union[NamespaceInfo, FileIO, None], Optional[bool]]
  25. """
  26. if sys_path is not None:
  27. sys.path, temp = sys_path, sys.path
  28. try:
  29. return _find_module(full_name=full_name, **kwargs)
  30. except ImportError:
  31. return None, None
  32. finally:
  33. if sys_path is not None:
  34. sys.path = temp
  35. def get_builtin_module_names(inference_state):
  36. return sys.builtin_module_names
  37. def _test_raise_error(inference_state, exception_type):
  38. """
  39. Raise an error to simulate certain problems for unit tests.
  40. """
  41. raise exception_type
  42. def _test_print(inference_state, stderr=None, stdout=None):
  43. """
  44. Force some prints in the subprocesses. This exists for unit tests.
  45. """
  46. if stderr is not None:
  47. print(stderr, file=sys.stderr)
  48. sys.stderr.flush()
  49. if stdout is not None:
  50. print(stdout)
  51. sys.stdout.flush()
  52. def _get_init_path(directory_path):
  53. """
  54. The __init__ file can be searched in a directory. If found return it, else
  55. None.
  56. """
  57. for suffix in all_suffixes():
  58. path = os.path.join(directory_path, '__init__' + suffix)
  59. if os.path.exists(path):
  60. return path
  61. return None
  62. def safe_literal_eval(inference_state, value):
  63. return parser_utils.safe_literal_eval(value)
  64. def iter_module_names(*args, **kwargs):
  65. return list(_iter_module_names(*args, **kwargs))
  66. def _iter_module_names(inference_state, paths):
  67. # Python modules/packages
  68. for path in paths:
  69. try:
  70. dir_entries = ((entry.name, entry.is_dir()) for entry in os.scandir(path))
  71. except OSError:
  72. try:
  73. zip_import_info = zipimporter(path)
  74. # Unfortunately, there is no public way to access zipimporter's
  75. # private _files member. We therefore have to use a
  76. # custom function to iterate over the files.
  77. dir_entries = _zip_list_subdirectory(
  78. zip_import_info.archive, zip_import_info.prefix)
  79. except ZipImportError:
  80. # The file might not exist or reading it might lead to an error.
  81. debug.warning("Not possible to list directory: %s", path)
  82. continue
  83. for name, is_dir in dir_entries:
  84. # First Namespaces then modules/stubs
  85. if is_dir:
  86. # pycache is obviously not an interesting namespace. Also the
  87. # name must be a valid identifier.
  88. if name != '__pycache__' and name.isidentifier():
  89. yield name
  90. else:
  91. if name.endswith('.pyi'): # Stub files
  92. modname = name[:-4]
  93. else:
  94. modname = inspect.getmodulename(name)
  95. if modname and '.' not in modname:
  96. if modname != '__init__':
  97. yield modname
  98. def _find_module(string, path=None, full_name=None, is_global_search=True):
  99. """
  100. Provides information about a module.
  101. This function isolates the differences in importing libraries introduced with
  102. python 3.3 on; it gets a module name and optionally a path. It will return a
  103. tuple containin an open file for the module (if not builtin), the filename
  104. or the name of the module if it is a builtin one and a boolean indicating
  105. if the module is contained in a package.
  106. """
  107. spec = None
  108. loader = None
  109. for finder in sys.meta_path:
  110. if is_global_search and finder != importlib.machinery.PathFinder:
  111. p = None
  112. else:
  113. p = path
  114. try:
  115. find_spec = finder.find_spec
  116. except AttributeError:
  117. # These are old-school clases that still have a different API, just
  118. # ignore those.
  119. continue
  120. spec = find_spec(string, p)
  121. if spec is not None:
  122. if spec.origin == "frozen":
  123. continue
  124. loader = spec.loader
  125. if loader is None and not spec.has_location:
  126. # This is a namespace package.
  127. full_name = string if not path else full_name
  128. implicit_ns_info = ImplicitNSInfo(full_name, spec.submodule_search_locations._path)
  129. return implicit_ns_info, True
  130. break
  131. return _find_module_py33(string, path, loader)
  132. def _find_module_py33(string, path=None, loader=None, full_name=None, is_global_search=True):
  133. if not loader:
  134. spec = importlib.machinery.PathFinder.find_spec(string, path)
  135. if spec is not None:
  136. loader = spec.loader
  137. if loader is None and path is None: # Fallback to find builtins
  138. try:
  139. spec = importlib.util.find_spec(string)
  140. if spec is not None:
  141. loader = spec.loader
  142. except ValueError as e:
  143. # See #491. Importlib might raise a ValueError, to avoid this, we
  144. # just raise an ImportError to fix the issue.
  145. raise ImportError("Originally " + repr(e))
  146. if loader is None:
  147. raise ImportError("Couldn't find a loader for {}".format(string))
  148. return _from_loader(loader, string)
  149. def _from_loader(loader, string):
  150. try:
  151. is_package_method = loader.is_package
  152. except AttributeError:
  153. is_package = False
  154. else:
  155. is_package = is_package_method(string)
  156. try:
  157. get_filename = loader.get_filename
  158. except AttributeError:
  159. return None, is_package
  160. else:
  161. module_path = get_filename(string)
  162. # To avoid unicode and read bytes, "overwrite" loader.get_source if
  163. # possible.
  164. try:
  165. f = type(loader).get_source
  166. except AttributeError:
  167. raise ImportError("get_source was not defined on loader")
  168. if f is not importlib.machinery.SourceFileLoader.get_source:
  169. # Unfortunately we are reading unicode here, not bytes.
  170. # It seems hard to get bytes, because the zip importer
  171. # logic just unpacks the zip file and returns a file descriptor
  172. # that we cannot as easily access. Therefore we just read it as
  173. # a string in the cases where get_source was overwritten.
  174. code = loader.get_source(string)
  175. else:
  176. code = _get_source(loader, string)
  177. if code is None:
  178. return None, is_package
  179. if isinstance(loader, zipimporter):
  180. return ZipFileIO(module_path, code, Path(loader.archive)), is_package
  181. return KnownContentFileIO(module_path, code), is_package
  182. def _get_source(loader, fullname):
  183. """
  184. This method is here as a replacement for SourceLoader.get_source. That
  185. method returns unicode, but we prefer bytes.
  186. """
  187. path = loader.get_filename(fullname)
  188. try:
  189. return loader.get_data(path)
  190. except OSError:
  191. raise ImportError('source not available through get_data()',
  192. name=fullname)
  193. def _zip_list_subdirectory(zip_path, zip_subdir_path):
  194. zip_file = ZipFile(zip_path)
  195. zip_subdir_path = Path(zip_subdir_path)
  196. zip_content_file_paths = zip_file.namelist()
  197. for raw_file_name in zip_content_file_paths:
  198. file_path = Path(raw_file_name)
  199. if file_path.parent == zip_subdir_path:
  200. file_path = file_path.relative_to(zip_subdir_path)
  201. yield file_path.name, raw_file_name.endswith("/")
  202. class ImplicitNSInfo:
  203. """Stores information returned from an implicit namespace spec"""
  204. def __init__(self, name, paths):
  205. self.name = name
  206. self.paths = paths