mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
Merge pull request #5592 from nyalldawson/batch
[processing] Fixes for batch processing
This commit is contained in:
commit
9b85e5b7f5
@ -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.
|
||||
|
@ -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'))
|
||||
|
@ -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',
|
||||
|
@ -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())
|
||||
|
||||
|
@ -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>"
|
||||
|
Loading…
x
Reference in New Issue
Block a user