mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-06 22:14:27 +08:00
submodules are automatically indexed without actually importing them. fixes #413.
However, this is not a 100% correct Python behavior. Python behavior would be to follow ALL imports in all modules (recursively) and check if the module was imported. However, that's a lot of work, that would slow down autocompletion. For now it's better to have no false positives in flaking and to ignore a few attribute errors.
This commit is contained in:
@@ -73,8 +73,8 @@ class NameFinder(object):
|
|||||||
gen = self.scope.scope_names_generator
|
gen = self.scope.scope_names_generator
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
if isinstance(self.scope, er.Class):
|
if isinstance(self.scope, er.Class):
|
||||||
# classes are only available directly via chaining?
|
# Classes don't have a positional limitation of their
|
||||||
# strange stuff...
|
# state. It's the whole class.
|
||||||
names = self.scope.get_defined_names()
|
names = self.scope.get_defined_names()
|
||||||
else:
|
else:
|
||||||
names = _get_defined_names_for_position(self.scope, self.position)
|
names = _get_defined_names_for_position(self.scope, self.position)
|
||||||
@@ -118,7 +118,7 @@ class NameFinder(object):
|
|||||||
|
|
||||||
self._last_filter_name_scope = name_list_scope
|
self._last_filter_name_scope = name_list_scope
|
||||||
scope_txt = (self.scope if self.scope == name_list_scope
|
scope_txt = (self.scope if self.scope == name_list_scope
|
||||||
else ('%s-%s' % self.scope, name_list_scope))
|
else '%s-%s' % (self.scope, name_list_scope))
|
||||||
debug.dbg('finder.filter_name "%s" in (%s): %s@%s', self.name_str,
|
debug.dbg('finder.filter_name "%s" in (%s): %s@%s', self.name_str,
|
||||||
scope_txt, u(result), self.position)
|
scope_txt, u(result), self.position)
|
||||||
return result
|
return result
|
||||||
|
|||||||
@@ -186,6 +186,13 @@ class FakeStatement(pr.Statement):
|
|||||||
self.set_expression_list(expression_list)
|
self.set_expression_list(expression_list)
|
||||||
|
|
||||||
|
|
||||||
|
class FakeImport(pr.Import):
|
||||||
|
def __init__(self, name, parent):
|
||||||
|
p = 0, 0
|
||||||
|
super(FakeImport, self).__init__(FakeSubModule, p, p, name)
|
||||||
|
self.parent = parent
|
||||||
|
|
||||||
|
|
||||||
class FakeName(pr.Name):
|
class FakeName(pr.Name):
|
||||||
def __init__(self, name_or_names, parent=None):
|
def __init__(self, name_or_names, parent=None):
|
||||||
p = 0, 0
|
p = 0, 0
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ So, why is there also a ``Class`` class here? Well, there are decorators and
|
|||||||
they change classes in Python 3.
|
they change classes in Python 3.
|
||||||
"""
|
"""
|
||||||
import copy
|
import copy
|
||||||
|
import os
|
||||||
|
import pkgutil
|
||||||
|
|
||||||
from jedi._compatibility import use_metaclass, unicode
|
from jedi._compatibility import use_metaclass, unicode
|
||||||
from jedi.parser import representation as pr
|
from jedi.parser import representation as pr
|
||||||
@@ -539,6 +541,10 @@ class ModuleWrapper(pr.Module):
|
|||||||
self._evaluator = evaluator
|
self._evaluator = evaluator
|
||||||
self._module = module
|
self._module = module
|
||||||
|
|
||||||
|
def scope_names_generator(self):
|
||||||
|
yield self, self.get_defined_names()
|
||||||
|
yield self, self._sub_modules()
|
||||||
|
|
||||||
@memoize_default()
|
@memoize_default()
|
||||||
def get_defined_names(self):
|
def get_defined_names(self):
|
||||||
names = ['__file__', '__package__', '__doc__', '__name__', '__version__']
|
names = ['__file__', '__package__', '__doc__', '__name__', '__version__']
|
||||||
@@ -547,6 +553,19 @@ class ModuleWrapper(pr.Module):
|
|||||||
module_attributes = [helpers.FakeName(n, parent) for n in names]
|
module_attributes = [helpers.FakeName(n, parent) for n in names]
|
||||||
return self._module.get_defined_names() + module_attributes
|
return self._module.get_defined_names() + module_attributes
|
||||||
|
|
||||||
|
@memoize_default()
|
||||||
|
def _sub_modules(self):
|
||||||
|
path = self._module.path
|
||||||
|
names = []
|
||||||
|
if path.endswith(os.path.sep + '__init__.py'):
|
||||||
|
mods = pkgutil.iter_modules([os.path.dirname(path)])
|
||||||
|
for module_loader, name, is_pkg in mods:
|
||||||
|
name = helpers.FakeName(name)
|
||||||
|
imp = helpers.FakeImport(name, self)
|
||||||
|
name.parent = imp
|
||||||
|
names.append(name)
|
||||||
|
return names
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
return getattr(self._module, name)
|
return getattr(self._module, name)
|
||||||
|
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ import module_not_exists
|
|||||||
module_not_exists
|
module_not_exists
|
||||||
|
|
||||||
|
|
||||||
#< ('rename1', 1,0), (0,24), (3,0), (6,17), ('rename2', 4,5), (10,17), (13,17)
|
#< ('rename1', 1,0), (0,24), (3,0), (6,17), ('rename2', 4,5), (10,17), (13,17), ('imports', 68, 16)
|
||||||
from import_tree import rename1
|
from import_tree import rename1
|
||||||
|
|
||||||
#< (0,8), ('rename1',3,0), ('rename2',4,20), ('rename2',6,0), (3,32), (7,32), (4,0)
|
#< (0,8), ('rename1',3,0), ('rename2',4,20), ('rename2',6,0), (3,32), (7,32), (4,0)
|
||||||
@@ -90,7 +90,7 @@ rename1.abc
|
|||||||
from import_tree.rename1 import abc
|
from import_tree.rename1 import abc
|
||||||
abc
|
abc
|
||||||
|
|
||||||
#< 20 ('rename1', 1,0), ('rename2', 4,5), (-10,24), (-7,0), (-4,17), (0,17), (3,17)
|
#< 20 ('rename1', 1,0), ('rename2', 4,5), (-10,24), (-7,0), (-4,17), (0,17), (3,17), ('imports', 68, 16)
|
||||||
from import_tree.rename1 import abc
|
from import_tree.rename1 import abc
|
||||||
|
|
||||||
#< (0, 32),
|
#< (0, 32),
|
||||||
|
|||||||
Reference in New Issue
Block a user