digitalhub 0.14.0b1__py3-none-any.whl → 0.14.0b3__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/context/builder.py +0 -4
- digitalhub/context/context.py +12 -8
- digitalhub/entities/_base/_base/entity.py +0 -4
- digitalhub/entities/_base/context/entity.py +1 -1
- digitalhub/entities/_base/entity/entity.py +0 -8
- digitalhub/entities/_base/executable/entity.py +9 -21
- digitalhub/entities/_base/material/entity.py +5 -21
- digitalhub/entities/_base/unversioned/entity.py +1 -1
- digitalhub/entities/_base/versioned/entity.py +1 -1
- digitalhub/entities/_processors/base/__init__.py +3 -0
- digitalhub/entities/_processors/{base.py → base/crud.py} +12 -232
- digitalhub/entities/_processors/base/import_export.py +122 -0
- digitalhub/entities/_processors/base/processor.py +302 -0
- digitalhub/entities/_processors/base/special_ops.py +108 -0
- digitalhub/entities/_processors/context/__init__.py +3 -0
- digitalhub/entities/_processors/context/crud.py +654 -0
- digitalhub/entities/_processors/context/import_export.py +242 -0
- digitalhub/entities/_processors/context/material.py +123 -0
- digitalhub/entities/_processors/context/processor.py +400 -0
- digitalhub/entities/_processors/context/special_ops.py +476 -0
- digitalhub/entities/_processors/processors.py +12 -0
- digitalhub/entities/_processors/utils.py +2 -2
- digitalhub/entities/artifact/crud.py +1 -1
- digitalhub/entities/dataitem/crud.py +6 -3
- digitalhub/entities/dataitem/table/entity.py +24 -1
- digitalhub/entities/dataitem/utils.py +4 -0
- digitalhub/entities/function/_base/entity.py +3 -3
- digitalhub/entities/function/crud.py +1 -1
- digitalhub/entities/model/_base/entity.py +46 -24
- digitalhub/entities/model/crud.py +1 -1
- digitalhub/entities/project/_base/entity.py +3 -12
- digitalhub/entities/project/crud.py +1 -2
- digitalhub/entities/run/_base/builder.py +0 -4
- digitalhub/entities/run/_base/entity.py +53 -66
- digitalhub/entities/run/crud.py +5 -2
- digitalhub/entities/secret/_base/entity.py +1 -5
- digitalhub/entities/secret/crud.py +1 -1
- digitalhub/entities/task/_base/builder.py +0 -4
- digitalhub/entities/task/_base/entity.py +5 -5
- digitalhub/entities/task/crud.py +1 -1
- digitalhub/entities/trigger/_base/entity.py +1 -5
- digitalhub/entities/trigger/crud.py +1 -1
- digitalhub/entities/workflow/_base/entity.py +3 -3
- digitalhub/entities/workflow/crud.py +1 -1
- digitalhub/factory/entity.py +283 -0
- digitalhub/factory/registry.py +197 -0
- digitalhub/factory/runtime.py +44 -0
- digitalhub/runtimes/_base.py +2 -2
- digitalhub/stores/client/dhcore/client.py +0 -14
- digitalhub/stores/client/dhcore/configurator.py +5 -28
- digitalhub/stores/client/dhcore/error_parser.py +0 -4
- digitalhub/stores/credentials/configurator.py +4 -29
- digitalhub/stores/credentials/handler.py +0 -12
- digitalhub/stores/credentials/store.py +0 -4
- digitalhub/stores/data/_base/store.py +0 -16
- digitalhub/stores/data/builder.py +0 -4
- digitalhub/stores/data/remote/store.py +0 -4
- digitalhub/stores/data/s3/configurator.py +2 -10
- digitalhub/stores/data/s3/store.py +0 -12
- digitalhub/stores/data/sql/configurator.py +0 -8
- digitalhub/stores/data/sql/store.py +0 -4
- digitalhub/stores/readers/data/factory.py +0 -8
- digitalhub/stores/readers/data/pandas/reader.py +9 -19
- digitalhub/utils/io_utils.py +0 -4
- {digitalhub-0.14.0b1.dist-info → digitalhub-0.14.0b3.dist-info}/METADATA +1 -1
- {digitalhub-0.14.0b1.dist-info → digitalhub-0.14.0b3.dist-info}/RECORD +69 -57
- digitalhub/entities/_processors/context.py +0 -1499
- digitalhub/factory/factory.py +0 -460
- {digitalhub-0.14.0b1.dist-info → digitalhub-0.14.0b3.dist-info}/WHEEL +0 -0
- {digitalhub-0.14.0b1.dist-info → digitalhub-0.14.0b3.dist-info}/licenses/AUTHORS +0 -0
- {digitalhub-0.14.0b1.dist-info → digitalhub-0.14.0b3.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: © 2025 DSLab - Fondazione Bruno Kessler
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import typing
|
|
8
|
+
|
|
9
|
+
from digitalhub.factory.registry import registry
|
|
10
|
+
from digitalhub.utils.exceptions import BuilderError
|
|
11
|
+
|
|
12
|
+
if typing.TYPE_CHECKING:
|
|
13
|
+
from digitalhub.entities._base.entity.entity import Entity
|
|
14
|
+
from digitalhub.entities._base.entity.metadata import Metadata
|
|
15
|
+
from digitalhub.entities._base.entity.spec import Spec, SpecValidator
|
|
16
|
+
from digitalhub.entities._base.entity.status import Status
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class EntityFactory:
|
|
20
|
+
"""
|
|
21
|
+
Factory for creating and managing entity builders.
|
|
22
|
+
|
|
23
|
+
This class handles the creation of entities and their components
|
|
24
|
+
through their respective builders, using a centralized registry.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def _call_builder_method(self, kind: str, method_name: str, *args, **kwargs):
|
|
28
|
+
"""
|
|
29
|
+
Helper method to get a builder and call a method on it.
|
|
30
|
+
|
|
31
|
+
Parameters
|
|
32
|
+
----------
|
|
33
|
+
kind : str
|
|
34
|
+
The kind of builder to retrieve.
|
|
35
|
+
method_name : str
|
|
36
|
+
The name of the method to call on the builder.
|
|
37
|
+
*args
|
|
38
|
+
Positional arguments to pass to the method.
|
|
39
|
+
**kwargs
|
|
40
|
+
Keyword arguments to pass to the method.
|
|
41
|
+
|
|
42
|
+
Returns
|
|
43
|
+
-------
|
|
44
|
+
Any
|
|
45
|
+
The result of calling the method on the builder.
|
|
46
|
+
"""
|
|
47
|
+
builder = registry.get_entity_builder(kind)
|
|
48
|
+
return getattr(builder, method_name)(*args, **kwargs)
|
|
49
|
+
|
|
50
|
+
def build_entity_from_params(self, **kwargs) -> Entity:
|
|
51
|
+
"""
|
|
52
|
+
Build an entity from parameters.
|
|
53
|
+
|
|
54
|
+
Parameters
|
|
55
|
+
----------
|
|
56
|
+
**kwargs
|
|
57
|
+
Entity parameters.
|
|
58
|
+
|
|
59
|
+
Returns
|
|
60
|
+
-------
|
|
61
|
+
Entity
|
|
62
|
+
Entity object.
|
|
63
|
+
"""
|
|
64
|
+
kind = self._get_kind(**kwargs)
|
|
65
|
+
builder = registry.get_entity_builder(kind)
|
|
66
|
+
return builder.build(**kwargs)
|
|
67
|
+
|
|
68
|
+
def build_entity_from_dict(self, obj: dict) -> Entity:
|
|
69
|
+
"""
|
|
70
|
+
Build an entity from a dictionary.
|
|
71
|
+
|
|
72
|
+
Parameters
|
|
73
|
+
----------
|
|
74
|
+
obj : dict
|
|
75
|
+
Dictionary with entity data.
|
|
76
|
+
|
|
77
|
+
Returns
|
|
78
|
+
-------
|
|
79
|
+
Entity
|
|
80
|
+
Entity object.
|
|
81
|
+
"""
|
|
82
|
+
kind = self._get_kind(**obj)
|
|
83
|
+
builder = registry.get_entity_builder(kind)
|
|
84
|
+
return builder.from_dict(obj)
|
|
85
|
+
|
|
86
|
+
def build_spec(self, kind_to_build_from: str, **kwargs) -> Spec:
|
|
87
|
+
"""
|
|
88
|
+
Build an entity spec.
|
|
89
|
+
|
|
90
|
+
Parameters
|
|
91
|
+
----------
|
|
92
|
+
kind_to_build_from : str
|
|
93
|
+
Entity type.
|
|
94
|
+
**kwargs
|
|
95
|
+
Additional spec parameters.
|
|
96
|
+
|
|
97
|
+
Returns
|
|
98
|
+
-------
|
|
99
|
+
Spec
|
|
100
|
+
Spec object.
|
|
101
|
+
"""
|
|
102
|
+
return self._call_builder_method(kind_to_build_from, "build_spec", **kwargs)
|
|
103
|
+
|
|
104
|
+
def build_metadata(self, kind_to_build_from: str, **kwargs) -> Metadata:
|
|
105
|
+
"""
|
|
106
|
+
Build an entity metadata.
|
|
107
|
+
|
|
108
|
+
Parameters
|
|
109
|
+
----------
|
|
110
|
+
kind_to_build_from : str
|
|
111
|
+
Entity type.
|
|
112
|
+
**kwargs
|
|
113
|
+
Additional metadata parameters.
|
|
114
|
+
|
|
115
|
+
Returns
|
|
116
|
+
-------
|
|
117
|
+
Metadata
|
|
118
|
+
Metadata object.
|
|
119
|
+
"""
|
|
120
|
+
return self._call_builder_method(kind_to_build_from, "build_metadata", **kwargs)
|
|
121
|
+
|
|
122
|
+
def build_status(self, kind_to_build_from: str, **kwargs) -> Status:
|
|
123
|
+
"""
|
|
124
|
+
Build an entity status.
|
|
125
|
+
|
|
126
|
+
Parameters
|
|
127
|
+
----------
|
|
128
|
+
kind_to_build_from : str
|
|
129
|
+
Entity type.
|
|
130
|
+
**kwargs
|
|
131
|
+
Additional status parameters.
|
|
132
|
+
|
|
133
|
+
Returns
|
|
134
|
+
-------
|
|
135
|
+
Status
|
|
136
|
+
Status object.
|
|
137
|
+
"""
|
|
138
|
+
return self._call_builder_method(kind_to_build_from, "build_status", **kwargs)
|
|
139
|
+
|
|
140
|
+
def get_entity_type_from_kind(self, kind: str) -> str:
|
|
141
|
+
"""
|
|
142
|
+
Get entity type from builder.
|
|
143
|
+
|
|
144
|
+
Parameters
|
|
145
|
+
----------
|
|
146
|
+
kind : str
|
|
147
|
+
Entity type.
|
|
148
|
+
|
|
149
|
+
Returns
|
|
150
|
+
-------
|
|
151
|
+
str
|
|
152
|
+
Entity type.
|
|
153
|
+
"""
|
|
154
|
+
return self._call_builder_method(kind, "get_entity_type")
|
|
155
|
+
|
|
156
|
+
def get_executable_kind(self, kind: str) -> str:
|
|
157
|
+
"""
|
|
158
|
+
Get executable kind.
|
|
159
|
+
|
|
160
|
+
Parameters
|
|
161
|
+
----------
|
|
162
|
+
kind : str
|
|
163
|
+
Kind.
|
|
164
|
+
|
|
165
|
+
Returns
|
|
166
|
+
-------
|
|
167
|
+
str
|
|
168
|
+
Executable kind.
|
|
169
|
+
"""
|
|
170
|
+
return self._call_builder_method(kind, "get_executable_kind")
|
|
171
|
+
|
|
172
|
+
def get_action_from_task_kind(self, kind: str, task_kind: str) -> str:
|
|
173
|
+
"""
|
|
174
|
+
Get action from task.
|
|
175
|
+
|
|
176
|
+
Parameters
|
|
177
|
+
----------
|
|
178
|
+
kind : str
|
|
179
|
+
Kind.
|
|
180
|
+
task_kind : str
|
|
181
|
+
Task kind.
|
|
182
|
+
|
|
183
|
+
Returns
|
|
184
|
+
-------
|
|
185
|
+
str
|
|
186
|
+
Action.
|
|
187
|
+
"""
|
|
188
|
+
return self._call_builder_method(kind, "get_action_from_task_kind", task_kind)
|
|
189
|
+
|
|
190
|
+
def get_task_kind_from_action(self, kind: str, action: str) -> list[str]:
|
|
191
|
+
"""
|
|
192
|
+
Get task kinds from action.
|
|
193
|
+
|
|
194
|
+
Parameters
|
|
195
|
+
----------
|
|
196
|
+
kind : str
|
|
197
|
+
Kind.
|
|
198
|
+
action : str
|
|
199
|
+
Action.
|
|
200
|
+
|
|
201
|
+
Returns
|
|
202
|
+
-------
|
|
203
|
+
list of str
|
|
204
|
+
Task kinds.
|
|
205
|
+
"""
|
|
206
|
+
return self._call_builder_method(kind, "get_task_kind_from_action", action)
|
|
207
|
+
|
|
208
|
+
def get_run_kind_from_action(self, kind: str, action: str) -> str:
|
|
209
|
+
"""
|
|
210
|
+
Get run kind.
|
|
211
|
+
|
|
212
|
+
Parameters
|
|
213
|
+
----------
|
|
214
|
+
kind : str
|
|
215
|
+
Kind.
|
|
216
|
+
|
|
217
|
+
Returns
|
|
218
|
+
-------
|
|
219
|
+
str
|
|
220
|
+
Run kind.
|
|
221
|
+
"""
|
|
222
|
+
return self._call_builder_method(kind, "get_run_kind_from_action", action)
|
|
223
|
+
|
|
224
|
+
def get_all_kinds(self, kind: str) -> list[str]:
|
|
225
|
+
"""
|
|
226
|
+
Get all kinds.
|
|
227
|
+
|
|
228
|
+
Parameters
|
|
229
|
+
----------
|
|
230
|
+
kind : str
|
|
231
|
+
Kind.
|
|
232
|
+
|
|
233
|
+
Returns
|
|
234
|
+
-------
|
|
235
|
+
list of str
|
|
236
|
+
All kinds.
|
|
237
|
+
"""
|
|
238
|
+
return self._call_builder_method(kind, "get_all_kinds")
|
|
239
|
+
|
|
240
|
+
def get_spec_validator(self, kind: str) -> SpecValidator:
|
|
241
|
+
"""
|
|
242
|
+
Get spec validators.
|
|
243
|
+
|
|
244
|
+
Parameters
|
|
245
|
+
----------
|
|
246
|
+
kind : str
|
|
247
|
+
Kind.
|
|
248
|
+
|
|
249
|
+
Returns
|
|
250
|
+
-------
|
|
251
|
+
SpecValidator
|
|
252
|
+
Spec validator.
|
|
253
|
+
"""
|
|
254
|
+
return self._call_builder_method(kind, "get_spec_validator")
|
|
255
|
+
|
|
256
|
+
@staticmethod
|
|
257
|
+
def _get_kind(**kwargs) -> str:
|
|
258
|
+
"""
|
|
259
|
+
Extract the 'kind' from parameters.
|
|
260
|
+
|
|
261
|
+
Parameters
|
|
262
|
+
----------
|
|
263
|
+
**kwargs
|
|
264
|
+
Entity parameters.
|
|
265
|
+
|
|
266
|
+
Returns
|
|
267
|
+
-------
|
|
268
|
+
str
|
|
269
|
+
The kind of the entity.
|
|
270
|
+
|
|
271
|
+
Raises
|
|
272
|
+
------
|
|
273
|
+
BuilderError
|
|
274
|
+
If 'kind' is not found in parameters.
|
|
275
|
+
"""
|
|
276
|
+
try:
|
|
277
|
+
return kwargs["kind"]
|
|
278
|
+
except KeyError:
|
|
279
|
+
raise BuilderError("Missing 'kind' parameter.")
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
# Global instance
|
|
283
|
+
entity_factory = EntityFactory()
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: © 2025 DSLab - Fondazione Bruno Kessler
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import typing
|
|
8
|
+
|
|
9
|
+
from digitalhub.factory.enums import FactoryEnum
|
|
10
|
+
from digitalhub.factory.utils import import_module, list_runtimes
|
|
11
|
+
from digitalhub.utils.exceptions import BuilderError
|
|
12
|
+
|
|
13
|
+
if typing.TYPE_CHECKING:
|
|
14
|
+
from digitalhub.entities._base.entity.builder import EntityBuilder
|
|
15
|
+
from digitalhub.entities._base.runtime_entity.builder import RuntimeEntityBuilder
|
|
16
|
+
from digitalhub.runtimes.builder import RuntimeBuilder
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class BuilderRegistry:
|
|
20
|
+
"""
|
|
21
|
+
Singleton registry for managing imported modules and builders.
|
|
22
|
+
|
|
23
|
+
This class centralizes the registration and retrieval of entity and runtime builders,
|
|
24
|
+
ensuring lazy loading and a single source of truth for available builders.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(self) -> None:
|
|
28
|
+
self._instance: BuilderRegistry | None = None
|
|
29
|
+
self._initialized = False
|
|
30
|
+
self._entity_builders: dict[str, EntityBuilder | RuntimeEntityBuilder] = {}
|
|
31
|
+
self._runtime_builders: dict[str, RuntimeBuilder] = {}
|
|
32
|
+
self._entities_registered = False
|
|
33
|
+
self._runtimes_registered = False
|
|
34
|
+
|
|
35
|
+
def add_entity_builder(
|
|
36
|
+
self,
|
|
37
|
+
name: str,
|
|
38
|
+
builder: type[EntityBuilder | RuntimeEntityBuilder],
|
|
39
|
+
) -> None:
|
|
40
|
+
"""
|
|
41
|
+
Register an entity builder.
|
|
42
|
+
|
|
43
|
+
Parameters
|
|
44
|
+
----------
|
|
45
|
+
name : str
|
|
46
|
+
The unique identifier for the builder.
|
|
47
|
+
builder : type[EntityBuilder] | type[RuntimeEntityBuilder]
|
|
48
|
+
The builder class to register. It will be instantiated immediately.
|
|
49
|
+
|
|
50
|
+
Raises
|
|
51
|
+
------
|
|
52
|
+
BuilderError
|
|
53
|
+
If a builder with the same name already exists.
|
|
54
|
+
"""
|
|
55
|
+
if name in self._entity_builders:
|
|
56
|
+
raise BuilderError(f"Builder {name} already exists.")
|
|
57
|
+
self._entity_builders[name] = builder()
|
|
58
|
+
|
|
59
|
+
def add_runtime_builder(self, name: str, builder: type[RuntimeBuilder]) -> None:
|
|
60
|
+
"""
|
|
61
|
+
Register a runtime builder.
|
|
62
|
+
|
|
63
|
+
Parameters
|
|
64
|
+
----------
|
|
65
|
+
name : str
|
|
66
|
+
The unique identifier for the builder.
|
|
67
|
+
builder : type[RuntimeBuilder]
|
|
68
|
+
The builder class to register. It will be instantiated immediately.
|
|
69
|
+
|
|
70
|
+
Raises
|
|
71
|
+
------
|
|
72
|
+
BuilderError
|
|
73
|
+
If a builder with the same name already exists.
|
|
74
|
+
"""
|
|
75
|
+
if name in self._runtime_builders:
|
|
76
|
+
raise BuilderError(f"Builder {name} already exists.")
|
|
77
|
+
self._runtime_builders[name] = builder()
|
|
78
|
+
|
|
79
|
+
def get_entity_builder(self, kind: str) -> EntityBuilder | RuntimeEntityBuilder:
|
|
80
|
+
"""
|
|
81
|
+
Retrieve the entity builder for the given kind, ensuring lazy registration.
|
|
82
|
+
|
|
83
|
+
Parameters
|
|
84
|
+
----------
|
|
85
|
+
kind : str
|
|
86
|
+
The kind of entity builder to retrieve.
|
|
87
|
+
|
|
88
|
+
Returns
|
|
89
|
+
-------
|
|
90
|
+
EntityBuilder | RuntimeEntityBuilder
|
|
91
|
+
The builder instance.
|
|
92
|
+
|
|
93
|
+
Raises
|
|
94
|
+
------
|
|
95
|
+
BuilderError
|
|
96
|
+
If no builder exists for the specified kind.
|
|
97
|
+
"""
|
|
98
|
+
if not self._entities_registered:
|
|
99
|
+
self._ensure_entities_registered()
|
|
100
|
+
if kind not in self._entity_builders:
|
|
101
|
+
if not self._runtimes_registered:
|
|
102
|
+
self._ensure_runtimes_registered()
|
|
103
|
+
if kind not in self._entity_builders:
|
|
104
|
+
raise BuilderError(f"Entity builder for kind '{kind}' not found.")
|
|
105
|
+
return self._entity_builders[kind]
|
|
106
|
+
|
|
107
|
+
def get_runtime_builder(self, kind: str) -> RuntimeBuilder:
|
|
108
|
+
"""
|
|
109
|
+
Retrieve the runtime builder for the given kind, ensuring lazy registration.
|
|
110
|
+
|
|
111
|
+
Parameters
|
|
112
|
+
----------
|
|
113
|
+
kind : str
|
|
114
|
+
The kind of runtime builder to retrieve.
|
|
115
|
+
|
|
116
|
+
Returns
|
|
117
|
+
-------
|
|
118
|
+
RuntimeBuilder
|
|
119
|
+
The builder instance.
|
|
120
|
+
|
|
121
|
+
Raises
|
|
122
|
+
------
|
|
123
|
+
BuilderError
|
|
124
|
+
If no builder exists for the specified kind.
|
|
125
|
+
"""
|
|
126
|
+
if kind not in self._runtime_builders:
|
|
127
|
+
if not self._runtimes_registered:
|
|
128
|
+
self._ensure_runtimes_registered()
|
|
129
|
+
if kind not in self._runtime_builders:
|
|
130
|
+
raise BuilderError(f"Runtime builder for kind '{kind}' not found.")
|
|
131
|
+
return self._runtime_builders[kind]
|
|
132
|
+
|
|
133
|
+
def _ensure_entities_registered(self) -> None:
|
|
134
|
+
"""
|
|
135
|
+
Ensure core entities are registered on-demand.
|
|
136
|
+
"""
|
|
137
|
+
if self._entities_registered:
|
|
138
|
+
return
|
|
139
|
+
try:
|
|
140
|
+
self._register_entities()
|
|
141
|
+
self._entities_registered = True
|
|
142
|
+
except Exception as e:
|
|
143
|
+
raise BuilderError(f"Failed to register core entities: {e}")
|
|
144
|
+
|
|
145
|
+
def _register_entities(self) -> None:
|
|
146
|
+
"""
|
|
147
|
+
Register core entity builders into the registry.
|
|
148
|
+
|
|
149
|
+
Imports the core entities module and registers all entity
|
|
150
|
+
builders with the registry.
|
|
151
|
+
"""
|
|
152
|
+
try:
|
|
153
|
+
module = import_module(FactoryEnum.REG_ENTITIES.value)
|
|
154
|
+
|
|
155
|
+
# Register core entities
|
|
156
|
+
for k, b in getattr(module, FactoryEnum.REG_ENTITIES_VAR.value, []):
|
|
157
|
+
self.add_entity_builder(k, b)
|
|
158
|
+
|
|
159
|
+
except Exception as e:
|
|
160
|
+
raise RuntimeError("Error registering core entities.") from e
|
|
161
|
+
|
|
162
|
+
def _ensure_runtimes_registered(self) -> None:
|
|
163
|
+
"""
|
|
164
|
+
Ensure runtime entities are registered on-demand.
|
|
165
|
+
"""
|
|
166
|
+
if self._runtimes_registered:
|
|
167
|
+
return
|
|
168
|
+
try:
|
|
169
|
+
self._register_runtimes_entities()
|
|
170
|
+
self._runtimes_registered = True
|
|
171
|
+
except Exception as e:
|
|
172
|
+
raise BuilderError(f"Failed to register runtime entities: {e}")
|
|
173
|
+
|
|
174
|
+
def _register_runtimes_entities(self) -> None:
|
|
175
|
+
"""
|
|
176
|
+
Register all runtime builders and their entities into the registry.
|
|
177
|
+
|
|
178
|
+
Imports each runtime package and registers its entity and runtime
|
|
179
|
+
builders with the registry.
|
|
180
|
+
"""
|
|
181
|
+
try:
|
|
182
|
+
for package in list_runtimes():
|
|
183
|
+
module = import_module(package)
|
|
184
|
+
|
|
185
|
+
# Register workflows, functions, tasks and runs entities builders
|
|
186
|
+
for k, b in getattr(module, FactoryEnum.REG_ENTITIES_VAR.value, []):
|
|
187
|
+
self.add_entity_builder(k, b)
|
|
188
|
+
|
|
189
|
+
# Register runtime builders
|
|
190
|
+
for k, b in getattr(module, FactoryEnum.REG_RUNTIME_VAR.value, []):
|
|
191
|
+
self.add_runtime_builder(k, b)
|
|
192
|
+
except Exception as e:
|
|
193
|
+
raise RuntimeError("Error registering runtime entities.") from e
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
# Global singleton instance
|
|
197
|
+
registry = BuilderRegistry()
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: © 2025 DSLab - Fondazione Bruno Kessler
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import typing
|
|
8
|
+
|
|
9
|
+
from digitalhub.factory.registry import registry
|
|
10
|
+
|
|
11
|
+
if typing.TYPE_CHECKING:
|
|
12
|
+
from digitalhub.runtimes._base import Runtime
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class RuntimeFactory:
|
|
16
|
+
"""
|
|
17
|
+
Factory for creating and managing runtime builders.
|
|
18
|
+
|
|
19
|
+
This class handles the creation of runtimes through their respective builders,
|
|
20
|
+
using a centralized registry.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def build_runtime(self, kind_to_build_from: str, project: str) -> Runtime:
|
|
24
|
+
"""
|
|
25
|
+
Build a runtime.
|
|
26
|
+
|
|
27
|
+
Parameters
|
|
28
|
+
----------
|
|
29
|
+
kind_to_build_from : str
|
|
30
|
+
Runtime type.
|
|
31
|
+
project : str
|
|
32
|
+
Project name.
|
|
33
|
+
|
|
34
|
+
Returns
|
|
35
|
+
-------
|
|
36
|
+
Runtime
|
|
37
|
+
Runtime object.
|
|
38
|
+
"""
|
|
39
|
+
builder = registry.get_runtime_builder(kind_to_build_from)
|
|
40
|
+
return builder.build(project=project)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
# Global instance
|
|
44
|
+
runtime_factory = RuntimeFactory()
|
digitalhub/runtimes/_base.py
CHANGED
|
@@ -7,7 +7,7 @@ from __future__ import annotations
|
|
|
7
7
|
from abc import abstractmethod
|
|
8
8
|
from typing import Any, Callable
|
|
9
9
|
|
|
10
|
-
from digitalhub.factory.
|
|
10
|
+
from digitalhub.factory.entity import entity_factory
|
|
11
11
|
from digitalhub.utils.exceptions import EntityError
|
|
12
12
|
from digitalhub.utils.logger import LOGGER
|
|
13
13
|
|
|
@@ -72,7 +72,7 @@ class Runtime:
|
|
|
72
72
|
raise RuntimeError(msg)
|
|
73
73
|
|
|
74
74
|
try:
|
|
75
|
-
return
|
|
75
|
+
return entity_factory.get_action_from_task_kind(task_kind, task_kind)
|
|
76
76
|
except EntityError:
|
|
77
77
|
msg = f"Task {task_kind} not allowed."
|
|
78
78
|
LOGGER.exception(msg)
|
|
@@ -58,12 +58,6 @@ class ClientDHCore(Client):
|
|
|
58
58
|
Parses backend responses and raises appropriate exceptions.
|
|
59
59
|
_configurator : ClientDHCoreConfigurator
|
|
60
60
|
Manages client configuration and authentication.
|
|
61
|
-
|
|
62
|
-
Examples
|
|
63
|
-
--------
|
|
64
|
-
>>> from digitalhub.stores.client.api import get_client
|
|
65
|
-
>>> client = get_client(local=False)
|
|
66
|
-
>>> # Client is now ready for API operations
|
|
67
61
|
"""
|
|
68
62
|
|
|
69
63
|
def __init__(self, config: dict | None = None) -> None:
|
|
@@ -75,10 +69,6 @@ class ClientDHCore(Client):
|
|
|
75
69
|
config : dict, optional
|
|
76
70
|
DHCore environment configuration. If None, loads from environment
|
|
77
71
|
variables and configuration files.
|
|
78
|
-
|
|
79
|
-
Returns
|
|
80
|
-
-------
|
|
81
|
-
None
|
|
82
72
|
"""
|
|
83
73
|
super().__init__()
|
|
84
74
|
|
|
@@ -490,10 +480,6 @@ class ClientDHCore(Client):
|
|
|
490
480
|
response : Response
|
|
491
481
|
HTTP response containing X-Api-Level header.
|
|
492
482
|
|
|
493
|
-
Returns
|
|
494
|
-
-------
|
|
495
|
-
None
|
|
496
|
-
|
|
497
483
|
Raises
|
|
498
484
|
------
|
|
499
485
|
ClientError
|
|
@@ -47,10 +47,6 @@ class ClientDHCoreConfigurator(Configurator):
|
|
|
47
47
|
def __init__(self) -> None:
|
|
48
48
|
"""
|
|
49
49
|
Initialize DHCore configurator and evaluate authentication type.
|
|
50
|
-
|
|
51
|
-
Returns
|
|
52
|
-
-------
|
|
53
|
-
None
|
|
54
50
|
"""
|
|
55
51
|
super().__init__()
|
|
56
52
|
self._auth_type: str | None = None
|
|
@@ -66,10 +62,6 @@ class ClientDHCoreConfigurator(Configurator):
|
|
|
66
62
|
|
|
67
63
|
Sanitizes endpoint and issuer URLs to ensure proper HTTP/HTTPS schemes
|
|
68
64
|
and removes trailing slashes.
|
|
69
|
-
|
|
70
|
-
Returns
|
|
71
|
-
-------
|
|
72
|
-
None
|
|
73
65
|
"""
|
|
74
66
|
env_creds = self._creds_handler.load_from_env(self.keys)
|
|
75
67
|
env_creds = self._sanitize_env_vars(env_creds)
|
|
@@ -107,10 +99,6 @@ class ClientDHCoreConfigurator(Configurator):
|
|
|
107
99
|
|
|
108
100
|
Handles keys without "DHCORE_" prefix for CLI compatibility. Falls back
|
|
109
101
|
to environment variables for missing endpoint and personal access token values.
|
|
110
|
-
|
|
111
|
-
Returns
|
|
112
|
-
-------
|
|
113
|
-
None
|
|
114
102
|
"""
|
|
115
103
|
file_creds = self._creds_handler.load_from_file(self.keys)
|
|
116
104
|
|
|
@@ -119,6 +107,11 @@ class ClientDHCoreConfigurator(Configurator):
|
|
|
119
107
|
if file_creds[pat] is None:
|
|
120
108
|
file_creds[pat] = self._creds_handler.load_from_env([pat]).get(pat)
|
|
121
109
|
|
|
110
|
+
# Because in the response there is no endpoint
|
|
111
|
+
endpoint = CredsEnvVar.DHCORE_ENDPOINT.value
|
|
112
|
+
if file_creds[endpoint] is None:
|
|
113
|
+
file_creds[endpoint] = self._creds_handler.load_from_env([endpoint]).get(endpoint)
|
|
114
|
+
|
|
122
115
|
file_creds = self._sanitize_file_vars(file_creds)
|
|
123
116
|
self._creds_handler.set_credentials(self._file, file_creds)
|
|
124
117
|
|
|
@@ -208,10 +201,6 @@ class ClientDHCoreConfigurator(Configurator):
|
|
|
208
201
|
|
|
209
202
|
Changes between environment and file credential sources, then re-evaluates
|
|
210
203
|
authentication type based on the new credentials.
|
|
211
|
-
|
|
212
|
-
Returns
|
|
213
|
-
-------
|
|
214
|
-
None
|
|
215
204
|
"""
|
|
216
205
|
super().change_origin()
|
|
217
206
|
|
|
@@ -230,10 +219,6 @@ class ClientDHCoreConfigurator(Configurator):
|
|
|
230
219
|
OAUTH2 (access + refresh tokens), ACCESS_TOKEN (access only), BASIC
|
|
231
220
|
(username + password). For EXCHANGE type, automatically exchanges the
|
|
232
221
|
personal access token and switches to file-based credentials storage.
|
|
233
|
-
|
|
234
|
-
Returns
|
|
235
|
-
-------
|
|
236
|
-
None
|
|
237
222
|
"""
|
|
238
223
|
creds = creds_handler.get_credentials(self._origin)
|
|
239
224
|
self._auth_type = self._eval_auth_type(creds)
|
|
@@ -305,10 +290,6 @@ class ClientDHCoreConfigurator(Configurator):
|
|
|
305
290
|
change_origin : bool, default False
|
|
306
291
|
Whether to switch credential sources on auth failure.
|
|
307
292
|
|
|
308
|
-
Returns
|
|
309
|
-
-------
|
|
310
|
-
None
|
|
311
|
-
|
|
312
293
|
Raises
|
|
313
294
|
------
|
|
314
295
|
ClientError
|
|
@@ -462,10 +443,6 @@ class ClientDHCoreConfigurator(Configurator):
|
|
|
462
443
|
----------
|
|
463
444
|
response : dict
|
|
464
445
|
OAuth2 token response with new credentials.
|
|
465
|
-
|
|
466
|
-
Returns
|
|
467
|
-
-------
|
|
468
|
-
None
|
|
469
446
|
"""
|
|
470
447
|
for key in self.keys_to_prefix:
|
|
471
448
|
key = key.lower()
|