Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #3959 from nyalldawson/processing_port_feedback
[processing] Port feedback object to c++
  • Loading branch information
nyalldawson committed Jan 11, 2017
2 parents 26a8a54 + 86e1138 commit a7806d1
Show file tree
Hide file tree
Showing 303 changed files with 1,024 additions and 836 deletions.
5 changes: 5 additions & 0 deletions doc/api_break.dox
Expand Up @@ -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}
Expand Down
1 change: 1 addition & 0 deletions python/core/core.sip
Expand Up @@ -259,6 +259,7 @@
%Include layertree/qgslayertreeregistrybridge.sip
%Include layertree/qgslayertreeutils.sip

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

Expand Down
80 changes: 80 additions & 0 deletions python/core/processing/qgsprocessingfeedback.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 );

};
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions python/plugins/processing/algs/gdal/GdalAlgorithm.py
Expand Up @@ -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()
Expand All @@ -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()
Expand Down
19 changes: 10 additions & 9 deletions python/plugins/processing/algs/gdal/GdalUtils.py
Expand Up @@ -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:
Expand All @@ -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
Expand All @@ -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:
Expand All @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/processing/algs/gdal/extractprojection.py
Expand Up @@ -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)

Expand Down
4 changes: 2 additions & 2 deletions python/plugins/processing/algs/gdal/information.py
Expand Up @@ -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>')
Expand Down
Expand Up @@ -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):
Expand Down
4 changes: 2 additions & 2 deletions python/plugins/processing/algs/gdal/ogr2ogrtopostgislist.py
Expand Up @@ -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):
Expand Down
4 changes: 2 additions & 2 deletions python/plugins/processing/algs/gdal/ogrinfo.py
Expand Up @@ -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>')
Expand Down
6 changes: 3 additions & 3 deletions python/plugins/processing/algs/grass7/Grass7Algorithm.py
Expand Up @@ -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 == '':
Expand Down Expand Up @@ -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):
Expand Down
11 changes: 5 additions & 6 deletions python/plugins/processing/algs/grass7/Grass7Utils.py
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions python/plugins/processing/algs/grass7/nviz7.py
Expand Up @@ -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)
Expand Down Expand Up @@ -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('.', '') \
Expand Down
4 changes: 2 additions & 2 deletions python/plugins/processing/algs/lidar/fusion/ASCII2DTM.py
Expand Up @@ -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)
Expand All @@ -84,4 +84,4 @@ def processAlgorithm(self, progress):
else:
FusionUtils.createFileList(files)
commands.append(FusionUtils.tempFileListFilepath())
FusionUtils.runFusion(commands, progress)
FusionUtils.runFusion(commands, feedback)
4 changes: 2 additions & 2 deletions python/plugins/processing/algs/lidar/fusion/CanopyMaxima.py
Expand Up @@ -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
Expand All @@ -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)
4 changes: 2 additions & 2 deletions python/plugins/processing/algs/lidar/fusion/CanopyModel.py
Expand Up @@ -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)
Expand Down Expand Up @@ -129,4 +129,4 @@ def processAlgorithm(self, progress):
else:
FusionUtils.createFileList(files)
commands.append(FusionUtils.tempFileListFilepath())
FusionUtils.runFusion(commands, progress)
FusionUtils.runFusion(commands, feedback)
4 changes: 2 additions & 2 deletions python/plugins/processing/algs/lidar/fusion/Catalog.py
Expand Up @@ -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)
Expand All @@ -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)
4 changes: 2 additions & 2 deletions python/plugins/processing/algs/lidar/fusion/ClipData.py
Expand Up @@ -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)
Expand All @@ -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 a7806d1

Please sign in to comment.