Skip to content

Commit

Permalink
Merge pull request #4721 from nyalldawson/processing_pt31
Browse files Browse the repository at this point in the history
[processing] Restore batch mode
  • Loading branch information
nyalldawson committed Jun 13, 2017
2 parents b6e75be + 54124bd commit a3b64e2
Show file tree
Hide file tree
Showing 14 changed files with 306 additions and 109 deletions.
23 changes: 23 additions & 0 deletions python/core/processing/qgsprocessingoutputs.sip
Expand Up @@ -36,6 +36,8 @@ class QgsProcessingOutputDefinition
sipType = sipType_QgsProcessingOutputHtml;
else if ( sipCpp->type() == "outputNumber" )
sipType = sipType_QgsProcessingOutputNumber;
else if ( sipCpp->type() == "outputString" )
sipType = sipType_QgsProcessingOutputString;
%End
public:

Expand Down Expand Up @@ -184,6 +186,27 @@ class QgsProcessingOutputNumber : QgsProcessingOutputDefinition
virtual QString type() const;
};

class QgsProcessingOutputString : QgsProcessingOutputDefinition
{
%Docstring
A string output for processing algorithms.
.. versionadded:: 3.0
%End

%TypeHeaderCode
#include "qgsprocessingoutputs.h"
%End
public:

QgsProcessingOutputString( const QString &name, const QString &description = QString() );
%Docstring
Constructor for QgsProcessingOutputString.
%End

virtual QString type() const;
};




/************************************************************************
Expand Down
28 changes: 28 additions & 0 deletions python/core/processing/qgsprocessingparameters.sip
Expand Up @@ -175,6 +175,8 @@ class QgsProcessingParameterDefinition
sipType = sipType_QgsProcessingParameterRasterOutput;
else if ( sipCpp->type() == "fileOut" )
sipType = sipType_QgsProcessingParameterFileOutput;
else if ( sipCpp->type() == "folderOut" )
sipType = sipType_QgsProcessingParameterFolderOutput;
%End
public:

Expand Down Expand Up @@ -1344,6 +1346,32 @@ class QgsProcessingParameterFileOutput : QgsProcessingParameterDefinition

};

class QgsProcessingParameterFolderOutput : QgsProcessingParameterDefinition
{
%Docstring
A folder output parameter.
.. versionadded:: 3.0
%End

%TypeHeaderCode
#include "qgsprocessingparameters.h"
%End
public:

QgsProcessingParameterFolderOutput( const QString &name, const QString &description = QString(),
const QVariant &defaultValue = QVariant(),
bool optional = false );
%Docstring
Constructor for QgsProcessingParameterFolderOutput.
%End

virtual QString type() const;
virtual bool isDestination() const;
virtual bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = 0 ) const;


};



/************************************************************************
Expand Down
15 changes: 8 additions & 7 deletions python/plugins/processing/core/GeoAlgorithm.py
Expand Up @@ -330,7 +330,7 @@ def executeAlgorithm(alg, parameters, context=None, feedback=None, model=None):
context = dataobjects.createContext()

#self.model = model
if True:
try:
#self.setOutputCRS()
#self.resolveOutputs()
#self.evaluateParameterValues()
Expand All @@ -341,12 +341,13 @@ def executeAlgorithm(alg, parameters, context=None, feedback=None, model=None):
return result
#self.convertUnsupportedFormats(context, feedback)
#self.runPostExecutionScript(feedback)
#except GeoAlgorithmExecutionException as gaee:
#lines = [self.tr('Error while executing algorithm')]
# lines = []
# lines.append(traceback.format_exc())
#QgsMessageLog.logMessage(gaee.msg, self.tr('Processing'), QgsMessageLog.CRITICAL)
#raise GeoAlgorithmExecutionException(gaee.msg, lines, gaee)
except GeoAlgorithmExecutionException as gaee:
lines = [self.tr('Error while executing algorithm')]
lines = []
lines.append(traceback.format_exc())
feedback.reportError(gaee.msg)
QgsMessageLog.logMessage(gaee.msg, self.tr('Processing'), QgsMessageLog.CRITICAL)
raise GeoAlgorithmExecutionException(gaee.msg, lines, gaee)
#except Exception as e:
# If something goes wrong and is not caught in the
# algorithm, we catch it here and wrap it
Expand Down
4 changes: 0 additions & 4 deletions python/plugins/processing/gui/AlgorithmDialog.py
Expand Up @@ -251,10 +251,6 @@ def accept(self):

self.buttonCancel.setEnabled(False)
self.finish(result, context, feedback)
#TODO
#else:
# QApplication.restoreOverrideCursor()
# self.resetGUI()
except AlgorithmDialogBase.InvalidParameterValue as e:
try:
self.buttonBox.accepted.connect(lambda e=e:
Expand Down
9 changes: 6 additions & 3 deletions python/plugins/processing/gui/AutofillDialog.py
Expand Up @@ -44,10 +44,13 @@ class AutofillDialog(BASE, WIDGET):
def __init__(self, alg):
super(AutofillDialog, self).__init__(None)
self.setupUi(self)
self.mode = None
self.param_index = None
self.alg = alg

self.cmbFillType.currentIndexChanged.connect(self.toggleParameters)

for param in alg.parameterDefinitions():
for param in self.alg.parameterDefinitions():
self.cmbParameters.addItem(param.description())

def toggleParameters(self, index):
Expand All @@ -60,10 +63,10 @@ def toggleParameters(self, index):

def accept(self):
self.mode = self.cmbFillType.currentIndex()
self.param = self.cmbParameters.currentIndex()
self.param_index = self.cmbParameters.currentIndex()
QDialog.accept(self)

def reject(self):
self.mode = None
self.param = None
self.param_index = None
QDialog.reject(self)
126 changes: 74 additions & 52 deletions python/plugins/processing/gui/BatchAlgorithmDialog.py
Expand Up @@ -26,23 +26,29 @@

__revision__ = '$Format:%H$'

from pprint import pformat
import time

from qgis.PyQt.QtWidgets import QApplication, QMessageBox, QSizePolicy
from qgis.PyQt.QtGui import QCursor
from qgis.PyQt.QtCore import Qt

from qgis.core import QgsProcessingParameterDefinition
from qgis.core import (QgsProcessingParameterDefinition,
QgsProcessingParameterRasterOutput,
QgsProcessingParameterFeatureSink,
QgsProcessingOutputLayerDefinition,
QgsProcessingOutputHtml,
QgsProcessingOutputNumber,
QgsProject)

from qgis.gui import QgsMessageBar

from processing.gui.BatchPanel import BatchPanel
from processing.gui.AlgorithmDialogBase import AlgorithmDialogBase
from processing.gui.AlgorithmExecutor import execute
from processing.gui.Postprocessing import handleAlgorithmResults

from processing.core.ProcessingResults import ProcessingResults

from processing.core.outputs import OutputNumber
from processing.core.outputs import OutputString
from processing.core.outputs import OutputHTML
from processing.core.ProcessingResults import resultsList

from processing.tools.system import getTempFilename
from processing.tools import dataobjects
Expand All @@ -56,7 +62,6 @@ def __init__(self, alg):
AlgorithmDialogBase.__init__(self, alg)

self.alg = alg
self.alg_parameters = []

self.setWindowTitle(self.tr('Batch Processing - {0}').format(self.alg.displayName()))

Expand All @@ -69,11 +74,11 @@ def __init__(self, alg):
self.layout().insertWidget(0, self.bar)

def accept(self):
self.alg_parameters = []
self.load = []
self.canceled = False
alg_parameters = []
load = []

context = dataobjects.createContext()
feedback = self.createFeedback()

for row in range(self.mainWidget.tblParameters.rowCount()):
col = 0
Expand All @@ -87,82 +92,99 @@ def accept(self):
self.bar.pushMessage("", self.tr('Wrong or missing parameter value: {0} (row {1})').format(
param.description(), row + 1),
level=QgsMessageBar.WARNING, duration=5)
self.algs = None
return
col += 1
for out in alg.destinationParameterDefinitions():
count_visible_outputs = 0
for out in self.alg.destinationParameterDefinitions():
if out.flags() & QgsProcessingParameterDefinition.FlagHidden:
continue

count_visible_outputs += 1
widget = self.mainWidget.tblParameters.cellWidget(row, col)
text = widget.getValue()
if text.strip() != '':
out.value = text
if param.checkValueIsAcceptable(text, context):
if isinstance(out, (QgsProcessingParameterRasterOutput,
QgsProcessingParameterFeatureSink)):
# load rasters and sinks on completion
parameters[out.name()] = QgsProcessingOutputLayerDefinition(text, context.project())
else:
parameters[out.name()] = text
col += 1
else:
self.bar.pushMessage("", self.tr('Wrong or missing output value: {0} (row {1})').format(
out.description(), row + 1),
level=QgsMessageBar.WARNING, duration=5)
self.algs = None
return

self.alg_parameters.append(parameters)
if self.alg.countVisibleOutputs():
widget = self.mainWidget.tblParameters.cellWidget(row, col)
self.load.append(widget.currentIndex() == 0)
else:
self.load.append(False)
alg_parameters.append(parameters)

QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
self.mainWidget.setEnabled(False)
self.buttonCancel.setEnabled(True)

self.progressBar.setMaximum(len(self.algs))
# Make sure the Log tab is visible before executing the algorithm
try:
self.tabWidget.setCurrentIndex(1)
self.repaint()
except:
pass

for count, parameters in enumerate(self.alg_parameters):
self.setText(self.tr('\nProcessing algorithm {0}/{1}...').format(count + 1, len(self.alg_parameters)))
start_time = time.time()

algorithm_results = []
for count, parameters in enumerate(alg_parameters):
if feedback.isCanceled():
break
self.setText(self.tr('\nProcessing algorithm {0}/{1}...').format(count + 1, len(alg_parameters)))
self.setInfo(self.tr('<b>Algorithm {0} starting...</b>').format(self.alg.displayName()), escape_html=False)
ret, results = execute(self.alg, parameters, context, self.feedback)
if ret and not self.canceled:
if self.load[count]:
handleAlgorithmResults(self.alg, context, self.feedback, False)

feedback.pushInfo(self.tr('Input parameters:'))
feedback.pushCommandInfo(pformat(parameters))
feedback.pushInfo('')

alg_start_time = time.time()
ret, results = execute(self.alg, parameters, context, feedback)
if ret:
self.setInfo(self.tr('Algorithm {0} correctly executed...').format(self.alg.displayName()), escape_html=False)
feedback.setProgress(100)
feedback.pushInfo(
self.tr('Execution completed in {0:0.2f} seconds'.format(time.time() - alg_start_time)))
feedback.pushInfo(self.tr('Results:'))
feedback.pushCommandInfo(pformat(results))
feedback.pushInfo('')
algorithm_results.append(results)
else:
QApplication.restoreOverrideCursor()
return
break

self.finish()
feedback.pushInfo(self.tr('Batch execution completed in {0:0.2f} seconds'.format(time.time() - start_time)))

def finish(self):
for count, parameters in enumerate(self.alg_parameters):
self.loadHTMLResults(self.alg, count)
handleAlgorithmResults(self.alg, context, feedback, False)

self.createSummaryTable()
self.finish(algorithm_results)
self.buttonCancel.setEnabled(False)

def finish(self, algorithm_results):
for count, results in enumerate(algorithm_results):
self.loadHTMLResults(results, count)

self.createSummaryTable(algorithm_results)
QApplication.restoreOverrideCursor()

self.mainWidget.setEnabled(True)
QMessageBox.information(self, self.tr('Batch processing'),
self.tr('Batch processing completed'))

def loadHTMLResults(self, alg, num):
for out in alg.outputs:
if out.flags() & QgsProcessingParameterDefinition.FlagHidden or not out.open:
continue

if isinstance(out, OutputHTML):
ProcessingResults.addResult(
'{} [{}]'.format(out.description(), num), out.value)
def loadHTMLResults(self, results, num):
for out in self.alg.outputDefinitions():
if isinstance(out, QgsProcessingOutputHtml) and out.name() in results and results[out.name()]:
resultsList.addResult(icon=self.alg.icon(), name='{} [{}]'.format(out.description(), num),
result=results[out.name()])

def createSummaryTable(self):
def createSummaryTable(self, algorithm_results):
createTable = False

for out in self.algs[0].outputs:
if isinstance(out, (OutputNumber, OutputString)):
for out in self.alg.outputDefinitions():
if isinstance(out, (QgsProcessingOutputNumber, QgsProcessingOutputString)):
createTable = True
break

Expand All @@ -171,12 +193,12 @@ def createSummaryTable(self):

outputFile = getTempFilename('html')
with codecs.open(outputFile, 'w', encoding='utf-8') as f:
for alg in self.algs:
for res in algorithm_results:
f.write('<hr>\n')
for out in alg.outputs:
if isinstance(out, (OutputNumber, OutputString)):
f.write('<p>{}: {}</p>\n'.format(out.description(), out.value))
for out in self.alg.outputDefinitions():
if isinstance(out, (QgsProcessingOutputNumber, QgsProcessingOutputString)) and out.name() in res:
f.write('<p>{}: {}</p>\n'.format(out.description(), res[out.name()]))
f.write('<hr>\n')

ProcessingResults.addResult(
'{} [summary]'.format(self.algs[0].name), outputFile)
resultsList.addResult(self.alg.icon(),
'{} [summary]'.format(self.alg.name()), outputFile)

0 comments on commit a3b64e2

Please sign in to comment.