mirror of
https://github.com/ModOrganizer2/modorganizer-plugin_python.git
synced 2026-07-27 14:03:33 -07:00
Merge pull request #27 from AnyOldName3/message-forwarding
Message forwarding
This commit is contained in:
+47
-8
@@ -1,8 +1,9 @@
|
||||
#ifndef Q_MOC_RUN
|
||||
#include <boost/python.hpp>
|
||||
#endif
|
||||
#include <QString>
|
||||
#include <utility.h>
|
||||
#include <QDebug>
|
||||
#include "error.h"
|
||||
|
||||
using namespace MOBase;
|
||||
namespace bpy = boost::python;
|
||||
@@ -10,17 +11,55 @@ namespace bpy = boost::python;
|
||||
void reportPythonError()
|
||||
{
|
||||
if (PyErr_Occurred()) {
|
||||
// prints to s_ErrIO buffer
|
||||
ErrWrapper &errWrapper = ErrWrapper::instance();
|
||||
|
||||
errWrapper.startRecordingExceptionMessage();
|
||||
PyErr_Print();
|
||||
// extract data from python buffer
|
||||
bpy::object mainModule = bpy::import("__main__");
|
||||
bpy::object mainNamespace = mainModule.attr("__dict__");
|
||||
bpy::object errMsgObj = bpy::eval("s_ErrIO.getvalue()", mainNamespace);
|
||||
QString errMsg = bpy::extract<QString>(errMsgObj.ptr());
|
||||
bpy::eval("s_ErrIO.truncate(0)", mainNamespace);
|
||||
errWrapper.stopRecordingExceptionMessage();
|
||||
|
||||
QString errMsg = errWrapper.getLastExceptionMessage();
|
||||
|
||||
throw MyException(errMsg);
|
||||
} else {
|
||||
throw MyException("An unexpected C++ exception was thrown in python code");
|
||||
}
|
||||
}
|
||||
|
||||
ErrWrapper & ErrWrapper::instance()
|
||||
{
|
||||
static ErrWrapper err;
|
||||
return err;
|
||||
}
|
||||
|
||||
void ErrWrapper::write(const char * message)
|
||||
{
|
||||
buffer << message;
|
||||
if (buffer.tellp() != 0 && buffer.str().back() == '\n')
|
||||
{
|
||||
// actually put the string in a variable so it doesn't get destroyed as soon as we get a pointer to its data
|
||||
std::string string = buffer.str().substr(0, buffer.str().length() - 1);
|
||||
qCritical().nospace().noquote() << string.c_str();
|
||||
buffer = std::stringstream();
|
||||
}
|
||||
|
||||
if (recordingExceptionMessage)
|
||||
{
|
||||
lastException << message;
|
||||
}
|
||||
}
|
||||
|
||||
void ErrWrapper::startRecordingExceptionMessage()
|
||||
{
|
||||
recordingExceptionMessage = true;
|
||||
lastException = std::stringstream();
|
||||
}
|
||||
|
||||
void ErrWrapper::stopRecordingExceptionMessage()
|
||||
{
|
||||
recordingExceptionMessage = false;
|
||||
}
|
||||
|
||||
QString ErrWrapper::getLastExceptionMessage()
|
||||
{
|
||||
return QString::fromStdString(lastException.str());
|
||||
}
|
||||
|
||||
@@ -1,7 +1,26 @@
|
||||
#ifndef ERROR_H
|
||||
#define ERROR_H
|
||||
#include <QString>
|
||||
#include <sstream>
|
||||
|
||||
// turn an error from the python interpreter into an exception
|
||||
void reportPythonError();
|
||||
|
||||
struct ErrWrapper
|
||||
{
|
||||
static ErrWrapper & instance();
|
||||
|
||||
void write(const char * message);
|
||||
|
||||
void startRecordingExceptionMessage();
|
||||
|
||||
void stopRecordingExceptionMessage();
|
||||
|
||||
QString getLastExceptionMessage();
|
||||
|
||||
std::stringstream buffer;
|
||||
bool recordingExceptionMessage;
|
||||
std::stringstream lastException;
|
||||
};
|
||||
|
||||
#endif // ERROR_H
|
||||
|
||||
@@ -1299,6 +1299,36 @@ PythonRunner::PythonRunner(const MOBase::IOrganizer *moInfo)
|
||||
|
||||
static const char *argv0 = "ModOrganizer.exe";
|
||||
|
||||
struct PrintWrapper
|
||||
{
|
||||
void write(const char * message)
|
||||
{
|
||||
buffer << message;
|
||||
if (buffer.tellp() != 0 && buffer.str().back() == '\n')
|
||||
{
|
||||
// actually put the string in a variable so it doesn't get destroyed as soon as we get a pointer to its data
|
||||
std::string string = buffer.str().substr(0, buffer.str().length() - 1);
|
||||
qDebug().nospace().noquote() << string.c_str();
|
||||
buffer = std::stringstream();
|
||||
}
|
||||
}
|
||||
|
||||
std::stringstream buffer;
|
||||
};
|
||||
|
||||
// ErrWrapper is in error.h
|
||||
|
||||
BOOST_PYTHON_MODULE(moprivate)
|
||||
{
|
||||
bpy::class_<PrintWrapper, boost::noncopyable>("PrintWrapper", bpy::init<>())
|
||||
.def("write", &PrintWrapper::write);
|
||||
bpy::class_<ErrWrapper, boost::noncopyable>("ErrWrapper", bpy::init<>())
|
||||
.def("instance", &ErrWrapper::instance, bpy::return_value_policy<bpy::reference_existing_object>()).staticmethod("instance")
|
||||
.def("write", &ErrWrapper::write)
|
||||
.def("startRecordingExceptionMessage", &ErrWrapper::startRecordingExceptionMessage)
|
||||
.def("stopRecordingExceptionMessage", &ErrWrapper::stopRecordingExceptionMessage)
|
||||
.def("getLastExceptionMessage", &ErrWrapper::getLastExceptionMessage);
|
||||
}
|
||||
|
||||
bool PythonRunner::initPython(const QString &pythonPath)
|
||||
{
|
||||
@@ -1317,6 +1347,7 @@ bool PythonRunner::initPython(const QString &pythonPath)
|
||||
|
||||
Py_SetProgramName(argBuffer);
|
||||
PyImport_AppendInittab("mobase", &PyInit_mobase);
|
||||
PyImport_AppendInittab("moprivate", &PyInit_moprivate);
|
||||
Py_OptimizeFlag = 2;
|
||||
Py_NoSiteFlag = 1;
|
||||
initPath();
|
||||
@@ -1331,11 +1362,13 @@ bool PythonRunner::initPython(const QString &pythonPath)
|
||||
bpy::object mainModule = bpy::import("__main__");
|
||||
bpy::object mainNamespace = mainModule.attr("__dict__");
|
||||
mainNamespace["sys"] = bpy::import("sys");
|
||||
mainNamespace["moprivate"] = bpy::import("moprivate");
|
||||
bpy::import("site");
|
||||
mainNamespace["io"] = bpy::import("io");
|
||||
bpy::exec("s_ErrIO = io.StringIO()\n"
|
||||
"sys.stderr = s_ErrIO",
|
||||
bpy::exec("sys.stdout = moprivate.PrintWrapper()\n"
|
||||
"sys.stderr = moprivate.ErrWrapper.instance()\n"
|
||||
"sys.excepthook = lambda x, y, z: sys.__excepthook__(x, y, z)\n",
|
||||
mainNamespace);
|
||||
|
||||
return true;
|
||||
} catch (const bpy::error_already_set&) {
|
||||
qDebug("failed to init python");
|
||||
|
||||
Reference in New Issue
Block a user