如何获取Python异常文本
我想在我的C++应用程序中嵌入Python。现在我在使用Boost库,这个工具非常棒。但我遇到了一个问题。
如果Python函数抛出异常,我想捕获这个异常,并在我的应用程序中打印出错误信息,或者获取一些详细的信息,比如导致错误的Python脚本中的行号。
我该怎么做呢?我在Python的API或者Boost中找不到获取详细异常信息的函数。
try {
module=import("MyModule"); //this line will throw excetion if MyModule contains an error
} catch ( error_already_set const & ) {
//Here i can said that i have error, but i cant determine what caused an error
std::cout << "error!" << std::endl;
}
PyErr_Print()只是把错误文本打印到标准错误输出,并且清除了错误,所以这不是解决方案。
5 个回答
7
在Python的C接口中,PyObject_Str
这个函数会返回一个新的引用,指向一个Python字符串对象,这个字符串是你传入的Python对象的字符串形式——就像在Python代码中用str(o)
一样。需要注意的是,异常对象并没有“像行号这样的信息”——这些信息在traceback对象中(你可以使用PyErr_Fetch
来获取异常对象和traceback对象)。我不太清楚Boost提供了什么来让这些特定的C接口函数更容易使用,但最坏的情况是,你可以直接使用C接口中提供的这些函数。
24
这是我目前想到的最稳妥的方法:
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 string
std::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);
}
65
好吧,我找到了怎么做的方法。
不使用boost的情况下(这里只能给出错误信息,因为提取错误信息的代码太长,没法在这里贴出来):
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 message
char *pStrErrorMessage = PyString_AsString(pvalue);
还有使用BOOST的版本
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