Port script code functions to c++ classes

Restore logging executed algorithms
This commit is contained in:
Nyall Dawson 2017-06-12 15:59:56 +10:00
parent 5177c7d181
commit 63611b1d8f
14 changed files with 573 additions and 142 deletions

View File

@ -255,6 +255,16 @@ class QgsProcessingAlgorithm
:rtype: bool
%End
virtual QString asPythonCommand( const QVariantMap &parameters, QgsProcessingContext &context ) const;
%Docstring
Returns a Python command string which can be executed to run the algorithm
using the specified ``parameters``.
Algorithms which cannot be run from a Python command should return an empty
string.
:rtype: str
%End
protected:
bool addParameter( QgsProcessingParameterDefinition *parameterDefinition /Transfer/ );

View File

@ -288,6 +288,14 @@ class QgsProcessingParameterDefinition
:rtype: bool
%End
virtual QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const;
%Docstring
Returns a string version of the parameter input ``value``, which is suitable for use as an input
parameter value when running an algorithm directly from a Python command.
The returned value must be correctly escaped - e.g. string values must be wrapped in ' 's.
:rtype: str
%End
protected:
@ -517,6 +525,8 @@ class QgsProcessingParameterBoolean : QgsProcessingParameterDefinition
%End
virtual QString type() const;
virtual QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const;
};
class QgsProcessingParameterCrs : QgsProcessingParameterDefinition
@ -540,6 +550,8 @@ class QgsProcessingParameterCrs : QgsProcessingParameterDefinition
virtual QString type() const;
virtual bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = 0 ) const;
virtual QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const;
};
class QgsProcessingParameterMapLayer : QgsProcessingParameterDefinition
@ -563,6 +575,8 @@ class QgsProcessingParameterMapLayer : QgsProcessingParameterDefinition
virtual QString type() const;
virtual bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = 0 ) const;
virtual QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const;
};
class QgsProcessingParameterExtent : QgsProcessingParameterDefinition
@ -586,6 +600,8 @@ class QgsProcessingParameterExtent : QgsProcessingParameterDefinition
virtual QString type() const;
virtual bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = 0 ) const;
virtual QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const;
};
@ -693,6 +709,8 @@ class QgsProcessingParameterMatrix : QgsProcessingParameterDefinition
virtual QString type() const;
virtual bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = 0 ) const;
virtual QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const;
QStringList headers() const;
%Docstring
@ -763,6 +781,8 @@ class QgsProcessingParameterMultipleLayers : QgsProcessingParameterDefinition
virtual QString type() const;
virtual bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = 0 ) const;
virtual QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const;
QgsProcessingParameterDefinition::LayerType layerType() const;
%Docstring
@ -826,6 +846,8 @@ class QgsProcessingParameterNumber : QgsProcessingParameterDefinition
virtual QString type() const;
virtual bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = 0 ) const;
virtual QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const;
double minimum() const;
%Docstring
@ -891,6 +913,8 @@ class QgsProcessingParameterRange : QgsProcessingParameterDefinition
virtual QString type() const;
virtual bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = 0 ) const;
virtual QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const;
QgsProcessingParameterNumber::Type dataType() const;
%Docstring
@ -928,6 +952,8 @@ class QgsProcessingParameterRasterLayer : QgsProcessingParameterDefinition
virtual QString type() const;
virtual bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = 0 ) const;
virtual QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const;
};
@ -954,6 +980,8 @@ class QgsProcessingParameterEnum : QgsProcessingParameterDefinition
virtual QString type() const;
virtual bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = 0 ) const;
virtual QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const;
QStringList options() const;
%Docstring
@ -1003,6 +1031,8 @@ class QgsProcessingParameterString : QgsProcessingParameterDefinition
%End
virtual QString type() const;
virtual QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const;
bool multiLine() const;
%Docstring
@ -1039,6 +1069,8 @@ class QgsProcessingParameterExpression : QgsProcessingParameterDefinition
%End
virtual QString type() const;
virtual QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const;
QString parentLayerParameter() const;
%Docstring
@ -1109,6 +1141,8 @@ class QgsProcessingParameterTableField : QgsProcessingParameterDefinition
virtual QString type() const;
virtual bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = 0 ) const;
virtual QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const;
QString parentLayerParameter() const;
%Docstring
@ -1173,6 +1207,8 @@ class QgsProcessingParameterFeatureSource : QgsProcessingParameterDefinition
virtual QString type() const;
virtual bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = 0 ) const;
virtual QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const;
QList< int > dataTypes() const;
%Docstring
@ -1214,6 +1250,8 @@ class QgsProcessingParameterFeatureSink : QgsProcessingParameterDefinition
virtual bool isDestination() const;
virtual bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = 0 ) const;
virtual QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const;
QgsProcessingParameterDefinition::LayerType dataType() const;
%Docstring
@ -1260,6 +1298,8 @@ class QgsProcessingParameterRasterOutput : QgsProcessingParameterDefinition
virtual bool isDestination() const;
virtual bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = 0 ) const;
virtual QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const;
};
class QgsProcessingParameterFileOutput : QgsProcessingParameterDefinition
@ -1286,6 +1326,8 @@ class QgsProcessingParameterFileOutput : QgsProcessingParameterDefinition
virtual bool isDestination() const;
virtual bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = 0 ) const;
virtual QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const;
QString fileFilter() const;
%Docstring

View File

@ -224,9 +224,9 @@ class FieldsCalculatorDialog(BASE, WIDGET):
parameters = self.getParamValues()
if parameters:
QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
ProcessingLog.addToLog(self.alg.getAsCommand())
context = dataobjects.createContext()
ProcessingLog.addToLog(self.alg.asPythonCommand(parameters, context))
self.executed, results = execute(self.alg, parameters, context, self.feedback)
if self.executed:
handleAlgorithmResults(self.alg,

View File

@ -301,23 +301,6 @@ class GeoAlgorithm(QgsProcessingAlgorithm):
return out.value
return None
def getAsCommand(self):
"""Returns the command that would run this same algorithm from
the console.
Should return None if the algorithm cannot be run from the
console.
"""
s = 'processing.run("' + self.id() + '",'
for param in self.parameterDefinitions():
s += param.getValueAsCommandLineParameter() + ','
for out in self.outputs:
if not out.flags() & QgsProcessingParameterDefinition.FlagHidden:
s += out.getValueAsCommandLineParameter() + ','
s = s[:-1] + ')'
return s
def tr(self, string, context=''):
if context == '':
context = self.__class__.__name__

View File

@ -139,13 +139,8 @@ class Processing(object):
for (name, value) in list(args[0].items()):
param = alg.parameterDefinition(name)
if param:
# TODO
# and param.setValue(value):
parameters[param.name()] = value
continue
output = alg.getOutputFromName(name)
if output and output.setValue(value):
continue
# fix_print_with_import
print('Error: Wrong parameter value %s for parameter %s.' % (value, name))
QgsMessageLog.logMessage(
@ -249,7 +244,7 @@ class Processing(object):
QApplication.restoreOverrideCursor()
if isinstance(feedback, MessageBarProgress):
feedback.close()
return alg
return results
@staticmethod
def tr(string, context=''):

View File

@ -86,14 +86,6 @@ class Parameter(object):
def __str__(self):
return u'{} <{}>'.format(self.name(), self.__class__.__name__)
def getValueAsCommandLineParameter(self):
"""
Returns the value of this parameter as it should have been
entered in the console if calling an algorithm using the
processing.run() method.
"""
return str(self.value)
def todict(self):
o = deepcopy(self.__dict__)
del o['metadata']
@ -145,9 +137,6 @@ class ParameterCrs(Parameter):
if self.value == 'ProjectCrs':
self.value = QgsProject.instance().crs().authid()
def getValueAsCommandLineParameter(self):
return '"' + str(self.value) + '"'
def getAsScriptCode(self):
param_type = ''
if self.flags() & QgsProcessingParameterDefinition.FlagOptional:
@ -169,17 +158,6 @@ class ParameterCrs(Parameter):
return ParameterCrs(name, descName, None, isOptional)
class ParameterDataObject(Parameter):
def getValueAsCommandLineParameter(self):
if self.value is None:
return str(None)
else:
s = QgsProcessingUtils.normalizeLayerSource(str(self.value))
s = '"%s"' % s
return s
class ParameterExtent(Parameter):
USE_MIN_COVERING_EXTENT = 'USE_MIN_COVERING_EXTENT'
@ -189,12 +167,6 @@ class ParameterExtent(Parameter):
# The value is a string in the form "xmin, xmax, ymin, ymax"
self.skip_crs_check = False
def getValueAsCommandLineParameter(self):
if self.value is not None:
return '"' + str(self.value) + '"'
else:
return str(None)
def getAsScriptCode(self):
param_type = ''
if self.flags() & QgsProcessingParameterDefinition.FlagOptional:
@ -217,9 +189,6 @@ class ParameterPoint(Parameter):
Parameter.__init__(self, name, description, default, optional)
# The value is a string in the form "x, y"
def getValueAsCommandLineParameter(self):
return '"' + str(self.value) + '"'
def getAsScriptCode(self):
param_type = ''
if self.flags() & QgsProcessingParameterDefinition.FlagOptional:
@ -243,9 +212,6 @@ class ParameterFile(Parameter):
self.ext = ext
self.isFolder = parseBool(isFolder)
def getValueAsCommandLineParameter(self):
return '"' + str(self.value) + '"'
def getAsScriptCode(self):
param_type = ''
if self.flags() & QgsProcessingParameterDefinition.FlagOptional:
@ -275,9 +241,6 @@ class ParameterFixedTable(Parameter):
self.numRows = int(numRows)
self.fixedNumOfRows = parseBool(fixedNumOfRows)
def getValueAsCommandLineParameter(self):
return '"' + str(self.value) + '"'
@staticmethod
def tableToString(table):
tablestring = ''
@ -302,7 +265,7 @@ class ParameterFixedTable(Parameter):
return ParameterFixedTable(name, descName, optional=isOptional)
class ParameterMultipleInput(ParameterDataObject):
class ParameterMultipleInput(Parameter):
"""A parameter representing several data objects.
@ -313,7 +276,7 @@ class ParameterMultipleInput(ParameterDataObject):
exported = None
def __init__(self, name='', description='', datatype=-1, optional=False, metadata={}):
ParameterDataObject.__init__(self, name, description, None, optional, metadata=metadata)
Parameter.__init__(self, name, description, None, optional, metadata=metadata)
self.datatype = int(float(datatype))
self.exported = None
self.minNumInputs = 0
@ -552,13 +515,6 @@ class ParameterNumber(Parameter):
return value
def getValueAsCommandLineParameter(self):
if self.value is None:
return str(None)
if isinstance(self.value, str):
return '"%s"' + self.value
return str(self.value)
class ParameterRange(Parameter):
@ -576,14 +532,11 @@ class ParameterRange(Parameter):
else:
self.isInteger = False
def getValueAsCommandLineParameter(self):
return '"' + str(self.value) + '"' if self.value is not None else str(None)
class ParameterRaster(ParameterDataObject):
class ParameterRaster(Parameter):
def __init__(self, name='', description='', optional=False, showSublayersDialog=True):
ParameterDataObject.__init__(self, name, description, None, optional)
Parameter.__init__(self, name, description, None, optional)
self.showSublayersDialog = parseBool(showSublayersDialog)
def getAsScriptCode(self):
@ -663,19 +616,11 @@ class ParameterEvaluationException(Exception):
class ParameterString(Parameter):
NEWLINE = '\n'
ESCAPED_NEWLINE = '\\n'
def __init__(self, name='', description='', default=None, multiline=False,
optional=False, evaluateExpressions=False, metadata={}):
Parameter.__init__(self, name, description, default, optional, metadata)
self.multiline = parseBool(multiline)
def getValueAsCommandLineParameter(self):
return ('"' + str(self.value.replace(ParameterString.NEWLINE,
ParameterString.ESCAPED_NEWLINE)) + '"'
if self.value is not None else str(None))
def getAsScriptCode(self):
param_type = ''
if self.flags() & QgsProcessingParameterDefinition.FlagOptional:
@ -707,18 +652,10 @@ class ParameterString(Parameter):
class ParameterExpression(Parameter):
NEWLINE = '\n'
ESCAPED_NEWLINE = '\\n'
def __init__(self, name='', description='', default=None, optional=False, parent_layer=None):
Parameter.__init__(self, name, description, default, optional)
self.parent_layer = parent_layer
def getValueAsCommandLineParameter(self):
return ('"' + str(self.value.replace(ParameterExpression.NEWLINE,
ParameterExpression.ESCAPED_NEWLINE)) + '"'
if self.value is not None else str(None))
def getAsScriptCode(self):
param_type = ''
if self.flags() & QgsProcessingParameterDefinition.FlagOptional:
@ -740,10 +677,10 @@ class ParameterExpression(Parameter):
return ParameterExpression(name, descName, optional=isOptional)
class ParameterTable(ParameterDataObject):
class ParameterTable(Parameter):
def __init__(self, name='', description='', optional=False):
ParameterDataObject.__init__(self, name, description, None, optional)
Parameter.__init__(self, name, description, None, optional)
self.exported = None
def getSafeExportedTable(self):
@ -807,9 +744,6 @@ class ParameterTableField(Parameter):
self.multiple = multiple
self.datatype = int(datatype)
def getValueAsCommandLineParameter(self):
return '"' + str(self.value) + '"' if self.value is not None else str(None)
def __str__(self):
return self.name() + ' <' + self.__module__.split('.')[-1] + ' from ' \
+ self.parent + '>'
@ -852,11 +786,11 @@ class ParameterTableField(Parameter):
return ParameterTableField(name, descName, parent, datatype, isOptional)
class ParameterVector(ParameterDataObject):
class ParameterVector(Parameter):
def __init__(self, name='', description='', datatype=[-1],
optional=False):
ParameterDataObject.__init__(self, name, description, None, optional)
Parameter.__init__(self, name, description, None, optional)
if isinstance(datatype, int):
datatype = [datatype]
elif isinstance(datatype, str):

View File

@ -239,10 +239,9 @@ class AlgorithmDialog(AlgorithmDialogBase):
QApplication.restoreOverrideCursor()
self.resetGUI()
else:
# TODO
#command = self.alg.getAsCommand()
#if command:
# ProcessingLog.addToLog(command)
command = self.alg.asPythonCommand(parameters, context)
if command:
ProcessingLog.addToLog(command)
self.buttonCancel.setEnabled(self.alg.flags() & QgsProcessingAlgorithm.FlagCanCancel)
result = executeAlgorithm(self.alg, parameters, context, feedback)
feedback.pushInfo(self.tr('Execution completed in {0:0.2f} seconds'.format(time.time() - start_time)))

View File

@ -49,8 +49,7 @@ from processing.core.parameters import (Parameter,
ParameterTableField,
ParameterBoolean,
ParameterString,
ParameterNumber,
ParameterDataObject)
ParameterNumber)
from processing.gui.Help2Html import getHtmlFromDescriptionsDict
@ -424,13 +423,15 @@ class ModelerAlgorithm(GeoAlgorithm):
value = param.defaultValue()
# We allow unexistent filepaths, since that allows
# algorithms to skip some conversion routines
if not param.checkValueIsAcceptable(value) and not isinstance(param,
ParameterDataObject):
raise GeoAlgorithmExecutionException(
self.tr('Wrong value {0} for {1} {2}', 'ModelerAlgorithm').format(
value, param.__class__.__name__, param.name()
)
)
# TODO
#if not param.checkValueIsAcceptable(value) and not isinstance(param,
# ParameterDataObject):
# raise GeoAlgorithmExecutionException(
# self.tr('Wrong value {0} for {1} {2}', 'ModelerAlgorithm').format(
# value, param.__class__.__name__, param.name()
# )
# )
for out in algInstance.outputs:
if not out.flags() & QgsProcessingParameterDefinition.FlagHidden:
@ -519,9 +520,9 @@ class ModelerAlgorithm(GeoAlgorithm):
feedback.pushDebugInfo(
self.tr('Model processed ok. Executed {0} algorithms total', 'ModelerAlgorithm').format(len(executed)))
def getAsCommand(self):
def asPythonCommand(self, parameters, context):
if self.descriptionFile:
return GeoAlgorithm.getAsCommand(self)
return QgsProcessingAlgorithm.asPythonCommand(self, parameters, context)
else:
return None

View File

@ -57,17 +57,6 @@ start_app()
class ParameterTest(unittest.TestCase):
def testGetValueAsCommandLineParameter(self):
parameter = Parameter('myName', 'myDesc')
parameter.setValue(None)
self.assertEqual(parameter.getValueAsCommandLineParameter(), "None")
parameter.setValue("someValue")
self.assertEqual(parameter.getValueAsCommandLineParameter(), 'someValue')
parameter.setValue(123)
self.assertEqual(parameter.getValueAsCommandLineParameter(), '123')
def testScriptCode(self):
"""Simple check that default constructed object export/import correctly"""
paramClasses = [c for c in list(sys.modules[__name__].__dict__.values())
@ -113,18 +102,6 @@ class ParameterCRSTest(unittest.TestCase):
self.assertTrue(result.optional)
class ParameterDataObjectTest(unittest.TestCase):
def testGetValueAsCommandLineParameter(self):
parameter = ParameterDataObject('myName', 'myDesc')
parameter.setValue(None)
self.assertEqual(parameter.getValueAsCommandLineParameter(), "None")
parameter = ParameterDataObject('myName', 'myDesc')
parameter.setValue("someFile.dat")
self.assertEqual(parameter.getValueAsCommandLineParameter(), '"someFile.dat"')
class ParameterExtentTest(unittest.TestCase):
def testScriptCode(self):
@ -176,11 +153,6 @@ class ParameterSelectionTest(unittest.TestCase):
class ParameterFileTest(unittest.TestCase):
def testGetValueAsCommandLineParameter(self):
parameter = ParameterFile('myName', 'myDesc')
parameter.setValue('myFile.png')
self.assertEqual(parameter.getValueAsCommandLineParameter(), '"myFile.png"')
def testScriptCode(self):
parameter = ParameterFile('myName', 'myDescription')
code = parameter.getAsScriptCode()

View File

@ -185,6 +185,26 @@ bool QgsProcessingAlgorithm::validateInputCrs( const QVariantMap &parameters, Qg
return true;
}
QString QgsProcessingAlgorithm::asPythonCommand( const QVariantMap &parameters, QgsProcessingContext &context ) const
{
QString s = QStringLiteral( "processing.run(\"%1\"," ).arg( id() );
QStringList parts;
Q_FOREACH ( const QgsProcessingParameterDefinition *def, mParameters )
{
if ( def->flags() & QgsProcessingParameterDefinition::FlagHidden )
continue;
if ( !parameters.contains( def->name() ) || !parameters.value( def->name() ).isValid() )
continue;
parts << QStringLiteral( "'%1':%2" ).arg( def->name(), def->valueAsPythonString( parameters.value( def->name() ), context ) );
}
s += QStringLiteral( " {%1})" ).arg( parts.join( ',' ) );
return s;
}
bool QgsProcessingAlgorithm::addParameter( QgsProcessingParameterDefinition *definition )
{
if ( !definition )

View File

@ -253,6 +253,15 @@ class CORE_EXPORT QgsProcessingAlgorithm
virtual bool validateInputCrs( const QVariantMap &parameters,
QgsProcessingContext &context ) const;
/**
* Returns a Python command string which can be executed to run the algorithm
* using the specified \a parameters.
*
* Algorithms which cannot be run from a Python command should return an empty
* string.
*/
virtual QString asPythonCommand( const QVariantMap &parameters, QgsProcessingContext &context ) const;
protected:
/**

View File

@ -585,6 +585,13 @@ QList<QgsMapLayer *> QgsProcessingParameters::parameterAsLayerList( const QgsPro
}
}
}
else if ( val.type() == QVariant::StringList )
{
Q_FOREACH ( const QString &s, val.toStringList() )
{
resultStringList << s;
}
}
else
resultStringList << val.toString();
@ -726,10 +733,25 @@ bool QgsProcessingParameterDefinition::checkValueIsAcceptable( const QVariant &i
return true;
}
QString QgsProcessingParameterDefinition::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
{
if ( value.canConvert<QgsProperty>() )
return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
return value.toString().prepend( '\'' ).append( '\'' );
}
QgsProcessingParameterBoolean::QgsProcessingParameterBoolean( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
: QgsProcessingParameterDefinition( name, description, defaultValue, optional )
{}
QString QgsProcessingParameterBoolean::valueAsPythonString( const QVariant &val, QgsProcessingContext & ) const
{
if ( val.canConvert<QgsProperty>() )
return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
return val.toBool() ? QStringLiteral( "True" ) : QStringLiteral( "False" );
}
QgsProcessingParameterCrs::QgsProcessingParameterCrs( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
: QgsProcessingParameterDefinition( name, description, defaultValue, optional )
{
@ -752,6 +774,20 @@ bool QgsProcessingParameterCrs::checkValueIsAcceptable( const QVariant &input, Q
return true;
}
QString QgsProcessingParameterCrs::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
{
if ( value.canConvert<QgsProperty>() )
return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
QVariantMap p;
p.insert( name(), value );
QgsMapLayer *layer = QgsProcessingParameters::parameterAsLayer( this, p, context );
if ( layer )
return QgsProcessingUtils::normalizeLayerSource( layer->source() ).prepend( '\'' ).append( '\'' );
return QgsProcessingParameterDefinition::valueAsPythonString( value, context );
}
QgsProcessingParameterMapLayer::QgsProcessingParameterMapLayer( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
: QgsProcessingParameterDefinition( name, description, defaultValue, optional )
{
@ -789,6 +825,17 @@ bool QgsProcessingParameterMapLayer::checkValueIsAcceptable( const QVariant &inp
return false;
}
QString QgsProcessingParameterMapLayer::valueAsPythonString( const QVariant &val, QgsProcessingContext &context ) const
{
if ( val.canConvert<QgsProperty>() )
return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
QVariantMap p;
p.insert( name(), val );
QgsMapLayer *layer = QgsProcessingParameters::parameterAsLayer( this, p, context );
return layer ? QgsProcessingUtils::normalizeLayerSource( layer->source() ).prepend( '\'' ).append( '\'' ) : QString();
}
QgsProcessingParameterExtent::QgsProcessingParameterExtent( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
: QgsProcessingParameterDefinition( name, description, defaultValue, optional )
{
@ -836,6 +883,20 @@ bool QgsProcessingParameterExtent::checkValueIsAcceptable( const QVariant &input
return false;
}
QString QgsProcessingParameterExtent::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
{
if ( value.canConvert<QgsProperty>() )
return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
QVariantMap p;
p.insert( name(), value );
QgsMapLayer *layer = QgsProcessingParameters::parameterAsLayer( this, p, context );
if ( layer )
return QgsProcessingUtils::normalizeLayerSource( layer->source() ).prepend( '\'' ).append( '\'' );
return QgsProcessingParameterDefinition::valueAsPythonString( value, context );
}
QgsProcessingParameterPoint::QgsProcessingParameterPoint( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
: QgsProcessingParameterDefinition( name, description, defaultValue, optional )
{
@ -943,6 +1004,36 @@ bool QgsProcessingParameterMatrix::checkValueIsAcceptable( const QVariant &input
return false;
}
QString QgsProcessingParameterMatrix::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
{
if ( value.canConvert<QgsProperty>() )
return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
QVariantMap p;
p.insert( name(), value );
QVariantList list = QgsProcessingParameters::parameterAsMatrix( this, p, context );
QStringList parts;
Q_FOREACH ( const QVariant &v, list )
{
if ( v.type() == QVariant::List )
{
QStringList parts2;
Q_FOREACH ( const QVariant &v2, v.toList() )
{
parts2 << v2.toString();
}
parts << parts2.join( ',' ).prepend( '[' ).append( ']' );
}
else
{
parts << v.toString();
}
}
return parts.join( ',' ).prepend( '[' ).append( ']' );
}
QStringList QgsProcessingParameterMatrix::headers() const
{
return mHeaders;
@ -1045,6 +1136,27 @@ bool QgsProcessingParameterMultipleLayers::checkValueIsAcceptable( const QVarian
return false;
}
QString QgsProcessingParameterMultipleLayers::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
{
if ( value.canConvert<QgsProperty>() )
return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
QVariantMap p;
p.insert( name(), value );
QList<QgsMapLayer *> list = QgsProcessingParameters::parameterAsLayerList( this, p, context );
if ( !list.isEmpty() )
{
QStringList parts;
Q_FOREACH ( const QgsMapLayer *layer, list )
{
parts << QgsProcessingUtils::normalizeLayerSource( layer->source() ).prepend( '\'' ).append( '\'' );
}
return parts.join( ',' ).prepend( '[' ).append( ']' );
}
return QgsProcessingParameterDefinition::valueAsPythonString( value, context );
}
QgsProcessingParameterDefinition::LayerType QgsProcessingParameterMultipleLayers::layerType() const
{
return mLayerType;
@ -1096,6 +1208,14 @@ bool QgsProcessingParameterNumber::checkValueIsAcceptable( const QVariant &input
return true;
}
QString QgsProcessingParameterNumber::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
{
if ( value.canConvert<QgsProperty>() )
return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
return value.toString();
}
double QgsProcessingParameterNumber::minimum() const
{
return mMin;
@ -1173,6 +1293,23 @@ bool QgsProcessingParameterRange::checkValueIsAcceptable( const QVariant &input,
return false;
}
QString QgsProcessingParameterRange::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
{
if ( value.canConvert<QgsProperty>() )
return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
QVariantMap p;
p.insert( name(), value );
QList< double > parts = QgsProcessingParameters::parameterAsRange( this, p, context );
QStringList stringParts;
Q_FOREACH ( double v, parts )
{
stringParts << QString::number( v );
}
return stringParts.join( ',' ).prepend( '[' ).append( ']' );
}
QgsProcessingParameterNumber::Type QgsProcessingParameterRange::dataType() const
{
return mDataType;
@ -1218,6 +1355,17 @@ bool QgsProcessingParameterRasterLayer::checkValueIsAcceptable( const QVariant &
return false;
}
QString QgsProcessingParameterRasterLayer::valueAsPythonString( const QVariant &val, QgsProcessingContext &context ) const
{
if ( val.canConvert<QgsProperty>() )
return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
QVariantMap p;
p.insert( name(), val );
QgsRasterLayer *layer = QgsProcessingParameters::parameterAsRasterLayer( this, p, context );
return layer ? QgsProcessingUtils::normalizeLayerSource( layer->source() ).prepend( '\'' ).append( '\'' ) : QString();
}
QgsProcessingParameterEnum::QgsProcessingParameterEnum( const QString &name, const QString &description, const QStringList &options, bool allowMultiple, const QVariant &defaultValue, bool optional )
: QgsProcessingParameterDefinition( name, description, defaultValue, optional )
, mOptions( options )
@ -1282,6 +1430,32 @@ bool QgsProcessingParameterEnum::checkValueIsAcceptable( const QVariant &input,
return false;
}
QString QgsProcessingParameterEnum::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
{
if ( value.canConvert<QgsProperty>() )
return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
if ( value.type() == QVariant::List )
{
QStringList parts;
Q_FOREACH ( const QVariant &val, value.toList() )
{
parts << QString::number( static_cast< int >( val.toDouble() ) );
}
return parts.join( ',' ).prepend( '[' ).append( ']' );
}
else if ( value.type() == QVariant::String )
{
QStringList parts = value.toString().split( ',' );
if ( parts.count() > 1 )
{
return parts.join( ',' ).prepend( '[' ).append( ']' );
}
}
return QString::number( static_cast< int >( value.toDouble() ) );
}
QStringList QgsProcessingParameterEnum::options() const
{
return mOptions;
@ -1309,6 +1483,16 @@ QgsProcessingParameterString::QgsProcessingParameterString( const QString &name,
}
QString QgsProcessingParameterString::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
{
if ( value.canConvert<QgsProperty>() )
return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
QString s = value.toString();
s.replace( '\n', QStringLiteral( "\\n" ) );
return s.prepend( '\'' ).append( '\'' );
}
bool QgsProcessingParameterString::multiLine() const
{
return mMultiLine;
@ -1326,6 +1510,16 @@ QgsProcessingParameterExpression::QgsProcessingParameterExpression( const QStrin
}
QString QgsProcessingParameterExpression::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
{
if ( value.canConvert<QgsProperty>() )
return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
QString s = value.toString();
s.replace( '\n', QStringLiteral( "\\n" ) );
return s.prepend( '\'' ).append( '\'' );
}
QString QgsProcessingParameterExpression::parentLayerParameter() const
{
return mParentLayerParameter;
@ -1383,6 +1577,33 @@ bool QgsProcessingParameterTableField::checkValueIsAcceptable( const QVariant &i
return true;
}
QString QgsProcessingParameterTableField::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
{
if ( value.canConvert<QgsProperty>() )
return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
if ( value.type() == QVariant::List )
{
QStringList parts;
Q_FOREACH ( const QVariant &val, value.toList() )
{
parts << val.toString().prepend( '\'' ).append( '\'' );
}
return parts.join( ',' ).prepend( '[' ).append( ']' );
}
else if ( value.type() == QVariant::StringList )
{
QStringList parts;
Q_FOREACH ( QString s, value.toStringList() )
{
parts << s.prepend( '\'' ).append( '\'' );
}
return parts.join( ',' ).prepend( '[' ).append( ']' );
}
return value.toString().prepend( '\'' ).append( '\'' );
}
QString QgsProcessingParameterTableField::parentLayerParameter() const
{
return mParentLayerParameter;
@ -1457,6 +1678,29 @@ bool QgsProcessingParameterFeatureSource::checkValueIsAcceptable( const QVariant
return false;
}
QString QgsProcessingParameterFeatureSource::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
{
if ( value.canConvert<QgsProperty>() )
return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
if ( value.canConvert<QgsProcessingFeatureSourceDefinition>() )
{
QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( value );
if ( fromVar.source.propertyType() == QgsProperty::StaticProperty )
{
return QStringLiteral( "QgsProcessingFeatureSourceDefinition('%1', %2)" ).arg( fromVar.source.staticValue().toString(),
fromVar.selectedFeaturesOnly ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
}
else
{
return QStringLiteral( "QgsProcessingFeatureSourceDefinition(QgsProperty.fromExpression('%1'), %2)" ).arg( fromVar.source.asExpression(),
fromVar.selectedFeaturesOnly ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
}
}
return value.toString().prepend( '\'' ).append( '\'' );
}
QList< int > QgsProcessingParameterFeatureSource::dataTypes() const
{
return mDataTypes;
@ -1501,6 +1745,27 @@ bool QgsProcessingParameterFeatureSink::checkValueIsAcceptable( const QVariant &
return true;
}
QString QgsProcessingParameterFeatureSink::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
{
if ( value.canConvert<QgsProperty>() )
return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
if ( value.canConvert<QgsProcessingOutputLayerDefinition>() )
{
QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( value );
if ( fromVar.sink.propertyType() == QgsProperty::StaticProperty )
{
return QStringLiteral( "QgsProcessingOutputLayerDefinition('%1')" ).arg( fromVar.sink.staticValue().toString() );
}
else
{
return QStringLiteral( "QgsProcessingOutputLayerDefinition(QgsProperty.fromExpression('%1'))" ).arg( fromVar.sink.asExpression() );
}
}
return value.toString().prepend( '\'' ).append( '\'' );
}
QgsProcessingParameterDefinition::LayerType QgsProcessingParameterFeatureSink::dataType() const
{
return mDataType;
@ -1560,6 +1825,27 @@ bool QgsProcessingParameterRasterOutput::checkValueIsAcceptable( const QVariant
return true;
}
QString QgsProcessingParameterRasterOutput::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
{
if ( value.canConvert<QgsProperty>() )
return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
if ( value.canConvert<QgsProcessingOutputLayerDefinition>() )
{
QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( value );
if ( fromVar.sink.propertyType() == QgsProperty::StaticProperty )
{
return QStringLiteral( "QgsProcessingOutputLayerDefinition('%1')" ).arg( fromVar.sink.staticValue().toString() );
}
else
{
return QStringLiteral( "QgsProcessingOutputLayerDefinition(QgsProperty.fromExpression('%1'))" ).arg( fromVar.sink.asExpression() );
}
}
return value.toString().prepend( '\'' ).append( '\'' );
}
QgsProcessingParameterFileOutput::QgsProcessingParameterFileOutput( const QString &name, const QString &description, const QString &fileFilter, const QVariant &defaultValue, bool optional )
: QgsProcessingParameterDefinition( name, description, defaultValue, optional )
@ -1596,6 +1882,27 @@ bool QgsProcessingParameterFileOutput::checkValueIsAcceptable( const QVariant &i
return true;
}
QString QgsProcessingParameterFileOutput::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
{
if ( value.canConvert<QgsProperty>() )
return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
if ( value.canConvert<QgsProcessingOutputLayerDefinition>() )
{
QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( value );
if ( fromVar.sink.propertyType() == QgsProperty::StaticProperty )
{
return QStringLiteral( "QgsProcessingOutputLayerDefinition('%1')" ).arg( fromVar.sink.staticValue().toString() );
}
else
{
return QStringLiteral( "QgsProcessingOutputLayerDefinition(QgsProperty.fromExpression('%1'))" ).arg( fromVar.sink.asExpression() );
}
}
return value.toString().prepend( '\'' ).append( '\'' );
}
QString QgsProcessingParameterFileOutput::fileFilter() const
{
return mFileFilter;

View File

@ -319,6 +319,13 @@ class CORE_EXPORT QgsProcessingParameterDefinition
*/
virtual bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = nullptr ) const;
/**
* Returns a string version of the parameter input \a value, which is suitable for use as an input
* parameter value when running an algorithm directly from a Python command.
* The returned value must be correctly escaped - e.g. string values must be wrapped in ' 's.
*/
virtual QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const;
protected:
//! Parameter name
@ -530,6 +537,7 @@ class CORE_EXPORT QgsProcessingParameterBoolean : public QgsProcessingParameterD
bool optional = false );
QString type() const override { return QStringLiteral( "boolean" ); }
QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const override;
};
/**
@ -550,6 +558,7 @@ class CORE_EXPORT QgsProcessingParameterCrs : public QgsProcessingParameterDefin
QString type() const override { return QStringLiteral( "crs" ); }
bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = nullptr ) const override;
QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const override;
};
/**
@ -570,6 +579,7 @@ class CORE_EXPORT QgsProcessingParameterMapLayer : public QgsProcessingParameter
QString type() const override { return QStringLiteral( "layer" ); }
bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = nullptr ) const override;
QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const override;
};
/**
@ -590,6 +600,7 @@ class CORE_EXPORT QgsProcessingParameterExtent : public QgsProcessingParameterDe
QString type() const override { return QStringLiteral( "extent" ); }
bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = nullptr ) const override;
QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const override;
};
@ -691,6 +702,7 @@ class CORE_EXPORT QgsProcessingParameterMatrix : public QgsProcessingParameterDe
QString type() const override { return QStringLiteral( "matrix" ); }
bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = nullptr ) const override;
QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const override;
/**
* Returns a list of column headers (if set).
@ -761,6 +773,7 @@ class CORE_EXPORT QgsProcessingParameterMultipleLayers : public QgsProcessingPar
QString type() const override { return QStringLiteral( "multilayer" ); }
bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = nullptr ) const override;
QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const override;
/**
* Returns the layer type for layers acceptable by the parameter.
@ -825,6 +838,7 @@ class CORE_EXPORT QgsProcessingParameterNumber : public QgsProcessingParameterDe
QString type() const override { return QStringLiteral( "number" ); }
bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = nullptr ) const override;
QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const override;
/**
* Returns the minimum value acceptable by the parameter.
@ -889,6 +903,7 @@ class CORE_EXPORT QgsProcessingParameterRange : public QgsProcessingParameterDef
QString type() const override { return QStringLiteral( "range" ); }
bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = nullptr ) const override;
QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const override;
/**
* Returns the acceptable data type for the range.
@ -925,6 +940,7 @@ class CORE_EXPORT QgsProcessingParameterRasterLayer : public QgsProcessingParame
QString type() const override { return QStringLiteral( "raster" ); }
bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = nullptr ) const override;
QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const override;
};
@ -948,6 +964,7 @@ class CORE_EXPORT QgsProcessingParameterEnum : public QgsProcessingParameterDefi
QString type() const override { return QStringLiteral( "enum" ); }
bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = nullptr ) const override;
QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const override;
/**
* Returns the list of acceptable options for the parameter.
@ -998,6 +1015,7 @@ class CORE_EXPORT QgsProcessingParameterString : public QgsProcessingParameterDe
bool optional = false );
QString type() const override { return QStringLiteral( "string" ); }
QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const override;
/**
* Returns true if the parameter allows multiline strings.
@ -1035,6 +1053,7 @@ class CORE_EXPORT QgsProcessingParameterExpression : public QgsProcessingParamet
bool optional = false );
QString type() const override { return QStringLiteral( "expression" ); }
QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const override;
/**
* Returns the name of the parent layer parameter, or an empty string if this is not set.
@ -1104,6 +1123,7 @@ class CORE_EXPORT QgsProcessingParameterTableField : public QgsProcessingParamet
QString type() const override { return QStringLiteral( "field" ); }
bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = nullptr ) const override;
QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const override;
/**
* Returns the name of the parent layer parameter, or an empty string if this is not set.
@ -1168,6 +1188,7 @@ class CORE_EXPORT QgsProcessingParameterFeatureSource : public QgsProcessingPara
QString type() const override { return QStringLiteral( "source" ); }
bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = nullptr ) const override;
QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const override;
/**
* Returns the geometry types for sources acceptable by the parameter.
@ -1209,6 +1230,7 @@ class CORE_EXPORT QgsProcessingParameterFeatureSink : public QgsProcessingParame
QString type() const override { return QStringLiteral( "sink" ); }
bool isDestination() const override { return true; }
bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = nullptr ) const override;
QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const override;
/**
* Returns the layer type for sinks associated with the parameter.
@ -1253,6 +1275,7 @@ class CORE_EXPORT QgsProcessingParameterRasterOutput : public QgsProcessingParam
QString type() const override { return QStringLiteral( "rasterOut" ); }
bool isDestination() const override { return true; }
bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = nullptr ) const override;
QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const override;
};
/**
@ -1276,6 +1299,7 @@ class CORE_EXPORT QgsProcessingParameterFileOutput : public QgsProcessingParamet
QString type() const override { return QStringLiteral( "fileOut" ); }
bool isDestination() const override { return true; }
bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = nullptr ) const override;
QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const override;
/**
* Returns the file filter string for files compatible with this output.

View File

@ -187,6 +187,31 @@ class DummyAlgorithm : public QgsProcessingAlgorithm
QVERIFY( !validateInputCrs( parameters, context ) );
}
void runAsPythonCommandChecks()
{
addParameter( new QgsProcessingParameterString( "p1" ) );
addParameter( new QgsProcessingParameterString( "p2" ) );
QgsProcessingParameterString *hidden = new QgsProcessingParameterString( "p3" );
hidden->setFlags( QgsProcessingParameterDefinition::FlagHidden );
addParameter( hidden );
QVariantMap params;
QgsProcessingContext context;
QCOMPARE( asPythonCommand( params, context ), QStringLiteral( "processing.run(\"test\", {})" ) );
params.insert( "p1", "a" );
QCOMPARE( asPythonCommand( params, context ), QStringLiteral( "processing.run(\"test\", {'p1':'a'})" ) );
params.insert( "p2", QVariant() );
// not set, should be no change
QCOMPARE( asPythonCommand( params, context ), QStringLiteral( "processing.run(\"test\", {'p1':'a'})" ) );
params.insert( "p2", "b" );
QCOMPARE( asPythonCommand( params, context ), QStringLiteral( "processing.run(\"test\", {'p1':'a','p2':'b'})" ) );
// hidden, shouldn't be shown
params.insert( "p3", "b" );
QCOMPARE( asPythonCommand( params, context ), QStringLiteral( "processing.run(\"test\", {'p1':'a','p2':'b'})" ) );
}
};
//dummy provider for testing
@ -291,6 +316,7 @@ class TestQgsProcessing: public QObject
void algorithmScope();
void validateInputCrs();
void generateIteratingDestination();
void asPythonCommand();
private:
@ -1318,6 +1344,12 @@ void TestQgsProcessing::parameterBoolean()
params.remove( "non_optional_default_false" );
QCOMPARE( QgsProcessingParameters::parameterAsBool( def.get(), params, context ), false );
QCOMPARE( def->valueAsPythonString( false, context ), QStringLiteral( "False" ) );
QCOMPARE( def->valueAsPythonString( true, context ), QStringLiteral( "True" ) );
QCOMPARE( def->valueAsPythonString( "false", context ), QStringLiteral( "False" ) );
QCOMPARE( def->valueAsPythonString( "true", context ), QStringLiteral( "True" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProperty::fromExpression( "\"a\"=1" ) ), context ), QStringLiteral( "QgsProperty.fromExpression('\"a\"=1')" ) );
def.reset( new QgsProcessingParameterBoolean( "optional_default_true", QString(), true, true ) );
QVERIFY( def->checkValueIsAcceptable( false ) );
@ -1445,6 +1477,12 @@ void TestQgsProcessing::parameterCrs()
params.insert( "non_optional", QString( "i'm not a crs, and nothing you can do will make me one" ) );
QVERIFY( !QgsProcessingParameters::parameterAsCrs( def.get(), params, context ).isValid() );
QCOMPARE( def->valueAsPythonString( "EPSG:12003", context ), QStringLiteral( "'EPSG:12003'" ) );
QCOMPARE( def->valueAsPythonString( "ProjectCrs", context ), QStringLiteral( "'ProjectCrs'" ) );
QCOMPARE( def->valueAsPythonString( raster1, context ), QString( "'" ) + testDataDir + QStringLiteral( "tenbytenraster.asc'" ) );
QCOMPARE( def->valueAsPythonString( r1->id(), context ), QString( "'" ) + testDataDir + QStringLiteral( "tenbytenraster.asc'" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProperty::fromExpression( "\"a\"=1" ) ), context ), QStringLiteral( "QgsProperty.fromExpression('\"a\"=1')" ) );
// optional
def.reset( new QgsProcessingParameterCrs( "optional", QString(), QString( "EPSG:3113" ), true ) );
params.insert( "optional", QVariant() );
@ -1515,6 +1553,10 @@ void TestQgsProcessing::parameterLayer()
params.insert( "non_optional", QVariant::fromValue( v1 ) );
QCOMPARE( QgsProcessingParameters::parameterAsLayer( def.get(), params, context ), v1 );
QCOMPARE( def->valueAsPythonString( raster1, context ), QString( "'" ) + testDataDir + QStringLiteral( "tenbytenraster.asc'" ) );
QCOMPARE( def->valueAsPythonString( r1->id(), context ), QString( "'" ) + testDataDir + QStringLiteral( "tenbytenraster.asc'" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( r1 ), context ), QString( "'" ) + testDataDir + QStringLiteral( "tenbytenraster.asc'" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProperty::fromExpression( "\"a\"=1" ) ), context ), QStringLiteral( "QgsProperty.fromExpression('\"a\"=1')" ) );
// optional
def.reset( new QgsProcessingParameterMapLayer( "optional", QString(), v1->id(), true ) );
@ -1593,6 +1635,12 @@ void TestQgsProcessing::parameterExtent()
params.insert( "non_optional", QString( "i'm not a crs, and nothing you can do will make me one" ) );
QVERIFY( QgsProcessingParameters::parameterAsExtent( def.get(), params, context ).isNull() );
QCOMPARE( def->valueAsPythonString( "1,2,3,4", context ), QStringLiteral( "'1,2,3,4'" ) );
QCOMPARE( def->valueAsPythonString( r1->id(), context ), QString( "'" ) + testDataDir + QStringLiteral( "tenbytenraster.asc'" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( r1 ), context ), QString( "'" ) + testDataDir + QStringLiteral( "tenbytenraster.asc'" ) );
QCOMPARE( def->valueAsPythonString( raster2, context ), QString( "'" ) + testDataDir + QStringLiteral( "landsat.tif'" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProperty::fromExpression( "\"a\"=1" ) ), context ), QStringLiteral( "QgsProperty.fromExpression('\"a\"=1')" ) );
// optional
def.reset( new QgsProcessingParameterExtent( "optional", QString(), QString( "5,6,7,8" ), true ) );
QVERIFY( def->checkValueIsAcceptable( false ) );
@ -1638,6 +1686,8 @@ void TestQgsProcessing::parameterPoint()
QCOMPARE( point.x(), 0.0 );
QCOMPARE( point.y(), 0.0 );
QCOMPARE( def->valueAsPythonString( "1,2", context ), QStringLiteral( "'1,2'" ) );
// optional
def.reset( new QgsProcessingParameterPoint( "optional", QString(), QString( "5.1,6.2" ), true ) );
QVERIFY( def->checkValueIsAcceptable( "1.1,2" ) );
@ -1677,6 +1727,9 @@ void TestQgsProcessing::parameterFile()
QVERIFY( def->checkValueIsAcceptable( "bricks.BMP" ) );
QVERIFY( !def->checkValueIsAcceptable( "bricks.pcx" ) );
QCOMPARE( def->valueAsPythonString( "bricks.bmp", context ), QStringLiteral( "'bricks.bmp'" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProperty::fromExpression( "\"a\"=1" ) ), context ), QStringLiteral( "QgsProperty.fromExpression('\"a\"=1')" ) );
// optional
def.reset( new QgsProcessingParameterFile( "optional", QString(), QgsProcessingParameterFile::File, QString(), QString( "gef.bmp" ), true ) );
QVERIFY( def->checkValueIsAcceptable( false ) );
@ -1716,6 +1769,12 @@ void TestQgsProcessing::parameterMatrix()
params.insert( "non_optional", QString( "4,5,6" ) );
QCOMPARE( QgsProcessingParameters::parameterAsMatrix( def.get(), params, context ), QVariantList() << 4 << 5 << 6 );
QCOMPARE( def->valueAsPythonString( 5, context ), QStringLiteral( "[5]" ) );
QCOMPARE( def->valueAsPythonString( QVariantList() << 1 << 2 << 3, context ), QStringLiteral( "[1,2,3]" ) );
QCOMPARE( def->valueAsPythonString( QVariantList() << ( QVariantList() << 1 << 2 << 3 ) << ( QVariantList() << 1 << 2 << 3 ), context ), QStringLiteral( "[1,2,3,1,2,3]" ) );
QCOMPARE( def->valueAsPythonString( "1,2,3", context ), QStringLiteral( "[1,2,3]" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProperty::fromExpression( "\"a\"=1" ) ), context ), QStringLiteral( "QgsProperty.fromExpression('\"a\"=1')" ) );
// optional
def.reset( new QgsProcessingParameterMatrix( "optional", QString(), 3, false, QStringList(), QVariantList() << 4 << 5 << 6, true ) );
QVERIFY( def->checkValueIsAcceptable( 5 ) );
@ -1820,6 +1879,13 @@ void TestQgsProcessing::parameterLayerList()
QVERIFY( !def->checkValueIsAcceptable( QStringList() << "layer12312312" << "layerB" ) );
QVERIFY( !def->checkValueIsAcceptable( QVariantList() << "layer12312312" << "layerB" ) );
QCOMPARE( def->valueAsPythonString( "layer12312312", context ), QStringLiteral( "'layer12312312'" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( r1 ), context ), QStringLiteral( "['" ) + testDataDir + QStringLiteral( "tenbytenraster.asc']" ) );
QCOMPARE( def->valueAsPythonString( r1->id(), context ), QStringLiteral( "['" ) + testDataDir + QStringLiteral( "tenbytenraster.asc']" ) );
QCOMPARE( def->valueAsPythonString( QStringList() << r1->id() << raster2, context ), QStringLiteral( "['" ) + testDataDir + QStringLiteral( "tenbytenraster.asc','" ) + testDataDir + QStringLiteral( "landsat.tif']" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProperty::fromExpression( "\"a\"=1" ) ), context ), QStringLiteral( "QgsProperty.fromExpression('\"a\"=1')" ) );
// optional with one default layer
def.reset( new QgsProcessingParameterMultipleLayers( "optional", QString(), QgsProcessingParameterDefinition::TypeAny, v1->id(), true ) );
QVERIFY( !def->checkValueIsAcceptable( false ) );
@ -1911,6 +1977,10 @@ void TestQgsProcessing::parameterNumber()
QVERIFY( def->checkValueIsAcceptable( 15 ) );
QVERIFY( def->checkValueIsAcceptable( "11.1" ) );
QCOMPARE( def->valueAsPythonString( 5, context ), QStringLiteral( "5" ) );
QCOMPARE( def->valueAsPythonString( QStringLiteral( "1.1" ), context ), QStringLiteral( "1.1" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProperty::fromExpression( "\"a\"=1" ) ), context ), QStringLiteral( "QgsProperty.fromExpression('\"a\"=1')" ) );
// optional
def.reset( new QgsProcessingParameterNumber( "optional", QString(), QgsProcessingParameterNumber::Double, 5.4, true ) );
QVERIFY( def->checkValueIsAcceptable( 5 ) );
@ -1977,6 +2047,10 @@ void TestQgsProcessing::parameterRange()
params.insert( "non_optional", QVariantList() << 1.1 );
range = QgsProcessingParameters::parameterAsRange( def.get(), params, context );
QCOMPARE( def->valueAsPythonString( "1.1,2", context ), QStringLiteral( "[1.1,2]" ) );
QCOMPARE( def->valueAsPythonString( QVariantList() << 1.1 << 2, context ), QStringLiteral( "[1.1,2]" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProperty::fromExpression( "\"a\"=1" ) ), context ), QStringLiteral( "QgsProperty.fromExpression('\"a\"=1')" ) );
// optional
def.reset( new QgsProcessingParameterRange( "optional", QString(), QgsProcessingParameterNumber::Double, QString( "5.4,7.4" ), true ) );
QVERIFY( def->checkValueIsAcceptable( "1.1,2" ) );
@ -2049,6 +2123,11 @@ void TestQgsProcessing::parameterRasterLayer()
params.insert( "non_optional", QString( "i'm not a layer, and nothing you can do will make me one" ) );
QVERIFY( !QgsProcessingParameters::parameterAsRasterLayer( def.get(), params, context ) );
QCOMPARE( def->valueAsPythonString( raster1, context ), QString( "'" ) + testDataDir + QStringLiteral( "tenbytenraster.asc'" ) );
QCOMPARE( def->valueAsPythonString( r1->id(), context ), QString( "'" ) + testDataDir + QStringLiteral( "tenbytenraster.asc'" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( r1 ), context ), QString( "'" ) + testDataDir + QStringLiteral( "tenbytenraster.asc'" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProperty::fromExpression( "\"a\"=1" ) ), context ), QStringLiteral( "QgsProperty.fromExpression('\"a\"=1')" ) );
// optional
def.reset( new QgsProcessingParameterRasterLayer( "optional", QString(), r1->id(), true ) );
QCOMPARE( QgsProcessingParameters::parameterAsRasterLayer( def.get(), params, context )->id(), r1->id() );
@ -2114,6 +2193,10 @@ void TestQgsProcessing::parameterEnum()
iNumber = QgsProcessingParameters::parameterAsEnum( def.get(), params, context );
QCOMPARE( iNumber, 2 );
QCOMPARE( def->valueAsPythonString( 5, context ), QStringLiteral( "5" ) );
QCOMPARE( def->valueAsPythonString( QStringLiteral( "1.1" ), context ), QStringLiteral( "1" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProperty::fromExpression( "\"a\"=1" ) ), context ), QStringLiteral( "QgsProperty.fromExpression('\"a\"=1')" ) );
// multiple
def.reset( new QgsProcessingParameterEnum( "non_optional", QString(), QStringList() << "A" << "B" << "C", true, 5, false ) );
QVERIFY( !def->checkValueIsAcceptable( false ) );
@ -2137,6 +2220,9 @@ void TestQgsProcessing::parameterEnum()
iNumbers = QgsProcessingParameters::parameterAsEnums( def.get(), params, context );
QCOMPARE( iNumbers, QList<int>() << 0 << 2 );
QCOMPARE( def->valueAsPythonString( QVariantList() << 1 << 2, context ), QStringLiteral( "[1,2]" ) );
QCOMPARE( def->valueAsPythonString( QStringLiteral( "1,2" ), context ), QStringLiteral( "[1,2]" ) );
// optional
def.reset( new QgsProcessingParameterEnum( "optional", QString(), QStringList() << "a" << "b", false, 5, true ) );
QVERIFY( def->checkValueIsAcceptable( 1 ) );
@ -2197,6 +2283,12 @@ void TestQgsProcessing::parameterString()
params.insert( "non_optional", QString( "abcdef" ) );
QCOMPARE( QgsProcessingParameters::parameterAsString( def.get(), params, context ), QString( "abcdef" ) );
QCOMPARE( def->valueAsPythonString( 5, context ), QStringLiteral( "'5'" ) );
QCOMPARE( def->valueAsPythonString( QStringLiteral( "abc" ), context ), QStringLiteral( "'abc'" ) );
QCOMPARE( def->valueAsPythonString( QStringLiteral( "abc\ndef" ), context ), QStringLiteral( "'abc\\ndef'" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProperty::fromExpression( "\"a\"=1" ) ), context ), QStringLiteral( "QgsProperty.fromExpression('\"a\"=1')" ) );
// optional
def.reset( new QgsProcessingParameterString( "optional", QString(), QString( "default" ), false, true ) );
QVERIFY( def->checkValueIsAcceptable( 1 ) );
@ -2224,6 +2316,12 @@ void TestQgsProcessing::parameterExpression()
params.insert( "non_optional", QString( "abcdef" ) );
QCOMPARE( QgsProcessingParameters::parameterAsExpression( def.get(), params, context ), QString( "abcdef" ) );
QCOMPARE( def->valueAsPythonString( 5, context ), QStringLiteral( "'5'" ) );
QCOMPARE( def->valueAsPythonString( QStringLiteral( "abc" ), context ), QStringLiteral( "'abc'" ) );
QCOMPARE( def->valueAsPythonString( QStringLiteral( "abc\ndef" ), context ), QStringLiteral( "'abc\\ndef'" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProperty::fromExpression( "\"a\"=1" ) ), context ), QStringLiteral( "QgsProperty.fromExpression('\"a\"=1')" ) );
// optional
def.reset( new QgsProcessingParameterExpression( "optional", QString(), QString( "default" ), QString(), true ) );
QVERIFY( def->checkValueIsAcceptable( 1 ) );
@ -2260,6 +2358,9 @@ void TestQgsProcessing::parameterField()
QStringList fields = QgsProcessingParameters::parameterAsFields( def.get(), params, context );
QCOMPARE( fields, QStringList() << "a" );
QCOMPARE( def->valueAsPythonString( QStringLiteral( "abc" ), context ), QStringLiteral( "'abc'" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProperty::fromExpression( "\"a\"=1" ) ), context ), QStringLiteral( "QgsProperty.fromExpression('\"a\"=1')" ) );
// multiple
def.reset( new QgsProcessingParameterTableField( "non_optional", QString(), QString(), QString(), QgsProcessingParameterTableField::Any, true, false ) );
QVERIFY( def->checkValueIsAcceptable( 1 ) );
@ -2276,6 +2377,9 @@ void TestQgsProcessing::parameterField()
fields = QgsProcessingParameters::parameterAsFields( def.get(), params, context );
QCOMPARE( fields, QStringList() << "a" << "b" );
QCOMPARE( def->valueAsPythonString( QStringList() << "a" << "b", context ), QStringLiteral( "['a','b']" ) );
QCOMPARE( def->valueAsPythonString( QStringList() << "a" << "b", context ), QStringLiteral( "['a','b']" ) );
// optional
def.reset( new QgsProcessingParameterTableField( "optional", QString(), QString( "def" ), QString(), QgsProcessingParameterTableField::Any, false, true ) );
QVERIFY( def->checkValueIsAcceptable( 1 ) );
@ -2370,6 +2474,12 @@ void TestQgsProcessing::parameterFeatureSource()
params.insert( "non_optional", QString( "i'm not a layer, and nothing you can do will make me one" ) );
QVERIFY( !QgsProcessingParameters::parameterAsVectorLayer( def.get(), params, context ) );
QCOMPARE( def->valueAsPythonString( QStringLiteral( "abc" ), context ), QStringLiteral( "'abc'" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProcessingFeatureSourceDefinition( "abc" ) ), context ), QStringLiteral( "QgsProcessingFeatureSourceDefinition('abc', False)" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProcessingFeatureSourceDefinition( QgsProperty::fromValue( "abc" ), true ) ), context ), QStringLiteral( "QgsProcessingFeatureSourceDefinition('abc', True)" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProcessingFeatureSourceDefinition( QgsProperty::fromExpression( "\"abc\" || \"def\"" ) ) ), context ), QStringLiteral( "QgsProcessingFeatureSourceDefinition(QgsProperty.fromExpression('\"abc\" || \"def\"'), False)" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProperty::fromExpression( "\"a\"=1" ) ), context ), QStringLiteral( "QgsProperty.fromExpression('\"a\"=1')" ) );
// optional
def.reset( new QgsProcessingParameterFeatureSource( "optional", QString(), QList< int >() << QgsProcessingParameterDefinition::TypeVectorAny, v1->id(), true ) );
params.insert( "optional", QVariant() );
@ -2410,6 +2520,12 @@ void TestQgsProcessing::parameterFeatureSink()
QVERIFY( def->checkValueIsAcceptable( "c:/Users/admin/Desktop/roads_clipped_transformed_v1_reprojected_final_clipped_aAAA.shp" ) );
QVERIFY( def->checkValueIsAcceptable( "c:/Users/admin/Desktop/roads_clipped_transformed_v1_reprojected_final_clipped_aAAA.shp", &context ) );
QCOMPARE( def->valueAsPythonString( QStringLiteral( "abc" ), context ), QStringLiteral( "'abc'" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProcessingOutputLayerDefinition( "abc" ) ), context ), QStringLiteral( "QgsProcessingOutputLayerDefinition('abc')" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProcessingOutputLayerDefinition( QgsProperty::fromValue( "abc" ) ) ), context ), QStringLiteral( "QgsProcessingOutputLayerDefinition('abc')" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProcessingOutputLayerDefinition( QgsProperty::fromExpression( "\"abc\" || \"def\"" ) ) ), context ), QStringLiteral( "QgsProcessingOutputLayerDefinition(QgsProperty.fromExpression('\"abc\" || \"def\"'))" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProperty::fromExpression( "\"a\"=1" ) ), context ), QStringLiteral( "QgsProperty.fromExpression('\"a\"=1')" ) );
// optional
def.reset( new QgsProcessingParameterFeatureSink( "optional", QString(), QgsProcessingParameterDefinition::TypeVectorAny, QString(), true ) );
QVERIFY( !def->checkValueIsAcceptable( false ) );
@ -2461,6 +2577,12 @@ void TestQgsProcessing::parameterRasterOut()
params.insert( "non_optional", QgsProcessingOutputLayerDefinition( "test.tif" ) );
QCOMPARE( QgsProcessingParameters::parameterAsRasterOutputLayer( def.get(), params, context ), QStringLiteral( "test.tif" ) );
QCOMPARE( def->valueAsPythonString( QStringLiteral( "abc" ), context ), QStringLiteral( "'abc'" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProcessingOutputLayerDefinition( "abc" ) ), context ), QStringLiteral( "QgsProcessingOutputLayerDefinition('abc')" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProcessingOutputLayerDefinition( QgsProperty::fromValue( "abc" ) ) ), context ), QStringLiteral( "QgsProcessingOutputLayerDefinition('abc')" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProcessingOutputLayerDefinition( QgsProperty::fromExpression( "\"abc\" || \"def\"" ) ) ), context ), QStringLiteral( "QgsProcessingOutputLayerDefinition(QgsProperty.fromExpression('\"abc\" || \"def\"'))" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProperty::fromExpression( "\"a\"=1" ) ), context ), QStringLiteral( "QgsProperty.fromExpression('\"a\"=1')" ) );
// optional
def.reset( new QgsProcessingParameterRasterOutput( "optional", QString(), QString( "default.tif" ), true ) );
QVERIFY( !def->checkValueIsAcceptable( false ) );
@ -2509,6 +2631,13 @@ void TestQgsProcessing::parameterFileOut()
params.insert( "non_optional", QgsProcessingOutputLayerDefinition( "test.txt" ) );
QCOMPARE( QgsProcessingParameters::parameterAsFileOutput( def.get(), params, context ), QStringLiteral( "test.txt" ) );
QCOMPARE( def->valueAsPythonString( QStringLiteral( "abc" ), context ), QStringLiteral( "'abc'" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProcessingOutputLayerDefinition( "abc" ) ), context ), QStringLiteral( "QgsProcessingOutputLayerDefinition('abc')" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProcessingOutputLayerDefinition( QgsProperty::fromValue( "abc" ) ) ), context ), QStringLiteral( "QgsProcessingOutputLayerDefinition('abc')" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProcessingOutputLayerDefinition( QgsProperty::fromExpression( "\"abc\" || \"def\"" ) ) ), context ), QStringLiteral( "QgsProcessingOutputLayerDefinition(QgsProperty.fromExpression('\"abc\" || \"def\"'))" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProperty::fromExpression( "\"a\"=1" ) ), context ), QStringLiteral( "QgsProperty.fromExpression('\"a\"=1')" ) );
// optional
def.reset( new QgsProcessingParameterFileOutput( "optional", QString(), QString(), QString( "default.txt" ), true ) );
QVERIFY( !def->checkValueIsAcceptable( false ) );
@ -2742,5 +2871,11 @@ void TestQgsProcessing::generateIteratingDestination()
QCOMPARE( fromVar.destinationProject, &p );
}
void TestQgsProcessing::asPythonCommand()
{
DummyAlgorithm alg( "test" );
alg.runAsPythonCommandChecks();
}
QGSTEST_MAIN( TestQgsProcessing )
#include "testqgsprocessing.moc"