Skip to content

Commit

Permalink
[processing] Allow modification of feature request when using
Browse files Browse the repository at this point in the history
vector.features

Allows for optimising the request through subsets of attributes
or no geometry fetching

(cherry-picked from 9e1ddcb)
  • Loading branch information
nyalldawson committed Aug 9, 2016
1 parent bdd5321 commit 60d9a60
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 10 deletions.
1 change: 1 addition & 0 deletions python/plugins/processing/tests/CMakeLists.txt
Expand Up @@ -7,6 +7,7 @@ PLUGIN_INSTALL(processing tests/data ${TEST_DATA_FILES})
IF(ENABLE_TESTS) IF(ENABLE_TESTS)
INCLUDE(UsePythonTest) INCLUDE(UsePythonTest)
ADD_PYTHON_TEST(ProcessingParametersTest ParametersTest.py) ADD_PYTHON_TEST(ProcessingParametersTest ParametersTest.py)
ADD_PYTHON_TEST(ProcessingToolsTest ToolsTest.py)
ADD_PYTHON_TEST(ProcessingQgisAlgorithmsTest QgisAlgorithmsTest.py) ADD_PYTHON_TEST(ProcessingQgisAlgorithmsTest QgisAlgorithmsTest.py)
ADD_PYTHON_TEST(ProcessingGdalAlgorithmsTest GdalAlgorithmsTest.py) ADD_PYTHON_TEST(ProcessingGdalAlgorithmsTest GdalAlgorithmsTest.py)
ADD_PYTHON_TEST(ProcessingGrass7AlgorithmsImageryTest Grass7AlgorithmsImageryTest.py) ADD_PYTHON_TEST(ProcessingGrass7AlgorithmsImageryTest Grass7AlgorithmsImageryTest.py)
Expand Down
89 changes: 89 additions & 0 deletions python/plugins/processing/tests/ToolsTest.py
@@ -0,0 +1,89 @@
# -*- coding: utf-8 -*-

"""
***************************************************************************
ToolsTest
---------------------
Date : July 2017
Copyright : (C) 2017 by Nyall Dawson
Email : nyall dot dawson at gmail dot com
***************************************************************************
* *
* 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 *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************
"""

__author__ = 'Nyall Dawson'
__date__ = 'July 2016'
__copyright__ = '(C) 2016, Nyall Dawson'

# This will get replaced with a git SHA1 when you do a git archive

__revision__ = '$Format:%H$'

from qgis.testing import start_app, unittest
from processing.tests.TestData import points2
from processing.tools import vector
from qgis.core import (QgsVectorLayer, QgsFeatureRequest)
from processing.core.ProcessingConfig import ProcessingConfig

start_app()


class VectorTest(unittest.TestCase):

def testFeatures(self):
ProcessingConfig.initialize()

test_data = points2()
test_layer = QgsVectorLayer(test_data, 'test', 'ogr')

# test with all features
features = vector.features(test_layer)
self.assertEqual(len(features), 8)
self.assertEqual(set([f.id() for f in features]), set([0, 1, 2, 3, 4, 5, 6, 7]))

# test with selected features
previous_value = ProcessingConfig.getSetting(ProcessingConfig.USE_SELECTED)
ProcessingConfig.setSettingValue(ProcessingConfig.USE_SELECTED, True)
test_layer.selectByIds([2, 4, 6])
features = vector.features(test_layer)
self.assertEqual(len(features), 3)
self.assertEqual(set([f.id() for f in features]), set([2, 4, 6]))

# selection, but not using selected features
ProcessingConfig.setSettingValue(ProcessingConfig.USE_SELECTED, False)
test_layer.selectByIds([2, 4, 6])
features = vector.features(test_layer)
self.assertEqual(len(features), 8)
self.assertEqual(set([f.id() for f in features]), set([0, 1, 2, 3, 4, 5, 6, 7]))

# using selected features, but no selection
ProcessingConfig.setSettingValue(ProcessingConfig.USE_SELECTED, True)
test_layer.removeSelection()
features = vector.features(test_layer)
self.assertEqual(len(features), 8)
self.assertEqual(set([f.id() for f in features]), set([0, 1, 2, 3, 4, 5, 6, 7]))

# test that feature request is honored
ProcessingConfig.setSettingValue(ProcessingConfig.USE_SELECTED, False)
features = vector.features(test_layer, QgsFeatureRequest().setFilterFids([1, 3, 5]))
self.assertEqual(set([f.id() for f in features]), set([1, 3, 5]))

# test that feature request is honored when using selections
ProcessingConfig.setSettingValue(ProcessingConfig.USE_SELECTED, True)
test_layer.selectByIds([2, 4, 6])
features = vector.features(test_layer, QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry))
self.assertTrue(all([f.geometry() == None for f in features]))
features = vector.features(test_layer, QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry))
self.assertEqual(set([f.id() for f in features]), set([2, 4, 6]))

ProcessingConfig.setSettingValue(ProcessingConfig.USE_SELECTED, previous_value)


if __name__ == '__main__':
unittest.main()
21 changes: 11 additions & 10 deletions python/plugins/processing/tools/vector.py
Expand Up @@ -37,7 +37,8 @@
from qgis.PyQt.QtCore import QVariant, QSettings from qgis.PyQt.QtCore import QVariant, QSettings
from qgis.core import (QGis, QgsFields, QgsField, QgsGeometry, QgsRectangle, from qgis.core import (QGis, QgsFields, QgsField, QgsGeometry, QgsRectangle,
QgsSpatialIndex, QgsMapLayerRegistry, QgsMapLayer, QgsVectorLayer, QgsSpatialIndex, QgsMapLayerRegistry, QgsMapLayer, QgsVectorLayer,
QgsVectorFileWriter, QgsDistanceArea, QgsDataSourceURI, QgsCredentials) QgsVectorFileWriter, QgsDistanceArea, QgsDataSourceURI, QgsCredentials,
QgsFeatureRequest)


from processing.core.ProcessingConfig import ProcessingConfig from processing.core.ProcessingConfig import ProcessingConfig
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
Expand Down Expand Up @@ -86,7 +87,7 @@
} }




def features(layer): def features(layer, request=QgsFeatureRequest()):
"""This returns an iterator over features in a vector layer, """This returns an iterator over features in a vector layer,
considering the selection that might exist in the layer, and the considering the selection that might exist in the layer, and the
configuration that indicates whether to use only selected feature configuration that indicates whether to use only selected feature
Expand All @@ -97,15 +98,15 @@ def features(layer):
""" """
class Features: class Features:


def __init__(self, layer): def __init__(self, layer, request):
self.layer = layer self.layer = layer
self.selection = False self.selection = False
self.iter = layer.getFeatures() if ProcessingConfig.getSetting(ProcessingConfig.USE_SELECTED)\
if ProcessingConfig.getSetting(ProcessingConfig.USE_SELECTED): and layer.selectedFeatureCount() > 0:
selected = layer.selectedFeatures() self.iter = layer.selectedFeaturesIterator(request)
if len(selected) > 0: self.selection = True
self.selection = True else:
self.iter = iter(selected) self.iter = layer.getFeatures(request)


def __iter__(self): def __iter__(self):
return self.iter return self.iter
Expand All @@ -116,7 +117,7 @@ def __len__(self):
else: else:
return int(self.layer.featureCount()) return int(self.layer.featureCount())


return Features(layer) return Features(layer, request)




def uniqueValues(layer, attribute): def uniqueValues(layer, attribute):
Expand Down

0 comments on commit 60d9a60

Please sign in to comment.