diff --git a/jedi/_compatibility.py b/jedi/_compatibility.py index c46b6402..8f7bc01f 100644 --- a/jedi/_compatibility.py +++ b/jedi/_compatibility.py @@ -85,6 +85,7 @@ def find_module_py33(string, path=None, loader=None, full_name=None, is_global_s raise ImportError("Couldn't find a loader for {}".format(string)) return _from_loader(loader, string) + issss is_package = loader.is_package(string) if is_package: if hasattr(loader, 'archive'): @@ -117,11 +118,6 @@ class ZipFileIO(KnownContentFileIO): def _from_loader(loader, string): is_package = loader.is_package(string) - #if isinstance(loader, ExtensionLoader): - # ExtensionLoader has not attribute get_filename, instead it has a - # path attribute that we can use to retrieve the module path - # module_path = loader.path - #else: try: get_filename = loader.get_filename except AttributeError: @@ -129,18 +125,40 @@ def _from_loader(loader, string): else: module_path = get_filename(string) - code = loader.get_source(string) + # To avoid unicode and read bytes, "overwrite" loader.get_source if + # possible. + f = loader.get_source.__func__ + if is_py3 and 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, loader.archive), is_package - # Unfortunately we are reading unicode here already, not bytes. - # It seems however 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. 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 as exc: + raise ImportError('source not available through get_data()', + name=fullname) from exc + + def find_module_pre_py3(string, path=None, full_name=None, is_global_search=True): # This import is here, because in other places it will raise a # DeprecationWarning. diff --git a/test/test_api/test_environment.py b/test/test_api/test_environment.py index cdbe4051..5c1911e4 100644 --- a/test/test_api/test_environment.py +++ b/test/test_api/test_environment.py @@ -7,7 +7,8 @@ import jedi from jedi._compatibility import py_version from jedi.api.environment import get_default_environment, find_virtualenvs, \ InvalidPythonEnvironment, find_system_environments, \ - get_system_environment, create_environment, get_cached_default_environment + get_system_environment, create_environment, InterpreterEnvironment, \ + get_cached_default_environment def test_sys_path(): @@ -71,7 +72,9 @@ def test_stdout_in_subprocess(evaluator, Script): Script('1').goto_definitions() -def test_killed_subprocess(evaluator, Script): +def test_killed_subprocess(evaluator, Script, environment): + if isinstance(environment, InterpreterEnvironment): + pytest.skip("We cannot kill our own process") # Just kill the subprocess. evaluator.compiled_subprocess._compiled_subprocess._process.kill() # Since the process was terminated (and nobody knows about it) the first diff --git a/test/test_evaluate/test_pyc.py b/test/test_evaluate/test_pyc.py index ac4c6996..37449572 100644 --- a/test/test_evaluate/test_pyc.py +++ b/test/test_evaluate/test_pyc.py @@ -13,7 +13,7 @@ import sys import pytest import jedi -from jedi.api.environment import SameEnvironment +from jedi.api.environment import SameEnvironment, InterpreterEnvironment SRC = """class Foo: @@ -55,13 +55,19 @@ def pyc_project_path(tmpdir): shutil.rmtree(path) -def test_pyc(pyc_project_path): +def test_pyc(pyc_project_path, environment): """ The list of completion must be greater than 2. """ path = os.path.join(pyc_project_path, 'blub.py') + if not isinstance(environment, InterpreterEnvironment): + # We are using the same version for pyc completions here, because it + # was compiled in that version. However with interpreter environments + # we also have the same version and it's easier to debug. + environment = SameEnvironment() + environment = environment s = jedi.Script( "from dummy_package import dummy; dummy.", path=path, - environment=SameEnvironment()) + environment=environment) assert len(s.completions()) >= 2