Skip to content
Permalink
Browse files

[processing] Port feedback object to c++

Algorithms are now passed a QgsProcessingFeedback object
instead of the loosely defined progress parameter.
  • Loading branch information
nyalldawson committed Jan 11, 2017
1 parent 26a8a54 commit ede452be8502ace23a97ecc57dce954c8f222a69
Showing 303 changed files with 1,012 additions and 835 deletions.
@@ -1831,6 +1831,11 @@ Processing {#qgis_api_break_3_0_Processing}

- Algorithm providers now subclass the c++ QgsProcessingProvider class, and must be adapted to the API for QgsProcessingProvider. Specifically,
getName() should be replaced with id(), getDescription() with name(), and getIcon with icon().
- Algorithm's processAlgorithm method now passes a QgsProcessingFeedback object instead of the loosely defined progress parameter. Algorithms will
need to update their use of the progress argument to utilise the QgsProcessingFeedback API.
- Similarly, Python processing scripts no longer have access to a progress variable for reporting their progress. Instead they have a feedback
object of type QgsProcessingFeedback, and will need to adapt their use of progress reporting to the QgsProcessingFeedback API.
- SilentProgress was removed. Use the base QgsProcessingFeedback class instead.


QGIS 2.4 {#qgis_api_break_2_4}
@@ -259,6 +259,7 @@
%Include layertree/qgslayertreeregistrybridge.sip
%Include layertree/qgslayertreeutils.sip

%Include processing/qgsprocessingfeedback.sip
%Include processing/qgsprocessingprovider.sip
%Include processing/qgsprocessingregistry.sip

@@ -0,0 +1,80 @@
/**
* \class QgsProcessingFeedback
* \ingroup core
* Base class for providing feedback from a processing algorithm.
*
* This base class implementation silently ignores all feedback reported by algorithms.
* Subclasses of QgsProcessingFeedback can be used to log this feedback or report
* it to users via the GUI.
* \note added in QGIS 3.0
*/
class QgsProcessingFeedback : public QgsFeedback
{
%TypeHeaderCode
#include <qgsprocessingfeedback.h>
%End

public:

/**
* Sets the algorithm's progress. The progress
* argument is limited to the range 0-100 and reflects the percentage
* progress through the task.
* @see setProgressText()
*/
virtual void setProgress( double progress );

/**
* Sets a progress report text string. This can be used in conjunction with
* setProgress() to provide detailed progress reports, such as "Transformed
* 4 of 5 layers".
* @see setProgress()
*/
virtual void setProgressText( const QString& text );

/**
* Reports that the algorithm encountered an error which prevented it
* from successfully executing.
*/
virtual void reportError( const QString& error );

/**
* Pushes a general informational message from the algorithm. This can
* be used to report feedback which is neither a status report or an
* error, such as "Found 47 matching features".
* @see pushCommandInfo()
* @see pushDebugInfo()
* @see pushConsoleInfo()
*/
virtual void pushInfo( const QString& info );

/**
* Pushes an informational message containing a command from the algorithm.
* This is usually used to report commands which are executed in an external
* application or as subprocesses.
* @see pushInfo()
* @see pushDebugInfo()
* @see pushConsoleInfo()
*/
virtual void pushCommandInfo( const QString& info );

/**
* Pushes an informational message containing debugging helpers from
* the algorithm.
* @see pushInfo()
* @see pushCommandInfo()
* @see pushConsoleInfo()
*/
virtual void pushDebugInfo( const QString& info );


/**
* Pushes a console feedback message from the algorithm. This is used to
* report the output from executing an external command or subprocess.
* @see pushInfo()
* @see pushDebugInfo()
* @see pushCommandInfo()
*/
virtual void pushConsoleInfo( const QString& info );

};
@@ -75,7 +75,7 @@ def defineCharacteristics(self):
self.addOutput(OutputVector(self.OUTPUT_LAYER,
self.tr('Output layer with selected features')))

def processAlgorithm(self, progress):
def processAlgorithm(self, feedback):
"""Here is where the processing itself takes place."""

# The first thing to do is retrieve the values of the parameters
@@ -56,7 +56,7 @@ def getIcon(self):
def getCustomParametersDialog(self):
return GdalAlgorithmDialog(self)

def processAlgorithm(self, progress):
def processAlgorithm(self, feedback):
commands = self.getConsoleCommands()
layers = dataobjects.getVectorLayers()
supported = dataobjects.getSupportedOutputVectorLayerExtensions()
@@ -73,7 +73,7 @@ def processAlgorithm(self, progress):
c = re.sub('["\']{}["\']'.format(fileName), "'" + exportedFileName + "'", c)

commands[i] = c
GdalUtils.runGdal(commands, progress)
GdalUtils.runGdal(commands, feedback)

def shortHelp(self):
helpPath = GdalUtils.gdalHelpPath()
@@ -35,10 +35,11 @@
from osgeo import gdal

from qgis.PyQt.QtCore import QSettings
from qgis.core import QgsApplication, QgsVectorFileWriter
from qgis.core import (QgsApplication,
QgsVectorFileWriter,
QgsProcessingFeedback)
from processing.core.ProcessingConfig import ProcessingConfig
from processing.core.ProcessingLog import ProcessingLog
from processing.core.SilentProgress import SilentProgress
from processing.tools.system import isWindows, isMac

try:
@@ -55,9 +56,9 @@ class GdalUtils(object):
supportedRasters = None

@staticmethod
def runGdal(commands, progress=None):
if progress is None:
progress = SilentProgress()
def runGdal(commands, feedback=None):
if feedback is None:
feedback = QgsProcessingFeedback()
envval = os.getenv('PATH')
# We need to give some extra hints to get things picked up on OS X
isDarwin = False
@@ -79,9 +80,9 @@ def runGdal(commands, progress=None):

fused_command = ' '.join([str(c) for c in commands])
ProcessingLog.addToLog(ProcessingLog.LOG_INFO, fused_command)
progress.setInfo('GDAL command:')
progress.setCommand(fused_command)
progress.setInfo('GDAL command output:')
feedback.pushInfo('GDAL command:')
feedback.pushCommandInfo(fused_command)
feedback.pushInfo('GDAL command output:')
success = False
retry_count = 0
while success == False:
@@ -97,7 +98,7 @@ def runGdal(commands, progress=None):
universal_newlines=True,
) as proc:
for line in proc.stdout:
progress.setConsoleInfo(line)
feedback.pushConsoleInfo(line)
loglines.append(line)
success = True
except IOError as e:
@@ -57,7 +57,7 @@ def defineCharacteristics(self):
def getConsoleCommands(self):
return ["extractprojection"]

def processAlgorithm(self, progress):
def processAlgorithm(self, feedback):
rasterPath = self.getParameterValue(self.INPUT)
createPrj = self.getParameterValue(self.PRJ_FILE)

@@ -73,8 +73,8 @@ def getConsoleCommands(self):
arguments.append(self.getParameterValue(information.INPUT))
return ['gdalinfo', GdalUtils.escapeAndJoin(arguments)]

def processAlgorithm(self, progress):
GdalUtils.runGdal(self.getConsoleCommands(), progress)
def processAlgorithm(self, feedback):
GdalUtils.runGdal(self.getConsoleCommands(), feedback)
output = self.getOutputValue(information.OUTPUT)
with open(output, 'w') as f:
f.write('<pre>')
@@ -118,9 +118,9 @@ def defineCharacteristics(self):
self.addParameter(ParameterString(self.OPTIONS,
self.tr('Additional creation options'), '', optional=True))

def processAlgorithm(self, progress):
def processAlgorithm(self, feedback):
self.processing = True
GdalAlgorithm.processAlgorithm(self, progress)
GdalAlgorithm.processAlgorithm(self, feedback)
self.processing = False

def getConsoleCommands(self):
@@ -162,9 +162,9 @@ def defineCharacteristics(self):
self.addParameter(ParameterString(self.OPTIONS,
self.tr('Additional creation options'), '', optional=True))

def processAlgorithm(self, progress):
def processAlgorithm(self, feedback):
self.processing = True
GdalAlgorithm.processAlgorithm(self, progress)
GdalAlgorithm.processAlgorithm(self, feedback)
self.processing = False

def getConsoleCommands(self):
@@ -67,8 +67,8 @@ def getConsoleCommands(self):
arguments.append(conn)
return arguments

def processAlgorithm(self, progress):
GdalUtils.runGdal(self.getConsoleCommands(), progress)
def processAlgorithm(self, feedback):
GdalUtils.runGdal(self.getConsoleCommands(), feedback)
output = self.getOutputValue(self.OUTPUT)
with open(output, 'w') as f:
f.write('<pre>')
@@ -236,7 +236,7 @@ def getDefaultCellsize(self):
cellsize = 100
return cellsize

def processAlgorithm(self, progress):
def processAlgorithm(self, feedback):
if system.isWindows():
path = Grass7Utils.grassPath()
if path == '':
@@ -286,12 +286,12 @@ def processAlgorithm(self, progress):
loglines = []
loglines.append(self.tr('GRASS GIS 7 execution commands'))
for line in self.commands:
progress.setCommand(line)
feedback.pushCommandInfo(line)
loglines.append(line)
if ProcessingConfig.getSetting(Grass7Utils.GRASS_LOG_COMMANDS):
ProcessingLog.addToLog(ProcessingLog.LOG_INFO, loglines)

Grass7Utils.executeGrass7(self.commands, progress, self.outputCommands)
Grass7Utils.executeGrass7(self.commands, feedback, self.outputCommands)

for out in self.outputs:
if isinstance(out, OutputHTML):
@@ -35,7 +35,6 @@
from qgis.PyQt.QtCore import QCoreApplication
from processing.core.ProcessingConfig import ProcessingConfig
from processing.core.ProcessingLog import ProcessingLog
from processing.core.SilentProgress import SilentProgress
from processing.tools.system import userFolder, isWindows, isMac, tempFolder, mkdir
from processing.tests.TestData import points

@@ -281,7 +280,7 @@ def prepareGrass7Execution(commands):
return command, env

@staticmethod
def executeGrass7(commands, progress, outputCommands=None):
def executeGrass7(commands, feedback, outputCommands=None):
loglines = []
loglines.append(Grass7Utils.tr('GRASS GIS 7 execution console output'))
grassOutDone = False
@@ -298,14 +297,14 @@ def executeGrass7(commands, progress, outputCommands=None):
for line in iter(proc.stdout.readline, ''):
if 'GRASS_INFO_PERCENT' in line:
try:
progress.setPercentage(int(line[len('GRASS_INFO_PERCENT') + 2:]))
feedback.setProgress(int(line[len('GRASS_INFO_PERCENT') + 2:]))
except:
pass
else:
if 'r.out' in line or 'v.out' in line:
grassOutDone = True
loglines.append(line)
progress.setConsoleInfo(line)
feedback.pushConsoleInfo(line)

# Some GRASS scripts, like r.mapcalculator or r.fillnulls, call
# other GRASS scripts during execution. This may override any
@@ -327,13 +326,13 @@ def executeGrass7(commands, progress, outputCommands=None):
for line in iter(proc.stdout.readline, ''):
if 'GRASS_INFO_PERCENT' in line:
try:
progress.setPercentage(int(
feedback.setProgress(int(
line[len('GRASS_INFO_PERCENT') + 2:]))
except:
pass
else:
loglines.append(line)
progress.setConsoleInfo(line)
feedback.pushConsoleInfo(line)

if ProcessingConfig.getSetting(Grass7Utils.GRASS_LOG_CONSOLE):
ProcessingLog.addToLog(ProcessingLog.LOG_INFO, loglines)
@@ -85,7 +85,7 @@ def defineCharacteristics(self):
self.tr('GRASS region cellsize (leave 0 for default)'),
0, None, 0.0))

def processAlgorithm(self, progress):
def processAlgorithm(self, feedback):
commands = []
vector = self.getParameterValue(self.VECTOR)
elevation = self.getParameterValue(self.ELEVATION)
@@ -132,7 +132,7 @@ def processAlgorithm(self, progress):
command += ' -q'
commands.append(command)
Grass7Utils.createTempMapset()
Grass7Utils.executeGrass7(commands, progress)
Grass7Utils.executeGrass7(commands, feedback)

def getTempFilename(self):
filename = 'tmp' + str(time.time()).replace('.', '') \
@@ -66,7 +66,7 @@ def defineCharacteristics(self):

self.addAdvancedModifiers()

def processAlgorithm(self, progress):
def processAlgorithm(self, feedback):
commands = [os.path.join(FusionUtils.FusionPath(), 'ASCII2DTM.exe')]
commands.append('/verbose')
self.addAdvancedModifiersToCommand(commands)
@@ -84,4 +84,4 @@ def processAlgorithm(self, progress):
else:
FusionUtils.createFileList(files)
commands.append(FusionUtils.tempFileListFilepath())
FusionUtils.runFusion(commands, progress)
FusionUtils.runFusion(commands, feedback)
@@ -68,7 +68,7 @@ def defineCharacteristics(self):
self.OUTPUT, self.tr('Output file with maxima')))
self.addAdvancedModifiers()

def processAlgorithm(self, progress):
def processAlgorithm(self, feedback):
commands = [os.path.join(FusionUtils.FusionPath(), 'CanopyMaxima.exe')]
commands.append('/verbose')
### begin
@@ -91,4 +91,4 @@ def processAlgorithm(self, progress):
commands.append(FusionUtils.tempFileListFilepath())
commands.append(self.getOutputValue(self.OUTPUT))

FusionUtils.runFusion(commands, progress)
FusionUtils.runFusion(commands, feedback)
@@ -93,7 +93,7 @@ def defineCharacteristics(self):
self.ASCII, self.tr('Add an ASCII output'), False))
self.addAdvancedModifiers()

def processAlgorithm(self, progress):
def processAlgorithm(self, feedback):
commands = [os.path.join(FusionUtils.FusionPath(), 'CanopyModel.exe')]
commands.append('/verbose')
ground = self.getParameterValue(self.GROUND)
@@ -129,4 +129,4 @@ def processAlgorithm(self, progress):
else:
FusionUtils.createFileList(files)
commands.append(FusionUtils.tempFileListFilepath())
FusionUtils.runFusion(commands, progress)
FusionUtils.runFusion(commands, feedback)
@@ -73,7 +73,7 @@ def defineCharacteristics(self):
advanced_modifiers.isAdvanced = True
self.addParameter(advanced_modifiers)

def processAlgorithm(self, progress):
def processAlgorithm(self, feedback):
commands = [os.path.join(FusionUtils.FusionPath(), 'Catalog.exe')]
commands.append('/verbose')
intensity = self.getParameterValue(self.INTENSITY)
@@ -95,4 +95,4 @@ def processAlgorithm(self, progress):
FusionUtils.createFileList(files)
commands.append(FusionUtils.tempFileListFilepath())
commands.append(self.getOutputValue(self.OUTPUT))
FusionUtils.runFusion(commands, progress)
FusionUtils.runFusion(commands, feedback)
@@ -67,7 +67,7 @@ def defineCharacteristics(self):
self.addParameter(height)
self.addAdvancedModifiers()

def processAlgorithm(self, progress):
def processAlgorithm(self, feedback):
commands = [os.path.join(FusionUtils.FusionPath(), 'ClipData.exe')]
commands.append('/verbose')
self.addAdvancedModifiersToCommand(commands)
@@ -91,4 +91,4 @@ def processAlgorithm(self, progress):
commands.append(extent[2])
commands.append(extent[1])
commands.append(extent[3])
FusionUtils.runFusion(commands, progress)
FusionUtils.runFusion(commands, feedback)

0 comments on commit ede452b

Please sign in to comment.
You can’t perform that action at this time.