2016-12-21 120 views
1

我最近將一個正在處理的C++項目升級到Python 3.5.2(它是一個可執行文件,其編譯爲32位或64位) ,並且在兩個版本中具有相同的行爲)。C/C++ Python異常回溯未生成

我創造我自己的異常:

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; 
} 

到目前爲止,一切都很好。如果我用蟒蛇抓住它,一切都很好:

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) 

打印正確的tracback到命令行。

然而,當我嘗試,我用PyErr_Fetch做在C++/Python的類似的事情:

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++中的異常。

回答

2

顯然PyErr_NormalizeException是在我的PyErr_Fetch調用後立即需要的,該調用將字符串的值轉換爲異常對象的實例。

PyObject* type; 
PyObject* value; 
PyObject* traceback; 

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

... 

解決了這個問題。我不知道爲什麼從C++生成的異常產生的值與來自python的異常產生的值改變了值,但是這會照顧它。