// This is a rudimentary way to get some 'debug' information // when a script goes awry. I put this code in my ScriptManager // class. I *called* it if the module_object returned from // PyImport_ExecCodeModule returns NULL (for me this was on // line 56 of ScriptManager.cpp). I dumped the return value // of this string to the log (using LL_SCRIPT log-level) std::string ssurge::ScriptManager::getErrorString() { PyObject * ptype, *pvalue; PyObject *ptrace; std::string s = ""; PyErr_Fetch(&ptype, &pvalue, &ptrace); if (ptype != NULL) { PyObject * temps = PyObject_Str(ptype); char * tempcstr = PyUnicode_AsUTF8(temps); s += "ptype = " + std::string(tempcstr) + "\n"; Py_DECREF(temps); } if (pvalue != NULL) { PyObject * temps = PyObject_Str(pvalue); char * tempcstr = PyUnicode_AsUTF8(temps); s += "pvalue = " + std::string(tempcstr) + "\n"; Py_DECREF(temps); } if (ptrace != NULL) { s += "ptrace =\n"; // The traceback object is more complex than the others: it's a linked-list // of "frames". Each frame is a context (e.g. A called B, who called C would generate // a linked list of A -> B -> C). Each frame has info about the filename, line#, etc. // Reference: http://stackoverflow.com/questions/1796510/accessing-a-python-traceback-from-the-c-api PyFrameObject * cur_frame; std::stringstream ss; PyTracebackObject * pactual_trace = (PyTracebackObject*)ptrace; while (pactual_trace != NULL) { cur_frame = pactual_trace->tb_frame; unsigned int frame_num = 0; char * fname = PyUnicode_AsUTF8(cur_frame->f_code->co_filename); int line = PyFrame_GetLineNumber(cur_frame); ss << "frame" << frame_num << ": " << fname << "@" << line << "\n"; frame_num++; //cur_frame = cur_frame->f_back; pactual_trace = pactual_trace->tb_next; } s += ss.str() + "\n"; } return s; }