cutter/src/common/PythonManager.cpp

136 lines
3.3 KiB
C++
Raw Normal View History

#ifdef CUTTER_ENABLE_PYTHON
2018-06-23 16:59:23 +00:00
#include "PythonAPI.h"
#include "PythonManager.h"
#include "Cutter.h"
2018-06-23 16:59:23 +00:00
#include <marshal.h>
2018-06-24 09:51:16 +00:00
#include <QDebug>
2018-06-23 16:59:23 +00:00
#include <QFile>
#include <QDebug>
#include "QtResImporter.h"
static PythonManager *uniqueInstance = nullptr;
2018-06-23 16:59:23 +00:00
PythonManager *PythonManager::getInstance()
{
if (!uniqueInstance) {
uniqueInstance = new PythonManager();
}
2018-06-23 16:59:23 +00:00
return uniqueInstance;
}
PythonManager::PythonManager()
{
}
PythonManager::~PythonManager()
{
}
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);
}
}
2019-02-13 22:24:22 +00:00
#ifdef CUTTER_ENABLE_PYTHON_BINDINGS
extern "C" PyObject *PyInit_CutterBindings();
2019-02-13 22:24:22 +00:00
#endif
2018-06-23 16:59:23 +00:00
void PythonManager::initialize()
{
initPythonHome();
PyImport_AppendInittab("_cutter", &PyInit_api);
#ifdef CUTTER_ENABLE_JUPYTER
2018-06-23 16:59:23 +00:00
PyImport_AppendInittab("cutter_internal", &PyInit_api_internal);
#endif
2018-06-23 16:59:23 +00:00
PyImport_AppendInittab("_qtres", &PyInit_qtres);
2019-02-13 22:24:22 +00:00
#ifdef CUTTER_ENABLE_PYTHON_BINDINGS
PyImport_AppendInittab("CutterBindings", &PyInit_CutterBindings);
2019-02-13 22:24:22 +00:00
#endif
2018-06-23 16:59:23 +00:00
Py_Initialize();
PyEval_InitThreads();
2019-02-09 13:05:06 +00:00
pyThreadStateCounter = 1; // we have the thread now => 1
2018-06-23 16:59:23 +00:00
RegQtResImporter();
2018-06-24 09:51:16 +00:00
saveThread();
2018-06-23 16:59:23 +00:00
}
2019-02-03 13:00:40 +00:00
void PythonManager::shutdown()
{
emit willShutDown();
// This is necessary to prevent a segfault when the CutterCore instance is deleted after the Shiboken::BindingManager
Core()->setProperty("_PySideInvalidatePtr", QVariant());
2019-02-03 13:00:40 +00:00
restoreThread();
Py_Finalize();
if (pythonHome) {
PyMem_RawFree(pythonHome);
}
}
2018-06-23 16:59:23 +00:00
void PythonManager::addPythonPath(char *path) {
2018-06-24 09:51:16 +00:00
restoreThread();
2018-06-23 16:59:23 +00:00
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);
2018-06-24 09:51:16 +00:00
saveThread();
2018-06-23 16:59:23 +00:00
}
2018-06-24 09:51:16 +00:00
void PythonManager::restoreThread()
2018-06-23 16:59:23 +00:00
{
2019-02-09 13:05:06 +00:00
pyThreadStateCounter++;
if (pyThreadStateCounter == 1 && pyThreadState) {
2018-06-23 16:59:23 +00:00
PyEval_RestoreThread(pyThreadState);
}
2018-06-24 09:51:16 +00:00
}
2018-06-23 16:59:23 +00:00
2018-06-24 09:51:16 +00:00
void PythonManager::saveThread()
{
2019-02-09 13:05:06 +00:00
pyThreadStateCounter--;
assert(pyThreadStateCounter >= 0);
if (pyThreadStateCounter == 0) {
pyThreadState = PyEval_SaveThread();
}
2018-06-23 16:59:23 +00:00
}
#endif