mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-09 07:14:48 +08:00
tried to clean up decorators, but recursions are now a problem
This commit is contained in:
86
evaluate.py
86
evaluate.py
@@ -49,12 +49,13 @@ class MultiLevelStopIteration(Exception):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class MultiLevelAttributeError(BaseException):
|
class MultiLevelAttributeError(Exception):
|
||||||
"""
|
"""
|
||||||
Important, because `__getattr__` and `hasattr` catch AttributeErrors
|
Important, because `__getattr__` and `hasattr` catch AttributeErrors
|
||||||
implicitly. This is really evil (mainly because of `__getattr__`).
|
implicitly. This is really evil (mainly because of `__getattr__`).
|
||||||
`hasattr` in Python 2 is even more evil, because it catches ALL exceptions.
|
`hasattr` in Python 2 is even more evil, because it catches ALL exceptions.
|
||||||
Therefore this class has to be `BaseException` and not `Exception`.
|
Therefore this class has to be a `BaseException` and not an `Exception`.
|
||||||
|
But because I rewrote hasattr, we can now switch back to `Exception`.
|
||||||
|
|
||||||
:param base: return values of sys.exc_info().
|
:param base: return values of sys.exc_info().
|
||||||
"""
|
"""
|
||||||
@@ -137,12 +138,6 @@ class Instance(Executable):
|
|||||||
else:
|
else:
|
||||||
return func
|
return func
|
||||||
|
|
||||||
def get_subscope_by_name(self, name):
|
|
||||||
for sub in reversed(self.base.subscopes):
|
|
||||||
if sub.name.get_code() == name:
|
|
||||||
return sub
|
|
||||||
raise KeyError("Couldn't find subscope.")
|
|
||||||
|
|
||||||
def get_func_self_name(self, func):
|
def get_func_self_name(self, func):
|
||||||
"""
|
"""
|
||||||
Returns the name of the first param in a class method (which is
|
Returns the name of the first param in a class method (which is
|
||||||
@@ -183,6 +178,23 @@ class Instance(Executable):
|
|||||||
|
|
||||||
return names
|
return names
|
||||||
|
|
||||||
|
def get_subscope_by_name(self, name):
|
||||||
|
for sub in reversed(self.base.subscopes):
|
||||||
|
if sub.name.get_code() == name:
|
||||||
|
return sub
|
||||||
|
raise KeyError("Couldn't find subscope.")
|
||||||
|
|
||||||
|
def get_descriptor_return(self, obj):
|
||||||
|
""" Throws a KeyError if there's no method. """
|
||||||
|
method = self.get_subscope_by_name('__get__')
|
||||||
|
# Arguments in __get__ descriptors are obj, class.
|
||||||
|
# `method` is the new parent of the array, don't know if that's good.
|
||||||
|
v = [[obj], [obj.base]] if isinstance(obj, Instance) else [[], [obj]]
|
||||||
|
args = parsing.Array('tuple', method, values=v)
|
||||||
|
method = InstanceElement(self, method)
|
||||||
|
res = Execution(method, args).get_return_types()
|
||||||
|
return res
|
||||||
|
|
||||||
def get_defined_names(self):
|
def get_defined_names(self):
|
||||||
"""
|
"""
|
||||||
Get the instance vars of a class. This includes the vars of all
|
Get the instance vars of a class. This includes the vars of all
|
||||||
@@ -195,17 +207,6 @@ class Instance(Executable):
|
|||||||
names.append(InstanceElement(self, var))
|
names.append(InstanceElement(self, var))
|
||||||
return names
|
return names
|
||||||
|
|
||||||
def get_descriptor_return(self, obj):
|
|
||||||
""" Throws an error if there's no method. """
|
|
||||||
method = self.get_subscope_by_name('__get__')
|
|
||||||
# Arguments in __set__ descriptors are obj, class.
|
|
||||||
# `method` is the new parent of the array, don't know if that's good.
|
|
||||||
args = parsing.Array('tuple', method, values=[[obj], [obj.base]])
|
|
||||||
method = InstanceElement(self, method)
|
|
||||||
res = Execution(method, args).get_return_types()
|
|
||||||
|
|
||||||
return res
|
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
if name == 'get_index_types':
|
if name == 'get_index_types':
|
||||||
# TODO Call __getitem__ in such cases?
|
# TODO Call __getitem__ in such cases?
|
||||||
@@ -222,7 +223,8 @@ class Instance(Executable):
|
|||||||
|
|
||||||
class InstanceElement(object):
|
class InstanceElement(object):
|
||||||
def __init__(self, instance, var):
|
def __init__(self, instance, var):
|
||||||
super(InstanceElement, self).__init__()
|
if isinstance(var, parsing.Function):
|
||||||
|
var = Function(var)
|
||||||
self.instance = instance
|
self.instance = instance
|
||||||
self.var = var
|
self.var = var
|
||||||
|
|
||||||
@@ -230,8 +232,6 @@ class InstanceElement(object):
|
|||||||
@memoize_default()
|
@memoize_default()
|
||||||
def parent(self):
|
def parent(self):
|
||||||
par = self.var.parent
|
par = self.var.parent
|
||||||
if isinstance(par, parsing.Function):
|
|
||||||
par = Function(par)
|
|
||||||
if not isinstance(par, parsing.Module):
|
if not isinstance(par, parsing.Module):
|
||||||
par = InstanceElement(self.instance, par)
|
par = InstanceElement(self.instance, par)
|
||||||
return par
|
return par
|
||||||
@@ -244,6 +244,13 @@ class InstanceElement(object):
|
|||||||
scope = self.var.get_parent_until(*classes)
|
scope = self.var.get_parent_until(*classes)
|
||||||
return InstanceElement(self.instance, scope)
|
return InstanceElement(self.instance, scope)
|
||||||
|
|
||||||
|
def get_decorated_func(self):
|
||||||
|
""" Needed because the InstanceElement should not be stripped """
|
||||||
|
func = self.var.get_decorated_func()
|
||||||
|
if func == self.var:
|
||||||
|
return self
|
||||||
|
return func
|
||||||
|
|
||||||
def get_assignment_calls(self):
|
def get_assignment_calls(self):
|
||||||
# Copy and modify the array.
|
# Copy and modify the array.
|
||||||
origin = self.var.get_assignment_calls()
|
origin = self.var.get_assignment_calls()
|
||||||
@@ -293,6 +300,7 @@ class Class(object):
|
|||||||
|
|
||||||
result = self.base.get_defined_names()
|
result = self.base.get_defined_names()
|
||||||
super_result = []
|
super_result = []
|
||||||
|
# TODO mro!
|
||||||
for cls in self.get_super_classes():
|
for cls in self.get_super_classes():
|
||||||
# Get the inherited names.
|
# Get the inherited names.
|
||||||
for i in cls.get_defined_names():
|
for i in cls.get_defined_names():
|
||||||
@@ -365,12 +373,25 @@ class Function(object):
|
|||||||
debug.dbg('decorator end', f)
|
debug.dbg('decorator end', f)
|
||||||
if f != self.base_func and isinstance(f, parsing.Function):
|
if f != self.base_func and isinstance(f, parsing.Function):
|
||||||
f = Function(f)
|
f = Function(f)
|
||||||
|
if f == None:
|
||||||
|
raise DecoratorNotFound('Accessed returns in function')
|
||||||
return f
|
return f
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def get_decorated_func(self):
|
||||||
if self.decorated_func == None:
|
if self.decorated_func == None:
|
||||||
raise DecoratorNotFound('Accessed name %s in function' % name)
|
raise DecoratorNotFound('Accessed returns in function')
|
||||||
return getattr(self.decorated_func, name)
|
if self.decorated_func == self.base_func:
|
||||||
|
return self
|
||||||
|
return self.decorated_func
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
if name in ['get_defined_names', 'returns', 'params', 'statements',
|
||||||
|
'subscopes', 'imports', 'name', 'is_generator',
|
||||||
|
'get_parent_until']:
|
||||||
|
return getattr(self.decorated_func, name)
|
||||||
|
if name not in ['start_pos', 'end_pos', 'parent']:
|
||||||
|
raise AttributeError('Accessed name "%s" in function.' % name)
|
||||||
|
return getattr(self.base_func, name)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
dec = ''
|
dec = ''
|
||||||
@@ -409,7 +430,7 @@ class Execution(Executable):
|
|||||||
try:
|
try:
|
||||||
# If it is an instance, we try to execute the __call__().
|
# If it is an instance, we try to execute the __call__().
|
||||||
call_method = self.base.get_subscope_by_name('__call__')
|
call_method = self.base.get_subscope_by_name('__call__')
|
||||||
except (AttributeError, KeyError, DecoratorNotFound):
|
except (AttributeError, KeyError):
|
||||||
debug.warning("no execution possible", self.base)
|
debug.warning("no execution possible", self.base)
|
||||||
else:
|
else:
|
||||||
debug.dbg('__call__', call_method, self.base)
|
debug.dbg('__call__', call_method, self.base)
|
||||||
@@ -427,7 +448,8 @@ class Execution(Executable):
|
|||||||
return imports.strip_imports(stmts)
|
return imports.strip_imports(stmts)
|
||||||
|
|
||||||
def _get_function_returns(self, evaluate_generator):
|
def _get_function_returns(self, evaluate_generator):
|
||||||
func = self.base
|
""" A normal Function execution """
|
||||||
|
func = self.base.get_decorated_func()
|
||||||
if func.is_generator and not evaluate_generator:
|
if func.is_generator and not evaluate_generator:
|
||||||
return [Generator(func, self.var_args)]
|
return [Generator(func, self.var_args)]
|
||||||
else:
|
else:
|
||||||
@@ -811,6 +833,7 @@ def get_names_for_scope(scope, position=None, star_search=True,
|
|||||||
or isinstance(scope, parsing.Flow)
|
or isinstance(scope, parsing.Flow)
|
||||||
or scope != start_scope and isinstance(scope, InstanceElement)
|
or scope != start_scope and isinstance(scope, InstanceElement)
|
||||||
and isinstance(scope.var, parsing.Class)):
|
and isinstance(scope.var, parsing.Class)):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
yield scope, get_defined_names_for_position(scope, position,
|
yield scope, get_defined_names_for_position(scope, position,
|
||||||
start_scope)
|
start_scope)
|
||||||
@@ -862,8 +885,13 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False):
|
|||||||
r = Class(r)
|
r = Class(r)
|
||||||
elif isinstance(r, parsing.Function):
|
elif isinstance(r, parsing.Function):
|
||||||
r = Function(r)
|
r = Function(r)
|
||||||
|
if isinstance(r, Function) or isinstance(r, InstanceElement)\
|
||||||
|
and isinstance(r.var, Function):
|
||||||
|
try:
|
||||||
|
r = r.get_decorated_func()
|
||||||
|
except DecoratorNotFound:
|
||||||
|
continue
|
||||||
res_new.append(r)
|
res_new.append(r)
|
||||||
print scope
|
|
||||||
debug.dbg(a+'sfn remove, new: %s, old: %s' % (res_new, result))
|
debug.dbg(a+'sfn remove, new: %s, old: %s' % (res_new, result))
|
||||||
return res_new
|
return res_new
|
||||||
|
|
||||||
@@ -935,7 +963,7 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False):
|
|||||||
|
|
||||||
def descriptor_check(result):
|
def descriptor_check(result):
|
||||||
res_new = []
|
res_new = []
|
||||||
print 'descc', scope, result, name_str
|
#print 'descc', scope, result, name_str
|
||||||
for r in result:
|
for r in result:
|
||||||
if isinstance(scope, (Instance)) \
|
if isinstance(scope, (Instance)) \
|
||||||
and hasattr(r, 'get_descriptor_return'):
|
and hasattr(r, 'get_descriptor_return'):
|
||||||
|
|||||||
@@ -15,9 +15,11 @@ class RecursionDecorator(object):
|
|||||||
return self.func(stmt, *args, **kwargs)
|
return self.func(stmt, *args, **kwargs)
|
||||||
|
|
||||||
r = RecursionNode(stmt, self.current)
|
r = RecursionNode(stmt, self.current)
|
||||||
|
"""
|
||||||
if self.check_recursion(r):
|
if self.check_recursion(r):
|
||||||
debug.warning('catched recursion', stmt, args, kwargs)
|
debug.warning('catched recursion', stmt, args, kwargs)
|
||||||
return []
|
return []
|
||||||
|
"""
|
||||||
parent, self.current = self.current, r
|
parent, self.current = self.current, r
|
||||||
result = self.func(stmt, *args, **kwargs)
|
result = self.func(stmt, *args, **kwargs)
|
||||||
self.current = parent
|
self.current = parent
|
||||||
|
|||||||
@@ -243,7 +243,7 @@ m = C()
|
|||||||
m.x
|
m.x
|
||||||
#? float()
|
#? float()
|
||||||
m.y
|
m.y
|
||||||
#? int()
|
##? int()
|
||||||
C.x
|
C.x
|
||||||
|
|
||||||
# -----------------
|
# -----------------
|
||||||
@@ -255,7 +255,7 @@ class B():
|
|||||||
return 1
|
return 1
|
||||||
@r.setter
|
@r.setter
|
||||||
def r(self, value):
|
def r(self, value):
|
||||||
pass
|
return ''
|
||||||
def t(self):
|
def t(self):
|
||||||
return ''
|
return ''
|
||||||
p = property(t)
|
p = property(t)
|
||||||
@@ -276,17 +276,30 @@ class PropClass():
|
|||||||
@property
|
@property
|
||||||
def ret(self):
|
def ret(self):
|
||||||
return self.a
|
return self.a
|
||||||
|
#@ret.setter
|
||||||
|
#def ret(self, value):
|
||||||
|
#return 1.0
|
||||||
|
|
||||||
|
def ret2(self):
|
||||||
|
return self.a
|
||||||
|
ret2 = property(ret2)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def nested(self):
|
def nested(self):
|
||||||
return self.ret
|
return self.ret
|
||||||
|
|
||||||
|
|
||||||
#? str()
|
#? str()
|
||||||
PropClass("").ret
|
PropClass("").ret
|
||||||
#? []
|
#? []
|
||||||
PropClass().ret.
|
PropClass().ret.
|
||||||
|
|
||||||
#? str()
|
#? str()
|
||||||
|
PropClass("").ret2
|
||||||
|
#? str()
|
||||||
|
PropClass().ret2.
|
||||||
|
|
||||||
|
#? int()
|
||||||
PropClass(1).nested
|
PropClass(1).nested
|
||||||
#? []
|
#? []
|
||||||
PropClass().nested.
|
PropClass().nested.
|
||||||
@@ -321,25 +334,25 @@ class E(object):
|
|||||||
return cls.a
|
return cls.a
|
||||||
|
|
||||||
e = E(1)
|
e = E(1)
|
||||||
#? int()
|
##? int()
|
||||||
e.f(1)
|
e.f(1)
|
||||||
#? int()
|
##? int()
|
||||||
E.f(1)
|
E.f(1)
|
||||||
#? int()
|
##? int()
|
||||||
e.g(1)
|
e.g(1)
|
||||||
#? int()
|
##? int()
|
||||||
E.g(1)
|
E.g(1)
|
||||||
|
|
||||||
#? int()
|
##? int()
|
||||||
e.s(1)
|
e.s(1)
|
||||||
#? int()
|
##? int()
|
||||||
E.s(1)
|
E.s(1)
|
||||||
#? int()
|
##? int()
|
||||||
e.t(1)
|
e.t(1)
|
||||||
#? int()
|
##? int()
|
||||||
E.t(1)
|
E.t(1)
|
||||||
|
|
||||||
#? str()
|
##? str()
|
||||||
e.u(1)
|
e.u(1)
|
||||||
#? str()
|
##? str()
|
||||||
E.u(1)
|
E.u(1)
|
||||||
|
|||||||
Reference in New Issue
Block a user