| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- import sys
- import os
- import inspect
- import importlib
- from pathlib import Path
- from zipfile import ZipFile
- from zipimport import zipimporter, ZipImportError
- from importlib.machinery import all_suffixes
- from jedi.inference.compiled import access
- from jedi import debug
- from jedi import parser_utils
- from jedi.file_io import KnownContentFileIO, ZipFileIO
- def get_sys_path():
- return sys.path
- def load_module(inference_state, **kwargs):
- return access.load_module(inference_state, **kwargs)
- def get_compiled_method_return(inference_state, id, attribute, *args, **kwargs):
- handle = inference_state.compiled_subprocess.get_access_handle(id)
- return getattr(handle.access, attribute)(*args, **kwargs)
- def create_simple_object(inference_state, obj):
- return access.create_access_path(inference_state, obj)
- def get_module_info(inference_state, sys_path=None, full_name=None, **kwargs):
- """
- Returns Tuple[Union[NamespaceInfo, FileIO, None], Optional[bool]]
- """
- if sys_path is not None:
- sys.path, temp = sys_path, sys.path
- try:
- return _find_module(full_name=full_name, **kwargs)
- except ImportError:
- return None, None
- finally:
- if sys_path is not None:
- sys.path = temp
- def get_builtin_module_names(inference_state):
- return sys.builtin_module_names
- def _test_raise_error(inference_state, exception_type):
- """
- Raise an error to simulate certain problems for unit tests.
- """
- raise exception_type
- def _test_print(inference_state, stderr=None, stdout=None):
- """
- Force some prints in the subprocesses. This exists for unit tests.
- """
- if stderr is not None:
- print(stderr, file=sys.stderr)
- sys.stderr.flush()
- if stdout is not None:
- print(stdout)
- sys.stdout.flush()
- def _get_init_path(directory_path):
- """
- The __init__ file can be searched in a directory. If found return it, else
- None.
- """
- for suffix in all_suffixes():
- path = os.path.join(directory_path, '__init__' + suffix)
- if os.path.exists(path):
- return path
- return None
- def safe_literal_eval(inference_state, value):
- return parser_utils.safe_literal_eval(value)
- def iter_module_names(*args, **kwargs):
- return list(_iter_module_names(*args, **kwargs))
- def _iter_module_names(inference_state, paths):
- # Python modules/packages
- for path in paths:
- try:
- dir_entries = ((entry.name, entry.is_dir()) for entry in os.scandir(path))
- except OSError:
- try:
- zip_import_info = zipimporter(path)
- # Unfortunately, there is no public way to access zipimporter's
- # private _files member. We therefore have to use a
- # custom function to iterate over the files.
- dir_entries = _zip_list_subdirectory(
- zip_import_info.archive, zip_import_info.prefix)
- except ZipImportError:
- # The file might not exist or reading it might lead to an error.
- debug.warning("Not possible to list directory: %s", path)
- continue
- for name, is_dir in dir_entries:
- # First Namespaces then modules/stubs
- if is_dir:
- # pycache is obviously not an interesting namespace. Also the
- # name must be a valid identifier.
- if name != '__pycache__' and name.isidentifier():
- yield name
- else:
- if name.endswith('.pyi'): # Stub files
- modname = name[:-4]
- else:
- modname = inspect.getmodulename(name)
- if modname and '.' not in modname:
- if modname != '__init__':
- yield modname
- def _find_module(string, path=None, full_name=None, is_global_search=True):
- """
- Provides information about a module.
- This function isolates the differences in importing libraries introduced with
- python 3.3 on; it gets a module name and optionally a path. It will return a
- tuple containin an open file for the module (if not builtin), the filename
- or the name of the module if it is a builtin one and a boolean indicating
- if the module is contained in a package.
- """
- spec = None
- loader = None
- for finder in sys.meta_path:
- if is_global_search and finder != importlib.machinery.PathFinder:
- p = None
- else:
- p = path
- try:
- find_spec = finder.find_spec
- except AttributeError:
- # These are old-school clases that still have a different API, just
- # ignore those.
- continue
- spec = find_spec(string, p)
- if spec is not None:
- if spec.origin == "frozen":
- continue
- loader = spec.loader
- if loader is None and not spec.has_location:
- # This is a namespace package.
- full_name = string if not path else full_name
- implicit_ns_info = ImplicitNSInfo(full_name, spec.submodule_search_locations._path)
- return implicit_ns_info, True
- break
- return _find_module_py33(string, path, loader)
- def _find_module_py33(string, path=None, loader=None, full_name=None, is_global_search=True):
- if not loader:
- spec = importlib.machinery.PathFinder.find_spec(string, path)
- if spec is not None:
- loader = spec.loader
- if loader is None and path is None: # Fallback to find builtins
- try:
- spec = importlib.util.find_spec(string)
- if spec is not None:
- loader = spec.loader
- except ValueError as e:
- # See #491. Importlib might raise a ValueError, to avoid this, we
- # just raise an ImportError to fix the issue.
- raise ImportError("Originally " + repr(e))
- if loader is None:
- raise ImportError("Couldn't find a loader for {}".format(string))
- return _from_loader(loader, string)
- def _from_loader(loader, string):
- try:
- is_package_method = loader.is_package
- except AttributeError:
- is_package = False
- else:
- is_package = is_package_method(string)
- try:
- get_filename = loader.get_filename
- except AttributeError:
- return None, is_package
- else:
- module_path = get_filename(string)
- # To avoid unicode and read bytes, "overwrite" loader.get_source if
- # possible.
- try:
- f = type(loader).get_source
- except AttributeError:
- raise ImportError("get_source was not defined on loader")
- if f is not importlib.machinery.SourceFileLoader.get_source:
- # Unfortunately we are reading unicode here, not bytes.
- # It seems hard to get bytes, because the zip importer
- # logic just unpacks the zip file and returns a file descriptor
- # that we cannot as easily access. Therefore we just read it as
- # a string in the cases where get_source was overwritten.
- code = loader.get_source(string)
- else:
- code = _get_source(loader, string)
- if code is None:
- return None, is_package
- if isinstance(loader, zipimporter):
- return ZipFileIO(module_path, code, Path(loader.archive)), is_package
- return KnownContentFileIO(module_path, code), is_package
- def _get_source(loader, fullname):
- """
- This method is here as a replacement for SourceLoader.get_source. That
- method returns unicode, but we prefer bytes.
- """
- path = loader.get_filename(fullname)
- try:
- return loader.get_data(path)
- except OSError:
- raise ImportError('source not available through get_data()',
- name=fullname)
- def _zip_list_subdirectory(zip_path, zip_subdir_path):
- zip_file = ZipFile(zip_path)
- zip_subdir_path = Path(zip_subdir_path)
- zip_content_file_paths = zip_file.namelist()
- for raw_file_name in zip_content_file_paths:
- file_path = Path(raw_file_name)
- if file_path.parent == zip_subdir_path:
- file_path = file_path.relative_to(zip_subdir_path)
- yield file_path.name, raw_file_name.endswith("/")
- class ImplicitNSInfo:
- """Stores information returned from an implicit namespace spec"""
- def __init__(self, name, paths):
- self.name = name
- self.paths = paths
|