mirror of
https://github.com/rizinorg/cutter.git
synced 2025-02-20 13:46:06 +00:00
WIP Python plugin PoC
This commit is contained in:
parent
a83791a3e0
commit
a1110ee2ac
@ -228,7 +228,9 @@ SOURCES += \
|
||||
RunScriptTask.cpp \
|
||||
dialogs/EditMethodDialog.cpp \
|
||||
dialogs/LoadNewTypesDialog.cpp \
|
||||
widgets/SdbWidget.cpp
|
||||
widgets/SdbWidget.cpp \
|
||||
plugins/CutterPythonPlugin.cpp \
|
||||
common/PythonManager.cpp
|
||||
|
||||
HEADERS += \
|
||||
Cutter.h \
|
||||
@ -339,7 +341,9 @@ HEADERS += \
|
||||
common/Json.h \
|
||||
dialogs/EditMethodDialog.h \
|
||||
dialogs/LoadNewTypesDialog.h \
|
||||
widgets/SdbWidget.h
|
||||
widgets/SdbWidget.h \
|
||||
plugins/CutterPythonPlugin.h \
|
||||
common/PythonManager.h
|
||||
|
||||
FORMS += \
|
||||
dialogs/AboutDialog.ui \
|
||||
|
@ -1,4 +1,9 @@
|
||||
#include "common/PythonManager.h"
|
||||
#include "CutterApplication.h"
|
||||
#ifdef CUTTER_ENABLE_JUPYTER
|
||||
#include "common/JupyterConnection.h"
|
||||
#endif
|
||||
#include "plugins/CutterPythonPlugin.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QFileOpenEvent>
|
||||
@ -14,11 +19,6 @@
|
||||
#include <QTranslator>
|
||||
#include <QLibraryInfo>
|
||||
|
||||
#ifdef CUTTER_ENABLE_JUPYTER
|
||||
#include "common/JupyterConnection.h"
|
||||
#endif
|
||||
#include "plugins/CutterPlugin.h"
|
||||
|
||||
#include "CutterConfig.h"
|
||||
|
||||
#include <cstdlib>
|
||||
@ -72,11 +72,9 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc
|
||||
QObject::tr("file"));
|
||||
cmd_parser.addOption(scriptOption);
|
||||
|
||||
#ifdef CUTTER_ENABLE_JUPYTER
|
||||
QCommandLineOption pythonHomeOption("pythonhome", QObject::tr("PYTHONHOME to use for Jupyter"),
|
||||
QCommandLineOption pythonHomeOption("pythonhome", QObject::tr("PYTHONHOME to use for embeded python interpreter"),
|
||||
"PYTHONHOME");
|
||||
cmd_parser.addOption(pythonHomeOption);
|
||||
#endif
|
||||
|
||||
cmd_parser.process(*this);
|
||||
|
||||
@ -98,11 +96,12 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CUTTER_ENABLE_JUPYTER
|
||||
// Init python
|
||||
if (cmd_parser.isSet(pythonHomeOption)) {
|
||||
Jupyter()->setPythonHome(cmd_parser.value(pythonHomeOption));
|
||||
Python()->setPythonHome(cmd_parser.value(pythonHomeOption));
|
||||
}
|
||||
#endif
|
||||
Python()->initialize();
|
||||
|
||||
|
||||
bool analLevelSpecified = false;
|
||||
int analLevel = 0;
|
||||
@ -219,18 +218,29 @@ void CutterApplication::loadPlugins()
|
||||
return;
|
||||
}
|
||||
|
||||
Python()->addPythonPath(pluginsDir.absolutePath().toLatin1().data());
|
||||
|
||||
CutterPlugin *cutterPlugin = nullptr;
|
||||
foreach (QString fileName, pluginsDir.entryList(QDir::Files)) {
|
||||
QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));
|
||||
QObject *plugin = pluginLoader.instance();
|
||||
if (plugin) {
|
||||
CutterPlugin *cutterPlugin = qobject_cast<CutterPlugin *>(plugin);
|
||||
if (cutterPlugin) {
|
||||
cutterPlugin->setupPlugin(Core());
|
||||
plugins.append(cutterPlugin);
|
||||
if (fileName.endsWith(".py")) {
|
||||
// Load python plugins
|
||||
cutterPlugin = Python()->loadPlugin(fileName.toLatin1().data());
|
||||
} else {
|
||||
// Load C++ plugins
|
||||
QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));
|
||||
QObject *plugin = pluginLoader.instance();
|
||||
if (plugin) {
|
||||
cutterPlugin = qobject_cast<CutterPlugin *>(plugin);
|
||||
}
|
||||
}
|
||||
|
||||
if (cutterPlugin) {
|
||||
cutterPlugin->setupPlugin(Core());
|
||||
plugins.append(cutterPlugin);
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << "Loaded" << plugins.length() << "plugins.";
|
||||
Core()->setCutterPlugins(plugins);
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include "common/PythonManager.h"
|
||||
#include "MainWindow.h"
|
||||
#include "ui_MainWindow.h"
|
||||
#include "common/Helpers.h"
|
||||
|
@ -2,18 +2,12 @@
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QDebug>
|
||||
#include <QThread>
|
||||
#include <QCoreApplication>
|
||||
#include <QDir>
|
||||
|
||||
#include "JupyterConnection.h"
|
||||
#include "NestedIPyKernel.h"
|
||||
#include "QtResImporter.h"
|
||||
#include "PythonAPI.h"
|
||||
#include "PythonManager.h"
|
||||
|
||||
#include <QVariant>
|
||||
#include <QDebug>
|
||||
|
||||
Q_GLOBAL_STATIC(JupyterConnection, uniqueInstance)
|
||||
|
||||
@ -24,130 +18,32 @@ JupyterConnection *JupyterConnection::getInstance()
|
||||
|
||||
JupyterConnection::JupyterConnection(QObject *parent) : QObject(parent)
|
||||
{
|
||||
/* Will be removed/reworked with python plugins PR */
|
||||
initPythonHome();
|
||||
initPython();
|
||||
qDebug() << "Python init";
|
||||
}
|
||||
|
||||
JupyterConnection::~JupyterConnection()
|
||||
{
|
||||
if (pyThreadState) {
|
||||
PyEval_RestoreThread(pyThreadState);
|
||||
|
||||
if (cutterNotebookAppInstance) {
|
||||
auto stopFunc = PyObject_GetAttrString(cutterNotebookAppInstance, "stop");
|
||||
PyObject_CallObject(stopFunc, nullptr);
|
||||
Py_DECREF(cutterNotebookAppInstance);
|
||||
}
|
||||
|
||||
Py_Finalize();
|
||||
}
|
||||
|
||||
if (pythonHome) {
|
||||
PyMem_RawFree(pythonHome);
|
||||
}
|
||||
}
|
||||
|
||||
void JupyterConnection::initPythonHome()
|
||||
{
|
||||
#if defined(APPIMAGE) || defined(MACOS_PYTHON_FRAMEWORK_BUNDLED)
|
||||
if (customPythonHome.isNull()) {
|
||||
auto pythonHomeDir = QDir(QCoreApplication::applicationDirPath());
|
||||
#ifdef APPIMAGE
|
||||
// Executable is in appdir/bin
|
||||
pythonHomeDir.cdUp();
|
||||
qInfo() << "Setting PYTHONHOME =" << pythonHomeDir.absolutePath() << " for AppImage.";
|
||||
#else // MACOS_PYTHON_FRAMEWORK_BUNDLED
|
||||
// @executable_path/../Frameworks/Python.framework/Versions/Current
|
||||
pythonHomeDir.cd("../Frameworks/Python.framework/Versions/Current");
|
||||
qInfo() << "Setting PYTHONHOME =" << pythonHomeDir.absolutePath() <<
|
||||
" for macOS Application Bundle.";
|
||||
#endif
|
||||
customPythonHome = pythonHomeDir.absolutePath();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!customPythonHome.isNull()) {
|
||||
qInfo() << "PYTHONHOME =" << customPythonHome;
|
||||
pythonHome = Py_DecodeLocale(customPythonHome.toLocal8Bit().constData(), nullptr);
|
||||
Py_SetPythonHome(pythonHome);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void JupyterConnection::initPython()
|
||||
{
|
||||
PyImport_AppendInittab("_cutter", &PyInit_api);
|
||||
PyImport_AppendInittab("cutter_internal", &PyInit_api_internal);
|
||||
PyImport_AppendInittab("_qtres", &PyInit_qtres);
|
||||
Py_Initialize();
|
||||
PyEval_InitThreads();
|
||||
|
||||
pyThreadState = PyEval_SaveThread();
|
||||
}
|
||||
|
||||
void JupyterConnection::createCutterJupyterModule()
|
||||
{
|
||||
if (pyThreadState) {
|
||||
PyEval_RestoreThread(pyThreadState);
|
||||
}
|
||||
|
||||
cutterJupyterModule = QtResImport("cutter_jupyter");
|
||||
if (!cutterJupyterModule) {
|
||||
PyErr_Print();
|
||||
qWarning() << "Could not import cutter_jupyter.";
|
||||
emit creationFailed();
|
||||
pyThreadState = PyEval_SaveThread();
|
||||
return;
|
||||
}
|
||||
|
||||
pyThreadState = PyEval_SaveThread();
|
||||
}
|
||||
|
||||
void JupyterConnection::start()
|
||||
{
|
||||
if (cutterNotebookAppInstance) {
|
||||
if (notebookInstanceExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Py_IsInitialized()) {
|
||||
initPython();
|
||||
}
|
||||
|
||||
if (!cutterJupyterModule) {
|
||||
createCutterJupyterModule();
|
||||
|
||||
if (!cutterJupyterModule) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PyEval_RestoreThread(pyThreadState);
|
||||
auto startFunc = PyObject_GetAttrString(cutterJupyterModule, "start_jupyter");
|
||||
cutterNotebookAppInstance = PyObject_CallObject(startFunc, nullptr);
|
||||
pyThreadState = PyEval_SaveThread();
|
||||
notebookInstanceExists = Python()->startJupyterNotebook();
|
||||
|
||||
emit urlReceived(getUrl());
|
||||
}
|
||||
|
||||
QString JupyterConnection::getUrl()
|
||||
{
|
||||
if (!cutterNotebookAppInstance) {
|
||||
if (!notebookInstanceExists) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PyEval_RestoreThread(pyThreadState);
|
||||
|
||||
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);
|
||||
|
||||
pyThreadState = PyEval_SaveThread();
|
||||
|
||||
return urlWithTokenString;
|
||||
QString url = Python()->getJupyterUrl();
|
||||
return url;
|
||||
}
|
||||
|
||||
long JupyterConnection::startNestedIPyKernel(const QStringList &argv)
|
||||
|
@ -5,16 +5,9 @@
|
||||
|
||||
#include <QProcess>
|
||||
#include <QMap>
|
||||
#include <cwchar>
|
||||
|
||||
class NestedIPyKernel;
|
||||
|
||||
struct _object;
|
||||
typedef _object PyObject;
|
||||
|
||||
struct _ts;
|
||||
typedef _ts PyThreadState;
|
||||
|
||||
class JupyterConnection : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -25,11 +18,6 @@ public:
|
||||
JupyterConnection(QObject *parent = nullptr);
|
||||
~JupyterConnection();
|
||||
|
||||
void setPythonHome(const QString pythonHome)
|
||||
{
|
||||
customPythonHome = pythonHome;
|
||||
}
|
||||
|
||||
void start();
|
||||
QString getUrl();
|
||||
|
||||
@ -42,26 +30,15 @@ signals:
|
||||
void creationFailed();
|
||||
|
||||
private:
|
||||
PyObject *cutterJupyterModule = nullptr;
|
||||
PyObject *cutterNotebookAppInstance = nullptr;
|
||||
|
||||
PyThreadState *pyThreadState = nullptr;
|
||||
|
||||
QMap<long, NestedIPyKernel *> kernels;
|
||||
long nextKernelId = 1;
|
||||
|
||||
QString customPythonHome;
|
||||
|
||||
wchar_t *pythonHome = nullptr;
|
||||
|
||||
void initPythonHome();
|
||||
void initPython();
|
||||
void createCutterJupyterModule();
|
||||
bool notebookInstanceExists = false;
|
||||
};
|
||||
|
||||
|
||||
#define Jupyter() (JupyterConnection::getInstance())
|
||||
|
||||
#endif
|
||||
#endif // CUTTER_ENABLE_JUPYTER
|
||||
|
||||
#endif //JUPYTERCONNECTION_H
|
||||
#endif // JUPYTERCONNECTION_H
|
||||
|
@ -1,10 +1,6 @@
|
||||
|
||||
#ifdef CUTTER_ENABLE_JUPYTER
|
||||
|
||||
#include "PythonAPI.h"
|
||||
#include "Cutter.h"
|
||||
#include "JupyterConnection.h"
|
||||
#include "NestedIPyKernel.h"
|
||||
|
||||
#include "CutterConfig.h"
|
||||
|
||||
@ -88,6 +84,9 @@ PyObject *PyInit_api()
|
||||
|
||||
// -----------------------------
|
||||
|
||||
#ifdef CUTTER_ENABLE_JUPYTER
|
||||
#include "JupyterConnection.h"
|
||||
#include "NestedIPyKernel.h"
|
||||
|
||||
PyObject *api_internal_launch_ipykernel(PyObject *self, PyObject *args, PyObject *kw)
|
||||
{
|
||||
@ -195,4 +194,4 @@ PyObject *PyInit_api_internal()
|
||||
return PyModule_Create(&CutterInternalModule);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // CUTTER_ENABLE_JUPYTER
|
||||
|
170
src/common/PythonManager.cpp
Normal file
170
src/common/PythonManager.cpp
Normal file
@ -0,0 +1,170 @@
|
||||
#include "PythonAPI.h"
|
||||
#include "PythonManager.h"
|
||||
|
||||
#include <marshal.h>
|
||||
#include <QFile>
|
||||
#include <QDebug>
|
||||
|
||||
#include "QtResImporter.h"
|
||||
#include "plugins/CutterPythonPlugin.h"
|
||||
|
||||
Q_GLOBAL_STATIC(PythonManager, uniqueInstance)
|
||||
|
||||
PythonManager *PythonManager::getInstance()
|
||||
{
|
||||
return uniqueInstance;
|
||||
}
|
||||
|
||||
PythonManager::PythonManager()
|
||||
{
|
||||
}
|
||||
|
||||
PythonManager::~PythonManager()
|
||||
{
|
||||
if (pyThreadState) {
|
||||
PyEval_RestoreThread(pyThreadState);
|
||||
|
||||
if (cutterNotebookAppInstance) {
|
||||
auto stopFunc = PyObject_GetAttrString(cutterNotebookAppInstance, "stop");
|
||||
PyObject_CallObject(stopFunc, nullptr);
|
||||
Py_DECREF(cutterNotebookAppInstance);
|
||||
}
|
||||
|
||||
Py_Finalize();
|
||||
}
|
||||
|
||||
if (pythonHome) {
|
||||
PyMem_RawFree(pythonHome);
|
||||
}
|
||||
}
|
||||
|
||||
void PythonManager::initPythonHome()
|
||||
{
|
||||
#if defined(APPIMAGE) || defined(MACOS_PYTHON_FRAMEWORK_BUNDLED)
|
||||
if (customPythonHome.isNull()) {
|
||||
auto pythonHomeDir = QDir(QCoreApplication::applicationDirPath());
|
||||
# ifdef APPIMAGE
|
||||
// Executable is in appdir/bin
|
||||
pythonHomeDir.cdUp();
|
||||
qInfo() << "Setting PYTHONHOME =" << pythonHomeDir.absolutePath() << " for AppImage.";
|
||||
# else // MACOS_PYTHON_FRAMEWORK_BUNDLED
|
||||
// @executable_path/../Frameworks/Python.framework/Versions/Current
|
||||
pythonHomeDir.cd("../Frameworks/Python.framework/Versions/Current");
|
||||
qInfo() << "Setting PYTHONHOME =" << pythonHomeDir.absolutePath() <<
|
||||
" for macOS Application Bundle.";
|
||||
# endif
|
||||
customPythonHome = pythonHomeDir.absolutePath();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!customPythonHome.isNull()) {
|
||||
qInfo() << "PYTHONHOME =" << customPythonHome;
|
||||
pythonHome = Py_DecodeLocale(customPythonHome.toLocal8Bit().constData(), nullptr);
|
||||
Py_SetPythonHome(pythonHome);
|
||||
}
|
||||
}
|
||||
|
||||
void PythonManager::initialize()
|
||||
{
|
||||
initPythonHome();
|
||||
|
||||
PyImport_AppendInittab("_cutter", &PyInit_api);
|
||||
PyImport_AppendInittab("cutter_internal", &PyInit_api_internal);
|
||||
PyImport_AppendInittab("_qtres", &PyInit_qtres);
|
||||
Py_Initialize();
|
||||
PyEval_InitThreads();
|
||||
|
||||
// Import other modules
|
||||
cutterJupyterModule = QtResImport("cutter_jupyter");
|
||||
cutterPluginModule = QtResImport("cutter_plugin");
|
||||
|
||||
pyThreadState = PyEval_SaveThread();
|
||||
}
|
||||
|
||||
void PythonManager::addPythonPath(char *path) {
|
||||
if (pyThreadState) {
|
||||
PyEval_RestoreThread(pyThreadState);
|
||||
}
|
||||
|
||||
PyObject *sysModule = PyImport_ImportModule("sys");
|
||||
if (!sysModule) {
|
||||
return;
|
||||
}
|
||||
PyObject *pythonPath = PyObject_GetAttrString(sysModule, "path");
|
||||
if (!pythonPath) {
|
||||
return;
|
||||
}
|
||||
PyObject *append = PyObject_GetAttrString(pythonPath, "append");
|
||||
if (!append) {
|
||||
return;
|
||||
}
|
||||
PyEval_CallFunction(append, "(s)", path);
|
||||
|
||||
pyThreadState = PyEval_SaveThread();
|
||||
}
|
||||
|
||||
bool PythonManager::startJupyterNotebook()
|
||||
{
|
||||
PyEval_RestoreThread(pyThreadState);
|
||||
|
||||
PyObject* startFunc = PyObject_GetAttrString(cutterJupyterModule, "start_jupyter");
|
||||
if (!startFunc) {
|
||||
qWarning() << "Couldn't get attribute start_jupyter.";
|
||||
return false;
|
||||
}
|
||||
|
||||
cutterNotebookAppInstance = PyObject_CallObject(startFunc, nullptr);
|
||||
pyThreadState = PyEval_SaveThread();
|
||||
|
||||
return cutterNotebookAppInstance != nullptr;
|
||||
}
|
||||
|
||||
QString PythonManager::getJupyterUrl()
|
||||
{
|
||||
PyEval_RestoreThread(pyThreadState);
|
||||
|
||||
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);
|
||||
|
||||
pyThreadState = PyEval_SaveThread();
|
||||
|
||||
return urlWithTokenString;
|
||||
}
|
||||
|
||||
CutterPythonPlugin* PythonManager::loadPlugin(char *pluginName) {
|
||||
CutterPythonPlugin *plugin = nullptr;
|
||||
if (!cutterPluginModule) {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
if (pyThreadState) {
|
||||
PyEval_RestoreThread(pyThreadState);
|
||||
}
|
||||
|
||||
PyObject *pluginModule = PyImport_ImportModule(pluginName);
|
||||
if (!pluginModule) {
|
||||
qWarning() << "Couldn't import the plugin" << QString(pluginName);
|
||||
}
|
||||
plugin = new CutterPythonPlugin(pluginModule);
|
||||
|
||||
pyThreadState = PyEval_SaveThread();
|
||||
|
||||
return plugin;
|
||||
}
|
||||
|
||||
PyObject *PythonManager::getAttrStringSafe(PyObject *object, const char* attribute)
|
||||
{
|
||||
PyObject *result = nullptr;
|
||||
if (pyThreadState) {
|
||||
PyEval_RestoreThread(pyThreadState);
|
||||
}
|
||||
|
||||
result = PyObject_GetAttrString(object, attribute);
|
||||
|
||||
pyThreadState = PyEval_SaveThread();
|
||||
|
||||
return result;
|
||||
}
|
48
src/common/PythonManager.h
Normal file
48
src/common/PythonManager.h
Normal file
@ -0,0 +1,48 @@
|
||||
#ifndef PYTHONMANAGER_H
|
||||
#define PYTHONMANAGER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class CutterPythonPlugin;
|
||||
typedef struct _ts PyThreadState;
|
||||
typedef struct _object PyObject;
|
||||
|
||||
class PythonManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static PythonManager *getInstance();
|
||||
|
||||
PythonManager();
|
||||
~PythonManager();
|
||||
|
||||
void setPythonHome(const QString pythonHome)
|
||||
{
|
||||
customPythonHome = pythonHome;
|
||||
}
|
||||
|
||||
void initPythonHome();
|
||||
void initialize();
|
||||
void addPythonPath(char *path);
|
||||
|
||||
bool startJupyterNotebook();
|
||||
QString getJupyterUrl();
|
||||
|
||||
CutterPythonPlugin *loadPlugin(char *pluginName);
|
||||
|
||||
PyObject *getAttrStringSafe(PyObject *object, const char* attribute);
|
||||
|
||||
private:
|
||||
QString customPythonHome;
|
||||
wchar_t *pythonHome = nullptr;
|
||||
PyThreadState *pyThreadState = nullptr;
|
||||
|
||||
PyObject *cutterJupyterModule;
|
||||
PyObject *cutterPluginModule;
|
||||
PyObject *cutterNotebookAppInstance = nullptr;
|
||||
};
|
||||
|
||||
#define Python() (PythonManager::getInstance())
|
||||
|
||||
#endif // PYTHONMANAGER_H
|
36
src/plugins/CutterPythonPlugin.cpp
Normal file
36
src/plugins/CutterPythonPlugin.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#include "CutterPythonPlugin.h"
|
||||
|
||||
CutterPythonPlugin::CutterPythonPlugin(PyObject* pluginModule)
|
||||
{
|
||||
this->pluginModule = pluginModule;
|
||||
}
|
||||
|
||||
void CutterPythonPlugin::setupPlugin(CutterCore *core)
|
||||
{
|
||||
Q_UNUSED(core)
|
||||
|
||||
//PyObject *pInstance = PyObject_GetAttrString(pluginModule, "plugin");
|
||||
PyObject *pInstance = Python()->getAttrStringSafe(pluginModule, "plugin");
|
||||
if (!pInstance) {
|
||||
qWarning() << "Cannot find plugin instance.";
|
||||
return;
|
||||
}
|
||||
|
||||
PyObject *pName = PyObject_GetAttrString(pInstance, "name");
|
||||
qDebug() << "pname" << pName;
|
||||
if (pName) {
|
||||
this->name = QString(PyUnicode_AS_DATA(pName));
|
||||
qDebug() << "OK COOL" << this->name;
|
||||
}
|
||||
}
|
||||
|
||||
CutterDockWidget* CutterPythonPlugin::setupInterface(MainWindow *main, QAction *action)
|
||||
{
|
||||
Q_UNUSED(main)
|
||||
Q_UNUSED(action)
|
||||
|
||||
return nullptr;
|
||||
}
|
18
src/plugins/CutterPythonPlugin.h
Normal file
18
src/plugins/CutterPythonPlugin.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef CUTTERPYTHONPLUGIN_H
|
||||
#define CUTTERPYTHONPLUGIN_H
|
||||
|
||||
#include "common/PythonManager.h"
|
||||
#include "CutterPlugin.h"
|
||||
|
||||
class CutterPythonPlugin : public CutterPlugin
|
||||
{
|
||||
public:
|
||||
CutterPythonPlugin(PyObject* pluginModule);
|
||||
void setupPlugin(CutterCore *core);
|
||||
CutterDockWidget* setupInterface(MainWindow *main, QAction *action);
|
||||
|
||||
private:
|
||||
PyObject *pluginModule;
|
||||
};
|
||||
|
||||
#endif // CUTTERPYTHONPLUGIN_H
|
21
src/python/cutter_plugin.py
Normal file
21
src/python/cutter_plugin.py
Normal file
@ -0,0 +1,21 @@
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
class CutterPlugin(ABC):
|
||||
name = ''
|
||||
description = ''
|
||||
version = ''
|
||||
author = ''
|
||||
core = None
|
||||
dockable = None
|
||||
|
||||
@abstractmethod
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def setupPlugin(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def setupInterface(self, main, action):
|
||||
pass
|
@ -86,5 +86,6 @@
|
||||
<file>img/icons/fork.svg</file>
|
||||
<file>python/cutter.py</file>
|
||||
<file>python/reg_qtres_importer.py</file>
|
||||
<file>python/cutter_plugin.py</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@ -1,9 +1,8 @@
|
||||
|
||||
#ifdef CUTTER_ENABLE_JUPYTER
|
||||
|
||||
#include "ui_JupyterWidget.h"
|
||||
|
||||
#include "common/JupyterConnection.h"
|
||||
#include "JupyterWidget.h"
|
||||
#include "ui_JupyterWidget.h"
|
||||
|
||||
#include <QTabWidget>
|
||||
#include <QHBoxLayout>
|
||||
|
@ -4,12 +4,10 @@
|
||||
|
||||
#ifdef CUTTER_ENABLE_JUPYTER
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <QAbstractButton>
|
||||
|
||||
#include "CutterDockWidget.h"
|
||||
#include "common/JupyterConnection.h"
|
||||
|
||||
#include <memory>
|
||||
#include <QAbstractButton>
|
||||
|
||||
namespace Ui {
|
||||
class JupyterWidget;
|
||||
|
Loading…
Reference in New Issue
Block a user