Skip to content

Commit 40f799b

Browse files
Merge pull request #214 from geo-engine/dataset_and_ml_model_name_in_res
Dataset_and_ml_model_name_in_res
2 parents 12c8f55 + 957de9c commit 40f799b

File tree

9 files changed

+244
-65
lines changed

9 files changed

+244
-65
lines changed

.github/.backend_git_ref

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
main
1+
main

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ python3 -m mypy tests
137137
Using the config file `mypy.ini`, you can suppress missing stub errors for external libraries.
138138
You can ignore a library by adding two lines to the config file. For example, suppressing matplotlib would look like this:
139139

140-
```
140+
```ini
141141
[mypy-matplotlib.*]
142142
ignore_missing_imports = True
143143

geoengine/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from .layers import Layer, LayerCollection, LayerListing, LayerCollectionListing, \
2020
LayerId, LayerCollectionId, LayerProviderId, \
2121
layer_collection, layer
22-
from .ml import register_ml_model, MlModelConfig
22+
from .ml import register_ml_model, MlModelConfig, MlModelName
2323
from .permissions import add_permission, remove_permission, add_role, remove_role, assign_role, revoke_role, \
2424
ADMIN_ROLE_ID, REGISTERED_USER_ROLE_ID, ANONYMOUS_USER_ROLE_ID, Permission, Resource, UserId, RoleId
2525
from .tasks import Task, TaskId

geoengine/datasets.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ def to_api_enum(self) -> geoengine_openapi_client.OgrSourceErrorSpec:
257257

258258

259259
class DatasetName:
260-
'''A wrapper for a dataset id'''
260+
'''A wrapper for a dataset name'''
261261

262262
__dataset_name: str
263263

@@ -266,7 +266,7 @@ def __init__(self, dataset_name: str) -> None:
266266

267267
@classmethod
268268
def from_response(cls, response: geoengine_openapi_client.CreateDatasetHandler200Response) -> DatasetName:
269-
'''Parse a http response to an `DatasetId`'''
269+
'''Parse a http response to an `DatasetName`'''
270270
return DatasetName(response.dataset_name)
271271

272272
def __str__(self) -> str:
@@ -276,7 +276,7 @@ def __repr__(self) -> str:
276276
return str(self)
277277

278278
def __eq__(self, other) -> bool:
279-
'''Checks if two dataset ids are equal'''
279+
'''Checks if two dataset names are equal'''
280280
if not isinstance(other, self.__class__):
281281
return False
282282

geoengine/ml.py

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
Util functions for machine learning
33
'''
44

5+
from __future__ import annotations
56
from pathlib import Path
67
import tempfile
78
from dataclasses import dataclass
9+
import geoengine_openapi_client.models
810
from onnx import TypeProto, TensorProto, ModelProto
911
from onnx.helper import tensor_dtype_to_string
1012
from geoengine_openapi_client.models import MlModelMetadata, MlModel, RasterDataType
@@ -23,10 +25,42 @@ class MlModelConfig:
2325
description: str = "My Ml Model Description"
2426

2527

28+
class MlModelName:
29+
'''A wrapper for an MlModel name'''
30+
31+
__ml_model_name: str
32+
33+
def __init__(self, ml_model_name: str) -> None:
34+
self.__ml_model_name = ml_model_name
35+
36+
@classmethod
37+
def from_response(cls, response: geoengine_openapi_client.models.MlModelNameResponse) -> MlModelName:
38+
'''Parse a http response to an `DatasetName`'''
39+
return MlModelName(response.ml_model_name)
40+
41+
def __str__(self) -> str:
42+
return self.__ml_model_name
43+
44+
def __repr__(self) -> str:
45+
return str(self)
46+
47+
def __eq__(self, other) -> bool:
48+
'''Checks if two dataset names are equal'''
49+
if not isinstance(other, self.__class__):
50+
return False
51+
52+
return self.__ml_model_name == other.__ml_model_name # pylint: disable=protected-access
53+
54+
def to_api_dict(self) -> geoengine_openapi_client.models.MlModelNameResponse:
55+
return geoengine_openapi_client.models.MlModelNameResponse(
56+
ml_model_name=str(self.__ml_model_name)
57+
)
58+
59+
2660
def register_ml_model(onnx_model: ModelProto,
2761
model_config: MlModelConfig,
2862
upload_timeout: int = 3600,
29-
register_timeout: int = 60):
63+
register_timeout: int = 60) -> MlModelName:
3064
'''Uploads an onnx file and registers it as an ml model'''
3165

3266
validate_model_config(
@@ -55,7 +89,8 @@ def register_ml_model(onnx_model: ModelProto,
5589

5690
model = MlModel(name=model_config.name, upload=str(upload_id), metadata=model_config.metadata,
5791
display_name=model_config.display_name, description=model_config.description)
58-
ml_api.add_ml_model(model, _request_timeout=register_timeout)
92+
res_name = ml_api.add_ml_model(model, _request_timeout=register_timeout)
93+
return MlModelName.from_response(res_name)
5994

6095

6196
def validate_model_config(onnx_model: ModelProto, *,

geoengine/permissions.py

Lines changed: 162 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,24 @@
66
from enum import Enum
77

88
import ast
9-
from typing import Dict, Literal, Any
9+
from typing import Dict, List, Literal, Any, Union
1010
from uuid import UUID
1111

1212
import geoengine_openapi_client
13+
import geoengine_openapi_client.api
14+
import geoengine_openapi_client.models
15+
import geoengine_openapi_client.models.role
1316

1417
from geoengine.auth import get_session
1518
from geoengine.datasets import DatasetName
1619
from geoengine.error import GeoEngineException
1720
from geoengine.layers import LayerCollectionId, LayerId
21+
from geoengine.ml import MlModelName
1822

1923

2024
class RoleId:
2125
'''A wrapper for a role id'''
26+
__role_id: UUID
2227

2328
def __init__(self, role_id: UUID) -> None:
2429
self.__role_id = role_id
@@ -48,6 +53,48 @@ def __repr__(self) -> str:
4853
return repr(self.__role_id)
4954

5055

56+
class Role:
57+
'''A wrapper for a role'''
58+
name: str
59+
id: RoleId
60+
61+
def __init__(self, role_id: Union[UUID, RoleId, str], role_name: str):
62+
''' Create a role with name and id '''
63+
64+
if isinstance(role_id, UUID):
65+
real_id = RoleId(role_id)
66+
elif isinstance(role_id, str):
67+
real_id = RoleId(UUID(role_id))
68+
else:
69+
real_id = role_id
70+
71+
self.id = real_id
72+
self.name = role_name
73+
74+
@classmethod
75+
def from_response(cls, response: geoengine_openapi_client.models.role.Role) -> Role:
76+
'''Parse a http response to an `RoleId`'''
77+
78+
role_id = response.id
79+
role_name = response.name
80+
81+
return Role(role_id, role_name)
82+
83+
def __eq__(self, other) -> bool:
84+
'''Checks if two role ids are equal'''
85+
if not isinstance(other, self.__class__):
86+
return False
87+
88+
return self.id == other.id and self.name == other.name
89+
90+
def role_id(self) -> RoleId:
91+
'''get the role id'''
92+
return self.id
93+
94+
def __repr__(self) -> str:
95+
return 'id: ' + repr(self.id) + ', name: ' + repr(self.name)
96+
97+
5198
class UserId:
5299
'''A wrapper for a role id'''
53100

@@ -82,11 +129,14 @@ def __repr__(self) -> str:
82129
class Resource:
83130
'''A wrapper for a resource id'''
84131

85-
def __init__(self, resource_type: Literal['dataset', 'layer', 'layerCollection'],
132+
id: str
133+
type: Literal['dataset', 'layer', 'layerCollection', 'mlModel', 'project']
134+
135+
def __init__(self, resource_type: Literal['dataset', 'layer', 'layerCollection', 'mlModel', 'project'],
86136
resource_id: str) -> None:
87137
'''Create a resource id'''
88-
self.__type = resource_type
89-
self.__id = resource_id
138+
self.type = resource_type
139+
self.id = resource_id
90140

91141
@classmethod
92142
def from_layer_id(cls, layer_id: LayerId) -> Resource:
@@ -99,25 +149,100 @@ def from_layer_collection_id(cls, layer_collection_id: LayerCollectionId) -> Res
99149
return Resource('layerCollection', str(layer_collection_id))
100150

101151
@classmethod
102-
def from_dataset_name(cls, dataset_name: DatasetName) -> Resource:
103-
'''Create a resource id from a dataset id'''
104-
return Resource('dataset', str(dataset_name))
152+
def from_dataset_name(cls, dataset_name: Union[DatasetName, str]) -> Resource:
153+
'''Create a resource id from a dataset name'''
154+
if isinstance(dataset_name, DatasetName):
155+
dataset_name = str(dataset_name)
156+
return Resource('dataset', dataset_name)
157+
158+
@classmethod
159+
def from_ml_model_name(cls, ml_model_name: Union[MlModelName, str]) -> Resource:
160+
'''Create a resource from an ml model name'''
161+
if isinstance(ml_model_name, MlModelName):
162+
ml_model_name = str(ml_model_name)
163+
return Resource('mlModel', ml_model_name)
105164

106165
def to_api_dict(self) -> geoengine_openapi_client.Resource:
107166
'''Convert to a dict for the API'''
108167
inner: Any = None
109168

110-
if self.__type == "layer":
111-
inner = geoengine_openapi_client.LayerResource(type="layer", id=self.__id)
112-
elif self.__type == "layerCollection":
113-
inner = geoengine_openapi_client.LayerCollectionResource(type="layerCollection", id=self.__id)
114-
elif self.__type == "project":
115-
inner = geoengine_openapi_client.ProjectResource(type="project", id=self.__id)
116-
elif self.__type == "dataset":
117-
inner = geoengine_openapi_client.DatasetResource(type="dataset", id=self.__id)
169+
if self.type == "layer":
170+
inner = geoengine_openapi_client.LayerResource(type="layer", id=self.id)
171+
elif self.type == "layerCollection":
172+
inner = geoengine_openapi_client.LayerCollectionResource(type="layerCollection", id=self.id)
173+
elif self.type == "project":
174+
inner = geoengine_openapi_client.ProjectResource(type="project", id=self.id)
175+
elif self.type == "dataset":
176+
inner = geoengine_openapi_client.DatasetResource(type="dataset", id=self.id)
177+
elif self.type == "mlModel":
178+
inner = geoengine_openapi_client.MlModelResource(type="mlModel", id=self.id)
179+
else:
180+
raise KeyError(f"Unknown resource type: {self.type}")
118181

119182
return geoengine_openapi_client.Resource(inner)
120183

184+
@classmethod
185+
def from_response(cls, response: geoengine_openapi_client.Resource) -> Resource:
186+
'''Convert to a dict for the API'''
187+
inner: Resource
188+
if isinstance(response.actual_instance, geoengine_openapi_client.LayerResource):
189+
inner = Resource('layer', response.actual_instance.id)
190+
elif isinstance(response.actual_instance, geoengine_openapi_client.LayerCollectionResource):
191+
inner = Resource('layerCollection', response.actual_instance.id)
192+
elif isinstance(response.actual_instance, geoengine_openapi_client.ProjectResource):
193+
inner = Resource('project', response.actual_instance.id)
194+
elif isinstance(response.actual_instance, geoengine_openapi_client.DatasetResource):
195+
inner = Resource('dataset', response.actual_instance.id)
196+
elif isinstance(response.actual_instance, geoengine_openapi_client.MlModelResource):
197+
inner = Resource('mlModel', response.actual_instance.id)
198+
else:
199+
raise KeyError(f"Unknown resource type from API: {response.actual_instance}")
200+
return inner
201+
202+
def __repr__(self):
203+
return 'id: ' + repr(self.id) + ', type: ' + repr(self.type)
204+
205+
def __eq__(self, value):
206+
'''Checks if two listings are equal'''
207+
if not isinstance(value, self.__class__):
208+
return False
209+
return self.id == value.id and self.type == value.type
210+
211+
212+
class PermissionListing:
213+
"""
214+
PermissionListing
215+
"""
216+
permission: Permission
217+
resource: Resource
218+
role: Role
219+
220+
def __init__(self, permission: Permission, resource: Resource, role: Role):
221+
''' Create a PermissionListing '''
222+
self.permission = permission
223+
self.resource = resource
224+
self.role = role
225+
226+
@classmethod
227+
def from_response(cls, response: geoengine_openapi_client.models.PermissionListing) -> PermissionListing:
228+
''' Transforms a response PermissionListing to a PermissionListing '''
229+
return PermissionListing(
230+
permission=Permission.from_response(response.permission),
231+
resource=Resource.from_response(response.resource),
232+
role=Role.from_response(response.role)
233+
)
234+
235+
def __eq__(self, other) -> bool:
236+
'''Checks if two listings are equal'''
237+
if not isinstance(other, self.__class__):
238+
return False
239+
return self.permission == other.permission and self.resource == other.resource and self.role == other.role
240+
241+
def __repr__(self) -> str:
242+
return 'Role: ' + repr(self.role) + ', ' \
243+
+ 'Resource: ' + repr(self.resource) + ', ' \
244+
+ 'Permission: ' + repr(self.permission)
245+
121246

122247
class Permission(str, Enum):
123248
'''A permission'''
@@ -128,6 +253,10 @@ def to_api_dict(self) -> geoengine_openapi_client.Permission:
128253
'''Convert to a dict for the API'''
129254
return geoengine_openapi_client.Permission(self.value)
130255

256+
@classmethod
257+
def from_response(cls, response: geoengine_openapi_client.Permission) -> Permission:
258+
return Permission(response)
259+
131260

132261
ADMIN_ROLE_ID: RoleId = RoleId(UUID("d5328854-6190-4af9-ad69-4e74b0961ac9"))
133262
REGISTERED_USER_ROLE_ID: RoleId = RoleId(UUID("4e8081b6-8aa6-4275-af0c-2fa2da557d28"))
@@ -164,6 +293,24 @@ def remove_permission(role: RoleId, resource: Resource, permission: Permission,
164293
))
165294

166295

296+
def list_permissions(resource: Resource, timeout: int = 60, offset=0, limit=20) -> List[PermissionListing]:
297+
'''Lists the roles and permissions assigned to a ressource'''
298+
299+
session = get_session()
300+
301+
with geoengine_openapi_client.ApiClient(session.configuration) as api_client:
302+
permission_api = geoengine_openapi_client.PermissionsApi(api_client)
303+
res = permission_api.get_resource_permissions_handler(
304+
resource_id=resource.id,
305+
resource_type=resource.type,
306+
offset=offset,
307+
limit=limit,
308+
_request_timeout=timeout
309+
)
310+
311+
return [PermissionListing.from_response(r) for r in res]
312+
313+
167314
def add_role(name: str, timeout: int = 60) -> RoleId:
168315
"""Add a new role. Requires admin role."""
169316

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ package_dir =
1818
packages = find:
1919
python_requires = >=3.9
2020
install_requires =
21-
geoengine-openapi-client == 0.0.18
21+
geoengine-openapi-client == 0.0.19
2222
geopandas >=0.9,<0.15
2323
matplotlib >=3.5,<3.8
2424
numpy >=1.21,<2.1

0 commit comments

Comments
 (0)