C/C++ 未生成 Python 异常回溯

C/C++ Python exception traceback not being generated

本文关键字:Python 异常 回溯 未生 C++      更新时间:2023-10-16

我最近升级了一个我正在做的C++项目,它嵌入了python,从Python 3.4.3到Python 3.5.2(它是一个构建为32位或64位的可执行文件,并且在两个版本中具有相同的行为)。

我正在创建自己的异常:

static PyObject* MyException_type_obj = 0;
void setup(PyObject* module){
MyException_type_obj = PyErr_NewException("my_module.MyException", NULL, NULL);
PyObject* dict = PyModule_GetDict(module);
PyDict_SetItemString(dict, "MyException", MyException_type_obj);
}

然后在一些由python代码调用的C++代码中提出它:

static PyObject* RaiseIt(PyObject* self, PyObject* args)
{
PyErr_Format(Forever_Exception_type_obj, "Exit Requested");
return 0;
}

目前为止,一切都好。如果我在 python 中捕获它,一切都很好:

try:
my_module.raise_it()
except my_module.MyException:
import sys, traceback
exc_type, exc_value, exc_tb = sys.exc_info()
print(traceback.format_exception(exc_type, exc_value, exc_tb)

将正确的回溯打印到命令行。

但是,当我尝试在C++/Python中使用PyErr_Fetch做类似的事情时:

std::string get_traceback(){
PyObject* type;
PyObject* value;
PyObject* traceback;
PyErr_Fetch(&type, &value, &traceback);
std::string fcn = "";
fcn += "def get_pretty_traceback(exc_type, exc_value, exc_tb):n";
fcn += "    import sys, tracebackn";
fcn += "    lines = []n"; 
fcn += "    lines = traceback.format_exception(exc_type, exc_value, exc_tb)n";
fcn += "    output = '\n'.join(lines)n";
fcn += "    return outputn";
PyRun_SimpleString(fcn.c_str());
PyObject* mod = PyImport_ImportModule("__main__");
PyObject* method = PyObject_GetAttrString(mod, "get_pretty_traceback");
PyObject* outStr = PyObject_CallObject(method, Py_BuildValue("OOO", type, value, traceback));
std::string pretty = PyBytes_AsString(PyUnicode_AsASCIIString(outStr));
Py_DECREF(method);
Py_DECREF(outStr);
return pretty;
}

它崩溃了,我得到一个空outStr.

获取一些其他详细信息

fcn += "    lines = []n"; 
fcn += "    try:n";
fcn += "        lines = traceback.format_exception(exc_type, exc_value, exc_tb)n";
fcn += "    except Exception as e:n";
fcn += "        print('Exception while rendering a python exception for C')n";
fcn += "        print(e)n";
fcn += "    output = '\n'.join(lines)n";

给我神秘的错误消息:

'str' object has no attribute '__cause__'

顺便说一句,这在python 2.7中也不会发生(有与字符串相关的微小更改)。它只在 python 3.5 中为我服务。

同样的 C++ get_traceback() 函数适用于在 python 中启动的异常,但不适用于C++异常。

显然,在我的PyErr_Fetch调用之后立即需要PyErr_NormalizeException,这会将值从字符串转换为异常对象的实例。

PyObject* type;
PyObject* value;
PyObject* traceback;
PyErr_Fetch(&type, &value, &traceback);
PyErr_NormalizeException(&type, &value, &traceback); // Added line
...

修复了此问题。我不知道为什么来自 C++ 生成的异常的值与来自 python 的异常的值会更改该值,但这会处理它。