temporary commit: introduced MultiLevelAttributeError. many prints to remove

This commit is contained in:
David Halter
2012-06-21 14:26:03 +02:00
parent a9676f77f1
commit 31a74da900
2 changed files with 118 additions and 25 deletions

View File

@@ -28,6 +28,8 @@ import debug
import builtin
import sys, traceback
memoize_caches = []
@@ -35,6 +37,23 @@ class MultiLevelStopIteration(Exception):
pass
class MultiLevelAttributeError(BaseException):
"""
Important, because `__getattr__` and `hasattr` catch AttributeErrors
implicitly. This is really evil (mainly because of `__getattr__`).
`hasattr` in Python 2 is even more evil, because it catches ALL exceptions.
Therefore this class has to be `BaseException` and not `Exception`.
"""
def __init__(self, base):
self.base = base
def __repr__(self):
return '%s: %s' % (self.base.__class__.__name__, self.base)
def __str__(self):
return self.__repr__()
def clear_caches():
for m in memoize_caches:
m.clear()
@@ -164,17 +183,32 @@ class Instance(Executable):
return names
@property
def line_nr(self):
return self.base.line_nr
def get_descriptor_return(self, obj):
""" Throws an error if there's no method. """
print '\n\nis_desc'
method = self.get_subscope_by_name('__get__')
print 'yessa'
# args in __set__ descriptors are obj, class.
args = [[obj], [obj.base]]
method = InstanceElement(self, method)
print 'la'
try:
res = Execution(method, args).get_return_types()
except Exception,e :
traceback.print_stack(file=sys.stdout)
print e, type(e)
print '\n'
#raise AttributeError('dini mueter')
raise e
@property
def indent(self):
return self.base.indent
print res
print '\n\n'
return res
@property
def name(self):
return self.base.name
def __getattr__(self, name):
if name not in ['line_nr', 'indent', 'name']:
raise AttributeError("Don't touch this (%s)!" % name)
return getattr(self.base, name)
def __repr__(self):
return "<e%s of %s (var_args: %s)>" % \
@@ -190,17 +224,36 @@ class InstanceElement(object):
@property
@memoize_default()
def parent(self):
try:
par = self.var.parent
if isinstance(par, parsing.Function):
par = Function(par)
return InstanceElement(self.instance, par)
except Exception, e:
traceback.print_stack(file=sys.stdout)
print e
print '\n'
raise
def get_parent_until(self, *classes):
scope = self.var.get_parent_until(*classes)
return InstanceElement(self.instance, scope)
def __getattr__(self, name):
def __getattribute__(self, name):
try:
a = object.__getattribute__(self, name)
except AttributeError:
try:
return getattr(self.var, name)
except AttributeError:
if name == '__get__':
raise
raise MultiLevelAttributeError(sys.exc_info()[1])
else:
if hasattr(a, '__get__'):
return a.__get__(self, self.__class__)
return a
def __repr__(self):
return "<%s of %s>" % (self.__class__.__name__, self.var)
@@ -268,9 +321,8 @@ class Function(object):
self.base_func = func
self.is_decorated = is_decorated
@property
@memoize_default()
def func(self):
def decorated_func(self):
"""
Returns the function, that is to be executed in the end.
This is also the places where the decorators are processed.
@@ -294,6 +346,13 @@ class Function(object):
old_func = Function(f, is_decorated=True)
params = parsing.Array(parsing.Array.NOARRAY, old_func)
params.values = [[old_func]]
try:
wrappers = Execution(decorator, params).get_return_types()
except Exception, e:
traceback.print_stack(file=sys.stdout)
print e
print '\n'
raise
wrappers = Execution(decorator, params).get_return_types()
if not len(wrappers):
debug.warning('no wrappers found', self.base_func)
@@ -309,8 +368,20 @@ class Function(object):
f = Function(f)
return f
def __getattr__(self, name):
return getattr(self.func, name)
def __getattribute__(self, name):
try:
a = object.__getattribute__(self, name)
except AttributeError:
try:
return getattr(self.decorated_func(), name)
except AttributeError:
if name == '__get__':
raise
raise MultiLevelAttributeError(sys.exc_info()[1])
else:
if hasattr(a, '__get__'):
return a.__get__(self, self.__class__)
return a
def __repr__(self):
return "<e%s of %s>" % (self.__class__.__name__, self.base_func)
@@ -337,7 +408,7 @@ class Execution(Executable):
# there maybe executions of executions
stmts = [Instance(self.base, self.var_args)]
elif isinstance(self.base, Generator):
return Execution(self.base.func).get_return_types(True)
return Execution(self.base.decorated_func()).get_return_types(True)
else:
# don't do this with exceptions, as usual, because some deeper
# exceptions could be catched - and I wouldn't know what happened.
@@ -348,12 +419,13 @@ class Execution(Executable):
# if it is an instance, we try to execute the __call__().
call_method = self.base.get_subscope_by_name('__call__')
except (AttributeError, KeyError):
print '\n\n\n\n\n\nfuuuuuuu'
debug.warning("no execution possible", self.base)
else:
debug.dbg('__call__', call_method, self.base)
base = self.base
if isinstance(self.base, Function):
base = self.base.func
base = self.base.decorated_func()
call_method = InstanceElement(base, call_method)
exe = Execution(call_method, self.var_args)
stmts = exe.get_return_types()
@@ -551,6 +623,7 @@ class Execution(Executable):
try:
return call.parent_stmt.parent
except AttributeError: # if operators are there
print '\n\n\n\n\n\nfuuuuuuu'
pass
raise IndexError('No params available')
@@ -647,6 +720,7 @@ class Array(object):
# multiple elements in the array
i = index.get_only_subelement().name
except AttributeError:
print '\n\n\n\n\n\nfuuuuuuu'
pass
else:
try:
@@ -665,9 +739,11 @@ class Array(object):
try:
str_key = key_elements.get_code()
except AttributeError:
print '\n\n\n\n\n\nfuuuuuuu'
try:
str_key = key_elements[0].name
except AttributeError:
print '\n\n\n\n\n\nfuuuuuuu'
str_key = None
if old_index == str_key:
index = i
@@ -836,6 +912,13 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False):
else:
inst = Instance(Class(par.parent.parent))
result.append(inst)
elif isinstance(par, Instance) \
and hasattr(par, 'get_descriptor_return'):
try:
result += par.get_descriptor_return(scope)
except KeyError:
result.append(par)
pass
else:
result.append(par)
return result
@@ -852,6 +935,10 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False):
s = scope.base if isinstance(scope, Class) else scope
# this means that a definition was found and is not e.g.
# in if/else.
print 'dini mueter1', name, name.parent, result
a = name.parent.parent
print 'dini mueter2', a
print 'end dini m'
if not name.parent or name.parent.parent == s:
break
# if there are results, ignore the other scopes
@@ -948,7 +1035,12 @@ def follow_statement(stmt, scope=None, seek_name=None):
debug.dbg('follow_stmt %s in %s (%s)' % (stmt, scope, seek_name))
call_list = stmt.get_assignment_calls()
debug.dbg('calls: %s' % call_list)
try:
result = follow_call_list(scope, call_list)
except AttributeError:
# This is so evil! But necessary to propagate errors.
raise MultiLevelAttributeError(sys.exc_info()[1])
# assignment checking is only important if the statement defines multiple
# variables
@@ -1067,7 +1159,8 @@ def follow_path(path, scope, position=None):
debug.warning('strange function call with {}', current, scope)
else:
# the function must not be decorated with something else
if isinstance(scope, Function) and isinstance(scope.func, Function):
if isinstance(scope, Function) and \
isinstance(scope.decorated_func(), Function):
# TODO check default function methods and return them
result = []
print 'la'

View File

@@ -150,7 +150,7 @@ CallClass()()
# -----------------
# properties
# -----------------
class Property(object):
class Property():
def __init__(self, fget, fset = None, fdel = None, doc = None):
self.fget = fget
self.fset = fset