Try to change the module cache

This commit is contained in:
Dave Halter
2018-09-02 13:06:36 +02:00
parent ecda9cc746
commit e3203ebaa5
9 changed files with 48 additions and 53 deletions

View File

@@ -36,6 +36,7 @@ from jedi.evaluate.sys_path import dotted_path_in_sys_path
from jedi.evaluate.filters import TreeNameDefinition, ParamName from jedi.evaluate.filters import TreeNameDefinition, ParamName
from jedi.evaluate.syntax_tree import tree_name_to_contexts from jedi.evaluate.syntax_tree import tree_name_to_contexts
from jedi.evaluate.context import ModuleContext from jedi.evaluate.context import ModuleContext
from jedi.evaluate.base_context import ContextSet
from jedi.evaluate.context.iterable import unpack_tuple_to_dict from jedi.evaluate.context.iterable import unpack_tuple_to_dict
# Jedi uses lots and lots of recursion. By setting this a little bit higher, we # Jedi uses lots and lots of recursion. By setting this a little bit higher, we
@@ -143,17 +144,18 @@ class Script(object):
debug.reset_time() debug.reset_time()
def _get_module(self): def _get_module(self):
name = '__main__' names = ('__main__',)
if self.path is not None: if self.path is not None:
import_names = dotted_path_in_sys_path(self._evaluator.get_sys_path(), self.path) import_names = dotted_path_in_sys_path(self._evaluator.get_sys_path(), self.path)
if import_names is not None: if import_names is not None:
name = '.'.join(import_names) names = import_names
module = ModuleContext( module = ModuleContext(
self._evaluator, self._module_node, self.path, self._evaluator, self._module_node, self.path,
code_lines=self._code_lines string_names=names,
code_lines=self._code_lines,
) )
imports.add_module_to_cache(self._evaluator, name, module) self._evaluator.module_cache.add(names, ContextSet(module))
return module return module
def __repr__(self): def __repr__(self):

View File

@@ -27,6 +27,7 @@ class MixedModuleContext(Context):
self.evaluator = evaluator self.evaluator = evaluator
self._namespaces = namespaces self._namespaces = namespaces
raise NotImplementedError("module names")
self._namespace_objects = [NamespaceObject(n) for n in namespaces] self._namespace_objects = [NamespaceObject(n) for n in namespaces]
self._module_context = ModuleContext( self._module_context = ModuleContext(
evaluator, tree_module, evaluator, tree_module,

View File

@@ -62,6 +62,7 @@ I need to mention now that lazy evaluation is really good because it
only *evaluates* what needs to be *evaluated*. All the statements and modules only *evaluates* what needs to be *evaluated*. All the statements and modules
that are not used are just being ignored. that are not used are just being ignored.
""" """
from functools import partial
from parso.python import tree from parso.python import tree
import parso import parso
@@ -125,11 +126,24 @@ class Evaluator(object):
from jedi.plugins import plugin_manager from jedi.plugins import plugin_manager
plugin_callbacks = plugin_manager.get_callbacks(self) plugin_callbacks = plugin_manager.get_callbacks(self)
self.execute = plugin_callbacks.decorate('execute', callback=_execute) self.execute = plugin_callbacks.decorate('execute', callback=_execute)
self.import_module = plugin_callbacks.decorate( self._import_module = partial(
'import_module', plugin_callbacks.decorate(
callback=imports.import_module 'import_module',
callback=imports.import_module
),
self,
) )
def import_module(self, import_names, parent_module_context, sys_path):
try:
return ContextSet(self.module_cache.get(import_names))
except KeyError:
pass
context_set = self._import_module(import_names, parent_module_context, sys_path)
self.module_cache.add(context_set, import_names)
return context_set
@property @property
@evaluator_function_cache() @evaluator_function_cache()
def builtins_module(self): def builtins_module(self):

View File

@@ -203,6 +203,7 @@ def _create(evaluator, access_handle, parent_context, *args):
if parent_context.tree_node.get_root_node() == module_node: if parent_context.tree_node.get_root_node() == module_node:
module_context = parent_context.get_root_context() module_context = parent_context.get_root_context()
else: else:
raise NotImplementedError('module misses string_names arg')
module_context = ModuleContext( module_context = ModuleContext(
evaluator, module_node, evaluator, module_node,
path=path, path=path,

View File

@@ -42,13 +42,14 @@ class ModuleContext(TreeContext):
api_type = u'module' api_type = u'module'
parent_context = None parent_context = None
def __init__(self, evaluator, module_node, path, code_lines): def __init__(self, evaluator, module_node, path, string_names, code_lines):
super(ModuleContext, self).__init__( super(ModuleContext, self).__init__(
evaluator, evaluator,
parent_context=None, parent_context=None,
tree_node=module_node tree_node=module_node
) )
self._path = path self._path = path
self._string_names = string_names
self.code_lines = code_lines self.code_lines = code_lines
def get_filters(self, search_global, until_position=None, origin_scope=None): def get_filters(self, search_global, until_position=None, origin_scope=None):
@@ -120,11 +121,7 @@ class ModuleContext(TreeContext):
return None return None
def py__name__(self): def py__name__(self):
for name, module in self.evaluator.module_cache.iterate_modules_with_names(): return '.'.join(self._string_names)
if module == self and name != '':
return name
return '__main__'
def py__file__(self): def py__file__(self):
""" """

View File

@@ -37,16 +37,14 @@ class ModuleCache(object):
self._path_cache = {} self._path_cache = {}
self._name_cache = {} self._name_cache = {}
def add(self, module, name): def add(self, string_names, context_set):
path = module.py__file__() #path = module.py__file__()
self._path_cache[path] = module #self._path_cache[path] = context_set
self._name_cache[name] = module if string_names is not None:
self._name_cache[string_names] = context_set
def iterate_modules_with_names(self): def get(self, string_names):
return self._name_cache.items() return self._name_cache[string_names]
def get(self, name):
return self._name_cache[name]
def get_from_path(self, path): def get_from_path(self, path):
return self._path_cache[path] return self._path_cache[path]
@@ -291,7 +289,6 @@ class Importer(object):
try: try:
context_set = ContextSet.from_sets([ context_set = ContextSet.from_sets([
self._evaluator.import_module( self._evaluator.import_module(
self._evaluator,
import_names[:i+1], import_names[:i+1],
parent_module_context, parent_module_context,
self.sys_path_with_modifications(), self.sys_path_with_modifications(),
@@ -410,11 +407,6 @@ def import_module(evaluator, import_names, parent_module_context, sys_path):
return ContextSet(module) return ContextSet(module)
module_name = '.'.join(import_names) module_name = '.'.join(import_names)
try:
return ContextSet(evaluator.module_cache.get(module_name))
except KeyError:
pass
if parent_module_context is None: if parent_module_context is None:
debug.dbg('global search_module %s', import_names[-1]) debug.dbg('global search_module %s', import_names[-1])
# Override the sys.path. It works only good that way. # Override the sys.path. It works only good that way.
@@ -467,10 +459,6 @@ def _load_module(evaluator, path=None, code=None, sys_path=None,
dotted_name = None dotted_name = None
else: else:
dotted_name = '.'.join(import_names) dotted_name = '.'.join(import_names)
try:
return evaluator.module_cache.get(dotted_name)
except KeyError:
pass
try: try:
return evaluator.module_cache.get_from_path(path) return evaluator.module_cache.get_from_path(path)
except KeyError: except KeyError:
@@ -497,6 +485,7 @@ def _load_module(evaluator, path=None, code=None, sys_path=None,
module = ModuleContext( module = ModuleContext(
evaluator, module_node, evaluator, module_node,
path=path, path=path,
string_names=import_names,
code_lines=get_cached_code_lines(evaluator.grammar, path), code_lines=get_cached_code_lines(evaluator.grammar, path),
) )
else: else:
@@ -506,23 +495,9 @@ def _load_module(evaluator, path=None, code=None, sys_path=None,
# The file might raise an ImportError e.g. and therefore not be # The file might raise an ImportError e.g. and therefore not be
# importable. # importable.
raise JediImportError(import_names) raise JediImportError(import_names)
if module is not None and dotted_name is not None:
add_module_to_cache(evaluator, dotted_name, module, safe=safe_module_name)
return module return module
def add_module_to_cache(evaluator, module_name, module, safe=False):
if not safe and '.' not in module_name:
# We cannot add paths with dots, because that would collide with
# the sepatator dots for nested packages. Therefore we return
# `__main__` in ModuleWrapper.py__name__(), which is similar to
# Python behavior.
return
evaluator.module_cache.add(module, module_name)
def get_modules_containing_name(evaluator, modules, name): def get_modules_containing_name(evaluator, modules, name):
""" """
Search a name in the directories of modules. Search a name in the directories of modules.
@@ -553,6 +528,7 @@ def get_modules_containing_name(evaluator, modules, name):
sys_path=e_sys_path, sys_path=e_sys_path,
import_names=import_names, import_names=import_names,
) )
evaluator.module_cache.add(import_names, ContextSet(module))
return module return module
# skip non python modules # skip non python modules

View File

@@ -151,6 +151,7 @@ def _get_paths_from_buildout_script(evaluator, buildout_script_path):
return return
from jedi.evaluate.context import ModuleContext from jedi.evaluate.context import ModuleContext
raise NotImplementedError("No module string_names, yet")
module = ModuleContext( module = ModuleContext(
evaluator, module_node, buildout_script_path, evaluator, module_node, buildout_script_path,
code_lines=get_cached_code_lines(evaluator.grammar, buildout_script_path), code_lines=get_cached_code_lines(evaluator.grammar, buildout_script_path),

View File

@@ -289,10 +289,9 @@ def collections_namedtuple(evaluator, obj, arguments):
# Parse source code # Parse source code
module = evaluator.grammar.parse(code) module = evaluator.grammar.parse(code)
generated_class = next(module.iter_classdefs()) generated_class = next(module.iter_classdefs())
parent_context = ModuleContext( parent_context = None
evaluator, module, None, raise NotImplementedError('TODO implement parent_context')
code_lines=parso.split_lines(code, keepends=True),
)
return ContextSet(ClassContext(evaluator, parent_context, generated_class)) return ContextSet(ClassContext(evaluator, parent_context, generated_class))

View File

@@ -89,8 +89,9 @@ def _merge_modules(context_set, stub_context):
context.evaluator, context.evaluator,
stub_context, stub_context,
context.tree_node, context.tree_node,
context._path, path=context._path,
context.code_lines string_names=context._string_names,
code_lines=context.code_lines
) )
else: else:
# TODO do we want this? # TODO do we want this?
@@ -160,7 +161,10 @@ class TypeshedPlugin(BasePlugin):
module_cls = StubOnlyModuleContext module_cls = StubOnlyModuleContext
# TODO use code_lines # TODO use code_lines
stub_module_context = module_cls( stub_module_context = module_cls(
context_set, evaluator, stub_module_node, path, code_lines=[] context_set, evaluator, stub_module_node,
path=path,
string_names=import_names,
code_lines=[],
) )
modules = _merge_modules(context_set, stub_module_context) modules = _merge_modules(context_set, stub_module_context)
return ContextSet.from_iterable(modules) return ContextSet.from_iterable(modules)