Skip to content
Permalink
Browse files

[processing] Fix GDAL algorithms hang when gdal command is not availa…

…ble to run
  • Loading branch information
nyalldawson committed Feb 21, 2021
1 parent 8f61a3a commit 6d26cb8b50022054cd12593ca0ecf2d8d764d7d0
@@ -129,6 +129,13 @@ After execution completes, the process' result code will be returned.
QProcess::ExitStatus exitStatus() const;
%Docstring
After a call to :py:func:`~QgsBlockingProcess.run`, returns the process' exit status.
%End

QProcess::ProcessError processError() const;
%Docstring
After a call to :py:func:`~QgsBlockingProcess.run`, returns the process' reported error.

Returns QProcess.UnknownError if no error occurred.
%End

};
@@ -150,6 +150,8 @@ def on_stderr(ba):
raise QgsProcessingException(GdalUtils.tr('Process was unexpectedly terminated'))
elif res == 0:
feedback.pushInfo(GdalUtils.tr('Process completed successfully'))
elif proc.processError() == QProcess.FailedToStart:
raise QgsProcessingException(GdalUtils.tr('Process {} failed to start. Either {} is missing, or you may have insufficient permissions to run the program.').format(command, command))
else:
feedback.reportError(GdalUtils.tr('Process returned error code {}').format(res))

@@ -272,8 +272,9 @@ int QgsBlockingProcess::run( QgsFeedback *feedback )

int result = 0;
QProcess::ExitStatus exitStatus = QProcess::NormalExit;
QProcess::ProcessError error = QProcess::UnknownError;

std::function<void()> runFunction = [ this, &result, &exitStatus, feedback]()
std::function<void()> runFunction = [ this, &result, &exitStatus, &error, feedback]()
{
// this function will always be run in worker threads -- either the blocking call is being made in a worker thread,
// or the blocking call has been made from the main thread and we've fired up a new thread for this function
@@ -319,8 +320,16 @@ int QgsBlockingProcess::run( QgsFeedback *feedback )
mStderrHandler( ba );
} );
p.start( mProcess, mArguments, QProcess::Unbuffered | QProcess::ReadWrite );

loop.exec();
if ( !p.waitForStarted() )
{
result = 1;
exitStatus = QProcess::NormalExit;
error = p.error();
}
else
{
loop.exec();
}

mStdoutHandler( p.readAllStandardOutput() );
mStderrHandler( p.readAllStandardError() );
@@ -339,11 +348,17 @@ int QgsBlockingProcess::run( QgsFeedback *feedback )
}

mExitStatus = exitStatus;
mProcessError = error;
return result;
}

QProcess::ExitStatus QgsBlockingProcess::exitStatus() const
{
return mExitStatus;
};

QProcess::ProcessError QgsBlockingProcess::processError() const
{
return mProcessError;
};
#endif // QT_CONFIG(process)
@@ -185,6 +185,13 @@ class CORE_EXPORT QgsBlockingProcess : public QObject
*/
QProcess::ExitStatus exitStatus() const;

/**
* After a call to run(), returns the process' reported error.
*
* Returns QProcess::UnknownError if no error occurred.
*/
QProcess::ProcessError processError() const;

private:

QString mProcess;
@@ -193,6 +200,7 @@ class CORE_EXPORT QgsBlockingProcess : public QObject
std::function< void( const QByteArray & ) > mStderrHandler;

QProcess::ExitStatus mExitStatus = QProcess::NormalExit;
QProcess::ProcessError mProcessError = QProcess::UnknownError;
};

#endif // QT_CONFIG(process)
@@ -113,6 +113,31 @@ def std_err(ba):
self.assertNotEqual(p.run(f), 0)
self.assertEqual(p.exitStatus(), QProcess.CrashExit)

def test_process_no_file(self):
"""
Test a script which doesn't exist
"""

def std_out(ba):
std_out.val += ba.data().decode('UTF-8')

std_out.val = ''

def std_err(ba):
std_err.val += ba.data().decode('UTF-8')

std_err.val = ''

# this program definitely doesn't exist!
p = QgsBlockingProcess('qgis_sucks', ['--version'])
p.setStdOutHandler(std_out)
p.setStdErrHandler(std_err)

f = QgsFeedback()
self.assertEqual(p.run(f), 1)
self.assertEqual(p.exitStatus(), QProcess.NormalExit)
self.assertEqual(p.processError(), QProcess.FailedToStart)

def test_process_env(self):
"""
Test that process inherits system environment correctly

0 comments on commit 6d26cb8

Please sign in to comment.