digitalhub 0.13.0b4__py3-none-any.whl → 0.14.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 +3 -8
- digitalhub/entities/_base/_base/entity.py +0 -11
- digitalhub/entities/_base/entity/builder.py +5 -5
- digitalhub/entities/_base/executable/entity.py +1 -1
- digitalhub/entities/_base/runtime_entity/builder.py +53 -18
- digitalhub/entities/_commons/utils.py +64 -21
- digitalhub/entities/_processors/base.py +11 -3
- digitalhub/entities/_processors/context.py +71 -22
- digitalhub/entities/_processors/utils.py +3 -3
- digitalhub/entities/artifact/crud.py +20 -4
- digitalhub/entities/artifact/utils.py +1 -1
- digitalhub/entities/dataitem/crud.py +20 -4
- digitalhub/entities/dataitem/table/entity.py +0 -21
- digitalhub/entities/dataitem/utils.py +1 -1
- digitalhub/entities/function/_base/entity.py +1 -1
- digitalhub/entities/function/crud.py +15 -4
- digitalhub/entities/model/_base/entity.py +21 -1
- digitalhub/entities/model/crud.py +21 -5
- digitalhub/entities/model/utils.py +1 -1
- digitalhub/entities/project/_base/entity.py +65 -33
- digitalhub/entities/project/crud.py +8 -1
- digitalhub/entities/run/_base/entity.py +21 -1
- digitalhub/entities/run/crud.py +22 -5
- digitalhub/entities/secret/crud.py +22 -5
- digitalhub/entities/task/crud.py +22 -5
- digitalhub/entities/trigger/crud.py +20 -4
- digitalhub/entities/workflow/_base/entity.py +1 -1
- digitalhub/entities/workflow/crud.py +15 -4
- digitalhub/factory/enums.py +18 -0
- digitalhub/factory/factory.py +136 -57
- digitalhub/factory/utils.py +3 -54
- digitalhub/stores/client/api.py +6 -10
- digitalhub/stores/client/builder.py +3 -3
- digitalhub/stores/client/dhcore/client.py +105 -163
- digitalhub/stores/client/dhcore/configurator.py +92 -289
- digitalhub/stores/client/dhcore/enums.py +0 -16
- digitalhub/stores/client/dhcore/params_builder.py +41 -83
- digitalhub/stores/client/dhcore/utils.py +14 -22
- digitalhub/stores/client/local/client.py +77 -45
- digitalhub/stores/credentials/ini_module.py +0 -16
- digitalhub/stores/data/local/store.py +0 -103
- digitalhub/stores/data/s3/configurator.py +60 -6
- digitalhub/stores/data/s3/store.py +44 -2
- digitalhub/stores/data/sql/store.py +15 -0
- digitalhub/utils/file_utils.py +0 -17
- digitalhub/utils/generic_utils.py +1 -2
- digitalhub/utils/store_utils.py +44 -0
- {digitalhub-0.13.0b4.dist-info → digitalhub-0.14.0b1.dist-info}/METADATA +3 -2
- {digitalhub-0.13.0b4.dist-info → digitalhub-0.14.0b1.dist-info}/RECORD +58 -59
- digitalhub/entities/task/_base/utils.py +0 -22
- digitalhub/stores/client/dhcore/models.py +0 -40
- digitalhub/stores/data/s3/utils.py +0 -78
- /digitalhub/entities/{_base/entity/_constructors → _constructors}/__init__.py +0 -0
- /digitalhub/entities/{_base/entity/_constructors → _constructors}/metadata.py +0 -0
- /digitalhub/entities/{_base/entity/_constructors → _constructors}/name.py +0 -0
- /digitalhub/entities/{_base/entity/_constructors → _constructors}/spec.py +0 -0
- /digitalhub/entities/{_base/entity/_constructors → _constructors}/status.py +0 -0
- /digitalhub/entities/{_base/entity/_constructors → _constructors}/uuid.py +0 -0
- {digitalhub-0.13.0b4.dist-info → digitalhub-0.14.0b1.dist-info}/WHEEL +0 -0
- {digitalhub-0.13.0b4.dist-info → digitalhub-0.14.0b1.dist-info}/licenses/AUTHORS +0 -0
- {digitalhub-0.13.0b4.dist-info → digitalhub-0.14.0b1.dist-info}/licenses/LICENSE +0 -0
digitalhub/__init__.py
CHANGED
|
@@ -95,16 +95,11 @@ from digitalhub.entities.workflow.crud import (
|
|
|
95
95
|
new_workflow,
|
|
96
96
|
update_workflow,
|
|
97
97
|
)
|
|
98
|
+
from digitalhub.stores.client.dhcore.utils import refresh_token, set_dhcore_env
|
|
99
|
+
from digitalhub.stores.credentials.api import get_current_profile, set_current_profile
|
|
100
|
+
from digitalhub.utils.store_utils import get_s3_client, get_sql_engine
|
|
98
101
|
|
|
99
102
|
try:
|
|
100
103
|
from digitalhub.entities.model.mlflow.utils import from_mlflow_run, get_mlflow_model_metrics
|
|
101
104
|
except ImportError:
|
|
102
105
|
...
|
|
103
|
-
|
|
104
|
-
# Register entities into registry
|
|
105
|
-
from digitalhub.factory.utils import register_entities, register_runtimes_entities
|
|
106
|
-
from digitalhub.stores.client.dhcore.utils import refresh_token, set_dhcore_env
|
|
107
|
-
from digitalhub.stores.credentials.api import get_current_profile, set_current_profile
|
|
108
|
-
|
|
109
|
-
register_entities()
|
|
110
|
-
register_runtimes_entities()
|
|
@@ -63,17 +63,6 @@ class Base:
|
|
|
63
63
|
if k not in self.__dict__:
|
|
64
64
|
setattr(self, k, v)
|
|
65
65
|
|
|
66
|
-
def _get_private_attrs(self) -> dict:
|
|
67
|
-
"""
|
|
68
|
-
Return all private attributes of the object.
|
|
69
|
-
|
|
70
|
-
Returns
|
|
71
|
-
-------
|
|
72
|
-
dict
|
|
73
|
-
A dictionary containing the private attributes of the entity instance.
|
|
74
|
-
"""
|
|
75
|
-
return {k: v for k, v in self.__dict__.items() if k.startswith("_")}
|
|
76
|
-
|
|
77
66
|
def __repr__(self) -> str:
|
|
78
67
|
"""
|
|
79
68
|
Return string representation of the entity object.
|
|
@@ -7,11 +7,11 @@ from __future__ import annotations
|
|
|
7
7
|
import typing
|
|
8
8
|
from abc import abstractmethod
|
|
9
9
|
|
|
10
|
-
from digitalhub.entities.
|
|
11
|
-
from digitalhub.entities.
|
|
12
|
-
from digitalhub.entities.
|
|
13
|
-
from digitalhub.entities.
|
|
14
|
-
from digitalhub.entities.
|
|
10
|
+
from digitalhub.entities._constructors.metadata import build_metadata
|
|
11
|
+
from digitalhub.entities._constructors.name import build_name
|
|
12
|
+
from digitalhub.entities._constructors.spec import build_spec
|
|
13
|
+
from digitalhub.entities._constructors.status import build_status
|
|
14
|
+
from digitalhub.entities._constructors.uuid import build_uuid
|
|
15
15
|
from digitalhub.utils.exceptions import BuilderError
|
|
16
16
|
|
|
17
17
|
if typing.TYPE_CHECKING:
|
|
@@ -430,7 +430,7 @@ class ExecutableEntity(VersionedEntity):
|
|
|
430
430
|
task_string = task._get_task_string()
|
|
431
431
|
|
|
432
432
|
# Get run validator for building trigger template
|
|
433
|
-
run_kind = factory.
|
|
433
|
+
run_kind = factory.get_run_kind_from_action(self.kind, action)
|
|
434
434
|
run_validator: SpecValidator = factory.get_spec_validator(run_kind)
|
|
435
435
|
# Override kwargs
|
|
436
436
|
kwargs["project"] = self.project
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
|
+
from digitalhub.entities._commons.utils import KindAction
|
|
7
8
|
from digitalhub.utils.exceptions import EntityError
|
|
8
9
|
|
|
9
10
|
|
|
@@ -13,16 +14,40 @@ class RuntimeEntityBuilder:
|
|
|
13
14
|
"""
|
|
14
15
|
|
|
15
16
|
EXECUTABLE_KIND: str = None
|
|
16
|
-
TASKS_KINDS:
|
|
17
|
-
|
|
17
|
+
TASKS_KINDS: list[KindAction] = None
|
|
18
|
+
RUN_KINDS: list[KindAction] = None
|
|
18
19
|
|
|
19
20
|
def __init__(self) -> None:
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
self._validate()
|
|
22
|
+
|
|
23
|
+
def _validate(self) -> None:
|
|
24
|
+
"""
|
|
25
|
+
Validate the entity.
|
|
26
|
+
"""
|
|
27
|
+
for attr_name in ["EXECUTABLE_KIND", "TASKS_KINDS", "RUN_KINDS"]:
|
|
28
|
+
value = getattr(self, attr_name)
|
|
29
|
+
if value is None:
|
|
30
|
+
raise EntityError(f"{attr_name} must be set")
|
|
31
|
+
|
|
32
|
+
for attr_name in ["TASKS_KINDS", "RUN_KINDS"]:
|
|
33
|
+
self._instance_validation(getattr(self, attr_name))
|
|
34
|
+
|
|
35
|
+
def _instance_validation(self, attribute: list[KindAction]) -> None:
|
|
36
|
+
"""
|
|
37
|
+
Validate if the attribute is a list of KindAction.
|
|
38
|
+
|
|
39
|
+
Parameters
|
|
40
|
+
----------
|
|
41
|
+
attribute : list[KindAction]
|
|
42
|
+
Attribute to validate.
|
|
43
|
+
"""
|
|
44
|
+
if not isinstance(attribute, list):
|
|
45
|
+
raise EntityError(f"{attribute} must be a list")
|
|
46
|
+
for i in attribute:
|
|
47
|
+
if not isinstance(i, KindAction):
|
|
48
|
+
raise EntityError(f"{attribute} must be a list of KindAction")
|
|
49
|
+
if i.kind is None:
|
|
50
|
+
raise EntityError(f"{attribute} must be a list of KindAction with kind set")
|
|
26
51
|
|
|
27
52
|
def get_action_from_task_kind(self, task_kind: str) -> str:
|
|
28
53
|
"""
|
|
@@ -39,8 +64,8 @@ class RuntimeEntityBuilder:
|
|
|
39
64
|
Action.
|
|
40
65
|
"""
|
|
41
66
|
for task in self.TASKS_KINDS:
|
|
42
|
-
if task
|
|
43
|
-
return task
|
|
67
|
+
if task.kind == task_kind:
|
|
68
|
+
return task.action
|
|
44
69
|
msg = f"Task kind {task_kind} not allowed."
|
|
45
70
|
raise EntityError(msg)
|
|
46
71
|
|
|
@@ -59,21 +84,30 @@ class RuntimeEntityBuilder:
|
|
|
59
84
|
Task kinds.
|
|
60
85
|
"""
|
|
61
86
|
for task in self.TASKS_KINDS:
|
|
62
|
-
if task
|
|
63
|
-
return task
|
|
87
|
+
if task.action == action:
|
|
88
|
+
return task.kind
|
|
64
89
|
msg = f"Action {action} not allowed."
|
|
65
90
|
raise EntityError(msg)
|
|
66
91
|
|
|
67
|
-
def
|
|
92
|
+
def get_run_kind_from_action(self, action: str) -> str:
|
|
68
93
|
"""
|
|
69
|
-
Get run kind.
|
|
94
|
+
Get run kind from action.
|
|
95
|
+
|
|
96
|
+
Parameters
|
|
97
|
+
----------
|
|
98
|
+
action : str
|
|
99
|
+
Action.
|
|
70
100
|
|
|
71
101
|
Returns
|
|
72
102
|
-------
|
|
73
103
|
str
|
|
74
104
|
Run kind.
|
|
75
105
|
"""
|
|
76
|
-
|
|
106
|
+
for run in self.RUN_KINDS:
|
|
107
|
+
if run.action == action:
|
|
108
|
+
return run.kind
|
|
109
|
+
msg = f"Action {action} not allowed."
|
|
110
|
+
raise EntityError(msg)
|
|
77
111
|
|
|
78
112
|
def get_executable_kind(self) -> str:
|
|
79
113
|
"""
|
|
@@ -95,8 +129,9 @@ class RuntimeEntityBuilder:
|
|
|
95
129
|
list[str]
|
|
96
130
|
All kinds.
|
|
97
131
|
"""
|
|
98
|
-
task_kinds = [i
|
|
99
|
-
|
|
132
|
+
task_kinds = [i.kind for i in self.TASKS_KINDS]
|
|
133
|
+
run_kinds = [i.kind for i in self.RUN_KINDS]
|
|
134
|
+
return [self.EXECUTABLE_KIND, *run_kinds, *task_kinds]
|
|
100
135
|
|
|
101
136
|
def get_all_actions(self) -> list[str]:
|
|
102
137
|
"""
|
|
@@ -107,4 +142,4 @@ class RuntimeEntityBuilder:
|
|
|
107
142
|
list[str]
|
|
108
143
|
All actions.
|
|
109
144
|
"""
|
|
110
|
-
return [i
|
|
145
|
+
return [i.action for i in self.TASKS_KINDS]
|
|
@@ -4,8 +4,34 @@
|
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
|
+
import re
|
|
8
|
+
from collections import namedtuple
|
|
9
|
+
|
|
7
10
|
from digitalhub.entities._commons.enums import EntityTypes
|
|
8
11
|
|
|
12
|
+
KindAction = namedtuple("KindAction", ["kind", "action"])
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
KEY_PATTERN_WITH_ID = "store://([^/]+)/([^/]+)/([^/]+)/([^:]+):(.+)"
|
|
16
|
+
KEY_PATTERN_NO_ID = "store://([^/]+)/([^/]+)/([^/]+)/([^:]+)"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def is_valid_key(key: str) -> bool:
|
|
20
|
+
"""
|
|
21
|
+
Check if an entity key is valid.
|
|
22
|
+
|
|
23
|
+
Parameters
|
|
24
|
+
----------
|
|
25
|
+
key : str
|
|
26
|
+
The entity key to validate.
|
|
27
|
+
|
|
28
|
+
Returns
|
|
29
|
+
-------
|
|
30
|
+
bool
|
|
31
|
+
True if the key is valid, False otherwise.
|
|
32
|
+
"""
|
|
33
|
+
return bool(re.fullmatch(KEY_PATTERN_WITH_ID, key) or re.fullmatch(KEY_PATTERN_NO_ID, key))
|
|
34
|
+
|
|
9
35
|
|
|
10
36
|
def parse_entity_key(key: str) -> tuple[str, str, str, str | None, str]:
|
|
11
37
|
"""
|
|
@@ -32,34 +58,34 @@ def parse_entity_key(key: str) -> tuple[str, str, str, str | None, str]:
|
|
|
32
58
|
ValueError
|
|
33
59
|
If the key format is invalid or cannot be parsed.
|
|
34
60
|
"""
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
key = key.replace("store://", "")
|
|
61
|
+
if not is_valid_key(key):
|
|
62
|
+
raise ValueError("Invalid entity key format.")
|
|
38
63
|
|
|
39
|
-
|
|
40
|
-
|
|
64
|
+
# Remove "store://" from the key
|
|
65
|
+
key = key.replace("store://", "")
|
|
41
66
|
|
|
42
|
-
|
|
43
|
-
|
|
67
|
+
# Split the key into parts
|
|
68
|
+
parts = key.split("/")
|
|
44
69
|
|
|
45
|
-
|
|
46
|
-
|
|
70
|
+
# The project is the first part
|
|
71
|
+
project = parts[0]
|
|
47
72
|
|
|
48
|
-
|
|
49
|
-
|
|
73
|
+
# The entity type is the second part
|
|
74
|
+
entity_type = parts[1]
|
|
50
75
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
name = None
|
|
54
|
-
uuid = parts[3]
|
|
76
|
+
# The kind is the third part
|
|
77
|
+
kind = parts[2]
|
|
55
78
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
79
|
+
# Tasks and runs have no name and uuid
|
|
80
|
+
if entity_type in (EntityTypes.TASK.value, EntityTypes.RUN.value):
|
|
81
|
+
name = None
|
|
82
|
+
uuid = parts[3]
|
|
59
83
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
84
|
+
# The name and uuid are separated by a colon in the last part
|
|
85
|
+
else:
|
|
86
|
+
name, uuid = parts[3].split(":")
|
|
87
|
+
|
|
88
|
+
return project, entity_type, kind, name, uuid
|
|
63
89
|
|
|
64
90
|
|
|
65
91
|
def get_entity_type_from_key(key: str) -> str:
|
|
@@ -112,3 +138,20 @@ def get_project_from_key(key: str) -> str:
|
|
|
112
138
|
"""
|
|
113
139
|
project, _, _, _, _ = parse_entity_key(key)
|
|
114
140
|
return project
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def map_actions(kind_action_list: list[tuple[str, str]]) -> list[KindAction]:
|
|
144
|
+
"""
|
|
145
|
+
Build task actions as KindAction namedtuples.
|
|
146
|
+
|
|
147
|
+
Parameters
|
|
148
|
+
----------
|
|
149
|
+
kind_action_list : list[tuple[str, str]]
|
|
150
|
+
List of kind-action couples.
|
|
151
|
+
|
|
152
|
+
Returns
|
|
153
|
+
-------
|
|
154
|
+
list[KindAction]
|
|
155
|
+
Returns the task actions as KindAction namedtuples.
|
|
156
|
+
"""
|
|
157
|
+
return [KindAction(kind, action) for (kind, action) in kind_action_list]
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
7
|
import typing
|
|
8
|
+
from warnings import warn
|
|
8
9
|
|
|
9
10
|
from digitalhub.context.api import delete_context
|
|
10
11
|
from digitalhub.entities._commons.enums import ApiCategories, BackendOperations
|
|
@@ -190,7 +191,7 @@ class BaseEntityOperationsProcessor:
|
|
|
190
191
|
file : str
|
|
191
192
|
Path to the YAML file containing project configuration.
|
|
192
193
|
**kwargs : dict
|
|
193
|
-
Additional parameters including 'local'
|
|
194
|
+
Additional parameters including 'local' and 'reset_id' flags.
|
|
194
195
|
|
|
195
196
|
Returns
|
|
196
197
|
-------
|
|
@@ -207,14 +208,21 @@ class BaseEntityOperationsProcessor:
|
|
|
207
208
|
obj["status"] = {}
|
|
208
209
|
obj["local"] = client.is_local()
|
|
209
210
|
ent: Project = factory.build_entity_from_dict(obj)
|
|
211
|
+
reset_id = kwargs.pop("reset_id", False)
|
|
210
212
|
|
|
211
213
|
try:
|
|
212
214
|
self._create_base_entity(ent._client, ent.ENTITY_TYPE, ent.to_dict())
|
|
213
215
|
except EntityAlreadyExistsError:
|
|
214
|
-
|
|
216
|
+
msg = f"Entity {ent.name} already exists."
|
|
217
|
+
if reset_id:
|
|
218
|
+
ent._import_entities(obj, reset_id=reset_id)
|
|
219
|
+
warn(f"{msg} Other entities ids have been imported.")
|
|
220
|
+
ent.refresh()
|
|
221
|
+
return ent
|
|
222
|
+
raise EntityError(f"{msg} If you want to update it, use load instead.")
|
|
215
223
|
|
|
216
224
|
# Import related entities
|
|
217
|
-
ent._import_entities(obj)
|
|
225
|
+
ent._import_entities(obj, reset_id=reset_id)
|
|
218
226
|
ent.refresh()
|
|
219
227
|
return ent
|
|
220
228
|
|
|
@@ -8,6 +8,8 @@ import typing
|
|
|
8
8
|
from typing import Any
|
|
9
9
|
|
|
10
10
|
from digitalhub.entities._commons.enums import ApiCategories, BackendOperations, Relationship, State
|
|
11
|
+
from digitalhub.entities._commons.utils import is_valid_key
|
|
12
|
+
from digitalhub.entities._constructors.uuid import build_uuid
|
|
11
13
|
from digitalhub.entities._processors.utils import (
|
|
12
14
|
get_context_from_identifier,
|
|
13
15
|
get_context_from_project,
|
|
@@ -319,7 +321,7 @@ class ContextEntityOperationsProcessor:
|
|
|
319
321
|
UnversionedEntity
|
|
320
322
|
The unversioned entity object populated with backend data.
|
|
321
323
|
"""
|
|
322
|
-
if not identifier
|
|
324
|
+
if not is_valid_key(identifier):
|
|
323
325
|
entity_id = identifier
|
|
324
326
|
else:
|
|
325
327
|
splt = identifier.split(":")
|
|
@@ -335,19 +337,25 @@ class ContextEntityOperationsProcessor:
|
|
|
335
337
|
|
|
336
338
|
def import_context_entity(
|
|
337
339
|
self,
|
|
338
|
-
file: str,
|
|
340
|
+
file: str | None = None,
|
|
341
|
+
key: str | None = None,
|
|
342
|
+
reset_id: bool = False,
|
|
343
|
+
context: str | None = None,
|
|
339
344
|
) -> ContextEntity:
|
|
340
345
|
"""
|
|
341
|
-
Import a context entity from a YAML file
|
|
342
|
-
|
|
343
|
-
Reads entity configuration from a YAML file and creates a new
|
|
344
|
-
context entity in the backend. Raises an error if the entity
|
|
345
|
-
already exists.
|
|
346
|
+
Import a context entity from a YAML file or from a storage key.
|
|
346
347
|
|
|
347
348
|
Parameters
|
|
348
349
|
----------
|
|
349
350
|
file : str
|
|
350
351
|
Path to the YAML file containing entity configuration.
|
|
352
|
+
key : str
|
|
353
|
+
Storage key (store://...) to read the entity from.
|
|
354
|
+
reset_id : bool
|
|
355
|
+
Flag to determine if the ID of context entities should be reset.
|
|
356
|
+
context : str, optional
|
|
357
|
+
Project name to use for context resolution. If None, uses
|
|
358
|
+
the project specified in the YAML file.
|
|
351
359
|
|
|
352
360
|
Returns
|
|
353
361
|
-------
|
|
@@ -359,32 +367,54 @@ class ContextEntityOperationsProcessor:
|
|
|
359
367
|
EntityError
|
|
360
368
|
If the entity already exists in the backend.
|
|
361
369
|
"""
|
|
362
|
-
|
|
370
|
+
if (file is None) == (key is None):
|
|
371
|
+
raise ValueError("Provide key or file, not both or none.")
|
|
372
|
+
|
|
373
|
+
if file is not None:
|
|
374
|
+
dict_obj: dict = read_yaml(file)
|
|
375
|
+
else:
|
|
376
|
+
ctx = get_context_from_identifier(key)
|
|
377
|
+
dict_obj: dict = self._read_context_entity(ctx, key)
|
|
378
|
+
|
|
363
379
|
dict_obj["status"] = {}
|
|
364
|
-
|
|
380
|
+
|
|
381
|
+
if context is None:
|
|
382
|
+
context = dict_obj["project"]
|
|
383
|
+
|
|
384
|
+
ctx = get_context_from_project(context)
|
|
365
385
|
obj = factory.build_entity_from_dict(dict_obj)
|
|
386
|
+
if reset_id:
|
|
387
|
+
new_id = build_uuid()
|
|
388
|
+
obj.id = new_id
|
|
389
|
+
obj.metadata.version = new_id
|
|
366
390
|
try:
|
|
367
|
-
self._create_context_entity(
|
|
391
|
+
bck_obj = self._create_context_entity(ctx, obj.ENTITY_TYPE, obj.to_dict())
|
|
392
|
+
new_obj: ContextEntity = factory.build_entity_from_dict(bck_obj)
|
|
368
393
|
except EntityAlreadyExistsError:
|
|
369
394
|
raise EntityError(f"Entity {obj.name} already exists. If you want to update it, use load instead.")
|
|
370
|
-
return
|
|
395
|
+
return new_obj
|
|
371
396
|
|
|
372
397
|
def import_executable_entity(
|
|
373
398
|
self,
|
|
374
|
-
file: str,
|
|
399
|
+
file: str | None = None,
|
|
400
|
+
key: str | None = None,
|
|
401
|
+
reset_id: bool = False,
|
|
402
|
+
context: str | None = None,
|
|
375
403
|
) -> ExecutableEntity:
|
|
376
404
|
"""
|
|
377
|
-
Import an executable entity from a YAML file
|
|
378
|
-
|
|
379
|
-
Reads executable entity configuration from a YAML file and creates
|
|
380
|
-
a new executable entity (function or workflow) in the backend.
|
|
381
|
-
Also imports associated task definitions if present in the file.
|
|
405
|
+
Import an executable entity from a YAML file or from a storage key.
|
|
382
406
|
|
|
383
407
|
Parameters
|
|
384
408
|
----------
|
|
385
409
|
file : str
|
|
386
410
|
Path to the YAML file containing executable entity configuration.
|
|
387
411
|
Can contain a single entity or a list with the executable and tasks.
|
|
412
|
+
key : str
|
|
413
|
+
Storage key (store://...) to read the entity from.
|
|
414
|
+
reset_id : bool
|
|
415
|
+
Flag to determine if the ID of executable entities should be reset.
|
|
416
|
+
context : str, optional
|
|
417
|
+
Project name to use for context resolution.
|
|
388
418
|
|
|
389
419
|
Returns
|
|
390
420
|
-------
|
|
@@ -396,7 +426,15 @@ class ContextEntityOperationsProcessor:
|
|
|
396
426
|
EntityError
|
|
397
427
|
If the entity already exists in the backend.
|
|
398
428
|
"""
|
|
399
|
-
|
|
429
|
+
if (file is None) == (key is None):
|
|
430
|
+
raise ValueError("Provide key or file, not both or none.")
|
|
431
|
+
|
|
432
|
+
if file is not None:
|
|
433
|
+
dict_obj: dict | list[dict] = read_yaml(file)
|
|
434
|
+
else:
|
|
435
|
+
ctx = get_context_from_identifier(key)
|
|
436
|
+
dict_obj: dict = self._read_context_entity(ctx, key)
|
|
437
|
+
|
|
400
438
|
if isinstance(dict_obj, list):
|
|
401
439
|
exec_dict = dict_obj[0]
|
|
402
440
|
exec_dict["status"] = {}
|
|
@@ -406,18 +444,29 @@ class ContextEntityOperationsProcessor:
|
|
|
406
444
|
tsk_dicts.append(i)
|
|
407
445
|
else:
|
|
408
446
|
exec_dict = dict_obj
|
|
447
|
+
exec_dict["status"] = {}
|
|
409
448
|
tsk_dicts = []
|
|
410
449
|
|
|
411
|
-
context
|
|
450
|
+
if context is None:
|
|
451
|
+
context = exec_dict["project"]
|
|
452
|
+
|
|
453
|
+
ctx = get_context_from_project(context)
|
|
412
454
|
obj: ExecutableEntity = factory.build_entity_from_dict(exec_dict)
|
|
455
|
+
|
|
456
|
+
if reset_id:
|
|
457
|
+
new_id = build_uuid()
|
|
458
|
+
obj.id = new_id
|
|
459
|
+
obj.metadata.version = new_id
|
|
460
|
+
|
|
413
461
|
try:
|
|
414
|
-
self._create_context_entity(
|
|
462
|
+
bck_obj = self._create_context_entity(ctx, obj.ENTITY_TYPE, obj.to_dict())
|
|
463
|
+
new_obj: ExecutableEntity = factory.build_entity_from_dict(bck_obj)
|
|
415
464
|
except EntityAlreadyExistsError:
|
|
416
465
|
raise EntityError(f"Entity {obj.name} already exists. If you want to update it, use load instead.")
|
|
417
466
|
|
|
418
|
-
|
|
467
|
+
new_obj.import_tasks(tsk_dicts)
|
|
419
468
|
|
|
420
|
-
return
|
|
469
|
+
return new_obj
|
|
421
470
|
|
|
422
471
|
def load_context_entity(
|
|
423
472
|
self,
|
|
@@ -8,7 +8,7 @@ import typing
|
|
|
8
8
|
|
|
9
9
|
from digitalhub.context.api import get_context
|
|
10
10
|
from digitalhub.entities._commons.enums import ApiCategories, BackendOperations, EntityTypes
|
|
11
|
-
from digitalhub.entities._commons.utils import get_project_from_key, parse_entity_key
|
|
11
|
+
from digitalhub.entities._commons.utils import get_project_from_key, is_valid_key, parse_entity_key
|
|
12
12
|
from digitalhub.factory.factory import factory
|
|
13
13
|
from digitalhub.stores.client.api import get_client
|
|
14
14
|
from digitalhub.utils.exceptions import ContextError, EntityError, EntityNotExistsError
|
|
@@ -57,7 +57,7 @@ def parse_identifier(
|
|
|
57
57
|
ValueError
|
|
58
58
|
If identifier is not a full key and project or entity_type is None.
|
|
59
59
|
"""
|
|
60
|
-
if not identifier
|
|
60
|
+
if not is_valid_key(identifier):
|
|
61
61
|
if project is None or entity_type is None:
|
|
62
62
|
raise ValueError("Project and entity type must be specified.")
|
|
63
63
|
return project, entity_type, entity_kind, identifier, entity_id
|
|
@@ -93,7 +93,7 @@ def get_context_from_identifier(
|
|
|
93
93
|
EntityError
|
|
94
94
|
If identifier is not a full key and project parameter is None.
|
|
95
95
|
"""
|
|
96
|
-
if not identifier
|
|
96
|
+
if not is_valid_key(identifier):
|
|
97
97
|
if project is None:
|
|
98
98
|
raise EntityError("Specify project if you do not specify entity key.")
|
|
99
99
|
else:
|
|
@@ -238,14 +238,25 @@ def list_artifacts(project: str, **kwargs) -> list[Artifact]:
|
|
|
238
238
|
)
|
|
239
239
|
|
|
240
240
|
|
|
241
|
-
def import_artifact(
|
|
241
|
+
def import_artifact(
|
|
242
|
+
file: str | None = None,
|
|
243
|
+
key: str | None = None,
|
|
244
|
+
reset_id: bool = False,
|
|
245
|
+
context: str | None = None,
|
|
246
|
+
) -> Artifact:
|
|
242
247
|
"""
|
|
243
|
-
Import object from a YAML file
|
|
248
|
+
Import an object from a YAML file or from a storage key.
|
|
244
249
|
|
|
245
250
|
Parameters
|
|
246
251
|
----------
|
|
247
252
|
file : str
|
|
248
|
-
Path to YAML file.
|
|
253
|
+
Path to the YAML file.
|
|
254
|
+
key : str
|
|
255
|
+
Entity key (store://...).
|
|
256
|
+
reset_id : bool
|
|
257
|
+
Flag to determine if the ID of executable entities should be reset.
|
|
258
|
+
context : str
|
|
259
|
+
Project name to use for context resolution.
|
|
249
260
|
|
|
250
261
|
Returns
|
|
251
262
|
-------
|
|
@@ -256,7 +267,12 @@ def import_artifact(file: str) -> Artifact:
|
|
|
256
267
|
--------
|
|
257
268
|
>>> obj = import_artifact("my-artifact.yaml")
|
|
258
269
|
"""
|
|
259
|
-
return context_processor.import_context_entity(
|
|
270
|
+
return context_processor.import_context_entity(
|
|
271
|
+
file,
|
|
272
|
+
key,
|
|
273
|
+
reset_id,
|
|
274
|
+
context,
|
|
275
|
+
)
|
|
260
276
|
|
|
261
277
|
|
|
262
278
|
def load_artifact(file: str) -> Artifact:
|
|
@@ -6,9 +6,9 @@ from __future__ import annotations
|
|
|
6
6
|
|
|
7
7
|
from typing import Any
|
|
8
8
|
|
|
9
|
-
from digitalhub.entities._base.entity._constructors.uuid import build_uuid
|
|
10
9
|
from digitalhub.entities._base.material.utils import build_log_path_from_source, eval_local_source
|
|
11
10
|
from digitalhub.entities._commons.enums import EntityTypes
|
|
11
|
+
from digitalhub.entities._constructors.uuid import build_uuid
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
def eval_source(
|
|
@@ -264,14 +264,25 @@ def list_dataitems(project: str, **kwargs) -> list[Dataitem]:
|
|
|
264
264
|
)
|
|
265
265
|
|
|
266
266
|
|
|
267
|
-
def import_dataitem(
|
|
267
|
+
def import_dataitem(
|
|
268
|
+
file: str | None = None,
|
|
269
|
+
key: str | None = None,
|
|
270
|
+
reset_id: bool = False,
|
|
271
|
+
context: str | None = None,
|
|
272
|
+
) -> Dataitem:
|
|
268
273
|
"""
|
|
269
|
-
Import object from a YAML file
|
|
274
|
+
Import an object from a YAML file or from a storage key.
|
|
270
275
|
|
|
271
276
|
Parameters
|
|
272
277
|
----------
|
|
273
278
|
file : str
|
|
274
|
-
Path to YAML file.
|
|
279
|
+
Path to the YAML file.
|
|
280
|
+
key : str
|
|
281
|
+
Entity key (store://...).
|
|
282
|
+
reset_id : bool
|
|
283
|
+
Flag to determine if the ID of executable entities should be reset.
|
|
284
|
+
context : str
|
|
285
|
+
Project name to use for context resolution.
|
|
275
286
|
|
|
276
287
|
Returns
|
|
277
288
|
-------
|
|
@@ -282,7 +293,12 @@ def import_dataitem(file: str) -> Dataitem:
|
|
|
282
293
|
--------
|
|
283
294
|
>>> obj = import_dataitem("my-dataitem.yaml")
|
|
284
295
|
"""
|
|
285
|
-
return context_processor.import_context_entity(
|
|
296
|
+
return context_processor.import_context_entity(
|
|
297
|
+
file,
|
|
298
|
+
key,
|
|
299
|
+
reset_id,
|
|
300
|
+
context,
|
|
301
|
+
)
|
|
286
302
|
|
|
287
303
|
|
|
288
304
|
def load_dataitem(file: str) -> Dataitem:
|
|
@@ -4,9 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
|
-
import shutil
|
|
8
7
|
import typing
|
|
9
|
-
from pathlib import Path
|
|
10
8
|
from typing import Any
|
|
11
9
|
|
|
12
10
|
from digitalhub.entities.dataitem._base.entity import Dataitem
|
|
@@ -138,22 +136,3 @@ class DataitemTable(Dataitem):
|
|
|
138
136
|
extension=extension,
|
|
139
137
|
**kwargs,
|
|
140
138
|
)
|
|
141
|
-
|
|
142
|
-
@staticmethod
|
|
143
|
-
def _clean_tmp_path(pth: Path | None, clean: bool) -> None:
|
|
144
|
-
"""
|
|
145
|
-
Clean temporary path.
|
|
146
|
-
|
|
147
|
-
Parameters
|
|
148
|
-
----------
|
|
149
|
-
pth : Path | None
|
|
150
|
-
Path to clean.
|
|
151
|
-
clean : bool
|
|
152
|
-
If True, the path will be cleaned.
|
|
153
|
-
|
|
154
|
-
Returns
|
|
155
|
-
-------
|
|
156
|
-
None
|
|
157
|
-
"""
|
|
158
|
-
if pth is not None and clean:
|
|
159
|
-
shutil.rmtree(pth)
|
|
@@ -9,9 +9,9 @@ import typing
|
|
|
9
9
|
from typing import Any
|
|
10
10
|
|
|
11
11
|
from digitalhub.context.api import get_context
|
|
12
|
-
from digitalhub.entities._base.entity._constructors.uuid import build_uuid
|
|
13
12
|
from digitalhub.entities._base.material.utils import build_log_path_from_source, eval_local_source
|
|
14
13
|
from digitalhub.entities._commons.enums import EntityKinds, EntityTypes
|
|
14
|
+
from digitalhub.entities._constructors.uuid import build_uuid
|
|
15
15
|
from digitalhub.stores.data.api import get_store
|
|
16
16
|
from digitalhub.stores.readers.data.api import get_reader_by_object
|
|
17
17
|
from digitalhub.utils.enums import FileExtensions
|