Skip to content

Commit

Permalink
Merge pull request #73 from traveltime-dev/2023-01_test-and-fix-metadata
Browse files Browse the repository at this point in the history
test and fix metadata
  • Loading branch information
olivierdalang authored Jan 4, 2023
2 parents 15997ca + 0e3851b commit 7e25536
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 66 deletions.
74 changes: 45 additions & 29 deletions travel_time_platform_plugin/algorithms/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
QgsCoordinateReferenceSystem,
QgsCoordinateTransform,
QgsExpression,
QgsExpressionContext,
QgsLayerMetadata,
QgsMapLayer,
QgsProcessingAlgorithm,
QgsProcessingException,
QgsProcessingOutputLayerDefinition,
QgsProcessingParameterDefinition,
QgsProcessingParameterEnum,
QgsProcessingParameterNumber,
Expand Down Expand Up @@ -140,6 +142,48 @@ def processAlgorithmConfigureParams(self, parameters, context, feedback):

self.params[p.name()] = param

def postProcessAlgorithm(self, context, feedback):
"""Sets the layer metadata"""

if hasattr(self, "sink_id") and self.sink_id is not None:
layer = QgsProcessingUtils.mapLayerFromString(self.sink_id, context)

# Save the metadata
metadata = QgsLayerMetadata()

def serialize(o):
"""Serialize parameters, taking into account QGIS input/output types"""
if isinstance(o, QgsMapLayer):
return o.dataUrl()
elif isinstance(o, QgsProcessingOutputLayerDefinition):
return o.sink.valueAsString(QgsExpressionContext())[0]
else:
feedback.pushWarning(
f"Could not serialize `{repr(o)}`, metadata will likely be incomplete."
)
return str(o)

params_json = json.dumps(self.raw_parameters, default=serialize)
params_readable = "\n".join(
k + ": " + str(v) for k, v in json.loads(params_json).items()
)

metadata.setAbstract(
"This layer was generated using the '{}' algorithm from the TravelTime Platform plugin version {}. The following parameters were used : \n{}".format(
self.displayName(), constants.TTP_VERSION, params_readable
)
)
metadata.setKeywords(
{
"TTP_VERSION": [constants.TTP_VERSION],
"TTP_ALGORITHM": [self.id()],
"TTP_PARAMS": [params_json],
}
)
layer.setMetadata(metadata)

return super().postProcessAlgorithm(context, feedback)

def createInstance(self):
return self.__class__()

Expand Down Expand Up @@ -415,7 +459,7 @@ def processAlgorithmMakeRequest(
return response_data

def postProcessAlgorithm(self, context, feedback):
"""Sets the output layer metadata and field aliases"""
"""Sets the field aliases"""

if hasattr(self, "sink_id") and self.sink_id is not None:
layer = QgsProcessingUtils.mapLayerFromString(self.sink_id, context)
Expand All @@ -428,32 +472,4 @@ def postProcessAlgorithm(self, context, feedback):
continue
layer.setFieldAlias(field_idx, alias)

# Save the metadata
metadata = QgsLayerMetadata()

def serialize(o):
if isinstance(o, QgsMapLayer):
return o.dataUrl()
else:
return None

params_json = json.dumps(self.raw_parameters, default=serialize)
params_readable = "\n".join(
k + ": " + str(v) for k, v in json.loads(params_json).items()
)

metadata.setAbstract(
"This layer was generated using the '{}' algorithm from the TravelTime Platform plugin version {}. The following parameters were used : \n{}".format(
self.displayName(), constants.TTP_VERSION, params_readable
)
)
metadata.setKeywords(
{
"TTP_VERSION": [constants.TTP_VERSION],
"TTP_ALGORITHM": [self.id()],
"TTP_PARAMS": [params_json],
}
)
layer.setMetadata(metadata)

return super().postProcessAlgorithm(context, feedback)
109 changes: 72 additions & 37 deletions travel_time_platform_plugin/tests/tests_algorithms.py
Original file line number Diff line number Diff line change
@@ -1,114 +1,151 @@
import itertools
import json
import random

import processing
from qgis.core import QgsFeature, QgsJsonUtils, QgsProject
from qgis.core import QgsFeature, QgsJsonUtils, QgsProcessingUtils, QgsProject

from ..algorithms.simple import TRANSPORTATION_TYPES, TimeMapSimpleAlgorithm
from ..constants import TTP_VERSION
from ..utils import timezones
from .base import TestCaseBase


class AlgorithmsBasicTest(TestCaseBase):
"""Testing algorithms with basic parameters (mostly default)"""

def _test_algorithm(self, algorithm_name, parameters, expected_result_count):
"""Runs tests on the given algorithm"""

# Run the algorithm
context = processing.createContext()
results = processing.runAndLoadResults(
algorithm_name,
{**parameters}, # copy the dict, as runAndLoadResults alters it (sic !)
context=context,
)

# Get the output layer
output_layer = QgsProcessingUtils.mapLayerFromString(results["OUTPUT"], context)

# self._feedback(20)

# Ensure we got the expected number of features
self.assertEqual(
output_layer.featureCount(),
expected_result_count,
)

# Assert TTP_ALGORITHM metadata
self.assertEquals(
output_layer.metadata().keywords("TTP_ALGORITHM")[0],
algorithm_name,
)

# Assert TTP_PARAMS metadata
self.assertEquals(
json.loads(output_layer.metadata().keywords("TTP_PARAMS")[0]),
parameters,
f"{output_layer.metadata().keywords('TTP_PARAMS')[0]}\n\n\nIS DIFFERNT FROM\n\n\n{parameters}",
)

# Assert TTP_VERSION metadata
self.assertEquals(
output_layer.metadata().keywords("TTP_VERSION")[0],
TTP_VERSION,
)

def test_processing_time_map_simple(self):
input_lyr = self._make_layer(["POINT(-3.1 55.9)"])
results = processing.runAndLoadResults(
self._test_algorithm(
"ttp_v4:time_map_simple",
{
"INPUT_SEARCHES": input_lyr,
"INPUT_SEARCHES": input_lyr.id(),
"INPUT_TIME": self._today_at_noon().isoformat(),
"OUTPUT": "memory:",
},
expected_result_count=1,
)
output_layer = QgsProject.instance().mapLayer(results["OUTPUT"])
self.assertEqual(output_layer.featureCount(), 1)

def test_processing_time_filter_simple(self):
input_lyr_a = self._make_layer(["POINT(0.0 51.5)"], name="a")
input_lyr_b = self._make_layer(
["POINT(0.1 51.5)", "POINT(-0.1 51.5)", "POINT(0.0 51.6)"], name="b"
)
results = processing.runAndLoadResults(
self._test_algorithm(
"ttp_v4:time_filter_simple",
{
"INPUT_SEARCHES": input_lyr_a,
"INPUT_LOCATIONS": input_lyr_b,
"INPUT_SEARCHES": input_lyr_a.id(),
"INPUT_LOCATIONS": input_lyr_b.id(),
"INPUT_TIME": self._today_at_noon().isoformat(),
"INPUT_TRAVEL_TIME": 15,
"OUTPUT": "memory:",
},
expected_result_count=3,
)
output_layer = QgsProject.instance().mapLayer(results["OUTPUT"])
self.assertEqual(output_layer.featureCount(), 3)

def test_processing_routes_simple(self):
input_lyr_a = self._make_layer(["POINT(0.0 51.5)"], name="a")
input_lyr_b = self._make_layer(
["POINT(0.1 51.5)", "POINT(-0.1 51.5)", "POINT(0.0 51.6)"], name="b"
)
results = processing.runAndLoadResults(
self._test_algorithm(
"ttp_v4:routes_simple",
{
"INPUT_SEARCHES": input_lyr_a,
"INPUT_LOCATIONS": input_lyr_b,
"INPUT_SEARCHES": input_lyr_a.id(),
"INPUT_LOCATIONS": input_lyr_b.id(),
"INPUT_TIME": self._today_at_noon().isoformat(),
"OUTPUT": "memory:",
},
expected_result_count=3,
)
output_layer = QgsProject.instance().mapLayer(results["OUTPUT"])
self.assertEqual(output_layer.featureCount(), 3)

def test_processing_time_map(self):
input_lyr_a = self._make_layer(["POINT(0.0 51.5)"])
results = processing.runAndLoadResults(
self._test_algorithm(
"ttp_v4:time_map",
{
"INPUT_DEPARTURE_SEARCHES": input_lyr_a,
"INPUT_DEPARTURE_SEARCHES": input_lyr_a.id(),
"INPUT_DEPARTURE_TIME": self._today_at_noon().isoformat(),
"INPUT_DEPARTURE_TRAVEL_TIME": "900",
"OUTPUT": "memory:",
},
expected_result_count=1,
)
output_layer = QgsProject.instance().mapLayer(results["OUTPUT"])
self.assertEqual(output_layer.featureCount(), 1)

def test_processing_time_filter(self):
input_lyr_a = self._make_layer(["POINT(0.0 51.5)"], name="a")
input_lyr_b = self._make_layer(
["POINT(0.1 51.5)", "POINT(0.2 51.5)", "POINT(0.3 51.5)"], name="b"
)
results = processing.runAndLoadResults(
self._test_algorithm(
"ttp_v4:time_filter",
{
"INPUT_DEPARTURE_SEARCHES": input_lyr_a,
"INPUT_DEPARTURE_SEARCHES": input_lyr_a.id(),
"INPUT_DEPARTURE_TIME": self._today_at_noon().isoformat(),
"INPUT_DEPARTURE_TRAVEL_TIME": "900",
"INPUT_LOCATIONS": input_lyr_b,
"INPUT_LOCATIONS": input_lyr_b.id(),
"OUTPUT": "memory:",
},
expected_result_count=3,
)
output_layer = QgsProject.instance().mapLayer(results["OUTPUT"])
self.assertEqual(output_layer.featureCount(), 3)

def test_processing_routes(self):
input_lyr_a = self._make_layer(["POINT(0.0 51.5)"], name="a")
input_lyr_b = self._make_layer(
["POINT(0.1 51.5)", "POINT(-0.1 51.5)", "POINT(0.0 51.6)"], name="b"
)
results = processing.runAndLoadResults(
self._test_algorithm(
"ttp_v4:routes",
{
"INPUT_DEPARTURE_SEARCHES": input_lyr_a,
"INPUT_DEPARTURE_SEARCHES": input_lyr_a.id(),
"INPUT_DEPARTURE_TIME": self._today_at_noon().isoformat(),
"INPUT_DEPARTURE_TRAVEL_TIME": "900",
"INPUT_LOCATIONS": input_lyr_b,
"INPUT_LOCATIONS": input_lyr_b.id(),
"OUTPUT": "memory:",
},
expected_result_count=3,
)
output_layer = QgsProject.instance().mapLayer(results["OUTPUT"])
self.assertEqual(output_layer.featureCount(), 3)

def test_processing_geocoding(self):
input_lyr = self._make_layer(
Expand All @@ -121,30 +158,28 @@ def test_processing_geocoding(self):
feat.setAttribute("place", place)
input_lyr.dataProvider().addFeature(feat)

results = processing.runAndLoadResults(
self._test_algorithm(
"ttp_v4:geocoding",
{
"INPUT_DATA": input_lyr,
"INPUT_DATA": input_lyr.id(),
"INPUT_QUERY_FIELD": '"place"',
"OUTPUT": "memory:",
},
expected_result_count=3,
)
output_layer = QgsProject.instance().mapLayer(results["OUTPUT"])
self.assertEqual(output_layer.featureCount(), 3)

def test_processing_reverse_geocoding(self):
input_lyr = self._make_layer(
["POINT(0.1 51.5)", "POINT(-0.1 51.5)", "POINT(0.0 51.6)"]
)
results = processing.runAndLoadResults(
self._test_algorithm(
"ttp_v4:reverse_geocoding",
{
"INPUT_DATA": input_lyr,
"INPUT_DATA": input_lyr.id(),
"OUTPUT": "memory:",
},
expected_result_count=3,
)
output_layer = QgsProject.instance().mapLayer(results["OUTPUT"])
self.assertEqual(output_layer.featureCount(), 3)


class AlgorithmsFeaturesTest(TestCaseBase):
Expand Down

0 comments on commit 7e25536

Please sign in to comment.