diff --git a/jedi/api/__init__.py b/jedi/api/__init__.py index c5359c26..a8a7c288 100644 --- a/jedi/api/__init__.py +++ b/jedi/api/__init__.py @@ -114,7 +114,7 @@ class Script(object): def _parsed_callback(self, parser): module = self._evaluator.wrap(parser.module) - self._evaluator.modules[unicode(module.name)] = module + imports.add_module(self._evaluator, unicode(module.name), module) @property def source_path(self): diff --git a/jedi/evaluate/compiled/__init__.py b/jedi/evaluate/compiled/__init__.py index 609da711..67d3f371 100644 --- a/jedi/evaluate/compiled/__init__.py +++ b/jedi/evaluate/compiled/__init__.py @@ -366,10 +366,13 @@ def load_module(path=None, name=None): # If a module is "corrupt" or not really a Python module or whatever. debug.warning('Module %s not importable.', path) return None + finally: + sys.path = temp + # Just access the cache after import, because of #59 as well as the very # complicated import structure of Python. module = sys.modules[dotted_path] - sys.path = temp + return CompiledObject(module) diff --git a/jedi/evaluate/imports.py b/jedi/evaluate/imports.py index 28fda879..c14a50c0 100644 --- a/jedi/evaluate/imports.py +++ b/jedi/evaluate/imports.py @@ -344,8 +344,7 @@ class Importer(object): if module_file is None and not module_path.endswith('.py'): module = compiled.load_module(module_path) else: - module = _load_module(self._evaluator, module_path, source, - sys_path, module_name) + module = _load_module(self._evaluator, module_path, source, sys_path) self._evaluator.modules[module_name] = module return [module] @@ -432,7 +431,7 @@ class Importer(object): return names -def _load_module(evaluator, path=None, source=None, sys_path=None, module_name=None): +def _load_module(evaluator, path=None, source=None, sys_path=None): def load(source): dotted_path = path and compiled.dotted_from_fs_path(path, sys_path) if path is not None and path.endswith('.py') \ @@ -453,6 +452,15 @@ def _load_module(evaluator, path=None, source=None, sys_path=None, module_name=N return module +def add_module(evaluator, module_name, module): + if '.' not in module_name: + # We cannot add paths with dots, because that would collide with + # the sepatator dots for nested packages. Therefore we return + # `__main__` in ModuleWrapper.py__name__(), which is similar to + # Python behavior. + evaluator.modules[module_name] = module + + def get_modules_containing_name(evaluator, mods, name): """ Search a name in the directories of modules. @@ -470,7 +478,10 @@ def get_modules_containing_name(evaluator, mods, name): with open(path, 'rb') as f: source = source_to_unicode(f.read()) if name in source: - return _load_module(evaluator, path, source) + module_name = os.path.basename(path)[:-3] # Remove `.py`. + module = _load_module(evaluator, path, source) + add_module(evaluator, module_name, module) + return module # skip non python modules mods = set(m for m in mods if not isinstance(m, compiled.CompiledObject)) diff --git a/jedi/evaluate/representation.py b/jedi/evaluate/representation.py index 19b8c0a9..1c11030b 100644 --- a/jedi/evaluate/representation.py +++ b/jedi/evaluate/representation.py @@ -763,6 +763,8 @@ class ModuleWrapper(use_metaclass(CachedMetaClass, tree.Module, Wrapper)): if module == self: return name + return '__main__' + def py__file__(self): """ In contrast to Python's __file__ can be None.