How to get Python exception text
Well, I found out how to do it.
Without boost (only error message, because code to extract info from traceback is too heavy to post it here):
PyObject *ptype, *pvalue, *ptraceback;PyErr_Fetch(&ptype, &pvalue, &ptraceback);//pvalue contains error message//ptraceback contains stack snapshot and many other information//(see python traceback structure)//Get error messagechar *pStrErrorMessage = PyString_AsString(pvalue);
And BOOST version
try{//some code that throws an error}catch(error_already_set &){ PyObject *ptype, *pvalue, *ptraceback; PyErr_Fetch(&ptype, &pvalue, &ptraceback); handle<> hType(ptype); object extype(hType); handle<> hTraceback(ptraceback); object traceback(hTraceback); //Extract error message string strErrorMessage = extract<string>(pvalue); //Extract line number (top entry of call stack) // if you want to extract another levels of call stack // also process traceback.attr("tb_next") recurently long lineno = extract<long> (traceback.attr("tb_lineno")); string filename = extract<string>(traceback.attr("tb_frame").attr("f_code").attr("co_filename")); string funcname = extract<string>(traceback.attr("tb_frame").attr("f_code").attr("co_name"));... //cleanup here
This is the most robust method I've been able to come up so far:
try { ... } catch (bp::error_already_set) { if (PyErr_Occurred()) { msg = handle_pyerror(); } py_exception = true; bp::handle_exception(); PyErr_Clear(); } if (py_exception) ....// decode a Python exception into a stringstd::string handle_pyerror(){ using namespace boost::python; using namespace boost; PyObject *exc,*val,*tb; object formatted_list, formatted; PyErr_Fetch(&exc,&val,&tb); handle<> hexc(exc),hval(allow_null(val)),htb(allow_null(tb)); object traceback(import("traceback")); if (!tb) { object format_exception_only(traceback.attr("format_exception_only")); formatted_list = format_exception_only(hexc,hval); } else { object format_exception(traceback.attr("format_exception")); formatted_list = format_exception(hexc,hval,htb); } formatted = str("\n").join(formatted_list); return extract<std::string>(formatted);}
In the Python C API, PyObject_Str
returns a new reference to a Python string object with the string form of the Python object you're passing as the argument -- just like str(o)
in Python code. Note that the exception object does not have "information like line number" -- that's in the traceback object (you can use PyErr_Fetch
to get both the exception object and the traceback object). Don't know what (if anything) Boost provides to make these specific C API functions easier to use, but, worst case, you could always resort to these functions as they are offered in the C API itself.