Skip to content

Commit 39d20a4

Browse files
committedJun 6, 2017
Move algorithm expression context generation to QgsProcessingAlgorithm
Fix error when selecting "from expression" in algorithm parameter dialog
1 parent 607fed8 commit 39d20a4

File tree

10 files changed

+141
-2
lines changed

10 files changed

+141
-2
lines changed
 

‎python/core/processing/qgsprocessingalgorithm.sip

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,15 @@ class QgsProcessingAlgorithm
228228
:rtype: QWidget
229229
%End
230230

231+
QgsExpressionContext createExpressionContext( const QVariantMap &parameters,
232+
QgsProcessingContext &context ) const;
233+
%Docstring
234+
Creates an expression context relating to the algorithm. This can be called by algorithms
235+
to create a new expression context ready for evaluating expressions within the algorithm.
236+
:rtype: QgsExpressionContext
237+
%End
238+
239+
231240
protected:
232241

233242
bool addParameter( QgsProcessingParameterDefinition *parameterDefinition /Transfer/ );

‎python/core/qgsexpressioncontext.sip

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,14 @@ class QgsExpressionContextUtils
866866
:rtype: QgsExpressionContext
867867
%End
868868

869+
static QgsExpressionContextScope *processingAlgorithmScope( const QgsProcessingAlgorithm *algorithm, const QVariantMap &parameters, QgsProcessingContext &context ) /Factory/;
870+
%Docstring
871+
Creates a new scope which contains variables and functions relating to a processing ``algorithm``,
872+
when used with the specified ``parameters`` and ``context``.
873+
For instance, algorithm name and parameter functions.
874+
:rtype: QgsExpressionContextScope
875+
%End
876+
869877
static void registerContextFunctions();
870878
%Docstring
871879
Registers all known core functions provided by QgsExpressionContextScope objects.

‎python/plugins/processing/gui/DestinationSelectionPanel.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,14 @@
3636
from qgis.gui import QgsEncodingFileDialog, QgsExpressionBuilderDialog
3737
from qgis.core import (QgsDataSourceUri,
3838
QgsCredentials,
39+
QgsExpression,
3940
QgsSettings,
4041
QgsProcessingParameterFeatureSink,
4142
QgsProcessingFeatureSinkDefinition)
4243
from processing.core.ProcessingConfig import ProcessingConfig
4344
from processing.core.outputs import OutputVector
4445
from processing.core.outputs import OutputDirectory
46+
from processing.tools.dataobjects import createContext
4547
from processing.gui.PostgisTableSelector import PostgisTableSelector
4648
from processing.gui.ParameterGuiUtils import getFileFilter
4749

@@ -122,11 +124,13 @@ def selectOutput(self):
122124
popupMenu.exec_(QCursor.pos())
123125

124126
def showExpressionsBuilder(self):
127+
context = self.alg.createExpressionContext({}, createContext())
125128
dlg = QgsExpressionBuilderDialog(None, self.leText.text(), self, 'generic',
126-
self.parameter.expressionContext(self.alg))
129+
context)
127130
dlg.setWindowTitle(self.tr('Expression based output'))
128131
if dlg.exec_() == QDialog.Accepted:
129-
self.leText.setText(dlg.expressionText())
132+
expression = QgsExpression(dlg.expressionText())
133+
self.leText.setText(expression.evaluate(context))
130134

131135
def saveToTemporary(self):
132136
self.leText.setText('')
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"name": "parameter",
3+
"type": "function",
4+
"description": "Returns the value of a processing algorithm input parameter.",
5+
"arguments": [
6+
{"arg":"name", "description":"name of the corresponding input parameter"}
7+
],
8+
"examples": [
9+
{ "expression":"parameter('BUFFER_SIZE')", "returns":"5.6"}
10+
]
11+
}

‎src/core/expression/qgsexpression.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,9 @@ void QgsExpression::initVariableHelp()
685685
//cluster variables
686686
sVariableHelpTexts.insert( QStringLiteral( "cluster_color" ), QCoreApplication::translate( "cluster_color", "Color of symbols within a cluster, or NULL if symbols have mixed colors." ) );
687687
sVariableHelpTexts.insert( QStringLiteral( "cluster_size" ), QCoreApplication::translate( "cluster_size", "Number of symbols contained within a cluster." ) );
688+
689+
//processing variables
690+
sVariableHelpTexts.insert( QStringLiteral( "algorithm_id" ), QCoreApplication::translate( "algorithm_id", "Unique ID for algorithm." ) );
688691
}
689692

690693
QString QgsExpression::variableHelpText( const QString &variableName, bool showValue, const QVariant &value )

‎src/core/processing/qgsprocessingalgorithm.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "qgsprocessingparameters.h"
2222
#include "qgsprocessingoutputs.h"
2323
#include "qgsrectangle.h"
24+
#include "qgsprocessingcontext.h"
2425

2526
QgsProcessingAlgorithm::~QgsProcessingAlgorithm()
2627
{
@@ -100,6 +101,22 @@ QWidget *QgsProcessingAlgorithm::createCustomParametersWidget( QWidget * ) const
100101
return nullptr;
101102
}
102103

104+
QgsExpressionContext QgsProcessingAlgorithm::createExpressionContext( const QVariantMap &parameters,
105+
QgsProcessingContext &context ) const
106+
{
107+
// start with context's expression context
108+
QgsExpressionContext c = context.expressionContext();
109+
if ( c.scopeCount() == 0 )
110+
{
111+
//empty scope, populate with initial scopes
112+
c << QgsExpressionContextUtils::globalScope()
113+
<< QgsExpressionContextUtils::projectScope( context.project() );
114+
}
115+
116+
c << QgsExpressionContextUtils::processingAlgorithmScope( this, parameters, context );
117+
return c;
118+
}
119+
103120
bool QgsProcessingAlgorithm::addParameter( QgsProcessingParameterDefinition *definition )
104121
{
105122
if ( !definition )

‎src/core/processing/qgsprocessingalgorithm.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,14 @@ class CORE_EXPORT QgsProcessingAlgorithm
229229
*/
230230
virtual QWidget *createCustomParametersWidget( QWidget *parent = nullptr ) const SIP_FACTORY;
231231

232+
/**
233+
* Creates an expression context relating to the algorithm. This can be called by algorithms
234+
* to create a new expression context ready for evaluating expressions within the algorithm.
235+
*/
236+
QgsExpressionContext createExpressionContext( const QVariantMap &parameters,
237+
QgsProcessingContext &context ) const;
238+
239+
232240
protected:
233241

234242
/**

‎src/core/qgsexpressioncontext.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
#include "qgsapplication.h"
3030
#include "qgsmapsettings.h"
3131
#include "qgsmaplayerlistutils.h"
32+
#include "qgsprocessingcontext.h"
33+
#include "qgsprocessingalgorithm.h"
3234

3335
#include <QSettings>
3436
#include <QDir>
@@ -707,6 +709,30 @@ class GetLayerVisibility : public QgsScopedExpressionFunction
707709

708710
};
709711

712+
class GetProcessingParameterValue : public QgsScopedExpressionFunction
713+
{
714+
public:
715+
GetProcessingParameterValue( const QVariantMap &params )
716+
: QgsScopedExpressionFunction( QStringLiteral( "parameter" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "name" ) ), QStringLiteral( "Processing" ) )
717+
, mParams( params )
718+
{}
719+
720+
QVariant func( const QVariantList &values, const QgsExpressionContext *, QgsExpression * ) override
721+
{
722+
return mParams.value( values.at( 0 ).toString() );
723+
}
724+
725+
QgsScopedExpressionFunction *clone() const override
726+
{
727+
return new GetProcessingParameterValue( mParams );
728+
}
729+
730+
private:
731+
732+
const QVariantMap mParams;
733+
734+
};
735+
710736
///@endcond
711737

712738
QgsExpressionContextScope *QgsExpressionContextUtils::projectScope( const QgsProject *project )
@@ -1077,11 +1103,29 @@ QgsExpressionContext QgsExpressionContextUtils::createFeatureBasedContext( const
10771103
return QgsExpressionContext() << scope;
10781104
}
10791105

1106+
QgsExpressionContextScope *QgsExpressionContextUtils::processingAlgorithmScope( const QgsProcessingAlgorithm *algorithm, const QVariantMap &parameters, QgsProcessingContext &context )
1107+
{
1108+
// set aside for future use
1109+
Q_UNUSED( context );
1110+
1111+
std::unique_ptr< QgsExpressionContextScope > scope( new QgsExpressionContextScope( QObject::tr( "Algorithm" ) ) );
1112+
if ( !algorithm )
1113+
return scope.release();
1114+
1115+
//add standard algorithm variables
1116+
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "algorithm_id" ), algorithm->id(), true ) );
1117+
1118+
scope->addFunction( QStringLiteral( "parameter" ), new GetProcessingParameterValue( parameters ) );
1119+
1120+
return scope.release();
1121+
}
1122+
10801123
void QgsExpressionContextUtils::registerContextFunctions()
10811124
{
10821125
QgsExpression::registerFunction( new GetNamedProjectColor( nullptr ) );
10831126
QgsExpression::registerFunction( new GetComposerItemVariables( nullptr ) );
10841127
QgsExpression::registerFunction( new GetLayerVisibility( QList<QgsMapLayer *>() ) );
1128+
QgsExpression::registerFunction( new GetProcessingParameterValue( QVariantMap() ) );
10851129
}
10861130

10871131
bool QgsScopedExpressionFunction::usesGeometry( const QgsExpressionNodeFunction *node ) const

‎src/core/qgsexpressioncontext.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ class QgsAtlasComposition;
3636
class QgsMapSettings;
3737
class QgsProject;
3838
class QgsSymbol;
39+
class QgsProcessingAlgorithm;
40+
class QgsProcessingContext;
3941

4042
/** \ingroup core
4143
* \class QgsScopedExpressionFunction
@@ -788,6 +790,13 @@ class CORE_EXPORT QgsExpressionContextUtils
788790
*/
789791
static QgsExpressionContext createFeatureBasedContext( const QgsFeature &feature, const QgsFields &fields );
790792

793+
/**
794+
* Creates a new scope which contains variables and functions relating to a processing \a algorithm,
795+
* when used with the specified \a parameters and \a context.
796+
* For instance, algorithm name and parameter functions.
797+
*/
798+
static QgsExpressionContextScope *processingAlgorithmScope( const QgsProcessingAlgorithm *algorithm, const QVariantMap &parameters, QgsProcessingContext &context ) SIP_FACTORY;
799+
791800
/** Registers all known core functions provided by QgsExpressionContextScope objects.
792801
*/
793802
static void registerContextFunctions();

‎tests/src/core/testqgsprocessing.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "qgspoint.h"
3131
#include "qgsgeometry.h"
3232
#include "qgsvectorfilewriter.h"
33+
#include "qgsexpressioncontext.h"
3334

3435
class DummyAlgorithm : public QgsProcessingAlgorithm
3536
{
@@ -219,6 +220,7 @@ class TestQgsProcessing: public QObject
219220
void combineLayerExtent();
220221
void processingFeatureSource();
221222
void processingFeatureSink();
223+
void algorithmScope();
222224

223225
private:
224226

@@ -2425,5 +2427,29 @@ void TestQgsProcessing::processingFeatureSink()
24252427
QCOMPARE( layer2->crs().authid(), QStringLiteral( "EPSG:3113" ) );
24262428
}
24272429

2430+
void TestQgsProcessing::algorithmScope()
2431+
{
2432+
QgsProcessingContext pc;
2433+
2434+
// no alg
2435+
std::unique_ptr< QgsExpressionContextScope > scope( QgsExpressionContextUtils::processingAlgorithmScope( nullptr, QVariantMap(), pc ) );
2436+
QVERIFY( scope.get() );
2437+
2438+
// with alg
2439+
std::unique_ptr< QgsProcessingAlgorithm > alg( new DummyAlgorithm( "alg1" ) );
2440+
QVariantMap params;
2441+
params.insert( QStringLiteral( "a_param" ), 5 );
2442+
scope.reset( QgsExpressionContextUtils::processingAlgorithmScope( alg.get(), params, pc ) );
2443+
QVERIFY( scope.get() );
2444+
QCOMPARE( scope->variable( QStringLiteral( "algorithm_id" ) ).toString(), alg->id() );
2445+
2446+
QgsExpressionContext context;
2447+
context.appendScope( scope.release() );
2448+
QgsExpression exp( "parameter('bad')" );
2449+
QVERIFY( !exp.evaluate( &context ).isValid() );
2450+
QgsExpression exp2( "parameter('a_param')" );
2451+
QCOMPARE( exp2.evaluate( &context ).toInt(), 5 );
2452+
}
2453+
24282454
QGSTEST_MAIN( TestQgsProcessing )
24292455
#include "testqgsprocessing.moc"

0 commit comments

Comments
 (0)
Please sign in to comment.