This is becoming utterly painful process.... I found out that the return value from "format_exception" function is NOT a list, i.e. PyList_Check() fails. PySequence_Check() succeeds but then PySequence_List() gives me back -1. So wtf?
I must say the API is crap on this part. Im trying to get error information regarding previous error and if all i get back is another error indicator, then what am I supposed to do? Recursive error handling? Sounds like da bomb! The API should have two levels of error handling. First level should expose a conventional error code mechanism for checking for bad params etc. Only if the error code says that there was a python error during evaluation/compilation should one need to use this mechanism. Just my two cents. Thanks for help. void get_python_error_info(string& info) { GIL g; PyObject* type = NULL; PyObject* value = NULL; PyObject* trace = NULL; PyErr_Fetch(&type, &value, &trace); py_ref ref_type(type); py_ref ref_value(value); py_ref ref_trace(trace); py_ref name(PyString_FromString("traceback")); py_ref module(PyImport_Import(name.get())); if (!module) { PyErr_Clear(); return; } PyObject* list = NULL; if (trace) { py_ref fun(PyObject_GetAttrString(module.get(), "format_exception")); if (fun) list = PyObject_CallFunctionObjArgs(type, value, trace, NULL); PyErr_Clear(); } else { py_ref fun(PyObject_GetAttrString(module.get(), "format_exception_only")); if (fun) list = PyObject_CallFunctionObjArgs(type, value, NULL); PyErr_Clear(); } if (list && PySequence_Check(list)) { Py_ssize_t len = PySequence_Size(list); for (Py_ssize_t i=0; i<len; ++i) { // bla bla } } Py_XDECREF(list); PyErr_Clear(); } > Hello group, > > I'm trying to get the Python exception information (message and > traceback) > stored into a string in my C++ code. However all i get back is the string > "None". This is what you get (actually "None\n") when there is no error set. > All the checks pass and all pointers get a value from the python > API calls. I've also tried with a different function such as > PyObject_CallFunctionObjArgs but the result is the same. Since you already know the three components (type, value, trace), I'd use traceback.format_exception instead (and remove the PyErr_Restore call - I'm unsure if it works the way you expect it). In this case you have to pass three arguments, so yes, use PyObject_CallFunctionObjArgs (remember the final NULL). Beware: format_exception returns a formatted list, not a string. You have to concatenate all the elements (either using ''.join or repeteadly calling PyString_Concat) > void get_python_exception(string& message, string& traceback) > { > GIL g; > PyObject* type = NULL; > PyObject* value = NULL; > PyObject* trace = NULL; > PyErr_Fetch(&type, &value, &trace); > py_ref ref_type(type); > py_ref ref_value(value); > py_ref ref_trace(trace); > py_ref name(PyString_FromString("traceback")); > py_ref module(PyImport_Import(name.get())); > if (module) > { > py_ref fun(PyObject_GetAttrString(module.get(), "format_exc")); > if (fun) > { > PyErr_Restore(type, value, trace); > ref_type.release(); > ref_value.release(); > ref_trace.release(); > py_ref ret(PyObject_CallObject(fun.get(), NULL)); > if (ret && PyString_Check(ret.get())) > { > char* str = PyString_AsString(ret.get()); > message = str; > traceback = "traceback not available"; > return; > } > } > } > message = "message not available"; > traceback = "traceback not available"; > } -- Gabriel Genellina -- http://mail.python.org/mailman/listinfo/python-list