diff --git a/jedi/api/classes.py b/jedi/api/classes.py index 4173b604..c774e233 100644 --- a/jedi/api/classes.py +++ b/jedi/api/classes.py @@ -12,9 +12,7 @@ from jedi import debug from jedi.inference.utils import unite from jedi.cache import memoize_method from jedi.inference import imports -from jedi.inference import compiled from jedi.inference.imports import ImportName -from jedi.inference.value import FunctionExecutionContext from jedi.inference.gradual.typeshed import StubModuleValue from jedi.inference.gradual.conversion import convert_names, convert_values 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)) -def defined_names(inference_state, value): +def defined_names(inference_state, context): """ List sub-definitions (e.g., methods in class). :type scope: Scope :rtype: list of Definition """ - filter = next(value.get_filters()) + filter = next(context.get_filters()) names = [name for name in filter.values()] 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) @memoize_method - def _get_module(self): + def _get_module_context(self): # This can take a while to complete, because in the worst case of # imports (consider `import a` completions), we need to load all # modules starting with a first. @@ -80,11 +78,11 @@ class BaseDefinition(object): @property def module_path(self): """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(): # Compiled modules should not return a module path even if they # have one. - return self._get_module().py__file__() + return self._get_module_context().py__file__() return None @@ -183,14 +181,14 @@ class BaseDefinition(object): >>> print(d.module_name) # doctest: +ELLIPSIS json """ - return self._get_module().py__name__() + return self._get_module_context().py__name__() def in_builtin_module(self): """Whether this is a builtin module.""" - if isinstance(self._get_module(), StubModuleValue): - return any(isinstance(value, compiled.CompiledObject) - for value in self._get_module().non_stub_value_set) - return isinstance(self._get_module(), compiled.CompiledObject) + value = self._get_module_context().get_value() + if isinstance(value, StubModuleValue): + return any(v.is_compiled() for v in value.non_stub_value_set) + return value.is_compiled() @property def line(self): @@ -360,13 +358,12 @@ class BaseDefinition(object): if not self._name.is_value_name: return None - value = self._name.parent_context - if value is None: + context = self._name.parent_context + if context is None: return None - if isinstance(value, FunctionExecutionContext): - value = value.function_value - return Definition(self._inference_state, value.name) + # TODO private access! + return Definition(self._inference_state, context._value.name) def __repr__(self): return "<%s %sname=%r, description=%r>" % ( @@ -588,7 +585,7 @@ class Definition(BaseDefinition): """ defs = self._name.infer() 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) ) diff --git a/jedi/api/completion.py b/jedi/api/completion.py index 47c15797..3a1239e2 100644 --- a/jedi/api/completion.py +++ b/jedi/api/completion.py @@ -109,6 +109,7 @@ class Completion: self._like_name, self._call_signatures_callback, self._code_lines, self._original_position )) + return completions if completions: return completions diff --git a/jedi/inference/__init__.py b/jedi/inference/__init__.py index a282a101..88384db8 100644 --- a/jedi/inference/__init__.py +++ b/jedi/inference/__init__.py @@ -111,11 +111,11 @@ class InferenceState(object): self.reset_recursion_limitations() 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): if sys_path is None: 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) @staticmethod diff --git a/jedi/inference/context.py b/jedi/inference/context.py index 64617aeb..0a2e6c69 100644 --- a/jedi/inference/context.py +++ b/jedi/inference/context.py @@ -103,6 +103,10 @@ class ModuleContext(AbstractContext): def py__package__(self): 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): filters = self._value.get_filters(origin_scope) # Skip the first filter and replace it. diff --git a/jedi/inference/gradual/conversion.py b/jedi/inference/gradual/conversion.py index 7226f749..96ffc2e7 100644 --- a/jedi/inference/gradual/conversion.py +++ b/jedi/inference/gradual/conversion.py @@ -91,7 +91,7 @@ def _load_stub_module(module): module.inference_state, import_names=module.string_names, python_value_set=ValueSet([module]), - parent_module_context=None, + parent_module_value=None, sys_path=module.inference_state.get_sys_path(), ) diff --git a/jedi/inference/gradual/typeshed.py b/jedi/inference/gradual/typeshed.py index dfa8e1d7..1dc9d511 100644 --- a/jedi/inference/gradual/typeshed.py +++ b/jedi/inference/gradual/typeshed.py @@ -7,7 +7,7 @@ from jedi._compatibility import FileNotFoundError, cast_path from jedi.parser_utils import get_cached_code_lines from jedi.inference.base_value import ValueSet, NO_VALUES 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__)))) 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): @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: python_value_set = inference_state.module_cache.get(import_names) except KeyError: - if parent_module_context is not None and parent_module_context.is_stub(): - parent_module_contexts = parent_module_context.non_stub_value_set + if parent_module_value is not None and parent_module_value.is_stub(): + parent_module_values = parent_module_value.non_stub_value_set else: - parent_module_contexts = [parent_module_context] + parent_module_values = [parent_module_value] if import_names == ('os', 'path'): # This is a huge exception, we follow a nested import # ``os.path``, because it's a very important one in Python # that is being achieved by messing with ``sys.modules`` in # ``os``. - python_parent = next(iter(parent_module_contexts)) + python_parent = next(iter(parent_module_values)) if python_parent is None: 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: python_value_set = ValueSet.from_sets( 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) @@ -118,7 +121,7 @@ def import_module_decorator(func): return 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: return ValueSet([stub]) 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, - parent_module_context, sys_path): + parent_module_value, sys_path): """ Trying to load a stub for a set of import_names. This is modelled to work like "PEP 561 -- Distributing and Packaging Type 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: - parent_module_context = _try_to_load_stub_cached( + parent_module_value = _try_to_load_stub_cached( 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: pass @@ -196,15 +199,15 @@ def _try_to_load_stub(inference_state, import_names, python_value_set, return m # 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: return m # 4. Try to load pyi file somewhere if python_value_set was not defined. if not python_value_set: - if parent_module_context is not None: + if parent_module_value is not None: try: - method = parent_module_context.py__path__ + method = parent_module_value.py__path__ except AttributeError: check_path = [] else: @@ -230,18 +233,18 @@ def _try_to_load_stub(inference_state, import_names, python_value_set, 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] map_ = None if len(import_names) == 1: map_ = _cache_stub_file_map(inference_state.grammar.version_info) import_name = _IMPORT_MAP.get(import_name, import_name) - elif isinstance(parent_module_context, ModuleContext): - if not parent_module_context.is_package: + elif isinstance(parent_module_value, ModuleValue): + if not parent_module_value.is_package: # Only if it's a package (= a folder) something can be # imported. return None - path = parent_module_context.py__path__() + path = parent_module_value.py__path__() map_ = _merge_create_stub_map(path) if map_ is not None: diff --git a/jedi/inference/imports.py b/jedi/inference/imports.py index 44064f18..137e747d 100644 --- a/jedi/inference/imports.py +++ b/jedi/inference/imports.py @@ -295,9 +295,9 @@ class Importer(object): value_set = ValueSet.from_sets([ self._inference_state.import_module( import_names[:i+1], - parent_module_context, + parent_module_value, sys_path - ) for parent_module_context in value_set + ) for parent_module_value in value_set ]) if not value_set: message = 'No module named ' + '.'.join(import_names) @@ -377,7 +377,7 @@ class Importer(object): @plugin_manager.decorate() @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`. """ @@ -388,7 +388,7 @@ def import_module(inference_state, import_names, parent_module_context, sys_path return ValueSet([module]) 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. # Injecting the path directly into `find_module` did not work. 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 else: try: - method = parent_module_context.py__path__ + method = parent_module_value.py__path__ except AttributeError: # The module is not a package. return NO_VALUES @@ -441,7 +441,7 @@ def import_module(inference_state, import_names, parent_module_context, sys_path 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) else: debug.dbg('search_module %s in paths %s: %s', module_name, paths, module) diff --git a/test/test_settings.py b/test/test_settings.py index 55caf0cb..d650627b 100644 --- a/test/test_settings.py +++ b/test/test_settings.py @@ -15,7 +15,7 @@ def test_base_auto_import_modules(auto_import_json, Script): loads, = Script('import json; json.loads').goto_definitions() assert isinstance(loads._name, ValueName) 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):