From 0e363be3c8ec4f6acd287c6f16da993b2960eade Mon Sep 17 00:00:00 2001 From: Christian Beilschmidt Date: Mon, 10 Nov 2025 10:50:10 +0100 Subject: [PATCH 1/2] build: adapt to openapi client update --- geoengine/layers.py | 42 ++++++++++++++------------ geoengine/permissions.py | 18 ++++++++--- geoengine/resource_identifier.py | 8 +++-- geoengine/tasks.py | 21 +++++++------ geoengine/types.py | 4 +-- geoengine/workflow.py | 35 +++++++++++++-------- mypy.ini | 2 +- pyproject.toml | 4 +-- tests/test_auth.py | 3 +- tests/test_data_usage.py | 11 +++++-- tests/test_ml.py | 52 ++++++++++++++++---------------- tests/test_plot.py | 5 +-- tests/test_wfs.py | 14 ++++++--- tests/test_wms.py | 5 +-- tests/util.py | 4 +++ 15 files changed, 137 insertions(+), 91 deletions(-) diff --git a/geoengine/layers.py b/geoengine/layers.py index 4fc13665..eefa71bf 100644 --- a/geoengine/layers.py +++ b/geoengine/layers.py @@ -10,7 +10,6 @@ from enum import auto from io import StringIO from typing import Any, Generic, Literal, TypeVar, cast -from uuid import UUID import geoengine_openapi_client from strenum import LowercaseStrEnum @@ -183,7 +182,7 @@ def parse_listing(response: geoengine_openapi_client.CollectionItem) -> Listing: layer_id_response = cast(geoengine_openapi_client.ProviderLayerId, inner.id) return LayerListing( listing_id=LayerId(layer_id_response.layer_id), - provider_id=LayerProviderId(UUID(layer_id_response.provider_id)), + provider_id=LayerProviderId(layer_id_response.provider_id), name=inner.name, description=inner.description, ) @@ -192,7 +191,7 @@ def parse_listing(response: geoengine_openapi_client.CollectionItem) -> Listing: collection_id_response = cast(geoengine_openapi_client.ProviderLayerCollectionId, inner.id) return LayerCollectionListing( listing_id=LayerCollectionId(collection_id_response.collection_id), - provider_id=LayerProviderId(UUID(collection_id_response.provider_id)), + provider_id=LayerProviderId(collection_id_response.provider_id), name=inner.name, description=inner.description, ) @@ -210,7 +209,7 @@ def parse_listing(response: geoengine_openapi_client.CollectionItem) -> Listing: name=response.name, description=response.description, collection_id=LayerCollectionId(response.id.collection_id), - provider_id=LayerProviderId(UUID(response.id.provider_id)), + provider_id=LayerProviderId(response.id.provider_id), items=items, ) @@ -291,7 +290,8 @@ def add_layer( self, name: str, description: str, - workflow: dict[str, Any] | WorkflowBuilderOperator, # TODO: improve type + # TODO: improve type + workflow: dict[str, Any] | WorkflowBuilderOperator, symbology: Symbology | None, timeout: int = 60, ) -> LayerId: @@ -318,7 +318,8 @@ def add_layer_with_permissions( self, name: str, description: str, - workflow: dict[str, Any] | WorkflowBuilderOperator, # TODO: improve type + # TODO: improve type + workflow: dict[str, Any] | WorkflowBuilderOperator, symbology: Symbology | None, permission_tuples: list[tuple[RoleId, Permission]] | None = None, timeout: int = 60, @@ -397,7 +398,8 @@ def add_existing_collection( collection_id = existing_collection.listing_id elif isinstance(existing_collection, LayerCollection): collection_id = existing_collection.collection_id - elif isinstance(existing_collection, str): # TODO: check for LayerId in Python 3.11+ + # TODO: check for LayerId in Python 3.11+ + elif isinstance(existing_collection, str): collection_id = existing_collection else: raise InputException("Invalid collection type") @@ -446,7 +448,7 @@ def search( with geoengine_openapi_client.ApiClient(session.configuration) as api_client: layers_api = geoengine_openapi_client.LayersApi(api_client) layer_collection_response = layers_api.search_handler( - provider=str(self.provider_id), + provider=self.provider_id, collection=str(self.collection_id), search_string=search_string, search_type=geoengine_openapi_client.SearchType(search_type), @@ -464,7 +466,7 @@ def search( listings.append( LayerCollectionListing( listing_id=LayerCollectionId(inner.id.collection_id), - provider_id=LayerProviderId(UUID(inner.id.provider_id)), + provider_id=LayerProviderId(inner.id.provider_id), name=inner.name, description=inner.description, ) @@ -473,7 +475,7 @@ def search( listings.append( LayerListing( listing_id=LayerId(inner.id.layer_id), - provider_id=LayerProviderId(UUID(inner.id.provider_id)), + provider_id=LayerProviderId(inner.id.provider_id), name=inner.name, description=inner.description, ) @@ -529,7 +531,8 @@ def get_or_create_unique_collection( if isinstance(res, Layer): raise TypeError(f"Found a Layer not a Layer collection for {collection_name}") - return cast(LayerCollection, existing_collections[0].load()) # we know that it is a collection since check that + # we know that it is a collection since check that + return cast(LayerCollection, existing_collections[0].load()) def __eq__(self, other): """Tests if two layer listings are identical""" @@ -594,7 +597,7 @@ def from_response(cls, response: geoengine_openapi_client.Layer) -> Layer: name=response.name, description=response.description, layer_id=LayerId(response.id.layer_id), - provider_id=LayerProviderId(UUID(response.id.provider_id)), + provider_id=LayerProviderId(response.id.provider_id), workflow=response.workflow.to_dict(), symbology=symbology, properties=cast(list[Any], response.properties), @@ -656,7 +659,7 @@ def save_as_dataset(self, timeout: int = 60) -> Task: with geoengine_openapi_client.ApiClient(session.configuration) as api_client: layers_api = geoengine_openapi_client.LayersApi(api_client) - response = layers_api.layer_to_dataset(str(self.provider_id), str(self.layer_id), _request_timeout=timeout) + response = layers_api.layer_to_dataset(self.provider_id, str(self.layer_id), _request_timeout=timeout) return Task(TaskId.from_response(response)) @@ -684,7 +687,7 @@ def as_workflow_id(self, timeout: int = 60) -> WorkflowId: with geoengine_openapi_client.ApiClient(session.configuration) as api_client: layers_api = geoengine_openapi_client.LayersApi(api_client) response = layers_api.layer_to_workflow_id_handler( - str(self.provider_id), self.layer_id, _request_timeout=timeout + self.provider_id, self.layer_id, _request_timeout=timeout ) return WorkflowId.from_response(response) @@ -721,11 +724,12 @@ def layer_collection( page = layers_api.list_root_collections_handler(offset, page_limit, _request_timeout=timeout) else: page = layers_api.list_collection_handler( - str(layer_provider_id), layer_collection_id, offset, page_limit, _request_timeout=timeout + layer_provider_id, layer_collection_id, offset, page_limit, _request_timeout=timeout ) if len(page.items) < page_limit: - if len(pages) == 0 or len(page.items) > 0: # we need at least one page before breaking + # we need at least one page before breaking + if len(pages) == 0 or len(page.items) > 0: pages.append(page) break @@ -744,7 +748,7 @@ def layer(layer_id: LayerId, layer_provider_id: LayerProviderId = LAYER_DB_PROVI with geoengine_openapi_client.ApiClient(session.configuration) as api_client: layers_api = geoengine_openapi_client.LayersApi(api_client) - response = layers_api.layer_handler(str(layer_provider_id), str(layer_id), _request_timeout=timeout) + response = layers_api.layer_handler(layer_provider_id, str(layer_id), _request_timeout=timeout) return Layer.from_response(response) @@ -799,7 +803,7 @@ def _add_layer_collection_to_collection( _request_timeout=timeout, ) - return LayerCollectionId(response.id) + return LayerCollectionId(str(response.id)) def _add_existing_layer_collection_to_collection( @@ -843,7 +847,7 @@ def _add_layer_to_collection( _request_timeout=timeout, ) - return LayerId(response.id) + return LayerId(str(response.id)) def _add_existing_layer_to_collection(layer_id: LayerId, collection_id: LayerCollectionId, timeout: int = 60) -> None: diff --git a/geoengine/permissions.py b/geoengine/permissions.py index 545b0aac..23e0a746 100644 --- a/geoengine/permissions.py +++ b/geoengine/permissions.py @@ -50,6 +50,9 @@ def __str__(self) -> str: def __repr__(self) -> str: return repr(self.__role_id) + def to_dict(self) -> UUID: + return self.__role_id + class Role: """A wrapper for a role""" @@ -124,6 +127,9 @@ def __str__(self) -> str: def __repr__(self) -> str: return repr(self.__user_id) + def to_dict(self) -> UUID: + return self.__user_id + class PermissionListing: """ @@ -230,7 +236,11 @@ def list_permissions(resource: Resource, timeout: int = 60, offset=0, limit=20) with geoengine_openapi_client.ApiClient(session.configuration) as api_client: permission_api = geoengine_openapi_client.PermissionsApi(api_client) res = permission_api.get_resource_permissions_handler( - resource_id=resource.id, resource_type=resource.type, offset=offset, limit=limit, _request_timeout=timeout + resource_id=str(resource.id), + resource_type=resource.type, + offset=offset, + limit=limit, + _request_timeout=timeout, ) return [PermissionListing.from_response(r) for r in res] @@ -259,7 +269,7 @@ def remove_role(role: RoleId, timeout: int = 60): with geoengine_openapi_client.ApiClient(session.configuration) as api_client: user_api = geoengine_openapi_client.UserApi(api_client) - user_api.remove_role_handler(str(role), _request_timeout=timeout) + user_api.remove_role_handler(role.to_dict(), _request_timeout=timeout) def assign_role(role: RoleId, user: UserId, timeout: int = 60): @@ -269,7 +279,7 @@ def assign_role(role: RoleId, user: UserId, timeout: int = 60): with geoengine_openapi_client.ApiClient(session.configuration) as api_client: user_api = geoengine_openapi_client.UserApi(api_client) - user_api.assign_role_handler(str(user), str(role), _request_timeout=timeout) + user_api.assign_role_handler(user.to_dict(), role.to_dict(), _request_timeout=timeout) def revoke_role(role: RoleId, user: UserId, timeout: int = 60): @@ -279,4 +289,4 @@ def revoke_role(role: RoleId, user: UserId, timeout: int = 60): with geoengine_openapi_client.ApiClient(session.configuration) as api_client: user_api = geoengine_openapi_client.UserApi(api_client) - user_api.revoke_role_handler(str(user), str(role), _request_timeout=timeout) + user_api.revoke_role_handler(user.to_dict(), role.to_dict(), _request_timeout=timeout) diff --git a/geoengine/resource_identifier.py b/geoengine/resource_identifier.py index a5b4fe5c..fde688e1 100644 --- a/geoengine/resource_identifier.py +++ b/geoengine/resource_identifier.py @@ -86,7 +86,7 @@ def __init__(self, upload_id: UUID) -> None: @classmethod def from_response(cls, response: geoengine_openapi_client.IdResponse) -> UploadId: """Parse a http response to an `UploadId`""" - return UploadId(UUID(response.id)) + return UploadId(response.id) def __str__(self) -> str: return str(self.__upload_id) @@ -109,11 +109,13 @@ def to_api_dict(self) -> geoengine_openapi_client.IdResponse: class Resource: """A wrapper for a resource id""" - id: str + id: str | UUID type: Literal["dataset", "layer", "layerCollection", "mlModel", "project"] def __init__( - self, resource_type: Literal["dataset", "layer", "layerCollection", "mlModel", "project"], resource_id: str + self, + resource_type: Literal["dataset", "layer", "layerCollection", "mlModel", "project"], + resource_id: str | UUID, ) -> None: """Create a resource id""" self.type = resource_type diff --git a/geoengine/tasks.py b/geoengine/tasks.py index f3300348..6669e7ba 100644 --- a/geoengine/tasks.py +++ b/geoengine/tasks.py @@ -28,7 +28,7 @@ def __init__(self, task_id: UUID) -> None: def from_response(cls, response: geoengine_openapi_client.TaskResponse) -> TaskId: """Parse a http response to an `TaskId`""" - return TaskId(UUID(response.task_id)) + return TaskId(response.task_id) def __eq__(self, other) -> bool: """Checks if two dataset ids are equal""" @@ -43,6 +43,9 @@ def __str__(self) -> str: def __repr__(self) -> str: return repr(self.__task_id) + def to_dict(self) -> UUID: + return self.__task_id + class TaskStatus(Enum): """An enum of task status types""" @@ -260,12 +263,12 @@ def get_status(self, timeout: int = 3600) -> TaskStatusInfo: """ session = get_session() - task_id_str = str(self.__task_id) + task_id = self.__task_id.to_dict() with geoengine_openapi_client.ApiClient(session.configuration) as api_client: tasks_api = geoengine_openapi_client.TasksApi(api_client) - print(task_id_str) - response = tasks_api.status_handler(task_id_str, _request_timeout=timeout) + print(task_id) + response = tasks_api.status_handler(task_id, _request_timeout=timeout) return TaskStatusInfo.from_response(response) @@ -275,11 +278,11 @@ def abort(self, force: bool = False, timeout: int = 3600) -> None: """ session = get_session() - task_id_str = str(self.__task_id) + task_id = self.__task_id.to_dict() with geoengine_openapi_client.ApiClient(session.configuration) as api_client: tasks_api = geoengine_openapi_client.TasksApi(api_client) - tasks_api.abort_handler(task_id_str, None if force is False else True, _request_timeout=timeout) + tasks_api.abort_handler(task_id, None if force is False else True, _request_timeout=timeout) def wait_for_finish( self, check_interval_seconds: float = 5, request_timeout: int = 3600, print_status: bool = True @@ -311,8 +314,8 @@ async def as_future(self, request_interval: int = 5, print_status=False) -> Task Returns a future that will be resolved when the task is finished in the backend. """ - def get_status_inner(tasks_api: geoengine_openapi_client.TasksApi, task_id_str: str, timeout: int = 3600): - return tasks_api.status_handler(task_id_str, _request_timeout=timeout) + def get_status_inner(tasks_api: geoengine_openapi_client.TasksApi, task_id: UUID, timeout: int = 3600): + return tasks_api.status_handler(task_id, _request_timeout=timeout) session = get_session() task_id_str = str(self.__task_id) @@ -346,6 +349,6 @@ def get_task_list(timeout: int = 3600) -> list[tuple[Task, TaskStatusInfo]]: result = [] for item in response: - result.append((Task(TaskId(UUID(item.task_id))), TaskStatusInfo.from_response(item))) + result.append((Task(TaskId(item.task_id)), TaskStatusInfo.from_response(item))) return result diff --git a/geoengine/types.py b/geoengine/types.py index 930c9cf3..d219deda 100644 --- a/geoengine/types.py +++ b/geoengine/types.py @@ -1171,7 +1171,7 @@ def __init__(self, dataset_id: UUID): @classmethod def from_response_internal(cls, response: geoengine_openapi_client.InternalDataId) -> InternalDataId: """Parse an http response to a `InternalDataId` object""" - return InternalDataId(UUID(response.dataset_id)) + return InternalDataId(response.dataset_id) def to_api_dict(self) -> geoengine_openapi_client.DataId: return geoengine_openapi_client.DataId( @@ -1207,7 +1207,7 @@ def __init__(self, provider_id: UUID, layer_id: str): def from_response_external(cls, response: geoengine_openapi_client.ExternalDataId) -> ExternalDataId: """Parse an http response to a `ExternalDataId` object""" - return ExternalDataId(UUID(response.provider_id), response.layer_id) + return ExternalDataId(response.provider_id, response.layer_id) def to_api_dict(self) -> geoengine_openapi_client.DataId: return geoengine_openapi_client.DataId( diff --git a/geoengine/workflow.py b/geoengine/workflow.py index 579b8adb..646ad76f 100644 --- a/geoengine/workflow.py +++ b/geoengine/workflow.py @@ -121,7 +121,7 @@ def from_response(cls, response: geoengine_openapi_client.IdResponse) -> Workflo """ Create a `WorkflowId` from an http response """ - return WorkflowId(UUID(response.id)) + return WorkflowId(response.id) def __str__(self) -> str: return str(self.__workflow_id) @@ -129,6 +129,9 @@ def __str__(self) -> str: def __repr__(self) -> str: return str(self) + def to_dict(self) -> UUID: + return self.__workflow_id + class RasterStreamProcessing: """ @@ -212,7 +215,9 @@ def __query_result_descriptor(self, timeout: int = 60) -> ResultDescriptor: with geoengine_openapi_client.ApiClient(session.configuration) as api_client: workflows_api = geoengine_openapi_client.WorkflowsApi(api_client) - response = workflows_api.get_workflow_metadata_handler(str(self.__workflow_id), _request_timeout=timeout) + response = workflows_api.get_workflow_metadata_handler( + self.__workflow_id.to_dict(), _request_timeout=timeout + ) debug(response) @@ -232,7 +237,7 @@ def workflow_definition(self, timeout: int = 60) -> geoengine_openapi_client.Wor with geoengine_openapi_client.ApiClient(session.configuration) as api_client: workflows_api = geoengine_openapi_client.WorkflowsApi(api_client) - response = workflows_api.load_workflow_handler(str(self.__workflow_id), _request_timeout=timeout) + response = workflows_api.load_workflow_handler(self.__workflow_id.to_dict(), _request_timeout=timeout) return response @@ -251,7 +256,7 @@ def get_dataframe( with geoengine_openapi_client.ApiClient(session.configuration) as api_client: wfs_api = geoengine_openapi_client.OGCWFSApi(api_client) response = wfs_api.wfs_feature_handler( - workflow=str(self.__workflow_id), + workflow=self.__workflow_id.to_dict(), service=geoengine_openapi_client.WfsService(geoengine_openapi_client.WfsService.WFS), request=geoengine_openapi_client.GetFeatureRequest( geoengine_openapi_client.GetFeatureRequest.GETFEATURE @@ -313,7 +318,7 @@ def wms_get_map_as_image(self, bbox: QueryRectangle, raster_colorizer: RasterCol with geoengine_openapi_client.ApiClient(session.configuration) as api_client: wms_api = geoengine_openapi_client.OGCWMSApi(api_client) response = wms_api.wms_map_handler( - workflow=str(self), + workflow=self.__workflow_id.to_dict(), version=geoengine_openapi_client.WmsVersion(geoengine_openapi_client.WmsVersion.ENUM_1_DOT_3_DOT_0), service=geoengine_openapi_client.WmsService(geoengine_openapi_client.WmsService.WMS), request=geoengine_openapi_client.GetMapRequest(geoengine_openapi_client.GetMapRequest.GETMAP), @@ -350,7 +355,7 @@ def plot_json(self, bbox: QueryRectangle, timeout: int = 3600) -> geoengine_open bbox.bbox_str, bbox.time_str, str(bbox.spatial_resolution), - str(self.__workflow_id), + self.__workflow_id.to_dict(), bbox.srs, _request_timeout=timeout, ) @@ -530,7 +535,9 @@ def get_provenance(self, timeout: int = 60) -> list[ProvenanceEntry]: with geoengine_openapi_client.ApiClient(session.configuration) as api_client: workflows_api = geoengine_openapi_client.WorkflowsApi(api_client) - response = workflows_api.get_workflow_provenance_handler(str(self.__workflow_id), _request_timeout=timeout) + response = workflows_api.get_workflow_provenance_handler( + self.__workflow_id.to_dict(), _request_timeout=timeout + ) return [ProvenanceEntry.from_response(item) for item in response] @@ -544,7 +551,7 @@ def metadata_zip(self, path: PathLike | BytesIO, timeout: int = 60) -> None: with geoengine_openapi_client.ApiClient(session.configuration) as api_client: workflows_api = geoengine_openapi_client.WorkflowsApi(api_client) response = workflows_api.get_workflow_all_metadata_zip_handler( - str(self.__workflow_id), _request_timeout=timeout + self.__workflow_id.to_dict(), _request_timeout=timeout ) if isinstance(path, BytesIO): @@ -573,7 +580,7 @@ def save_as_dataset( with geoengine_openapi_client.ApiClient(session.configuration) as api_client: workflows_api = geoengine_openapi_client.WorkflowsApi(api_client) response = workflows_api.dataset_from_workflow_handler( - str(self.__workflow_id), + self.__workflow_id.to_dict(), geoengine_openapi_client.RasterDatasetFromWorkflow( name=name, display_name=display_name, description=description, query=query_rectangle ), @@ -767,7 +774,8 @@ def create_geo_data_frame( data_frame = record_batch.to_pandas() geometry = gpd.GeoSeries.from_wkt(data_frame[api.GEOMETRY_COLUMN_NAME]) - del data_frame[api.GEOMETRY_COLUMN_NAME] # delete the duplicated column + # delete the duplicated column + del data_frame[api.GEOMETRY_COLUMN_NAME] geo_data_frame = gpd.GeoDataFrame( data_frame, @@ -777,7 +785,8 @@ def create_geo_data_frame( # split time column geo_data_frame[[time_start_column, time_end_column]] = geo_data_frame[api.TIME_COLUMN_NAME].tolist() - del geo_data_frame[api.TIME_COLUMN_NAME] # delete the duplicated column + # delete the duplicated column + del geo_data_frame[api.TIME_COLUMN_NAME] # parse time columns for time_column in [time_start_column, time_end_column]: @@ -986,7 +995,7 @@ def get_quota(user_id: UUID | None = None, timeout: int = 60) -> geoengine_opena if user_id is None: return user_api.quota_handler(_request_timeout=timeout) - return user_api.get_user_quota_handler(str(user_id), _request_timeout=timeout) + return user_api.get_user_quota_handler(user_id, _request_timeout=timeout) def update_quota(user_id: UUID, new_available_quota: int, timeout: int = 60) -> None: @@ -999,7 +1008,7 @@ def update_quota(user_id: UUID, new_available_quota: int, timeout: int = 60) -> with geoengine_openapi_client.ApiClient(session.configuration) as api_client: user_api = geoengine_openapi_client.UserApi(api_client) user_api.update_user_quota_handler( - str(user_id), geoengine_openapi_client.UpdateQuota(available=new_available_quota), _request_timeout=timeout + user_id, geoengine_openapi_client.UpdateQuota(available=new_available_quota), _request_timeout=timeout ) diff --git a/mypy.ini b/mypy.ini index b3bd0382..e1376e8c 100644 --- a/mypy.ini +++ b/mypy.ini @@ -1,5 +1,5 @@ [mypy] -plugins = numpy.typing.mypy_plugin, pydantic.mypy +plugins = pydantic.mypy [mypy-geopandas.*] ignore_missing_imports = True diff --git a/pyproject.toml b/pyproject.toml index 6c86b5f7..07cc6d53 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ readme = { file = "README.md", content-type = "text/markdown" } license-files = ["LICENSE"] requires-python = ">=3.10" dependencies = [ - "geoengine-openapi-client == 0.0.26", + "geoengine-openapi-client @ git+https://github.com/geo-engine/openapi-client@openapi-7.17.0#subdirectory=python", # TODO update when merged "geopandas >=1.0,<2.0", "matplotlib >=3.5,<3.11", "numpy >=1.21,<2.4", @@ -27,7 +27,7 @@ dependencies = [ "rasterio >=1.3,<2", "requests >= 2.26,<3", "rioxarray >=0.9.1, <0.20", - "StrEnum >=0.4.6,<0.5", # TODO: use from stdlib when `python_requires = >=3.11` + "StrEnum >=0.4.6,<0.5", # TODO: use from stdlib when `python_requires = >=3.11` "vega >= 3.5,<4.2", "websockets >= 14.2,<16", "xarray >=0.19,<2025.8", diff --git a/tests/test_auth.py b/tests/test_auth.py index 9ee85c2a..d19d2a2b 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -10,6 +10,7 @@ from geoengine.error import GeoEngineException from geoengine.types import QueryRectangle from tests.ge_test import GeoEngineTestInstance +from tests.util import NOT_FOUND_UUID from . import UrllibMocker @@ -27,7 +28,7 @@ def setUp(self) -> None: def test_uninitialized(self): with self.assertRaises(ge.UninitializedException) as exception: - ge.workflow_by_id("foobar").get_dataframe( + ge.workflow_by_id(NOT_FOUND_UUID).get_dataframe( QueryRectangle( ge.BoundingBox2D(-180, -90, 180, 90), ge.TimeInterval(datetime.now()), diff --git a/tests/test_data_usage.py b/tests/test_data_usage.py index c911615b..786f716e 100644 --- a/tests/test_data_usage.py +++ b/tests/test_data_usage.py @@ -1,6 +1,7 @@ """Tests for WMS calls""" import unittest +from uuid import UUID import pandas as pd @@ -58,14 +59,20 @@ def test_data_usage(self): expected = pd.DataFrame( { - "computationId": ["7b08af4a-8793-4299-83c1-39d0c20560f5", "57fba95f-d693-432b-a65b-58ac225a384a"], + "computationId": [ + UUID("7b08af4a-8793-4299-83c1-39d0c20560f5"), + UUID("57fba95f-d693-432b-a65b-58ac225a384a"), + ], "count": [4, 4], "data": ["land_cover", "land_cover"], "timestamp": [ pd.Timestamp("2025-01-09 16:40:22.933000+0000", tz="UTC"), pd.Timestamp("2025-01-09 16:40:10.970000+0000", tz="UTC"), ], - "userId": ["e440bffc-d899-4304-aace-b23fc56828b2", "e440bffc-d899-4304-aace-b23fc56828b2"], + "userId": [ + UUID("e440bffc-d899-4304-aace-b23fc56828b2"), + UUID("e440bffc-d899-4304-aace-b23fc56828b2"), + ], } ) diff --git a/tests/test_ml.py b/tests/test_ml.py index ad8e6597..5a5f39b1 100644 --- a/tests/test_ml.py +++ b/tests/test_ml.py @@ -27,7 +27,7 @@ class MlModelTests(unittest.TestCase): def setUp(self) -> None: ge.reset(False) - def test_model_dim_to_tensorshape(self): + def test_model_dim_to_tensorshape(self) -> None: """Test model_dim_to_tensorshape""" dim_1d: list[TSP.Dimension] = [TSP.Dimension(dim_value=7)] @@ -71,7 +71,7 @@ def test_model_dim_to_tensorshape(self): mts_4d_v = MlTensorShape3D(bands=4, y=512, x=512) self.assertEqual(model_dim_to_tensorshape(dim_4d_v), mts_4d_v) - def test_uploading_onnx_model(self): + def test_uploading_onnx_model(self) -> None: clf = RandomForestClassifier(random_state=42) training_x = np.array([[1, 2], [3, 4]], dtype=np.float32) training_y = np.array([0, 1], dtype=np.int64) @@ -94,14 +94,14 @@ def test_uploading_onnx_model(self): name=model_name, file_name="model.onnx", metadata=MlModelMetadata( - inputType=RasterDataType.F32, - outputType=RasterDataType.I64, - inputShape=MlTensorShape3D(y=1, x=1, bands=2), - outputShape=MlTensorShape3D(y=1, x=1, bands=1), - inputNoDataHandling=MlModelInputNoDataHandling( + input_type=RasterDataType.F32, + output_type=RasterDataType.I64, + input_shape=MlTensorShape3D(y=1, x=1, bands=2), + output_shape=MlTensorShape3D(y=1, x=1, bands=1), + input_no_data_handling=MlModelInputNoDataHandling( variant=MlModelInputNoDataHandlingVariant.SKIPIFNODATA ), - outputNoDataHandling=MlModelOutputNoDataHandling( + output_no_data_handling=MlModelOutputNoDataHandling( variant=MlModelOutputNoDataHandlingVariant.NANISNODATA ), ), @@ -136,14 +136,14 @@ def test_uploading_onnx_model(self): name=model_name, file_name="model.onnx", metadata=MlModelMetadata( - inputType=RasterDataType.F32, - outputType=RasterDataType.I64, - inputShape=MlTensorShape3D(y=1, x=1, bands=4), - outputShape=MlTensorShape3D(y=1, x=1, bands=1), - inputNoDataHandling=MlModelInputNoDataHandling( + input_type=RasterDataType.F32, + output_type=RasterDataType.I64, + input_shape=MlTensorShape3D(y=1, x=1, bands=4), + output_shape=MlTensorShape3D(y=1, x=1, bands=1), + input_no_data_handling=MlModelInputNoDataHandling( variant=MlModelInputNoDataHandlingVariant.SKIPIFNODATA ), - outputNoDataHandling=MlModelOutputNoDataHandling( + output_no_data_handling=MlModelOutputNoDataHandling( variant=MlModelOutputNoDataHandlingVariant.NANISNODATA ), ), @@ -162,14 +162,14 @@ def test_uploading_onnx_model(self): name=model_name, file_name="model.onnx", metadata=MlModelMetadata( - inputType=RasterDataType.F64, - outputType=RasterDataType.I64, - inputShape=MlTensorShape3D(y=1, x=1, bands=2), - outputShape=MlTensorShape3D(y=1, x=1, bands=1), - inputNoDataHandling=MlModelInputNoDataHandling( + input_type=RasterDataType.F64, + output_type=RasterDataType.I64, + input_shape=MlTensorShape3D(y=1, x=1, bands=2), + output_shape=MlTensorShape3D(y=1, x=1, bands=1), + input_no_data_handling=MlModelInputNoDataHandling( variant=MlModelInputNoDataHandlingVariant.SKIPIFNODATA ), - outputNoDataHandling=MlModelOutputNoDataHandling( + output_no_data_handling=MlModelOutputNoDataHandling( variant=MlModelOutputNoDataHandlingVariant.NANISNODATA ), ), @@ -189,14 +189,14 @@ def test_uploading_onnx_model(self): name="foo", file_name="model.onnx", metadata=MlModelMetadata( - inputType=RasterDataType.F32, - outputType=RasterDataType.I32, - inputShape=MlTensorShape3D(y=1, x=1, bands=2), - outputShape=MlTensorShape3D(y=1, x=1, bands=1), - inputNoDataHandling=MlModelInputNoDataHandling( + input_type=RasterDataType.F32, + output_type=RasterDataType.I32, + input_shape=MlTensorShape3D(y=1, x=1, bands=2), + output_shape=MlTensorShape3D(y=1, x=1, bands=1), + input_no_data_handling=MlModelInputNoDataHandling( variant=MlModelInputNoDataHandlingVariant.SKIPIFNODATA ), - outputNoDataHandling=MlModelOutputNoDataHandling( + output_no_data_handling=MlModelOutputNoDataHandling( variant=MlModelOutputNoDataHandlingVariant.NANISNODATA ), ), diff --git a/tests/test_plot.py b/tests/test_plot.py index fe6ab04e..3e498976 100644 --- a/tests/test_plot.py +++ b/tests/test_plot.py @@ -9,6 +9,7 @@ import geoengine as ge from tests.ge_test import GeoEngineTestInstance +from tests.util import NOT_FOUND_UUID from . import UrllibMocker @@ -68,7 +69,7 @@ def test_result_descriptor(self): ) m.get( - "http://mock-instance/workflow/foo/metadata", + f"http://mock-instance/workflow/{NOT_FOUND_UUID}/metadata", status_code=404, json={ "error": "NotFound", @@ -88,7 +89,7 @@ def test_result_descriptor(self): self.assertEqual(repr(result_descriptor), textwrap.dedent(expected_repr)) with self.assertRaises(ge.NotFoundException) as exception: - workflow = ge.workflow_by_id("foo") + workflow = ge.workflow_by_id(NOT_FOUND_UUID) result_descriptor = workflow.get_result_descriptor() diff --git a/tests/test_wfs.py b/tests/test_wfs.py index 6ca649e1..a4ea87d3 100644 --- a/tests/test_wfs.py +++ b/tests/test_wfs.py @@ -4,6 +4,7 @@ import textwrap import unittest from datetime import datetime +from uuid import UUID import geoengine_openapi_client import geopandas as gpd @@ -12,6 +13,7 @@ from shapely.geometry import Point import geoengine as ge +from tests.util import NOT_FOUND_UUID from . import UrllibMocker @@ -425,6 +427,8 @@ def test_wfs_error(self): ) def test_repr(self): + uuid = UUID("5fdf8020-d8d9-4f93-81f5-6554ebe6e216") + with UrllibMocker() as m: m.post( "http://mock-instance/anonymous", @@ -441,7 +445,7 @@ def test_repr(self): ) m.get( - "http://mock-instance/workflow/foobar/metadata", + f"http://mock-instance/workflow/{uuid}/metadata", json={ "type": "vector", "dataType": "MultiPoint", @@ -481,9 +485,9 @@ def test_repr(self): ge.initialize("http://mock-instance") - workflow = ge.workflow_by_id("foobar") + workflow = ge.workflow_by_id(uuid) - self.assertEqual(repr(workflow), "foobar") + self.assertEqual(repr(workflow), str(uuid)) def test_result_descriptor(self): with UrllibMocker() as m: @@ -541,7 +545,7 @@ def test_result_descriptor(self): ) m.get( - "http://mock-instance/workflow/foo/metadata", + f"http://mock-instance/workflow/{NOT_FOUND_UUID}/metadata", status_code=404, json={ "error": "NotFound", @@ -583,7 +587,7 @@ def test_result_descriptor(self): self.assertEqual(repr(result_descriptor), textwrap.dedent(expected_repr)) with self.assertRaises(ge.NotFoundException) as exception: - workflow = ge.workflow_by_id("foo") + workflow = ge.workflow_by_id(NOT_FOUND_UUID) result_descriptor = workflow.get_result_descriptor() diff --git a/tests/test_wms.py b/tests/test_wms.py index 51aa1a84..6211f570 100644 --- a/tests/test_wms.py +++ b/tests/test_wms.py @@ -12,6 +12,7 @@ from geoengine.colorizer import Colorizer from geoengine.types import RasterBandDescriptor, SingleBandRasterColorizer from tests.ge_test import GeoEngineTestInstance +from tests.util import NOT_FOUND_UUID from . import UrllibMocker @@ -191,7 +192,7 @@ def test_result_descriptor(self): ) m.get( - "http://mock-instance/workflow/foo/metadata", + f"http://mock-instance/workflow/{NOT_FOUND_UUID}/metadata", status_code=404, json={ "error": "NotFound", @@ -216,7 +217,7 @@ def test_result_descriptor(self): self.assertEqual(repr(result_descriptor), textwrap.dedent(expected_repr)) with self.assertRaises(ge.NotFoundException) as exception: - workflow = ge.workflow_by_id("foo") + workflow = ge.workflow_by_id(NOT_FOUND_UUID) result_descriptor = workflow.get_result_descriptor() diff --git a/tests/util.py b/tests/util.py index 036d8d26..2049aa20 100644 --- a/tests/util.py +++ b/tests/util.py @@ -5,6 +5,7 @@ from json import dumps, loads from unittest.mock import _patch, patch from urllib.parse import parse_qs +from uuid import UUID import urllib3 @@ -26,6 +27,9 @@ def is_url_match(url1: str, url2: str) -> bool: ) +NOT_FOUND_UUID: UUID = UUID("9d70d443-0f9f-4455-87a7-9ce2d406af07") + + class UrllibMocker: """Mock urllib3 requests""" From 0a82c62b5be6618a0ff255beb55408e54914aa3f Mon Sep 17 00:00:00 2001 From: Christian Beilschmidt Date: Wed, 12 Nov 2025 10:40:13 +0100 Subject: [PATCH 2/2] use published openapi version --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 07cc6d53..aa9a4109 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ readme = { file = "README.md", content-type = "text/markdown" } license-files = ["LICENSE"] requires-python = ">=3.10" dependencies = [ - "geoengine-openapi-client @ git+https://github.com/geo-engine/openapi-client@openapi-7.17.0#subdirectory=python", # TODO update when merged + "geoengine-openapi-client == 0.0.28", "geopandas >=1.0,<2.0", "matplotlib >=3.5,<3.11", "numpy >=1.21,<2.4", @@ -27,7 +27,7 @@ dependencies = [ "rasterio >=1.3,<2", "requests >= 2.26,<3", "rioxarray >=0.9.1, <0.20", - "StrEnum >=0.4.6,<0.5", # TODO: use from stdlib when `python_requires = >=3.11` + "StrEnum >=0.4.6,<0.5", # TODO: use from stdlib when `python_requires = >=3.11` "vega >= 3.5,<4.2", "websockets >= 14.2,<16", "xarray >=0.19,<2025.8",