diff --git a/jedi/inference/compiled/subprocess/functions.py b/jedi/inference/compiled/subprocess/functions.py index fe2c4d18..39181993 100644 --- a/jedi/inference/compiled/subprocess/functions.py +++ b/jedi/inference/compiled/subprocess/functions.py @@ -1,10 +1,13 @@ from __future__ import print_function import sys import os +import re +import inspect from jedi._compatibility import find_module, cast_path, force_unicode, \ - all_suffixes + all_suffixes, scandir from jedi.inference.compiled import access +from jedi import debug from jedi import parser_utils @@ -77,3 +80,37 @@ def _get_init_path(directory_path): def safe_literal_eval(inference_state, value): return parser_utils.safe_literal_eval(value) + + +def iter_module_names(*args, **kwargs): + return list(_iter_module_names(*args, **kwargs)) + return sorted(set(_iter_module_names(*args, **kwargs))) + + +def _iter_module_names(inference_state, paths): + # Python modules/packages + for path in paths: + try: + dirs = scandir(path) + except OSError: + # The file might not exist or reading it might lead to an error. + debug.warning("Not possible to list directory: %s", path) + continue + for dir_entry in dirs: + name = dir_entry.name + # First Namespaces then modules/stubs + if dir_entry.is_dir(): + # pycache is obviously not an interestin namespace. Also the + # name must be a valid identifier. + # TODO use str.isidentifier, once Python 2 is removed + if name != '__pycache__' and not re.search(r'\W|^\d', name): + yield name + else: + if name.endswith('.pyi'): # Stub files + modname = name[:-4] + else: + modname = inspect.getmodulename(name) + + if modname and '.' not in modname: + if modname != '__init__': + yield modname diff --git a/jedi/inference/imports.py b/jedi/inference/imports.py index 2ae6b498..926d05ef 100644 --- a/jedi/inference/imports.py +++ b/jedi/inference/imports.py @@ -31,7 +31,6 @@ from jedi.inference.names import ImportName, SubModuleName from jedi.inference.base_value import ValueSet, NO_VALUES from jedi.inference.gradual.typeshed import import_module_decorator, \ create_stub_module, parse_stub_module -from jedi.inference.value.module import iter_module_names as module_iter_module_names from jedi.plugins import plugin_manager @@ -560,5 +559,5 @@ def iter_module_names(inference_state, module_context, search_path, for name in inference_state.compiled_subprocess.get_builtin_module_names(): yield module_cls(module_context, name) - for name in module_iter_module_names(inference_state, search_path): + for name in inference_state.compiled_subprocess.iter_module_names(search_path): yield module_cls(module_context, name) diff --git a/jedi/inference/value/module.py b/jedi/inference/value/module.py index 72048ff7..51cc5863 100644 --- a/jedi/inference/value/module.py +++ b/jedi/inference/value/module.py @@ -1,8 +1,5 @@ -import re import os -from jedi._compatibility import scandir -from jedi import debug from jedi.inference.cache import inference_state_method_cache from jedi.inference.names import AbstractNameDefinition, ModuleName from jedi.inference.filters import GlobalNameFilter, ParserTreeFilter, DictFilter, MergedFilter @@ -38,38 +35,6 @@ class _ModuleAttributeName(AbstractNameDefinition): return compiled.get_string_value_set(self.parent_context.inference_state) -def iter_module_names(*args, **kwargs): - return sorted(set(iter_module_names(*args, **kwargs))) - - -def iter_module_names(inference_state, paths): - # Python modules/packages - for path in paths: - try: - dirs = scandir(path) - except OSError: - # The file might not exist or reading it might lead to an error. - debug.warning("Not possible to list directory: %s", path) - continue - for dir_entry in dirs: - name = dir_entry.name - # First Namespaces then modules/stubs - if dir_entry.is_dir(): - # pycache is obviously not an interestin namespace. Also the - # name must be a valid identifier. - # TODO use str.isidentifier, once Python 2 is removed - if name != '__pycache__' and not re.search(r'\W|^\d', name): - yield name - else: - if name.endswith('.py'): - if name != '__init__.py': - yield name[:-3] - # Stub files - elif name.endswith('.pyi'): - if name != '__init__.pyi': - yield name[:-4] - - class SubModuleDictMixin(object): @inference_state_method_cache() def sub_modules_dict(self): @@ -79,7 +44,9 @@ class SubModuleDictMixin(object): """ names = {} if self.is_package(): - mods = iter_module_names(self.inference_state, self.py__path__()) + mods = self.inference_state.compiled_subprocess.iter_module_names( + self.py__path__() + ) for name in mods: # It's obviously a relative import to the current module. names[name] = SubModuleName(self.as_context(), name) diff --git a/test/completion/on_import.py b/test/completion/on_import.py index 76984b12..ddf04151 100644 --- a/test/completion/on_import.py +++ b/test/completion/on_import.py @@ -12,6 +12,8 @@ def from_names_goto(): def builtin_test(): #? ['math'] import math + #? ['mmap'] + import mmap # ----------------- # completions within imports