Skip to content

Commit 5b1c100

Browse files
nyalldawsongithub-actions[bot]
authored andcommitted
Fix leak when directly iterating feature in PyQGIS
Fixes #32944
1 parent 1959776 commit 5b1c100

File tree

4 files changed

+42
-0
lines changed

4 files changed

+42
-0
lines changed

python/PyQt6/core/auto_generated/qgsfeature.sip.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ geometry and a list of field/values attributes.
4040
QgsAttributes attributes = sipCpp->attributes();
4141
PyObject *attrs = sipConvertFromType( &attributes, sipType_QgsAttributes, Py_None );
4242
sipRes = PyObject_GetIter( attrs );
43+
// PyObject_GetIter has added a ref to attrs - we need to decrement the ref from sipConvertFromType,
44+
// so that the garbage collector will delete attrs when the iterator is deleted
45+
Py_DECREF( attrs );
4346
%End
4447

4548

python/core/auto_generated/qgsfeature.sip.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ geometry and a list of field/values attributes.
4040
QgsAttributes attributes = sipCpp->attributes();
4141
PyObject *attrs = sipConvertFromType( &attributes, sipType_QgsAttributes, Py_None );
4242
sipRes = PyObject_GetIter( attrs );
43+
// PyObject_GetIter has added a ref to attrs - we need to decrement the ref from sipConvertFromType,
44+
// so that the garbage collector will delete attrs when the iterator is deleted
45+
Py_DECREF( attrs );
4346
%End
4447

4548
SIP_PYOBJECT __getitem__( int key ) /HoldGIL/;

src/core/qgsfeature.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ class CORE_EXPORT QgsFeature
7676
QgsAttributes attributes = sipCpp->attributes();
7777
PyObject *attrs = sipConvertFromType( &attributes, sipType_QgsAttributes, Py_None );
7878
sipRes = PyObject_GetIter( attrs );
79+
// PyObject_GetIter has added a ref to attrs - we need to decrement the ref from sipConvertFromType,
80+
// so that the garbage collector will delete attrs when the iterator is deleted
81+
Py_DECREF( attrs );
7982
% End
8083
#endif
8184

tests/src/python/test_qgsvectorlayer.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,39 @@ def test_FeatureCount(self):
320320
myCount = myLayer.featureCount()
321321
self.assertEqual(myCount, 6)
322322

323+
def test_attribute_iteration(self):
324+
layer = QgsVectorLayer(
325+
self.get_test_data_path("lines.shp").as_posix(), "Lines", "ogr"
326+
)
327+
self.assertTrue(layer.isValid())
328+
all_attrs = [
329+
[attr for attr in feat.attributes()] for feat in layer.getFeatures()
330+
]
331+
self.assertCountEqual(
332+
all_attrs,
333+
[
334+
["Highway", 1.0],
335+
["Highway", 1.0],
336+
["Arterial", 2.0],
337+
["Arterial", 2.0],
338+
["Arterial", 2.0],
339+
["Arterial", 2.0],
340+
],
341+
)
342+
343+
all_attrs = [[attr for attr in feat] for feat in layer.getFeatures()]
344+
self.assertCountEqual(
345+
all_attrs,
346+
[
347+
["Highway", 1.0],
348+
["Highway", 1.0],
349+
["Arterial", 2.0],
350+
["Arterial", 2.0],
351+
["Arterial", 2.0],
352+
["Arterial", 2.0],
353+
],
354+
)
355+
323356
# undo stack
324357
def testUndoStack(self):
325358
layer = createLayerWithOnePoint()

0 commit comments

Comments
 (0)