forked from VimPlug/jedi
Fix a lot of the import completion issues.
This commit is contained in:
@@ -222,7 +222,7 @@ class Completion:
|
|||||||
return level, names
|
return level, names
|
||||||
|
|
||||||
def _get_importer_names(self, names, level=0, only_modules=True):
|
def _get_importer_names(self, names, level=0, only_modules=True):
|
||||||
names = [str(n) for n in names]
|
names = [n.value for n in names]
|
||||||
i = imports.Importer(self._evaluator, names, self._module_context, level)
|
i = imports.Importer(self._evaluator, names, self._module_context, level)
|
||||||
return i.completion_names(self._evaluator, only_modules=only_modules)
|
return i.completion_names(self._evaluator, only_modules=only_modules)
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ from jedi import settings
|
|||||||
from jedi.common import source_to_unicode, unite
|
from jedi.common import source_to_unicode, unite
|
||||||
from jedi.evaluate import compiled
|
from jedi.evaluate import compiled
|
||||||
from jedi.evaluate import analysis
|
from jedi.evaluate import analysis
|
||||||
|
from jedi.evaluate.filters import AbstractNameDefinition
|
||||||
|
|
||||||
|
|
||||||
def completion_names(evaluator, imp, pos):
|
def completion_names(evaluator, imp, pos):
|
||||||
@@ -163,6 +164,36 @@ def get_init_path(directory_path):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class ImportName(AbstractNameDefinition):
|
||||||
|
api_type = 'module'
|
||||||
|
start_pos = (1, 0)
|
||||||
|
|
||||||
|
def __init__(self, parent_module, string_name):
|
||||||
|
self.parent_context = parent_module
|
||||||
|
self.string_name = string_name
|
||||||
|
|
||||||
|
def infer(self):
|
||||||
|
return Importer(
|
||||||
|
self.parent_context.evaluator,
|
||||||
|
[self.string_name],
|
||||||
|
self.parent_context,
|
||||||
|
).follow()
|
||||||
|
|
||||||
|
def get_root_context(self):
|
||||||
|
# Not sure if this is correct.
|
||||||
|
return self.parent_context.get_root_context()
|
||||||
|
|
||||||
|
|
||||||
|
class SubModuleName(ImportName):
|
||||||
|
def infer(self):
|
||||||
|
return Importer(
|
||||||
|
self.parent_context.evaluator,
|
||||||
|
[self.string_name],
|
||||||
|
self.parent_context,
|
||||||
|
level=1
|
||||||
|
).follow()
|
||||||
|
|
||||||
|
|
||||||
class Importer(object):
|
class Importer(object):
|
||||||
def __init__(self, evaluator, import_path, module_context, level=0):
|
def __init__(self, evaluator, import_path, module_context, level=0):
|
||||||
"""
|
"""
|
||||||
@@ -350,14 +381,16 @@ class Importer(object):
|
|||||||
self._evaluator.modules[module_name] = module
|
self._evaluator.modules[module_name] = module
|
||||||
return set([module])
|
return set([module])
|
||||||
|
|
||||||
def _generate_name(self, name):
|
def _generate_name(self, name, in_module=None):
|
||||||
# Create a pseudo import to be able to follow them.
|
# Create a pseudo import to be able to follow them.
|
||||||
name = helpers.FakeName(name)
|
if in_module is None:
|
||||||
imp = helpers.FakeImport(name, parent=self.module_context)
|
#imp = helpers.FakeImport(name, parent=self.module_context)
|
||||||
name.parent = imp
|
#name.parent = imp
|
||||||
return name
|
#return name
|
||||||
|
return ImportName(self.module_context, name)
|
||||||
|
return SubModuleName(in_module, name)
|
||||||
|
|
||||||
def _get_module_names(self, search_path=None):
|
def _get_module_names(self, search_path=None, in_module=None):
|
||||||
"""
|
"""
|
||||||
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.
|
||||||
@@ -365,13 +398,13 @@ class Importer(object):
|
|||||||
|
|
||||||
names = []
|
names = []
|
||||||
# add builtin module names
|
# add builtin module names
|
||||||
if search_path is None:
|
if search_path is None and in_module is None:
|
||||||
names += [self._generate_name(name) for name in sys.builtin_module_names]
|
names += [self._generate_name(name) for name in sys.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 module_loader, name, is_pkg in pkgutil.iter_modules(search_path):
|
for module_loader, name, is_pkg in pkgutil.iter_modules(search_path):
|
||||||
names.append(self._generate_name(name))
|
names.append(self._generate_name(name, in_module=in_module))
|
||||||
return names
|
return names
|
||||||
|
|
||||||
def completion_names(self, evaluator, only_modules=False):
|
def completion_names(self, evaluator, only_modules=False):
|
||||||
@@ -380,6 +413,7 @@ class Importer(object):
|
|||||||
definition that is not defined in a module.
|
definition that is not defined in a module.
|
||||||
"""
|
"""
|
||||||
from jedi.evaluate import finder
|
from jedi.evaluate import finder
|
||||||
|
from jedi.evaluate.representation import ModuleContext
|
||||||
names = []
|
names = []
|
||||||
if self.import_path:
|
if self.import_path:
|
||||||
# flask
|
# flask
|
||||||
@@ -396,15 +430,16 @@ class Importer(object):
|
|||||||
if os.path.isdir(flaskext):
|
if os.path.isdir(flaskext):
|
||||||
names += self._get_module_names([flaskext])
|
names += self._get_module_names([flaskext])
|
||||||
|
|
||||||
for scope in self.follow():
|
for context in self.follow():
|
||||||
# Non-modules are not completable.
|
# Non-modules are not completable.
|
||||||
if not scope.type == 'file_input': # not a module
|
if context.api_type != 'module': # not a module
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# namespace packages
|
# namespace packages
|
||||||
if isinstance(scope, tree.Module) and scope.path.endswith('__init__.py'):
|
if isinstance(context, ModuleContext) and \
|
||||||
paths = scope.py__path__()
|
context.py__file__().endswith('__init__.py'):
|
||||||
names += self._get_module_names(paths)
|
paths = context.py__path__()
|
||||||
|
names += self._get_module_names(paths, in_module=context)
|
||||||
|
|
||||||
if only_modules:
|
if only_modules:
|
||||||
# In the case of an import like `from x.` we don't need to
|
# In the case of an import like `from x.` we don't need to
|
||||||
@@ -416,12 +451,8 @@ class Importer(object):
|
|||||||
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for names_dict in scope.names_dicts(search_global=False):
|
for filter in context.get_filters(search_global=False):
|
||||||
_names = list(chain.from_iterable(names_dict.values()))
|
names += filter.values()
|
||||||
if not _names:
|
|
||||||
continue
|
|
||||||
_names = finder.filter_definition_names(_names, scope)
|
|
||||||
names += _names
|
|
||||||
else:
|
else:
|
||||||
# Empty import path=completion after import
|
# Empty import path=completion after import
|
||||||
if not self.level:
|
if not self.level:
|
||||||
|
|||||||
@@ -773,23 +773,6 @@ class ModuleAttributeName(AbstractNameDefinition):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class SubModuleName(AbstractNameDefinition):
|
|
||||||
api_type = 'module'
|
|
||||||
start_pos = (1, 0)
|
|
||||||
|
|
||||||
def __init__(self, parent_module, string_name):
|
|
||||||
self.parent_context = parent_module
|
|
||||||
self.string_name = string_name
|
|
||||||
|
|
||||||
def infer(self):
|
|
||||||
return imports.Importer(
|
|
||||||
self.parent_context.evaluator,
|
|
||||||
[self.string_name],
|
|
||||||
self.parent_context,
|
|
||||||
level=1
|
|
||||||
).follow()
|
|
||||||
|
|
||||||
|
|
||||||
class ModuleContext(use_metaclass(CachedMetaClass, context.TreeContext, Wrapper)):
|
class ModuleContext(use_metaclass(CachedMetaClass, context.TreeContext, Wrapper)):
|
||||||
api_type = 'module'
|
api_type = 'module'
|
||||||
parent_context = None
|
parent_context = None
|
||||||
@@ -941,7 +924,7 @@ class ModuleContext(use_metaclass(CachedMetaClass, context.TreeContext, Wrapper)
|
|||||||
mods = pkgutil.iter_modules([os.path.dirname(path)])
|
mods = pkgutil.iter_modules([os.path.dirname(path)])
|
||||||
for module_loader, name, is_pkg in mods:
|
for module_loader, name, is_pkg 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] = imports.SubModuleName(self, name)
|
||||||
|
|
||||||
# TODO add something like this in the future, its cleaner than the
|
# TODO add something like this in the future, its cleaner than the
|
||||||
# import hacks.
|
# import hacks.
|
||||||
|
|||||||
Reference in New Issue
Block a user