Skip to content

Commit

Permalink
Fix leak when directly iterating feature in PyQGIS
Browse files Browse the repository at this point in the history
Fixes #32944
  • Loading branch information
nyalldawson authored and github-actions[bot] committed Feb 21, 2025
1 parent 1959776 commit 5b1c100
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 0 deletions.
3 changes: 3 additions & 0 deletions python/PyQt6/core/auto_generated/qgsfeature.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ geometry and a list of field/values attributes.
QgsAttributes attributes = sipCpp->attributes();
PyObject *attrs = sipConvertFromType( &attributes, sipType_QgsAttributes, Py_None );
sipRes = PyObject_GetIter( attrs );
// PyObject_GetIter has added a ref to attrs - we need to decrement the ref from sipConvertFromType,
// so that the garbage collector will delete attrs when the iterator is deleted
Py_DECREF( attrs );
%End


Expand Down
3 changes: 3 additions & 0 deletions python/core/auto_generated/qgsfeature.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ geometry and a list of field/values attributes.
QgsAttributes attributes = sipCpp->attributes();
PyObject *attrs = sipConvertFromType( &attributes, sipType_QgsAttributes, Py_None );
sipRes = PyObject_GetIter( attrs );
// PyObject_GetIter has added a ref to attrs - we need to decrement the ref from sipConvertFromType,
// so that the garbage collector will delete attrs when the iterator is deleted
Py_DECREF( attrs );
%End

SIP_PYOBJECT __getitem__( int key ) /HoldGIL/;
Expand Down
3 changes: 3 additions & 0 deletions src/core/qgsfeature.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ class CORE_EXPORT QgsFeature
QgsAttributes attributes = sipCpp->attributes();
PyObject *attrs = sipConvertFromType( &attributes, sipType_QgsAttributes, Py_None );
sipRes = PyObject_GetIter( attrs );
// PyObject_GetIter has added a ref to attrs - we need to decrement the ref from sipConvertFromType,
// so that the garbage collector will delete attrs when the iterator is deleted
Py_DECREF( attrs );
% End
#endif

Expand Down
33 changes: 33 additions & 0 deletions tests/src/python/test_qgsvectorlayer.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,39 @@ def test_FeatureCount(self):
myCount = myLayer.featureCount()
self.assertEqual(myCount, 6)

def test_attribute_iteration(self):
layer = QgsVectorLayer(
self.get_test_data_path("lines.shp").as_posix(), "Lines", "ogr"
)
self.assertTrue(layer.isValid())
all_attrs = [
[attr for attr in feat.attributes()] for feat in layer.getFeatures()
]
self.assertCountEqual(
all_attrs,
[
["Highway", 1.0],
["Highway", 1.0],
["Arterial", 2.0],
["Arterial", 2.0],
["Arterial", 2.0],
["Arterial", 2.0],
],
)

all_attrs = [[attr for attr in feat] for feat in layer.getFeatures()]
self.assertCountEqual(
all_attrs,
[
["Highway", 1.0],
["Highway", 1.0],
["Arterial", 2.0],
["Arterial", 2.0],
["Arterial", 2.0],
["Arterial", 2.0],
],
)

# undo stack
def testUndoStack(self):
layer = createLayerWithOnePoint()
Expand Down

0 comments on commit 5b1c100

Please sign in to comment.