Skip to content

Commit a5d7fe2

Browse files
committedJun 28, 2021
Unit tests for OGR provider querySublayers, minor fixes
1 parent 15e1e23 commit a5d7fe2

File tree

9 files changed

+158
-13
lines changed

9 files changed

+158
-13
lines changed
 

‎src/core/providers/ogr/qgsogrprovider.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -627,9 +627,10 @@ QList<QgsProviderSublayerDetails> QgsOgrProvider::_subLayers( Qgis::SublayerQuer
627627
if ( !mSubLayerList.isEmpty() )
628628
return mSubLayerList;
629629

630-
if ( mOgrLayer && ( mIsSubLayer || layerCount() == 1 ) )
630+
const size_t totalLayerCount = layerCount();
631+
if ( mOgrLayer && ( mIsSubLayer || totalLayerCount == 1 ) )
631632
{
632-
mSubLayerList << QgsOgrProviderUtils::querySubLayerList( mLayerIndex, mOgrLayer, mGDALDriverName, flags, mIsSubLayer, dataSourceUri() );
633+
mSubLayerList << QgsOgrProviderUtils::querySubLayerList( mLayerIndex, mOgrLayer, mGDALDriverName, flags, mIsSubLayer, dataSourceUri(), totalLayerCount == 1 );
633634
}
634635
else
635636
{
@@ -638,7 +639,7 @@ QList<QgsProviderSublayerDetails> QgsOgrProvider::_subLayers( Qgis::SublayerQuer
638639
// reuse the same dataset. Can help in a particular with a FileGDB with
639640
// the FileGDB driver
640641
QgsOgrLayerUniquePtr firstLayer;
641-
for ( unsigned int i = 0; i < layerCount() ; i++ )
642+
for ( size_t i = 0; i < totalLayerCount ; i++ )
642643
{
643644
QString errCause;
644645
QgsOgrLayerUniquePtr layer = QgsOgrProviderUtils::getLayer( mOgrOrigLayer->datasetName(),
@@ -652,7 +653,7 @@ QList<QgsProviderSublayerDetails> QgsOgrProvider::_subLayers( Qgis::SublayerQuer
652653
if ( !layer )
653654
continue;
654655

655-
mSubLayerList << QgsOgrProviderUtils::querySubLayerList( i, layer.get(), mGDALDriverName, flags, mIsSubLayer, dataSourceUri() );
656+
mSubLayerList << QgsOgrProviderUtils::querySubLayerList( i, layer.get(), mGDALDriverName, flags, mIsSubLayer, dataSourceUri(), totalLayerCount == 1 );
656657
if ( firstLayer == nullptr )
657658
{
658659
firstLayer = std::move( layer );

‎src/core/providers/ogr/qgsogrprovidermetadata.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,11 +1046,11 @@ QList<QgsProviderSublayerDetails> QgsOgrProviderMetadata::querySublayers( const
10461046
skippedLayerNames = QgsSqliteUtils::systemTables();
10471047
}
10481048

1049-
const unsigned int layerCount = firstLayer->GetLayerCount();
1049+
const int layerCount = firstLayer->GetLayerCount();
10501050

10511051
if ( layerCount == 1 )
10521052
{
1053-
return QgsOgrProviderUtils::querySubLayerList( 0, firstLayer.get(), driverName, flags, false, uri, feedback );
1053+
return QgsOgrProviderUtils::querySubLayerList( 0, firstLayer.get(), driverName, flags, false, uri, true, feedback );
10541054
}
10551055
else
10561056
{
@@ -1059,7 +1059,7 @@ QList<QgsProviderSublayerDetails> QgsOgrProviderMetadata::querySublayers( const
10591059
// layer alive while we iterate over the other layers, so that we can
10601060
// reuse the same dataset. Can help in a particular with a FileGDB with
10611061
// the FileGDB driver
1062-
for ( unsigned int i = 0; i < layerCount; i++ )
1062+
for ( int i = 0; i < layerCount; i++ )
10631063
{
10641064
if ( feedback && feedback->isCanceled() )
10651065
break;
@@ -1081,7 +1081,7 @@ QList<QgsProviderSublayerDetails> QgsOgrProviderMetadata::querySublayers( const
10811081
continue;
10821082
}
10831083

1084-
res << QgsOgrProviderUtils::querySubLayerList( i, i == 0 ? firstLayer.get() : layer.get(), driverName, flags, false, uri, feedback );
1084+
res << QgsOgrProviderUtils::querySubLayerList( i, i == 0 ? firstLayer.get() : layer.get(), driverName, flags, false, uri, false, feedback );
10851085
}
10861086
return res;
10871087
}

‎src/core/providers/ogr/qgsogrproviderutils.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2292,7 +2292,7 @@ bool QgsOgrProviderUtils::canDriverShareSameDatasetAmongLayers( const QString &d
22922292
!( updateMode && dsName.endsWith( QLatin1String( ".shp.zip" ), Qt::CaseInsensitive ) );
22932293
}
22942294

2295-
QList< QgsProviderSublayerDetails > QgsOgrProviderUtils::querySubLayerList( int i, QgsOgrLayer *layer, const QString &driverName, Qgis::SublayerQueryFlags flags, bool isSubLayer, const QString &baseUri, QgsFeedback *feedback )
2295+
QList< QgsProviderSublayerDetails > QgsOgrProviderUtils::querySubLayerList( int i, QgsOgrLayer *layer, const QString &driverName, Qgis::SublayerQueryFlags flags, bool isSubLayer, const QString &baseUri, bool hasSingleLayerOnly, QgsFeedback *feedback )
22962296
{
22972297
QString layerName = QString::fromUtf8( layer->name() );
22982298

@@ -2329,9 +2329,12 @@ QList< QgsProviderSublayerDetails > QgsOgrProviderUtils::querySubLayerList( int
23292329

23302330

23312331
QVariantMap parts = QgsOgrProviderMetadata().decodeUri( baseUri );
2332-
parts.insert( QStringLiteral( "layerName" ), layerName );
2332+
if ( !hasSingleLayerOnly )
2333+
parts.insert( QStringLiteral( "layerName" ), layerName );
2334+
else
2335+
parts.remove( QStringLiteral( "layerName" ) );
23332336

2334-
if ( slowGeomTypeRetrieval || wkbFlatten( layerGeomType ) != wkbUnknown )
2337+
if ( slowGeomTypeRetrieval || wkbFlatten( layerGeomType ) != wkbUnknown || !( flags & Qgis::SublayerQueryFlag::ResolveGeometryType ) )
23352338
{
23362339
const long long layerFeatureCount = flags & Qgis::SublayerQueryFlag::CountFeatures ? layer->GetApproxFeatureCount() : static_cast< long >( Qgis::FeatureCountState::Uncounted );
23372340

‎src/core/providers/ogr/qgsogrproviderutils.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,8 @@ class CORE_EXPORT QgsOgrProviderUtils
257257
bool updateMode,
258258
const QString &dsName );
259259

260-
static QList<QgsProviderSublayerDetails> querySubLayerList( int i, QgsOgrLayer *layer, const QString &driverName, Qgis::SublayerQueryFlags flags, bool isSubLayer, const QString &baseUri, QgsFeedback *feedback = nullptr );
260+
static QList<QgsProviderSublayerDetails> querySubLayerList( int i, QgsOgrLayer *layer, const QString &driverName, Qgis::SublayerQueryFlags flags, bool isSubLayer,
261+
const QString &baseUri, bool hasSingleLayerOnly, QgsFeedback *feedback = nullptr );
261262

262263
};
263264

‎tests/src/python/test_provider_ogr.py

Lines changed: 133 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@
4242
QgsWkbTypes,
4343
QgsNetworkAccessManager,
4444
QgsLayerMetadata,
45-
QgsNotSupportedException
45+
QgsNotSupportedException,
46+
QgsMapLayerType,
47+
QgsProviderSublayerDetails,
48+
Qgis
4649
)
4750
from qgis.testing import start_app, unittest
4851
from qgis.utils import spatialite_connect
@@ -1501,6 +1504,135 @@ def testFieldDomains(self):
15011504
self.assertTrue(enum_setup.config()['map'], [{'one': '1'}, {'2': '2'}])
15021505
self.assertEqual(vl.editorWidgetSetup(fields.lookupField('with_enum_domain')).type(), 'ValueMap')
15031506

1507+
def test_provider_sublayer_details(self):
1508+
"""
1509+
Test retrieving sublayer details from data provider metadata
1510+
"""
1511+
metadata = QgsProviderRegistry.instance().providerMetadata('ogr')
1512+
1513+
# invalid uri
1514+
res = metadata.querySublayers('')
1515+
self.assertFalse(res)
1516+
1517+
# not a vector
1518+
res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, 'landsat.tif'))
1519+
self.assertFalse(res)
1520+
1521+
# single layer vector
1522+
res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, 'lines.shp'))
1523+
self.assertEqual(len(res), 1)
1524+
self.assertEqual(res[0].layerNumber(), 0)
1525+
self.assertEqual(res[0].name(), "lines")
1526+
self.assertEqual(res[0].description(), '')
1527+
self.assertEqual(res[0].uri(), TEST_DATA_DIR + "/lines.shp")
1528+
self.assertEqual(res[0].providerKey(), "ogr")
1529+
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
1530+
1531+
# make sure result is valid to load layer from
1532+
options = QgsProviderSublayerDetails.LayerOptions(QgsCoordinateTransformContext())
1533+
vl = res[0].toLayer(options)
1534+
self.assertTrue(vl.isValid())
1535+
1536+
# geopackage with two vector layers
1537+
res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mixed_layers.gpkg"))
1538+
self.assertEqual(len(res), 2)
1539+
self.assertEqual(res[0].layerNumber(), 0)
1540+
self.assertEqual(res[0].name(), "points")
1541+
self.assertEqual(res[0].description(), "")
1542+
self.assertEqual(res[0].uri(), "{}/mixed_layers.gpkg|layername=points".format(TEST_DATA_DIR))
1543+
self.assertEqual(res[0].providerKey(), "ogr")
1544+
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
1545+
self.assertEqual(res[0].featureCount(), Qgis.FeatureCountState.Uncounted)
1546+
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Point)
1547+
vl = res[0].toLayer(options)
1548+
self.assertTrue(vl.isValid())
1549+
self.assertEqual(vl.wkbType(), QgsWkbTypes.Point)
1550+
1551+
self.assertEqual(res[1].layerNumber(), 1)
1552+
self.assertEqual(res[1].name(), "lines")
1553+
self.assertEqual(res[1].description(), "")
1554+
self.assertEqual(res[1].uri(), "{}/mixed_layers.gpkg|layername=lines".format(TEST_DATA_DIR))
1555+
self.assertEqual(res[1].providerKey(), "ogr")
1556+
self.assertEqual(res[1].type(), QgsMapLayerType.VectorLayer)
1557+
self.assertEqual(res[1].featureCount(), Qgis.FeatureCountState.Uncounted)
1558+
self.assertEqual(res[1].wkbType(), QgsWkbTypes.MultiLineString)
1559+
vl = res[1].toLayer(options)
1560+
self.assertTrue(vl.isValid())
1561+
self.assertEqual(vl.wkbType(), QgsWkbTypes.MultiLineString)
1562+
1563+
# request feature count
1564+
res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mixed_layers.gpkg"), Qgis.SublayerQueryFlag.CountFeatures)
1565+
self.assertEqual(len(res), 2)
1566+
self.assertEqual(res[0].name(), "points")
1567+
self.assertEqual(res[0].featureCount(), 0)
1568+
self.assertEqual(res[1].name(), "lines")
1569+
self.assertEqual(res[1].featureCount(), 6)
1570+
1571+
# layer with mixed geometry types - without resolving geometry types
1572+
res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mixed_types.TAB"))
1573+
self.assertEqual(len(res), 1)
1574+
self.assertEqual(res[0].layerNumber(), 0)
1575+
self.assertEqual(res[0].name(), "mixed_types")
1576+
self.assertEqual(res[0].description(), "")
1577+
self.assertEqual(res[0].uri(), "{}/mixed_types.TAB".format(TEST_DATA_DIR))
1578+
self.assertEqual(res[0].providerKey(), "ogr")
1579+
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
1580+
self.assertEqual(res[0].featureCount(), Qgis.FeatureCountState.Uncounted)
1581+
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Unknown)
1582+
vl = res[0].toLayer(options)
1583+
self.assertTrue(vl.isValid())
1584+
1585+
# layer with mixed geometry types - without resolving geometry types, but with feature count
1586+
res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mixed_types.TAB"), Qgis.SublayerQueryFlag.CountFeatures)
1587+
self.assertEqual(len(res), 1)
1588+
self.assertEqual(res[0].layerNumber(), 0)
1589+
self.assertEqual(res[0].name(), "mixed_types")
1590+
self.assertEqual(res[0].description(), "")
1591+
self.assertEqual(res[0].uri(), "{}/mixed_types.TAB".format(TEST_DATA_DIR))
1592+
self.assertEqual(res[0].providerKey(), "ogr")
1593+
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
1594+
self.assertEqual(res[0].featureCount(), 13)
1595+
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Unknown)
1596+
1597+
# layer with mixed geometry types - resolve geometry type (for OGR provider this implies also that we count features!)
1598+
res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, "mixed_types.TAB"), Qgis.SublayerQueryFlag.ResolveGeometryType)
1599+
self.assertEqual(len(res), 3)
1600+
self.assertEqual(res[0].layerNumber(), 0)
1601+
self.assertEqual(res[0].name(), "mixed_types")
1602+
self.assertEqual(res[0].description(), "")
1603+
self.assertEqual(res[0].uri(), "{}/mixed_types.TAB|geometrytype=Point".format(TEST_DATA_DIR))
1604+
self.assertEqual(res[0].providerKey(), "ogr")
1605+
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
1606+
self.assertEqual(res[0].featureCount(), 4)
1607+
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Point)
1608+
vl = res[0].toLayer(options)
1609+
self.assertTrue(vl.isValid())
1610+
self.assertEqual(vl.wkbType(), QgsWkbTypes.Point)
1611+
1612+
self.assertEqual(res[1].layerNumber(), 0)
1613+
self.assertEqual(res[1].name(), "mixed_types")
1614+
self.assertEqual(res[1].description(), "")
1615+
self.assertEqual(res[1].uri(), "{}/mixed_types.TAB|geometrytype=LineString".format(TEST_DATA_DIR))
1616+
self.assertEqual(res[1].providerKey(), "ogr")
1617+
self.assertEqual(res[1].type(), QgsMapLayerType.VectorLayer)
1618+
self.assertEqual(res[1].featureCount(), 4)
1619+
self.assertEqual(res[1].wkbType(), QgsWkbTypes.LineString)
1620+
vl = res[1].toLayer(options)
1621+
self.assertTrue(vl.isValid())
1622+
self.assertEqual(vl.wkbType(), QgsWkbTypes.LineString)
1623+
1624+
self.assertEqual(res[2].layerNumber(), 0)
1625+
self.assertEqual(res[2].name(), "mixed_types")
1626+
self.assertEqual(res[2].description(), "")
1627+
self.assertEqual(res[2].uri(), "{}/mixed_types.TAB|geometrytype=Polygon".format(TEST_DATA_DIR))
1628+
self.assertEqual(res[2].providerKey(), "ogr")
1629+
self.assertEqual(res[2].type(), QgsMapLayerType.VectorLayer)
1630+
self.assertEqual(res[2].featureCount(), 3)
1631+
self.assertEqual(res[2].wkbType(), QgsWkbTypes.Polygon)
1632+
vl = res[2].toLayer(options)
1633+
self.assertTrue(vl.isValid())
1634+
self.assertEqual(vl.wkbType(), QgsWkbTypes.Polygon)
1635+
15041636

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

‎tests/testdata/mixed_types.DAT

209 Bytes
Binary file not shown.

‎tests/testdata/mixed_types.ID

52 Bytes
Binary file not shown.

‎tests/testdata/mixed_types.MAP

2 KB
Binary file not shown.

‎tests/testdata/mixed_types.TAB

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
!table
2+
!version 300
3+
!charset WindowsLatin1
4+
5+
Definition Table
6+
Type NATIVE Charset "WindowsLatin1"
7+
Fields 1
8+
Field1 Char (10) ;

0 commit comments

Comments
 (0)
Please sign in to comment.