Commit 4761aa32 authored by Nikita Sirgienko's avatar Nikita Sirgienko
Browse files

[Python] Fix bug with unworking interruption

parent 2f86a75c
......@@ -48,6 +48,11 @@ void PythonServer::login()
filePath = QStringLiteral("python_cantor_worksheet");
}
void PythonServer::interrupt()
{
PyErr_SetInterrupt();
}
void PythonServer::runPythonCommand(const QString& command) const
{
PyObject* py_dict = PyModule_GetDict(m_pModule);
......
......@@ -33,12 +33,13 @@ class PythonServer : public QObject
explicit PythonServer(QObject* parent = nullptr);
public Q_SLOTS:
Q_SCRIPTABLE void login();
Q_SCRIPTABLE void setFilePath(const QString& path);
Q_SCRIPTABLE void runPythonCommand(const QString& command) const;
Q_SCRIPTABLE QString getOutput() const;
Q_SCRIPTABLE QString getError() const;
Q_SCRIPTABLE QString variables(bool parseValue) const;
void login();
void interrupt();
void setFilePath(const QString& path);
void runPythonCommand(const QString& command) const;
QString getOutput() const;
QString getError() const;
QString variables(bool parseValue) const;
private:
PyObject* m_pModule;
......
......@@ -19,6 +19,7 @@
*/
#include <iostream>
#include <csignal>
#include <QApplication>
#include <QTimer>
......@@ -32,6 +33,7 @@ const QChar unitSep(31);
const char messageEnd = 29;
PythonServer server;
bool isInterrupted = false;
QTimer inputTimer;
QMetaObject::Connection connection;
......@@ -43,7 +45,6 @@ QLatin1String CODE("code");
QLatin1String FILEPATH("setFilePath");
QLatin1String MODEL("model");
void routeInput() {
QByteArray bytes;
char c;
......@@ -71,21 +72,27 @@ void routeInput() {
else if (records[0] == LOGIN)
{
server.login();
const QByteArray bytes = QString::fromLatin1("login done").toLocal8Bit();
//std::cout << bytes.data();
}
else if (records[0] == CODE)
{
server.runPythonCommand(records[1]);
const QString& result =
server.getOutput()
+ unitSep
+ server.getError()
+ QLatin1Char(messageEnd);
const QByteArray bytes = result.toLocal8Bit();
std::cout << bytes.data();
if (!isInterrupted)
{
const QString& result =
server.getOutput()
+ unitSep
+ server.getError()
+ QLatin1Char(messageEnd);
const QByteArray bytes = result.toLocal8Bit();
std::cout << bytes.data();
}
else
{
// No replay when interrupted
isInterrupted = false;
}
}
else if (records[0] == FILEPATH)
{
......@@ -110,8 +117,19 @@ void routeInput() {
}
}
void signal_handler(int signal)
{
if (signal == SIGINT)
{
isInterrupted = true;
server.interrupt();
}
}
int main(int argc, char *argv[])
{
std::signal(SIGINT, signal_handler);
QCoreApplication app(argc, argv);
connection = QObject::connect(&inputTimer, &QTimer::timeout, routeInput);
......
......@@ -127,7 +127,7 @@ void PythonSession::interrupt()
if(!expressionQueue().isEmpty())
{
qDebug()<<"interrupting " << expressionQueue().first()->command();
if(m_process->state() != QProcess::NotRunning)
if(m_process && m_process->state() != QProcess::NotRunning)
{
#ifndef Q_OS_WIN
const int pid=m_process->pid();
......@@ -140,11 +140,7 @@ void PythonSession::interrupt()
expression->setStatus(Cantor::Expression::Interrupted);
expressionQueue().clear();
// Cleanup inner state and call octave prompt printing
// If we move this code for interruption to Session, we need add function for
// cleaning before setting Done status
m_output.clear();
m_process->write("\n");
qDebug()<<"done interrupting";
}
......
......@@ -275,5 +275,34 @@ void TestPython2::testCompletion()
QVERIFY(completions.contains(QLatin1String("max")));
}
void TestPython2::testInterrupt()
{
Cantor::Expression* e1=session()->evaluateExpression(QLatin1String("import time; time.sleep(45)"));
Cantor::Expression* e2=session()->evaluateExpression(QLatin1String("2"));
// Wait, because server need time to read input
QTest::qWait(100);
QCOMPARE(e1->status(), Cantor::Expression::Computing);
QCOMPARE(e2->status(), Cantor::Expression::Queued);
while(session()->status() != Cantor::Session::Running)
waitForSignal(session(), SIGNAL(statusChanged(Cantor::Session::Status)));
session()->interrupt();
while(session()->status() != Cantor::Session::Done)
waitForSignal(session(), SIGNAL(statusChanged(Cantor::Session::Status)));
QCOMPARE(e1->status(), Cantor::Expression::Interrupted);
QCOMPARE(e2->status(), Cantor::Expression::Interrupted);
Cantor::Expression* e = evalExp(QLatin1String("2+2"));
QVERIFY(e != nullptr);
QVERIFY(e->result());
QCOMPARE(e->result()->data().toString(), QLatin1String("4"));
}
QTEST_MAIN(TestPython2)
......@@ -47,6 +47,7 @@ class TestPython2 : public BackendTest
void testDictVariable();
void testCompletion();
void testInterrupt();
private:
QString backendName() override;
};
......
......@@ -286,5 +286,35 @@ void TestPython3::testDictVariable()
evalExp(QLatin1String("del d"));
}
void TestPython3::testInterrupt()
{
Cantor::Expression* e1=session()->evaluateExpression(QLatin1String("import time; time.sleep(45)"));
Cantor::Expression* e2=session()->evaluateExpression(QLatin1String("2"));
// Wait, because server need time to read input
QTest::qWait(100);
QCOMPARE(e1->status(), Cantor::Expression::Computing);
QCOMPARE(e2->status(), Cantor::Expression::Queued);
while(session()->status() != Cantor::Session::Running)
waitForSignal(session(), SIGNAL(statusChanged(Cantor::Session::Status)));
session()->interrupt();
while(session()->status() != Cantor::Session::Done)
waitForSignal(session(), SIGNAL(statusChanged(Cantor::Session::Status)));
QCOMPARE(e1->status(), Cantor::Expression::Interrupted);
QCOMPARE(e2->status(), Cantor::Expression::Interrupted);
Cantor::Expression* e = evalExp(QLatin1String("2+2"));
QVERIFY(e != nullptr);
QCOMPARE(e->status(), Cantor::Expression::Done);
QVERIFY(e->result());
QCOMPARE(e->result()->data().toString(), QLatin1String("4"));
}
QTEST_MAIN(TestPython3)
......@@ -47,6 +47,7 @@ class TestPython3 : public BackendTest
void testDictVariable();
void testCompletion();
void testInterrupt();
private:
QString backendName() override;
};
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment