digitalhub 0.12.0__py3-none-any.whl → 0.13.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of digitalhub might be problematic. Click here for more details.
- digitalhub/__init__.py +1 -1
- digitalhub/entities/_base/executable/entity.py +105 -57
- digitalhub/entities/_base/material/entity.py +8 -15
- digitalhub/entities/_base/material/utils.py +1 -1
- digitalhub/entities/_processors/context.py +3 -3
- digitalhub/entities/artifact/crud.py +4 -0
- digitalhub/entities/dataitem/crud.py +4 -0
- digitalhub/entities/model/crud.py +4 -0
- digitalhub/entities/project/_base/entity.py +0 -2
- digitalhub/entities/run/_base/entity.py +2 -2
- digitalhub/entities/trigger/_base/entity.py +11 -0
- digitalhub/stores/client/dhcore/client.py +57 -20
- digitalhub/stores/client/dhcore/configurator.py +280 -183
- digitalhub/stores/client/dhcore/enums.py +3 -0
- digitalhub/stores/client/dhcore/utils.py +8 -8
- digitalhub/stores/{configurator → credentials}/api.py +3 -3
- digitalhub/stores/credentials/configurator.py +37 -0
- digitalhub/stores/credentials/enums.py +54 -0
- digitalhub/stores/{configurator/configurator.py → credentials/handler.py} +23 -77
- digitalhub/stores/{configurator → credentials}/ini_module.py +1 -1
- digitalhub/stores/credentials/store.py +49 -0
- digitalhub/stores/data/_base/store.py +19 -6
- digitalhub/stores/data/api.py +37 -1
- digitalhub/stores/data/builder.py +46 -53
- digitalhub/stores/data/local/store.py +4 -7
- digitalhub/stores/data/remote/store.py +4 -7
- digitalhub/stores/data/s3/configurator.py +36 -92
- digitalhub/stores/data/s3/store.py +42 -57
- digitalhub/stores/data/s3/utils.py +1 -1
- digitalhub/stores/data/sql/configurator.py +35 -83
- digitalhub/stores/data/sql/store.py +15 -15
- {digitalhub-0.12.0.dist-info → digitalhub-0.13.0b1.dist-info}/METADATA +1 -1
- {digitalhub-0.12.0.dist-info → digitalhub-0.13.0b1.dist-info}/RECORD +37 -39
- digitalhub/stores/configurator/credentials_store.py +0 -69
- digitalhub/stores/configurator/enums.py +0 -25
- digitalhub/stores/data/s3/enums.py +0 -20
- digitalhub/stores/data/sql/enums.py +0 -20
- digitalhub/stores/data/utils.py +0 -38
- /digitalhub/stores/{configurator → credentials}/__init__.py +0 -0
- {digitalhub-0.12.0.dist-info → digitalhub-0.13.0b1.dist-info}/WHEEL +0 -0
- {digitalhub-0.12.0.dist-info → digitalhub-0.13.0b1.dist-info}/licenses/AUTHORS +0 -0
- {digitalhub-0.12.0.dist-info → digitalhub-0.13.0b1.dist-info}/licenses/LICENSE +0 -0
digitalhub/__init__.py
CHANGED
|
@@ -104,7 +104,7 @@ except ImportError:
|
|
|
104
104
|
# Register entities into registry
|
|
105
105
|
from digitalhub.factory.utils import register_entities, register_runtimes_entities
|
|
106
106
|
from digitalhub.stores.client.dhcore.utils import refresh_token, set_dhcore_env
|
|
107
|
-
from digitalhub.stores.
|
|
107
|
+
from digitalhub.stores.credentials.api import get_current_env, set_current_env
|
|
108
108
|
|
|
109
109
|
register_entities()
|
|
110
110
|
register_runtimes_entities()
|
|
@@ -5,12 +5,14 @@
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
7
|
import typing
|
|
8
|
+
from abc import abstractmethod
|
|
8
9
|
|
|
9
10
|
from digitalhub.entities._base.versioned.entity import VersionedEntity
|
|
10
11
|
from digitalhub.entities._commons.enums import EntityTypes
|
|
11
12
|
from digitalhub.entities._processors.context import context_processor
|
|
12
|
-
from digitalhub.entities.run.crud import
|
|
13
|
-
from digitalhub.entities.task.crud import delete_task
|
|
13
|
+
from digitalhub.entities.run.crud import list_runs
|
|
14
|
+
from digitalhub.entities.task.crud import delete_task, list_tasks
|
|
15
|
+
from digitalhub.entities.trigger.crud import list_triggers
|
|
14
16
|
from digitalhub.factory.factory import factory
|
|
15
17
|
from digitalhub.utils.exceptions import EntityAlreadyExistsError, EntityError
|
|
16
18
|
|
|
@@ -123,13 +125,13 @@ class ExecutableEntity(VersionedEntity):
|
|
|
123
125
|
if task_obj.spec.function == self._get_executable_string():
|
|
124
126
|
self._tasks[task_obj.kind] = task_obj
|
|
125
127
|
|
|
126
|
-
def new_task(self,
|
|
128
|
+
def new_task(self, kind: str, **kwargs) -> Task:
|
|
127
129
|
"""
|
|
128
130
|
Create new task. If the task already exists, update it.
|
|
129
131
|
|
|
130
132
|
Parameters
|
|
131
133
|
----------
|
|
132
|
-
|
|
134
|
+
kind : str
|
|
133
135
|
Kind the object.
|
|
134
136
|
**kwargs : dict
|
|
135
137
|
Keyword arguments.
|
|
@@ -139,21 +141,18 @@ class ExecutableEntity(VersionedEntity):
|
|
|
139
141
|
Task
|
|
140
142
|
New task.
|
|
141
143
|
"""
|
|
142
|
-
self._raise_if_exists(
|
|
143
|
-
|
|
144
|
-
if kwargs is None:
|
|
145
|
-
kwargs = {}
|
|
144
|
+
self._raise_if_exists(kind)
|
|
146
145
|
|
|
147
146
|
# Override kwargs
|
|
148
147
|
kwargs["project"] = self.project
|
|
149
148
|
kwargs[self.ENTITY_TYPE] = self._get_executable_string()
|
|
150
|
-
kwargs["kind"] =
|
|
149
|
+
kwargs["kind"] = kind
|
|
151
150
|
|
|
152
151
|
# Create object instance
|
|
153
152
|
task: Task = factory.build_entity_from_params(**kwargs)
|
|
154
153
|
task.save()
|
|
155
154
|
|
|
156
|
-
self._tasks[
|
|
155
|
+
self._tasks[kind] = task
|
|
157
156
|
return task
|
|
158
157
|
|
|
159
158
|
def get_task(self, kind: str) -> Task:
|
|
@@ -184,6 +183,23 @@ class ExecutableEntity(VersionedEntity):
|
|
|
184
183
|
self._tasks[kind] = resp[0]
|
|
185
184
|
return self._tasks[kind]
|
|
186
185
|
|
|
186
|
+
def list_task(self, **kwargs) -> list[Task]:
|
|
187
|
+
"""
|
|
188
|
+
List tasks.
|
|
189
|
+
|
|
190
|
+
Parameters
|
|
191
|
+
----------
|
|
192
|
+
**kwargs : dict
|
|
193
|
+
Keyword arguments.
|
|
194
|
+
|
|
195
|
+
Returns
|
|
196
|
+
-------
|
|
197
|
+
list
|
|
198
|
+
List of tasks.
|
|
199
|
+
"""
|
|
200
|
+
kwargs["params"] = {self.ENTITY_TYPE: self._get_executable_string()}
|
|
201
|
+
return list_tasks(self.project, **kwargs)
|
|
202
|
+
|
|
187
203
|
def update_task(self, kind: str, **kwargs) -> Task:
|
|
188
204
|
"""
|
|
189
205
|
Update task.
|
|
@@ -202,9 +218,6 @@ class ExecutableEntity(VersionedEntity):
|
|
|
202
218
|
"""
|
|
203
219
|
self._raise_if_not_exists(kind)
|
|
204
220
|
|
|
205
|
-
if kwargs is None:
|
|
206
|
-
kwargs = {}
|
|
207
|
-
|
|
208
221
|
# Update kwargs
|
|
209
222
|
kwargs["project"] = self.project
|
|
210
223
|
kwargs["kind"] = kind
|
|
@@ -319,6 +332,12 @@ class ExecutableEntity(VersionedEntity):
|
|
|
319
332
|
# Runs
|
|
320
333
|
##############################
|
|
321
334
|
|
|
335
|
+
@abstractmethod
|
|
336
|
+
def run(self, *args, **kwargs) -> Run:
|
|
337
|
+
"""
|
|
338
|
+
Create and execute a new run.
|
|
339
|
+
"""
|
|
340
|
+
|
|
322
341
|
def get_run(
|
|
323
342
|
self,
|
|
324
343
|
identifier: str,
|
|
@@ -347,13 +366,14 @@ class ExecutableEntity(VersionedEntity):
|
|
|
347
366
|
Using entity ID:
|
|
348
367
|
>>> obj = executable.get_run("123")
|
|
349
368
|
"""
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
369
|
+
entities = self.list_runs(**kwargs)
|
|
370
|
+
for entity in entities:
|
|
371
|
+
if getattr(entity.spec, self.ENTITY_TYPE) == self._get_executable_string():
|
|
372
|
+
if entity.id == identifier:
|
|
373
|
+
return entity
|
|
374
|
+
if entity.key == identifier:
|
|
375
|
+
return entity
|
|
376
|
+
raise EntityError(f"Run '{identifier}' does not exist or does not belong to this executable.")
|
|
357
377
|
|
|
358
378
|
def list_runs(self, **kwargs) -> list[Run]:
|
|
359
379
|
"""
|
|
@@ -373,47 +393,20 @@ class ExecutableEntity(VersionedEntity):
|
|
|
373
393
|
--------
|
|
374
394
|
>>> objs = executable.list_runs()
|
|
375
395
|
"""
|
|
376
|
-
if kwargs is None:
|
|
377
|
-
kwargs = {}
|
|
378
396
|
kwargs["params"] = {self.ENTITY_TYPE: self._get_executable_string()}
|
|
379
397
|
return list_runs(self.project, **kwargs)
|
|
380
398
|
|
|
381
|
-
def delete_run(
|
|
382
|
-
self,
|
|
383
|
-
identifier: str,
|
|
384
|
-
**kwargs,
|
|
385
|
-
) -> None:
|
|
386
|
-
"""
|
|
387
|
-
Delete run from backend.
|
|
388
|
-
|
|
389
|
-
Parameters
|
|
390
|
-
----------
|
|
391
|
-
identifier : str
|
|
392
|
-
Entity key (store://...) or entity ID.
|
|
393
|
-
**kwargs : dict
|
|
394
|
-
Parameters to pass to the API call.
|
|
395
|
-
|
|
396
|
-
Returns
|
|
397
|
-
-------
|
|
398
|
-
dict
|
|
399
|
-
Response from backend.
|
|
400
|
-
|
|
401
|
-
Examples
|
|
402
|
-
--------
|
|
403
|
-
>>> executable.delete_run("store://my-run-key")
|
|
404
|
-
|
|
405
|
-
"""
|
|
406
|
-
delete_run(
|
|
407
|
-
identifier=identifier,
|
|
408
|
-
project=self.project,
|
|
409
|
-
**kwargs,
|
|
410
|
-
)
|
|
411
|
-
|
|
412
399
|
##############################
|
|
413
400
|
# Trigger
|
|
414
401
|
##############################
|
|
415
402
|
|
|
416
|
-
def trigger(
|
|
403
|
+
def trigger(
|
|
404
|
+
self,
|
|
405
|
+
action: str,
|
|
406
|
+
trigger_kind: str,
|
|
407
|
+
trigger_name: str,
|
|
408
|
+
**kwargs,
|
|
409
|
+
) -> Trigger:
|
|
417
410
|
"""
|
|
418
411
|
Trigger function.
|
|
419
412
|
|
|
@@ -439,9 +432,6 @@ class ExecutableEntity(VersionedEntity):
|
|
|
439
432
|
# Get run validator for building trigger template
|
|
440
433
|
run_kind = factory.get_run_kind(self.kind)
|
|
441
434
|
run_validator: SpecValidator = factory.get_spec_validator(run_kind)
|
|
442
|
-
if kwargs is None:
|
|
443
|
-
kwargs = {}
|
|
444
|
-
|
|
445
435
|
# Override kwargs
|
|
446
436
|
kwargs["project"] = self.project
|
|
447
437
|
kwargs["kind"] = trigger_kind
|
|
@@ -454,3 +444,61 @@ class ExecutableEntity(VersionedEntity):
|
|
|
454
444
|
trigger: Trigger = factory.build_entity_from_params(**kwargs)
|
|
455
445
|
trigger.save()
|
|
456
446
|
return trigger
|
|
447
|
+
|
|
448
|
+
def get_trigger(
|
|
449
|
+
self,
|
|
450
|
+
identifier: str,
|
|
451
|
+
**kwargs,
|
|
452
|
+
) -> Trigger:
|
|
453
|
+
"""
|
|
454
|
+
Get object from backend.
|
|
455
|
+
|
|
456
|
+
Parameters
|
|
457
|
+
----------
|
|
458
|
+
identifier : str
|
|
459
|
+
Entity key (store://...) or entity ID.
|
|
460
|
+
**kwargs : dict
|
|
461
|
+
Parameters to pass to the API call.
|
|
462
|
+
|
|
463
|
+
Returns
|
|
464
|
+
-------
|
|
465
|
+
Trigger
|
|
466
|
+
Object instance.
|
|
467
|
+
|
|
468
|
+
Examples
|
|
469
|
+
--------
|
|
470
|
+
Using entity key:
|
|
471
|
+
>>> obj = executable.get_trigger("store://my-trigger-key")
|
|
472
|
+
|
|
473
|
+
Using entity ID:
|
|
474
|
+
>>> obj = executable.get_trigger("123")
|
|
475
|
+
"""
|
|
476
|
+
entities = self.list_triggers(**kwargs)
|
|
477
|
+
for entity in entities:
|
|
478
|
+
if getattr(entity.spec, self.ENTITY_TYPE) == self._get_executable_string():
|
|
479
|
+
if entity.id == identifier:
|
|
480
|
+
return entity
|
|
481
|
+
if entity.key == identifier:
|
|
482
|
+
return entity
|
|
483
|
+
raise EntityError(f"Trigger '{identifier}' does not exist or does not belong to this executable.")
|
|
484
|
+
|
|
485
|
+
def list_triggers(self, **kwargs) -> list[Trigger]:
|
|
486
|
+
"""
|
|
487
|
+
List all triggers from backend.
|
|
488
|
+
|
|
489
|
+
Parameters
|
|
490
|
+
----------
|
|
491
|
+
**kwargs : dict
|
|
492
|
+
Parameters to pass to the API call.
|
|
493
|
+
|
|
494
|
+
Returns
|
|
495
|
+
-------
|
|
496
|
+
list[Trigger]
|
|
497
|
+
List of object instances.
|
|
498
|
+
|
|
499
|
+
Examples
|
|
500
|
+
--------
|
|
501
|
+
>>> objs = executable.list_triggers()
|
|
502
|
+
"""
|
|
503
|
+
kwargs["params"] = {self.ENTITY_TYPE: self._get_executable_string()}
|
|
504
|
+
return list_triggers(self.project, **kwargs)
|
|
@@ -83,9 +83,8 @@ class MaterialEntity(VersionedEntity):
|
|
|
83
83
|
List of file paths.
|
|
84
84
|
"""
|
|
85
85
|
store = get_store(self.project, self.spec.path)
|
|
86
|
-
paths = self.get_file_paths()
|
|
87
86
|
dst = store._build_temp()
|
|
88
|
-
return store.download(self.spec.path, dst=dst
|
|
87
|
+
return store.download(self.spec.path, dst=dst)
|
|
89
88
|
|
|
90
89
|
def download(
|
|
91
90
|
self,
|
|
@@ -94,10 +93,7 @@ class MaterialEntity(VersionedEntity):
|
|
|
94
93
|
) -> str:
|
|
95
94
|
"""
|
|
96
95
|
This function downloads one or more file from storage on local
|
|
97
|
-
machine.
|
|
98
|
-
It looks inside the object's status for the file(s) path under
|
|
99
|
-
files attribute. If it does not find it, it will try to download
|
|
100
|
-
what it can from spec.path.
|
|
96
|
+
machine from spec.path.
|
|
101
97
|
The files are downloaded into a destination folder. If the destination
|
|
102
98
|
is not specified, it will set by default under the context path
|
|
103
99
|
as '<ctx-root>/<entity_type>', e.g. './dataitem'.
|
|
@@ -115,31 +111,24 @@ class MaterialEntity(VersionedEntity):
|
|
|
115
111
|
Returns
|
|
116
112
|
-------
|
|
117
113
|
str
|
|
118
|
-
|
|
114
|
+
Download path.
|
|
119
115
|
|
|
120
116
|
Examples
|
|
121
117
|
--------
|
|
122
118
|
Download a single file:
|
|
123
119
|
|
|
124
|
-
>>> entity.status.files[0]
|
|
125
|
-
{
|
|
126
|
-
"path ": "data.csv",
|
|
127
|
-
"name ": "data.csv",
|
|
128
|
-
"content_type ": "text/csv;charset=utf-8 "
|
|
129
|
-
}
|
|
130
120
|
>>> path = entity.download()
|
|
131
121
|
>>> print(path)
|
|
132
122
|
dataitem/data.csv
|
|
133
123
|
"""
|
|
134
124
|
store = get_store(self.project, self.spec.path)
|
|
135
|
-
paths = self.get_file_paths()
|
|
136
125
|
|
|
137
126
|
if destination is None:
|
|
138
127
|
dst = self._context().root / self.ENTITY_TYPE
|
|
139
128
|
else:
|
|
140
129
|
dst = Path(destination)
|
|
141
130
|
|
|
142
|
-
return store.download(self.spec.path, dst
|
|
131
|
+
return store.download(self.spec.path, dst, overwrite=overwrite)
|
|
143
132
|
|
|
144
133
|
def upload(self, source: SourcesOrListOfSources) -> None:
|
|
145
134
|
"""
|
|
@@ -193,6 +182,10 @@ class MaterialEntity(VersionedEntity):
|
|
|
193
182
|
-------
|
|
194
183
|
None
|
|
195
184
|
"""
|
|
185
|
+
available = 100 - len(self.status.files)
|
|
186
|
+
if len(files) > available:
|
|
187
|
+
files = files[:available]
|
|
188
|
+
|
|
196
189
|
path_list = self.get_file_paths()
|
|
197
190
|
for f in files:
|
|
198
191
|
if f.get("path") not in path_list:
|
|
@@ -6,7 +6,7 @@ from __future__ import annotations
|
|
|
6
6
|
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
|
|
9
|
-
from digitalhub.stores.data.
|
|
9
|
+
from digitalhub.stores.data.api import get_default_store
|
|
10
10
|
from digitalhub.utils.file_utils import eval_zip_type
|
|
11
11
|
from digitalhub.utils.uri_utils import has_local_scheme
|
|
12
12
|
|
|
@@ -135,7 +135,7 @@ class ContextEntityOperationsProcessor:
|
|
|
135
135
|
msg = None
|
|
136
136
|
except Exception as e:
|
|
137
137
|
uploaded = False
|
|
138
|
-
msg = str(e)
|
|
138
|
+
msg = str(e.args)
|
|
139
139
|
|
|
140
140
|
new_obj.status.message = msg
|
|
141
141
|
|
|
@@ -984,7 +984,7 @@ class ContextEntityOperationsProcessor:
|
|
|
984
984
|
)
|
|
985
985
|
return context.client.read_object(api, **kwargs)
|
|
986
986
|
|
|
987
|
-
def
|
|
987
|
+
def stop_entity(
|
|
988
988
|
self,
|
|
989
989
|
project: str,
|
|
990
990
|
entity_type: str,
|
|
@@ -1019,7 +1019,7 @@ class ContextEntityOperationsProcessor:
|
|
|
1019
1019
|
)
|
|
1020
1020
|
context.client.create_object(api, **kwargs)
|
|
1021
1021
|
|
|
1022
|
-
def
|
|
1022
|
+
def resume_entity(
|
|
1023
1023
|
self,
|
|
1024
1024
|
project: str,
|
|
1025
1025
|
entity_type: str,
|
|
@@ -311,6 +311,7 @@ def delete_artifact(
|
|
|
311
311
|
project: str | None = None,
|
|
312
312
|
entity_id: str | None = None,
|
|
313
313
|
delete_all_versions: bool = False,
|
|
314
|
+
cascade: bool = True,
|
|
314
315
|
**kwargs,
|
|
315
316
|
) -> dict:
|
|
316
317
|
"""
|
|
@@ -326,6 +327,8 @@ def delete_artifact(
|
|
|
326
327
|
Entity ID.
|
|
327
328
|
delete_all_versions : bool
|
|
328
329
|
Delete all versions of the named entity. If True, use entity name instead of entity key as identifier.
|
|
330
|
+
cascade : bool
|
|
331
|
+
Cascade delete.
|
|
329
332
|
**kwargs : dict
|
|
330
333
|
Parameters to pass to the API call.
|
|
331
334
|
|
|
@@ -350,5 +353,6 @@ def delete_artifact(
|
|
|
350
353
|
project=project,
|
|
351
354
|
entity_id=entity_id,
|
|
352
355
|
delete_all_versions=delete_all_versions,
|
|
356
|
+
cascade=cascade,
|
|
353
357
|
**kwargs,
|
|
354
358
|
)
|
|
@@ -329,6 +329,7 @@ def delete_dataitem(
|
|
|
329
329
|
project: str | None = None,
|
|
330
330
|
entity_id: str | None = None,
|
|
331
331
|
delete_all_versions: bool = False,
|
|
332
|
+
cascade: bool = True,
|
|
332
333
|
**kwargs,
|
|
333
334
|
) -> dict:
|
|
334
335
|
"""
|
|
@@ -344,6 +345,8 @@ def delete_dataitem(
|
|
|
344
345
|
Entity ID.
|
|
345
346
|
delete_all_versions : bool
|
|
346
347
|
Delete all versions of the named entity. If True, use entity name instead of entity key as identifier.
|
|
348
|
+
cascade : bool
|
|
349
|
+
Cascade delete.
|
|
347
350
|
**kwargs : dict
|
|
348
351
|
Parameters to pass to the API call.
|
|
349
352
|
|
|
@@ -368,5 +371,6 @@ def delete_dataitem(
|
|
|
368
371
|
project=project,
|
|
369
372
|
entity_id=entity_id,
|
|
370
373
|
delete_all_versions=delete_all_versions,
|
|
374
|
+
cascade=cascade,
|
|
371
375
|
**kwargs,
|
|
372
376
|
)
|
|
@@ -310,6 +310,7 @@ def delete_model(
|
|
|
310
310
|
project: str | None = None,
|
|
311
311
|
entity_id: str | None = None,
|
|
312
312
|
delete_all_versions: bool = False,
|
|
313
|
+
cascade: bool = True,
|
|
313
314
|
**kwargs,
|
|
314
315
|
) -> dict:
|
|
315
316
|
"""
|
|
@@ -325,6 +326,8 @@ def delete_model(
|
|
|
325
326
|
Entity ID.
|
|
326
327
|
delete_all_versions : bool
|
|
327
328
|
Delete all versions of the named entity. If True, use entity name instead of entity key as identifier.
|
|
329
|
+
cascade : bool
|
|
330
|
+
Cascade delete.
|
|
328
331
|
**kwargs : dict
|
|
329
332
|
Parameters to pass to the API call.
|
|
330
333
|
|
|
@@ -349,5 +352,6 @@ def delete_model(
|
|
|
349
352
|
project=project,
|
|
350
353
|
entity_id=entity_id,
|
|
351
354
|
delete_all_versions=delete_all_versions,
|
|
355
|
+
cascade=cascade,
|
|
352
356
|
**kwargs,
|
|
353
357
|
)
|
|
@@ -147,7 +147,7 @@ class Run(UnversionedEntity):
|
|
|
147
147
|
None
|
|
148
148
|
"""
|
|
149
149
|
if not self.spec.local_execution:
|
|
150
|
-
return context_processor.
|
|
150
|
+
return context_processor.stop_entity(self.project, self.ENTITY_TYPE, self.id)
|
|
151
151
|
|
|
152
152
|
def resume(self) -> None:
|
|
153
153
|
"""
|
|
@@ -158,7 +158,7 @@ class Run(UnversionedEntity):
|
|
|
158
158
|
None
|
|
159
159
|
"""
|
|
160
160
|
if not self.spec.local_execution:
|
|
161
|
-
return context_processor.
|
|
161
|
+
return context_processor.resume_entity(self.project, self.ENTITY_TYPE, self.id)
|
|
162
162
|
|
|
163
163
|
def log_metric(
|
|
164
164
|
self,
|
|
@@ -8,6 +8,7 @@ import typing
|
|
|
8
8
|
|
|
9
9
|
from digitalhub.entities._base.versioned.entity import VersionedEntity
|
|
10
10
|
from digitalhub.entities._commons.enums import EntityTypes
|
|
11
|
+
from digitalhub.entities._processors.context import context_processor
|
|
11
12
|
|
|
12
13
|
if typing.TYPE_CHECKING:
|
|
13
14
|
from digitalhub.entities._base.entity.metadata import Metadata
|
|
@@ -36,3 +37,13 @@ class Trigger(VersionedEntity):
|
|
|
36
37
|
super().__init__(project, name, uuid, kind, metadata, spec, status, user)
|
|
37
38
|
self.spec: TriggerSpec
|
|
38
39
|
self.status: TriggerStatus
|
|
40
|
+
|
|
41
|
+
def stop(self) -> None:
|
|
42
|
+
"""
|
|
43
|
+
Stop trigger.
|
|
44
|
+
|
|
45
|
+
Returns
|
|
46
|
+
-------
|
|
47
|
+
None
|
|
48
|
+
"""
|
|
49
|
+
return context_processor.stop_entity(self.project, self.ENTITY_TYPE, self.id)
|
|
@@ -6,6 +6,7 @@ from __future__ import annotations
|
|
|
6
6
|
|
|
7
7
|
import typing
|
|
8
8
|
from typing import Any
|
|
9
|
+
from warnings import warn
|
|
9
10
|
|
|
10
11
|
from requests import request
|
|
11
12
|
from requests.exceptions import JSONDecodeError
|
|
@@ -16,13 +17,19 @@ from digitalhub.stores.client.dhcore.configurator import ClientDHCoreConfigurato
|
|
|
16
17
|
from digitalhub.stores.client.dhcore.error_parser import ErrorParser
|
|
17
18
|
from digitalhub.stores.client.dhcore.key_builder import ClientDHCoreKeyBuilder
|
|
18
19
|
from digitalhub.stores.client.dhcore.params_builder import ClientDHCoreParametersBuilder
|
|
19
|
-
from digitalhub.utils.exceptions import BackendError
|
|
20
|
+
from digitalhub.utils.exceptions import BackendError, ClientError
|
|
20
21
|
from digitalhub.utils.generic_utils import dump_json
|
|
21
22
|
|
|
22
23
|
if typing.TYPE_CHECKING:
|
|
23
24
|
from requests import Response
|
|
24
25
|
|
|
25
26
|
|
|
27
|
+
# API levels that are supported
|
|
28
|
+
MAX_API_LEVEL = 20
|
|
29
|
+
MIN_API_LEVEL = 13
|
|
30
|
+
LIB_VERSION = 13
|
|
31
|
+
|
|
32
|
+
|
|
26
33
|
class ClientDHCore(Client):
|
|
27
34
|
"""
|
|
28
35
|
DHCore client.
|
|
@@ -56,7 +63,6 @@ class ClientDHCore(Client):
|
|
|
56
63
|
|
|
57
64
|
# Client Configurator
|
|
58
65
|
self._configurator = ClientDHCoreConfigurator()
|
|
59
|
-
self._configurator.configure(config)
|
|
60
66
|
|
|
61
67
|
##############################
|
|
62
68
|
# CRUD methods
|
|
@@ -165,9 +171,6 @@ class ClientDHCore(Client):
|
|
|
165
171
|
list[dict]
|
|
166
172
|
Response objects.
|
|
167
173
|
"""
|
|
168
|
-
if kwargs is None:
|
|
169
|
-
kwargs = {}
|
|
170
|
-
|
|
171
174
|
if "params" not in kwargs:
|
|
172
175
|
kwargs["params"] = {}
|
|
173
176
|
|
|
@@ -224,9 +227,6 @@ class ClientDHCore(Client):
|
|
|
224
227
|
list[dict]
|
|
225
228
|
Response objects.
|
|
226
229
|
"""
|
|
227
|
-
if kwargs is None:
|
|
228
|
-
kwargs = {}
|
|
229
|
-
|
|
230
230
|
if "params" not in kwargs:
|
|
231
231
|
kwargs["params"] = {}
|
|
232
232
|
|
|
@@ -281,13 +281,28 @@ class ClientDHCore(Client):
|
|
|
281
281
|
Response object.
|
|
282
282
|
"""
|
|
283
283
|
self._configurator.check_config()
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
284
|
+
url = self._build_url(api)
|
|
285
|
+
full_kwargs = self._configurator.get_auth_parameters(kwargs)
|
|
286
|
+
return self._make_call(call_type, url, **full_kwargs)
|
|
287
|
+
|
|
288
|
+
def _build_url(self, api: str) -> str:
|
|
289
|
+
"""
|
|
290
|
+
Build the url.
|
|
291
|
+
|
|
292
|
+
Parameters
|
|
293
|
+
----------
|
|
294
|
+
api : str
|
|
295
|
+
The api to call.
|
|
296
|
+
|
|
297
|
+
Returns
|
|
298
|
+
-------
|
|
299
|
+
str
|
|
300
|
+
The url.
|
|
301
|
+
"""
|
|
302
|
+
endpoint = self._configurator.get_endpoint()
|
|
303
|
+
return f"{endpoint}/{api.removeprefix('/')}"
|
|
289
304
|
|
|
290
|
-
def _make_call(self, call_type: str, url: str,
|
|
305
|
+
def _make_call(self, call_type: str, url: str, refresh: bool = True, **kwargs) -> dict:
|
|
291
306
|
"""
|
|
292
307
|
Make a call to the DHCore API.
|
|
293
308
|
|
|
@@ -297,6 +312,8 @@ class ClientDHCore(Client):
|
|
|
297
312
|
The type of call to make.
|
|
298
313
|
url : str
|
|
299
314
|
The URL to call.
|
|
315
|
+
refresh : bool
|
|
316
|
+
Whether to refresh the access token.
|
|
300
317
|
**kwargs : dict
|
|
301
318
|
Keyword arguments to pass to the request.
|
|
302
319
|
|
|
@@ -309,17 +326,37 @@ class ClientDHCore(Client):
|
|
|
309
326
|
response = request(call_type, url, timeout=60, **kwargs)
|
|
310
327
|
|
|
311
328
|
# Evaluate DHCore API version
|
|
312
|
-
self.
|
|
329
|
+
self._check_core_version(response)
|
|
313
330
|
|
|
314
|
-
# Handle token refresh
|
|
315
|
-
if response.status_code in [401] and
|
|
316
|
-
self._configurator.get_new_access_token()
|
|
317
|
-
kwargs = self._configurator.
|
|
318
|
-
return self._make_call(call_type, url,
|
|
331
|
+
# Handle token refresh (redo call)
|
|
332
|
+
if (response.status_code in [401]) and (refresh) and self._configurator.refreshable_auth_types():
|
|
333
|
+
self._configurator.get_new_access_token(change_origin=True)
|
|
334
|
+
kwargs = self._configurator.get_auth_parameters(kwargs)
|
|
335
|
+
return self._make_call(call_type, url, refresh=False, **kwargs)
|
|
319
336
|
|
|
320
337
|
self._error_parser.parse(response)
|
|
321
338
|
return self._dictify_response(response)
|
|
322
339
|
|
|
340
|
+
def _check_core_version(self, response: Response) -> None:
|
|
341
|
+
"""
|
|
342
|
+
Raise an exception if DHCore API version is not supported.
|
|
343
|
+
|
|
344
|
+
Parameters
|
|
345
|
+
----------
|
|
346
|
+
response : Response
|
|
347
|
+
The response object.
|
|
348
|
+
|
|
349
|
+
Returns
|
|
350
|
+
-------
|
|
351
|
+
None
|
|
352
|
+
"""
|
|
353
|
+
if "X-Api-Level" in response.headers:
|
|
354
|
+
core_api_level = int(response.headers["X-Api-Level"])
|
|
355
|
+
if not (MIN_API_LEVEL <= core_api_level <= MAX_API_LEVEL):
|
|
356
|
+
raise ClientError("Backend API level not supported.")
|
|
357
|
+
if LIB_VERSION < core_api_level:
|
|
358
|
+
warn("Backend API level is higher than library version. You should consider updating the library.")
|
|
359
|
+
|
|
323
360
|
def _dictify_response(self, response: Response) -> dict:
|
|
324
361
|
"""
|
|
325
362
|
Return dict from response.
|