How can I add context to an exception in Python

exception, python

Solution

The first item in `ex.args` is always the message -- if there is any. (Note for some exceptions, such as the one raised by `assert False`, `ex.args` is an empty tuple.)

I don't know of a cleaner way to modify the message than reassigning a new tuple to `ex.args`. (We can't modify the tuple since tuples are immutable).

The code below is similar to yours, except it constructs the tuple without using an intermediate list, it handles the case when `ex.args` is empty, and to make the code more readable, it hides the boilerplate inside a context manager:

import contextlib

def process(val):
    with context(val):
        do_something(val)

def do_something(val):
    # assert False
    return 1/val

@contextlib.contextmanager
def context(msg):
    try:
        yield
    except Exception as ex:
        msg = '{}: {}'.format(msg, ex.args[0]) if ex.args else str(msg)
        ex.args = (msg,) + ex.args[1:]
        raise

process(0)

yields a stack trace with this as the final message:

ZeroDivisionError: 0: division by zero

Problem

I would like to add context to an exception like this: ``` def process(vals): for key in vals: try: do_something(vals[key]) except Exception as ex: # base class. Not sure what to expect. raise # with context regarding the key that was being processed. ``` I found a way that is uncharacteristically long winded for Python. Is there a better way than this? ``` try: do_something(vals[key]) except Exception as ex: args = list(ex.args) if len(args) > 1: args[0] = "{}: {}".format(key, args[0]) ex.args = tuple(args) raise # Will re-trhow ValueError with new args[0] ```

Original source