Added QgsDataProvider::ProviderOptions to the bindings

This commit is contained in:
Alessandro Pasotti 2018-06-01 14:18:44 +02:00
parent 0fa88e6faf
commit 3aa630ca25
5 changed files with 30 additions and 88 deletions

View File

@ -50,14 +50,14 @@ no library is involved.
Py_BEGIN_ALLOW_THREADS
sipCpp = new QgsProviderMetadata( *a0, *a1, [a2]( const QString &dataSource ) -> QgsDataProvider*
sipCpp = new QgsProviderMetadata( *a0, *a1, [a2]( const QString &dataSource, const QgsDataProvider::ProviderOptions &providerOptions ) -> QgsDataProvider*
{
QgsDataProvider *provider;
provider = nullptr;
PyObject *sipResObj;
SIP_BLOCK_THREADS
sipResObj = sipCallMethod( NULL, a2, "D", new QString( dataSource ), sipType_QString, NULL );
sipResObj = sipCallMethod( NULL, a2, "DD", new QString( dataSource ), sipType_QString, NULL, new QgsDataProvider::ProviderOptions( providerOptions ), sipType_QgsDataProvider_ProviderOptions, NULL );
if ( sipResObj )
{

View File

@ -182,7 +182,7 @@ Returns a string containing the available protocol drivers
void registerProvider( QgsProviderMetadata *providerMetadata /Transfer/ );
%Docstring
register a new vector data provider from its ``providerMetadata``
register a new vector data provider from its ``providerMetadata``
.. note::

View File

@ -71,14 +71,14 @@ class CORE_EXPORT QgsProviderMetadata
Py_BEGIN_ALLOW_THREADS
sipCpp = new QgsProviderMetadata( *a0, *a1, [a2]( const QString &dataSource ) -> QgsDataProvider*
sipCpp = new QgsProviderMetadata( *a0, *a1, [a2]( const QString &dataSource, const QgsDataProvider::ProviderOptions &providerOptions ) -> QgsDataProvider*
{
QgsDataProvider *provider;
provider = nullptr;
PyObject *sipResObj;
SIP_BLOCK_THREADS
sipResObj = sipCallMethod( NULL, a2, "D", new QString( dataSource ), sipType_QString, NULL );
sipResObj = sipCallMethod( NULL, a2, "DD", new QString( dataSource ), sipType_QString, NULL, new QgsDataProvider::ProviderOptions( providerOptions ), sipType_QgsDataProvider_ProviderOptions, NULL );
if ( sipResObj )
{

View File

@ -46,6 +46,7 @@ from qgis.core import (
QgsProviderMetadata,
QgsGeometryEngine,
QgsSpatialIndex,
QgsDataProvider,
)
from qgis.PyQt.QtCore import QVariant
@ -54,7 +55,7 @@ from qgis.PyQt.QtCore import QVariant
class PyFeatureIterator(QgsAbstractFeatureIterator):
def __init__(self, source, request):
super(PyFeatureIterator, self).__init__(request)
super().__init__(request)
self._request = request if request is not None else QgsFeatureRequest()
self._source = source
self._index = 0
@ -187,13 +188,13 @@ class PyProvider(QgsVectorDataProvider):
return 'Python Test Provider'
@classmethod
def createProvider(cls, uri):
return PyProvider(uri)
def createProvider(cls, uri, providerOptions):
return PyProvider(uri, providerOptions)
# Implementation of functions from QgsVectorDataProvider
def __init__(self, uri=''):
super(PyProvider, self).__init__(uri)
def __init__(self, uri='', providerOptions=QgsDataProvider.ProviderOptions()):
super().__init__(uri)
# Use the memory layer to parse the uri
mlayer = QgsVectorLayer(uri, 'ml', 'memory')
self.setNativeTypes(mlayer.dataProvider().nativeTypes())
@ -206,6 +207,7 @@ class PyProvider(QgsVectorDataProvider):
self._subset_string = ''
self._crs = mlayer.crs()
self._spatialindex = None
self._provider_options = providerOptions
if 'index=yes'in self._uri:
self.createSpatialIndex()
@ -307,16 +309,21 @@ class PyProvider(QgsVectorDataProvider):
def renameAttributes(self, renamedAttributes):
result = True
for key, new_name in renamedAttributes:
fieldIndex = key
# We need to replace all fields because python bindings return a copy from [] and at()
new_fields = [self._fields.at(i) for i in range(self._fields.count())]
for fieldIndex, new_name in renamedAttributes.items():
if fieldIndex < 0 or fieldIndex >= self._fields.count():
result = False
continue
if new_name in self._fields.indexFromName(new_name) >= 0:
if self._fields.indexFromName(new_name) >= 0:
#field name already in use
result = False
continue
self._fields[fieldIndex].setName(new_name)
new_fields[fieldIndex].setName(new_name)
if result:
self._fields = QgsFields()
for i in range(len(new_fields)):
self._fields.append(new_fields[i])
return result
def deleteAttributes(self, attributes):

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
"""QGIS Unit tests for the python layer provider.
"""QGIS Unit tests for the python dataprovider.
.. note:: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -144,13 +144,13 @@ class TestPyQgsPythonProvider(unittest.TestCase, ProviderTestCase):
return self.createLayer()
def testGetFeaturesSubsetAttributes2(self):
""" Override and skip this test for memory provider, as it's actually more efficient for the memory provider to return
""" Override and skip this test for pythonprovider provider, as it's actually more efficient for the pythonprovider provider to return
its features as direct copies (due to implicit sharing of QgsFeature)
"""
pass
def testGetFeaturesNoGeometry(self):
""" Override and skip this test for memory provider, as it's actually more efficient for the memory provider to return
""" Override and skip this test for pythonprovider provider, as it's actually more efficient for the pythonprovider provider to return
its features as direct copies (due to implicit sharing of QgsFeature)
"""
pass
@ -163,8 +163,8 @@ class TestPyQgsPythonProvider(unittest.TestCase, ProviderTestCase):
def testCtors(self):
testVectors = ["Point", "LineString", "Polygon", "MultiPoint", "MultiLineString", "MultiPolygon", "None"]
for v in testVectors:
layer = QgsVectorLayer(v, "test", "memory")
assert layer.isValid(), "Failed to create valid %s memory layer" % (v)
layer = QgsVectorLayer(v, "test", "pythonprovider")
assert layer.isValid(), "Failed to create valid %s pythonprovider layer" % (v)
def testLayerGeometry(self):
testVectors = [("Point", QgsWkbTypes.PointGeometry, QgsWkbTypes.Point),
@ -199,7 +199,7 @@ class TestPyQgsPythonProvider(unittest.TestCase, ProviderTestCase):
("MultiPolygon25D", QgsWkbTypes.PolygonGeometry, QgsWkbTypes.MultiPolygon25D),
("None", QgsWkbTypes.NullGeometry, QgsWkbTypes.NoGeometry)]
for v in testVectors:
layer = QgsVectorLayer(v[0], "test", "memory")
layer = QgsVectorLayer(v[0], "test", "pythonprovider")
myMessage = ('Expected: %s\nGot: %s\n' %
(v[1], layer.geometryType()))
@ -210,7 +210,7 @@ class TestPyQgsPythonProvider(unittest.TestCase, ProviderTestCase):
assert layer.wkbType() == v[2], myMessage
def testAddFeatures(self):
layer = QgsVectorLayer("Point", "test", "memory")
layer = QgsVectorLayer("Point", "test", "pythonprovider")
provider = layer.dataProvider()
res = provider.addAttributes([QgsField("name", QVariant.String),
@ -260,7 +260,7 @@ class TestPyQgsPythonProvider(unittest.TestCase, ProviderTestCase):
assert compareWkt(str(geom.asWkt()), "Point (10 10)"), myMessage
def testGetFields(self):
layer = QgsVectorLayer("Point", "test", "memory")
layer = QgsVectorLayer("Point", "test", "pythonprovider")
provider = layer.dataProvider()
provider.addAttributes([QgsField("name", QVariant.String),
@ -345,7 +345,7 @@ class TestPyQgsPythonProvider(unittest.TestCase, ProviderTestCase):
assert f == importedFields.field(f.name())
def testRenameAttributes(self):
layer = QgsVectorLayer("Point", "test", "memory")
layer = QgsVectorLayer("Point", "test", "pythonprovider")
provider = layer.dataProvider()
res = provider.addAttributes([QgsField("name", QVariant.String),
@ -382,71 +382,6 @@ class TestPyQgsPythonProvider(unittest.TestCase, ProviderTestCase):
self.assertEqual(fet.fields()[1].name(), 'mapinfo_is_the_stone_age')
self.assertEqual(fet.fields()[2].name(), 'super_size')
def testUniqueSource(self):
"""
Similar memory layers should have unique source - some code checks layer source to identify
matching layers
"""
layer = QgsVectorLayer("Point", "test", "memory")
layer2 = QgsVectorLayer("Point", "test2", "memory")
self.assertNotEqual(layer.source(), layer2.source())
def testCreateMemoryLayer(self):
"""
Test QgsMemoryProviderUtils.createMemoryLayer()
"""
# no fields
layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields())
self.assertTrue(layer.isValid())
self.assertEqual(layer.name(), 'my name')
self.assertTrue(layer.fields().isEmpty())
# similar layers should have unique sources
layer2 = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields())
self.assertNotEqual(layer.source(), layer2.source())
# geometry type
layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields(), QgsWkbTypes.Point)
self.assertTrue(layer.isValid())
self.assertEqual(layer.wkbType(), QgsWkbTypes.Point)
layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields(), QgsWkbTypes.PolygonZM)
self.assertTrue(layer.isValid())
self.assertEqual(layer.wkbType(), QgsWkbTypes.PolygonZM)
# crs
layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields(), QgsWkbTypes.PolygonZM, QgsCoordinateReferenceSystem.fromEpsgId(3111))
self.assertTrue(layer.isValid())
self.assertEqual(layer.wkbType(), QgsWkbTypes.PolygonZM)
self.assertTrue(layer.crs().isValid())
self.assertEqual(layer.crs().authid(), 'EPSG:3111')
# fields
fields = QgsFields()
fields.append(QgsField("string", QVariant.String))
fields.append(QgsField("long", QVariant.LongLong))
fields.append(QgsField("double", QVariant.Double))
fields.append(QgsField("integer", QVariant.Int))
fields.append(QgsField("date", QVariant.Date))
fields.append(QgsField("datetime", QVariant.DateTime))
fields.append(QgsField("time", QVariant.Time))
layer = QgsMemoryProviderUtils.createMemoryLayer('my name', fields)
self.assertTrue(layer.isValid())
self.assertFalse(layer.fields().isEmpty())
self.assertEqual(len(layer.fields()), len(fields))
for i in range(len(fields)):
self.assertEqual(layer.fields()[i].name(), fields[i].name())
self.assertEqual(layer.fields()[i].type(), fields[i].type())
# unsupported field type
fields = QgsFields()
fields.append(QgsField("rect", QVariant.RectF))
layer = QgsMemoryProviderUtils.createMemoryLayer('my name', fields)
self.assertTrue(layer.isValid())
self.assertFalse(layer.fields().isEmpty())
self.assertEqual(layer.fields()[0].name(), 'rect')
self.assertEqual(layer.fields()[0].type(), QVariant.String) # should be mapped to string
def testThreadSafetyWithIndex(self):
layer = QgsVectorLayer('Point?crs=epsg:4326&index=yes&field=pk:integer&field=cnt:int8&field=name:string(0)&field=name2:string(0)&field=num_char:string&key=pk',
'test', 'pythonprovider')