Skip to content

Commit 14787ff

Browse files
committed
[processing] Add easy method to retrieve layers from context
Allows python algorithms to call layer = context.getMapLayer(other_alg_results['OUTPUT'] )
1 parent ceee370 commit 14787ff

File tree

5 files changed

+123
-46
lines changed

5 files changed

+123
-46
lines changed

python/core/processing/qgsprocessingcontext.sip.in

+14
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,18 @@ stored in this context. This includes settings like any layers loaded in the tem
273273
and layersToLoadOnCompletion().
274274
This is only safe to call when both this context and the other ``context`` share the same
275275
thread() affinity, and that thread is the current thread.
276+
%End
277+
278+
QgsMapLayer *getMapLayer( const QString &identifier );
279+
%Docstring
280+
Returns a map layer from the context with a matching ``identifier``.
281+
This method considers layer IDs, names and sources when matching
282+
the ``identifier`` (see :py:func:`QgsProcessingUtils.mapLayerFromString()`
283+
for details).
284+
285+
Ownership is not transferred and remains with the context.
286+
287+
.. seealso:: :py:func:`takeResultLayer`
276288
%End
277289

278290
QgsMapLayer *takeResultLayer( const QString &id ) /TransferBack/;
@@ -281,6 +293,8 @@ Takes the result map layer with matching ``id`` from the context and
281293
transfers ownership of it back to the caller. This method can be used
282294
to remove temporary layers which are not required for further processing
283295
from a context.
296+
297+
.. seealso:: :py:func:`getMapLayer`
284298
%End
285299

286300
private:

src/core/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ SET(QGIS_CORE_SRCS
101101

102102
processing/qgsprocessingalgorithm.cpp
103103
processing/qgsprocessingalgrunnertask.cpp
104+
processing/qgsprocessingcontext.cpp
104105
processing/qgsprocessingfeedback.cpp
105106
processing/qgsprocessingoutputs.cpp
106107
processing/qgsprocessingparameters.cpp
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/***************************************************************************
2+
qgsprocessingcontext.cpp
3+
----------------------
4+
begin : April 2017
5+
copyright : (C) 2017 by Nyall Dawson
6+
email : nyall dot dawson at gmail dot com
7+
***************************************************************************/
8+
9+
/***************************************************************************
10+
* *
11+
* This program is free software; you can redistribute it and/or modify *
12+
* it under the terms of the GNU General Public License as published by *
13+
* the Free Software Foundation; either version 2 of the License, or *
14+
* (at your option) any later version. *
15+
* *
16+
***************************************************************************/
17+
18+
#include "qgsprocessingcontext.h"
19+
#include "qgsprocessingutils.h"
20+
21+
void QgsProcessingContext::setInvalidGeometryCheck( QgsFeatureRequest::InvalidGeometryCheck check )
22+
{
23+
mInvalidGeometryCheck = check;
24+
25+
switch ( mInvalidGeometryCheck )
26+
{
27+
case QgsFeatureRequest::GeometryAbortOnInvalid:
28+
{
29+
auto callback = []( const QgsFeature & feature )
30+
{
31+
throw QgsProcessingException( QObject::tr( "Feature (%1) has invalid geometry. Please fix the geometry or change the Processing setting to the \"Ignore invalid input features\" option." ).arg( feature.id() ) );
32+
};
33+
mInvalidGeometryCallback = callback;
34+
break;
35+
}
36+
37+
case QgsFeatureRequest::GeometrySkipInvalid:
38+
{
39+
auto callback = [ = ]( const QgsFeature & feature )
40+
{
41+
if ( mFeedback )
42+
mFeedback->reportError( QObject::tr( "Feature (%1) has invalid geometry and has been skipped. Please fix the geometry or change the Processing setting to the \"Ignore invalid input features\" option." ).arg( feature.id() ) );
43+
};
44+
mInvalidGeometryCallback = callback;
45+
break;
46+
}
47+
48+
default:
49+
break;
50+
}
51+
}
52+
53+
void QgsProcessingContext::takeResultsFrom( QgsProcessingContext &context )
54+
{
55+
QMap< QString, LayerDetails > loadOnCompletion = context.layersToLoadOnCompletion();
56+
QMap< QString, LayerDetails >::const_iterator llIt = loadOnCompletion.constBegin();
57+
for ( ; llIt != loadOnCompletion.constEnd(); ++llIt )
58+
{
59+
mLayersToLoadOnCompletion.insert( llIt.key(), llIt.value() );
60+
}
61+
context.setLayersToLoadOnCompletion( QMap< QString, LayerDetails >() );
62+
tempLayerStore.transferLayersFromStore( context.temporaryLayerStore() );
63+
}
64+
65+
QgsMapLayer *QgsProcessingContext::getMapLayer( const QString &identifier )
66+
{
67+
return QgsProcessingUtils::mapLayerFromString( identifier, *this, false );
68+
}
69+
70+
QgsMapLayer *QgsProcessingContext::takeResultLayer( const QString &id )
71+
{
72+
return tempLayerStore.takeMapLayer( tempLayerStore.mapLayer( id ) );
73+
}

src/core/processing/qgsprocessingcontext.h

+17-46
Original file line numberDiff line numberDiff line change
@@ -220,37 +220,7 @@ class CORE_EXPORT QgsProcessingContext
220220
* reset the invalidGeometryCallback() to a default implementation.
221221
* \see invalidGeometryCheck()
222222
*/
223-
void setInvalidGeometryCheck( QgsFeatureRequest::InvalidGeometryCheck check )
224-
{
225-
mInvalidGeometryCheck = check;
226-
227-
switch ( mInvalidGeometryCheck )
228-
{
229-
case QgsFeatureRequest::GeometryAbortOnInvalid:
230-
{
231-
auto callback = []( const QgsFeature & feature )
232-
{
233-
throw QgsProcessingException( QObject::tr( "Feature (%1) has invalid geometry. Please fix the geometry or change the Processing setting to the \"Ignore invalid input features\" option." ).arg( feature.id() ) );
234-
};
235-
mInvalidGeometryCallback = callback;
236-
break;
237-
}
238-
239-
case QgsFeatureRequest::GeometrySkipInvalid:
240-
{
241-
auto callback = [ = ]( const QgsFeature & feature )
242-
{
243-
if ( mFeedback )
244-
mFeedback->reportError( QObject::tr( "Feature (%1) has invalid geometry and has been skipped. Please fix the geometry or change the Processing setting to the \"Ignore invalid input features\" option." ).arg( feature.id() ) );
245-
};
246-
mInvalidGeometryCallback = callback;
247-
break;
248-
}
249-
250-
default:
251-
break;
252-
}
253-
}
223+
void setInvalidGeometryCheck( QgsFeatureRequest::InvalidGeometryCheck check );
254224

255225
/**
256226
* Sets a callback function to use when encountering an invalid geometry and
@@ -374,28 +344,29 @@ class CORE_EXPORT QgsProcessingContext
374344
* This is only safe to call when both this context and the other \a context share the same
375345
* thread() affinity, and that thread is the current thread.
376346
*/
377-
void takeResultsFrom( QgsProcessingContext &context )
378-
{
379-
QMap< QString, LayerDetails > loadOnCompletion = context.layersToLoadOnCompletion();
380-
QMap< QString, LayerDetails >::const_iterator llIt = loadOnCompletion.constBegin();
381-
for ( ; llIt != loadOnCompletion.constEnd(); ++llIt )
382-
{
383-
mLayersToLoadOnCompletion.insert( llIt.key(), llIt.value() );
384-
}
385-
context.setLayersToLoadOnCompletion( QMap< QString, LayerDetails >() );
386-
tempLayerStore.transferLayersFromStore( context.temporaryLayerStore() );
387-
}
347+
void takeResultsFrom( QgsProcessingContext &context );
348+
349+
/**
350+
* Returns a map layer from the context with a matching \a identifier.
351+
* This method considers layer IDs, names and sources when matching
352+
* the \a identifier (see QgsProcessingUtils::mapLayerFromString()
353+
* for details).
354+
*
355+
* Ownership is not transferred and remains with the context.
356+
*
357+
* \see takeResultLayer()
358+
*/
359+
QgsMapLayer *getMapLayer( const QString &identifier );
388360

389361
/**
390362
* Takes the result map layer with matching \a id from the context and
391363
* transfers ownership of it back to the caller. This method can be used
392364
* to remove temporary layers which are not required for further processing
393365
* from a context.
366+
*
367+
* \see getMapLayer()
394368
*/
395-
QgsMapLayer *takeResultLayer( const QString &id ) SIP_TRANSFERBACK
396-
{
397-
return tempLayerStore.takeMapLayer( tempLayerStore.mapLayer( id ) );
398-
}
369+
QgsMapLayer *takeResultLayer( const QString &id ) SIP_TRANSFERBACK;
399370

400371
private:
401372

tests/src/analysis/testqgsprocessing.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -881,36 +881,53 @@ void TestQgsProcessing::mapLayerFromString()
881881

882882
// no project set yet
883883
QVERIFY( ! QgsProcessingUtils::mapLayerFromString( QString(), c ) );
884+
QVERIFY( !c.getMapLayer( QString() ) );
884885
QVERIFY( ! QgsProcessingUtils::mapLayerFromString( QStringLiteral( "v1" ), c ) );
886+
QVERIFY( !c.getMapLayer( QStringLiteral( "v1" ) ) );
885887

886888
c.setProject( &p );
887889

888890
// layers from current project
889891
QVERIFY( ! QgsProcessingUtils::mapLayerFromString( QString(), c ) );
892+
QVERIFY( !c.getMapLayer( QString() ) );
890893
QCOMPARE( QgsProcessingUtils::mapLayerFromString( raster1, c ), r1 );
894+
QCOMPARE( c.getMapLayer( raster1 ), r1 );
891895
QCOMPARE( QgsProcessingUtils::mapLayerFromString( raster2, c ), r2 );
896+
QCOMPARE( c.getMapLayer( raster2 ), r2 );
892897
QCOMPARE( QgsProcessingUtils::mapLayerFromString( "R1", c ), r1 );
898+
QCOMPARE( c.getMapLayer( "R1" ), r1 );
893899
QCOMPARE( QgsProcessingUtils::mapLayerFromString( "ar2", c ), r2 );
900+
QCOMPARE( c.getMapLayer( "ar2" ), r2 );
894901
QCOMPARE( QgsProcessingUtils::mapLayerFromString( "V4", c ), v1 );
902+
QCOMPARE( c.getMapLayer( "V4" ), v1 );
895903
QCOMPARE( QgsProcessingUtils::mapLayerFromString( "v1", c ), v2 );
904+
QCOMPARE( c.getMapLayer( "v1" ), v2 );
896905
QCOMPARE( QgsProcessingUtils::mapLayerFromString( r1->id(), c ), r1 );
906+
QCOMPARE( c.getMapLayer( r1->id() ), r1 );
897907
QCOMPARE( QgsProcessingUtils::mapLayerFromString( v1->id(), c ), v1 );
908+
QCOMPARE( c.getMapLayer( v1->id() ), v1 );
898909

899910
// check that layers in context temporary store are used
900911
QgsVectorLayer *v5 = new QgsVectorLayer( "Polygon", "V5", "memory" );
901912
QgsVectorLayer *v6 = new QgsVectorLayer( "Point", "v6", "memory" );
902913
c.temporaryLayerStore()->addMapLayers( QList<QgsMapLayer *>() << v5 << v6 );
903914
QCOMPARE( QgsProcessingUtils::mapLayerFromString( "V5", c ), v5 );
915+
QCOMPARE( c.getMapLayer( "V5" ), v5 );
904916
QCOMPARE( QgsProcessingUtils::mapLayerFromString( "v6", c ), v6 );
917+
QCOMPARE( c.getMapLayer( "v6" ), v6 );
905918
QCOMPARE( QgsProcessingUtils::mapLayerFromString( v5->id(), c ), v5 );
919+
QCOMPARE( c.getMapLayer( v5->id() ), v5 );
906920
QCOMPARE( QgsProcessingUtils::mapLayerFromString( v6->id(), c ), v6 );
921+
QCOMPARE( c.getMapLayer( v6->id() ), v6 );
907922
QVERIFY( ! QgsProcessingUtils::mapLayerFromString( "aaaaa", c ) );
923+
QVERIFY( !c.getMapLayer( "aaaa" ) );
908924

909925
// if specified, check that layers can be loaded
910926
QVERIFY( ! QgsProcessingUtils::mapLayerFromString( "aaaaa", c ) );
911927
QString newRaster = testDataDir + "requires_warped_vrt.tif";
912928
// don't allow loading
913929
QVERIFY( ! QgsProcessingUtils::mapLayerFromString( newRaster, c, false ) );
930+
QVERIFY( !c.getMapLayer( newRaster ) );
914931
// allow loading
915932
QgsMapLayer *loadedLayer = QgsProcessingUtils::mapLayerFromString( newRaster, c, true );
916933
QVERIFY( loadedLayer->isValid() );
@@ -920,6 +937,7 @@ void TestQgsProcessing::mapLayerFromString()
920937

921938
// since it's now in temporary store, should be accessible even if we deny loading new layers
922939
QCOMPARE( QgsProcessingUtils::mapLayerFromString( newRaster, c, false ), loadedLayer );
940+
QCOMPARE( c.getMapLayer( newRaster ), loadedLayer );
923941
}
924942

925943
void TestQgsProcessing::algorithm()

0 commit comments

Comments
 (0)