Skip to content

Commit e533a40

Browse files
committedFeb 12, 2019
[processing] Expose some model related variables to expressions
run inside models Allows expressions to access important variables like the current model path
1 parent 2180b63 commit e533a40

File tree

9 files changed

+95
-1
lines changed

9 files changed

+95
-1
lines changed
 

‎python/core/auto_generated/qgsexpressioncontext.sip.in

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,17 @@ standard scopes such as the global and project scopes.
10791079
Creates a new scope which contains variables and functions relating to a processing ``algorithm``,
10801080
when used with the specified ``parameters`` and ``context``.
10811081
For instance, algorithm name and parameter functions.
1082+
1083+
.. seealso:: :py:func:`processingModelAlgorithmScope`
1084+
%End
1085+
1086+
static QgsExpressionContextScope *processingModelAlgorithmScope( const QgsProcessingModelAlgorithm *model, const QVariantMap &parameters, QgsProcessingContext &context ) /Factory/;
1087+
%Docstring
1088+
Creates a new scope which contains variables and functions relating to a processing ``model`` algorithm,
1089+
when used with the specified ``parameters`` and ``context``.
1090+
For instance, model name and path variables.
1091+
1092+
.. versionadded:: 3.6
10821093
%End
10831094

10841095
static QgsExpressionContextScope *notificationScope( const QString &message = QString() ) /Factory/;

‎src/core/expression/qgsexpression.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,10 @@ void QgsExpression::initVariableHelp()
799799

800800
//processing variables
801801
sVariableHelpTexts.insert( QStringLiteral( "algorithm_id" ), QCoreApplication::translate( "algorithm_id", "Unique ID for algorithm." ) );
802+
sVariableHelpTexts.insert( QStringLiteral( "model_path" ), QCoreApplication::translate( "variable_help", "Full path (including file name) of current model (or project path if model is embedded in a project)." ) );
803+
sVariableHelpTexts.insert( QStringLiteral( "model_folder" ), QCoreApplication::translate( "variable_help", "Folder containing current model (or project folder if model is embedded in a project)." ) );
804+
sVariableHelpTexts.insert( QStringLiteral( "model_name" ), QCoreApplication::translate( "variable_help", "Name of current model." ) );
805+
sVariableHelpTexts.insert( QStringLiteral( "model_group" ), QCoreApplication::translate( "variable_help", "Group for current model." ) );
802806
sVariableHelpTexts.insert( QStringLiteral( "fullextent_minx" ), QCoreApplication::translate( "fullextent_minx", "Minimum x-value from full canvas extent (including all layers)." ) );
803807
sVariableHelpTexts.insert( QStringLiteral( "fullextent_miny" ), QCoreApplication::translate( "fullextent_miny", "Minimum y-value from full canvas extent (including all layers)." ) );
804808
sVariableHelpTexts.insert( QStringLiteral( "fullextent_maxx" ), QCoreApplication::translate( "fullextent_maxx", "Maximum x-value from full canvas extent (including all layers)." ) );

‎src/core/processing/models/qgsprocessingmodelalgorithm.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1381,6 +1381,13 @@ QString QgsProcessingModelAlgorithm::asPythonCommand( const QVariantMap &paramet
13811381
return QgsProcessingAlgorithm::asPythonCommand( parameters, context );
13821382
}
13831383

1384+
QgsExpressionContext QgsProcessingModelAlgorithm::createExpressionContext( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeatureSource *source ) const
1385+
{
1386+
QgsExpressionContext res = QgsProcessingAlgorithm::createExpressionContext( parameters, context, source );
1387+
res << QgsExpressionContextUtils::processingModelAlgorithmScope( this, parameters, context );
1388+
return res;
1389+
}
1390+
13841391
QgsProcessingAlgorithm *QgsProcessingModelAlgorithm::createInstance() const
13851392
{
13861393
QgsProcessingModelAlgorithm *alg = new QgsProcessingModelAlgorithm();

‎src/core/processing/models/qgsprocessingmodelalgorithm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ class CORE_EXPORT QgsProcessingModelAlgorithm : public QgsProcessingAlgorithm
5757

5858
bool canExecute( QString *errorMessage SIP_OUT = nullptr ) const override;
5959
QString asPythonCommand( const QVariantMap &parameters, QgsProcessingContext &context ) const override;
60+
QgsExpressionContext createExpressionContext( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeatureSource *source = nullptr ) const override;
6061

6162
/**
6263
* Sets the model \a name.

‎src/core/qgsexpressioncontext.cpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
#include "qgsexpressionutils.h"
3636
#include "qgslayoutrendercontext.h"
3737
#include "qgsxmlutils.h"
38-
38+
#include "qgsprocessingmodelalgorithm.h"
3939
#include <QSettings>
4040
#include <QDir>
4141

@@ -1329,6 +1329,29 @@ QgsExpressionContextScope *QgsExpressionContextUtils::processingAlgorithmScope(
13291329
return scope.release();
13301330
}
13311331

1332+
QgsExpressionContextScope *QgsExpressionContextUtils::processingModelAlgorithmScope( const QgsProcessingModelAlgorithm *model, const QVariantMap &, QgsProcessingContext &context )
1333+
{
1334+
std::unique_ptr< QgsExpressionContextScope > modelScope( new QgsExpressionContextScope( QObject::tr( "Model" ) ) );
1335+
QString modelPath;
1336+
if ( !model->sourceFilePath().isEmpty() )
1337+
{
1338+
modelPath = model->sourceFilePath();
1339+
}
1340+
else if ( context.project() )
1341+
{
1342+
// fallback to project path -- the model may be embedded in a project, OR an unsaved model. In either case the
1343+
// project path is a logical value to fall back to
1344+
modelPath = context.project()->projectStorage() ? context.project()->fileName() : context.project()->absoluteFilePath();
1345+
}
1346+
1347+
const QString modelFolder = QFileInfo( modelPath ).path();
1348+
modelScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "model_path" ), QDir::toNativeSeparators( modelPath ), true ) );
1349+
modelScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "model_folder" ), QDir::toNativeSeparators( modelFolder ), true, true ) );
1350+
modelScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "model_name" ), model->displayName(), true ) );
1351+
modelScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "model_group" ), model->group(), true ) );
1352+
return modelScope.release();
1353+
}
1354+
13321355
QgsExpressionContextScope *QgsExpressionContextUtils::notificationScope( const QString &message )
13331356
{
13341357
std::unique_ptr< QgsExpressionContextScope > scope( new QgsExpressionContextScope() );

‎src/core/qgsexpressioncontext.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class QgsProcessingAlgorithm;
4141
class QgsProcessingContext;
4242
class QgsLayoutAtlas;
4343
class QgsLayoutItem;
44+
class QgsProcessingModelAlgorithm;
4445

4546
/**
4647
* \ingroup core
@@ -987,9 +988,18 @@ class CORE_EXPORT QgsExpressionContextUtils
987988
* Creates a new scope which contains variables and functions relating to a processing \a algorithm,
988989
* when used with the specified \a parameters and \a context.
989990
* For instance, algorithm name and parameter functions.
991+
* \see processingModelAlgorithmScope()
990992
*/
991993
static QgsExpressionContextScope *processingAlgorithmScope( const QgsProcessingAlgorithm *algorithm, const QVariantMap &parameters, QgsProcessingContext &context ) SIP_FACTORY;
992994

995+
/**
996+
* Creates a new scope which contains variables and functions relating to a processing \a model algorithm,
997+
* when used with the specified \a parameters and \a context.
998+
* For instance, model name and path variables.
999+
* \since QGIS 3.6
1000+
*/
1001+
static QgsExpressionContextScope *processingModelAlgorithmScope( const QgsProcessingModelAlgorithm *model, const QVariantMap &parameters, QgsProcessingContext &context ) SIP_FACTORY;
1002+
9931003
/**
9941004
* Creates a new scope which contains variables and functions relating to provider notifications
9951005
* \param message the notification message

‎src/gui/processing/qgsprocessingmodelerparameterwidget.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,8 @@ QgsExpressionContext QgsProcessingModelerParameterWidget::createExpressionContex
189189
alg = mModel->childAlgorithm( mChildId ).algorithm();
190190
QgsExpressionContextScope *algorithmScope = QgsExpressionContextUtils::processingAlgorithmScope( alg, QVariantMap(), mContext );
191191
c << algorithmScope;
192+
QgsExpressionContextScope *modelScope = QgsExpressionContextUtils::processingModelAlgorithmScope( mModel, QVariantMap(), mContext );
193+
c << modelScope;
192194
QgsExpressionContextScope *childScope = mModel->createExpressionContextScopeForChildAlgorithm( mChildId, mContext, QVariantMap(), QVariantMap() );
193195
c << childScope;
194196

‎src/gui/processing/qgsprocessingwidgetwrapper.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,8 @@ QgsExpressionContext QgsAbstractProcessingParameterWidgetWrapper::createExpressi
239239

240240
if ( mWidgetContext.model() )
241241
{
242+
c << QgsExpressionContextUtils::processingModelAlgorithmScope( mWidgetContext.model(), QVariantMap(), *context );
243+
242244
const QgsProcessingAlgorithm *alg = nullptr;
243245
if ( mWidgetContext.model()->childAlgorithms().contains( mWidgetContext.modelChildAlgorithmId() ) )
244246
alg = mWidgetContext.model()->childAlgorithm( mWidgetContext.modelChildAlgorithmId() ).algorithm();

‎tests/src/analysis/testqgsprocessing.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,7 @@ class TestQgsProcessing: public QObject
562562
void processingFeatureSource();
563563
void processingFeatureSink();
564564
void algorithmScope();
565+
void modelScope();
565566
void validateInputCrs();
566567
void generateIteratingDestination();
567568
void asPythonCommand();
@@ -5999,6 +6000,39 @@ void TestQgsProcessing::algorithmScope()
59996000
QCOMPARE( exp2.evaluate( &context ).toInt(), 5 );
60006001
}
60016002

6003+
void TestQgsProcessing::modelScope()
6004+
{
6005+
QgsProcessingContext pc;
6006+
6007+
QgsProcessingModelAlgorithm alg( "test", "testGroup" );
6008+
QVariantMap params;
6009+
params.insert( QStringLiteral( "a_param" ), 5 );
6010+
std::unique_ptr< QgsExpressionContextScope > scope( QgsExpressionContextUtils::processingModelAlgorithmScope( &alg, params, pc ) );
6011+
QVERIFY( scope.get() );
6012+
QCOMPARE( scope->variable( QStringLiteral( "model_name" ) ).toString(), QStringLiteral( "test" ) );
6013+
QCOMPARE( scope->variable( QStringLiteral( "model_group" ) ).toString(), QStringLiteral( "testGroup" ) );
6014+
QVERIFY( scope->hasVariable( QStringLiteral( "model_path" ) ) );
6015+
QVERIFY( scope->hasVariable( QStringLiteral( "model_folder" ) ) );
6016+
QVERIFY( scope->variable( QStringLiteral( "model_path" ) ).toString().isEmpty() );
6017+
QVERIFY( scope->variable( QStringLiteral( "model_folder" ) ).toString().isEmpty() );
6018+
6019+
QgsProject p;
6020+
pc.setProject( &p );
6021+
p.setFileName( TEST_DATA_DIR + QStringLiteral( "/test_file.qgs" ) );
6022+
scope.reset( QgsExpressionContextUtils::processingModelAlgorithmScope( &alg, params, pc ) );
6023+
QCOMPARE( scope->variable( QStringLiteral( "model_path" ) ).toString(), TEST_DATA_DIR + QStringLiteral( "/test_file.qgs" ) );
6024+
QCOMPARE( scope->variable( QStringLiteral( "model_folder" ) ).toString(), TEST_DATA_DIR );
6025+
6026+
alg.setSourceFilePath( TEST_DATA_DIR + QStringLiteral( "/processing/my_model.model3" ) );
6027+
scope.reset( QgsExpressionContextUtils::processingModelAlgorithmScope( &alg, params, pc ) );
6028+
QCOMPARE( scope->variable( QStringLiteral( "model_path" ) ).toString(), TEST_DATA_DIR + QStringLiteral( "/processing/my_model.model3" ) );
6029+
QCOMPARE( scope->variable( QStringLiteral( "model_folder" ) ).toString(), TEST_DATA_DIR + QStringLiteral( "/processing" ) );
6030+
6031+
QgsExpressionContext ctx = alg.createExpressionContext( QVariantMap(), pc );
6032+
QVERIFY( scope->hasVariable( QStringLiteral( "model_path" ) ) );
6033+
QVERIFY( scope->hasVariable( QStringLiteral( "model_folder" ) ) );
6034+
}
6035+
60026036
void TestQgsProcessing::validateInputCrs()
60036037
{
60046038
DummyAlgorithm alg( "test" );

0 commit comments

Comments
 (0)
Please sign in to comment.