2018-02-22 21:08:06 +00:00
|
|
|
|
2018-03-02 13:15:53 +00:00
|
|
|
#ifdef CUTTER_ENABLE_JUPYTER
|
|
|
|
|
2018-02-22 21:08:06 +00:00
|
|
|
#include <Python.h>
|
2018-04-30 09:45:02 +00:00
|
|
|
#include <marshal.h>
|
2018-02-22 21:08:06 +00:00
|
|
|
|
|
|
|
#include <QFile>
|
2018-02-23 15:24:19 +00:00
|
|
|
#include <csignal>
|
2018-02-22 21:08:06 +00:00
|
|
|
|
2018-03-04 17:42:02 +00:00
|
|
|
#include "Cutter.h"
|
2018-02-22 21:08:06 +00:00
|
|
|
#include "NestedIPyKernel.h"
|
|
|
|
|
|
|
|
NestedIPyKernel *NestedIPyKernel::start(const QStringList &argv)
|
|
|
|
{
|
|
|
|
PyThreadState *parentThreadState = PyThreadState_Get();
|
|
|
|
|
|
|
|
PyThreadState *threadState = Py_NewInterpreter();
|
2018-03-21 20:32:32 +00:00
|
|
|
if (!threadState) {
|
2018-02-22 21:08:06 +00:00
|
|
|
qWarning() << "Could not create subinterpreter.";
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2018-04-30 09:45:02 +00:00
|
|
|
QFile moduleFile(":/python/cutter_ipykernel.pyc");
|
|
|
|
bool isBytecode = moduleFile.exists();
|
|
|
|
if (!isBytecode) {
|
|
|
|
moduleFile.setFileName(":/python/cutter_ipykernel.py");
|
|
|
|
}
|
2018-02-22 21:08:06 +00:00
|
|
|
moduleFile.open(QIODevice::ReadOnly);
|
|
|
|
QByteArray moduleCode = moduleFile.readAll();
|
|
|
|
moduleFile.close();
|
|
|
|
|
2018-04-30 09:45:02 +00:00
|
|
|
PyObject *moduleCodeObject;
|
|
|
|
if (isBytecode) {
|
|
|
|
moduleCodeObject = PyMarshal_ReadObjectFromString(moduleCode.constData() + 12,
|
|
|
|
moduleCode.size() - 12);
|
|
|
|
} else {
|
|
|
|
moduleCodeObject = Py_CompileString(moduleCode.constData(), "cutter_ipykernel.py",
|
|
|
|
Py_file_input);
|
|
|
|
}
|
2018-03-21 20:32:32 +00:00
|
|
|
if (!moduleCodeObject) {
|
2018-02-22 21:08:06 +00:00
|
|
|
qWarning() << "Could not compile cutter_ipykernel.";
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
auto cutterIPykernelModule = PyImport_ExecCodeModule("cutter_ipykernel", moduleCodeObject);
|
|
|
|
Py_DECREF(moduleCodeObject);
|
2018-03-21 20:32:32 +00:00
|
|
|
if (!cutterIPykernelModule) {
|
2018-02-22 21:08:06 +00:00
|
|
|
qWarning() << "Could not import cutter_ipykernel.";
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto kernel = new NestedIPyKernel(cutterIPykernelModule, argv);
|
|
|
|
|
|
|
|
PyThreadState_Swap(parentThreadState);
|
|
|
|
|
|
|
|
return kernel;
|
|
|
|
}
|
|
|
|
|
|
|
|
NestedIPyKernel::NestedIPyKernel(PyObject *cutterIPykernelModule, const QStringList &argv)
|
|
|
|
{
|
2018-02-23 12:04:53 +00:00
|
|
|
threadState = PyThreadState_Get();
|
|
|
|
|
2018-02-22 21:08:06 +00:00
|
|
|
auto launchFunc = PyObject_GetAttrString(cutterIPykernelModule, "launch_ipykernel");
|
|
|
|
|
|
|
|
PyObject *argvListObject = PyList_New(argv.size());
|
2018-03-21 20:32:32 +00:00
|
|
|
for (int i = 0; i < argv.size(); i++) {
|
2018-02-22 21:08:06 +00:00
|
|
|
QString s = argv[i];
|
2018-03-21 20:32:32 +00:00
|
|
|
PyList_SetItem(argvListObject, i, PyUnicode_DecodeUTF8(s.toUtf8().constData(), s.length(),
|
|
|
|
nullptr));
|
2018-02-22 21:08:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
kernel = PyObject_CallFunction(launchFunc, "O", argvListObject);
|
|
|
|
}
|
|
|
|
|
|
|
|
NestedIPyKernel::~NestedIPyKernel()
|
|
|
|
{
|
2018-02-23 16:42:54 +00:00
|
|
|
auto parentThreadState = PyThreadState_Swap(threadState);
|
|
|
|
auto ret = PyObject_CallMethod(kernel, "cleanup", nullptr);
|
2018-03-21 20:32:32 +00:00
|
|
|
if (!ret) {
|
2018-02-23 16:42:54 +00:00
|
|
|
PyErr_Print();
|
|
|
|
}
|
|
|
|
PyThreadState_Swap(parentThreadState);
|
2018-02-22 21:08:06 +00:00
|
|
|
}
|
|
|
|
|
2018-02-23 12:04:53 +00:00
|
|
|
void NestedIPyKernel::sendSignal(long signum)
|
2018-02-22 21:08:06 +00:00
|
|
|
{
|
|
|
|
auto parentThreadState = PyThreadState_Swap(threadState);
|
2018-02-23 15:24:19 +00:00
|
|
|
auto ret = PyObject_CallMethod(kernel, "send_signal", "l", signum);
|
2018-03-21 20:32:32 +00:00
|
|
|
if (!ret) {
|
2018-02-23 15:24:19 +00:00
|
|
|
PyErr_Print();
|
|
|
|
}
|
2018-02-22 21:08:06 +00:00
|
|
|
PyThreadState_Swap(parentThreadState);
|
|
|
|
}
|
2018-02-23 12:04:53 +00:00
|
|
|
|
|
|
|
QVariant NestedIPyKernel::poll()
|
|
|
|
{
|
|
|
|
QVariant ret;
|
|
|
|
auto parentThreadState = PyThreadState_Swap(threadState);
|
|
|
|
PyObject *pyRet = PyObject_CallMethod(kernel, "poll", nullptr);
|
2018-03-21 20:32:32 +00:00
|
|
|
if (pyRet) {
|
|
|
|
if (PyLong_Check(pyRet)) {
|
2018-02-23 15:24:19 +00:00
|
|
|
ret = (qlonglong)PyLong_AsLong(pyRet);
|
|
|
|
}
|
2018-03-21 20:32:32 +00:00
|
|
|
} else {
|
2018-02-23 15:24:19 +00:00
|
|
|
PyErr_Print();
|
2018-02-23 12:04:53 +00:00
|
|
|
}
|
|
|
|
PyThreadState_Swap(parentThreadState);
|
|
|
|
return ret;
|
2018-03-02 13:15:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|