Example #1
0
/**
 * Convert a python error state to a C++ exception
 * @param withTrace If true then a traceback will be included in the exception
 * message
 * @throws std::runtime_error
 */
void throwRuntimeError(const bool withTrace) {
  GlobalInterpreterLock gil;
  if (!PyErr_Occurred()) {
    throw std::runtime_error(
        "ErrorHandling::throwRuntimeError - No Python error state set!");
  }
  PyObject *exception(nullptr), *value(nullptr), *traceback(nullptr);
  PyErr_Fetch(&exception, &value, &traceback);
  PyErr_NormalizeException(&exception, &value, &traceback);
  PyErr_Clear();
  PyObject *str_repr = PyObject_Str(value);
  std::stringstream msg;
  if (value && str_repr) {
    msg << PyString_AsString(str_repr);
  } else {
    msg << "Unknown exception has occurred.";
  }
  if (withTrace) {
    tracebackToMsg(msg, reinterpret_cast<PyTracebackObject *>(traceback));
  }

  // Ensure we decrement the reference count on the traceback and exception
  // objects as they hold references to local the stack variables that were
  // present when the exception was raised. This could include child algorithms
  // with workspaces stored that would not otherwise be cleaned up until the
  // program exited.
  Py_XDECREF(traceback);
  Py_XDECREF(exception);
  Py_XDECREF(value);
  // Raise this error as a C++ error
  throw std::runtime_error(msg.str());
}
Example #2
0
/**
 * Form a traceback
 * @param msg The reference to the textstream to accumulate the message
 * @param traceback A traceback object
 * @param root If true then this is the root of the traceback
 */
void PythonScript::tracebackToMsg(QTextStream &msgStream,
                                  PyTracebackObject *traceback, bool root) {
  if (traceback == nullptr)
    return;
  msgStream << "\n  ";
  if (root)
    msgStream << "at";
  else
    msgStream << "caused by";

  int lineno = traceback->tb_lineno;
  QString filename =
      QString::fromAscii(TO_CSTRING(traceback->tb_frame->f_code->co_filename));
  if (filename == identifier().c_str()) {
    lineno = getRealLineNo(lineno);
    sendLineChangeSignal(lineno, true);
  }

  msgStream << " line " << lineno << " in \'" << filename << "\'";
  tracebackToMsg(msgStream, traceback->tb_next, false);
}
Example #3
0
/**
 * This emits the error signal and resets the error state
 * of the python interpreter.
 */
void PythonScript::emit_error() {
  // gil is necessary so other things don't continue
  ScopedPythonGIL lock;

  // return early if nothing happened
  if (!PyErr_Occurred()) {
    emit finished(MSG_FINISHED);
    return;
  }
  // get the error information out
  PyObject *exception(nullptr), *value(nullptr), *traceback(nullptr);
  PyErr_Fetch(&exception, &value, &traceback);

  // special check for system exceptions
  if (bool(exception) &&
      PyErr_GivenExceptionMatches(exception, PyExc_SystemExit) &&
      PyObject_HasAttrString(exception, "code")) {
    // value is the return code handed to sys.exit
    long code = 0;
    if (bool(value) && INT_CHECK(value)) {
      code = TO_LONG(value);
    }

    // if we are returning 0 then cleanup and return
    if (code == 0) {
      // maybe shouldn't clear the error, but for now this
      // is the agreed upon behavior
      PyErr_Clear();
      Py_XDECREF(traceback);
      Py_XDECREF(exception);
      Py_XDECREF(value);
      emit finished(MSG_FINISHED);
      return;
    }
  }

  // prework on the exception handling
  PyErr_NormalizeException(&exception, &value, &traceback);
  PyErr_Clear();

  // convert the traceback into something useful
  int lineNumber = 0;
  QString filename;
  if (traceback) {
    PyTracebackObject *tb = (PyTracebackObject *)traceback;
    lineNumber = tb->tb_lineno;
    filename = TO_CSTRING(tb->tb_frame->f_code->co_filename);
  }

  // the error message is the full (formated) traceback
  PyObject *str_repr = PyObject_Str(value);
  QString message;
  QTextStream msgStream(&message);
  if (value && str_repr) {
    if (exception == PyExc_SyntaxError) {
      msgStream << constructSyntaxErrorStr(value);
    } else {
      QString excTypeName(
          value->ob_type
              ->tp_name); // This is fully qualified with the module name
      excTypeName = excTypeName.section(".", -1);
      msgStream << excTypeName << ": " << TO_CSTRING(str_repr);
    }

  } else {
    msgStream << "Unknown exception has occurred.";
  }
  tracebackToMsg(msgStream, (PyTracebackObject *)(traceback));
  msgStream << "\n";

  Py_XDECREF(traceback);
  Py_XDECREF(exception);
  Py_XDECREF(value);

  emit error(msgStream.readAll(), filename, lineNumber);
}