diff --git a/src/core/expression/qgsexpressionfunction.cpp b/src/core/expression/qgsexpressionfunction.cpp index 66b26614d78e..28f06a0aac00 100644 --- a/src/core/expression/qgsexpressionfunction.cpp +++ b/src/core/expression/qgsexpressionfunction.cpp @@ -9148,7 +9148,28 @@ const QList &QgsExpression::Functions() functions << varFunction; - functions << new QgsStaticExpressionFunction( QStringLiteral( "eval_template" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "template" ) ), fcnEvalTemplate, QStringLiteral( "General" ), QString(), true ); + QgsStaticExpressionFunction *evalTemplateFunction = new QgsStaticExpressionFunction( QStringLiteral( "eval_template" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "template" ) ), fcnEvalTemplate, QStringLiteral( "General" ), QString(), true, QSet() << QgsFeatureRequest::ALL_ATTRIBUTES ); + evalTemplateFunction->setIsStaticFunction( + []( const QgsExpressionNodeFunction * node, QgsExpression * parent, const QgsExpressionContext * context ) + { + if ( node->args()->count() > 0 ) + { + QgsExpressionNode *argNode = node->args()->at( 0 ); + + if ( argNode->isStatic( parent, context ) ) + { + QString expString = argNode->eval( parent, context ).toString(); + + QgsExpression e( expString ); + + if ( e.rootNode() && e.rootNode()->isStatic( parent, context ) ) + return true; + } + } + + return false; + } ); + functions << evalTemplateFunction; QgsStaticExpressionFunction *evalFunc = new QgsStaticExpressionFunction( QStringLiteral( "eval" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "expression" ) ), fcnEval, QStringLiteral( "General" ), QString(), true, QSet() << QgsFeatureRequest::ALL_ATTRIBUTES ); evalFunc->setIsStaticFunction( diff --git a/tests/src/python/test_qgsexpression.py b/tests/src/python/test_qgsexpression.py index abade6da0eeb..d49855034048 100644 --- a/tests/src/python/test_qgsexpression.py +++ b/tests/src/python/test_qgsexpression.py @@ -323,6 +323,23 @@ def testSuccessfulEvaluationReturnsNoEvalErrorString(self): exp = QgsExpression("True is False") # the result does not matter self.assertEqual(exp.evalErrorString(), "") + def testEvalTemplate(self): + layer = QgsVectorLayer("Point?field=a:int&field=b:string", "test eval-template", "memory") + context = layer.createExpressionContext() + + expression = QgsExpression("eval_template('123 [% \"b\" %] 789')") + expression.prepare(context) + columns = expression.referencedColumns() + + # Insure prepare has returned all attributes as referenced columns with feature-less context + self.assertTrue(QgsFeatureRequest.ALL_ATTRIBUTES in columns) + + feature = QgsFeature(layer.fields()) + feature.setAttributes([1, '456']) + context.setFeature(feature) + + self.assertEqual(expression.evaluate(context), '123 456 789') + def testExceptionDuringEvalReturnsTraceback(self): QgsExpression.registerFunction(self.raise_exception) exp = QgsExpression('raise_exception()')