Reputation: 13
I'm using a new Python/C API PyErr_GetRaisedException added in 3.12 version to retrieve exception and then using other Python/C APIs to get exception type, value, and traceback details.
Then I'm calling "format_exception" function from traceback module to get error call stack. But this function call throws exception
Is the exception returned by PyErr_GetRaisedException normalized??
Also, I looked at PyErr_NormalizeException API but it is deprecated in 3.12. Is there any other API to normalize exception?
PyObject* pException = PyErr_GetRaisedException();
if (pException) {
pExceptionType = PyObject_Type(pException);
pValue = PyException_GetArgs(pException);
pTraceback = PyException_GetTraceback(pException);
}
PyObject* module_name = PyString_FromString("traceback");
PyObject* pyth_module = PyImport_Import(module_name);
PyObject* pyth_func = PyObject_GetAttrString(pyth_module, "format_exception");
if (pyth_func && PyCallable_Check(pyth_func)) {
PyObject* pyArgsTuple = PyTuple_New(3);
PyTuple_SetItem(pyArgsTuple, 0, pType);
PyTuple_SetItem(pyArgsTuple, 1, pValue);
PyTuple_SetItem(pyArgsTuple, 2, pTraceback);
PyObject* pyth_val = PyObject_CallObject(pyth_func, pyArgsTuple);
PyObject* pystr = PyObject_Str(pyth_val);
char* traceBackCStr = PyString_AsString(pystr);
}
Upvotes: 0
Views: 108
Reputation: 70693
Yes, the exception is normalized, because it can't be denormalized.
Background: The (also deprecated) function PyErr_Fetch
returns three separate values: type
, value
, traceback
. It does not guarantee that the type
is actually the type of value
. PyErr_NormalizeException
fixes that.
Since PyErr_GetRaisedException
only returns the value
, there is no place for there to be an inconsistency. PyObject_Type
always returns the correct type of value
.
Historical Background (note: this is only inferred from the source code history)
In the past, PyErr_SetObject(PyObject *type, PyObject *value)
directly set type and value and didn't care whether value
was actually an instance of type
. This was used deliberately to set an exception type and a string as a value. No exception object was actually constructed at this point. I assume this was a performance optimization.
Nowadays, PyErr_SetObject
already costructs/normalizes the exception before setting it.
Upvotes: 0