mirror of
https://github.com/rizinorg/cutter.git
synced 2025-01-19 10:58:51 +00:00
Prepare IPyKernel communication
This commit is contained in:
parent
05be34ae6b
commit
926a9ffd1e
@ -102,7 +102,8 @@ SOURCES += \
|
|||||||
CutterApplication.cpp \
|
CutterApplication.cpp \
|
||||||
utils/JupyterConnection.cpp \
|
utils/JupyterConnection.cpp \
|
||||||
widgets/JupyterWidget.cpp \
|
widgets/JupyterWidget.cpp \
|
||||||
utils/PythonAPI.cpp
|
utils/PythonAPI.cpp \
|
||||||
|
utils/NestedIPyKernel.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
cutter.h \
|
cutter.h \
|
||||||
@ -166,7 +167,8 @@ HEADERS += \
|
|||||||
widgets/VTablesWidget.h \
|
widgets/VTablesWidget.h \
|
||||||
utils/JupyterConnection.h \
|
utils/JupyterConnection.h \
|
||||||
widgets/JupyterWidget.h \
|
widgets/JupyterWidget.h \
|
||||||
utils/PythonAPI.h
|
utils/PythonAPI.h \
|
||||||
|
utils/NestedIPyKernel.h
|
||||||
|
|
||||||
FORMS += \
|
FORMS += \
|
||||||
dialogs/AboutDialog.ui \
|
dialogs/AboutDialog.ui \
|
||||||
|
@ -7,6 +7,9 @@ from ipykernel.ipkernel import IPythonKernel
|
|||||||
|
|
||||||
# TODO: Make this behave like a Popen instance and pipe it to IPyKernelInterfaceJupyter!
|
# TODO: Make this behave like a Popen instance and pipe it to IPyKernelInterfaceJupyter!
|
||||||
class IPyKernelInterfaceKernel:
|
class IPyKernelInterfaceKernel:
|
||||||
|
def kill(self):
|
||||||
|
print("No!! Not into the pit! It burns!!!")
|
||||||
|
|
||||||
def poll(self):
|
def poll(self):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -5,6 +5,12 @@ from notebook.notebookapp import *
|
|||||||
|
|
||||||
# TODO: this must behave like a Popen instance and pipe to IPyKernelInterfaceKernel!
|
# TODO: this must behave like a Popen instance and pipe to IPyKernelInterfaceKernel!
|
||||||
class IPyKernelInterfaceJupyter:
|
class IPyKernelInterfaceJupyter:
|
||||||
|
def __init__(self, id):
|
||||||
|
self._id = id
|
||||||
|
|
||||||
|
def kill(self):
|
||||||
|
print("DIE!! " + str(self._id))
|
||||||
|
|
||||||
def poll(self):
|
def poll(self):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -45,8 +51,8 @@ class CutterInternalIPyKernelManager(IOLoopKernelManager):
|
|||||||
|
|
||||||
# TODO: kernel_cmd including python executable and so on is currently used for argv. Make a clean version!
|
# TODO: kernel_cmd including python executable and so on is currently used for argv. Make a clean version!
|
||||||
import cutter_internal
|
import cutter_internal
|
||||||
cutter_internal.launch_ipykernel(kernel_cmd, env=env, **kw)
|
id = cutter_internal.launch_ipykernel(kernel_cmd, env=env, **kw)
|
||||||
self.kernel = IPyKernelInterfaceJupyter()
|
self.kernel = IPyKernelInterfaceJupyter(id)
|
||||||
# self._launch_kernel(kernel_cmd, env=env,
|
# self._launch_kernel(kernel_cmd, env=env,
|
||||||
# **kw)
|
# **kw)
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
|
||||||
#include "JupyterConnection.h"
|
#include "JupyterConnection.h"
|
||||||
|
#include "NestedIPyKernel.h"
|
||||||
#include "PythonAPI.h"
|
#include "PythonAPI.h"
|
||||||
|
|
||||||
Q_GLOBAL_STATIC(JupyterConnection, uniqueInstance)
|
Q_GLOBAL_STATIC(JupyterConnection, uniqueInstance)
|
||||||
@ -124,3 +125,24 @@ QString JupyterConnection::getUrl()
|
|||||||
|
|
||||||
return urlWithTokenString;
|
return urlWithTokenString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long JupyterConnection::startNestedIPyKernel(const QStringList &argv)
|
||||||
|
{
|
||||||
|
NestedIPyKernel *kernel = NestedIPyKernel::start(argv);
|
||||||
|
|
||||||
|
if (!kernel)
|
||||||
|
{
|
||||||
|
qWarning() << "Could not start nested IPyKernel.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
long id = nextKernelId++;
|
||||||
|
kernels.insert(id, kernel);
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
NestedIPyKernel *JupyterConnection::getNestedIPyKernel(long id)
|
||||||
|
{
|
||||||
|
return kernels[id];
|
||||||
|
}
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
|
|
||||||
|
class NestedIPyKernel;
|
||||||
|
|
||||||
struct _object;
|
struct _object;
|
||||||
typedef _object PyObject;
|
typedef _object PyObject;
|
||||||
|
|
||||||
@ -22,6 +24,9 @@ public:
|
|||||||
void start();
|
void start();
|
||||||
QString getUrl();
|
QString getUrl();
|
||||||
|
|
||||||
|
long startNestedIPyKernel(const QStringList &argv);
|
||||||
|
NestedIPyKernel *getNestedIPyKernel(long id);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void urlReceived(const QString &url);
|
void urlReceived(const QString &url);
|
||||||
void creationFailed();
|
void creationFailed();
|
||||||
@ -32,6 +37,9 @@ private:
|
|||||||
|
|
||||||
PyThreadState *pyThreadState = nullptr;
|
PyThreadState *pyThreadState = nullptr;
|
||||||
|
|
||||||
|
QMap<long, NestedIPyKernel *> kernels;
|
||||||
|
long nextKernelId = 1;
|
||||||
|
|
||||||
void initPython();
|
void initPython();
|
||||||
void createCutterJupyterModule();
|
void createCutterJupyterModule();
|
||||||
};
|
};
|
||||||
|
70
src/utils/NestedIPyKernel.cpp
Normal file
70
src/utils/NestedIPyKernel.cpp
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
|
||||||
|
#include <Python.h>
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
|
#include "cutter.h"
|
||||||
|
#include "NestedIPyKernel.h"
|
||||||
|
|
||||||
|
NestedIPyKernel *NestedIPyKernel::start(const QStringList &argv)
|
||||||
|
{
|
||||||
|
PyThreadState *parentThreadState = PyThreadState_Get();
|
||||||
|
|
||||||
|
PyThreadState *threadState = Py_NewInterpreter();
|
||||||
|
if (!threadState)
|
||||||
|
{
|
||||||
|
qWarning() << "Could not create subinterpreter.";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile moduleFile(":/python/cutter_ipykernel.py");
|
||||||
|
moduleFile.open(QIODevice::ReadOnly);
|
||||||
|
QByteArray moduleCode = moduleFile.readAll();
|
||||||
|
moduleFile.close();
|
||||||
|
|
||||||
|
auto moduleCodeObject = Py_CompileString(moduleCode.constData(), "cutter_ipykernel.py", Py_file_input);
|
||||||
|
if (!moduleCodeObject)
|
||||||
|
{
|
||||||
|
qWarning() << "Could not compile cutter_ipykernel.";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
auto cutterIPykernelModule = PyImport_ExecCodeModule("cutter_ipykernel", moduleCodeObject);
|
||||||
|
Py_DECREF(moduleCodeObject);
|
||||||
|
if (!cutterIPykernelModule)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
auto launchFunc = PyObject_GetAttrString(cutterIPykernelModule, "launch_ipykernel");
|
||||||
|
|
||||||
|
PyObject *argvListObject = PyList_New(argv.size());
|
||||||
|
for (int i = 0; i < argv.size(); i++)
|
||||||
|
{
|
||||||
|
QString s = argv[i];
|
||||||
|
PyList_SetItem(argvListObject, i, PyUnicode_DecodeUTF8(s.toUtf8().constData(), s.length(), nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel = PyObject_CallFunction(launchFunc, "O", argvListObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
NestedIPyKernel::~NestedIPyKernel()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void NestedIPyKernel::kill()
|
||||||
|
{
|
||||||
|
auto parentThreadState = PyThreadState_Swap(threadState);
|
||||||
|
PyObject_CallMethod(kernel, "kill", nullptr);
|
||||||
|
PyThreadState_Swap(parentThreadState);
|
||||||
|
}
|
29
src/utils/NestedIPyKernel.h
Normal file
29
src/utils/NestedIPyKernel.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#ifndef NESTEDIPYKERNEL_H
|
||||||
|
#define NESTEDIPYKERNEL_H
|
||||||
|
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
struct _object;
|
||||||
|
typedef _object PyObject;
|
||||||
|
|
||||||
|
struct _ts;
|
||||||
|
typedef _ts PyThreadState;
|
||||||
|
|
||||||
|
class NestedIPyKernel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static NestedIPyKernel *start(const QStringList &argv);
|
||||||
|
~NestedIPyKernel();
|
||||||
|
|
||||||
|
void kill();
|
||||||
|
|
||||||
|
private:
|
||||||
|
NestedIPyKernel(PyObject *cutterIPykernelModule, const QStringList &argv);
|
||||||
|
|
||||||
|
PyThreadState *threadState;
|
||||||
|
PyObject *kernel;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //NESTEDIPYKERNEL_H
|
@ -1,6 +1,8 @@
|
|||||||
|
|
||||||
#include "PythonAPI.h"
|
#include "PythonAPI.h"
|
||||||
#include "cutter.h"
|
#include "cutter.h"
|
||||||
|
#include "JupyterConnection.h"
|
||||||
|
#include "NestedIPyKernel.h"
|
||||||
|
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
|
||||||
@ -67,47 +69,30 @@ PyObject *api_internal_launch_ipykernel(PyObject *self, PyObject *args, PyObject
|
|||||||
argv.append(s);
|
argv.append(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyThreadState *parentThreadState = PyThreadState_Get();
|
long id = Jupyter()->startNestedIPyKernel(argv);
|
||||||
|
|
||||||
QFile moduleFile(":/python/cutter_ipykernel.py");
|
return PyLong_FromLong(id);
|
||||||
moduleFile.open(QIODevice::ReadOnly);
|
|
||||||
QByteArray moduleCode = moduleFile.readAll();
|
|
||||||
moduleFile.close();
|
|
||||||
|
|
||||||
auto moduleCodeObject = Py_CompileString(moduleCode.constData(), "cutter_ipykernel.py", Py_file_input);
|
|
||||||
if (!moduleCodeObject)
|
|
||||||
{
|
|
||||||
qWarning() << "Could not compile cutter_ipykernel.";
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
auto cutterIPykernelModule = PyImport_ExecCodeModule("cutter_ipykernel", moduleCodeObject);
|
|
||||||
Py_DECREF(moduleCodeObject);
|
PyObject *api_internal_kernel_interface_kill(PyObject *, PyObject *args)
|
||||||
if (!cutterIPykernelModule)
|
|
||||||
{
|
{
|
||||||
qWarning() << "Could not import cutter_ipykernel.";
|
long id;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "l", &id))
|
||||||
|
{
|
||||||
|
qWarning() << "Invalid args passed to api_internal_kernel_interface_kill().";
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto launchFunc = PyObject_GetAttrString(cutterIPykernelModule, "launch_ipykernel");
|
Jupyter()->getNestedIPyKernel(id)->kill();
|
||||||
|
|
||||||
argvListObject = PyList_New(argv.size());
|
Py_RETURN_NONE;
|
||||||
for (int i = 0; i < argv.size(); i++)
|
|
||||||
{
|
|
||||||
QString s = argv[i];
|
|
||||||
PyList_SetItem(argvListObject, i, PyUnicode_DecodeUTF8(s.toUtf8().constData(), s.length(), nullptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ipyKernel = PyObject_CallFunction(launchFunc, "O", argvListObject);
|
|
||||||
Q_UNUSED(ipyKernel);
|
|
||||||
|
|
||||||
PyThreadState_Swap(parentThreadState);
|
|
||||||
|
|
||||||
return PyLong_FromLong(42);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PyMethodDef CutterInternalMethods[] = {
|
PyMethodDef CutterInternalMethods[] = {
|
||||||
{"launch_ipykernel", (PyCFunction)api_internal_launch_ipykernel, METH_VARARGS | METH_KEYWORDS,
|
{"launch_ipykernel", (PyCFunction)api_internal_launch_ipykernel, METH_VARARGS | METH_KEYWORDS,
|
||||||
"Launch an IPython Kernel in a subinterpreter"},
|
"Launch an IPython Kernel in a subinterpreter"},
|
||||||
|
{"kernel_interface_kill", (PyCFunction)api_internal_kernel_interface_kill, METH_VARARGS, ""},
|
||||||
{NULL, NULL, 0, NULL}
|
{NULL, NULL, 0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user