forked from VimPlug/jedi
caches have their own module now.
This commit is contained in:
@@ -442,7 +442,7 @@ class Script(object):
|
||||
return match.groups()
|
||||
|
||||
def __del__(self):
|
||||
evaluate.clear_caches()
|
||||
api_classes._clear_caches()
|
||||
|
||||
|
||||
def set_debug_function(func_cb=debug.print_to_stdout, warnings=True,
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
import re
|
||||
import os
|
||||
|
||||
import cache
|
||||
import dynamic
|
||||
import helpers
|
||||
import settings
|
||||
import evaluate
|
||||
import imports
|
||||
@@ -10,6 +13,20 @@ import parsing
|
||||
import keywords
|
||||
|
||||
|
||||
def _clear_caches():
|
||||
"""
|
||||
Clears all caches of this and related modules. The only cache that will not
|
||||
be deleted is the module cache.
|
||||
"""
|
||||
cache.clear_caches()
|
||||
dynamic.search_param_cache.clear()
|
||||
helpers.ExecutionRecursionDecorator.reset()
|
||||
|
||||
evaluate.follow_statement.reset()
|
||||
|
||||
imports.imports_processed = 0
|
||||
|
||||
|
||||
class BaseDefinition(object):
|
||||
_mapping = {'posixpath': 'os.path',
|
||||
'riscospath': 'os.path',
|
||||
@@ -193,7 +210,7 @@ class Completion(BaseDefinition):
|
||||
|
||||
self._followed_definitions = \
|
||||
[BaseDefinition(d, d.start_pos) for d in defs]
|
||||
evaluate.clear_caches()
|
||||
_clear_caches()
|
||||
|
||||
return self._followed_definitions
|
||||
|
||||
|
||||
53
jedi/cache.py
Normal file
53
jedi/cache.py
Normal file
@@ -0,0 +1,53 @@
|
||||
memoize_caches = []
|
||||
faked_scopes = []
|
||||
|
||||
|
||||
def clear_caches():
|
||||
""" Jedi caches many things, that should be completed after each completion
|
||||
finishes.
|
||||
"""
|
||||
global memoize_caches, faked_scopes
|
||||
|
||||
# memorize_caches must never be deleted, because the dicts will get lost in
|
||||
# the wrappers.
|
||||
for m in memoize_caches:
|
||||
m.clear()
|
||||
|
||||
faked_scopes = [] # TODO really needed anymore? weakrefs are gone...
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import re
|
||||
import evaluate
|
||||
|
||||
|
||||
#@evaluate.memoize_default() # TODO add
|
||||
#@cache.memoize_default() # TODO add
|
||||
def follow_param(param):
|
||||
func = param.parent_function
|
||||
#print func, param, param.parent_function
|
||||
|
||||
@@ -9,6 +9,7 @@ from __future__ import with_statement
|
||||
|
||||
import os
|
||||
|
||||
import cache
|
||||
import parsing
|
||||
import modules
|
||||
import evaluate
|
||||
@@ -93,7 +94,7 @@ class ParamListener(object):
|
||||
self.param_possibilities.append(params)
|
||||
|
||||
|
||||
@evaluate.memoize_default([])
|
||||
@cache.memoize_default([])
|
||||
def search_params(param):
|
||||
"""
|
||||
This is a dynamic search for params. If you try to complete a type:
|
||||
@@ -223,7 +224,7 @@ def dec(func):
|
||||
|
||||
|
||||
#@dec
|
||||
@evaluate.memoize_default([])
|
||||
@cache.memoize_default([])
|
||||
def _check_array_additions(compare_array, module, is_list):
|
||||
"""
|
||||
Checks if a `parsing.Array` has "add" statements:
|
||||
|
||||
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,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import copy
|
||||
import contextlib
|
||||
|
||||
import cache
|
||||
import parsing
|
||||
import evaluate
|
||||
import debug
|
||||
@@ -195,7 +196,7 @@ def generate_param_array(args_tuple, parent_stmt=None):
|
||||
values.append([arg])
|
||||
pos = None
|
||||
arr = parsing.Array(pos, parsing.Array.TUPLE, parent_stmt, values=values)
|
||||
evaluate.faked_scopes.append(arr)
|
||||
cache.faked_scopes.append(arr)
|
||||
return arr
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import imp
|
||||
import sys
|
||||
import time
|
||||
|
||||
import cache
|
||||
import builtin
|
||||
import modules
|
||||
import debug
|
||||
@@ -91,7 +92,7 @@ class ImportPath(parsing.Base):
|
||||
n = parsing.Name(i.namespace.names[1:], zero, zero, self.import_stmt)
|
||||
new = parsing.Import(zero, zero, n)
|
||||
new.parent = parent
|
||||
evaluate.faked_scopes.append(new)
|
||||
cache.faked_scopes.append(new)
|
||||
debug.dbg('Generated a nested import: %s' % new)
|
||||
return new
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import sys
|
||||
import os
|
||||
import time
|
||||
|
||||
import cache
|
||||
import parsing
|
||||
import builtin
|
||||
import debug
|
||||
@@ -215,7 +216,7 @@ class ModuleWithCursor(Module):
|
||||
return self._part_parser
|
||||
|
||||
|
||||
@evaluate.memoize_default([])
|
||||
@cache.memoize_default([])
|
||||
def sys_path_with_modifications(module):
|
||||
def execute_code(code):
|
||||
c = "import os; from os.path import *; result=%s"
|
||||
|
||||
Reference in New Issue
Block a user