Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Expose api to determine capabilities of QgsVectorFileWriter
Currently allows determining whether field comments and aliases
are supported by the writer
  • Loading branch information
nyalldawson committed Apr 21, 2023
1 parent 7557095 commit 308eb1d
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 0 deletions.
8 changes: 8 additions & 0 deletions python/core/auto_additions/qgis.py
Expand Up @@ -728,6 +728,14 @@
# --
Qgis.VectorExportResult.baseClass = Qgis
# monkey patching scoped based enum
Qgis.VectorFileWriterCapability.FieldAliases.__doc__ = "Writer can support field aliases"
Qgis.VectorFileWriterCapability.FieldComments.__doc__ = "Writer can support field comments"
Qgis.VectorFileWriterCapability.__doc__ = 'Capabilities supported by a :py:class:`QgsVectorFileWriter` object.\n\n.. versionadded:: 3.32\n\n' + '* ``FieldAliases``: ' + Qgis.VectorFileWriterCapability.FieldAliases.__doc__ + '\n' + '* ``FieldComments``: ' + Qgis.VectorFileWriterCapability.FieldComments.__doc__
# --
Qgis.VectorFileWriterCapability.baseClass = Qgis
Qgis.VectorFileWriterCapabilities.baseClass = Qgis
VectorFileWriterCapabilities = Qgis # dirty hack since SIP seems to introduce the flags in module
# monkey patching scoped based enum
Qgis.SqlLayerDefinitionCapability.SubsetStringFilter.__doc__ = "SQL layer definition supports subset string filter"
Qgis.SqlLayerDefinitionCapability.GeometryColumn.__doc__ = "SQL layer definition supports geometry column"
Qgis.SqlLayerDefinitionCapability.PrimaryKeys.__doc__ = "SQL layer definition supports primary keys"
Expand Down
11 changes: 11 additions & 0 deletions python/core/auto_generated/qgis.sip.in
Expand Up @@ -415,6 +415,15 @@ The development version
UserCanceled,
};

enum class VectorFileWriterCapability
{
FieldAliases,
FieldComments,
};

typedef QFlags<Qgis::VectorFileWriterCapability> VectorFileWriterCapabilities;


enum class SqlLayerDefinitionCapability
{
SubsetStringFilter,
Expand Down Expand Up @@ -2113,6 +2122,8 @@ QFlags<Qgis::LabelPolygonPlacementFlag> operator|(Qgis::LabelPolygonPlacementFla

QFlags<Qgis::DatabaseProviderConnectionCapability2> operator|(Qgis::DatabaseProviderConnectionCapability2 f1, QFlags<Qgis::DatabaseProviderConnectionCapability2> f2);

QFlags<Qgis::VectorFileWriterCapability> operator|(Qgis::VectorFileWriterCapability f1, QFlags<Qgis::VectorFileWriterCapability> f2);




Expand Down
25 changes: 25 additions & 0 deletions python/core/auto_generated/qgsvectorfilewriter.sip.in
Expand Up @@ -606,6 +606,31 @@ Checks whether there were any errors in constructor
QString errorMessage() const;
%Docstring
Retrieves error message
%End

QString driver() const;
%Docstring
Returns the GDAL (short) driver name associated with the output file.

.. seealso:: :py:func:`driverLongName`

.. versionadded:: 3.32
%End

QString driverLongName() const;
%Docstring
Returns the GDAL long driver name associated with the output file.

.. seealso:: :py:func:`driver`

.. versionadded:: 3.32
%End

Qgis::VectorFileWriterCapabilities capabilities() const;
%Docstring
Returns the capabilities supported by the writer.

.. versionadded:: 3.32
%End

virtual bool addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags = QgsFeatureSink::Flags() );
Expand Down
33 changes: 33 additions & 0 deletions src/core/qgsvectorfilewriter.cpp
Expand Up @@ -246,6 +246,8 @@ void QgsVectorFileWriter::init( QString vectorFileName,
return;
}

mOgrDriverLongName = QString( GDALGetMetadataItem( poDriver, GDAL_DMD_LONGNAME, nullptr ) );

MetaData metadata;
bool metadataFound = driverMetadata( driverName, metadata );

Expand Down Expand Up @@ -559,6 +561,22 @@ void QgsVectorFileWriter::init( QString vectorFileName,

mFieldValueConverter = fieldValueConverter;

#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0)
if ( const char *pszCreateFieldDefnFlags = GDALGetMetadataItem( poDriver, GDAL_DMD_CREATION_FIELD_DEFN_FLAGS, nullptr ) )
{
char **papszTokens = CSLTokenizeString2( pszCreateFieldDefnFlags, " ", 0 );
if ( CSLFindString( papszTokens, "AlternativeName" ) >= 0 )
{
mCapabilities |= Qgis::VectorFileWriterCapability::FieldAliases;
}
if ( CSLFindString( papszTokens, "Comment" ) >= 0 )
{
mCapabilities |= Qgis::VectorFileWriterCapability::FieldComments;
}
CSLDestroy( papszTokens );
}
#endif

switch ( action )
{
case CreateOrOverwriteFile:
Expand Down Expand Up @@ -2549,6 +2567,21 @@ QString QgsVectorFileWriter::errorMessage() const
return mErrorMessage;
}

QString QgsVectorFileWriter::driver() const
{
return mOgrDriverName;
}

QString QgsVectorFileWriter::driverLongName() const
{
return mOgrDriverLongName;
}

Qgis::VectorFileWriterCapabilities QgsVectorFileWriter::capabilities() const
{
return mCapabilities;
}

bool QgsVectorFileWriter::addFeature( QgsFeature &feature, QgsFeatureSink::Flags )
{
return addFeatureWithStyle( feature, nullptr, Qgis::DistanceUnit::Meters );
Expand Down
26 changes: 26 additions & 0 deletions src/core/qgsvectorfilewriter.h
Expand Up @@ -825,6 +825,29 @@ class CORE_EXPORT QgsVectorFileWriter : public QgsFeatureSink
//! Retrieves error message
QString errorMessage() const;

/**
* Returns the GDAL (short) driver name associated with the output file.
*
* \see driverLongName()
* \since QGIS 3.32
*/
QString driver() const;

/**
* Returns the GDAL long driver name associated with the output file.
*
* \see driver()
* \since QGIS 3.32
*/
QString driverLongName() const;

/**
* Returns the capabilities supported by the writer.
*
* \since QGIS 3.32
*/
Qgis::VectorFileWriterCapabilities capabilities() const;

bool addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags = QgsFeatureSink::Flags() ) override;
bool addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags = QgsFeatureSink::Flags() ) override;
QString lastError() const override;
Expand Down Expand Up @@ -945,6 +968,7 @@ class CORE_EXPORT QgsVectorFileWriter : public QgsFeatureSink
double mSymbologyScale;

QString mOgrDriverName;
QString mOgrDriverLongName;

//! Field value converter
FieldValueConverter *mFieldValueConverter = nullptr;
Expand Down Expand Up @@ -1041,6 +1065,8 @@ class CORE_EXPORT QgsVectorFileWriter : public QgsFeatureSink
bool mUsingTransaction = false;
QSet< QVariant::Type > mSupportedListSubTypes;

Qgis::VectorFileWriterCapabilities mCapabilities;

void createSymbolLayerTable( QgsVectorLayer *vl, const QgsCoordinateTransform &ct, OGRDataSourceH ds );
gdal::ogr_feature_unique_ptr createFeature( const QgsFeature &feature );
bool writeFeature( OGRLayerH layer, OGRFeatureH feature );
Expand Down
47 changes: 47 additions & 0 deletions tests/src/python/test_qgsvectorfilewriter.py
Expand Up @@ -28,6 +28,7 @@
)
from qgis.core import (
NULL,
Qgis,
QgsCoordinateReferenceSystem,
QgsCoordinateTransform,
QgsCoordinateTransformContext,
Expand Down Expand Up @@ -1645,6 +1646,52 @@ def testWriteJsonMapToGpkg(self):
f = next(layer.getFeatures())
self.assertEqual(f.attributes()[1], attr_val)

@unittest.skipIf(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(3, 7, 0), "GDAL 3.7 required")
def test_field_capabilities(self):
with tempfile.TemporaryDirectory() as temp_dir:
dest_file_name = os.path.join(temp_dir,
'test_gpkg.gpkg')
fields = QgsFields()
fields.append(QgsField("note", QVariant.Double))
lyrname = "test1"
opts = QgsVectorFileWriter.SaveVectorOptions()
opts.driverName = "GPKG"
opts.layerName = lyrname
opts.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteFile
writer = QgsVectorFileWriter.create(dest_file_name, fields,
QgsWkbTypes.Point,
QgsCoordinateReferenceSystem.fromEpsgId(
4326),
QgsCoordinateTransformContext(),
opts, QgsFeatureSink.SinkFlags(),
None, lyrname)

self.assertEqual(writer.driver(), 'GPKG')
self.assertEqual(writer.driverLongName(), 'GeoPackage')
self.assertTrue(
writer.capabilities() & Qgis.VectorFileWriterCapability.FieldAliases)
self.assertTrue(
writer.capabilities() & Qgis.VectorFileWriterCapability.FieldComments)

dest_file_name = os.path.join(temp_dir,
'test_shp.shp')
opts.driverName = "ESRI Shapefile"
writer = QgsVectorFileWriter.create(dest_file_name, fields,
QgsWkbTypes.Point,
QgsCoordinateReferenceSystem.fromEpsgId(
4326),
QgsCoordinateTransformContext(),
opts,
QgsFeatureSink.SinkFlags(),
None, lyrname)

self.assertEqual(writer.driver(), 'ESRI Shapefile')
self.assertEqual(writer.driverLongName(), 'ESRI Shapefile')
self.assertFalse(
writer.capabilities() & Qgis.VectorFileWriterCapability.FieldAliases)
self.assertFalse(
writer.capabilities() & Qgis.VectorFileWriterCapability.FieldComments)


if __name__ == '__main__':
unittest.main()

0 comments on commit 308eb1d

Please sign in to comment.