1
0
forked from VimPlug/jedi

caches have their own module now.

This commit is contained in:
David Halter
2012-12-12 21:28:19 +01:00
parent 169b35b5a9
commit e8ddc35a1b
9 changed files with 109 additions and 97 deletions

View File

@@ -18,6 +18,7 @@ import sys
import itertools
import copy
import cache
import parsing
import debug
import builtin
@@ -26,9 +27,6 @@ import helpers
import dynamic
import docstrings
memoize_caches = []
faked_scopes = []
class DecoratorNotFound(LookupError):
"""
@@ -63,66 +61,6 @@ class MultiLevelAttributeError(Exception):
return 'Original:\n\n' + ''.join(tb)
def clear_caches():
"""
Clears all caches of this and related modules. Jedi caches many things,
that should be completed after each completion finishes. The only things
that stays is the module cache (which is not deleted here).
"""
global memoize_caches, faked_scopes
for m in memoize_caches:
m.clear()
dynamic.search_param_cache.clear()
helpers.ExecutionRecursionDecorator.reset()
# memorize_caches must never be deleted, because the dicts will get lost in
# the wrappers.
faked_scopes = []
follow_statement.reset()
imports.imports_processed = 0
def memoize_default(default=None):
"""
This is a typical memoization decorator, BUT there is one difference:
To prevent recursion it sets defaults.
Preventing recursion is in this case the much bigger use than speed. I
don't think, that there is a big speed difference, but there are many cases
where recursion could happen (think about a = b; b = a).
"""
def func(function):
memo = {}
memoize_caches.append(memo)
def wrapper(*args, **kwargs):
key = (args, frozenset(kwargs.items()))
if key in memo:
return memo[key]
else:
memo[key] = default
rv = function(*args, **kwargs)
memo[key] = rv
return rv
return wrapper
return func
class CachedMetaClass(type):
"""
This is basically almost the same than the decorator above, it just caches
class initializations. I haven't found any other way, so I do it with meta
classes.
"""
@memoize_default()
def __call__(self, *args, **kwargs):
return super(CachedMetaClass, self).__call__(*args, **kwargs)
class Executable(parsing.Base):
""" An instance is also an executable - because __init__ is called """
def __init__(self, base, var_args=None):
@@ -140,7 +78,7 @@ class Executable(parsing.Base):
return self.base.parent
class Instance(use_metaclass(CachedMetaClass, Executable)):
class Instance(use_metaclass(cache.CachedMetaClass, Executable)):
""" This class is used to evaluate instances. """
def __init__(self, base, var_args=None):
super(Instance, self).__init__(base, var_args)
@@ -159,7 +97,7 @@ class Instance(use_metaclass(CachedMetaClass, Executable)):
# (No var_args) used.
self.is_generated = False
@memoize_default()
@cache.memoize_default()
def get_init_execution(self, func):
func = InstanceElement(self, func, True)
return Execution(func, self.var_args)
@@ -227,7 +165,7 @@ class Instance(use_metaclass(CachedMetaClass, Executable)):
args = helpers.generate_param_array(v)
return self.execute_subscope_by_name('__get__', args)
@memoize_default([])
@cache.memoize_default([])
def get_defined_names(self):
"""
Get the instance vars of a class. This includes the vars of all
@@ -273,7 +211,7 @@ class Instance(use_metaclass(CachedMetaClass, Executable)):
(type(self).__name__, self.base, len(self.var_args or []))
class InstanceElement(use_metaclass(CachedMetaClass)):
class InstanceElement(use_metaclass(cache.CachedMetaClass)):
"""
InstanceElement is a wrapper for any object, that is used as an instance
variable (e.g. self.variable or class methods).
@@ -288,7 +226,7 @@ class InstanceElement(use_metaclass(CachedMetaClass)):
self.is_class_var = is_class_var
@property
@memoize_default()
@cache.memoize_default()
def parent(self):
par = self.var.parent
if isinstance(par, Class) and par == self.instance.base \
@@ -317,8 +255,8 @@ class InstanceElement(use_metaclass(CachedMetaClass)):
par = InstanceElement(self.instance, origin.parent_stmt,
self.is_class_var)
new.parent_stmt = par
faked_scopes.append(par)
faked_scopes.append(new)
cache.faked_scopes.append(par)
cache.faked_scopes.append(new)
return new
def __getattr__(self, name):
@@ -331,7 +269,7 @@ class InstanceElement(use_metaclass(CachedMetaClass)):
return "<%s of %s>" % (type(self).__name__, self.var)
class Class(use_metaclass(CachedMetaClass, parsing.Base)):
class Class(use_metaclass(cache.CachedMetaClass, parsing.Base)):
"""
This class is not only important to extend `parsing.Class`, it is also a
important for descriptors (if the descriptor methods are evaluated or not).
@@ -339,7 +277,7 @@ class Class(use_metaclass(CachedMetaClass, parsing.Base)):
def __init__(self, base):
self.base = base
@memoize_default(default=[])
@cache.memoize_default(default=[])
def get_super_classes(self):
supers = []
# TODO care for mro stuff (multiple super classes).
@@ -355,7 +293,7 @@ class Class(use_metaclass(CachedMetaClass, parsing.Base)):
supers += get_scopes_for_name(builtin.Builtin.scope, 'object')
return supers
@memoize_default(default=[])
@cache.memoize_default(default=[])
def get_defined_names(self):
def in_iterable(name, iterable):
""" checks if the name is in the variable 'iterable'. """
@@ -397,7 +335,7 @@ class Class(use_metaclass(CachedMetaClass, parsing.Base)):
return "<e%s of %s>" % (type(self).__name__, self.base)
class Function(use_metaclass(CachedMetaClass, parsing.Base)):
class Function(use_metaclass(cache.CachedMetaClass, parsing.Base)):
"""
Needed because of decorators. Decorators are evaluated here.
"""
@@ -408,7 +346,7 @@ class Function(use_metaclass(CachedMetaClass, parsing.Base)):
self.is_decorated = is_decorated
@property
@memoize_default()
@cache.memoize_default()
def _decorated_func(self):
"""
Returns the function, that is to be executed in the end.
@@ -432,7 +370,7 @@ class Function(use_metaclass(CachedMetaClass, parsing.Base)):
# Create param array.
old_func = Function(f, is_decorated=True)
params = helpers.generate_param_array([old_func], old_func)
faked_scopes.append(old_func)
cache.faked_scopes.append(old_func)
wrappers = Execution(decorator, params).get_return_types()
if not len(wrappers):
@@ -481,7 +419,7 @@ class Execution(Executable):
multiple calls to functions and recursion has to be avoided. But this is
responsibility of the decorators.
"""
@memoize_default(default=[])
@cache.memoize_default(default=[])
@helpers.ExecutionRecursionDecorator
def get_return_types(self, evaluate_generator=False):
""" Get the return types of a function. """
@@ -555,7 +493,7 @@ class Execution(Executable):
stmts += follow_statement(r)
return stmts
@memoize_default(default=[])
@cache.memoize_default(default=[])
def get_params(self):
"""
This returns the params for an Execution/Instance and is injected as a
@@ -581,7 +519,7 @@ class Execution(Executable):
new_param.is_generated = True
name = copy.copy(param.get_name())
name.parent = new_param
faked_scopes.append(new_param)
cache.faked_scopes.append(new_param)
return name
result = []
@@ -737,7 +675,7 @@ class Execution(Executable):
if isinstance(copied, parsing.Function):
copied = Function(copied)
objects.append(copied)
faked_scopes.append(copied)
cache.faked_scopes.append(copied)
return objects
def __getattr__(self, name):
@@ -745,7 +683,7 @@ class Execution(Executable):
raise AttributeError('Tried to access %s: %s. Why?' % (name, self))
return getattr(self.base, name)
@memoize_default()
@cache.memoize_default()
def _scope_copy(self, scope):
try:
""" Copies a scope (e.g. if) in an execution """
@@ -758,28 +696,28 @@ class Execution(Executable):
else:
copied = helpers.fast_parent_copy(scope)
copied.parent = self._scope_copy(copied.parent)
faked_scopes.append(copied)
cache.faked_scopes.append(copied)
return copied
except AttributeError:
raise MultiLevelAttributeError(sys.exc_info())
@property
@memoize_default()
@cache.memoize_default()
def returns(self):
return self.copy_properties('returns')
@property
@memoize_default()
@cache.memoize_default()
def asserts(self):
return self.copy_properties('asserts')
@property
@memoize_default()
@cache.memoize_default()
def statements(self):
return self.copy_properties('statements')
@property
@memoize_default()
@cache.memoize_default()
def subscopes(self):
return self.copy_properties('subscopes')
@@ -791,7 +729,7 @@ class Execution(Executable):
(type(self).__name__, self.base)
class Generator(use_metaclass(CachedMetaClass, parsing.Base)):
class Generator(use_metaclass(cache.CachedMetaClass, parsing.Base)):
""" Cares for `yield` statements. """
def __init__(self, func, var_args):
super(Generator, self).__init__()
@@ -830,7 +768,7 @@ class Generator(use_metaclass(CachedMetaClass, parsing.Base)):
return "<%s of %s>" % (type(self).__name__, self.func)
class Array(use_metaclass(CachedMetaClass, parsing.Base)):
class Array(use_metaclass(cache.CachedMetaClass, parsing.Base)):
"""
Used as a mirror to parsing.Array, if needed. It defines some getter
methods which are important in this module.
@@ -1380,7 +1318,7 @@ def assign_tuples(tup, results, seek_name):
@helpers.RecursionDecorator
@memoize_default(default=[])
@cache.memoize_default(default=[])
def follow_statement(stmt, seek_name=None):
"""
The starting point of the completion. A statement always owns a call list,