2323 QgsFeatureRequest ,
2424 QgsFeature ,
2525 QgsGeometry ,
26+ QgsProject ,
2627 QgsWkbTypes ,
28+ QgsExpression ,
29+ QgsExpressionContext ,
30+ QgsExpressionContextUtils ,
2731 NULL ,
32+ QgsCoordinateTransform ,
2833 QgsMemoryProviderUtils ,
2934 QgsCoordinateReferenceSystem ,
3035 QgsRectangle ,
3641 QgsApplication ,
3742 QgsProviderRegistry ,
3843 QgsProviderMetadata ,
44+ QgsGeometryEngine ,
3945)
4046
4147from qgis .PyQt .QtCore import QVariant
4248
4349
44- class PyFeatureIterator (QgsFeatureIterator ):
50+ class PyFeatureIterator (QgsAbstractFeatureIterator ):
4551
4652 def __init__ (self , source , request ):
47- super (PyFeatureIterator , self ).__init__ ()
48- self ._request = request
49- self ._index = 0
53+ super (PyFeatureIterator , self ).__init__ (request )
54+ self ._request = request if request is not None else QgsFeatureRequest ()
5055 self ._source = source
56+ self ._index = 0
57+ self ._transform = QgsCoordinateTransform ()
58+ if self ._request .destinationCrs ().isValid () and self ._request .destinationCrs () != self ._source ._provider .crs ():
59+ self ._transform = QgsCoordinateTransform (self ._source ._provider .crs (), self ._request .destinationCrs (), self ._request .transformContext ())
60+ self ._filter_rect = self .filterRectToSourceCrs (self ._transform )
61+ if not self ._filter_rect .isNull ():
62+ self ._select_rect_geom = QgsGeometry .fromRect (self ._filter_rect )
63+ self ._select_rect_engine = QgsGeometry .createGeometryEngine (self ._select_rect_geom .constGet ())
64+ self ._select_rect_engine .prepareGeometry ()
65+ else :
66+ self ._select_rect_engine = None
67+ self ._select_rect_geom = None
5168
52- def nextFeature (self , f ):
69+ def fetchFeature (self , f ):
5370 """fetch next feature, return true on success"""
5471 #virtual bool nextFeature( QgsFeature &f );
72+ if self ._index < 0 :
73+ f .setValid (False )
74+ return False
5575 try :
56- _f = self ._source ._features [self ._index ]
57- self ._index += 1
58- f .setAttributes (_f .attributes ())
59- f .setGeometry (_f .geometry ())
60- f .setValid (_f .isValid ())
61- return True
62- except Exception as e :
76+ found = False
77+ while not found :
78+ _f = self ._source ._features [list (self ._source ._features .keys ())[self ._index ]]
79+ self ._index += 1
80+ self ._source ._expression_context .setFeature (_f )
81+ if self ._request .filterType () == QgsFeatureRequest .FilterExpression :
82+ if not self ._request .filterExpression ().evaluate (self ._source ._expression_context ):
83+ continue
84+ if self ._source ._subset_expression :
85+ if not self ._source ._subset_expression .evaluate (self ._source ._expression_context ):
86+ continue
87+ elif self ._request .filterType () == QgsFeatureRequest .FilterFids :
88+ if not _f .id () in self ._request .filterFids ():
89+ continue
90+ elif self ._request .filterType () == QgsFeatureRequest .FilterFid :
91+ if _f .id () != self ._request .filterFid ():
92+ continue
93+ if not self ._filter_rect .isNull ():
94+ if not _f .hasGeometry ():
95+ continue
96+ if self ._request .flags () & QgsFeatureRequest .ExactIntersect :
97+ # do exact check in case we're doing intersection
98+ if not self ._select_rect_engine .intersects (_f .geometry ().constGet ()):
99+ continue
100+ else :
101+ if not _f .geometry ().boundingBox ().intersects (self ._filter_rect ):
102+ continue
103+ f .setGeometry (_f .geometry ())
104+ self .geometryToDestinationCrs (f , self ._transform )
105+ f .setFields (_f .fields ())
106+ f .setAttributes (_f .attributes ())
107+ f .setValid (_f .isValid ())
108+ f .setId (_f .id ())
109+ return True
110+ except IndexError as e :
63111 f .setValid (False )
64112 return False
65113
66114 def __iter__ (self ):
67- 'Returns itself as an iterator object'
115+ """Returns self as an iterator object"""
116+ self ._index = 0
68117 return self
69118
70119 def __next__ (self ):
71- ' Returns the next value till current is lower than high'
120+ """ Returns the next value till current is lower than high"""
72121 f = QgsFeature ()
73122 if not self .nextFeature (f ):
74123 raise StopIteration
@@ -78,12 +127,15 @@ def __next__(self):
78127 def rewind (self ):
79128 """reset the iterator to the starting position"""
80129 #virtual bool rewind() = 0;
130+ if self ._index < 0 :
131+ return False
81132 self ._index = 0
133+ return True
82134
83135 def close (self ):
84136 """end of iterating: free the resources / lock"""
85137 #virtual bool close() = 0;
86- self ._index = 0
138+ self ._index = - 1
87139 return True
88140
89141
@@ -94,10 +146,20 @@ def __init__(self, provider):
94146 self ._provider = provider
95147 self ._features = provider ._features
96148
149+ self ._expression_context = QgsExpressionContext ()
150+ self ._expression_context .appendScope (QgsExpressionContextUtils .globalScope ())
151+ self ._expression_context .appendScope (QgsExpressionContextUtils .projectScope (QgsProject .instance ()))
152+ self ._expression_context .setFields (self ._provider .fields ())
153+ if self ._provider .subsetString ():
154+ self ._subset_expression = QgsExpression (self ._provider .subsetString ())
155+ self ._subset_expression .prepare (self ._expression_context )
156+ else :
157+ self ._subset_expression = None
158+
97159 def getFeatures (self , request ):
98160 # QgsFeatureIterator getFeatures( const QgsFeatureRequest &request ) override;
99161 # NOTE: this is the same as PyProvider.getFeatures
100- return PyFeatureIterator (self , request )
162+ return QgsFeatureIterator ( PyFeatureIterator (self , request ) )
101163
102164
103165class PyProvider (QgsVectorDataProvider ):
@@ -127,56 +189,81 @@ def __init__(self, uri=''):
127189 super (PyProvider , self ).__init__ (uri )
128190 # Use the memory layer to parse the uri
129191 mlayer = QgsVectorLayer (uri , 'ml' , 'memory' )
192+ self .setNativeTypes (mlayer .dataProvider ().nativeTypes ())
130193 self ._uri = uri
131194 self ._fields = mlayer .fields ()
132195 self ._wkbType = mlayer .wkbType ()
133196 self ._features = {}
134197 self ._extent = QgsRectangle ()
135198 self ._extent .setMinimal ()
136199 self ._subset_string = ''
200+ self ._crs = mlayer .crs ()
137201
138202 def featureSource (self ):
139203 return PyFeatureSource (self )
140204
141205 def dataSourceUri (self , expandAuthConfig = True ):
142- #QString dataSourceUri( bool expandAuthConfig = true ) const override;
143206 return self ._uri
144207
145208 def storageType (self ):
146- #QString storageType() const override;
147209 return "Python test memory storage"
148210
149- def getFeatures (self , request = None ):
150- #QgsFeatureIterator getFeatures( const QgsFeatureRequest &request ) const override;
151- return PyFeatureIterator (PyFeatureSource (self ), request )
211+ def getFeatures (self , request = QgsFeatureRequest ()):
212+ return QgsFeatureIterator (PyFeatureIterator (PyFeatureSource (self ), request ))
213+
214+ def uniqueValues (self , fieldIndex , limit = 1 ):
215+ results = set ()
216+ if fieldIndex >= 0 and fieldIndex < self .fields ().count ():
217+ req = QgsFeatureRequest ()
218+ req .setFlags (QgsFeatureRequest .NoGeometry )
219+ req .setSubsetOfAttributes ([fieldIndex ])
220+ for f in self .getFeatures (req ):
221+ results .add (f .attributes ()[fieldIndex ])
222+ return results
152223
153224 def wkbType (self ):
154- #QgsWkbTypes::Type wkbType() const override;
155225 return self ._wkbType
156226
157227 def featureCount (self ):
158- # TODO: get from source
159- # long featureCount() const override;
160- return len (self ._features )
228+ if not self .subsetString ():
229+ return len (self ._features )
230+ else :
231+ req = QgsFeatureRequest ()
232+ req .setFlags (QgsFeatureRequest .NoGeometry )
233+ req .setSubsetOfAttributes ([])
234+ return len ([f for f in self .getFeatures (req )])
161235
162236 def fields (self ):
163- #QgsFields fields() const override;
164237 return self ._fields
165238
166239 def addFeatures (self , flist , flags = None ):
167- # bool addFeatures( QgsFeatureList &flist, QgsFeatureSink::Flags flags = nullptr ) override;
168240 added = False
241+ f_added = []
242+ for f in flist :
243+ if f .hasGeometry () and (f .geometry ().wkbType () != self .wkbType ()):
244+ return added , f_added
245+
169246 for f in flist :
170- f .setId (self .next_feature_id )
171- self ._features [self .next_feature_id ] = f
247+ _f = QgsFeature (self .fields ())
248+ _f .setGeometry (f .geometry ())
249+ attrs = [None for i in range (_f .fields ().count ())]
250+ for i in range (min (len (attrs ), len (f .attributes ()))):
251+ attrs [i ] = f .attributes ()[i ]
252+ _f .setAttributes (attrs )
253+ _f .setId (self .next_feature_id )
254+ self ._features [self .next_feature_id ] = _f
172255 self .next_feature_id += 1
173256 added = True
174- if added :
257+ f_added .append (_f )
258+
259+ if len (f_added ):
175260 self .updateExtents ()
261+
176262 return added , flist
177263
178264 def deleteFeatures (self , ids ):
179- #bool deleteFeatures( const QgsFeatureIds &id ) override;
265+ if not ids :
266+ return True
180267 removed = False
181268 for id in ids :
182269 if id in self ._features :
@@ -187,21 +274,20 @@ def deleteFeatures(self, ids):
187274 return removed
188275
189276 def addAttributes (self , attrs ):
190- #bool addAttributes( const QList<QgsField> &attributes ) override;
191277 try :
192- self ._fields .append (attrs )
193278 for new_f in attrs :
279+ if new_f .type () not in (QVariant .Int , QVariant .Double , QVariant .String , QVariant .Date , QVariant .Time , QVariant .DateTime , QVariant .LongLong , QVariant .StringList , QVariant .List ):
280+ continue
281+ self ._fields .append (new_f )
194282 for f in self ._features .values ():
195283 old_attrs = f .attributes ()
196- old_attrs .app
197284 old_attrs .append (None )
198285 f .setAttributes (old_attrs )
199286 return True
200- except :
287+ except Exception :
201288 return False
202289
203- def renameAttributes (self , renameAttributes ):
204- #bool renameAttributes( const QgsFieldNameMap &renamedAttributes ) override;
290+ def renameAttributes (self , renamedAttributes ):
205291 result = True
206292 for key , new_name in renamedAttributes :
207293 fieldIndex = key
@@ -216,7 +302,6 @@ def renameAttributes(self, renameAttributes):
216302 return True
217303
218304 def deleteAttributes (self , attributes ):
219- #bool deleteAttributes( const QgsAttributeIds &attributes ) override;
220305 attrIdx = sorted (attributes .toList (), reverse = True )
221306
222307 # delete attributes one-by-one with decreasing index
@@ -229,52 +314,55 @@ def deleteAttributes(self, attributes):
229314 return True
230315
231316 def changeAttributeValues (self , attr_map ):
232- #bool changeAttributeValues( const QgsChangedAttributesMap &attr_map ) override;
233317 for feature_id , attrs in attr_map .items ():
234318 try :
235319 f = self ._features [feature_id ]
236320 except KeyError :
237321 continue
238- for k , v in attrs :
322+ for k , v in attrs . items () :
239323 f .setAttribute (k , v )
240324 return True
241325
242326 def changeGeometryValues (self , geometry_map ):
243- #bool changeGeometryValues( const QgsGeometryMap &geometry_map ) override;
244- #TODO
327+ for feature_id , geometry in geometry_map .items ():
328+ try :
329+ f = self ._features [feature_id ]
330+ f .setGeometry (geometry )
331+ except KeyError :
332+ continue
333+ self .updateExtents ()
245334 return True
246335
336+ def allFeatureIds (self ):
337+ return list (self ._features .keys ())
338+
247339 def subsetString (self ):
248- #QString subsetString() const override;
249340 return self ._subset_string
250341
251342 def setSubsetString (self , subsetString ):
252- #bool setSubsetString( const QString &theSQL, bool updateFeatureCount = true ) override;
253343 self ._subset_string = subsetString
344+ self .updateExtents ()
345+ self .clearMinMaxCache ()
346+ self .dataChanged .emit ()
254347
255348 def supportsSubsetString (self ):
256- #bool supportsSubsetString() const override { return true; }
257349 return True
258350
259351 def createSpatialIndex (self ):
260- #bool createSpatialIndex() override;
261352 return True
262353
263354 def capabilities (self ):
264- #QgsVectorDataProvider::Capabilities capabilities() const override;
265355 return QgsVectorDataProvider .AddFeatures | QgsVectorDataProvider .DeleteFeatures | QgsVectorDataProvider .ChangeGeometries | QgsVectorDataProvider .ChangeAttributeValues | QgsVectorDataProvider .AddAttributes | QgsVectorDataProvider .DeleteAttributes | QgsVectorDataProvider .RenameAttributes | QgsVectorDataProvider .SelectAtId | QgsVectorDataProvider . CircularGeometries
266356
267357 #/* Implementation of functions from QgsDataProvider */
268358
269359 def name (self ):
270- #QString name() const override;
271360 return self .providerKey ()
272361
273362 def extent (self ):
274- #QgsRectangle extent() const override;
275- if self ._extent .isEmpty () and not self ._features :
363+ if self ._extent .isEmpty () and self ._features :
276364 self ._extent .setMinimal ()
277- if self ._subset_string . isEmpty () :
365+ if not self ._subset_string :
278366 # fast way - iterate through all features
279367 for feat in self ._features .values ():
280368 if feat .hasGeometry ():
@@ -284,18 +372,15 @@ def extent(self):
284372 if f .hasGeometry ():
285373 self ._extent .combineExtentWith (f .geometry ().boundingBox ())
286374
287- elif self ._features :
375+ elif not self ._features :
288376 self ._extent .setMinimal ()
289- return self ._extent
377+ return QgsRectangle ( self ._extent )
290378
291379 def updateExtents (self ):
292- #void updateExtents() override;
293380 self ._extent .setMinimal ()
294381
295382 def isValid (self ):
296- #bool isValid() const override;
297383 return True
298384
299385 def crs (self ):
300- #QgsCoordinateReferenceSystem crs() const override;
301- return QgsCoordinateReferenceSystem (4326 )
386+ return self ._crs
0 commit comments