Merge pull request #5592 from nyalldawson/batch

[processing] Fixes for batch processing
This commit is contained in:
Alexander Bruy 2017-11-10 08:34:37 +02:00 committed by GitHub
commit 9b85e5b7f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 137 additions and 57 deletions

View File

@ -2028,6 +2028,67 @@ bool null_from_qvariant_converter( const QVariant *varp, PyObject **objp )
}
%End
// Mapped type for QList<QgsWkbTypes::GeometryType>.
%MappedType QList<QgsWkbTypes::GeometryType>
{
%TypeHeaderCode
#include <qgswkbtypes.h>
%End
%ConvertFromTypeCode
// Create the list.
PyObject *l;
if ((l = PyList_New(sipCpp->size())) == NULL)
return NULL;
// Set the list elements.
for (int i = 0; i < sipCpp->size(); ++i)
{
QgsWkbTypes::GeometryType e = sipCpp->at(i);
PyObject *eobj;
if ((eobj = sipConvertFromEnum(e, sipType_QgsWkbTypes_GeometryType)) == NULL)
{
Py_DECREF(l);
return NULL;
}
PyList_SET_ITEM(l, i, eobj);
}
return l;
%End
%ConvertToTypeCode
// Check the type if that is all that is required.
if (sipIsErr == NULL)
{
if (!PyList_Check(sipPy))
return 0;
for (SIP_SSIZE_T i = 0; i < PyList_GET_SIZE(sipPy); ++i)
if (PyObject_TypeCheck(PyList_GET_ITEM(sipPy, i), sipTypeAsPyTypeObject(sipType_QgsWkbTypes_GeometryType)))
return 0;
return 1;
}
QList<QgsWkbTypes::GeometryType> *ql = new QList<QgsWkbTypes::GeometryType>;
for (SIP_SSIZE_T i = 0; i < PyList_GET_SIZE(sipPy); ++i)
{
long l = SIPLong_AsLong(PyList_GET_ITEM(sipPy, i));
ql->append(static_cast<QgsWkbTypes::GeometryType>(l));
}
*sipCppPtr = ql;
return sipGetState(sipTransferObj);
%End
};
%PostInitialisationCode //#spellok
// Import the Chimera helper registration functions.

View File

@ -43,6 +43,7 @@ from qgis.core import (QgsProcessingParameterDefinition,
QgsProject)
from qgis.gui import QgsMessageBar
from qgis.utils import OverrideCursor
from processing.gui.BatchPanel import BatchPanel
from processing.gui.AlgorithmDialogBase import AlgorithmDialogBase
@ -103,7 +104,7 @@ class BatchAlgorithmDialog(AlgorithmDialogBase):
count_visible_outputs += 1
widget = self.mainWidget.tblParameters.cellWidget(row, col)
text = widget.getValue()
if param.checkValueIsAcceptable(text, context):
if out.checkValueIsAcceptable(text, context):
if isinstance(out, (QgsProcessingParameterRasterDestination,
QgsProcessingParameterFeatureSink)):
# load rasters and sinks on completion
@ -119,47 +120,48 @@ class BatchAlgorithmDialog(AlgorithmDialogBase):
alg_parameters.append(parameters)
QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
self.mainWidget.setEnabled(False)
self.buttonCancel.setEnabled(True)
with OverrideCursor(Qt.WaitCursor):
# Make sure the Log tab is visible before executing the algorithm
try:
self.tabWidget.setCurrentIndex(1)
self.repaint()
except:
pass
self.mainWidget.setEnabled(False)
self.buttonCancel.setEnabled(True)
start_time = time.time()
# Make sure the Log tab is visible before executing the algorithm
try:
self.tabWidget.setCurrentIndex(1)
self.repaint()
except:
pass
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)
start_time = time.time()
feedback.pushInfo(self.tr('Input parameters:'))
feedback.pushCommandInfo(pformat(parameters))
feedback.pushInfo('')
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)
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(self.tr('Input parameters:'))
feedback.pushCommandInfo(pformat(parameters))
feedback.pushInfo('')
algorithm_results.append(results)
else:
break
feedback.pushInfo(self.tr('Batch execution completed in {0:0.2f} seconds'.format(time.time() - start_time)))
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:
break
handleAlgorithmResults(self.alg, context, feedback, False)
feedback.pushInfo(self.tr('Batch execution completed in {0:0.2f} seconds'.format(time.time() - start_time)))
handleAlgorithmResults(self.alg, context, feedback, False)
self.finish(algorithm_results)
self.buttonCancel.setEnabled(False)
@ -169,8 +171,6 @@ class BatchAlgorithmDialog(AlgorithmDialogBase):
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'))

View File

@ -94,7 +94,7 @@ class BatchInputSelectionPanel(QWidget):
popupmenu.addAction(selectLayerAction)
selectFileAction = QAction(
self.tr('Select from filesystem'), self.pushButton)
self.tr('Select from file system'), self.pushButton)
selectFileAction.triggered.connect(self.showFileSelectionDialog)
popupmenu.addAction(selectFileAction)
@ -150,7 +150,7 @@ class BatchInputSelectionPanel(QWidget):
path = ''
ret, selected_filter = QFileDialog.getOpenFileNames(self, self.tr('Open file'), path,
self.tr('All files (*.*);;') + getFileFilter(self.param))
getFileFilter(self.param))
if ret:
files = list(ret)
settings.setValue('/Processing/LastInputPath',

View File

@ -31,8 +31,9 @@ import json
from qgis.PyQt import uic
from qgis.PyQt.QtWidgets import QTableWidgetItem, QComboBox, QHeaderView, QFileDialog, QMessageBox
from qgis.PyQt.QtCore import QDir, QFileInfo
from qgis.core import (QgsApplication,
QgsSettings,
QgsProcessingParameterDefinition)
from qgis.gui import QgsMessageBar
from processing.gui.wrappers import WidgetWrapperFactory
@ -87,6 +88,10 @@ class BatchPanel(BASE, WIDGET):
self.tblParameters.horizontalHeader().sectionDoubleClicked.connect(
self.fillParameterValues)
self.tblParameters.horizontalHeader().resizeSections(QHeaderView.ResizeToContents)
self.tblParameters.horizontalHeader().setDefaultSectionSize(250)
self.tblParameters.horizontalHeader().setMinimumSectionSize(150)
self.initWidgets()
def layerRegistryChanged(self):
@ -133,18 +138,19 @@ class BatchPanel(BASE, WIDGET):
for i in range(2):
self.addRow()
self.tblParameters.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive)
self.tblParameters.horizontalHeader().setDefaultSectionSize(250)
self.tblParameters.horizontalHeader().setMinimumSectionSize(150)
self.tblParameters.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
self.tblParameters.horizontalHeader().resizeSections(QHeaderView.ResizeToContents)
self.tblParameters.verticalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
self.tblParameters.horizontalHeader().setStretchLastSection(True)
def load(self):
settings = QgsSettings()
last_path = settings.value("/Processing/LastBatchPath", QDir.homePath())
filename, selected_filter = QFileDialog.getOpenFileName(self,
self.tr('Open Batch'), None,
self.tr('Open Batch'), last_path,
self.tr('JSON files (*.json)'))
if filename:
last_path = QFileInfo(filename).path()
settings.setValue('/Processing/LastBatchPath', last_path)
with open(filename) as f:
values = json.load(f)
else:
@ -161,17 +167,19 @@ class BatchPanel(BASE, WIDGET):
for param in self.alg.parameterDefinitions():
if param.flags() & QgsProcessingParameterDefinition.FlagHidden:
continue
if param.isDestination():
continue
if param.name() in params:
value = params[param.name()].strip('"')
value = params[param.name()].strip("'")
wrapper = self.wrappers[row][column]
wrapper.setValue(value)
column += 1
for out in self.alg.outputs:
for out in self.alg.destinationParameterDefinitions():
if out.flags() & QgsProcessingParameterDefinition.FlagHidden:
continue
if out.name() in outputs:
value = outputs[out.name()].strip('"')
value = outputs[out.name()].strip("'")
widget = self.tblParameters.cellWidget(row, column)
widget.setValue(value)
column += 1
@ -192,36 +200,42 @@ class BatchPanel(BASE, WIDGET):
for param in alg.parameterDefinitions():
if param.flags() & QgsProcessingParameterDefinition.FlagHidden:
continue
if param.isDestination():
continue
wrapper = self.wrappers[row][col]
if not param.checkValueIsAcceptable(wrapper.value, context):
if not param.checkValueIsAcceptable(wrapper.value(), context):
self.parent.bar.pushMessage("", self.tr('Wrong or missing parameter value: {0} (row {1})').format(
param.description(), row + 1),
level=QgsMessageBar.WARNING, duration=5)
param.description(), row + 1),
level=QgsMessageBar.WARNING, duration=5)
return
algParams[param.name()] = param.getValueAsCommandLineParameter()
algParams[param.name()] = param.valueAsPythonString(wrapper.value(), context)
col += 1
for out in alg.outputs:
for out in alg.destinationParameterDefinitions():
if out.flags() & QgsProcessingParameterDefinition.FlagHidden:
continue
widget = self.tblParameters.cellWidget(row, col)
text = widget.getValue()
if text.strip() != '':
algOutputs[out.name] = text.strip()
algOutputs[out.name()] = text.strip()
col += 1
else:
self.parent.bar.pushMessage("", self.tr('Wrong or missing output value: {0} (row {1})').format(
out.description(), row + 1),
level=QgsMessageBar.WARNING, duration=5)
out.description(), row + 1),
level=QgsMessageBar.WARNING, duration=5)
return
toSave.append({self.PARAMETERS: algParams, self.OUTPUTS: algOutputs})
settings = QgsSettings()
last_path = settings.value("/Processing/LastBatchPath", QDir.homePath())
filename, __ = QFileDialog.getSaveFileName(self,
self.tr('Save Batch'),
None,
last_path,
self.tr('JSON files (*.json)'))
if filename:
if not filename.endswith('.json'):
filename += '.json'
last_path = QFileInfo(filename).path()
settings.setValue('/Processing/LastBatchPath', last_path)
with open(filename, 'w') as f:
json.dump(toSave, f)
@ -271,6 +285,10 @@ class BatchPanel(BASE, WIDGET):
def fillParameterValues(self, column):
wrapper = self.wrappers[0][column]
if wrapper is None:
# e.g. double clicking on a destination header
return
for row in range(1, self.tblParameters.rowCount()):
self.wrappers[row][column].setValue(wrapper.value())

View File

@ -82,7 +82,8 @@ def handleAlgorithmResults(alg, context, feedback=None, showResults=True):
wrongLayers.append(str(l))
i += 1
QApplication.restoreOverrideCursor()
feedback.setProgress(100)
if wrongLayers:
msg = "The following layers were not correctly generated.<ul>"
msg += "".join(["<li>%s</li>" % lay for lay in wrongLayers]) + "</ul>"