Is it possible to write an exception handler to catch the run-time errors generated by ALL the methods in class? I can do it by surrounding each one with try/except:
Assuming you've got a decorator catch_exception
as in @Jon Clement's answer...
class ErrorCatcher(type):
def __new__(cls, name, bases, dct):
for m in dct:
if hasattr(dct[m], '__call__'):
dct[m] = catch_exception(dct[m])
return type.__new__(cls, name, bases, dct)
class Test(object):
__metaclass__ = ErrorCatcher
def __init__(self, val):
self.val = val
def calc(self):
return self.val / 0
The metaclass applies catch_exception
to everything that appears to be a method while it is defining Test
.
In response to a comment regarding custom messages for each method, one could attach such a message (or even a callback function to generate a message) as an attribute:
class Test(object):
__metaclass__ = ErrorCatcher
def __init__(self, val):
self.val = val
def calc(self):
return self.val / 0
calc.msg = "Dividing by 0 is ill-advised"
The catch_exception
decorator would look for a msg
attribute on its argument and use it, if found, in handling the exception.
This approach could be extended; instead of a string, msg
could be a mapping of exception types to strings. In either case, the string could be replaced (with support from catch_exception
, of course) with an arbitrary callback function that takes, say, the raised exception as an argument.
def calc_handler(exc):
# ...
calc.callback = calc_handler
Warning: if you want something like this, it's likely you don't... but if you really want to...
Something like:
import functools
def catch_exception(f):
@functools.wraps(f)
def func(*args, **kwargs):
try:
return f(*args, **kwargs)
except Exception as e:
print 'Caught an exception in', f.__name__
return func
class Test(object):
def __init__(self, val):
self.val = val
@catch_exception
def calc():
return self.val / 0
t = Test(3)
t.calc()
shows how to decorate individual functions. You can then create a class decorator to apply this decorator to each method (be careful of classmethod's
/staticmethod's
/properties
etc...)
A decorator would be a good solution here.
Here's an example of how you could do it:
import inspect
def catch_exception_decorator(function):
def decorated_function:
try:
function()
except:
raise MyError(self.__class__, inspect.stack()[1][3])
return decorated_function
class MyClass(object):
def __init__(self):
...
@catch_exception_decorator
def f1(self):
...
@catch_exception_decorator on top of the function is a shortcut for f1 = catch_exception_decorator(f1)
.
Instead of doing self.class, you could also access class data from the instance, as long as you're not shadowing variables. inspect.stack()[1][3] is the function name of the current function. You can use these to create the exception attributes.