Skip to content
Permalink
Browse files

Allow model child parameters to take values from an expression

The expression is evaluated just before the child algorithm is
executed, so can utilise results already calculated by other
children in the model through the use of expression context
functions
  • Loading branch information
nyalldawson committed Jul 7, 2017
1 parent 52f4c5e commit 3243a1a34c3cd1b4112bce5eb91b5dc440bfcb16
@@ -39,12 +39,13 @@ class QgsProcessingModelAlgorithm : QgsProcessingAlgorithm
ModelParameter,
ChildOutput,
StaticValue,
Expression,
};

ChildParameterSource();
%Docstring
Constructor for ChildParameterSource. It is recommended that the static methods
fromStaticValue(), fromModelParameter() and fromChildOutput() are used instead.
fromStaticValue(), fromModelParameter(), fromChildOutput() and fromExpression() are used instead.
%End

bool operator==( const QgsProcessingModelAlgorithm::ChildParameterSource &other ) const;
@@ -58,6 +59,7 @@ class QgsProcessingModelAlgorithm : QgsProcessingAlgorithm
Returns a new ChildParameterSource which takes its value from a static ``value``.
.. seealso:: fromModelParameter()
.. seealso:: fromChildOutput()
.. seealso:: fromExpression()
:rtype: QgsProcessingModelAlgorithm.ChildParameterSource
%End

@@ -66,13 +68,27 @@ class QgsProcessingModelAlgorithm : QgsProcessingAlgorithm
Returns a new ChildParameterSource which takes its value from a parent model parameter.
.. seealso:: fromStaticValue()
.. seealso:: fromChildOutput()
.. seealso:: fromExpression()
:rtype: QgsProcessingModelAlgorithm.ChildParameterSource
%End

static QgsProcessingModelAlgorithm::ChildParameterSource fromChildOutput( const QString &childId, const QString &outputName );
%Docstring
Returns a new ChildParameterSource which takes its value from an output generated by a child algorithm.
.. seealso:: fromStaticValue()
.. seealso:: fromModelParameter()
.. seealso:: fromExpression()
:rtype: QgsProcessingModelAlgorithm.ChildParameterSource
%End

static QgsProcessingModelAlgorithm::ChildParameterSource fromExpression( const QString &expression );
%Docstring
Returns a new ChildParameterSource which takes its value from an expression. The expression
is evaluated just before the child algorithm executes, and can use functions available
in its expression context to include results calculated from the child algorithms already
executed by the model.
.. seealso:: fromStaticValue()
.. seealso:: fromChildOutput()
.. seealso:: fromModelParameter()
:rtype: QgsProcessingModelAlgorithm.ChildParameterSource
%End
@@ -137,6 +153,22 @@ class QgsProcessingModelAlgorithm : QgsProcessingAlgorithm
Sets the source's child algorithm output ``name`` from which the output value will be taken. Calling this will also change the source() to ChildOutput.
.. seealso:: outputName()
.. seealso:: setOutputChildId()
%End

QString expression() const;
%Docstring
Returns the source's expression. This is only used when the source() is Expression.
.. seealso:: setExpression()
:rtype: str
%End

void setExpression( const QString &expression );
%Docstring
Sets the source's expression. Calling this will also change the source() to Expression.
The expression is evaluated just before the child algorithm executes, and can use functions available
in its expression context to include results calculated from the child algorithms already
executed by the model.
.. seealso:: expression()
%End

QVariant toVariant() const;
@@ -385,6 +385,13 @@ QVariantMap QgsProcessingModelAlgorithm::parametersForChildAlgorithm( const Chil
paramParts << linkedChildResults.value( source.outputName() );
break;
}

case ChildParameterSource::Expression:
{
QgsExpression exp( source.expression() );
paramParts << exp.evaluate();
break;
}
}
}
if ( paramParts.count() == 1 )
@@ -1125,6 +1132,8 @@ bool QgsProcessingModelAlgorithm::ChildParameterSource::operator==( const QgsPro
return mChildId == other.mChildId && mOutputName == other.mOutputName;
case ModelParameter:
return mParameterName == other.mParameterName;
case Expression:
return mExpression == other.mExpression;
}
return false;
}
@@ -1154,6 +1163,14 @@ QgsProcessingModelAlgorithm::ChildParameterSource QgsProcessingModelAlgorithm::C
return src;
}

QgsProcessingModelAlgorithm::ChildParameterSource QgsProcessingModelAlgorithm::ChildParameterSource::fromExpression( const QString &expression )
{
ChildParameterSource src;
src.mSource = Expression;
src.mExpression = expression;
return src;
}

QgsProcessingModelAlgorithm::ChildParameterSource::Source QgsProcessingModelAlgorithm::ChildParameterSource::source() const
{
return mSource;
@@ -1177,6 +1194,10 @@ QVariant QgsProcessingModelAlgorithm::ChildParameterSource::toVariant() const
case StaticValue:
map.insert( QStringLiteral( "static_value" ), mStaticValue );
break;

case Expression:
map.insert( QStringLiteral( "expression" ), mExpression );
break;
}
return map;
}
@@ -1198,6 +1219,10 @@ bool QgsProcessingModelAlgorithm::ChildParameterSource::loadVariant( const QVari
case StaticValue:
mStaticValue = map.value( QStringLiteral( "static_value" ) );
break;

case Expression:
mExpression = map.value( QStringLiteral( "expression" ) ).toString();
break;
}
return true;
}
@@ -1214,6 +1239,9 @@ QString QgsProcessingModelAlgorithm::ChildParameterSource::asPythonCode() const

case StaticValue:
return mStaticValue.toString();

case Expression:
return QStringLiteral( "QgsExpression('%1').evaluate()" ).arg( mExpression );
}
return QString();
}
@@ -49,11 +49,12 @@ class CORE_EXPORT QgsProcessingModelAlgorithm : public QgsProcessingAlgorithm
ModelParameter, //!< Parameter value is taken from a parent model parameter
ChildOutput, //!< Parameter value is taken from an output generated by a child algorithm
StaticValue, //!< Parameter value is a static value
Expression, //!< Parameter value is taken from an expression, evaluated just before the algorithm runs
};

/**
* Constructor for ChildParameterSource. It is recommended that the static methods
* fromStaticValue(), fromModelParameter() and fromChildOutput() are used instead.
* fromStaticValue(), fromModelParameter(), fromChildOutput() and fromExpression() are used instead.
*/
ChildParameterSource() = default;

@@ -67,23 +68,37 @@ class CORE_EXPORT QgsProcessingModelAlgorithm : public QgsProcessingAlgorithm
* Returns a new ChildParameterSource which takes its value from a static \a value.
* \see fromModelParameter()
* \see fromChildOutput()
* \see fromExpression()
*/
static QgsProcessingModelAlgorithm::ChildParameterSource fromStaticValue( const QVariant &value );

/**
* Returns a new ChildParameterSource which takes its value from a parent model parameter.
* \see fromStaticValue()
* \see fromChildOutput()
* \see fromExpression()
*/
static QgsProcessingModelAlgorithm::ChildParameterSource fromModelParameter( const QString &parameterName );

/**
* Returns a new ChildParameterSource which takes its value from an output generated by a child algorithm.
* \see fromStaticValue()
* \see fromModelParameter()
* \see fromExpression()
*/
static QgsProcessingModelAlgorithm::ChildParameterSource fromChildOutput( const QString &childId, const QString &outputName );

/**
* Returns a new ChildParameterSource which takes its value from an expression. The expression
* is evaluated just before the child algorithm executes, and can use functions available
* in its expression context to include results calculated from the child algorithms already
* executed by the model.
* \see fromStaticValue()
* \see fromChildOutput()
* \see fromModelParameter()
*/
static QgsProcessingModelAlgorithm::ChildParameterSource fromExpression( const QString &expression );

/**
* Returns the parameter value's source.
*/
@@ -141,6 +156,21 @@ class CORE_EXPORT QgsProcessingModelAlgorithm : public QgsProcessingAlgorithm
*/
void setOutputName( const QString &name ) { mOutputName = name; mSource = ChildOutput; }

/**
* Returns the source's expression. This is only used when the source() is Expression.
* \see setExpression()
*/
QString expression() const { return mExpression; }

/**
* Sets the source's expression. Calling this will also change the source() to Expression.
* The expression is evaluated just before the child algorithm executes, and can use functions available
* in its expression context to include results calculated from the child algorithms already
* executed by the model.
* \see expression()
*/
void setExpression( const QString &expression ) { mExpression = expression; mSource = Expression; }

/**
* Saves this source to a QVariant.
* \see loadVariant()
@@ -165,6 +195,7 @@ class CORE_EXPORT QgsProcessingModelAlgorithm : public QgsProcessingAlgorithm
QString mParameterName;
QString mChildId;
QString mOutputName;
QString mExpression;

};

@@ -4220,6 +4220,19 @@ void TestQgsProcessing::modelerAlgorithm()
QCOMPARE( oSource.outputName(), QStringLiteral( "d" ) );
QCOMPARE( oSource.source(), QgsProcessingModelAlgorithm::ChildParameterSource::ChildOutput );

// expression source
QgsProcessingModelAlgorithm::ChildParameterSource expSource = QgsProcessingModelAlgorithm::ChildParameterSource::fromExpression( "1+2" );
QCOMPARE( expSource.source(), QgsProcessingModelAlgorithm::ChildParameterSource::Expression );
QCOMPARE( expSource.expression(), QStringLiteral( "1+2" ) );
expSource.setExpression( "1+3" );
QCOMPARE( expSource.expression(), QStringLiteral( "1+3" ) );
expSource = QgsProcessingModelAlgorithm::ChildParameterSource::fromStaticValue( 5 );
// check that calling setExpression flips source to Expression
QCOMPARE( expSource.source(), QgsProcessingModelAlgorithm::ChildParameterSource::StaticValue );
expSource.setExpression( "1+4" );
QCOMPARE( expSource.expression(), QStringLiteral( "1+4" ) );
QCOMPARE( expSource.source(), QgsProcessingModelAlgorithm::ChildParameterSource::Expression );

// source equality operator
QVERIFY( QgsProcessingModelAlgorithm::ChildParameterSource::fromStaticValue( 5 ) ==
QgsProcessingModelAlgorithm::ChildParameterSource::fromStaticValue( 5 ) );
@@ -4239,6 +4252,12 @@ void TestQgsProcessing::modelerAlgorithm()
QgsProcessingModelAlgorithm::ChildParameterSource::fromChildOutput( QStringLiteral( "alg2" ), QStringLiteral( "out" ) ) );
QVERIFY( QgsProcessingModelAlgorithm::ChildParameterSource::fromChildOutput( QStringLiteral( "alg" ), QStringLiteral( "out" ) ) !=
QgsProcessingModelAlgorithm::ChildParameterSource::fromChildOutput( QStringLiteral( "alg" ), QStringLiteral( "out2" ) ) );
QVERIFY( QgsProcessingModelAlgorithm::ChildParameterSource::fromExpression( QStringLiteral( "a" ) ) ==
QgsProcessingModelAlgorithm::ChildParameterSource::fromExpression( QStringLiteral( "a" ) ) );
QVERIFY( QgsProcessingModelAlgorithm::ChildParameterSource::fromExpression( QStringLiteral( "a" ) ) !=
QgsProcessingModelAlgorithm::ChildParameterSource::fromExpression( QStringLiteral( "b" ) ) );
QVERIFY( QgsProcessingModelAlgorithm::ChildParameterSource::fromExpression( QStringLiteral( "a" ) ) !=
QgsProcessingModelAlgorithm::ChildParameterSource::fromStaticValue( QStringLiteral( "b" ) ) );



@@ -4562,9 +4581,11 @@ void TestQgsProcessing::modelerAlgorithm()
alg5c1.addParameterSources( "x", QgsProcessingModelAlgorithm::ChildParameterSources() << QgsProcessingModelAlgorithm::ChildParameterSource::fromModelParameter( "p1" ) );
alg5c1.addParameterSources( "y", QgsProcessingModelAlgorithm::ChildParameterSources() << QgsProcessingModelAlgorithm::ChildParameterSource::fromChildOutput( "cx2", "out3" ) );
alg5c1.addParameterSources( "z", QgsProcessingModelAlgorithm::ChildParameterSources() << QgsProcessingModelAlgorithm::ChildParameterSource::fromStaticValue( 5 ) );
alg5c1.addParameterSources( "a", QgsProcessingModelAlgorithm::ChildParameterSources() << QgsProcessingModelAlgorithm::ChildParameterSource::fromExpression( "2*2" ) );
alg5c1.addParameterSources( "zm", QgsProcessingModelAlgorithm::ChildParameterSources() << QgsProcessingModelAlgorithm::ChildParameterSource::fromStaticValue( 6 )
<< QgsProcessingModelAlgorithm::ChildParameterSource::fromModelParameter( "p2" )
<< QgsProcessingModelAlgorithm::ChildParameterSource::fromChildOutput( "cx2", "out4" ) );
<< QgsProcessingModelAlgorithm::ChildParameterSource::fromChildOutput( "cx2", "out4" )
<< QgsProcessingModelAlgorithm::ChildParameterSource::fromExpression( "1+2" ) );
alg5c1.setActive( true );
alg5c1.setOutputsCollapsed( true );
alg5c1.setParametersCollapsed( true );
@@ -4609,21 +4630,26 @@ void TestQgsProcessing::modelerAlgorithm()
QCOMPARE( alg6c1.description(), QStringLiteral( "child 1" ) );
QCOMPARE( alg6c1.position().x(), 1.0 );
QCOMPARE( alg6c1.position().y(), 2.0 );
QCOMPARE( alg6c1.parameterSources().count(), 4 );
QCOMPARE( alg6c1.parameterSources().count(), 5 );
QCOMPARE( alg6c1.parameterSources().value( "x" ).at( 0 ).source(), QgsProcessingModelAlgorithm::ChildParameterSource::ModelParameter );
QCOMPARE( alg6c1.parameterSources().value( "x" ).at( 0 ).parameterName(), QStringLiteral( "p1" ) );
QCOMPARE( alg6c1.parameterSources().value( "y" ).at( 0 ).source(), QgsProcessingModelAlgorithm::ChildParameterSource::ChildOutput );
QCOMPARE( alg6c1.parameterSources().value( "y" ).at( 0 ).outputChildId(), QStringLiteral( "cx2" ) );
QCOMPARE( alg6c1.parameterSources().value( "y" ).at( 0 ).outputName(), QStringLiteral( "out3" ) );
QCOMPARE( alg6c1.parameterSources().value( "z" ).at( 0 ).source(), QgsProcessingModelAlgorithm::ChildParameterSource::StaticValue );
QCOMPARE( alg6c1.parameterSources().value( "z" ).at( 0 ).staticValue().toInt(), 5 );
QCOMPARE( alg6c1.parameterSources().value( "a" ).at( 0 ).source(), QgsProcessingModelAlgorithm::ChildParameterSource::Expression );
QCOMPARE( alg6c1.parameterSources().value( "a" ).at( 0 ).expression(), QStringLiteral( "2*2" ) );
QCOMPARE( alg6c1.parameterSources().value( "zm" ).count(), 4 );
QCOMPARE( alg6c1.parameterSources().value( "zm" ).at( 0 ).source(), QgsProcessingModelAlgorithm::ChildParameterSource::StaticValue );
QCOMPARE( alg6c1.parameterSources().value( "zm" ).at( 0 ).staticValue().toInt(), 6 );
QCOMPARE( alg6c1.parameterSources().value( "zm" ).at( 1 ).source(), QgsProcessingModelAlgorithm::ChildParameterSource::ModelParameter );
QCOMPARE( alg6c1.parameterSources().value( "zm" ).at( 1 ).parameterName(), QStringLiteral( "p2" ) );
QCOMPARE( alg6c1.parameterSources().value( "zm" ).at( 2 ).source(), QgsProcessingModelAlgorithm::ChildParameterSource::ChildOutput );
QCOMPARE( alg6c1.parameterSources().value( "zm" ).at( 2 ).outputChildId(), QStringLiteral( "cx2" ) );
QCOMPARE( alg6c1.parameterSources().value( "zm" ).at( 2 ).outputName(), QStringLiteral( "out4" ) );
QCOMPARE( alg6c1.parameterSources().value( "zm" ).at( 3 ).source(), QgsProcessingModelAlgorithm::ChildParameterSource::Expression );
QCOMPARE( alg6c1.parameterSources().value( "zm" ).at( 3 ).expression(), QStringLiteral( "1+2" ) );

QCOMPARE( alg6c1.modelOutputs().count(), 1 );
QCOMPARE( alg6c1.modelOutputs().value( QStringLiteral( "a" ) ).description(), QStringLiteral( "my output" ) );
@@ -4739,7 +4765,7 @@ void TestQgsProcessing::modelExecution()
alg2c1.setAlgorithmId( "native:buffer" );
alg2c1.addParameterSources( "INPUT", QgsProcessingModelAlgorithm::ChildParameterSources() << QgsProcessingModelAlgorithm::ChildParameterSource::fromModelParameter( "SOURCE_LAYER" ) );
alg2c1.addParameterSources( "DISTANCE", QgsProcessingModelAlgorithm::ChildParameterSources() << QgsProcessingModelAlgorithm::ChildParameterSource::fromModelParameter( "DIST" ) );
alg2c1.addParameterSources( "SEGMENTS", QgsProcessingModelAlgorithm::ChildParameterSources() << QgsProcessingModelAlgorithm::ChildParameterSource::fromStaticValue( 16 ) );
alg2c1.addParameterSources( "SEGMENTS", QgsProcessingModelAlgorithm::ChildParameterSources() << QgsProcessingModelAlgorithm::ChildParameterSource::fromExpression( QStringLiteral( "8*2" ) ) );
alg2c1.addParameterSources( "END_CAP_STYLE", QgsProcessingModelAlgorithm::ChildParameterSources() << QgsProcessingModelAlgorithm::ChildParameterSource::fromStaticValue( 1 ) );
alg2c1.addParameterSources( "JOIN_STYLE", QgsProcessingModelAlgorithm::ChildParameterSources() << QgsProcessingModelAlgorithm::ChildParameterSource::fromStaticValue( 2 ) );
alg2c1.addParameterSources( "DISSOLVE", QgsProcessingModelAlgorithm::ChildParameterSources() << QgsProcessingModelAlgorithm::ChildParameterSource::fromStaticValue( false ) );
@@ -4814,7 +4840,7 @@ void TestQgsProcessing::modelExecution()
"##model_out_layer=output outputVector\n"
"##my_out=output outputVector\n"
"results={}\n"
"outputs['cx1']=processing.run('native:buffer', {'DISSOLVE':false,'DISTANCE':parameters['DIST'],'END_CAP_STYLE':1,'INPUT':parameters['SOURCE_LAYER'],'JOIN_STYLE':2,'SEGMENTS':16}, context=context, feedback=feedback)\n"
"outputs['cx1']=processing.run('native:buffer', {'DISSOLVE':false,'DISTANCE':parameters['DIST'],'END_CAP_STYLE':1,'INPUT':parameters['SOURCE_LAYER'],'JOIN_STYLE':2,'SEGMENTS':QgsExpression('8*2').evaluate()}, context=context, feedback=feedback)\n"
"results['MODEL_OUT_LAYER']=outputs['cx1']['OUTPUT']\n"
"outputs['cx2']=processing.run('native:centroids', {'INPUT':outputs['cx1']['OUTPUT']}, context=context, feedback=feedback)\n"
"outputs['cx3']=processing.run('native:extractbyexpression', {'EXPRESSION':true,'INPUT':outputs['cx1']['OUTPUT'],'OUTPUT':parameters['MY_OUT']}, context=context, feedback=feedback)\n"

0 comments on commit 3243a1a

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