digitalhub 0.14.0b0__py3-none-any.whl → 0.14.0b2__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.

Files changed (37) hide show
  1. digitalhub/entities/_base/executable/entity.py +20 -12
  2. digitalhub/entities/_base/material/entity.py +8 -4
  3. digitalhub/entities/_processors/base.py +8 -8
  4. digitalhub/entities/_processors/context.py +15 -15
  5. digitalhub/entities/_processors/utils.py +2 -2
  6. digitalhub/entities/artifact/crud.py +23 -7
  7. digitalhub/entities/dataitem/crud.py +28 -9
  8. digitalhub/entities/dataitem/table/entity.py +28 -1
  9. digitalhub/entities/dataitem/utils.py +4 -0
  10. digitalhub/entities/function/_base/entity.py +3 -3
  11. digitalhub/entities/function/crud.py +23 -7
  12. digitalhub/entities/model/_base/entity.py +51 -9
  13. digitalhub/entities/model/crud.py +21 -7
  14. digitalhub/entities/project/_base/entity.py +121 -41
  15. digitalhub/entities/project/crud.py +20 -6
  16. digitalhub/entities/run/_base/entity.py +58 -15
  17. digitalhub/entities/run/crud.py +22 -7
  18. digitalhub/entities/secret/crud.py +21 -7
  19. digitalhub/entities/task/_base/entity.py +4 -4
  20. digitalhub/entities/task/crud.py +18 -6
  21. digitalhub/entities/trigger/crud.py +23 -7
  22. digitalhub/entities/workflow/_base/entity.py +3 -3
  23. digitalhub/entities/workflow/crud.py +23 -7
  24. digitalhub/factory/entity.py +283 -0
  25. digitalhub/factory/registry.py +221 -0
  26. digitalhub/factory/runtime.py +44 -0
  27. digitalhub/runtimes/_base.py +2 -2
  28. digitalhub/stores/client/dhcore/client.py +8 -4
  29. digitalhub/stores/credentials/configurator.py +4 -5
  30. digitalhub/stores/data/s3/configurator.py +2 -2
  31. digitalhub/stores/readers/data/pandas/reader.py +9 -3
  32. {digitalhub-0.14.0b0.dist-info → digitalhub-0.14.0b2.dist-info}/METADATA +1 -1
  33. {digitalhub-0.14.0b0.dist-info → digitalhub-0.14.0b2.dist-info}/RECORD +36 -34
  34. digitalhub/factory/factory.py +0 -460
  35. {digitalhub-0.14.0b0.dist-info → digitalhub-0.14.0b2.dist-info}/WHEEL +0 -0
  36. {digitalhub-0.14.0b0.dist-info → digitalhub-0.14.0b2.dist-info}/licenses/AUTHORS +0 -0
  37. {digitalhub-0.14.0b0.dist-info → digitalhub-0.14.0b2.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,221 @@
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
+ Returns
51
+ -------
52
+ None
53
+
54
+ Raises
55
+ ------
56
+ BuilderError
57
+ If a builder with the same name already exists.
58
+ """
59
+ if name in self._entity_builders:
60
+ raise BuilderError(f"Builder {name} already exists.")
61
+ self._entity_builders[name] = builder()
62
+
63
+ def add_runtime_builder(self, name: str, builder: type[RuntimeBuilder]) -> None:
64
+ """
65
+ Register a runtime builder.
66
+
67
+ Parameters
68
+ ----------
69
+ name : str
70
+ The unique identifier for the builder.
71
+ builder : type[RuntimeBuilder]
72
+ The builder class to register. It will be instantiated immediately.
73
+
74
+ Returns
75
+ -------
76
+ None
77
+
78
+ Raises
79
+ ------
80
+ BuilderError
81
+ If a builder with the same name already exists.
82
+ """
83
+ if name in self._runtime_builders:
84
+ raise BuilderError(f"Builder {name} already exists.")
85
+ self._runtime_builders[name] = builder()
86
+
87
+ def get_entity_builder(self, kind: str) -> EntityBuilder | RuntimeEntityBuilder:
88
+ """
89
+ Retrieve the entity builder for the given kind, ensuring lazy registration.
90
+
91
+ Parameters
92
+ ----------
93
+ kind : str
94
+ The kind of entity builder to retrieve.
95
+
96
+ Returns
97
+ -------
98
+ EntityBuilder | RuntimeEntityBuilder
99
+ The builder instance.
100
+
101
+ Raises
102
+ ------
103
+ BuilderError
104
+ If no builder exists for the specified kind.
105
+ """
106
+ if not self._entities_registered:
107
+ self._ensure_entities_registered()
108
+ if kind not in self._entity_builders:
109
+ if not self._runtimes_registered:
110
+ self._ensure_runtimes_registered()
111
+ if kind not in self._entity_builders:
112
+ raise BuilderError(f"Entity builder for kind '{kind}' not found.")
113
+ return self._entity_builders[kind]
114
+
115
+ def get_runtime_builder(self, kind: str) -> RuntimeBuilder:
116
+ """
117
+ Retrieve the runtime builder for the given kind, ensuring lazy registration.
118
+
119
+ Parameters
120
+ ----------
121
+ kind : str
122
+ The kind of runtime builder to retrieve.
123
+
124
+ Returns
125
+ -------
126
+ RuntimeBuilder
127
+ The builder instance.
128
+
129
+ Raises
130
+ ------
131
+ BuilderError
132
+ If no builder exists for the specified kind.
133
+ """
134
+ if kind not in self._runtime_builders:
135
+ if not self._runtimes_registered:
136
+ self._ensure_runtimes_registered()
137
+ if kind not in self._runtime_builders:
138
+ raise BuilderError(f"Runtime builder for kind '{kind}' not found.")
139
+ return self._runtime_builders[kind]
140
+
141
+ def _ensure_entities_registered(self) -> None:
142
+ """
143
+ Ensure core entities are registered on-demand.
144
+
145
+ Returns
146
+ -------
147
+ None
148
+ """
149
+ if self._entities_registered:
150
+ return
151
+ try:
152
+ self._register_entities()
153
+ self._entities_registered = True
154
+ except Exception as e:
155
+ raise BuilderError(f"Failed to register core entities: {e}")
156
+
157
+ def _register_entities(self) -> None:
158
+ """
159
+ Register core entity builders into the registry.
160
+
161
+ Imports the core entities module and registers all entity
162
+ builders with the registry.
163
+
164
+ Returns
165
+ -------
166
+ None
167
+ """
168
+ try:
169
+ module = import_module(FactoryEnum.REG_ENTITIES.value)
170
+
171
+ # Register core entities
172
+ for k, b in getattr(module, FactoryEnum.REG_ENTITIES_VAR.value, []):
173
+ self.add_entity_builder(k, b)
174
+
175
+ except Exception as e:
176
+ raise RuntimeError("Error registering core entities.") from e
177
+
178
+ def _ensure_runtimes_registered(self) -> None:
179
+ """
180
+ Ensure runtime entities are registered on-demand.
181
+
182
+ Returns
183
+ -------
184
+ None
185
+ """
186
+ if self._runtimes_registered:
187
+ return
188
+ try:
189
+ self._register_runtimes_entities()
190
+ self._runtimes_registered = True
191
+ except Exception as e:
192
+ raise BuilderError(f"Failed to register runtime entities: {e}")
193
+
194
+ def _register_runtimes_entities(self) -> None:
195
+ """
196
+ Register all runtime builders and their entities into the registry.
197
+
198
+ Imports each runtime package and registers its entity and runtime
199
+ builders with the registry.
200
+
201
+ Returns
202
+ -------
203
+ None
204
+ """
205
+ try:
206
+ for package in list_runtimes():
207
+ module = import_module(package)
208
+
209
+ # Register workflows, functions, tasks and runs entities builders
210
+ for k, b in getattr(module, FactoryEnum.REG_ENTITIES_VAR.value, []):
211
+ self.add_entity_builder(k, b)
212
+
213
+ # Register runtime builders
214
+ for k, b in getattr(module, FactoryEnum.REG_RUNTIME_VAR.value, []):
215
+ self.add_runtime_builder(k, b)
216
+ except Exception as e:
217
+ raise RuntimeError("Error registering runtime entities.") from e
218
+
219
+
220
+ # Global singleton instance
221
+ 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()
@@ -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.factory import 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 factory.get_action_from_task_kind(task_kind, task_kind)
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)
@@ -26,8 +26,8 @@ if typing.TYPE_CHECKING:
26
26
 
27
27
  # API levels that are supported
28
28
  MAX_API_LEVEL = 20
29
- MIN_API_LEVEL = 11
30
- LIB_VERSION = 13
29
+ MIN_API_LEVEL = 14
30
+ LIB_VERSION = 14
31
31
 
32
32
 
33
33
  class ClientDHCore(Client):
@@ -61,8 +61,12 @@ class ClientDHCore(Client):
61
61
 
62
62
  Examples
63
63
  --------
64
- >>> from digitalhub.stores.client.api import get_client
65
- >>> client = get_client(local=False)
64
+ >>> from digitalhub.stores.client.api import (
65
+ ... get_client,
66
+ ... )
67
+ >>> client = get_client(
68
+ ... local=False
69
+ ... )
66
70
  >>> # Client is now ready for API operations
67
71
  """
68
72
 
@@ -62,12 +62,10 @@ class Configurator:
62
62
  self.load_file_vars()
63
63
 
64
64
  @abstractmethod
65
- def load_env_vars(self) -> None:
66
- ...
65
+ def load_env_vars(self) -> None: ...
67
66
 
68
67
  @abstractmethod
69
- def load_file_vars(self) -> None:
70
- ...
68
+ def load_file_vars(self) -> None: ...
71
69
 
72
70
  def check_config(self) -> None:
73
71
  """
@@ -143,7 +141,8 @@ class Configurator:
143
141
  raise ConfigError("Origin has already been changed.")
144
142
  if self._origin == self._env:
145
143
  self.change_to_file()
146
- self.change_to_env()
144
+ else:
145
+ self.change_to_env()
147
146
 
148
147
  def change_to_file(self) -> None:
149
148
  """
@@ -4,7 +4,7 @@
4
4
 
5
5
  from __future__ import annotations
6
6
 
7
- from datetime import datetime, timezone
7
+ from datetime import datetime, timedelta, timezone
8
8
 
9
9
  from botocore.config import Config
10
10
 
@@ -165,5 +165,5 @@ class S3StoreConfigurator(Configurator):
165
165
  return False
166
166
  dt = datetime.strptime(timestamp, "%Y-%m-%dT%H:%M:%SZ")
167
167
  dt = dt.replace(tzinfo=timezone.utc)
168
- now = datetime.now(timezone.utc) + datetime.timedelta(seconds=120)
168
+ now = datetime.now(timezone.utc) + timedelta(seconds=120)
169
169
  return dt < now
@@ -133,7 +133,9 @@ class DataframeReaderPandas(DataframeReader):
133
133
  -------
134
134
  None
135
135
  """
136
- df.to_csv(dst, index=False, **kwargs)
136
+ if "index" not in kwargs:
137
+ kwargs["index"] = False
138
+ df.to_csv(dst, **kwargs)
137
139
 
138
140
  @staticmethod
139
141
  def write_parquet(df: pd.DataFrame, dst: str | BytesIO, **kwargs) -> None:
@@ -153,7 +155,9 @@ class DataframeReaderPandas(DataframeReader):
153
155
  -------
154
156
  None
155
157
  """
156
- df.to_parquet(dst, index=False, **kwargs)
158
+ if "index" not in kwargs:
159
+ kwargs["index"] = False
160
+ df.to_parquet(dst, **kwargs)
157
161
 
158
162
  @staticmethod
159
163
  def write_table(df: pd.DataFrame, table: str, engine: Any, schema: str | None = None, **kwargs) -> None:
@@ -177,7 +181,9 @@ class DataframeReaderPandas(DataframeReader):
177
181
  -------
178
182
  None
179
183
  """
180
- df.to_sql(table, engine, schema=schema, index=False, **kwargs)
184
+ if "index" not in kwargs:
185
+ kwargs["index"] = False
186
+ df.to_sql(table, engine, schema=schema, **kwargs)
181
187
 
182
188
  ##############################
183
189
  # Utils
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: digitalhub
3
- Version: 0.14.0b0
3
+ Version: 0.14.0b2
4
4
  Summary: Python SDK for Digitalhub
5
5
  Project-URL: Homepage, https://github.com/scc-digitalhub/digitalhub-sdk
6
6
  Author-email: Fondazione Bruno Kessler <digitalhub@fbk.eu>, Matteo Martini <mmartini@fbk.eu>