def logAndContinue(f):
def doit(*a, **kw):
try: return f(*a, **kw)
except: log.err()
return doit
class ErrorLoggingType(type):
def __new__(cls, name, bases, attrs):
for (fname, func) in attrs.items():
attrs[fname] = logAndContinue(func)
return type.__new__(cls, name, bases, attrs)
class Errorful(object):
__metaclass__ = ErrorLoggingType
def error(self): 1/0
This is almost always up to the task, but last night I discovered a case where it didn't do all I wanted. The problem arose from the fact that, in a traceback, Python uses the code object's name, not the function object's name. In the above example, this would result in "doit" showing up in the traceback, instead of "error". So, I hacked up the following to get a code object with the name I wanted:
def formatArgs((args, varargs, kwargs, defaults)):
if defaults is None:
argString = ', '.join(args)
namespace = {}
else:
argString = ', '.join(args[:-len(defaults)])
defaultArgs = zip(args[-len(defaults):], defaults)
dfltString = ['%s=%s' % (a, a) for (a, v) in defaultArgs]
defaultArgString = ', '.join(dfltString)
if argString:
argString += ', ' + defaultArgString
else:
argString = defaultArgString
namespace = dict(defaultargs)
if varargs:
argString += ', *' + varargs
if kwargs:
argString += ', **' + kwargs
return argString, namespace
def _abcMethod(name, func):
s = "def %s(%s): raise NotImplementedError\n"
argspec, namespace = formatArgs(inspect.getargspec(func))
s = s % (name, argspec)
exec s in namespace
return namespace.pop(name)
As is hinted by the function "_abcMethod", I used this to generate functions for a generated Abstract Base Class version of a defined Interface. Since the only thing these functions do is raise an exception, it was somewhat more important than usual to have their names be correct.
formatArgs
could be replaced by a call to new.code
, but because new.code
takes 14 arguments, I don't think the code would be any simpler ;)
Curious what advantages/disadvantages this has WRT to decorators.
ReplyDeleteI think they're pretty much orthogonal. Care to elaborate?
ReplyDelete