Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

wrapping class method in try / except using decorator

I have a general purpose function that sends info about exceptions to an application log. I use the exception_handler function from within methods in classes. The app log handler that is passed into and called by the exception_handler creates a JSON string that is what actually gets sent to the logfile. This all works fine.

def exception_handler(log, terminate=False):
    exc_type, exc_value, exc_tb = sys.exc_info()
    filename, line_num, func_name, text = traceback.extract_tb(exc_tb)[-1]
    log.error('{0} Thrown from module: {1} in {2} at line: {3} ({4})'.format(exc_value, filename, func_name, line_num, text))
    del (filename, line_num, func_name, text)
    if terminate:
        sys.exit()

I use it as follows: (a hyper-simplified example)

from utils import exception_handler

class Demo1(object):
    def __init__(self):
        self.log = {a class that implements the application log}

    def demo(self, name):
        try:
            print(name)
        except Exception:
            exception_handler(self.log, True)

I would like to alter exception_handler for use as a decorator for a large number of methods, i.e.:

@handle_exceptions
def func1(self, name)
    {some code that gets wrapped in a try / except by the decorator}

I've looked at a number of articles about decorators, but I haven't yet figured out how to implement what I want to do. I need to pass a reference to the active log object and also pass 0 or more arguments to the wrapped function. I'd be happy to convert exception_handler to a method in a class if that makes things easier.

like image 377
RoyHB Avatar asked Apr 22 '14 12:04

RoyHB


People also ask

What is wrapper in decorator?

Wrappers around the functions are also knows as decorators which are a very powerful and useful tool in Python since it allows programmers to modify the behavior of function or class. Decorators allow us to wrap another function in order to extend the behavior of the wrapped function, without permanently modifying it.

Can a class method be a decorator?

In Python, the @classmethod decorator is used to declare a method in the class as a class method that can be called using ClassName. MethodName() . The class method can also be called using an object of the class. The @classmethod is an alternative of the classmethod() function.

Can I use a decorator on a method?

Decorators dynamically alter the functionality of a function, method, or class without having to directly use subclasses or change the source code of the function being decorated.

Why do you need a wrapper in a decorator?

The purpose of having a wrapper function is that a function decorator receives a function object to decorate, and it must return the decorated function.


2 Answers

Such a decorator would simply be:

def handle_exceptions(f):
    def wrapper(*args, **kw):
        try:
            return f(*args, **kw)
        except Exception:
            self = args[0]
            exception_handler(self.log, True)
    return wrapper

This decorator simply calls the wrapped function inside a try suite.

This can be applied to methods only, as it assumes the first argument is self.

like image 162
Martijn Pieters Avatar answered Oct 13 '22 08:10

Martijn Pieters


Thanks to Martijn for pointing me in the right direction. I couldn't get his suggested solution to work but after a little more searching based on his example the following works fine:

def handle_exceptions(fn):
    from functools import wraps
    @wraps(fn)
    def wrapper(self, *args, **kw):
        try:
            return fn(self, *args, **kw)
        except Exception:
            exception_handler(self.log)
    return wrapper
like image 42
RoyHB Avatar answered Oct 13 '22 08:10

RoyHB