Python Decorators and Error Handling

Python decorators are super convenient for making error handling a breeze, but a lot of people don’t know how to use them. Here is a quick tutorial on how they work.

Basically, a decorator is a function that takes another function as input, and provides a wrapper of additional behavior around that function. You apply a decorator to its input function by invoking it with the @ sign above the input function definition, like so:

def generic_decorator(fn):
    def wrapper(*args, **kwargs):
        return fn() + " Decorated"
    return wrapper

@generic_decorator
def f():
    return "Hello world"

This can be implemented without decorators, but it will be very syntactically burdensome. The code below implements a generic error handler decorator that can be applied to any robot function and implements a set of behavior if that function encounters an error. In this case, we email a specified email address and log the error to a spreadsheet database.

def robot_error_handler(email_address):
    def decorator(fn):
        def wrapper(*args, **kwargs):
            try:
                return fn(*args, **kwargs)
            except Exception as e:
                print(f"PRANCE Error Handler: {e}")
                print(str(e))
                email_error(recipient=email_address, error=str(e))
                log_error_to_spreadsheet(str(e))
        return wrapper
    return decorator
    

Now, just by writing @prance_error_handler(email_address='stefanmgolas@gmail.com') above a function definition I can encapsulate this function with this generic error handling behavior, for example:

@robot_error_handler(email_address='stefanmgolas@gmail.com')
def robot_function():
    raise ValueError('Testing error handler')

I’ve found this very useful, I hope you do too

5 Likes

As we just discussed in person, this would be wicked useful in combination with Pynopticon:

2 Likes

You two are amazing, thanks for all of this!