diff --git a/ORStools/ORStoolsPlugin.py b/ORStools/ORStoolsPlugin.py index 33fa4b5c..2156bf8a 100644 --- a/ORStools/ORStoolsPlugin.py +++ b/ORStools/ORStoolsPlugin.py @@ -33,7 +33,7 @@ import os.path from .gui import ORStoolsDialog -from .proc import provider +from .proc import provider, ENDPOINTS, DEFAULT_SETTINGS class ORStools: @@ -89,19 +89,19 @@ def unload(self) -> None: def add_default_provider_to_settings(self): s = QgsSettings() settings = s.value("ORStools/config") - if not settings: - def_settings = { - "providers": [ - { - "ENV_VARS": { - "ORS_QUOTA": "X-Ratelimit-Limit", - "ORS_REMAINING": "X-Ratelimit-Remaining", - }, - "base_url": "https://api.openrouteservice.org", - "key": "", - "name": "openrouteservice", - "timeout": 60, - } - ] - } - s.setValue("ORStools/config", def_settings) + + settings_keys = ["ENV_VARS", "base_url", "key", "name", "endpoints"] + + # Add any new settings here for backwards compatibility + if settings: + changed = False + for i, prov in enumerate(settings["providers"]): + if any([i not in prov for i in settings_keys]): + changed = True + # Add here, like the endpoints + prov["endpoints"] = ENDPOINTS + settings["providers"][i] = prov + if changed: + s.setValue("ORStools/config", settings) + else: + s.setValue("ORStools/config", DEFAULT_SETTINGS) diff --git a/ORStools/gui/ORStoolsDialogConfig.py b/ORStools/gui/ORStoolsDialogConfig.py index edffcd50..9e5e724c 100644 --- a/ORStools/gui/ORStoolsDialogConfig.py +++ b/ORStools/gui/ORStoolsDialogConfig.py @@ -29,13 +29,19 @@ from qgis.gui import QgsCollapsibleGroupBox -from PyQt5 import QtWidgets +from qgis.PyQt import QtWidgets from qgis.PyQt.QtCore import QMetaObject -from qgis.PyQt.QtWidgets import QDialog, QInputDialog, QLineEdit, QDialogButtonBox +from qgis.PyQt.QtWidgets import ( + QDialog, + QInputDialog, + QLineEdit, + QDialogButtonBox, +) from qgis.PyQt.QtGui import QIntValidator from ORStools.utils import configmanager from .ORStoolsDialogConfigUI import Ui_ORStoolsDialogConfigBase +from ..proc import ENDPOINTS, DEFAULT_SETTINGS class ORStoolsDialogConfigMain(QDialog, Ui_ORStoolsDialogConfigBase): @@ -63,23 +69,55 @@ def __init__(self, parent=None) -> None: self.buttonBox.button(QDialogButtonBox.Ok).setText(self.tr("Save")) def accept(self) -> None: - """When the OK Button is clicked, in-memory temp_config is updated and written to config.yml""" + """When the OK Button is clicked, in-memory temp_config is updated and written to settings""" collapsible_boxes = self.providers.findChildren(QgsCollapsibleGroupBox) + collapsible_boxes = [ + i for i in collapsible_boxes if "_provider_endpoints" not in i.objectName() + ] for idx, box in enumerate(collapsible_boxes): current_provider = self.temp_config["providers"][idx] + current_provider["key"] = box.findChild( QtWidgets.QLineEdit, box.title() + "_key_text" ).text() + current_provider["base_url"] = box.findChild( QtWidgets.QLineEdit, box.title() + "_base_url_text" ).text() + timeout_input = box.findChild(QtWidgets.QLineEdit, box.title() + "_timeout_text") # https://doc.qt.io/qt-5/qvalidator.html#State-enum + if timeout_input.validator().State() != 2: self._adjust_timeout_input(timeout_input) + current_provider["timeout"] = int(timeout_input.text()) + endpoint_box = box.findChild( + QgsCollapsibleGroupBox, f"{box.title()}_provider_endpoints" + ) + current_provider["endpoints"] = { + "directions": endpoint_box.findChild( + QtWidgets.QLineEdit, box.title() + "_directions_endpoint" + ).text(), + "isochrones": endpoint_box.findChild( + QtWidgets.QLineEdit, box.title() + "_isochrones_endpoint" + ).text(), + "matrix": endpoint_box.findChild( + QtWidgets.QLineEdit, box.title() + "_matrix_endpoint" + ).text(), + "optimization": endpoint_box.findChild( + QtWidgets.QLineEdit, box.title() + "_optimization_endpoint" + ).text(), + "export": endpoint_box.findChild( + QtWidgets.QLineEdit, box.title() + "_export_endpoint" + ).text(), + "snapping": endpoint_box.findChild( + QtWidgets.QLineEdit, box.title() + "_snapping_endpoint" + ).text(), + } + configmanager.write_config(self.temp_config) self.close() @@ -109,6 +147,7 @@ def _build_ui(self) -> None: provider_entry["base_url"], provider_entry["key"], provider_entry["timeout"], + provider_entry["endpoints"], new=False, ) @@ -128,7 +167,7 @@ def _add_provider(self) -> None: self, self.tr("New ORS provider"), self.tr("Enter a name for the provider") ) if ok: - self._add_box(provider_name, "http://localhost:8082/ors", "", 60, new=True) + self._add_box(provider_name, "http://localhost:8082/ors", "", 60, ENDPOINTS, new=True) def _remove_provider(self) -> None: """Remove list of providers from list.""" @@ -158,25 +197,15 @@ def _collapse_boxes(self) -> None: for box in collapsible_boxes: box.setCollapsed(True) - def _add_box(self, name: str, url: str, key: str, timeout: int, new: bool = False) -> None: + def _add_box( + self, name: str, url: str, key: str, timeout: int, endpoints: dict, new: bool = False + ) -> None: """ Adds a provider box to the QWidget layout and self.temp_config. - - :param name: provider name - :type name: str - - :param url: provider's base url - :type url: str - - :param key: user's API key - :type key: str - - :param new: Specifies whether user wants to insert provider or the GUI is being built. - :type new: boolean """ if new: self.temp_config["providers"].append( - dict(name=name, base_url=url, key=key, timeout=timeout) + dict(name=name, base_url=url, key=key, timeout=timeout, endpoints=endpoints) ) provider = QgsCollapsibleGroupBox(self.providers) @@ -184,32 +213,87 @@ def _add_box(self, name: str, url: str, key: str, timeout: int, new: bool = Fals provider.setTitle(name) gridLayout_3 = QtWidgets.QGridLayout(provider) gridLayout_3.setObjectName(name + "_grid") + + # API Key section key_label = QtWidgets.QLabel(provider) key_label.setObjectName(name + "_key_label") key_label.setText(self.tr("API Key")) gridLayout_3.addWidget(key_label, 0, 0, 1, 1) + key_text = QtWidgets.QLineEdit(provider) key_text.setObjectName(name + "_key_text") key_text.setText(key) gridLayout_3.addWidget(key_text, 1, 0, 1, 4) + + # Base URL section base_url_label = QtWidgets.QLabel(provider) base_url_label.setObjectName("base_url_label") base_url_label.setText(self.tr("Base URL")) gridLayout_3.addWidget(base_url_label, 2, 0, 1, 1) + base_url_text = QtWidgets.QLineEdit(provider) base_url_text.setObjectName(name + "_base_url_text") base_url_text.setText(url) gridLayout_3.addWidget(base_url_text, 3, 0, 1, 4) + # Timeout section timeout_label = QtWidgets.QLabel(provider) timeout_label.setObjectName("timeout_label") timeout_label.setText(self.tr("Request timeout in seconds (1 - 3600)")) gridLayout_3.addWidget(timeout_label, 4, 0, 1, 1) + timeout_text = QtWidgets.QLineEdit(provider) timeout_text.setObjectName(name + "_timeout_text") timeout_text.setText(str(timeout)) timeout_text.setValidator(QIntValidator(1, 3600, timeout_text)) gridLayout_3.addWidget(timeout_text, 5, 0, 1, 4) + # Service Endpoints section + endpoint_box = QgsCollapsibleGroupBox(provider) + endpoint_box.setObjectName(name + "_provider_endpoints") + endpoint_box.setTitle(self.tr("Service Endpoints")) + endpoint_layout = QtWidgets.QGridLayout(endpoint_box) + gridLayout_3.addWidget(endpoint_box, 6, 0, 1, 4) + + row = 0 + for endpoint_name, endpoint_value in endpoints.items(): + endpoint_label = QtWidgets.QLabel(endpoint_box) + endpoint_label.setText(self.tr(endpoint_name.capitalize())) + endpoint_layout.addWidget(endpoint_label, row, 0, 1, 1) + + endpoint_lineedit = QtWidgets.QLineEdit(endpoint_box) + endpoint_lineedit.setText(endpoint_value) + endpoint_lineedit.setObjectName(f"{name}_{endpoint_name}_endpoint") + + endpoint_layout.addWidget(endpoint_lineedit, row, 1, 1, 3) + + row += 1 + + # Add reset buttons at the bottom + button_layout = QtWidgets.QHBoxLayout() + + reset_url_button = QtWidgets.QPushButton(self.tr("Reset URL"), provider) + reset_url_button.setObjectName(name + "_reset_url_button") + reset_url_button.clicked.connect( + lambda _, t=base_url_text: t.setText(DEFAULT_SETTINGS["providers"][0]["base_url"]) + ) + button_layout.addWidget(reset_url_button) + + reset_endpoints_button = QtWidgets.QPushButton(self.tr("Reset Endpoints"), provider) + reset_endpoints_button.setObjectName(name + "_reset_endpoints_button") + reset_endpoints_button.clicked.connect(self._reset_endpoints) + button_layout.addWidget(reset_endpoints_button) + + gridLayout_3.addLayout(button_layout, 7, 0, 1, 4) + self.verticalLayout.addWidget(provider) provider.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + + def _reset_endpoints(self) -> None: + """Resets the endpoints to their original values.""" + for line_edit_remove in self.providers.findChildren(QLineEdit): + name = line_edit_remove.objectName() + if name.endswith("endpoint"): + endpoint_name = name.split("_")[1] + endpoint_value = ENDPOINTS[endpoint_name] + line_edit_remove.setText(endpoint_value) diff --git a/ORStools/gui/ORStoolsDialogConfigUI.py b/ORStools/gui/ORStoolsDialogConfigUI.py index e6975c98..f42a9bde 100644 --- a/ORStools/gui/ORStoolsDialogConfigUI.py +++ b/ORStools/gui/ORStoolsDialogConfigUI.py @@ -2,16 +2,19 @@ # Form implementation generated from reading ui file 'ORStools/gui/ORStoolsDialogConfigUI.ui' # -# Created by: PyQt5 UI code generator 5.9.2 +# Created by: PyQt5 UI code generator 5.15.10 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic5 is +# run again. Do not edit this file unless you know what you are doing. + from PyQt5 import QtCore, QtGui, QtWidgets + class Ui_ORStoolsDialogConfigBase(object): def setupUi(self, ORStoolsDialogConfigBase): ORStoolsDialogConfigBase.setObjectName("ORStoolsDialogConfigBase") - ORStoolsDialogConfigBase.resize(414, 67) + ORStoolsDialogConfigBase.resize(414, 100) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -20,6 +23,16 @@ def setupUi(self, ORStoolsDialogConfigBase): self.gridLayout = QtWidgets.QGridLayout(ORStoolsDialogConfigBase) self.gridLayout.setSizeConstraint(QtWidgets.QLayout.SetMinAndMaxSize) self.gridLayout.setObjectName("gridLayout") + self.buttonBox = QtWidgets.QDialogButtonBox(ORStoolsDialogConfigBase) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.gridLayout.addWidget(self.buttonBox, 1, 2, 1, 1) + self.provider_add = QtWidgets.QPushButton(ORStoolsDialogConfigBase) + self.provider_add.setObjectName("provider_add") + self.gridLayout.addWidget(self.provider_add, 1, 0, 1, 1) + self.provider_remove = QtWidgets.QPushButton(ORStoolsDialogConfigBase) + self.provider_remove.setObjectName("provider_remove") + self.gridLayout.addWidget(self.provider_remove, 1, 1, 1, 1) self.providers = QtWidgets.QWidget(ORStoolsDialogConfigBase) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) @@ -31,16 +44,6 @@ def setupUi(self, ORStoolsDialogConfigBase): self.verticalLayout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint) self.verticalLayout.setObjectName("verticalLayout") self.gridLayout.addWidget(self.providers, 0, 0, 1, 3) - self.buttonBox = QtWidgets.QDialogButtonBox(ORStoolsDialogConfigBase) - self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) - self.buttonBox.setObjectName("buttonBox") - self.gridLayout.addWidget(self.buttonBox, 1, 2, 1, 1) - self.provider_add = QtWidgets.QPushButton(ORStoolsDialogConfigBase) - self.provider_add.setObjectName("provider_add") - self.gridLayout.addWidget(self.provider_add, 1, 0, 1, 1) - self.provider_remove = QtWidgets.QPushButton(ORStoolsDialogConfigBase) - self.provider_remove.setObjectName("provider_remove") - self.gridLayout.addWidget(self.provider_remove, 1, 1, 1, 1) self.retranslateUi(ORStoolsDialogConfigBase) QtCore.QMetaObject.connectSlotsByName(ORStoolsDialogConfigBase) @@ -50,4 +53,3 @@ def retranslateUi(self, ORStoolsDialogConfigBase): ORStoolsDialogConfigBase.setWindowTitle(_translate("ORStoolsDialogConfigBase", "Provider Settings")) self.provider_add.setText(_translate("ORStoolsDialogConfigBase", "Add")) self.provider_remove.setText(_translate("ORStoolsDialogConfigBase", "Remove")) - diff --git a/ORStools/gui/ORStoolsDialogConfigUI.ui b/ORStools/gui/ORStoolsDialogConfigUI.ui index 4850b501..f3efa28f 100644 --- a/ORStools/gui/ORStoolsDialogConfigUI.ui +++ b/ORStools/gui/ORStoolsDialogConfigUI.ui @@ -7,7 +7,7 @@ 0 0 414 - 67 + 100 @@ -23,25 +23,10 @@ QLayout::SetMinAndMaxSize - - - - - 0 - 0 - - - - - QLayout::SetDefaultConstraint - - - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok + QDialogButtonBox::Ok @@ -59,6 +44,21 @@ + + + + + 0 + 0 + + + + + QLayout::SetDefaultConstraint + + + + diff --git a/ORStools/proc/__init__.py b/ORStools/proc/__init__.py index 1edf9987..87e79c3f 100644 --- a/ORStools/proc/__init__.py +++ b/ORStools/proc/__init__.py @@ -26,3 +26,28 @@ * * ***************************************************************************/ """ + +ENDPOINTS = { + "directions": "directions", + "isochrones": "isochrones", + "matrix": "matrix", + "optimization": "optimization", + "snapping": "snapping", + "export": "export", +} + +DEFAULT_SETTINGS = { + "providers": [ + { + "ENV_VARS": { + "ORS_QUOTA": "X-Ratelimit-Limit", + "ORS_REMAINING": "X-Ratelimit-Remaining", + }, + "base_url": "https://api.openrouteservice.org", + "key": "", + "name": "openrouteservice", + "timeout": 60, + "endpoints": ENDPOINTS, + } + ] +} diff --git a/ORStools/proc/base_processing_algorithm.py b/ORStools/proc/base_processing_algorithm.py index 0cdbb106..f9274f4c 100644 --- a/ORStools/proc/base_processing_algorithm.py +++ b/ORStools/proc/base_processing_algorithm.py @@ -179,6 +179,11 @@ def option_parameters(self) -> [QgsProcessingParameterDefinition]: ), ] + def get_endpoint_names_from_provider(self, provider: str) -> dict: + providers = configmanager.read_config()["providers"] + ors_provider = providers[provider] + return ors_provider["endpoints"] + @classmethod def _get_ors_client_from_provider( cls, provider: str, feedback: QgsProcessingFeedback diff --git a/ORStools/proc/directions_lines_proc.py b/ORStools/proc/directions_lines_proc.py index b0e52e6b..392134bf 100644 --- a/ORStools/proc/directions_lines_proc.py +++ b/ORStools/proc/directions_lines_proc.py @@ -186,7 +186,10 @@ def processAlgorithm( try: if optimization_mode is not None: params = get_params_optimize(line, profile, optimization_mode) - response = ors_client.request("/optimization", {}, post_json=params) + endpoint = self.get_endpoint_names_from_provider(parameters[self.IN_PROVIDER])[ + "optimization" + ] + response = ors_client.request(f"{endpoint}/", {}, post_json=params) sink.addFeature( directions_core.get_output_features_optimization( @@ -221,8 +224,11 @@ def processAlgorithm( params = directions_core.build_default_parameters( preference, point_list=line, options=options, extra_info=extra_info ) + endpoint = self.get_endpoint_names_from_provider(parameters[self.IN_PROVIDER])[ + "directions" + ] response = ors_client.request( - "/v2/directions/" + profile + "/geojson", {}, post_json=params + f"/v2/{endpoint}/{profile}/geojson", {}, post_json=params ) if extra_info: diff --git a/ORStools/proc/directions_points_layer_proc.py b/ORStools/proc/directions_points_layer_proc.py index f3544b08..e17fa1e6 100644 --- a/ORStools/proc/directions_points_layer_proc.py +++ b/ORStools/proc/directions_points_layer_proc.py @@ -228,7 +228,10 @@ def sort(f): ) params = get_params_optimize(points, profile, optimization_mode) - response = ors_client.request("/optimization", {}, post_json=params) + endpoint = self.get_endpoint_names_from_provider(parameters[self.IN_PROVIDER])[ + "optimization" + ] + response = ors_client.request(f"{endpoint}/", {}, post_json=params) sink.addFeature( directions_core.get_output_features_optimization( @@ -263,8 +266,11 @@ def sort(f): params = directions_core.build_default_parameters( preference, point_list=points, options=options, extra_info=extra_info ) + endpoint = self.get_endpoint_names_from_provider(parameters[self.IN_PROVIDER])[ + "directions" + ] response = ors_client.request( - "/v2/directions/" + profile + "/geojson", {}, post_json=params + f"/v2/{endpoint}/{profile}/geojson", {}, post_json=params ) if extra_info: diff --git a/ORStools/proc/directions_points_layers_proc.py b/ORStools/proc/directions_points_layers_proc.py index 8b09e755..b97d323c 100644 --- a/ORStools/proc/directions_points_layers_proc.py +++ b/ORStools/proc/directions_points_layers_proc.py @@ -236,8 +236,11 @@ def sort_end(f): ) try: + endpoint = self.get_endpoint_names_from_provider(parameters[self.IN_PROVIDER])[ + "directions" + ] response = ors_client.request( - "/v2/directions/" + profile + "/geojson", {}, post_json=params + f"/v2/{endpoint}/{profile}/geojson", {}, post_json=params ) except (exceptions.ApiError, exceptions.InvalidKey, exceptions.GenericServerError) as e: msg = f"Route from {values[0]} to {values[1]} caused a {e.__class__.__name__}:\n{str(e)}" diff --git a/ORStools/proc/export_proc.py b/ORStools/proc/export_proc.py index 9d190800..14d6a017 100644 --- a/ORStools/proc/export_proc.py +++ b/ORStools/proc/export_proc.py @@ -108,7 +108,8 @@ def processAlgorithm( # Make request and catch ApiError try: - response = ors_client.request("/v2/export/" + profile, {}, post_json=params) + endpoint = self.get_endpoint_names_from_provider(parameters[self.IN_PROVIDER])["export"] + response = ors_client.request(f"/v2/{endpoint}/{profile}", {}, post_json=params) nodes_dict = {item["nodeId"]: item["location"] for item in response["nodes"]} edges = response["edges"] for edge in edges: diff --git a/ORStools/proc/isochrones_layer_proc.py b/ORStools/proc/isochrones_layer_proc.py index 1284dc20..6db28764 100644 --- a/ORStools/proc/isochrones_layer_proc.py +++ b/ORStools/proc/isochrones_layer_proc.py @@ -194,7 +194,10 @@ def processAlgorithm( # If feature causes error, report and continue with next try: # Populate features from response - response = ors_client.request("/v2/isochrones/" + profile, {}, post_json=params) + endpoint = self.get_endpoint_names_from_provider(parameters[self.IN_PROVIDER])[ + "isochrones" + ] + response = ors_client.request(f"/v2/{endpoint}/{profile}", {}, post_json=params) for isochrone in self.isochrones.get_features(response, params["id"]): sink.addFeature(isochrone) diff --git a/ORStools/proc/isochrones_point_proc.py b/ORStools/proc/isochrones_point_proc.py index 380726a3..331f00b1 100644 --- a/ORStools/proc/isochrones_point_proc.py +++ b/ORStools/proc/isochrones_point_proc.py @@ -151,7 +151,10 @@ def processAlgorithm( ) try: - response = ors_client.request("/v2/isochrones/" + profile, {}, post_json=params) + endpoint = self.get_endpoint_names_from_provider(parameters[self.IN_PROVIDER])[ + "isochrones" + ] + response = ors_client.request(f"/v2/{endpoint}/{profile}", {}, post_json=params) # Populate features from response for isochrone in self.isochrones.get_features(response, params["id"]): diff --git a/ORStools/proc/matrix_proc.py b/ORStools/proc/matrix_proc.py index fdc52e61..b3fbff78 100644 --- a/ORStools/proc/matrix_proc.py +++ b/ORStools/proc/matrix_proc.py @@ -175,7 +175,8 @@ def processAlgorithm( # Make request and catch ApiError try: - response = ors_client.request("/v2/matrix/" + profile, {}, post_json=params) + endpoint = self.get_endpoint_names_from_provider(parameters[self.IN_PROVIDER])["matrix"] + response = ors_client.request(f"/v2/{endpoint}/{profile}", {}, post_json=params) except (exceptions.ApiError, exceptions.InvalidKey, exceptions.GenericServerError) as e: msg = f"{e.__class__.__name__}: {str(e)}" diff --git a/tests/test_gui.py b/tests/test_gui.py index d59d4fde..cfce0d7b 100644 --- a/tests/test_gui.py +++ b/tests/test_gui.py @@ -1,3 +1,6 @@ +from qgis.PyQt.QtWidgets import QLineEdit +from qgis._core import QgsSettings +from qgis.gui import QgsCollapsibleGroupBox from qgis.testing import unittest from qgis.PyQt.QtTest import QTest @@ -10,6 +13,7 @@ ) import pytest +from .test_proc import TestProc from tests.utils.utilities import get_qgis_app CANVAS: QgsMapCanvas @@ -20,6 +24,7 @@ class TestGui(unittest.TestCase): def test_without_live_preview(self): from ORStools.gui.ORStoolsDialog import ORStoolsDialog + from ORStools.gui.ORStoolsDialogConfig import ORStoolsDialogConfigMain from ORStools.utils import maptools CRS = QgsCoordinateReferenceSystem.fromEpsgId(3857) @@ -30,6 +35,13 @@ def test_without_live_preview(self): self.assertEqual(CANVAS.width(), 600) self.assertEqual(CANVAS.height(), 400) + # Set and reset config to test whether the reset works + dlg_config = ORStoolsDialogConfigMain() + provider = dlg_config.providers.findChildren(QgsCollapsibleGroupBox)[0] + + line_edit = provider.findChild(QLineEdit, "openrouteservice_directions_endpoint") + line_edit.setText("thisisnotanendpoint") + dlg = ORStoolsDialog(IFACE) dlg.open() self.assertTrue(dlg.isVisible()) @@ -245,3 +257,104 @@ def map_dclick(self, x, y, side): side, Qt.NoModifier, ) + + def test_ORStoolsDialogConfig_endpoints(self): + from ORStools.gui.ORStoolsDialogConfig import ORStoolsDialogConfigMain + + CRS = QgsCoordinateReferenceSystem.fromEpsgId(3857) + CANVAS.setExtent(QgsRectangle(258889, 7430342, 509995, 7661955)) + CANVAS.setDestinationCrs(CRS) + CANVAS.setFrameStyle(0) + CANVAS.resize(600, 400) + self.assertEqual(CANVAS.width(), 600) + self.assertEqual(CANVAS.height(), 400) + + # Set and reset config to test whether the reset works + dlg_config = ORStoolsDialogConfigMain() + provider = dlg_config.providers.findChildren(QgsCollapsibleGroupBox)[0] + + # set endpoint of directions to non-existent value + line_edit = provider.findChild(QLineEdit, "openrouteservice_directions_endpoint") + line_edit.setText("thisisnotanendpoint") + dlg_config.accept() + + settings_directions_endpoint = QgsSettings().value("ORStools/config")["providers"][0][ + "endpoints" + ]["directions"] + + self.assertEqual(settings_directions_endpoint, "thisisnotanendpoint") + + proc = TestProc() + proc.setUpClass() + + self.assertRaises(StopIteration, proc.test_directions_points_layer) + + # reset endpoints + dlg_config._reset_endpoints() + + dlg_config._reset_endpoints() + dlg_config.accept() + + settings_directions_endpoint = QgsSettings().value("ORStools/config")["providers"][0][ + "endpoints" + ]["directions"] + + self.assertEqual(settings_directions_endpoint, "directions") + + layer = proc.test_directions_points_layer() + + self.assertEqual( + "POINT(8.67251100000000008 49.39887900000000087)", + next(layer.getFeatures()).geometry().asPolyline()[0].asWkt(), + ) + + def test_ORStoolsDialogConfig_url(self): + from ORStools.gui.ORStoolsDialogConfig import ORStoolsDialogConfigMain + + CRS = QgsCoordinateReferenceSystem.fromEpsgId(3857) + CANVAS.setExtent(QgsRectangle(258889, 7430342, 509995, 7661955)) + CANVAS.setDestinationCrs(CRS) + CANVAS.setFrameStyle(0) + CANVAS.resize(600, 400) + self.assertEqual(CANVAS.width(), 600) + self.assertEqual(CANVAS.height(), 400) + + # Set and reset config to test whether the reset works + dlg_config = ORStoolsDialogConfigMain() + provider = dlg_config.providers.findChildren(QgsCollapsibleGroupBox)[0] + + # set endpoint of directions to non-existent value + line_edit = provider.findChild(QLineEdit, "openrouteservice_base_url_text") + line_edit.setText("thisisnotaurl") + dlg_config.accept() + + settings_directions_endpoint = QgsSettings().value("ORStools/config")["providers"][0][ + "base_url" + ] + + self.assertEqual(settings_directions_endpoint, "thisisnotaurl") + + proc = TestProc() + proc.setUpClass() + + self.assertRaises(Exception, proc.test_directions_points_layer) + + # reset url + url_reset_button = dlg_config.findChild(QPushButton, "openrouteservice_reset_url_button") + url_reset_button.clicked.emit() + + dlg_config._reset_endpoints() + dlg_config.accept() + + settings_directions_endpoint = QgsSettings().value("ORStools/config")["providers"][0][ + "endpoints" + ]["directions"] + + self.assertEqual(settings_directions_endpoint, "directions") + + layer = proc.test_directions_points_layer() + + self.assertEqual( + "POINT(8.67251100000000008 49.39887900000000087)", + next(layer.getFeatures()).geometry().asPolyline()[0].asWkt(), + ) diff --git a/tests/test_proc.py b/tests/test_proc.py index 21a2594b..6ec06e0d 100644 --- a/tests/test_proc.py +++ b/tests/test_proc.py @@ -16,7 +16,6 @@ from ORStools.proc.isochrones_layer_proc import ORSIsochronesLayerAlgo from ORStools.proc.isochrones_point_proc import ORSIsochronesPointAlgo from ORStools.proc.matrix_proc import ORSMatrixAlgo -from ORStools.proc.export_proc import ORSExportAlgo class TestProc(unittest.TestCase): @@ -44,7 +43,7 @@ def setUpClass(cls) -> None: feature = QgsFeature() feature.setGeometry(line_geometry) cls.line_layer.dataProvider().addFeature(feature) - + lower_left = QgsPointXY(8.45, 48.85) upper_right = QgsPointXY(8.46, 48.86) cls.bbox = QgsRectangle(lower_left, upper_right) @@ -101,6 +100,8 @@ def test_directions_points_layer(self): feat_length = next(processed_layer.getFeatures()).geometry().length() self.assertTrue(feat_length > 0) + return processed_layer + def test_directions_points_layers(self): parameters = { "INPUT_AVOID_BORDERS": None, @@ -226,4 +227,3 @@ def test_matrix(self): # self.assertTrue(feat_point.hasGeometry()) # feat_line = next(processed_nodes.getFeatures()) # self.assertTrue(feat_line.hasGeometry()) - \ No newline at end of file