Commit 6e8f3a01 authored by Nikita Sirgienko's avatar Nikita Sirgienko
Browse files

[Python] Merge python and python3 codebase into one and update tests for python

parent 648087ed
......@@ -56,7 +56,6 @@ set_package_properties(PythonLibs3 PROPERTIES DESCRIPTION "A powerful dynamic pr
find_package(PythonLibs3)
if(PYTHONLIBS3_FOUND)
add_subdirectory(python)
add_subdirectory(python3)
endif(PYTHONLIBS3_FOUND)
set_package_properties(LuaJIT PROPERTIES DESCRIPTION "A lightweight, extensible programming language (luajit implementation)."
......
......@@ -9,13 +9,18 @@ set( PythonBackend_SRCS
pythonextensions.cpp
)
qt5_add_resources(PythonBackend_RSCS python.qrc)
set(PythonServer_SRCS
pythonservermain.cpp
pythonserver.cpp
)
ki18n_wrap_ui(PythonBackend_SRCS settings.ui)
include_directories(${PYTHONLIBS3_INCLUDE_DIRS})
add_library(cantor_pythonbackend SHARED ${PythonBackend_SRCS} ${PythonBackend_RSCS})
generate_export_header(cantor_pythonbackend)
qt5_add_resources(PythonBackend_RSCS python.qrc)
ki18n_wrap_ui(PythonBackend_SRCS settings.ui)
kconfig_add_kcfg_files(PythonBackend_SRCS settings.kcfgc)
add_backend(pythonbackend ${PythonBackend_SRCS} ${PythonBackend_RSCS})
target_link_libraries(cantor_pythonbackend
cantorlibs
KF5::KIOCore
......@@ -24,5 +29,26 @@ target_link_libraries(cantor_pythonbackend
KF5::SyntaxHighlighting
)
add_executable(cantor_pythonserver ${PythonServer_SRCS})
set_target_properties(cantor_pythonserver PROPERTIES INSTALL_RPATH_USE_LINK_PATH false)
target_link_libraries(cantor_pythonserver ${PYTHONLIBS3_LIBRARIES})
if(BUILD_TESTING)
add_executable(testpython testpython.cpp settings.cpp)
add_test(NAME testpython COMMAND testpython)
target_link_libraries(testpython
Qt5::Test
KF5::ConfigCore
KF5::ConfigGui
cantorlibs
cantortest
)
endif(BUILD_TESTING)
install(FILES cantor_python.knsrc DESTINATION ${KDE_INSTALL_CONFDIR})
install(FILES pythonbackend.kcfg DESTINATION ${KDE_INSTALL_KCFGDIR})
install(TARGETS cantor_pythonbackend DESTINATION ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
install(TARGETS cantor_pythonserver DESTINATION ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
#install(DIRECTORY . DESTINATION ${KDE_INSTALL_DATADIR}/cantor/pythonbackend FILES_MATCHING PATTERN "*.py")
......@@ -21,6 +21,7 @@
#include "pythonbackend.h"
#include "pythonsession.h"
#include "pythonextensions.h"
#include "settings.h"
#include "ui_settings.h"
#include <QDebug>
......@@ -28,18 +29,13 @@
PythonBackend::PythonBackend(QObject* parent, const QList<QVariant>& args) : Cantor::Backend(parent, args)
{
qDebug()<<"Creating PythonBackend";
new PythonLinearAlgebraExtension(this);
new PythonPackagingExtension(this);
new PythonPlotExtension(this);
new PythonScriptExtension(this);
new PythonVariableManagementExtension(this);
}
PythonBackend::~PythonBackend()
{
qDebug()<<"Destroying PythonBackend";
//setObjectName(QLatin1String("python3backend"));
}
QWidget* PythonBackend::settingsWidget(QWidget* parent) const
......@@ -50,3 +46,62 @@ QWidget* PythonBackend::settingsWidget(QWidget* parent) const
return widget;
}
Cantor::Session* PythonBackend::createSession()
{
return new PythonSession(this);
}
QString PythonBackend::id() const
{
return QLatin1String("python");
}
QString PythonBackend::version() const
{
return QLatin1String("3.6");
}
Cantor::Backend::Capabilities PythonBackend::capabilities() const
{
qDebug()<<"Requesting capabilities of PythonSession";
Backend::Capabilities cap =
Cantor::Backend::SyntaxHighlighting |
Cantor::Backend::Completion |
Cantor::Backend::SyntaxHelp;
if(PythonSettings::variableManagement())
cap |= Cantor::Backend::VariableManagement;
return cap;
}
QUrl PythonBackend::helpUrl() const
{
const QUrl& localDoc = PythonSettings::self()->localDoc();
if (!localDoc.isEmpty())
return localDoc;
else
return QUrl(i18nc("The url to the documentation Python", "https://docs.python.org/3/"));
}
QString PythonBackend::description() const
{
return i18n("<b>Python</b> is a remarkably powerful dynamic programming language that is used in a wide variety of application domains. " \
"There are several Python packages to scientific programming.");
}
KConfigSkeleton* PythonBackend::config() const
{
return PythonSettings::self();
}
bool PythonBackend::requirementsFullfilled(QString* const reason) const
{
const QString& path = PythonSettings::pythonServerPath().toLocalFile();
return Cantor::Backend::checkExecutable(QLatin1String("Cantor Python Server"), path, reason);
}
K_PLUGIN_FACTORY_WITH_JSON(pythonbackend, "pythonbackend.json", registerPlugin<PythonBackend>();)
#include "pythonbackend.moc"
......@@ -22,19 +22,24 @@
#define _PYTHONBACKEND_H
#include "backend.h"
#include <cantor_pythonbackend_export.h>
class CANTOR_PYTHONBACKEND_EXPORT PythonBackend : public Cantor::Backend
class PythonBackend : public Cantor::Backend
{
Q_OBJECT
public:
explicit PythonBackend(QObject* parent = nullptr, const QList<QVariant>& args = QList<QVariant>());
~PythonBackend() override;
QWidget* settingsWidget(QWidget* parent) const override;
KConfigSkeleton* config() const override = 0;
Cantor::Backend::Capabilities capabilities() const override = 0;
Cantor::Session* createSession() override;
QString id() const override;
QString version() const override;
Cantor::Backend::Capabilities capabilities() const override;
QUrl helpUrl() const override;
QString description() const override;
bool requirementsFullfilled(QString* const reason = nullptr) const override;
KConfigSkeleton* config() const override;
};
......
......@@ -5,10 +5,10 @@
https://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
<include>QStandardPaths</include>
<kcfgfile name="cantorrc"/>
<group name="Python3Backend">
<group name="PythonBackend">
<entry name="pythonServerPath" type="Url">
<label>Path to Cantor python3 server executable</label>
<default code="true">QUrl::fromLocalFile(QStandardPaths::findExecutable(QLatin1String("cantor_python3server")))</default>
<label>Path to Cantor python server executable</label>
<default code="true">QUrl::fromLocalFile(QStandardPaths::findExecutable(QLatin1String("cantor_pythonserver")))</default>
</entry>
<entry name="localDoc" type="Url">
<label>Url to the local Python documentation</label>
......
......@@ -25,15 +25,15 @@
#include "textresult.h"
#include "imageresult.h"
#include "helpresult.h"
#include <QDebug>
#include <KIconLoader>
#include <QFile>
#include "pythonsession.h"
#include "session.h"
#include "settings.h"
#include <KIconLoader>
#include <QDir>
#include <QFileSystemWatcher>
#include <QTemporaryFile>
#include <QFile>
#include <QDebug>
PythonExpression::PythonExpression(Cantor::Session* session, bool internal) : Cantor::Expression(session, internal),
m_tempFile(nullptr)
......@@ -59,8 +59,7 @@ QString PythonExpression::internalCommand()
{
QString cmd = command();
PythonSession* pythonSession = static_cast<PythonSession*>(session());
if((pythonSession->integratePlots()) && (command().contains(QLatin1String("show()")))){
if((PythonSettings::integratePlots()) && (command().contains(QLatin1String("show()")))){
m_tempFile = new QTemporaryFile(QDir::tempPath() + QLatin1String("/cantor_python-XXXXXX.png"));
m_tempFile->open();
QString saveFigCommand = QLatin1String("savefig('%1')");
......
......@@ -25,7 +25,7 @@
#include <QTextEdit>
#include <QDebug>
PythonHighlighter::PythonHighlighter(QObject* parent, PythonSession* session, const int pythonVersion) : Cantor::DefaultHighlighter(parent, session)
PythonHighlighter::PythonHighlighter(QObject* parent, PythonSession* session) : Cantor::DefaultHighlighter(parent, session)
{
qDebug() << "PythonHighlighter constructor";
addRule(QRegularExpression(QStringLiteral("\\b\\w+(?=\\()")), functionFormat());
......@@ -34,12 +34,6 @@ PythonHighlighter::PythonHighlighter(QObject* parent, PythonSession* session, co
addKeywords(PythonKeywords::instance()->keywords());
addFunctions(PythonKeywords::instance()->functions());
addVariables(PythonKeywords::instance()->variables());
if (pythonVersion == 2)
{
removeRule(QLatin1String("print"));
addRule(QLatin1String("print"), keywordFormat());
}
}
void PythonHighlighter::highlightBlock(const QString &text)
......
......@@ -29,7 +29,7 @@ class PythonHighlighter : public Cantor::DefaultHighlighter
Q_OBJECT
public:
explicit PythonHighlighter(QObject* parent, PythonSession* session, const int pythonVersion);
explicit PythonHighlighter(QObject* parent, PythonSession* session);
~PythonHighlighter() override = default;
protected:
......
......@@ -27,6 +27,7 @@
#include "pythoncompletionobject.h"
#include "pythonkeywords.h"
#include "pythonutils.h"
#include "settings.h"
#include <QDebug>
#include <QDir>
......@@ -47,11 +48,9 @@ const QChar recordSep(30);
const QChar unitSep(31);
const QChar messageEnd = 29;
PythonSession::PythonSession(Cantor::Backend* backend, int pythonVersion, const QUrl serverExecutableUrl)
PythonSession::PythonSession(Cantor::Backend* backend)
: Session(backend)
, m_process(nullptr)
, m_serverExecutableUrl(serverExecutableUrl)
, m_pythonVersion(pythonVersion)
{
setVariableModel(new PythonVariableModel(this));
}
......@@ -77,7 +76,7 @@ void PythonSession::login()
m_process = new QProcess(this);
m_process->setProcessChannelMode(QProcess::ForwardedErrorChannel);
m_process->start(m_serverExecutableUrl.toLocalFile());
m_process->start(PythonSettings::pythonServerPath().toLocalFile());
m_process->waitForStarted();
m_process->waitForReadyRead();
......@@ -100,7 +99,7 @@ void PythonSession::login()
dir = QFileInfo(m_worksheetPath).absoluteDir().absolutePath();
sendCommand(QLatin1String("setFilePath"), QStringList() << m_worksheetPath << dir);
const QStringList& scripts = autorunScripts();
const QStringList& scripts = PythonSettings::autorunScripts();
if(!scripts.isEmpty()){
QString autorunScripts = scripts.join(QLatin1String("\n"));
evaluateExpression(autorunScripts, Cantor::Expression::DeleteOnFinish, true);
......@@ -173,7 +172,7 @@ Cantor::Expression* PythonSession::evaluateExpression(const QString& cmd, Cantor
QSyntaxHighlighter* PythonSession::syntaxHighlighter(QObject* parent)
{
return new PythonHighlighter(parent, this, m_pythonVersion);
return new PythonHighlighter(parent, this);
}
Cantor::CompletionObject* PythonSession::completionFor(const QString& command, int index)
......@@ -212,12 +211,7 @@ void PythonSession::readOutput()
while (m_process->bytesAvailable() > 0)
{
const QByteArray& bytes = m_process->readAll();
if (m_pythonVersion == 3)
m_output.append(QString::fromUtf8(bytes));
else if (m_pythonVersion == 2)
m_output.append(QString::fromLocal8Bit(bytes));
else
qCritical() << "Unsupported Python version" << m_pythonVersion;
m_output.append(QString::fromUtf8(bytes));
}
qDebug() << "m_output: " << m_output;
......
......@@ -23,16 +23,15 @@
#define _PYTHONSESSION_H
#include "session.h"
#include <cantor_pythonbackend_export.h>
#include <QStringList>
#include <QUrl>
#include <QProcess>
class CANTOR_PYTHONBACKEND_EXPORT PythonSession : public Cantor::Session
class PythonSession : public Cantor::Session
{
Q_OBJECT
public:
PythonSession(Cantor::Backend* backend, int pythonVersion, const QUrl serverExecutableUrl);
PythonSession(Cantor::Backend* backend);
~PythonSession() override;
void login() override;
......@@ -45,16 +44,10 @@ class CANTOR_PYTHONBACKEND_EXPORT PythonSession : public Cantor::Session
QSyntaxHighlighter* syntaxHighlighter(QObject* parent) override;
void setWorksheetPath(const QString& path) override;
virtual bool integratePlots() const = 0;
virtual QStringList autorunScripts() const = 0;
virtual bool variableManagement() const = 0;
private:
QProcess* m_process;
QUrl m_serverExecutableUrl;
QString m_worksheetPath;
int m_pythonVersion;
QString m_output;
......
......@@ -27,6 +27,8 @@
#include <QDBusInterface>
#include <QString>
#include "settings.h"
using namespace Cantor;
PythonVariableModel::PythonVariableModel(PythonSession* session):
......@@ -45,7 +47,7 @@ void PythonVariableModel::update()
if (m_expression)
return;
int variableManagement = static_cast<PythonSession*>(session())->variableManagement();
int variableManagement = PythonSettings::variableManagement();
const QString command = QString::fromLatin1("%variables %1").arg(variableManagement);
m_expression = session()->evaluateExpression(command, Cantor::Expression::FinishingBehavior::DoNotDelete, true);
connect(m_expression, &Cantor::Expression::statusChanged, this, &PythonVariableModel::extractVariables);
......
File=python3backend.kcfg
File=pythonbackend.kcfg
ClassName=PythonSettings
Singleton=true
......@@ -18,7 +18,7 @@
Copyright (C) 2015 Minh Ngo <minh@fedoraproject.org>
*/
#include "testpython3.h"
#include "testpython.h"
#include "session.h"
#include "backend.h"
......@@ -31,7 +31,7 @@
QString TestPython3::backendName()
{
return QLatin1String("python3");
return QLatin1String("python");
}
void TestPython3::testSimpleCommand()
......
set(Python3Backend_SRCS
python3backend.cpp
python3session.cpp
)
set(Python3Server_SRCS
../python/pythonservermain.cpp
../python/pythonserver.cpp
)
include_directories(${PYTHONLIBS3_INCLUDE_DIRS})
kconfig_add_kcfg_files(Python3Backend_SRCS settings.kcfgc)
add_backend(python3backend ${Python3Backend_SRCS})
target_link_libraries(cantor_python3backend cantor_pythonbackend)
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})
if(BUILD_TESTING)
add_executable(testpython3 testpython3.cpp settings.cpp)
add_test(NAME testpython3 COMMAND testpython3)
target_link_libraries(testpython3
Qt5::Test
KF5::ConfigCore
KF5::ConfigGui
cantorlibs
cantortest
)
endif(BUILD_TESTING)
install(FILES cantor_python3.knsrc DESTINATION ${KDE_INSTALL_CONFDIR})
install(FILES python3backend.kcfg DESTINATION ${KDE_INSTALL_KCFGDIR})
install(TARGETS cantor_python3server ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
/*
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) 2014, 2015 Minh Ngo <minh@fedoraproject.org>
Copyright (C) 2019 Alexander Semke <alexander.semke@web.de>
*/
#include "python3backend.h"
#include "python3session.h"
#include "settings.h"
#include <klocalizedstring.h>
Python3Backend::Python3Backend(QObject* parent, const QList<QVariant>& args)
: PythonBackend(parent, args)
{
setObjectName(QLatin1String("python3backend"));
}
Cantor::Session* Python3Backend::createSession()
{
return new Python3Session(this);
}
QString Python3Backend::id() const
{
return QLatin1String("python3");
}
QString Python3Backend::version() const
{
return QLatin1String("3.6");
}
Cantor::Backend::Capabilities Python3Backend::capabilities() const
{
qDebug()<<"Requesting capabilities of Python3Session";
Backend::Capabilities cap =
Cantor::Backend::SyntaxHighlighting |
Cantor::Backend::Completion |
Cantor::Backend::SyntaxHelp;
if(PythonSettings::variableManagement())
cap |= Cantor::Backend::VariableManagement;
return cap;
}
QUrl Python3Backend::helpUrl() const
{
const QUrl& localDoc = PythonSettings::self()->localDoc();
if (!localDoc.isEmpty())
return localDoc;
else
return QUrl(i18nc("The url to the documentation Python", "https://docs.python.org/3/"));
}
QString Python3Backend::description() const
{
return i18n("<b>Python</b> is a remarkably powerful dynamic programming language that is used in a wide variety of application domains. " \
"There are several Python packages to scientific programming.");
}
KConfigSkeleton* Python3Backend::config() const
{
return PythonSettings::self();
}
bool Python3Backend::requirementsFullfilled(QString* const reason) const
{
const QString& path = PythonSettings::pythonServerPath().toLocalFile();
return Cantor::Backend::checkExecutable(QLatin1String("Cantor Python3 Server"), path, reason);
}
K_PLUGIN_FACTORY_WITH_JSON(python3backend, "python3backend.json", registerPlugin<Python3Backend>();)
#include "python3backend.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) 2014, 2015 Minh Ngo <minh@fedoraproject.org>
*/
#ifndef _PYTHON3BACKEND_H
#define _PYTHON3BACKEND_H
#include "../python/pythonbackend.h"
class Python3Backend : public PythonBackend
{
public:
explicit Python3Backend(QObject* parent = nullptr, const QList<QVariant>& args = QList<QVariant>());
Cantor::Session* createSession() override;
QString id() const override;
QString version() const override;
Cantor::Backend::Capabilities capabilities() const override;
QUrl helpUrl() const override;
QString description() const override;
bool requirementsFullfilled(QString* const reason = nullptr) const override;
KConfigSkeleton* config() const override;
};
#endif
/*
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 "settings.h"
Python3Session::Python3Session(Cantor::Backend* backend)
: PythonSession(backend, 3, PythonSettings::pythonServerPath())
{
}
bool Python3Session::integratePlots() const
{
return PythonSettings::integratePlots();
}
QStringList Python3Session::autorunScripts() const