#4471 Implement python script running and editor in ResInsight GUI, same as Octave.

This commit is contained in:
Gaute Lindkvist 2019-07-26 14:54:54 +02:00
parent 8f464e5e23
commit 3ba962aefb
16 changed files with 200 additions and 61 deletions

View File

@ -899,7 +899,73 @@ QStringList RiaApplication::octaveArguments() const
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
bool RiaApplication::launchProcess(const QString& program, const QStringList& arguments) QProcessEnvironment RiaApplication::octaveProcessEnvironment() const
{
QProcessEnvironment penv = QProcessEnvironment::systemEnvironment();
#ifdef WIN32
// Octave plugins compiled by ResInsight are dependent on Qt (currently Qt 32-bit only)
// Some Octave installations for Windows have included Qt, and some don't. To make sure these plugins always can be
// executed, the path to octave_plugin_dependencies is added to global path
QString pathString = penv.value("PATH", "");
if (pathString == "")
pathString = QApplication::applicationDirPath() + "\\octave_plugin_dependencies";
else
pathString = QApplication::applicationDirPath() + "\\octave_plugin_dependencies" + ";" + pathString;
penv.insert("PATH", pathString);
#else
// Set the LD_LIBRARY_PATH to make the octave plugins find the embedded Qt
QString ldPath = penv.value("LD_LIBRARY_PATH", "");
if (ldPath == "")
ldPath = QApplication::applicationDirPath();
else
ldPath = QApplication::applicationDirPath() + ":" + ldPath;
penv.insert("LD_LIBRARY_PATH", ldPath);
#endif
return penv;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RiaApplication::pythonPath() const
{
return m_preferences->pythonExecutable();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QProcessEnvironment RiaApplication::pythonProcessEnvironment() const
{
QProcessEnvironment penv = QProcessEnvironment::systemEnvironment();
penv.insert("RESINSIGHT_GRPC_PORT", QString("%1").arg(m_grpcServer->portNumber()));
penv.insert("RESINSIGHT_EXECUTABLE", QCoreApplication::applicationFilePath());
QStringList ripsLocations;
#ifdef WIN32
ripsLocations << QCoreApplication::applicationDirPath() + "\\Python"
<< QCoreApplication::applicationDirPath() + "\\..\\..\\Python";
#else
ripsLocations << QCoreApplication::applicationDirPath() + "/Python";
#endif
penv.insert("PYTHONPATH", QString("%1;%2").arg(penv.value("PYTHONPATH")).arg(ripsLocations.join(";")));
return penv;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RiaApplication::launchProcess(const QString& program, const QStringList& arguments, const QProcessEnvironment& processEnvironment)
{ {
if (m_workerProcess == nullptr) if (m_workerProcess == nullptr)
{ {
@ -920,34 +986,7 @@ bool RiaApplication::launchProcess(const QString& program, const QStringList& ar
m_runningWorkerProcess = true; m_runningWorkerProcess = true;
m_workerProcess = new caf::UiProcess(QCoreApplication::instance()); m_workerProcess = new caf::UiProcess(QCoreApplication::instance());
QProcessEnvironment penv = QProcessEnvironment::systemEnvironment(); m_workerProcess->setProcessEnvironment(processEnvironment);
#ifdef WIN32
// Octave plugins compiled by ResInsight are dependent on Qt (currently Qt 32-bit only)
// Some Octave installations for Windows have included Qt, and some don't. To make sure these plugins always can be
// executed, the path to octave_plugin_dependencies is added to global path
QString pathString = penv.value("PATH", "");
if (pathString == "")
pathString = QApplication::applicationDirPath() + "\\octave_plugin_dependencies";
else
pathString = QApplication::applicationDirPath() + "\\octave_plugin_dependencies" + ";" + pathString;
penv.insert("PATH", pathString);
#else
// Set the LD_LIBRARY_PATH to make the octave plugins find the embedded Qt
QString ldPath = penv.value("LD_LIBRARY_PATH", "");
if (ldPath == "")
ldPath = QApplication::applicationDirPath();
else
ldPath = QApplication::applicationDirPath() + ":" + ldPath;
penv.insert("LD_LIBRARY_PATH", ldPath);
#endif
m_workerProcess->setProcessEnvironment(penv);
QCoreApplication::instance()->connect(m_workerProcess, QCoreApplication::instance()->connect(m_workerProcess,
SIGNAL(finished(int, QProcess::ExitStatus)), SIGNAL(finished(int, QProcess::ExitStatus)),
@ -989,7 +1028,8 @@ bool RiaApplication::launchProcess(const QString& program, const QStringList& ar
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
bool RiaApplication::launchProcessForMultipleCases(const QString& program, bool RiaApplication::launchProcessForMultipleCases(const QString& program,
const QStringList& arguments, const QStringList& arguments,
const std::vector<int>& caseIds) const std::vector<int>& caseIds,
const QProcessEnvironment& processEnvironment)
{ {
m_currentCaseIds.clear(); m_currentCaseIds.clear();
std::copy(caseIds.begin(), caseIds.end(), std::back_inserter(m_currentCaseIds)); std::copy(caseIds.begin(), caseIds.end(), std::back_inserter(m_currentCaseIds));
@ -997,7 +1037,7 @@ bool RiaApplication::launchProcessForMultipleCases(const QString& progr
m_currentProgram = program; m_currentProgram = program;
m_currentArguments = arguments; m_currentArguments = arguments;
return launchProcess(m_currentProgram, m_currentArguments); return launchProcess(m_currentProgram, m_currentArguments, processEnvironment);
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------

View File

@ -33,6 +33,7 @@
#include <QApplication> #include <QApplication>
#include <QMutex> #include <QMutex>
#include <QProcess> #include <QProcess>
#include <QProcessEnvironment>
#include <QString> #include <QString>
#include <iostream> #include <iostream>
@ -144,9 +145,13 @@ public:
QString octavePath() const; QString octavePath() const;
QStringList octaveArguments() const; QStringList octaveArguments() const;
QProcessEnvironment octaveProcessEnvironment() const;
bool launchProcess(const QString& program, const QStringList& arguments); QString pythonPath() const;
bool launchProcessForMultipleCases(const QString& program, const QStringList& arguments, const std::vector<int>& caseIds); QProcessEnvironment pythonProcessEnvironment() const;
bool launchProcess(const QString& program, const QStringList& arguments, const QProcessEnvironment& processEnvironment);
bool launchProcessForMultipleCases(const QString& program, const QStringList& arguments, const std::vector<int>& caseIds, const QProcessEnvironment& processEnvironment);
void terminateProcess(); void terminateProcess();
void waitForProcess() const; void waitForProcess() const;

View File

@ -1655,6 +1655,8 @@ void RiaGuiApplication::slotWorkerProcessFinished(int exitCode, QProcess::ExitSt
{ {
m_mainWindow->processMonitor()->stopMonitorWorkProcess(); m_mainWindow->processMonitor()->stopMonitorWorkProcess();
QProcessEnvironment processEnvironment = m_workerProcess->processEnvironment();
// Execute delete later so that other slots that are hooked up // Execute delete later so that other slots that are hooked up
// get a chance to run before we delete the object // get a chance to run before we delete the object
if (m_workerProcess) if (m_workerProcess)
@ -1684,7 +1686,7 @@ void RiaGuiApplication::slotWorkerProcessFinished(int exitCode, QProcess::ExitSt
// If multiple cases are present, invoke launchProcess() which will set next current case, and run script on this case // If multiple cases are present, invoke launchProcess() which will set next current case, and run script on this case
if (!m_currentCaseIds.empty()) if (!m_currentCaseIds.empty())
{ {
launchProcess(m_currentProgram, m_currentArguments); launchProcess(m_currentProgram, m_currentArguments, processEnvironment);
} }
else else
{ {

View File

@ -67,6 +67,10 @@ RiaPreferences::RiaPreferences(void)
CAF_PDM_InitField(&octaveShowHeaderInfoWhenExecutingScripts, "octaveShowHeaderInfoWhenExecutingScripts", false, "Show Text Header When Executing Scripts", "", "", ""); CAF_PDM_InitField(&octaveShowHeaderInfoWhenExecutingScripts, "octaveShowHeaderInfoWhenExecutingScripts", false, "Show Text Header When Executing Scripts", "", "", "");
octaveShowHeaderInfoWhenExecutingScripts.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::HIDDEN); octaveShowHeaderInfoWhenExecutingScripts.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::HIDDEN);
CAF_PDM_InitField(&pythonExecutable, "pythonExecutable", QString("python"), "Python Executable Location", "", "", "");
pythonExecutable.uiCapability()->setUiEditorTypeName(caf::PdmUiFilePathEditor::uiEditorTypeName());
pythonExecutable.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::TOP);
CAF_PDM_InitField(&ssihubAddress, "ssihubAddress", QString("http://"), "SSIHUB Address", "", "", ""); CAF_PDM_InitField(&ssihubAddress, "ssihubAddress", QString("http://"), "SSIHUB Address", "", "", "");
ssihubAddress.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::TOP); ssihubAddress.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::TOP);
@ -273,6 +277,9 @@ void RiaPreferences::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering&
octaveGroup->add(&octaveExecutable); octaveGroup->add(&octaveExecutable);
octaveGroup->add(&octaveShowHeaderInfoWhenExecutingScripts); octaveGroup->add(&octaveShowHeaderInfoWhenExecutingScripts);
caf::PdmUiGroup* pythonGroup = uiOrdering.addNewGroup("Python");
pythonGroup->add(&pythonExecutable);
caf::PdmUiGroup* scriptGroup = uiOrdering.addNewGroup("Script files"); caf::PdmUiGroup* scriptGroup = uiOrdering.addNewGroup("Script files");
scriptGroup->add(&scriptDirectories); scriptGroup->add(&scriptDirectories);
scriptGroup->add(&scriptEditorExecutable); scriptGroup->add(&scriptEditorExecutable);

View File

@ -77,6 +77,8 @@ public: // Pdm Fields
caf::PdmField<QString> octaveExecutable; caf::PdmField<QString> octaveExecutable;
caf::PdmField<bool> octaveShowHeaderInfoWhenExecutingScripts; caf::PdmField<bool> octaveShowHeaderInfoWhenExecutingScripts;
caf::PdmField<QString> pythonExecutable;
caf::PdmField<QString> ssihubAddress; caf::PdmField<QString> ssihubAddress;
caf::PdmField<caf::AppEnum<RiaDefines::MeshModeType>> defaultMeshModeType; caf::PdmField<caf::AppEnum<RiaDefines::MeshModeType>> defaultMeshModeType;

View File

@ -65,11 +65,11 @@ RicfCommandResponse RicfRunOctaveScript::execute()
bool ok; bool ok;
if (caseIds.empty()) if (caseIds.empty())
{ {
ok = RiaApplication::instance()->launchProcess(octavePath, processArguments); ok = RiaApplication::instance()->launchProcess(octavePath, processArguments, RiaApplication::instance()->octaveProcessEnvironment());
} }
else else
{ {
ok = RiaApplication::instance()->launchProcessForMultipleCases(octavePath, processArguments, caseIds); ok = RiaApplication::instance()->launchProcessForMultipleCases(octavePath, processArguments, caseIds, RiaApplication::instance()->octaveProcessEnvironment());
} }
RicfCommandResponse response; RicfCommandResponse response;

View File

@ -56,12 +56,23 @@ void RicExecuteScriptFeature::onActionTriggered(bool isChecked)
RimCalcScript* calcScript = selection[0]; RimCalcScript* calcScript = selection[0];
RiaApplication* app = RiaApplication::instance(); RiaApplication* app = RiaApplication::instance();
QString octavePath = app->octavePath(); if (calcScript->scriptType() == RimCalcScript::OCTAVE)
if (!octavePath.isEmpty())
{ {
QStringList arguments = RimCalcScript::createCommandLineArguments(calcScript->absoluteFileName()); QString octavePath = app->octavePath();
if (!octavePath.isEmpty())
RiaApplication::instance()->launchProcess(octavePath, arguments); {
QStringList arguments = RimCalcScript::createCommandLineArguments(calcScript->absoluteFileName());
RiaApplication::instance()->launchProcess(octavePath, arguments, app->octaveProcessEnvironment());
}
}
else if (calcScript->scriptType() == RimCalcScript::PYTHON)
{
QString pythonPath = app->pythonPath();
if (!pythonPath.isEmpty())
{
QStringList arguments = RimCalcScript::createCommandLineArguments(calcScript->absoluteFileName());
RiaApplication::instance()->launchProcess(pythonPath, arguments, app->pythonProcessEnvironment());
}
} }
} }

View File

@ -80,7 +80,7 @@ void RicExecuteScriptForCasesFeature::onActionTriggered(bool isChecked)
if (caseIdsInSelection.size() > 0) if (caseIdsInSelection.size() > 0)
{ {
RiaApplication::instance()->launchProcessForMultipleCases(octavePath, arguments, caseIdsInSelection); RiaApplication::instance()->launchProcessForMultipleCases(octavePath, arguments, caseIdsInSelection, app->octaveProcessEnvironment());
} }
} }
} }

View File

@ -48,6 +48,31 @@ RimCalcScript::RimCalcScript()
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
RimCalcScript::~RimCalcScript() {} RimCalcScript::~RimCalcScript() {}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimCalcScript::ScriptType RimCalcScript::scriptType(const QString& absoluteFileNameScript)
{
QFileInfo fileInfo(absoluteFileNameScript);
if (fileInfo.suffix() == "py")
{
return PYTHON;
}
else if (fileInfo.suffix() == "m")
{
return OCTAVE;
}
return UNKNOWN;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimCalcScript::ScriptType RimCalcScript::scriptType() const
{
return scriptType(absoluteFileName());
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -55,20 +80,27 @@ QStringList RimCalcScript::createCommandLineArguments(const QString& absoluteFil
{ {
QStringList arguments; QStringList arguments;
if (scriptType(absoluteFileNameScript) == PYTHON)
{ {
auto app = RiaApplication::instance(); arguments.append(absoluteFileNameScript);
arguments = app->octaveArguments();
arguments.append("--path");
} }
else if (scriptType(absoluteFileNameScript) == OCTAVE)
{ {
QFileInfo fi(absoluteFileNameScript); {
QString octaveFunctionSearchPath = fi.absolutePath(); auto app = RiaApplication::instance();
QString absFilePath = fi.absoluteFilePath();
arguments << octaveFunctionSearchPath; arguments = app->octaveArguments();
arguments << absFilePath; arguments.append("--path");
}
{
QFileInfo fi(absoluteFileNameScript);
QString octaveFunctionSearchPath = fi.absolutePath();
QString absFilePath = fi.absoluteFilePath();
arguments << octaveFunctionSearchPath;
arguments << absFilePath;
}
} }
bool debugPrintArgumentText = false; bool debugPrintArgumentText = false;
@ -76,8 +108,19 @@ QStringList RimCalcScript::createCommandLineArguments(const QString& absoluteFil
{ {
QString argumentString = arguments.join(" "); QString argumentString = arguments.join(" ");
RiaLogging::info("Octave arguments : " + argumentString); RiaLogging::info("Scriptarguments : " + argumentString);
} }
return arguments; return arguments;
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimCalcScript::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName /*= ""*/)
{
if (scriptType() == PYTHON)
{
uiCapability()->setUiIconFromResourceString(":/PythonScriptFile16x16.png");
}
}

View File

@ -30,11 +30,25 @@ class RimCalcScript : public caf::PdmObject
CAF_PDM_HEADER_INIT; CAF_PDM_HEADER_INIT;
public: public:
enum ScriptType
{
OCTAVE = 0,
PYTHON = 1,
UNKNOWN = 2
};
RimCalcScript(); RimCalcScript();
~RimCalcScript() override; ~RimCalcScript() override;
ScriptType scriptType() const;
static ScriptType scriptType(const QString& fileName);
static QStringList createCommandLineArguments(const QString& absoluteFileNameScript); static QStringList createCommandLineArguments(const QString& absoluteFileNameScript);
caf::PdmField<QString> absoluteFileName; caf::PdmField<QString> absoluteFileName;
caf::PdmField<QString> content; // TODO: Obsolete field, can be deleted on next project file revision. caf::PdmField<QString> content; // TODO: Obsolete field, can be deleted on next project file revision.
protected:
void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "") override;
}; };

View File

@ -96,7 +96,7 @@ void RimCommandExecuteScript::redo()
arguments.append("--eval"); arguments.append("--eval");
arguments << this->scriptText(); arguments << this->scriptText();
RiaApplication::instance()->launchProcess(octavePath, arguments); RiaApplication::instance()->launchProcess(octavePath, arguments, app->octaveProcessEnvironment());
} }
} }

View File

@ -81,8 +81,8 @@ void RimScriptCollection::readContentFromDisc()
// Build a list of all scripts in the specified directory // Build a list of all scripts in the specified directory
{ {
QString filter = "*.m"; QStringList nameFilters; nameFilters << "*.m" << "*.py";
QStringList fileList = caf::Utils::getFilesInDirectory(directory, filter, true); QStringList fileList = caf::Utils::getFilesInDirectory(directory, nameFilters, true);
int i; int i;
for (i = 0; i < fileList.size(); i++) for (i = 0; i < fileList.size(); i++)

Binary file not shown.

After

Width:  |  Height:  |  Size: 802 B

View File

@ -23,6 +23,7 @@
<file>WellCollection.png</file> <file>WellCollection.png</file>
<file>octave.png</file> <file>octave.png</file>
<file>OctaveScriptFile16x16.png</file> <file>OctaveScriptFile16x16.png</file>
<file>PythonScriptFile16x16.png</file>
<file>Folder.png</file> <file>Folder.png</file>
<file>EclipseInput48x48.png</file> <file>EclipseInput48x48.png</file>
<file>Cases16x16.png</file> <file>Cases16x16.png</file>

View File

@ -80,18 +80,32 @@ QString Utils::absoluteFileName(const QString& fileName)
return QDir::toNativeSeparators(fi.absoluteFilePath()); return QDir::toNativeSeparators(fi.absoluteFilePath());
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QStringList Utils::getFilesInDirectory(const QString& dirPath,
const QString& nameFilter,
bool getAbsoluteFileNames)
{
QStringList nameFilters; nameFilters << nameFilter;
return getFilesInDirectory(dirPath, nameFilters, getAbsoluteFileNames);
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
QStringList Utils::getFilesInDirectory(const QString& dirPath, const QString& filter, bool getAbsoluteFileNames) QStringList Utils::getFilesInDirectory(const QString& dirPath, const QStringList& nameFilters, bool getAbsoluteFileNames)
{ {
QDir::SortFlags sortFlags = QDir::SortFlags(QDir::Name | QDir::IgnoreCase); QDir::SortFlags sortFlags = QDir::SortFlags(QDir::Name | QDir::IgnoreCase);
// Only get files // Only get files
QDir::Filters filters = QDir::Files; QDir::Filters typeFilter = QDir::Files;
QDir dir(dirPath, filter, sortFlags, filters); QDir dir(dirPath);
dir.setFilter(typeFilter);
dir.setNameFilters(nameFilters);
dir.setSorting(sortFlags);
QFileInfoList fileInfoList = dir.entryInfoList(); QFileInfoList fileInfoList = dir.entryInfoList();
@ -110,7 +124,6 @@ QStringList Utils::getFilesInDirectory(const QString& dirPath, const QString& fi
return retFileNames; return retFileNames;
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------

View File

@ -56,7 +56,8 @@ public:
static double editToDouble(QLineEdit* lineEdit, double defaultVal); static double editToDouble(QLineEdit* lineEdit, double defaultVal);
static QString absoluteFileName(const QString& fileName); static QString absoluteFileName(const QString& fileName);
static QStringList getFilesInDirectory(const QString& dirPath, const QString& filter, bool getAbsoluteFileNames); static QStringList getFilesInDirectory(const QString& dirPath, const QString& nameFilter, bool getAbsoluteFileNames);
static QStringList getFilesInDirectory(const QString& dirPath, const QStringList& nameFilters, bool getAbsoluteFileNames);
static QString constructFullFileName(const QString& folder, const QString& baseFileName, const QString& extension); static QString constructFullFileName(const QString& folder, const QString& baseFileName, const QString& extension);
static QString makeValidFileBasename(const QString& fileBasenameCandidate); static QString makeValidFileBasename(const QString& fileBasenameCandidate);