From 6e2a76feb9d6586a9c9db804661f8fb0292c8eeb Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Sun, 15 Dec 2019 17:37:24 +0100 Subject: [PATCH] Fix a goto case with nested pyi files --- jedi/inference/__init__.py | 9 ++-- jedi/inference/compiled/access.py | 19 +++---- jedi/inference/imports.py | 51 ++++++++++++------- .../test_gradual/test_conversion.py | 7 +++ .../test_inference/test_gradual/test_stubs.py | 6 +-- 5 files changed, 56 insertions(+), 36 deletions(-) diff --git a/jedi/inference/__init__.py b/jedi/inference/__init__.py index 6540d1f4..bd1b66c3 100644 --- a/jedi/inference/__init__.py +++ b/jedi/inference/__init__.py @@ -107,12 +107,9 @@ class InferenceState(object): self.reset_recursion_limitations() - 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_value, - sys_path, prefer_stubs=prefer_stubs) + def import_module(self, import_names, sys_path=None, prefer_stubs=True): + return imports.import_module_by_names( + self, import_names, sys_path, prefer_stubs=prefer_stubs) @staticmethod @plugin_manager.decorate() diff --git a/jedi/inference/compiled/access.py b/jedi/inference/compiled/access.py index 54f01691..95fa3fa4 100644 --- a/jedi/inference/compiled/access.py +++ b/jedi/inference/compiled/access.py @@ -391,15 +391,16 @@ class DirectObjectAccess(object): except AttributeError: pass else: - try: - __import__(module) - # For some modules like _sqlite3, the __module__ for classes is - # different, in this case it's sqlite3. So we have to try to - # load that "original" module, because it's not loaded yet. If - # we don't do that, we don't really have a "parent" module and - # we would fall back to builtins. - except ImportError: - pass + if module is not None: + try: + __import__(module) + # For some modules like _sqlite3, the __module__ for classes is + # different, in this case it's sqlite3. So we have to try to + # load that "original" module, because it's not loaded yet. If + # we don't do that, we don't really have a "parent" module and + # we would fall back to builtins. + except ImportError: + pass module = inspect.getmodule(return_obj) if module is None: diff --git a/jedi/inference/imports.py b/jedi/inference/imports.py index 5f19f945..27fcb758 100644 --- a/jedi/inference/imports.py +++ b/jedi/inference/imports.py @@ -288,26 +288,11 @@ class Importer(object): if not self.import_path or not self._infer_possible: return NO_VALUES - import_names = tuple( - force_unicode(i.value if isinstance(i, tree.Name) else i) - for i in self.import_path - ) sys_path = self._sys_path_with_modifications(is_completion=False) - value_set = [None] - for i, name in enumerate(self.import_path): - value_set = ValueSet.from_sets([ - self._inference_state.import_module( - import_names[:i+1], - parent_module_value, - sys_path - ) for parent_module_value in value_set - ]) - if not value_set: - message = 'No module named ' + '.'.join(import_names) - _add_error(self._module_context, name, message) - return NO_VALUES - return value_set + return import_module_by_names( + self._inference_state, self.import_path, sys_path, self._module_context + ) def _get_module_names(self, search_path=None, in_module=None): """ @@ -381,6 +366,36 @@ class Importer(object): return names +def import_module_by_names(inference_state, import_names, sys_path=None, + module_context=None, prefer_stubs=True): + if sys_path is None: + sys_path = inference_state.get_sys_path() + + str_import_names = tuple( + force_unicode(i.value if isinstance(i, tree.Name) else i) + for i in import_names + ) + value_set = [None] + for i, name in enumerate(import_names): + value_set = ValueSet.from_sets([ + import_module( + inference_state, + str_import_names[:i+1], + parent_module_value, + sys_path, + prefer_stubs=prefer_stubs, + ) for parent_module_value in value_set + ]) + if not value_set: + message = 'No module named ' + '.'.join(str_import_names) + if module_context is not None: + _add_error(module_context, name, message) + else: + debug.warning(message) + return NO_VALUES + return value_set + + @plugin_manager.decorate() @import_module_decorator def import_module(inference_state, import_names, parent_module_value, sys_path): diff --git a/test/test_inference/test_gradual/test_conversion.py b/test/test_inference/test_gradual/test_conversion.py index e2f2b9ed..cdf62a0c 100644 --- a/test/test_inference/test_gradual/test_conversion.py +++ b/test/test_inference/test_gradual/test_conversion.py @@ -14,3 +14,10 @@ def test_sqlite3_conversion(Script): d, = script1.goto_definitions(only_stubs=True) assert d.is_stub() assert d.full_name == 'sqlite3.dbapi2.Connection' + + script2 = Script(path=d.module_path, line=d.line, column=d.column) + d, = script2.goto_definitions() + assert not d.is_stub() + assert d.full_name == 'sqlite3.Connection' + v, = d._name.infer() + assert v.is_compiled() diff --git a/test/test_inference/test_gradual/test_stubs.py b/test/test_inference/test_gradual/test_stubs.py index c811b01f..4642c466 100644 --- a/test/test_inference/test_gradual/test_stubs.py +++ b/test/test_inference/test_gradual/test_stubs.py @@ -28,12 +28,12 @@ from test.helpers import root_dir {'goto_has_python': True}], ['from keyword import kwlist; kwlist', 'typing.Sequence', True, True, - {'full_name': 'keyword.kwlist'}], + {'goto_full_name': 'keyword.kwlist'}], ['from keyword import kwlist', 'typing.Sequence', True, True, - {'full_name': 'keyword.kwlist'}], + {'goto_full_name': 'keyword.kwlist'}], ['from socket import AF_INET', 'socket.AddressFamily', True, False, - {'full_name': 'socket.AF_INET'}], + {'goto_full_name': 'socket.AF_INET'}], ['from socket import socket', 'socket.socket', True, True, {}], ['import with_stub', 'with_stub', True, True, {}],