未生成 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 异常回溯的主要内容,如果未能解决你的问题,请参考以下文章

python 这意味着无论何时引发未捕获的异常,我都会立即得知发生了什么(完全回溯)。

生成随机迷宫--深度优先(递归回溯)算法

Python生成器回溯和八皇后问题

来自未处理异常的 C++ 堆栈跟踪?

如何生成未处理的 MFC 异常?

如何将 Cython 生成的模块从 python 导入 C/C++ 主文件? (用 C/C++ 编程)[关闭]