From 3b2a7768f8ae3f691cd9c35d3cb001101a4af498 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Tue, 16 Jul 2024 08:21:45 +1000 Subject: [PATCH 1/3] Fix __geo_interface__ should use None for NULL values Fixes #58084 --- python/core/additions/qgsfeature.py | 4 ++-- tests/src/python/test_qgsfeature.py | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/python/core/additions/qgsfeature.py b/python/core/additions/qgsfeature.py index c94d18806e22d..bf0100ab01dca 100644 --- a/python/core/additions/qgsfeature.py +++ b/python/core/additions/qgsfeature.py @@ -16,12 +16,12 @@ * * *************************************************************************** """ +from PyQt5.QtCore import QVariant def mapping_feature(feature): geom = feature.geometry() - fields = [field.name() for field in feature.fields()] - properties = dict(list(zip(fields, feature.attributes()))) + properties = {k: None if (v is None or isinstance(v, QVariant) and v.isNull()) else v for k, v in feature.attributeMap().items()} return {'type': 'Feature', 'properties': properties, 'geometry': geom.__geo_interface__} diff --git a/tests/src/python/test_qgsfeature.py b/tests/src/python/test_qgsfeature.py index 24f99934ea812..1eb09be1458c5 100644 --- a/tests/src/python/test_qgsfeature.py +++ b/tests/src/python/test_qgsfeature.py @@ -305,6 +305,29 @@ def testUnsetFeature(self): self.assertTrue(f.isUnsetValue(3)) self.assertTrue(f.isUnsetValue(4)) + def test_geo_interface(self): + fields = QgsFields() + field1 = QgsField('my_field', QVariant.String) + fields.append(field1) + field2 = QgsField('my_field2', QVariant.String) + fields.append(field2) + field3 = QgsField('my_field3', QVariant.Int) + fields.append(field3) + + feat = QgsFeature(fields) + feat.setAttributes(['abc', 'def', 123]) + feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(123, 456))) + self.assertEqual(feat.__geo_interface__, {'geometry': {'coordinates': [123.0, 456.0], 'type': 'Point'}, + 'properties': {'my_field': 'abc', 'my_field2': 'def', 'my_field3': 123}, + 'type': 'Feature'}) + + feat.setAttributes([NULL, None, NULL]) + self.assertEqual(feat.__geo_interface__, { + 'geometry': {'coordinates': [123.0, 456.0], 'type': 'Point'}, + 'properties': {'my_field': None, 'my_field2': None, + 'my_field3': None}, + 'type': 'Feature'}) + if __name__ == '__main__': unittest.main() From 1245fee33b414761ecfb0033d10e1da005888b2c Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Thu, 18 Jul 2024 22:38:40 +1000 Subject: [PATCH 2/3] Update python/core/additions/qgsfeature.py Co-authored-by: Even Rouault --- python/core/additions/qgsfeature.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/core/additions/qgsfeature.py b/python/core/additions/qgsfeature.py index bf0100ab01dca..6ba45b4763709 100644 --- a/python/core/additions/qgsfeature.py +++ b/python/core/additions/qgsfeature.py @@ -21,7 +21,7 @@ def mapping_feature(feature): geom = feature.geometry() - properties = {k: None if (v is None or isinstance(v, QVariant) and v.isNull()) else v for k, v in feature.attributeMap().items()} + properties = {k: None if (v is None or (isinstance(v, QVariant) and v.isNull())) else v for k, v in feature.attributeMap().items()} return {'type': 'Feature', 'properties': properties, 'geometry': geom.__geo_interface__} From b361a52c77c86aa36519d66a707fe7c9f67b6cef Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Fri, 19 Jul 2024 13:47:46 +1000 Subject: [PATCH 3/3] Fix test --- tests/src/python/test_qgsfeature.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/src/python/test_qgsfeature.py b/tests/src/python/test_qgsfeature.py index 1eb09be1458c5..17bd2bed92a78 100644 --- a/tests/src/python/test_qgsfeature.py +++ b/tests/src/python/test_qgsfeature.py @@ -12,6 +12,8 @@ import os import qgis # NOQA +from qgis.PyQt.QtCore import QVariant + from qgis.core import ( NULL, QgsFeature,