1
0
forked from VimPlug/jedi

Better scanning for module names, now includes namespace packages and stubs

This commit is contained in:
Dave Halter
2019-05-18 00:11:08 +02:00
parent 8e3f85c475
commit 0fb5fd271a
5 changed files with 36 additions and 28 deletions

View File

@@ -108,9 +108,6 @@ def warning(message, *args, **kwargs):
debug_function('RED', i + 'warning: ' + message) debug_function('RED', i + 'warning: ' + message)
error = warning # Just for compatibility with logging.
def speed(name): def speed(name):
if debug_function and enable_speed: if debug_function and enable_speed:
now = time.time() now = time.time()

View File

@@ -1,5 +1,6 @@
import re import re
import os import os
import logging
from jedi.evaluate.cache import evaluator_method_cache from jedi.evaluate.cache import evaluator_method_cache
from jedi.evaluate.names import ContextNameMixin, AbstractNameDefinition from jedi.evaluate.names import ContextNameMixin, AbstractNameDefinition
@@ -8,6 +9,8 @@ from jedi.evaluate import compiled
from jedi.evaluate.base_context import TreeContext from jedi.evaluate.base_context import TreeContext
from jedi.evaluate.names import SubModuleName from jedi.evaluate.names import SubModuleName
logger = logging.getLogger(__name__)
class _ModuleAttributeName(AbstractNameDefinition): class _ModuleAttributeName(AbstractNameDefinition):
""" """
@@ -35,6 +38,32 @@ class ModuleName(ContextNameMixin, AbstractNameDefinition):
return self._name return self._name
def iter_module_names(evaluator, paths):
# Python modules/packages
for n in evaluator.compiled_subprocess.list_module_names(paths):
yield n
for path in paths:
try:
dirs = os.listdir(path)
except OSError:
# The file might not exist or reading it might lead to an error.
logger.error("Not possible to list directory: %s", path)
continue
for name in dirs:
# Namespaces
if os.path.isdir(os.path.join(path, name)):
# 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('\W|^\d', name):
yield name
# Stub files
if name.endswith('.pyi'):
if name != '__init__.pyi':
yield name[:-4]
class SubModuleDictMixin(object): class SubModuleDictMixin(object):
@evaluator_method_cache() @evaluator_method_cache()
def sub_modules_dict(self): def sub_modules_dict(self):
@@ -48,7 +77,7 @@ class SubModuleDictMixin(object):
except AttributeError: except AttributeError:
pass pass
else: else:
mods = self._iter_module_names(method()) mods = iter_module_names(self.evaluator, method())
for name in mods: for name in mods:
# It's obviously a relative import to the current module. # It's obviously a relative import to the current module.
names[name] = SubModuleName(self, name) names[name] = SubModuleName(self, name)
@@ -57,9 +86,6 @@ class SubModuleDictMixin(object):
# add all the variables, this is only about submodules. # add all the variables, this is only about submodules.
return names return names
def _iter_module_names(self, path):
return self.evaluator.compiled_subprocess.list_module_names(path)
class ModuleMixin(SubModuleDictMixin): class ModuleMixin(SubModuleDictMixin):
def get_filters(self, search_global=False, until_position=None, origin_scope=None): def get_filters(self, search_global=False, until_position=None, origin_scope=None):

View File

@@ -1,5 +1,3 @@
import os
from jedi.evaluate.base_context import ContextWrapper from jedi.evaluate.base_context import ContextWrapper
from jedi.evaluate.context.module import ModuleContext from jedi.evaluate.context.module import ModuleContext
from jedi.evaluate.filters import ParserTreeFilter, \ from jedi.evaluate.filters import ParserTreeFilter, \
@@ -61,17 +59,6 @@ class StubModuleContext(ModuleContext):
for f in filters: for f in filters:
yield f yield f
def _iter_module_names(self, paths):
for path in paths:
dirs = os.listdir(path)
for name in dirs:
if os.path.isdir(os.path.join(path, name)):
if name != '__pycache__':
yield name
if name.endswith('.pyi'):
if name != '__init__.pyi':
yield name[:-4]
class TypingModuleWrapper(StubModuleContext): class TypingModuleWrapper(StubModuleContext):
def get_filters(self, *args, **kwargs): def get_filters(self, *args, **kwargs):

View File

@@ -32,6 +32,7 @@ from jedi.evaluate.cache import evaluator_method_cache
from jedi.evaluate.names import ImportName, SubModuleName from jedi.evaluate.names import ImportName, SubModuleName
from jedi.evaluate.base_context import ContextSet, NO_CONTEXTS from jedi.evaluate.base_context import ContextSet, NO_CONTEXTS
from jedi.evaluate.gradual.typeshed import import_module_decorator from jedi.evaluate.gradual.typeshed import import_module_decorator
from jedi.evaluate.context.module import iter_module_names
class ModuleCache(object): class ModuleCache(object):
@@ -309,18 +310,16 @@ class Importer(object):
Get the names of all modules in the search_path. This means file names Get the names of all modules in the search_path. This means file names
and not names defined in the files. and not names defined in the files.
""" """
sub = self._evaluator.compiled_subprocess
names = [] names = []
# add builtin module names # add builtin module names
if search_path is None and in_module is None: if search_path is None and in_module is None:
names += [ImportName(self.module_context, name) names += [ImportName(self.module_context, name)
for name in sub.get_builtin_module_names()] for name in self._evaluator.compiled_subprocess.get_builtin_module_names()]
if search_path is None: if search_path is None:
search_path = self._sys_path_with_modifications() search_path = self._sys_path_with_modifications()
for name in sub.list_module_names(search_path): for name in iter_module_names(self._evaluator, search_path):
if in_module is None: if in_module is None:
n = ImportName(self.module_context, name) n = ImportName(self.module_context, name)
else: else:
@@ -361,7 +360,6 @@ class Importer(object):
if not only_modules: if not only_modules:
from jedi.evaluate.gradual.conversion import stub_to_actual_context_set from jedi.evaluate.gradual.conversion import stub_to_actual_context_set
contexts = ContextSet([context])
both_contexts = ContextSet.from_sets( both_contexts = ContextSet.from_sets(
stub_to_actual_context_set(context, ignore_compiled=True) stub_to_actual_context_set(context, ignore_compiled=True)
for context in contexts for context in contexts

View File

@@ -178,9 +178,9 @@ def test_hashlib_params(Script, environment):
if environment.version_info < (3,): if environment.version_info < (3,):
pytest.skip() pytest.skip()
script = Script(source='from hashlib import ', line=1, column=20) script = Script(source='from hashlib import sha256')
c = script.completions() c, = script.completions()
assert c[2].params assert [p.name for p in c.params] == ['arg']
def test_signature_params(Script): def test_signature_params(Script):