From 05be34ae6b4d8c122f962c36f05049527892b3a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Thu, 22 Feb 2018 20:56:15 +0100 Subject: [PATCH] Jupyter refactoring and cleanup --- src/python/cutter_ipykernel.py | 2 +- src/utils/JupyterConnection.cpp | 63 +++++++++++++++++++++++++++++++-- src/utils/JupyterConnection.h | 10 ++++++ src/widgets/JupyterWidget.cpp | 8 ++--- src/widgets/JupyterWidget.h | 2 -- 5 files changed, 75 insertions(+), 10 deletions(-) diff --git a/src/python/cutter_ipykernel.py b/src/python/cutter_ipykernel.py index dace563c..1ebcaad4 100644 --- a/src/python/cutter_ipykernel.py +++ b/src/python/cutter_ipykernel.py @@ -28,7 +28,7 @@ def launch_ipykernel(argv): def run_kernel(): app = CutterIPKernelApp.instance() app.kernel_class = CutterIPythonKernel - app.log_level = logging.DEBUG + #app.log_level = logging.DEBUG app.initialize(argv[3:]) app.start() diff --git a/src/utils/JupyterConnection.cpp b/src/utils/JupyterConnection.cpp index f558d668..a8c2e36c 100644 --- a/src/utils/JupyterConnection.cpp +++ b/src/utils/JupyterConnection.cpp @@ -11,6 +11,13 @@ #include "JupyterConnection.h" #include "PythonAPI.h" +Q_GLOBAL_STATIC(JupyterConnection, uniqueInstance) + +JupyterConnection *JupyterConnection::getInstance() +{ + return uniqueInstance; +} + JupyterConnection::JupyterConnection(QObject *parent) : QObject(parent) { } @@ -24,18 +31,29 @@ JupyterConnection::~JupyterConnection() auto stopFunc = PyObject_GetAttrString(cutterNotebookAppInstance, "stop"); PyObject_CallObject(stopFunc, nullptr); Py_DECREF(cutterNotebookAppInstance); + } + if (Py_IsInitialized()) + { Py_FinalizeEx(); } } -void JupyterConnection::start() + +void JupyterConnection::initPython() { PyImport_AppendInittab("cutter", &PyInit_api); PyImport_AppendInittab("cutter_internal", &PyInit_api_internal); Py_Initialize(); PyEval_InitThreads(); + pyThreadState = PyEval_SaveThread(); +} + +void JupyterConnection::createCutterJupyterModule() +{ + PyEval_RestoreThread(pyThreadState); + QFile moduleFile(":/python/cutter_jupyter.py"); moduleFile.open(QIODevice::ReadOnly); QByteArray moduleCode = moduleFile.readAll(); @@ -46,6 +64,7 @@ void JupyterConnection::start() { qWarning() << "Could not compile cutter_jupyter."; emit creationFailed(); + pyThreadState = PyEval_SaveThread(); return; } cutterJupyterModule = PyImport_ExecCodeModule("cutter_jupyter", moduleCodeObject); @@ -54,16 +73,54 @@ void JupyterConnection::start() { qWarning() << "Could not import cutter_jupyter."; emit creationFailed(); + pyThreadState = PyEval_SaveThread(); return; } + pyThreadState = PyEval_SaveThread(); +} + +void JupyterConnection::start() +{ + if (cutterNotebookAppInstance) + { + return; + } + + if (!Py_IsInitialized()) + { + initPython(); + } + + if (!cutterJupyterModule) + { + createCutterJupyterModule(); + } + + PyEval_RestoreThread(pyThreadState); auto startFunc = PyObject_GetAttrString(cutterJupyterModule, "start_jupyter"); cutterNotebookAppInstance = PyObject_CallObject(startFunc, nullptr); + pyThreadState = PyEval_SaveThread(); + + emit urlReceived(getUrl()); +} + +QString JupyterConnection::getUrl() +{ + if (!cutterNotebookAppInstance) + { + return nullptr; + } + + PyEval_RestoreThread(pyThreadState); + auto urlWithToken = PyObject_GetAttrString(cutterNotebookAppInstance, "url_with_token"); auto asciiBytes = PyUnicode_AsASCIIString(urlWithToken); - emit urlReceived(QString::fromUtf8(PyBytes_AsString(asciiBytes))); + auto urlWithTokenString = QString::fromUtf8(PyBytes_AsString(asciiBytes)); Py_DECREF(asciiBytes); Py_DECREF(urlWithToken); pyThreadState = PyEval_SaveThread(); -} + + return urlWithTokenString; +} \ No newline at end of file diff --git a/src/utils/JupyterConnection.h b/src/utils/JupyterConnection.h index 64d20f7d..e956cc7c 100644 --- a/src/utils/JupyterConnection.h +++ b/src/utils/JupyterConnection.h @@ -14,10 +14,13 @@ class JupyterConnection : public QObject Q_OBJECT public: + static JupyterConnection* getInstance(); + JupyterConnection(QObject *parent = nullptr); ~JupyterConnection(); void start(); + QString getUrl(); signals: void urlReceived(const QString &url); @@ -28,6 +31,13 @@ private: PyObject *cutterNotebookAppInstance = nullptr; PyThreadState *pyThreadState = nullptr; + + void initPython(); + void createCutterJupyterModule(); }; + +#define Jupyter() (JupyterConnection::getInstance()) + + #endif //JUPYTERCONNECTION_H diff --git a/src/widgets/JupyterWidget.cpp b/src/widgets/JupyterWidget.cpp index 71273cf3..0ef421a5 100644 --- a/src/widgets/JupyterWidget.cpp +++ b/src/widgets/JupyterWidget.cpp @@ -14,10 +14,9 @@ JupyterWidget::JupyterWidget(QWidget *parent, Qt::WindowFlags flags) : { ui->setupUi(this); - jupyter = new JupyterConnection(this); - connect(jupyter, &JupyterConnection::urlReceived, this, &JupyterWidget::urlReceived); - connect(jupyter, &JupyterConnection::creationFailed, this, &JupyterWidget::creationFailed); - jupyter->start(); + connect(Jupyter(), &JupyterConnection::urlReceived, this, &JupyterWidget::urlReceived); + connect(Jupyter(), &JupyterConnection::creationFailed, this, &JupyterWidget::creationFailed); + Jupyter()->start(); } JupyterWidget::~JupyterWidget() @@ -48,6 +47,7 @@ void JupyterWidget::creationFailed() ui->tabWidget->addTab(failPage, tr("Error")); } + JupyterWebView::JupyterWebView(JupyterWidget *mainWidget, QWidget *parent) : QWebEngineView(parent) { this->mainWidget = mainWidget; diff --git a/src/widgets/JupyterWidget.h b/src/widgets/JupyterWidget.h index 63485d38..39ce4c64 100644 --- a/src/widgets/JupyterWidget.h +++ b/src/widgets/JupyterWidget.h @@ -32,8 +32,6 @@ private slots: private: std::unique_ptr ui; - - JupyterConnection *jupyter; };