- BT_ASSERT(PyErr_Occurred() != NULL);
- PyErr_Fetch(&type, &value, &traceback);
- BT_ASSERT(type != NULL);
+ BT_ASSERT(py_exc_tb);
+
+ /*
+ * Import the standard `traceback` module which contains the
+ * functions to format a traceback.
+ */
+ traceback_module = PyImport_ImportModule("traceback");
+ if (!traceback_module) {
+ BT_LOGE_STR("Failed to import `traceback` module.");
+ goto error;
+ }
+
+ format_tb_func = PyObject_GetAttrString(traceback_module,
+ "format_tb");
+ if (!format_tb_func) {
+ BT_LOGE("Cannot find `format_tb` attribute in `traceback` module.");
+ goto error;
+ }
+
+ if (!PyCallable_Check(format_tb_func)) {
+ BT_LOGE("`traceback.format_tb` attribute is not callable.");
+ goto error;
+ }
+
+ /*
+ * If we are calling format_exception_only, `py_exc_tb` is NULL, so the
+ * effective argument list is of length 2.
+ */
+ exc_str_list = PyObject_CallFunctionObjArgs(
+ format_tb_func, py_exc_tb, NULL);
+ if (!exc_str_list) {
+ if (BT_LOG_ON_ERROR) {
+ BT_LOGE("Failed to call `traceback.format_tb` function:");
+ PyErr_Print();
+ }
+
+ goto error;
+ }
+
+ msg_buf = py_str_list_to_gstring(exc_str_list, log_level);
+ if (!msg_buf) {
+ goto error;
+ }
+
+ goto end;
+
+error:
+ if (msg_buf) {
+ g_string_free(msg_buf, TRUE);
+ msg_buf = NULL;
+ }
+
+end:
+ Py_XDECREF(traceback_module);
+ Py_XDECREF(format_tb_func);
+ Py_XDECREF(exc_str_list);