1
0
forked from VimPlug/jedi

StubModuleContext is now a wrapped context

This commit is contained in:
Dave Halter
2018-12-05 21:33:23 +01:00
parent 3d4f241129
commit 2406c8374f
2 changed files with 81 additions and 94 deletions

View File

@@ -38,27 +38,7 @@ class ModuleName(ContextNameMixin, AbstractNameDefinition):
return self._name
class ModuleContext(TreeContext):
api_type = u'module'
parent_context = None
def __init__(self, evaluator, module_node, path, string_names, code_lines):
super(ModuleContext, self).__init__(
evaluator,
parent_context=None,
tree_node=module_node
)
self._path = path
self._string_names = string_names
self.code_lines = code_lines
def is_module(self):
return True
def iter_star_filters(self, search_global=False):
for star_module in self.star_imports():
yield next(star_module.get_filters(search_global))
class ModuleMixin(object):
def get_filters(self, search_global=False, until_position=None, origin_scope=None):
yield MergedFilter(
ParserTreeFilter(
@@ -74,6 +54,67 @@ class ModuleContext(TreeContext):
for star_filter in self.iter_star_filters():
yield star_filter
def py__class__(self):
return compiled.get_special_object(self.evaluator, u'MODULE_CLASS')
def is_module(self):
return True
@property
@evaluator_method_cache()
def name(self):
return ModuleName(self, self._string_name)
@property
def _string_name(self):
""" This is used for the goto functions. """
# TODO It's ugly that we even use this, the name is usually well known
# ahead so just pass it when create a ModuleContext.
if self._path is None:
return '' # no path -> empty name
else:
sep = (re.escape(os.path.sep),) * 2
r = re.search(r'([^%s]*?)(%s__init__)?(\.pyi?|\.so)?$' % sep, self._path)
# Remove PEP 3149 names
return re.sub(r'\.[a-z]+-\d{2}[mud]{0,3}$', '', r.group(1))
@evaluator_method_cache()
def _sub_modules_dict(self):
"""
Lists modules in the directory of this module (if this module is a
package).
"""
names = {}
try:
method = self.py__path__
except AttributeError:
pass
else:
for path in method():
mods = iter_modules([path])
for module_loader, name, is_pkg in mods:
# It's obviously a relative import to the current module.
names[name] = SubModuleName(self, name)
# TODO add something like this in the future, its cleaner than the
# import hacks.
# ``os.path`` is a hardcoded exception, because it's a
# ``sys.modules`` modification.
# if str(self.name) == 'os':
# names.append(Name('path', parent_context=self))
return names
@evaluator_method_cache()
def _module_attributes_dict(self):
names = ['__file__', '__package__', '__doc__', '__name__']
# All the additional module attributes are strings.
return dict((n, _ModuleAttributeName(self, n)) for n in names)
def iter_star_filters(self, search_global=False):
for star_module in self.star_imports():
yield next(star_module.get_filters(search_global))
# I'm not sure if the star import cache is really that effective anymore
# with all the other really fast import caches. Recheck. Also we would need
# to push the star imports into Evaluator.module_cache, if we reenable this.
@@ -90,29 +131,21 @@ class ModuleContext(TreeContext):
modules += new
return modules
@evaluator_method_cache()
def _module_attributes_dict(self):
names = ['__file__', '__package__', '__doc__', '__name__']
# All the additional module attributes are strings.
return dict((n, _ModuleAttributeName(self, n)) for n in names)
@property
def _string_name(self):
""" This is used for the goto functions. """
# TODO It's ugly that we even use this, the name is usually well known
# ahead so just pass it when create a ModuleContext.
if self._path is None:
return '' # no path -> empty name
else:
sep = (re.escape(os.path.sep),) * 2
r = re.search(r'([^%s]*?)(%s__init__)?(\.pyi?|\.so)?$' % sep, self._path)
# Remove PEP 3149 names
return re.sub(r'\.[a-z]+-\d{2}[mud]{0,3}$', '', r.group(1))
class ModuleContext(ModuleMixin, TreeContext):
api_type = u'module'
parent_context = None
@property
@evaluator_method_cache()
def name(self):
return ModuleName(self, self._string_name)
def __init__(self, evaluator, module_node, path, string_names, code_lines):
super(ModuleContext, self).__init__(
evaluator,
parent_context=None,
tree_node=module_node
)
self._path = path
self._string_names = string_names
self.code_lines = code_lines
#print(self._path)
def _get_init_directory(self):
"""
@@ -189,36 +222,6 @@ class ModuleContext(TreeContext):
else:
return self._py__path__
@evaluator_method_cache()
def _sub_modules_dict(self):
"""
Lists modules in the directory of this module (if this module is a
package).
"""
names = {}
try:
method = self.py__path__
except AttributeError:
pass
else:
for path in method():
mods = iter_modules([path])
for module_loader, name, is_pkg in mods:
# It's obviously a relative import to the current module.
names[name] = SubModuleName(self, name)
# TODO add something like this in the future, its cleaner than the
# import hacks.
# ``os.path`` is a hardcoded exception, because it's a
# ``sys.modules`` modification.
# if str(self.name) == 'os':
# names.append(Name('path', parent_context=self))
return names
def py__class__(self):
return compiled.get_special_object(self.evaluator, u'MODULE_CLASS')
def __repr__(self):
return "<%s: %s@%s-%s is_stub=%s>" % (
self.__class__.__name__, self._string_name,

View File

@@ -14,6 +14,7 @@ from jedi.evaluate.context import ModuleContext, FunctionContext, \
MethodContext, ClassContext
from jedi.evaluate.context.function import FunctionMixin
from jedi.evaluate.context.klass import ClassMixin
from jedi.evaluate.context.module import ModuleMixin
from jedi.evaluate.context.typing import TypingModuleFilterWrapper, \
TypingModuleName
from jedi.evaluate.compiled.context import CompiledObject, CompiledName
@@ -87,14 +88,7 @@ def _merge_modules(context_set, stub_context):
for context in context_set:
if isinstance(context, ModuleContext):
yield StubModuleContext(
context.evaluator,
stub_context,
context.tree_node,
path=context._path,
string_names=context._string_names,
code_lines=context.code_lines
)
yield StubModuleContext.create_cached(context.evaluator, context, stub_context)
else:
# TODO do we want this? This includes compiled?!
yield stub_context
@@ -386,15 +380,6 @@ class StubFilter(AbstractFilter):
)
class _MixedStubContextMixin(object):
"""
Mixes the actual contexts with the stub module contexts.
"""
def __init__(self, evaluator, stub_context, *args, **kwargs):
super(_MixedStubContextMixin, self).__init__(evaluator, *args, **kwargs)
self.stub_context = stub_context
class _StubContextFilterMixin(object):
def get_filters(self, search_global=False, until_position=None,
origin_scope=None, **kwargs):
@@ -414,11 +399,10 @@ class _StubContextFilterMixin(object):
yield f
class StubModuleContext(_MixedStubContextMixin, _StubContextFilterMixin, ModuleContext):
@property
def _wrapped_context(self):
# TODO this is stupid.
return super(_StubContextFilterMixin, self)
class StubModuleContext(_StubContextFilterMixin, ModuleMixin, ContextWrapper):
def __init__(self, context, stub_context):
super(StubModuleContext, self).__init__(context)
self.stub_context = stub_context
class StubClassContext(_StubContextFilterMixin, ClassMixin, ContextWrapper):