From 39ed0d0f8ac1378f617e81bf1bb393b9c2e4dab5 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Tue, 24 Dec 2013 19:47:52 +0100 Subject: [PATCH] most evaluate representation classes probably receive the evaluator instance now --- jedi/evaluate/__init__.py | 16 +++++----- jedi/evaluate/cache.py | 15 +++++---- jedi/evaluate/representation.py | 54 ++++++++++++++++++--------------- 3 files changed, 47 insertions(+), 38 deletions(-) diff --git a/jedi/evaluate/__init__.py b/jedi/evaluate/__init__.py index 5cfd5a38..f9af24d7 100644 --- a/jedi/evaluate/__init__.py +++ b/jedi/evaluate/__init__.py @@ -255,10 +255,12 @@ class Evaluator(object): r = func.var.params[r.position_nr] # add docstring knowledge - doc_params = docstrings.follow_param(r) + """ + doc_params = docstrings.follow_param(r) TODO ENABLE if doc_params: res_new += doc_params continue + """ if not r.is_generated: res_new += dynamic.search_params(r) @@ -267,7 +269,7 @@ class Evaluator(object): if c in ('*', '**'): t = 'tuple' if c == '*' else 'dict' res_new = [er.Instance( - self.find_name(builtin.Builtin.scope, t)[0]) + self, self.find_name(builtin.Builtin.scope, t)[0]) ] if not r.assignment_details: # this means that there are no default params, @@ -284,7 +286,7 @@ class Evaluator(object): if check_instance is not None: # class renames - add = [er.InstanceElement(check_instance, a, True) + add = [er.InstanceElement(self, check_instance, a, True) if isinstance(a, (er.Function, pr.Function)) else a for a in add] res_new += add @@ -346,7 +348,7 @@ class Evaluator(object): if isinstance(scope, er.InstanceElement): inst = scope.instance else: - inst = er.Instance(er.Class(until())) + inst = er.Instance(self, er.Class(self, until())) inst.is_generated = True result.append(inst) elif par.isinstance(pr.Statement): @@ -543,7 +545,7 @@ class Evaluator(object): result += self.follow_statement(call.stmt) else: if isinstance(call, pr.Lambda): - result.append(er.Function(call)) + result.append(er.Function(self, call)) # With things like params, these can also be functions... elif isinstance(call, pr.Base) and call.isinstance( er.Function, er.Class, er.Instance, dynamic.ArrayInstance): @@ -595,7 +597,7 @@ class Evaluator(object): # for pr.Literal scopes = self.find_name(builtin.Builtin.scope, current.type_as_string()) # Make instances of those number/string objects. - scopes = [er.Instance(s, (current.value,)) for s in scopes] + scopes = [er.Instance(self, s, (current.value,)) for s in scopes] result = imports.strip_imports(self, scopes) return self.follow_paths(path, result, scope, position=position) @@ -662,7 +664,7 @@ class Evaluator(object): return self.follow_paths(path, set(result), call_scope, position=position) def execute(self, scope, params, evaluate_generator=False): - return er.Execution(scope, params).get_return_types(evaluate_generator) + return er.Execution(self, scope, params).get_return_types(evaluate_generator) def goto(self, stmt, call_path=None): if call_path is None: diff --git a/jedi/evaluate/cache.py b/jedi/evaluate/cache.py index 3ef7ebc7..44526373 100644 --- a/jedi/evaluate/cache.py +++ b/jedi/evaluate/cache.py @@ -5,7 +5,7 @@ """ -def memoize_default(default, cache_is_in_self=False): +def memoize_default(default, cache_is_in_self=False, first_arg_is_evaluator=False): """ This is a typical memoization decorator, BUT there is one difference: To prevent recursion it sets defaults. @@ -17,6 +17,8 @@ def memoize_default(default, cache_is_in_self=False): def wrapper(obj, *args, **kwargs): if cache_is_in_self: cache = obj.memoize_cache + elif first_arg_is_evaluator: # needed for meta classes + cache = args[0].memoize_cache else: cache = obj._evaluator.memoize_cache @@ -24,7 +26,7 @@ def memoize_default(default, cache_is_in_self=False): memo = cache[function] except KeyError: memo = {} - cache[function] = function + cache[function] = memo key = (args, frozenset(kwargs.items())) if key in memo: @@ -39,10 +41,11 @@ def memoize_default(default, cache_is_in_self=False): 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(None) + This is basically almost the same than the decorator above, it just caches + class initializations. I haven't found any other way, so I'm doing it with + meta classes. + """ + @memoize_default(None, first_arg_is_evaluator=True) def __call__(self, *args, **kwargs): return super(CachedMetaClass, self).__call__(*args, **kwargs) diff --git a/jedi/evaluate/representation.py b/jedi/evaluate/representation.py index 4d539a75..dee8a273 100644 --- a/jedi/evaluate/representation.py +++ b/jedi/evaluate/representation.py @@ -34,7 +34,7 @@ class Executable(pr.IsScope): :param var_args: The param input array, consist of `pr.Array` or list. """ def __init__(self, evaluator, base, var_args=()): - self.evaluator = evaluator + self._evaluator = evaluator self.base = base self.var_args = var_args @@ -74,8 +74,8 @@ class Instance(use_metaclass(CachedMetaClass, Executable)): @memoize_default(None) def _get_method_execution(self, func): - func = InstanceElement(self, func, True) - return Execution(func, self.var_args) + func = InstanceElement(self._evaluator, self, func, True) + return Execution(self._evaluator, func, self.var_args) def _get_func_self_name(self, func): """ @@ -96,7 +96,7 @@ class Instance(use_metaclass(CachedMetaClass, Executable)): """ n = copy.copy(name) n.names = n.names[1:] - names.append(InstanceElement(self, n)) + names.append(InstanceElement(self._evaluator, self, n)) names = [] # This loop adds the names of the self object, copies them and removes @@ -125,17 +125,17 @@ class Instance(use_metaclass(CachedMetaClass, Executable)): add_self_dot_name(n) for s in self.base.get_super_classes(): - names += Instance(s)._get_self_attributes() + names += Instance(self._evaluator, s)._get_self_attributes() return names def get_subscope_by_name(self, name): sub = self.base.get_subscope_by_name(name) - return InstanceElement(self, sub, True) + return InstanceElement(self._evaluator, self, sub, True) def execute_subscope_by_name(self, name, args=()): method = self.get_subscope_by_name(name) - return Execution(method, args).get_return_types() + return Execution(self._evaluator, method, args).get_return_types() def get_descriptor_return(self, obj): """ Throws a KeyError if there's no method. """ @@ -154,7 +154,7 @@ class Instance(use_metaclass(CachedMetaClass, Executable)): class_names = self.base.instance_names() for var in class_names: - names.append(InstanceElement(self, var, True)) + names.append(InstanceElement(self._evaluator, self, var, True)) return names def scope_generator(self): @@ -167,7 +167,7 @@ class Instance(use_metaclass(CachedMetaClass, Executable)): names = [] class_names = self.base.instance_names() for var in class_names: - names.append(InstanceElement(self, var, True)) + names.append(InstanceElement(self._evaluator, self, var, True)) yield self, names def get_index_types(self, index=None): @@ -195,9 +195,9 @@ class InstanceElement(use_metaclass(CachedMetaClass, pr.Base)): InstanceElement is a wrapper for any object, that is used as an instance variable (e.g. self.variable or class methods). """ - def __init__(self, instance, var, is_class_var=False): + def __init__(self, evaluator, instance, var, is_class_var=False): if isinstance(var, pr.Function): - var = Function(var) + var = Function(evaluator, var) elif isinstance(var, pr.Class): var = Class(var) self.instance = instance @@ -213,7 +213,7 @@ class InstanceElement(use_metaclass(CachedMetaClass, pr.Base)): and par == self.instance.base.base: par = self.instance elif not isinstance(par, pr.Module): - par = InstanceElement(self.instance, par, self.is_class_var) + par = InstanceElement(self.instance._evaluator, self.instance, par, self.is_class_var) return par def get_parent_until(self, *args, **kwargs): @@ -228,13 +228,13 @@ class InstanceElement(use_metaclass(CachedMetaClass, pr.Base)): def get_commands(self): # Copy and modify the array. - return [InstanceElement(self.instance, command, self.is_class_var) + return [InstanceElement(self.instance._evaluator, self.instance, command, self.is_class_var) if not isinstance(command, unicode) else command for command in self.var.get_commands()] def __iter__(self): for el in self.var.__iter__(): - yield InstanceElement(self.instance, el, self.is_class_var) + yield InstanceElement(self.instance._evaluator, self.instance, el, self.is_class_var) def __getattr__(self, name): return getattr(self.var, name) @@ -352,12 +352,12 @@ class Function(use_metaclass(CachedMetaClass, pr.IsScope)): debug.warning('multiple decorators found', self.base_func, dec_results) # Create param array. - old_func = Function(f, is_decorated=True) + old_func = Function(self._evaluator, f, is_decorated=True) if instance is not None and decorator.isinstance(Function): - old_func = InstanceElement(instance, old_func) + old_func = InstanceElement(self._evaluator, instance, old_func) instance = None - wrappers = Execution(decorator, (old_func,)).get_return_types() + wrappers = Execution(self._evaluator, decorator, (old_func,)).get_return_types() if not len(wrappers): debug.warning('no wrappers found', self.base_func) return None @@ -369,7 +369,7 @@ class Function(use_metaclass(CachedMetaClass, pr.IsScope)): debug.dbg('decorator end', f) if f != self.base_func and isinstance(f, pr.Function): - f = Function(f) + f = Function(self._evaluator, f) return f def get_decorated_func(self, instance=None): @@ -380,7 +380,7 @@ class Function(use_metaclass(CachedMetaClass, pr.IsScope)): # If the decorator func is not found, just ignore the decorator # function, because sometimes decorators are just really # complicated. - return Function(self.base_func, True) + return Function(self._evaluator, self.base_func, True) return decorated_func def get_magic_method_names(self): @@ -473,12 +473,12 @@ class Execution(Executable): cls = Class(cls) su = cls.get_super_classes() if su: - return [Instance(su[0])] + return [Instance(self._evaluator, su[0])] return [] if base.isinstance(Class): # There maybe executions of executions. - return [Instance(base, self.var_args)] + return [Instance(self._evaluator, base, self.var_args)] elif isinstance(base, Generator): return base.iter_content() else: @@ -508,7 +508,10 @@ class Execution(Executable): if func.is_generator and not evaluate_generator: return [Generator(func, self.var_args)] else: + """ stmts = docstrings.find_return_types(func) + """ + stmts=[] for r in self.returns: if r is not None: stmts += self._evaluator.follow_statement(r) @@ -727,7 +730,7 @@ class Execution(Executable): copied = helpers.fast_parent_copy(element) copied.parent = self._scope_copy(copied.parent) if isinstance(copied, pr.Function): - copied = Function(copied) + copied = Function(self._evaluator, copied) objects.append(copied) return objects @@ -781,7 +784,8 @@ class Execution(Executable): class Generator(use_metaclass(CachedMetaClass, pr.Base, Iterable)): """ Cares for `yield` statements. """ - def __init__(self, func, var_args): + def __init__(self, evaluator, func, var_args): + # Need evaluator for `CachedMetaClass`. super(Generator, self).__init__() self.func = func self.var_args = var_args @@ -807,7 +811,7 @@ class Generator(use_metaclass(CachedMetaClass, pr.Base, Iterable)): def iter_content(self): """ returns the content of __iter__ """ - return Execution(self.func, self.var_args).get_return_types(True) + return Execution(self._evaluator, self.func, self.var_args).get_return_types(True) def get_index_types(self, index=None): debug.warning('Tried to get array access on a generator', self) @@ -897,7 +901,7 @@ class Array(use_metaclass(CachedMetaClass, pr.Base, Iterable)): """ # `array.type` is a string with the type, e.g. 'list'. scope = self._evaluator.find_name(builtin.Builtin.scope, self._array.type)[0] - scope = Instance(scope) + scope = Instance(self._evaluator, scope) names = scope.get_defined_names() return [ArrayMethod(n) for n in names]