Commit 4683339e authored by Minh Ngo's avatar Minh Ngo
Browse files

Move Python3 backend to the separate process.

All python specific stuffs have been removed from backends/python/.
Python3 backend will create a separate process to deal with Python
specific stuff to resolve a problem with symbols conflict between
Python2 and Python3 libraries.
parent 2347786b
......@@ -44,13 +44,6 @@ PythonBackend::~PythonBackend()
qDebug()<<"Destroying PythonBackend";
}
Cantor::Session* PythonBackend::createSession()
{
qDebug()<<"Spawning a new Python session";
return new PythonSession(this);
}
Cantor::Backend::Capabilities PythonBackend::capabilities() const
{
qDebug()<<"Requesting capabilities of PythonSession";
......
......@@ -30,7 +30,6 @@ class PythonBackend : public Cantor::Backend
explicit PythonBackend(QObject* parent = 0, const QList<QVariant> args = QList<QVariant>());
~PythonBackend();
Cantor::Session *createSession();
Cantor::Backend::Capabilities capabilities() const;
QWidget* settingsWidget(QWidget* parent) const;
......
......@@ -57,9 +57,6 @@ void PythonSession::login()
{
qDebug()<<"login";
Py_Initialize();
m_pModule = PyImport_AddModule("__main__");
if(PythonSettings::integratePlots())
{
qDebug() << "integratePlots";
......@@ -220,7 +217,7 @@ void PythonSession::runExpression(PythonExpression* expr)
readOutput(expr, commandProcessing);
}
void PythonSession::runClassOutputPython()
void PythonSession::runClassOutputPython() const
{
QString classOutputPython = QLatin1String("import sys\n" \
"class CatchOutPythonBackend:\n" \
......@@ -233,39 +230,21 @@ void PythonSession::runClassOutputPython()
"sys.stdout = outputPythonBackend\n" \
"sys.stderr = errorPythonBackend\n");
PyRun_SimpleString(classOutputPython.toStdString().c_str());
runPythonCommand(classOutputPython);
}
void PythonSession::getPythonCommandOutput(QString commandProcessing)
{
qDebug() << "Running python command" << commandProcessing.toStdString().c_str();
qDebug() << "Running python command" << commandProcessing;
runClassOutputPython();
PyRun_SimpleString(commandProcessing.toStdString().c_str());
PyObject *outputPython = PyObject_GetAttrString(m_pModule, "outputPythonBackend");
PyObject *output = PyObject_GetAttrString(outputPython, "value");
#ifdef BUILD_WITH_PYTHON3
string outputString = PyUnicode_AsUTF8(output);
m_output = QString::fromUtf8(outputString.c_str());
#else
string outputString = PyString_AsString(output);
m_output = QString::fromLocal8Bit(outputString.c_str());
#endif
PyObject *errorPython = PyObject_GetAttrString(m_pModule, "errorPythonBackend");
PyObject *error = PyObject_GetAttrString(errorPython, "value");
#ifdef BUILD_WITH_PYTHON3
string errorString = PyUnicode_AsUTF8(error);
m_error = QString::fromUtf8(errorString.c_str());
#else
string errorString = PyString_AsString(error);
m_error = QString::fromLocal8Bit(errorString.c_str());
#endif
runPythonCommand(commandProcessing);
m_output = getOutput();
m_error = getError();
}
bool PythonSession::identifyKeywords(QString command)
bool PythonSession::identifyKeywords(const QString& command)
{
QString verifyErrorImport;
......@@ -327,7 +306,7 @@ bool PythonSession::identifyKeywords(QString command)
return true;
}
QString PythonSession::identifyPythonModule(QString command)
QString PythonSession::identifyPythonModule(const QString& command) const
{
QString module;
......@@ -339,7 +318,7 @@ QString PythonSession::identifyPythonModule(QString command)
return module;
}
QString PythonSession::identifyVariableModule(QString command)
QString PythonSession::identifyVariableModule(const QString& command) const
{
QString variable;
......@@ -368,7 +347,7 @@ void PythonSession::expressionFinished()
qDebug() << "size: " << m_runningExpressions.size();
}
void PythonSession::readOutput(PythonExpression* expr, QString commandProcessing)
void PythonSession::readOutput(PythonExpression* expr, const QString& commandProcessing)
{
qDebug() << "readOutput";
......@@ -392,7 +371,7 @@ void PythonSession::readOutput(PythonExpression* expr, QString commandProcessing
changeStatus(Cantor::Session::Done);
}
void PythonSession::plotFileChanged(QString filename)
void PythonSession::plotFileChanged(const QString& filename)
{
qDebug() << "plotFileChanged filename:" << filename;
......
......@@ -55,8 +55,8 @@ class PythonSession : public Cantor::Session
virtual QAbstractItemModel* variableModel();
public Q_SLOTS:
void readOutput(PythonExpression* expr, QString commandProcessing);
void plotFileChanged(QString filename);
void readOutput(PythonExpression* expr, const QString& commandProcessing);
void plotFileChanged(const QString& filename);
private:
KDirWatch* m_watch;
......@@ -65,19 +65,21 @@ class PythonSession : public Cantor::Session
QString m_error;
Cantor::DefaultVariableModel* m_variableModel;
PyObject *m_pModule;
QList<PythonExpression*> m_runningExpressions;
PythonExpression* m_currentExpression;
void listVariables();
void runClassOutputPython();
void runClassOutputPython() const;
void getPythonCommandOutput(QString commandProcessing);
QString identifyPythonModule(QString command);
QString identifyVariableModule(QString command);
bool identifyKeywords(QString command);
QString identifyPythonModule(const QString& command) const;
QString identifyVariableModule(const QString& command) const;
bool identifyKeywords(const QString& command);
virtual void runPythonCommand(const QString& command) const = 0;
virtual QString getOutput() const = 0;
virtual QString getError() const = 0;
private Q_SLOTS:
void expressionFinished();
......
......@@ -7,6 +7,7 @@ set( Python2Backend_SRCS
../python/pythoncompletionobject.cpp
../python/pythonextensions.cpp
python2backend.cpp
python2session.cpp
)
if(MSVC)
......
......@@ -22,6 +22,7 @@
#include <klocalizedstring.h>
#include "python2session.h"
#include "cantor_macros.h"
Python2Backend::Python2Backend(QObject* parent, const QList<QVariant> args)
......@@ -37,6 +38,11 @@ Python2Backend::Python2Backend(QObject* parent, const QList<QVariant> args)
pythonLib.load();
}
Cantor::Session* Python2Backend::createSession()
{
return new Python2Session(this);
}
QString Python2Backend::id() const
{
return QLatin1String("python2");
......
......@@ -29,6 +29,8 @@ class Python2Backend : public PythonBackend
public:
explicit Python2Backend(QObject* parent = 0, const QList<QVariant> args = QList<QVariant>());
Cantor::Session* createSession();
QString id() const;
KUrl helpUrl() const;
QString description() const;
......
/*
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
---
Copyright (C) 2015 Minh Ngo <minh@fedoraproject.org>
*/
#include "python2session.h"
#include <Python.h>
Python2Session::Python2Session(Cantor::Backend* backend)
: PythonSession(backend)
, m_pModule(nullptr)
{
}
void Python2Session::runPythonCommand(const QString& command) const
{
PyRun_SimpleString(command.toStdString().c_str());
}
void Python2Session::login()
{
Py_Initialize();
m_pModule = PyImport_AddModule("__main__");
PythonSession::login();
}
QString Python2Session::getOutput() const
{
PyObject *outputPython = PyObject_GetAttrString(m_pModule, "outputPythonBackend");
PyObject *output = PyObject_GetAttrString(outputPython, "value");
return pyObjectToQString(output);
}
QString Python2Session::getError() const
{
PyObject *errorPython = PyObject_GetAttrString(m_pModule, "errorPythonBackend");
PyObject *error = PyObject_GetAttrString(errorPython, "value");
return pyObjectToQString(error);
}
QString Python2Session::pyObjectToQString(PyObject* obj) const
{
return QString::fromLocal8Bit(PyString_AsString(obj));
}
\ No newline at end of file
/*
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
---
Copyright (C) 2015 Minh Ngo <minh@fedoraproject.org>
*/
#ifndef _PYTHON2SESSION_H
#define _PYTHON2SESSION_H
#include "../python/pythonsession.h"
struct _object;
typedef _object PyObject;
class Python2Session : public PythonSession
{
public:
Python2Session(Cantor::Backend* backend);
void login();
private:
void runPythonCommand(const QString& command) const;
QString getOutput() const;
QString getError() const;
QString pyObjectToQString(PyObject* obj) const;
private:
PyObject *m_pModule;
};
#endif
\ No newline at end of file
add_definitions(-DBUILD_WITH_PYTHON3)
set( Python3Backend_SRCS
../python/pythonbackend.cpp
../python/pythonsession.cpp
......@@ -9,13 +7,9 @@ set( Python3Backend_SRCS
../python/pythoncompletionobject.cpp
../python/pythonextensions.cpp
python3backend.cpp
python3session.cpp
)
string(REPLACE "-l" "" PYTHON3_LIB_NAME ${PYTHONLIBS3_LDFLAGS})
add_definitions(-DPYTHON3_LIB_NAME="${PYTHON3_LIB_NAME}")
include_directories(${PYTHONLIBS3_INCLUDE_DIRS})
kconfig_add_kcfg_files(Python3Backend_SRCS ../python/settings.kcfgc)
install(FILES ../python/pythonbackend.kcfg DESTINATION ${KCFG_INSTALL_DIR})
......@@ -23,13 +17,15 @@ ki18n_wrap_ui(Python3Backend_SRCS ../python/settings.ui)
add_library(cantor_python3backend MODULE ${Python3Backend_SRCS})
target_link_libraries(cantor_python3backend
${PYTHONLIBS3_LIBRARIES}
cantorlibs
KF5::KIOCore
KF5::ConfigCore
KF5::ConfigGui)
KF5::ConfigGui
Qt5::DBus)
install(FILES cantor_python3.knsrc DESTINATION ${CONFIG_INSTALL_DIR})
install(FILES python3backend.desktop DESTINATION ${SERVICES_INSTALL_DIR}/cantor)
install(FILES ../python/keywords.xml DESTINATION ${DATA_INSTALL_DIR}/cantor/python3backend)
install(TARGETS cantor_python3backend DESTINATION ${PLUGIN_INSTALL_DIR})
\ No newline at end of file
install(TARGETS cantor_python3backend DESTINATION ${PLUGIN_INSTALL_DIR})
add_subdirectory(python3server)
\ No newline at end of file
......@@ -22,12 +22,18 @@
#include <klocalizedstring.h>
#include "python3session.h"
#include "cantor_macros.h"
Python3Backend::Python3Backend(QObject* parent, const QList<QVariant> args)
: PythonBackend(parent, args)
{
setObjectName(QLatin1String("python3backend"));
}
Cantor::Session* Python3Backend::createSession()
{
return new Python3Session(this);
QLibrary pythonLib(QLatin1String(PYTHON3_LIB_NAME));
pythonLib.setLoadHints(QLibrary::ExportExternalSymbolsHint);
pythonLib.load();
......
......@@ -29,6 +29,8 @@ class Python3Backend : public PythonBackend
public:
explicit Python3Backend(QObject* parent = 0, const QList<QVariant> args = QList<QVariant>());
Cantor::Session* createSession();
QString id() const;
KUrl helpUrl() const;
QString description() const;
......
include_directories(${PYTHONLIBS3_INCLUDE_DIRS})
set(Python3Server_SRCS
python3server.cpp
main.cpp
)
add_executable(cantor_python3server ${Python3Server_SRCS})
set_target_properties(cantor_python3server PROPERTIES INSTALL_RPATH_USE_LINK_PATH false)
target_link_libraries(cantor_python3server
${PYTHONLIBS3_LIBRARIES}
Qt5::DBus)
install(TARGETS cantor_python3server ${INSTALL_TARGETS_DEFAULT_ARGS})
\ No newline at end of file
/*
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
---
Copyright (C) 2015 Minh Ngo <minh@fedoraproject.org>
*/
#include <unistd.h>
#include <QDebug>
#include <QApplication>
#include <QDBusError>
#include <QDBusConnection>
#include <QTextStream>
#include "python3server.h"
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
if (!QDBusConnection::sessionBus().isConnected())
{
qDebug() << "Can't connect to the D-Bus session bus.\n"
"To start it, run: eval `dbus-launch --auto-syntax`";
return 1;
}
const QString& serviceName = QString::fromLatin1("org.kde.Cantor.Python3-%1").arg(getpid());
if (!QDBusConnection::sessionBus().registerService(serviceName))
{
qDebug() << QDBusConnection::sessionBus().lastError().message();
return 2;
}
Python3Server server;
QDBusConnection::sessionBus().registerObject(QString::fromAscii("/"), &server, QDBusConnection::ExportAllSlots);
QTextStream(stdout) << "ready" << endl;
return app.exec();
}
\ No newline at end of file
/*
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
---
Copyright (C) 2015 Minh Ngo <minh@fedoraproject.org>
*/
#include "python3server.h"
#include <Python.h>
#include <QDebug>
#include <QDBusConnection>
Python3Server::Python3Server(QObject* parent)
: QObject(parent)
{
}
void Python3Server::login()
{
Py_Initialize();
m_pModule = PyImport_AddModule("__main__");
}
void Python3Server::runPythonCommand(const QString& command) const
{
PyRun_SimpleString(command.toStdString().c_str());
}
QString Python3Server::getError() const
{
PyObject *outputPython = PyObject_GetAttrString(m_pModule, "outputPythonBackend");
PyObject *output = PyObject_GetAttrString(outputPython, "value");
return pyObjectToQString(output);
}
QString Python3Server::getOutput() const
{
PyObject *errorPython = PyObject_GetAttrString(m_pModule, "errorPythonBackend");
PyObject *error = PyObject_GetAttrString(errorPython, "value");
return pyObjectToQString(error);
}
QString Python3Server::pyObjectToQString(PyObject* obj) const
{
return QString::fromUtf8(PyUnicode_AsUTF8(obj));
}
#include "python3server.moc"
/*
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
---
Copyright (C) 2015 Minh Ngo <minh@fedoraproject.org>
*/
#ifndef _PYTHON3SERVER_H
#define _PYTHON3SERVER_H
#include <QObject>
#include <QString>
struct _object;
typedef _object PyObject;
class Python3Server : public QObject
{
Q_OBJECT
public:
Python3Server(QObject* parent = nullptr);
public Q_SLOTS:
Q_SCRIPTABLE void login();
Q_SCRIPTABLE void runPythonCommand(const QString& command) const;
Q_SCRIPTABLE QString getOutput() const;
Q_SCRIPTABLE QString getError() const;
private:
QString pyObjectToQString(PyObject* obj) const;
private:
PyObject* m_pModule;
};
#endif
\ No newline at end of file
/*
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
---
Copyright (C) 2015 Minh Ngo <minh@fedoraproject.org>
*/
#include "python3session.h"
#include <signal.h>
#include <unistd.h>
#include <QDebug>
#include <QDBusConnection>
#include <QDBusInterface>
#include <QDBusReply>
#include <KProcess>
#include <KStandardDirs>
Python3Session::Python3Session(Cantor::Backend* backend)
: PythonSession(backend)
, m_pIface(nullptr)
, m_pProcess(nullptr)
{
}
void Python3Session::login()
{
if (m_pProcess)