Skip to content
Permalink
Browse files

Added QgsDataProvider::ProviderOptions to the bindings

  • Loading branch information
elpaso committed Jun 1, 2018
1 parent 0fa88e6 commit 3aa630ca259bebe264fe4d6adbefbe991e3a25db
@@ -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 )
{
@@ -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::

@@ -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 )
{
@@ -46,6 +46,7 @@
QgsProviderMetadata,
QgsGeometryEngine,
QgsSpatialIndex,
QgsDataProvider,
)

from qgis.PyQt.QtCore import QVariant
@@ -54,7 +55,7 @@
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 @@ def description(cls):
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 @@ def __init__(self, uri=''):
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 @@ def addAttributes(self, attrs):

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):
@@ -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 @@ def getEditableLayer(self):
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 @@ def testGetFeaturesDestinationCrs(self):
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 @@ def testLayerGeometry(self):
("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 @@ def testLayerGeometry(self):
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 @@ def testAddFeatures(self):
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 @@ def testSaveFields(self):
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 @@ def testRenameAttributes(self):
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')

0 comments on commit 3aa630c

Please sign in to comment.
You can’t perform that action at this time.