From 74a201ecbac209ae0418eeb585298eeef7be3c35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Sun, 3 Feb 2019 12:31:59 +0100 Subject: [PATCH] Move everything Jupyter related out of PythonManager Fix importing cutter in Python --- src/common/JupyterConnection.cpp | 52 ++++++++++++++++++++++++++++++-- src/common/JupyterConnection.h | 10 ++++++ src/common/PythonAPI.cpp | 2 +- src/common/PythonManager.cpp | 39 ++---------------------- src/common/PythonManager.h | 17 +++++------ 5 files changed, 71 insertions(+), 49 deletions(-) diff --git a/src/common/JupyterConnection.cpp b/src/common/JupyterConnection.cpp index 9f7ac383..9b5685ad 100644 --- a/src/common/JupyterConnection.cpp +++ b/src/common/JupyterConnection.cpp @@ -5,6 +5,7 @@ #include "JupyterConnection.h" #include "NestedIPyKernel.h" #include "PythonManager.h" +#include "QtResImporter.h" #include #include @@ -18,6 +19,7 @@ JupyterConnection *JupyterConnection::getInstance() JupyterConnection::JupyterConnection(QObject *parent) : QObject(parent) { + connect(Python(), &PythonManager::willShutDown, this, &JupyterConnection::stop); } JupyterConnection::~JupyterConnection() @@ -31,18 +33,29 @@ void JupyterConnection::start() return; } - notebookInstanceExists = Python()->startJupyterNotebook(); + notebookInstanceExists = startJupyterNotebook(); emit urlReceived(getUrl()); } +void JupyterConnection::stop() +{ + if (cutterNotebookAppInstance) { + Python()->restoreThread(); + auto stopFunc = PyObject_GetAttrString(cutterNotebookAppInstance, "stop"); + PyObject_CallObject(stopFunc, nullptr); + Py_DECREF(cutterNotebookAppInstance); + Python()->saveThread(); + } +} + QString JupyterConnection::getUrl() { if (!notebookInstanceExists) { return nullptr; } - QString url = Python()->getJupyterUrl(); + QString url = getJupyterUrl(); return url; } @@ -94,4 +107,39 @@ QVariant JupyterConnection::pollNestedIPyKernel(long id) return v; } +bool JupyterConnection::startJupyterNotebook() +{ + Python()->restoreThread(); + + if (!cutterJupyterModule) { + cutterJupyterModule = QtResImport("cutter_jupyter"); + } + + PyObject* startFunc = PyObject_GetAttrString(cutterJupyterModule, "start_jupyter"); + if (!startFunc) { + qWarning() << "Couldn't get attribute start_jupyter."; + return false; + } + + cutterNotebookAppInstance = PyObject_CallObject(startFunc, nullptr); + Python()->saveThread(); + + return cutterNotebookAppInstance != nullptr; +} + +QString JupyterConnection::getJupyterUrl() +{ + Python()->restoreThread(); + + auto urlWithToken = PyObject_GetAttrString(cutterNotebookAppInstance, "url_with_token"); + auto asciiBytes = PyUnicode_AsASCIIString(urlWithToken); + auto urlWithTokenString = QString::fromUtf8(PyBytes_AsString(asciiBytes)); + Py_DECREF(asciiBytes); + Py_DECREF(urlWithToken); + + Python()->saveThread(); + + return urlWithTokenString; +} + #endif diff --git a/src/common/JupyterConnection.h b/src/common/JupyterConnection.h index 445b1296..148c8e4d 100644 --- a/src/common/JupyterConnection.h +++ b/src/common/JupyterConnection.h @@ -7,6 +7,7 @@ #include class NestedIPyKernel; +typedef struct _object PyObject; class JupyterConnection : public QObject { @@ -25,6 +26,9 @@ public: NestedIPyKernel *getNestedIPyKernel(long id); QVariant pollNestedIPyKernel(long id); +public slots: + void stop(); + signals: void urlReceived(const QString &url); void creationFailed(); @@ -34,6 +38,12 @@ private: long nextKernelId = 1; bool notebookInstanceExists = false; + + PyObject *cutterJupyterModule = nullptr; + PyObject *cutterNotebookAppInstance = nullptr; + + bool startJupyterNotebook(); + QString getJupyterUrl(); }; diff --git a/src/common/PythonAPI.cpp b/src/common/PythonAPI.cpp index 1dc18768..848d4cb2 100644 --- a/src/common/PythonAPI.cpp +++ b/src/common/PythonAPI.cpp @@ -66,7 +66,7 @@ PyMethodDef CutterMethods[] = { "Refresh Cutter widgets" }, { - "message", (PyCFunction) api_message, METH_VARARGS | METH_KEYWORDS, + "message", (PyCFunction)(void *)/* don't remove this double cast! */api_message, METH_VARARGS | METH_KEYWORDS, "Print message" }, {NULL, NULL, 0, NULL} diff --git a/src/common/PythonManager.cpp b/src/common/PythonManager.cpp index 79e557e8..0d1cbb59 100644 --- a/src/common/PythonManager.cpp +++ b/src/common/PythonManager.cpp @@ -32,11 +32,7 @@ PythonManager::~PythonManager() restoreThread(); - if (cutterNotebookAppInstance) { - auto stopFunc = PyObject_GetAttrString(cutterNotebookAppInstance, "stop"); - PyObject_CallObject(stopFunc, nullptr); - Py_DECREF(cutterNotebookAppInstance); - } + emit willShutDown(); Py_Finalize(); @@ -81,8 +77,9 @@ void PythonManager::initialize() Py_Initialize(); PyEval_InitThreads(); + RegQtResImporter(); + // Import other modules - cutterJupyterModule = QtResImport("cutter_jupyter"); cutterPluginModule = QtResImport("cutter_plugin"); saveThread(); @@ -108,36 +105,6 @@ void PythonManager::addPythonPath(char *path) { saveThread(); } -bool PythonManager::startJupyterNotebook() -{ - restoreThread(); - - PyObject* startFunc = PyObject_GetAttrString(cutterJupyterModule, "start_jupyter"); - if (!startFunc) { - qWarning() << "Couldn't get attribute start_jupyter."; - return false; - } - - cutterNotebookAppInstance = PyObject_CallObject(startFunc, nullptr); - saveThread(); - - return cutterNotebookAppInstance != nullptr; -} - -QString PythonManager::getJupyterUrl() -{ - restoreThread(); - - auto urlWithToken = PyObject_GetAttrString(cutterNotebookAppInstance, "url_with_token"); - auto asciiBytes = PyUnicode_AsASCIIString(urlWithToken); - auto urlWithTokenString = QString::fromUtf8(PyBytes_AsString(asciiBytes)); - Py_DECREF(asciiBytes); - Py_DECREF(urlWithToken); - - saveThread(); - - return urlWithTokenString; -} CutterPythonPlugin* PythonManager::loadPlugin(const char *pluginName) { CutterPythonPlugin *plugin = nullptr; diff --git a/src/common/PythonManager.h b/src/common/PythonManager.h index 50c045a2..d2878526 100644 --- a/src/common/PythonManager.h +++ b/src/common/PythonManager.h @@ -7,40 +7,37 @@ class CutterPythonPlugin; typedef struct _ts PyThreadState; typedef struct _object PyObject; -class PythonManager +class PythonManager: public QObject { + Q_OBJECT + public: static PythonManager *getInstance(); PythonManager(); ~PythonManager(); - void setPythonHome(const QString pythonHome) - { - customPythonHome = pythonHome; - } + void setPythonHome(const QString &pythonHome) { customPythonHome = pythonHome; } void initPythonHome(); void initialize(); void addPythonPath(char *path); - bool startJupyterNotebook(); - QString getJupyterUrl(); - PyObject *createModule(QString module); CutterPythonPlugin *loadPlugin(const char *pluginName); void restoreThread(); void saveThread(); +signals: + void willShutDown(); + private: QString customPythonHome; wchar_t *pythonHome = nullptr; PyThreadState *pyThreadState = nullptr; - PyObject *cutterJupyterModule; PyObject *cutterPluginModule; - PyObject *cutterNotebookAppInstance = nullptr; }; #define Python() (PythonManager::getInstance())