Commit bab221e2 authored by Nikita Sirgienko's avatar Nikita Sirgienko
Browse files

[Python] Add PythonVariableModel

parent 26d0155c
......@@ -3,6 +3,7 @@ set( PythonBackend_SRCS
pythonsession.cpp
pythonexpression.cpp
pythonkeywords.cpp
pythonvariablemodel.cpp
pythonhighlighter.cpp
pythoncompletionobject.cpp
pythonextensions.cpp
......
......@@ -99,6 +99,7 @@ void PythonCompletionObject::extractCompletions(Cantor::Expression::Status statu
{
if (!m_expression)
return;
switch(status)
{
case Cantor::Expression::Error:
......
......@@ -143,20 +143,12 @@ void PythonHighlighter::highlightBlock(const QString &text)
setCurrentBlockState(state);
}
void PythonHighlighter::updateHighlight()
void PythonHighlighter::addUserVariable(const QStringList& variables)
{
addVariables(m_variables);
rehighlight();
addVariables(variables);
}
void PythonHighlighter::addVariable(const QString variable)
void PythonHighlighter::removeUserVariable(const QStringList& variables)
{
m_variables << variable;
}
void PythonHighlighter::clearVariables()
{
removeRules(m_variables);
m_variables.clear();
rehighlight();
removeRules(variables);
}
......@@ -32,9 +32,8 @@ class PythonHighlighter : public Cantor::DefaultHighlighter
~PythonHighlighter() override = default;
public Q_SLOTS:
void updateHighlight();
void addVariable(const QString variable);
void clearVariables();
void addUserVariable(const QStringList& variables);
void removeUserVariable(const QStringList& variables);
protected:
void highlightBlock(const QString& text) override;
......@@ -42,8 +41,6 @@ class PythonHighlighter : public Cantor::DefaultHighlighter
private:
QRegExp commentStartExpression;
QRegExp commentEndExpression;
QStringList m_variables;
};
#endif /* _PYTHONHIGHLIGHTER_H */
......@@ -144,4 +144,59 @@ void PythonServer::setFilePath(const QString& path)
PyRun_SimpleString(("__file__ = '"+path.toStdString()+"'").c_str());
}
QString PythonServer::variables() const
{
// FIXME: This code allows get full form of numpy array, but for big arrays it's could cause performonce problems
// especially for displaying in variables panel
// So, uncomment this, when fix this problem
/*
"try: \n"
" import numpy \n"
" __cantor_numpy_internal__ = numpy.get_printoptions()['threshold'] \n"
" numpy.set_printoptions(threshold=100000000) \n"
"except ModuleNotFoundError: \n"
" pass \n"
"try: \n"
" import numpy \n"
" numpy.set_printoptions(threshold=__cantor_numpy_internal__) \n"
" del __cantor_numpy_internal__ \n"
"except ModuleNotFoundError: \n"
" pass \n"
*/
PyRun_SimpleString("__tmp_globals__ = globals()");
PyObject* globals = PyObject_GetAttrString(m_pModule,"__tmp_globals__");
PyObject *key, *value;
Py_ssize_t pos = 0;
QStringList vars;
const QChar sep(30); // INFORMATION SEPARATOR TWO
while (PyDict_Next(globals, &pos, &key, &value)) {
const QString& keyString = pyObjectToQString(key);
if (keyString.startsWith(QLatin1String("__")))
continue;
if (keyString == QLatin1String("CatchOutPythonBackend")
|| keyString == QLatin1String("errorPythonBackend")
|| keyString == QLatin1String("outputPythonBackend"))
continue;
if (PyModule_Check(value))
continue;
if (PyFunction_Check(value))
continue;
if (PyType_Check(value))
continue;
const QString& valueString = pyObjectToQString(PyObject_Repr(value));
vars.append(keyString + QChar(31) + valueString);
}
return vars.join(sep);
}
......@@ -38,6 +38,7 @@ class PythonServer : public QObject
Q_SCRIPTABLE void runPythonCommand(const QString& command) const;
Q_SCRIPTABLE QString getOutput() const;
Q_SCRIPTABLE QString getError() const;
Q_SCRIPTABLE QString variables() const;
private:
PyObject* m_pModule;
......
......@@ -21,6 +21,7 @@
#include "pythonsession.h"
#include "pythonexpression.h"
#include "pythonvariablemodel.h"
#include "pythonhighlighter.h"
#include "pythoncompletionobject.h"
#include "pythonkeywords.h"
......@@ -43,13 +44,14 @@
PythonSession::PythonSession(Cantor::Backend* backend, int pythonVersion, const QString serverName, const QString DbusChannelName)
: Session(backend)
, m_variableModel(new Cantor::DefaultVariableModel(this))
, m_variableModel(new PythonVariableModel(this))
, m_currentExpression(nullptr)
, m_pIface(nullptr)
, m_pProcess(nullptr)
, serverName(serverName)
, DbusChannelName(DbusChannelName)
, m_pythonVersion(pythonVersion)
, m_needUpdate(false)
{
}
......@@ -98,6 +100,8 @@ void PythonSession::login()
return;
}
m_variableModel->setPythonServer(m_pIface);
m_pIface->call(QString::fromLatin1("login"));
m_pIface->call(QString::fromLatin1("setFilePath"), worksheetPath);
......@@ -105,14 +109,13 @@ void PythonSession::login()
if(!scripts.isEmpty()){
QString autorunScripts = scripts.join(QLatin1String("\n"));
getPythonCommandOutput(autorunScripts);
m_variableModel->update();
}
const QString& importerFile = QLatin1String(":py/import_default_modules.py");
evaluateExpression(fromSource(importerFile), Cantor::Expression::DeleteOnFinish, true);
listVariables();
changeStatus(Session::Done);
emit loginDone();
}
......@@ -123,7 +126,6 @@ void PythonSession::logout()
m_pProcess->terminate();
m_variableModel->clearVariables();
emit clearVariables();
qDebug()<<"logout";
changeStatus(Status::Disable);
......@@ -283,6 +285,7 @@ void PythonSession::expressionFinished()
void PythonSession::updateOutput()
{
m_needUpdate |= !m_currentExpression->isInternal();
if(m_error.isEmpty()){
m_currentExpression->parseOutput(m_output);
......@@ -293,7 +296,11 @@ void PythonSession::updateOutput()
qDebug() << "error: " << m_error;
}
listVariables();
if (m_needUpdate)
{
m_variableModel->update();
m_needUpdate = false;
}
changeStatus(Cantor::Session::Done);
}
......@@ -307,60 +314,11 @@ void PythonSession::readOutput(const QString& commandProcessing)
updateOutput();
}
void PythonSession::listVariables()
{
const QString& listVariableCommand = QLatin1String(
"try: \n"
" import numpy \n"
" __cantor_numpy_internal__ = numpy.get_printoptions()['threshold'] \n"
" numpy.set_printoptions(threshold=100000000) \n"
"except ModuleNotFoundError: \n"
" pass \n"
"print(globals()) \n"
"try: \n"
" import numpy \n"
" numpy.set_printoptions(threshold=__cantor_numpy_internal__) \n"
" del __cantor_numpy_internal__ \n"
"except ModuleNotFoundError: \n"
" pass \n"
);
getPythonCommandOutput(listVariableCommand);
qDebug() << m_output;
m_output.remove(QLatin1String("{"));
m_output.remove(QLatin1String("<"));
m_output.remove(QLatin1String(">"));
m_output.remove(QLatin1String("}"));
foreach(QString line, m_output.split(QLatin1String(", '"))){
QStringList parts = line.simplified().split(QLatin1String(":"));
const QString& first = parts.first();
const QString& last = parts.last();
if(!first.startsWith(QLatin1String("'__")) && !first.startsWith(QLatin1String("__")) && !first.startsWith(QLatin1String("CatchOutPythonBackend'")) &&
!first.startsWith(QLatin1String("errorPythonBackend'")) && !first.startsWith(QLatin1String("outputPythonBackend'")) &&
!last.startsWith(QLatin1String(" class ")) && !last.startsWith(QLatin1String(" function ")) &&
!last.startsWith(QLatin1String(" module '")) /*skip imported modules*/ )
{
m_variableModel->addVariable(parts.first().remove(QLatin1String("'")).simplified(), parts.last().simplified());
emit newVariable(parts.first().remove(QLatin1String("'")).simplified());
}
}
emit updateHighlighter();
}
QSyntaxHighlighter* PythonSession::syntaxHighlighter(QObject* parent)
{
PythonHighlighter* highlighter = new PythonHighlighter(parent, m_pythonVersion);
QObject::connect(this, SIGNAL(updateHighlighter()), highlighter, SLOT(updateHighlight()));
QObject::connect(this, SIGNAL(newVariable(QString)), highlighter, SLOT(addVariable(QString)));
connect(this, &PythonSession::clearVariables, highlighter, &PythonHighlighter::clearVariables);
connect ( m_variableModel, &Cantor::DefaultVariableModel::variablesAdded, highlighter, &PythonHighlighter::addUserVariable);
connect ( m_variableModel, &Cantor::DefaultVariableModel::variablesRemoved, highlighter, &PythonHighlighter::removeUserVariable);
return highlighter;
}
......
......@@ -26,11 +26,8 @@
#include <cantor_pythonbackend_export.h>
#include <QStringList>
namespace Cantor {
class DefaultVariableModel;
}
class PythonExpression;
class PythonVariableModel;
class KDirWatch;
class QDBusInterface;
class KProcess;
......@@ -58,7 +55,7 @@ class CANTOR_PYTHONBACKEND_EXPORT PythonSession : public Cantor::Session
virtual QStringList autorunScripts() const = 0;
private:
Cantor::DefaultVariableModel* m_variableModel;
PythonVariableModel* m_variableModel;
QList<PythonExpression*> m_runningExpressions;
PythonExpression* m_currentExpression;
......@@ -71,13 +68,13 @@ class CANTOR_PYTHONBACKEND_EXPORT PythonSession : public Cantor::Session
QString worksheetPath;
int m_pythonVersion;
bool m_needUpdate;
protected:
QString m_output;
QString m_error;
private:
void listVariables();
void getPythonCommandOutput(const QString& commandProcessing);
QString identifyPythonModule(const QString& command) const;
......@@ -96,11 +93,6 @@ class CANTOR_PYTHONBACKEND_EXPORT PythonSession : public Cantor::Session
private Q_SLOTS:
void readOutput(const QString& commandProcessing);
void expressionFinished();
Q_SIGNALS:
void updateHighlighter();
void newVariable(const QString variable);
void clearVariables();
};
#endif /* _PYTHONSESSION_H */
/*
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) 2018 Nikita Sirgienko <warquark@gmail.com>
*/
#include "pythonvariablemodel.h"
#include "pythonsession.h"
#include "textresult.h"
#include <QDebug>
#include <QDBusReply>
#include <QDBusInterface>
#include <QString>
using namespace Cantor;
PythonVariableModel::PythonVariableModel(PythonSession* session):
DefaultVariableModel(session),
m_pIface(nullptr)
{
}
void PythonVariableModel::setPythonServer(QDBusInterface* pIface)
{
m_pIface = pIface;
}
void PythonVariableModel::update()
{
if (!m_pIface)
return;
const QString& data = QDBusReply<QString>(m_pIface->call(QString::fromLatin1("variables"))).value();
const QStringList& records = data.split(QChar(30), QString::SkipEmptyParts);
QList<Variable> variables;
for (const QString& record : records)
{
const QString& name = record.section(QChar(31), 0, 0);
const QString& value = record.section(QChar(31), 1, 1);
variables << Variable{name, value};
}
setVariables(variables);
}
/*
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) 2019 Nikita Sirgienko <warquark@gmail.com>
*/
#ifndef _PYTHONVARIABLEMODEL_H
#define _PYTHONVARIABLEMODEL_H
#include "defaultvariablemodel.h"
class PythonSession;
class QDBusInterface;
class PythonVariableModel : public Cantor::DefaultVariableModel
{
public:
PythonVariableModel( PythonSession* session);
~PythonVariableModel() override = default;
void update() override;
void setPythonServer(QDBusInterface* pIface);
private:
QDBusInterface* m_pIface;
};
#endif /* _PYTHONVARIABLEMODEL_H */
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