forked from VimPlug/jedi
caches have their own module now.
This commit is contained in:
116
jedi/evaluate.py
116
jedi/evaluate.py
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user