TAGS :Viewed: 9 - Published at: a few seconds ago

[ Change message of a caught Python exception (at least on Python 3.x, hopefully on 2.5+ too) ]

Quite similar to the question "Getting the error message of an exception" except that I don't want to get the message out of the exception, I want to SET it.

Until recently, I thought I had a working solution involving changing my_exception.args but i've just reached the limits trying to play with SyntaxError.

A bit of (bad) code to get things ready :

def get_exc(code):
    """Quick & dirty code to get exceptions."""
    try:
        exec(code)
    except:
        return sys.exc_info()
    assert False

Then, getting a NameError exception, printing it, updating it, re-printing it, re-raising it : it seems like it works properly :

code = "foo = bar" # NameError("name 'bar' is not defined",)
error = get_exc(code)
type_, val, bt = error
print("Error", str(error), repr(error))
print("val", str(val), repr(val))
print("args", str(val.args), repr(val.args))
val.args = ("Setting val.args", )
print("Error", str(error), repr(error))
print("val", str(val), repr(val))
raise val

I can see the Setting val.args message in the exception representation, its string conversion and when I raise it.

Trying to do the same with various other types of errors seems to be fine except for SyntaxError. First thing first, the exception has a few more attributes including msg. Let's try to get the exception, print it, update it (both via msg and args), re-print it, re-raising it.

code = "return" # SyntaxError("'return' outside function", ('<string>', 1, 0, None))
error = get_exc(code)
type_, val, bt = error
print("Error", str(error), repr(error))
print("val", str(val), repr(val))
val.args = ("Setting val.args", val.args[1])
val.msg = "Setting val.msg"
print("Error", str(error), repr(error))
print("val", str(val), repr(val))
raise val

repr displays Setting val.args while str and raise display Setting val.msg. How odd!

This leads to a few (quite related) questions :

  • why do we have the same information ("invalid syntax") in two places (args and msg).

  • what is the actual working and recommanded way to update the message ? At the moment, I'm assuming something along the lines of "change args and if there is a msg attribute, change it too" but I do not find this very beautiful nor am I sure that it will work for other types of Exceptions I might have not considered.

Additional reference : I've looked for a solution in PEP 352 - Required Superclass for Exceptions but I didn't find what I needed.

Edit:

To confirm accepted answer : print(val.msg is val.args[0]) # True

Answer 1


.args is an attribute of BaseException, and is usually just passed all of the arguments to the exception.

.msg is the first argument, and is an attribute of SyntaxError. It references the same string as given in .args, if any.

Source link.

what is the actual working and recommanded way to update the message ?

To not do so at all. Most of the time, one should just raise a new, chained exception.

There is also no way to do this for an arbitrary class, since they can have effectively any layout.