[processing] Cleanup some layer/writer related handling

Ensure that layers created by QgsProcessingUtils::createFeatureSink
can always be retrieved using QgsProcessingUtils::mapLayerFromString
This commit is contained in:
Nyall Dawson 2017-05-09 15:03:51 +10:00
parent cb23ebed65
commit 6aa10c6817
9 changed files with 33 additions and 40 deletions

View File

@ -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
@ -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::

View File

@ -86,7 +86,7 @@ class VectorSplit(GeoAlgorithm):
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)

View File

@ -10,8 +10,8 @@ from qgis.core import QgsFeature, QgsField, QgsProcessingUtils
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)

View File

@ -385,8 +385,7 @@ class OutputVector(Output):
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

View File

@ -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):

View File

@ -8,7 +8,7 @@ from qgis.core import QgsWkbTypes, QgsProcessingUtils
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)

View File

@ -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
@ -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
{
@ -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 );
}
}
@ -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 );
}

View File

@ -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.
*/
@ -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
/**
@ -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.
@ -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:

View File

@ -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" ) );
@ -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" ) );
@ -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" ) );
@ -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 );
@ -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 );