Paul T.
Paul T.

Reputation: 329

getting the exception class name in python?

I want to generate a string in an exception handler that contains the name of the exception, and any arguments passed...oretty much the final output that one gets with Traceback.

For example, if raise bar.FnordError("message") is called, in the exception handler, I want to produce the string: "bar.FnordError: message"

I want it to work for built in exceptions, as well as exceptions in the current and other modules. This is what I came up with, but it doesn't seem very pythonic.

def this_is_lame(err):
    if type(err).__module__ in ['__main__', 'builtins']:
        return "{}: {}".format(type(err).__name__, err)
    else:
        return "{}.{}: {}".format(type(err).__module__, type(err).__name__, err)

I've dug through the BaseException C code in python, and the Traceback standard library. I seem to be missing the correct "nice" accessor.

Is BaseException.__format__ documented anywhere? Are there escapes for it?

I've played around in the interpreter and nothing quite gives me what I want.

import sys
import traceback

import bar

try:
    raise bar.FnordError("message")
except Exception as err:
    print(type(err))
    print(repr(err))
    print(type(err).__module__)
    print(type(err).__name__)
    print(err)
    print("this is what I want: '{}'".format(this_is_lame(err)))

print()

try:
    raise ValueError("message")
except Exception as err:
    print(type(err))
    print(repr(err))
    print(type(err).__module__)
    print(type(err).__name__)
    print("this is what I want: '{}'".format(this_is_lame(err)))

which produces:

$ python foo.py
<class 'bar.FnordError'>
FnordError('message',)
bar
FnordError
message
this is what I want: 'bar.FnordError: message'

<class 'ValueError'>
ValueError('message',)
builtins
ValueError
this is what I want: 'ValueError: message'

Upvotes: 5

Views: 3984

Answers (1)

user2357112
user2357112

Reputation: 281843

There's no "nice" accessor. Python itself does something pretty similar to what you're doing in the default sys.excepthook, although exceptions defined in __main__ print as __main__.WhateverException.

If you want to see how Python itself does it, on Python 2, the check happens in PyErr_Display, which checks strcmp(modstr, "exceptions"):

moduleName = PyObject_GetAttrString(exception, "__module__");
if (moduleName == NULL)
    err = PyFile_WriteString("<unknown>", f);
else {
    char* modstr = PyString_AsString(moduleName);
    if (modstr && strcmp(modstr, "exceptions"))
    {
        err = PyFile_WriteString(modstr, f);
        err += PyFile_WriteString(".", f);
    }
    Py_DECREF(moduleName);
}

On Python 3, print_exception checks _PyUnicode_CompareWithId(moduleName, &PyId_builtins).

moduleName = _PyObject_GetAttrId(type, &PyId___module__);
if (moduleName == NULL || !PyUnicode_Check(moduleName))
{
    Py_XDECREF(moduleName);
    err = PyFile_WriteString("<unknown>", f);
}
else {
    if (_PyUnicode_CompareWithId(moduleName, &PyId_builtins) != 0)
    {
        err = PyFile_WriteObject(moduleName, f, Py_PRINT_RAW);
        err += PyFile_WriteString(".", f);
    }
    Py_DECREF(moduleName);
}

Upvotes: 2

Related Questions