未生成 C/C++ Python 异常回溯
Posted
技术标签:
【中文标题】未生成 C/C++ Python 异常回溯【英文标题】:C/C++ Python exception traceback not being generated 【发布时间】:2016-12-21 16:59:33 【问题描述】:我最近将我正在处理的一个嵌入 python 的 C++ 项目从 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, traceback\n";
fcn += " lines = []\n";
fcn += " lines = traceback.format_exception(exc_type, exc_value, exc_tb)\n";
fcn += " output = '\\n'.join(lines)\n";
fcn += " return output\n";
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++ 的异常。
【问题讨论】:
【参考方案1】:显然在我的PyErr_Fetch
调用之后立即需要PyErr_NormalizeException
,它将值从字符串转换为异常对象的实例。
PyObject* type;
PyObject* value;
PyObject* traceback;
PyErr_Fetch(&type, &value, &traceback);
PyErr_NormalizeException(&type, &value, &traceback); // Added line
...
解决了这个问题。我不知道为什么来自 C++ 中生成的异常的值与来自 python 的异常值会改变值,但这会解决它。
【讨论】:
以上是关于未生成 C/C++ Python 异常回溯的主要内容,如果未能解决你的问题,请参考以下文章