forked from VimPlug/jedi
Fix os path resolving issues
This commit is contained in:
@@ -12,9 +12,7 @@ from jedi import debug
|
|||||||
from jedi.inference.utils import unite
|
from jedi.inference.utils import unite
|
||||||
from jedi.cache import memoize_method
|
from jedi.cache import memoize_method
|
||||||
from jedi.inference import imports
|
from jedi.inference import imports
|
||||||
from jedi.inference import compiled
|
|
||||||
from jedi.inference.imports import ImportName
|
from jedi.inference.imports import ImportName
|
||||||
from jedi.inference.value import FunctionExecutionContext
|
|
||||||
from jedi.inference.gradual.typeshed import StubModuleValue
|
from jedi.inference.gradual.typeshed import StubModuleValue
|
||||||
from jedi.inference.gradual.conversion import convert_names, convert_values
|
from jedi.inference.gradual.conversion import convert_names, convert_values
|
||||||
from jedi.inference.base_value import ValueSet
|
from jedi.inference.base_value import ValueSet
|
||||||
@@ -25,14 +23,14 @@ def _sort_names_by_start_pos(names):
|
|||||||
return sorted(names, key=lambda s: s.start_pos or (0, 0))
|
return sorted(names, key=lambda s: s.start_pos or (0, 0))
|
||||||
|
|
||||||
|
|
||||||
def defined_names(inference_state, value):
|
def defined_names(inference_state, context):
|
||||||
"""
|
"""
|
||||||
List sub-definitions (e.g., methods in class).
|
List sub-definitions (e.g., methods in class).
|
||||||
|
|
||||||
:type scope: Scope
|
:type scope: Scope
|
||||||
:rtype: list of Definition
|
:rtype: list of Definition
|
||||||
"""
|
"""
|
||||||
filter = next(value.get_filters())
|
filter = next(context.get_filters())
|
||||||
names = [name for name in filter.values()]
|
names = [name for name in filter.values()]
|
||||||
return [Definition(inference_state, n) for n in _sort_names_by_start_pos(names)]
|
return [Definition(inference_state, n) for n in _sort_names_by_start_pos(names)]
|
||||||
|
|
||||||
@@ -71,7 +69,7 @@ class BaseDefinition(object):
|
|||||||
self.is_keyword = isinstance(self._name, KeywordName)
|
self.is_keyword = isinstance(self._name, KeywordName)
|
||||||
|
|
||||||
@memoize_method
|
@memoize_method
|
||||||
def _get_module(self):
|
def _get_module_context(self):
|
||||||
# This can take a while to complete, because in the worst case of
|
# This can take a while to complete, because in the worst case of
|
||||||
# imports (consider `import a` completions), we need to load all
|
# imports (consider `import a` completions), we need to load all
|
||||||
# modules starting with a first.
|
# modules starting with a first.
|
||||||
@@ -80,11 +78,11 @@ class BaseDefinition(object):
|
|||||||
@property
|
@property
|
||||||
def module_path(self):
|
def module_path(self):
|
||||||
"""Shows the file path of a module. e.g. ``/usr/lib/python2.7/os.py``"""
|
"""Shows the file path of a module. e.g. ``/usr/lib/python2.7/os.py``"""
|
||||||
module = self._get_module()
|
module = self._get_module_context()
|
||||||
if module.is_stub() or not module.is_compiled():
|
if module.is_stub() or not module.is_compiled():
|
||||||
# Compiled modules should not return a module path even if they
|
# Compiled modules should not return a module path even if they
|
||||||
# have one.
|
# have one.
|
||||||
return self._get_module().py__file__()
|
return self._get_module_context().py__file__()
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -183,14 +181,14 @@ class BaseDefinition(object):
|
|||||||
>>> print(d.module_name) # doctest: +ELLIPSIS
|
>>> print(d.module_name) # doctest: +ELLIPSIS
|
||||||
json
|
json
|
||||||
"""
|
"""
|
||||||
return self._get_module().py__name__()
|
return self._get_module_context().py__name__()
|
||||||
|
|
||||||
def in_builtin_module(self):
|
def in_builtin_module(self):
|
||||||
"""Whether this is a builtin module."""
|
"""Whether this is a builtin module."""
|
||||||
if isinstance(self._get_module(), StubModuleValue):
|
value = self._get_module_context().get_value()
|
||||||
return any(isinstance(value, compiled.CompiledObject)
|
if isinstance(value, StubModuleValue):
|
||||||
for value in self._get_module().non_stub_value_set)
|
return any(v.is_compiled() for v in value.non_stub_value_set)
|
||||||
return isinstance(self._get_module(), compiled.CompiledObject)
|
return value.is_compiled()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def line(self):
|
def line(self):
|
||||||
@@ -360,13 +358,12 @@ class BaseDefinition(object):
|
|||||||
if not self._name.is_value_name:
|
if not self._name.is_value_name:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
value = self._name.parent_context
|
context = self._name.parent_context
|
||||||
if value is None:
|
if context is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if isinstance(value, FunctionExecutionContext):
|
# TODO private access!
|
||||||
value = value.function_value
|
return Definition(self._inference_state, context._value.name)
|
||||||
return Definition(self._inference_state, value.name)
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<%s %sname=%r, description=%r>" % (
|
return "<%s %sname=%r, description=%r>" % (
|
||||||
@@ -588,7 +585,7 @@ class Definition(BaseDefinition):
|
|||||||
"""
|
"""
|
||||||
defs = self._name.infer()
|
defs = self._name.infer()
|
||||||
return sorted(
|
return sorted(
|
||||||
unite(defined_names(self._inference_state, d) for d in defs),
|
unite(defined_names(self._inference_state, d.as_context()) for d in defs),
|
||||||
key=lambda s: s._name.start_pos or (0, 0)
|
key=lambda s: s._name.start_pos or (0, 0)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ class Completion:
|
|||||||
self._like_name, self._call_signatures_callback,
|
self._like_name, self._call_signatures_callback,
|
||||||
self._code_lines, self._original_position
|
self._code_lines, self._original_position
|
||||||
))
|
))
|
||||||
|
return completions
|
||||||
if completions:
|
if completions:
|
||||||
return completions
|
return completions
|
||||||
|
|
||||||
|
|||||||
@@ -111,11 +111,11 @@ class InferenceState(object):
|
|||||||
self.reset_recursion_limitations()
|
self.reset_recursion_limitations()
|
||||||
self.allow_different_encoding = True
|
self.allow_different_encoding = True
|
||||||
|
|
||||||
def import_module(self, import_names, parent_module_context=None,
|
def import_module(self, import_names, parent_module_value=None,
|
||||||
sys_path=None, prefer_stubs=True):
|
sys_path=None, prefer_stubs=True):
|
||||||
if sys_path is None:
|
if sys_path is None:
|
||||||
sys_path = self.get_sys_path()
|
sys_path = self.get_sys_path()
|
||||||
return imports.import_module(self, import_names, parent_module_context,
|
return imports.import_module(self, import_names, parent_module_value,
|
||||||
sys_path, prefer_stubs=prefer_stubs)
|
sys_path, prefer_stubs=prefer_stubs)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|||||||
@@ -103,6 +103,10 @@ class ModuleContext(AbstractContext):
|
|||||||
def py__package__(self):
|
def py__package__(self):
|
||||||
return self._value.py__package__
|
return self._value.py__package__
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_package(self):
|
||||||
|
return self._value.is_package
|
||||||
|
|
||||||
def get_filters(self, until_position=None, origin_scope=None):
|
def get_filters(self, until_position=None, origin_scope=None):
|
||||||
filters = self._value.get_filters(origin_scope)
|
filters = self._value.get_filters(origin_scope)
|
||||||
# Skip the first filter and replace it.
|
# Skip the first filter and replace it.
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ def _load_stub_module(module):
|
|||||||
module.inference_state,
|
module.inference_state,
|
||||||
import_names=module.string_names,
|
import_names=module.string_names,
|
||||||
python_value_set=ValueSet([module]),
|
python_value_set=ValueSet([module]),
|
||||||
parent_module_context=None,
|
parent_module_value=None,
|
||||||
sys_path=module.inference_state.get_sys_path(),
|
sys_path=module.inference_state.get_sys_path(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from jedi._compatibility import FileNotFoundError, cast_path
|
|||||||
from jedi.parser_utils import get_cached_code_lines
|
from jedi.parser_utils import get_cached_code_lines
|
||||||
from jedi.inference.base_value import ValueSet, NO_VALUES
|
from jedi.inference.base_value import ValueSet, NO_VALUES
|
||||||
from jedi.inference.gradual.stub_value import TypingModuleWrapper, StubModuleValue
|
from jedi.inference.gradual.stub_value import TypingModuleWrapper, StubModuleValue
|
||||||
from jedi.inference.context import ModuleContext
|
from jedi.inference.value import ModuleValue
|
||||||
|
|
||||||
_jedi_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
_jedi_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
TYPESHED_PATH = os.path.join(_jedi_path, 'third_party', 'typeshed')
|
TYPESHED_PATH = os.path.join(_jedi_path, 'third_party', 'typeshed')
|
||||||
@@ -90,27 +90,30 @@ def _cache_stub_file_map(version_info):
|
|||||||
|
|
||||||
def import_module_decorator(func):
|
def import_module_decorator(func):
|
||||||
@wraps(func)
|
@wraps(func)
|
||||||
def wrapper(inference_state, import_names, parent_module_context, sys_path, prefer_stubs):
|
def wrapper(inference_state, import_names, parent_module_value, sys_path, prefer_stubs):
|
||||||
try:
|
try:
|
||||||
python_value_set = inference_state.module_cache.get(import_names)
|
python_value_set = inference_state.module_cache.get(import_names)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
if parent_module_context is not None and parent_module_context.is_stub():
|
if parent_module_value is not None and parent_module_value.is_stub():
|
||||||
parent_module_contexts = parent_module_context.non_stub_value_set
|
parent_module_values = parent_module_value.non_stub_value_set
|
||||||
else:
|
else:
|
||||||
parent_module_contexts = [parent_module_context]
|
parent_module_values = [parent_module_value]
|
||||||
if import_names == ('os', 'path'):
|
if import_names == ('os', 'path'):
|
||||||
# This is a huge exception, we follow a nested import
|
# This is a huge exception, we follow a nested import
|
||||||
# ``os.path``, because it's a very important one in Python
|
# ``os.path``, because it's a very important one in Python
|
||||||
# that is being achieved by messing with ``sys.modules`` in
|
# that is being achieved by messing with ``sys.modules`` in
|
||||||
# ``os``.
|
# ``os``.
|
||||||
python_parent = next(iter(parent_module_contexts))
|
python_parent = next(iter(parent_module_values))
|
||||||
if python_parent is None:
|
if python_parent is None:
|
||||||
python_parent, = inference_state.import_module(('os',), prefer_stubs=False)
|
python_parent, = inference_state.import_module(('os',), prefer_stubs=False)
|
||||||
python_value_set = python_parent.py__getattribute__('path')
|
python_value_set = ValueSet.from_sets(
|
||||||
|
func(inference_state, (n,), None, sys_path,)
|
||||||
|
for n in ['posixpath', 'ntpath', 'macpath', 'os2emxpath']
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
python_value_set = ValueSet.from_sets(
|
python_value_set = ValueSet.from_sets(
|
||||||
func(inference_state, import_names, p, sys_path,)
|
func(inference_state, import_names, p, sys_path,)
|
||||||
for p in parent_module_contexts
|
for p in parent_module_values
|
||||||
)
|
)
|
||||||
inference_state.module_cache.add(import_names, python_value_set)
|
inference_state.module_cache.add(import_names, python_value_set)
|
||||||
|
|
||||||
@@ -118,7 +121,7 @@ def import_module_decorator(func):
|
|||||||
return python_value_set
|
return python_value_set
|
||||||
|
|
||||||
stub = _try_to_load_stub_cached(inference_state, import_names, python_value_set,
|
stub = _try_to_load_stub_cached(inference_state, import_names, python_value_set,
|
||||||
parent_module_context, sys_path)
|
parent_module_value, sys_path)
|
||||||
if stub is not None:
|
if stub is not None:
|
||||||
return ValueSet([stub])
|
return ValueSet([stub])
|
||||||
return python_value_set
|
return python_value_set
|
||||||
@@ -141,18 +144,18 @@ def _try_to_load_stub_cached(inference_state, import_names, *args, **kwargs):
|
|||||||
|
|
||||||
|
|
||||||
def _try_to_load_stub(inference_state, import_names, python_value_set,
|
def _try_to_load_stub(inference_state, import_names, python_value_set,
|
||||||
parent_module_context, sys_path):
|
parent_module_value, sys_path):
|
||||||
"""
|
"""
|
||||||
Trying to load a stub for a set of import_names.
|
Trying to load a stub for a set of import_names.
|
||||||
|
|
||||||
This is modelled to work like "PEP 561 -- Distributing and Packaging Type
|
This is modelled to work like "PEP 561 -- Distributing and Packaging Type
|
||||||
Information", see https://www.python.org/dev/peps/pep-0561.
|
Information", see https://www.python.org/dev/peps/pep-0561.
|
||||||
"""
|
"""
|
||||||
if parent_module_context is None and len(import_names) > 1:
|
if parent_module_value is None and len(import_names) > 1:
|
||||||
try:
|
try:
|
||||||
parent_module_context = _try_to_load_stub_cached(
|
parent_module_value = _try_to_load_stub_cached(
|
||||||
inference_state, import_names[:-1], NO_VALUES,
|
inference_state, import_names[:-1], NO_VALUES,
|
||||||
parent_module_context=None, sys_path=sys_path)
|
parent_module_value=None, sys_path=sys_path)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -196,15 +199,15 @@ def _try_to_load_stub(inference_state, import_names, python_value_set,
|
|||||||
return m
|
return m
|
||||||
|
|
||||||
# 3. Try to load typeshed
|
# 3. Try to load typeshed
|
||||||
m = _load_from_typeshed(inference_state, python_value_set, parent_module_context, import_names)
|
m = _load_from_typeshed(inference_state, python_value_set, parent_module_value, import_names)
|
||||||
if m is not None:
|
if m is not None:
|
||||||
return m
|
return m
|
||||||
|
|
||||||
# 4. Try to load pyi file somewhere if python_value_set was not defined.
|
# 4. Try to load pyi file somewhere if python_value_set was not defined.
|
||||||
if not python_value_set:
|
if not python_value_set:
|
||||||
if parent_module_context is not None:
|
if parent_module_value is not None:
|
||||||
try:
|
try:
|
||||||
method = parent_module_context.py__path__
|
method = parent_module_value.py__path__
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
check_path = []
|
check_path = []
|
||||||
else:
|
else:
|
||||||
@@ -230,18 +233,18 @@ def _try_to_load_stub(inference_state, import_names, python_value_set,
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def _load_from_typeshed(inference_state, python_value_set, parent_module_context, import_names):
|
def _load_from_typeshed(inference_state, python_value_set, parent_module_value, import_names):
|
||||||
import_name = import_names[-1]
|
import_name = import_names[-1]
|
||||||
map_ = None
|
map_ = None
|
||||||
if len(import_names) == 1:
|
if len(import_names) == 1:
|
||||||
map_ = _cache_stub_file_map(inference_state.grammar.version_info)
|
map_ = _cache_stub_file_map(inference_state.grammar.version_info)
|
||||||
import_name = _IMPORT_MAP.get(import_name, import_name)
|
import_name = _IMPORT_MAP.get(import_name, import_name)
|
||||||
elif isinstance(parent_module_context, ModuleContext):
|
elif isinstance(parent_module_value, ModuleValue):
|
||||||
if not parent_module_context.is_package:
|
if not parent_module_value.is_package:
|
||||||
# Only if it's a package (= a folder) something can be
|
# Only if it's a package (= a folder) something can be
|
||||||
# imported.
|
# imported.
|
||||||
return None
|
return None
|
||||||
path = parent_module_context.py__path__()
|
path = parent_module_value.py__path__()
|
||||||
map_ = _merge_create_stub_map(path)
|
map_ = _merge_create_stub_map(path)
|
||||||
|
|
||||||
if map_ is not None:
|
if map_ is not None:
|
||||||
|
|||||||
@@ -295,9 +295,9 @@ class Importer(object):
|
|||||||
value_set = ValueSet.from_sets([
|
value_set = ValueSet.from_sets([
|
||||||
self._inference_state.import_module(
|
self._inference_state.import_module(
|
||||||
import_names[:i+1],
|
import_names[:i+1],
|
||||||
parent_module_context,
|
parent_module_value,
|
||||||
sys_path
|
sys_path
|
||||||
) for parent_module_context in value_set
|
) for parent_module_value in value_set
|
||||||
])
|
])
|
||||||
if not value_set:
|
if not value_set:
|
||||||
message = 'No module named ' + '.'.join(import_names)
|
message = 'No module named ' + '.'.join(import_names)
|
||||||
@@ -377,7 +377,7 @@ class Importer(object):
|
|||||||
|
|
||||||
@plugin_manager.decorate()
|
@plugin_manager.decorate()
|
||||||
@import_module_decorator
|
@import_module_decorator
|
||||||
def import_module(inference_state, import_names, parent_module_context, sys_path):
|
def import_module(inference_state, import_names, parent_module_value, sys_path):
|
||||||
"""
|
"""
|
||||||
This method is very similar to importlib's `_gcd_import`.
|
This method is very similar to importlib's `_gcd_import`.
|
||||||
"""
|
"""
|
||||||
@@ -388,7 +388,7 @@ def import_module(inference_state, import_names, parent_module_context, sys_path
|
|||||||
return ValueSet([module])
|
return ValueSet([module])
|
||||||
|
|
||||||
module_name = '.'.join(import_names)
|
module_name = '.'.join(import_names)
|
||||||
if parent_module_context is None:
|
if parent_module_value is None:
|
||||||
# Override the sys.path. It works only good that way.
|
# Override the sys.path. It works only good that way.
|
||||||
# Injecting the path directly into `find_module` did not work.
|
# Injecting the path directly into `find_module` did not work.
|
||||||
file_io_or_ns, is_pkg = inference_state.compiled_subprocess.get_module_info(
|
file_io_or_ns, is_pkg = inference_state.compiled_subprocess.get_module_info(
|
||||||
@@ -401,7 +401,7 @@ def import_module(inference_state, import_names, parent_module_context, sys_path
|
|||||||
return NO_VALUES
|
return NO_VALUES
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
method = parent_module_context.py__path__
|
method = parent_module_value.py__path__
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# The module is not a package.
|
# The module is not a package.
|
||||||
return NO_VALUES
|
return NO_VALUES
|
||||||
@@ -441,7 +441,7 @@ def import_module(inference_state, import_names, parent_module_context, sys_path
|
|||||||
is_package=is_pkg,
|
is_package=is_pkg,
|
||||||
)
|
)
|
||||||
|
|
||||||
if parent_module_context is None:
|
if parent_module_value is None:
|
||||||
debug.dbg('global search_module %s: %s', import_names[-1], module)
|
debug.dbg('global search_module %s: %s', import_names[-1], module)
|
||||||
else:
|
else:
|
||||||
debug.dbg('search_module %s in paths %s: %s', module_name, paths, module)
|
debug.dbg('search_module %s in paths %s: %s', module_name, paths, module)
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ def test_base_auto_import_modules(auto_import_json, Script):
|
|||||||
loads, = Script('import json; json.loads').goto_definitions()
|
loads, = Script('import json; json.loads').goto_definitions()
|
||||||
assert isinstance(loads._name, ValueName)
|
assert isinstance(loads._name, ValueName)
|
||||||
value, = loads._name.infer()
|
value, = loads._name.infer()
|
||||||
assert isinstance(value.parent_context, StubModuleValue)
|
assert isinstance(value.parent_context._value, StubModuleValue)
|
||||||
|
|
||||||
|
|
||||||
def test_auto_import_modules_imports(auto_import_json, Script):
|
def test_auto_import_modules_imports(auto_import_json, Script):
|
||||||
|
|||||||
Reference in New Issue
Block a user