diff --git a/jedi/evaluate/imports.py b/jedi/evaluate/imports.py index 78841a7e..107a56db 100644 --- a/jedi/evaluate/imports.py +++ b/jedi/evaluate/imports.py @@ -179,52 +179,54 @@ class ImportWrapper(pr.Base): # check recursion return [] - if self.import_path: - try: - module, rest = self._importer.follow_file_system() - except ModuleNotFound as e: - analysis.add(self._evaluator, 'import-error', e.name_part) - return [] + try: + if self.import_path: + try: + module, rest = self._importer.follow_file_system() + except ModuleNotFound as e: + analysis.add(self._evaluator, 'import-error', e.name_part) + return [] - if self.import_stmt.is_nested() and not self.nested_resolve: - scopes = [NestedImportModule(module, self.import_stmt)] - else: - scopes = [module] - - star_imports = remove_star_imports(self._evaluator, module) - if star_imports: - scopes = [StarImportModule(scopes[0], star_imports)] - - # goto only accepts Names or NameParts - if is_goto and not rest: - scopes = [s.name.names[-1] for s in scopes] - - # follow the rest of the import (not FS -> classes, functions) - if len(rest) > 1 or rest and self.is_like_search: - scopes = [] - if ('os', 'path') == self.import_path[:2] \ - and not self._is_relative_import(): - # 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``. - scopes = self._evaluator.follow_path(iter(rest), [module], module) - elif rest: - if is_goto: - scopes = list(chain.from_iterable( - self._evaluator.find_types(s, rest[0], is_goto=True) - for s in scopes)) + if self.import_stmt.is_nested() and not self.nested_resolve: + scopes = [NestedImportModule(module, self.import_stmt)] else: - scopes = list(chain.from_iterable( - self._evaluator.follow_path(iter(rest), [s], s) - for s in scopes)) - else: - scopes = [ImportWrapper.GlobalNamespace] - debug.dbg('after import: %s', scopes) - if not scopes: - analysis.add(self._evaluator, 'import-error', - self._importer.import_path[-1]) - self._evaluator.recursion_detector.pop_stmt() + scopes = [module] + + star_imports = remove_star_imports(self._evaluator, module) + if star_imports: + scopes = [StarImportModule(scopes[0], star_imports)] + + # goto only accepts Names or NameParts + if is_goto and not rest: + scopes = [s.name.names[-1] for s in scopes] + + # follow the rest of the import (not FS -> classes, functions) + if len(rest) > 1 or rest and self.is_like_search: + scopes = [] + if ('os', 'path') == self.import_path[:2] \ + and not self._is_relative_import(): + # 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``. + scopes = self._evaluator.follow_path(iter(rest), [module], module) + elif rest: + if is_goto: + scopes = list(chain.from_iterable( + self._evaluator.find_types(s, rest[0], is_goto=True) + for s in scopes)) + else: + scopes = list(chain.from_iterable( + self._evaluator.follow_path(iter(rest), [s], s) + for s in scopes)) + else: + scopes = [ImportWrapper.GlobalNamespace] + debug.dbg('after import: %s', scopes) + if not scopes: + analysis.add(self._evaluator, 'import-error', + self._importer.import_path[-1]) + finally: + self._evaluator.recursion_detector.pop_stmt() return scopes diff --git a/jedi/evaluate/representation.py b/jedi/evaluate/representation.py index 410280b7..771bcc33 100644 --- a/jedi/evaluate/representation.py +++ b/jedi/evaluate/representation.py @@ -686,6 +686,14 @@ class ModuleWrapper(use_metaclass(CachedMetaClass, pr.Module, Wrapper)): imp = helpers.FakeImport(name, self, level=1) name.parent = imp names.append(name) + + # TODO add something like this in the future, its cleaner than the + # import hacks. + # ``os.path`` is a hardcoded exception, because it's a + # ``sys.modules`` modification. + #if str(self.name) == 'os': + # names.append(helpers.FakeName('path', parent=self)) + return names def __getattr__(self, name): diff --git a/test/test_api/test_api_classes.py b/test/test_api/test_api_classes.py index 94799cff..18d46c9e 100644 --- a/test/test_api/test_api_classes.py +++ b/test/test_api/test_api_classes.py @@ -267,3 +267,14 @@ class TestGotoAssignments(TestCase): n = nms[1].goto_assignments()[0] assert n.name == 'load' assert n.type == 'function' + + nms = names('import os; os.path', references=True) + assert nms[0].name == 'os' + assert nms[0].type == 'import' + n = nms[0].goto_assignments()[0] + assert n.name == 'os' + assert n.type == 'module' + + n = nms[2].goto_assignments()[0] + assert n.name == 'path' + assert n.type == 'import'