Skip to content

Commit

Permalink
[processing] Cleanup some layer/writer related handling
Browse files Browse the repository at this point in the history
Ensure that layers created by QgsProcessingUtils::createFeatureSink
can always be retrieved using QgsProcessingUtils::mapLayerFromString
  • Loading branch information
nyalldawson committed May 9, 2017
1 parent cb23ebe commit 6aa10c6
Show file tree
Hide file tree
Showing 9 changed files with 33 additions and 40 deletions.
5 changes: 2 additions & 3 deletions python/core/processing/qgsprocessingutils.sip
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,7 @@ class QgsProcessingUtils
const QgsFields &fields,
QgsWkbTypes::Type geometryType,
const QgsCoordinateReferenceSystem &crs,
QgsProcessingContext &context,
QgsVectorLayer **outputLayer /Out/ ) /PyName=createFeatureSink/;
QgsProcessingContext &context ) /PyName=createFeatureSink/;
%Docstring
Creates a feature sink ready for adding features. The ``destination`` specifies a destination
URI for the resultant layer. It may be updated in place to reflect the actual destination
Expand All @@ -142,7 +141,7 @@ class QgsProcessingUtils
If the ``encoding`` is not specified, the default encoding from the ``context`` will be used.

If a layer is created for the feature sink, the layer will automatically be added to the ``context``'s
temporary layer store, and the ``outputLayer`` argument updated to point at this newly created layer.
temporary layer store.

.. note::

Expand Down
2 changes: 1 addition & 1 deletion python/plugins/processing/algs/qgis/VectorSplit.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def processAlgorithm(self, context, feedback):
for current, i in enumerate(uniqueValues):
fName = u'{0}_{1}.shp'.format(baseName, str(i).strip())

writer, dest, _layer = QgsProcessingUtils.createFeatureSink(fName, None, fields, geomType, crs, context)
writer, dest = QgsProcessingUtils.createFeatureSink(fName, None, fields, geomType, crs, context)
for f in QgsProcessingUtils.getFeatures(layer, context):
if f[fieldName] == i:
writer.addFeature(f)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
layer = QgsProcessingUtils.mapLayerFromString(input, context)
fields = layer.fields()
fields.append(QgsField('UNIQ_COUNT', QVariant.Int))
writer, writer_dest, writer_layer = QgsProcessingUtils.createFeatureSink(N_unique_values, None, fields, layer.wkbType(), layer.crs(),
context)
writer, writer_dest = QgsProcessingUtils.createFeatureSink(N_unique_values, None, fields, layer.wkbType(), layer.crs(),
context)

class_field_index = layer.fields().lookupField(class_field)
value_field_index = layer.fields().lookupField(value_field)
Expand Down
3 changes: 1 addition & 2 deletions python/plugins/processing/core/outputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,7 @@ def getVectorWriter(self, fields, geomType, crs, context):
settings = QgsSettings()
self.encoding = settings.value('/Processing/encoding', 'System', str)

w, w_dest, w_layer = QgsProcessingUtils.createFeatureSink(self.value, self.encoding, fields, geomType, crs, context)
self.layer = w_layer
w, w_dest = QgsProcessingUtils.createFeatureSink(self.value, self.encoding, fields, geomType, crs, context)
self.value = w_dest
return w

Expand Down
9 changes: 4 additions & 5 deletions python/plugins/processing/gui/Postprocessing.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,10 @@ def handleAlgorithmResults(alg, context, feedback=None, showResults=True):
continue
if isinstance(out, (OutputRaster, OutputVector, OutputTable)):
try:
if hasattr(out, "layer") and out.layer is not None:
out.layer.setName(out.description)
QgsProject.instance().addMapLayer(context.temporaryLayerStore().takeMapLayer(out.layer))
# temporary hack to work around mutable outputs
out.layer = None
layer = QgsProcessingUtils.mapLayerFromString(out.value, context)
if layer:
layer.setName(out.description)
QgsProject.instance().addMapLayer(context.temporaryLayerStore().takeMapLayer(layer))
else:
if ProcessingConfig.getSetting(
ProcessingConfig.USE_FILENAME_AS_LAYER_NAME):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
layer = QgsProcessingUtils.mapLayerFromString(INPUT_LAYER, context)
fields = layer.fields()

writer, writer_dest, writer_layer = QgsProcessingUtils.createFeatureSink(OUTPUT_LAYER, 'utf-8', fields, QgsWkbTypes.Point, layer.crs(),
writer, writer_dest = QgsProcessingUtils.createFeatureSink(OUTPUT_LAYER, 'utf-8', fields, QgsWkbTypes.Point, layer.crs(),
context)

features = QgsProcessingUtils.getFeatures(layer, context)
Expand Down
20 changes: 8 additions & 12 deletions src/core/processing/qgsprocessingutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -328,12 +328,10 @@ void parseDestinationString( QString &destination, QString &providerKey, QString
}
}

QgsFeatureSink *QgsProcessingUtils::createFeatureSink( QString &destination, const QString &encoding, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs, QgsProcessingContext &context, QgsVectorLayer *&outputLayer )
QgsFeatureSink *QgsProcessingUtils::createFeatureSink( QString &destination, const QString &encoding, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs, QgsProcessingContext &context )
{
outputLayer = nullptr;
QgsVectorLayer *layer = nullptr;

QString destEncoding = encoding;
QgsVectorLayer *layer = nullptr;
if ( destEncoding.isEmpty() )
{
// no destination encoding specified, use default
Expand All @@ -344,8 +342,6 @@ QgsFeatureSink *QgsProcessingUtils::createFeatureSink( QString &destination, con
{
// memory provider cannot be used with QgsVectorLayerImport - so create layer manually
layer = QgsMemoryProviderUtils::createMemoryLayer( destination, fields, geometryType, crs );
if ( layer && layer->isValid() )
destination = layer->id();
}
else
{
Expand Down Expand Up @@ -376,6 +372,7 @@ QgsFeatureSink *QgsProcessingUtils::createFeatureSink( QString &destination, con
return nullptr;
}

// use destination string as layer name (eg "postgis:..." )
layer = new QgsVectorLayer( uri, destination, providerKey );
}
}
Expand All @@ -389,19 +386,18 @@ QgsFeatureSink *QgsProcessingUtils::createFeatureSink( QString &destination, con
return nullptr;
}

// update destination to layer ID
destination = layer->id();

context.temporaryLayerStore()->addMapLayer( layer );

outputLayer = layer;
// this is a factory, so we need to return a proxy
return new QgsProxyFeatureSink( layer->dataProvider() );
}

void QgsProcessingUtils::createFeatureSinkPython( QgsFeatureSink **sink, QString &destination, const QString &encoding, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs, QgsProcessingContext &context, QgsVectorLayer **outputLayer )
void QgsProcessingUtils::createFeatureSinkPython( QgsFeatureSink **sink, QString &destination, const QString &encoding, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs, QgsProcessingContext &context )
{
QgsVectorLayer *layer = nullptr;
*sink = createFeatureSink( destination, encoding, fields, geometryType, crs, context, layer );
if ( outputLayer )
*outputLayer = layer;
*sink = createFeatureSink( destination, encoding, fields, geometryType, crs, context );
}


10 changes: 4 additions & 6 deletions src/core/processing/qgsprocessingutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ class CORE_EXPORT QgsProcessingUtils
* If the \a encoding is not specified, the default encoding from the \a context will be used.
*
* If a layer is created for the feature sink, the layer will automatically be added to the \a context's
* temporary layer store, and the \a outputLayer argument updated to point at this newly created layer.
* temporary layer store.
*
* The caller takes responsibility for deleting the returned sink.
*/
Expand All @@ -152,8 +152,7 @@ class CORE_EXPORT QgsProcessingUtils
const QgsFields &fields,
QgsWkbTypes::Type geometryType,
const QgsCoordinateReferenceSystem &crs,
QgsProcessingContext &context,
QgsVectorLayer *&outputLayer ) SIP_FACTORY;
QgsProcessingContext &context ) SIP_FACTORY;
#endif

/**
Expand All @@ -166,7 +165,7 @@ class CORE_EXPORT QgsProcessingUtils
* If the \a encoding is not specified, the default encoding from the \a context will be used.
*
* If a layer is created for the feature sink, the layer will automatically be added to the \a context's
* temporary layer store, and the \a outputLayer argument updated to point at this newly created layer.
* temporary layer store.
*
* \note this version of the createFeatureSink() function has an API designed around use from the
* SIP bindings. c++ code should call the other createFeatureSink() version.
Expand All @@ -179,8 +178,7 @@ class CORE_EXPORT QgsProcessingUtils
const QgsFields &fields,
QgsWkbTypes::Type geometryType,
const QgsCoordinateReferenceSystem &crs,
QgsProcessingContext &context,
QgsVectorLayer **outputLayer SIP_OUT ) SIP_PYNAME( createFeatureSink );
QgsProcessingContext &context ) SIP_PYNAME( createFeatureSink );


private:
Expand Down
18 changes: 10 additions & 8 deletions tests/src/core/testqgsprocessing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -748,8 +748,9 @@ void TestQgsProcessing::createFeatureSink()
QgsVectorLayer *layer = nullptr;

// should create a memory layer
QgsFeatureSink *sink = QgsProcessingUtils::createFeatureSink( destination, QString(), QgsFields(), QgsWkbTypes::Point, QgsCoordinateReferenceSystem(), context, layer );
QgsFeatureSink *sink = QgsProcessingUtils::createFeatureSink( destination, QString(), QgsFields(), QgsWkbTypes::Point, QgsCoordinateReferenceSystem(), context );
QVERIFY( sink );
layer = qobject_cast< QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( destination, context, false ) );
QVERIFY( layer );
QCOMPARE( static_cast< QgsProxyFeatureSink *>( sink )->destinationSink(), layer->dataProvider() );
QCOMPARE( layer->dataProvider()->name(), QStringLiteral( "memory" ) );
Expand All @@ -765,8 +766,9 @@ void TestQgsProcessing::createFeatureSink()

// specific memory layer output
destination = QStringLiteral( "memory:mylayer" );
sink = QgsProcessingUtils::createFeatureSink( destination, QString(), QgsFields(), QgsWkbTypes::Point, QgsCoordinateReferenceSystem(), context, layer );
sink = QgsProcessingUtils::createFeatureSink( destination, QString(), QgsFields(), QgsWkbTypes::Point, QgsCoordinateReferenceSystem(), context );
QVERIFY( sink );
layer = qobject_cast< QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( destination, context, false ) );
QVERIFY( layer );
QCOMPARE( static_cast< QgsProxyFeatureSink *>( sink )->destinationSink(), layer->dataProvider() );
QCOMPARE( layer->dataProvider()->name(), QStringLiteral( "memory" ) );
Expand All @@ -784,8 +786,9 @@ void TestQgsProcessing::createFeatureSink()
destination = QStringLiteral( "memory:mylayer" );
QgsFields fields;
fields.append( QgsField( QStringLiteral( "my_field" ), QVariant::String, QString(), 100 ) );
sink = QgsProcessingUtils::createFeatureSink( destination, QString(), fields, QgsWkbTypes::PointZM, QgsCoordinateReferenceSystem::fromEpsgId( 3111 ), context, layer );
sink = QgsProcessingUtils::createFeatureSink( destination, QString(), fields, QgsWkbTypes::PointZM, QgsCoordinateReferenceSystem::fromEpsgId( 3111 ), context );
QVERIFY( sink );
layer = qobject_cast< QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( destination, context, false ) );
QVERIFY( layer );
QCOMPARE( static_cast< QgsProxyFeatureSink *>( sink )->destinationSink(), layer->dataProvider() );
QCOMPARE( layer->dataProvider()->name(), QStringLiteral( "memory" ) );
Expand All @@ -807,16 +810,15 @@ void TestQgsProcessing::createFeatureSink()
// non memory layer output
destination = QDir::tempPath() + "/create_feature_sink.tab";
QString prevDest = destination;
sink = QgsProcessingUtils::createFeatureSink( destination, QString(), fields, QgsWkbTypes::Polygon, QgsCoordinateReferenceSystem::fromEpsgId( 3111 ), context, layer );
sink = QgsProcessingUtils::createFeatureSink( destination, QString(), fields, QgsWkbTypes::Polygon, QgsCoordinateReferenceSystem::fromEpsgId( 3111 ), context );
QVERIFY( sink );
f = QgsFeature( fields );
f.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "Polygon((0 0, 0 1, 1 1, 1 0, 0 0 ))" ) ) );
f.setAttributes( QgsAttributes() << "val" );
QVERIFY( sink->addFeature( f ) );
QVERIFY( !layer );
QCOMPARE( destination, prevDest );
delete sink;
layer = new QgsVectorLayer( destination, "test_layer", "ogr" );
layer = qobject_cast< QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( destination, context, true ) );
QVERIFY( layer->isValid() );
QCOMPARE( layer->crs().authid(), QStringLiteral( "EPSG:3111" ) );
QCOMPARE( layer->fields().size(), 1 );
Expand All @@ -829,14 +831,14 @@ void TestQgsProcessing::createFeatureSink()
// no extension, should default to shp
destination = QDir::tempPath() + "/create_feature_sink2";
prevDest = QDir::tempPath() + "/create_feature_sink2.shp";
sink = QgsProcessingUtils::createFeatureSink( destination, QString(), fields, QgsWkbTypes::Point25D, QgsCoordinateReferenceSystem::fromEpsgId( 3111 ), context, layer );
sink = QgsProcessingUtils::createFeatureSink( destination, QString(), fields, QgsWkbTypes::Point25D, QgsCoordinateReferenceSystem::fromEpsgId( 3111 ), context );
QVERIFY( sink );
f.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "PointZ(1 2 3)" ) ) );
QVERIFY( sink->addFeature( f ) );
QVERIFY( !layer );
QCOMPARE( destination, prevDest );
delete sink;
layer = new QgsVectorLayer( destination, "test_layer", "ogr" );
layer = qobject_cast< QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( destination, context, true ) );
QCOMPARE( layer->wkbType(), QgsWkbTypes::Point25D );
QCOMPARE( layer->crs().authid(), QStringLiteral( "EPSG:3111" ) );
QCOMPARE( layer->fields().size(), 1 );
Expand Down

0 comments on commit 6aa10c6

Please sign in to comment.