digitalhub 0.8.0b0__py3-none-any.whl → 0.8.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.

Files changed (159) hide show
  1. digitalhub/__init__.py +62 -94
  2. digitalhub/client/__init__.py +0 -0
  3. digitalhub/client/builder.py +105 -0
  4. digitalhub/client/objects/__init__.py +0 -0
  5. digitalhub/client/objects/base.py +56 -0
  6. digitalhub/client/objects/dhcore.py +681 -0
  7. digitalhub/client/objects/local.py +533 -0
  8. digitalhub/context/__init__.py +0 -0
  9. digitalhub/context/builder.py +178 -0
  10. digitalhub/context/context.py +136 -0
  11. digitalhub/datastores/__init__.py +0 -0
  12. digitalhub/datastores/builder.py +134 -0
  13. digitalhub/datastores/objects/__init__.py +0 -0
  14. digitalhub/datastores/objects/base.py +85 -0
  15. digitalhub/datastores/objects/local.py +42 -0
  16. digitalhub/datastores/objects/remote.py +23 -0
  17. digitalhub/datastores/objects/s3.py +38 -0
  18. digitalhub/datastores/objects/sql.py +60 -0
  19. digitalhub/entities/__init__.py +0 -0
  20. digitalhub/entities/_base/__init__.py +0 -0
  21. digitalhub/entities/_base/api.py +346 -0
  22. digitalhub/entities/_base/base.py +82 -0
  23. digitalhub/entities/_base/crud.py +610 -0
  24. digitalhub/entities/_base/entity/__init__.py +0 -0
  25. digitalhub/entities/_base/entity/base.py +132 -0
  26. digitalhub/entities/_base/entity/context.py +118 -0
  27. digitalhub/entities/_base/entity/executable.py +380 -0
  28. digitalhub/entities/_base/entity/material.py +214 -0
  29. digitalhub/entities/_base/entity/unversioned.py +87 -0
  30. digitalhub/entities/_base/entity/versioned.py +94 -0
  31. digitalhub/entities/_base/metadata.py +59 -0
  32. digitalhub/entities/_base/spec/__init__.py +0 -0
  33. digitalhub/entities/_base/spec/base.py +58 -0
  34. digitalhub/entities/_base/spec/material.py +22 -0
  35. digitalhub/entities/_base/state.py +31 -0
  36. digitalhub/entities/_base/status/__init__.py +0 -0
  37. digitalhub/entities/_base/status/base.py +32 -0
  38. digitalhub/entities/_base/status/material.py +49 -0
  39. digitalhub/entities/_builders/__init__.py +0 -0
  40. digitalhub/entities/_builders/metadata.py +60 -0
  41. digitalhub/entities/_builders/name.py +31 -0
  42. digitalhub/entities/_builders/spec.py +43 -0
  43. digitalhub/entities/_builders/status.py +62 -0
  44. digitalhub/entities/_builders/uuid.py +33 -0
  45. digitalhub/entities/artifact/__init__.py +0 -0
  46. digitalhub/entities/artifact/builder.py +133 -0
  47. digitalhub/entities/artifact/crud.py +358 -0
  48. digitalhub/entities/artifact/entity/__init__.py +0 -0
  49. digitalhub/entities/artifact/entity/_base.py +39 -0
  50. digitalhub/entities/artifact/entity/artifact.py +9 -0
  51. digitalhub/entities/artifact/spec.py +39 -0
  52. digitalhub/entities/artifact/status.py +15 -0
  53. digitalhub/entities/dataitem/__init__.py +0 -0
  54. digitalhub/entities/dataitem/builder.py +144 -0
  55. digitalhub/entities/dataitem/crud.py +395 -0
  56. digitalhub/entities/dataitem/entity/__init__.py +0 -0
  57. digitalhub/entities/dataitem/entity/_base.py +75 -0
  58. digitalhub/entities/dataitem/entity/dataitem.py +9 -0
  59. digitalhub/entities/dataitem/entity/iceberg.py +7 -0
  60. digitalhub/entities/dataitem/entity/table.py +125 -0
  61. digitalhub/entities/dataitem/models.py +62 -0
  62. digitalhub/entities/dataitem/spec.py +61 -0
  63. digitalhub/entities/dataitem/status.py +38 -0
  64. digitalhub/entities/entity_types.py +19 -0
  65. digitalhub/entities/function/__init__.py +0 -0
  66. digitalhub/entities/function/builder.py +86 -0
  67. digitalhub/entities/function/crud.py +305 -0
  68. digitalhub/entities/function/entity.py +101 -0
  69. digitalhub/entities/function/models.py +118 -0
  70. digitalhub/entities/function/spec.py +81 -0
  71. digitalhub/entities/function/status.py +9 -0
  72. digitalhub/entities/model/__init__.py +0 -0
  73. digitalhub/entities/model/builder.py +152 -0
  74. digitalhub/entities/model/crud.py +358 -0
  75. digitalhub/entities/model/entity/__init__.py +0 -0
  76. digitalhub/entities/model/entity/_base.py +34 -0
  77. digitalhub/entities/model/entity/huggingface.py +9 -0
  78. digitalhub/entities/model/entity/mlflow.py +90 -0
  79. digitalhub/entities/model/entity/model.py +9 -0
  80. digitalhub/entities/model/entity/sklearn.py +9 -0
  81. digitalhub/entities/model/models.py +26 -0
  82. digitalhub/entities/model/spec.py +146 -0
  83. digitalhub/entities/model/status.py +33 -0
  84. digitalhub/entities/project/__init__.py +0 -0
  85. digitalhub/entities/project/builder.py +82 -0
  86. digitalhub/entities/project/crud.py +350 -0
  87. digitalhub/entities/project/entity.py +2060 -0
  88. digitalhub/entities/project/spec.py +50 -0
  89. digitalhub/entities/project/status.py +9 -0
  90. digitalhub/entities/registries.py +48 -0
  91. digitalhub/entities/run/__init__.py +0 -0
  92. digitalhub/entities/run/builder.py +77 -0
  93. digitalhub/entities/run/crud.py +232 -0
  94. digitalhub/entities/run/entity.py +461 -0
  95. digitalhub/entities/run/spec.py +153 -0
  96. digitalhub/entities/run/status.py +114 -0
  97. digitalhub/entities/secret/__init__.py +0 -0
  98. digitalhub/entities/secret/builder.py +93 -0
  99. digitalhub/entities/secret/crud.py +294 -0
  100. digitalhub/entities/secret/entity.py +73 -0
  101. digitalhub/entities/secret/spec.py +35 -0
  102. digitalhub/entities/secret/status.py +9 -0
  103. digitalhub/entities/task/__init__.py +0 -0
  104. digitalhub/entities/task/builder.py +74 -0
  105. digitalhub/entities/task/crud.py +241 -0
  106. digitalhub/entities/task/entity.py +135 -0
  107. digitalhub/entities/task/models.py +199 -0
  108. digitalhub/entities/task/spec.py +51 -0
  109. digitalhub/entities/task/status.py +9 -0
  110. digitalhub/entities/utils.py +184 -0
  111. digitalhub/entities/workflow/__init__.py +0 -0
  112. digitalhub/entities/workflow/builder.py +91 -0
  113. digitalhub/entities/workflow/crud.py +304 -0
  114. digitalhub/entities/workflow/entity.py +77 -0
  115. digitalhub/entities/workflow/spec.py +15 -0
  116. digitalhub/entities/workflow/status.py +9 -0
  117. digitalhub/readers/__init__.py +0 -0
  118. digitalhub/readers/builder.py +54 -0
  119. digitalhub/readers/objects/__init__.py +0 -0
  120. digitalhub/readers/objects/base.py +70 -0
  121. digitalhub/readers/objects/pandas.py +207 -0
  122. digitalhub/readers/registry.py +15 -0
  123. digitalhub/registry/__init__.py +0 -0
  124. digitalhub/registry/models.py +87 -0
  125. digitalhub/registry/registry.py +74 -0
  126. digitalhub/registry/utils.py +150 -0
  127. digitalhub/runtimes/__init__.py +0 -0
  128. digitalhub/runtimes/base.py +164 -0
  129. digitalhub/runtimes/builder.py +53 -0
  130. digitalhub/runtimes/kind_registry.py +170 -0
  131. digitalhub/stores/__init__.py +0 -0
  132. digitalhub/stores/builder.py +257 -0
  133. digitalhub/stores/objects/__init__.py +0 -0
  134. digitalhub/stores/objects/base.py +189 -0
  135. digitalhub/stores/objects/local.py +230 -0
  136. digitalhub/stores/objects/remote.py +143 -0
  137. digitalhub/stores/objects/s3.py +563 -0
  138. digitalhub/stores/objects/sql.py +328 -0
  139. digitalhub/utils/__init__.py +0 -0
  140. digitalhub/utils/data_utils.py +127 -0
  141. digitalhub/utils/env_utils.py +123 -0
  142. digitalhub/utils/exceptions.py +55 -0
  143. digitalhub/utils/file_utils.py +204 -0
  144. digitalhub/utils/generic_utils.py +207 -0
  145. digitalhub/utils/git_utils.py +148 -0
  146. digitalhub/utils/io_utils.py +79 -0
  147. digitalhub/utils/logger.py +17 -0
  148. digitalhub/utils/uri_utils.py +56 -0
  149. {digitalhub-0.8.0b0.dist-info → digitalhub-0.8.0b1.dist-info}/METADATA +27 -12
  150. digitalhub-0.8.0b1.dist-info/RECORD +161 -0
  151. test/test_crud_artifacts.py +1 -1
  152. test/test_crud_dataitems.py +1 -1
  153. test/test_crud_functions.py +1 -1
  154. test/test_crud_runs.py +1 -1
  155. test/test_crud_tasks.py +1 -1
  156. digitalhub-0.8.0b0.dist-info/RECORD +0 -14
  157. {digitalhub-0.8.0b0.dist-info → digitalhub-0.8.0b1.dist-info}/LICENSE.txt +0 -0
  158. {digitalhub-0.8.0b0.dist-info → digitalhub-0.8.0b1.dist-info}/WHEEL +0 -0
  159. {digitalhub-0.8.0b0.dist-info → digitalhub-0.8.0b1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,461 @@
1
+ from __future__ import annotations
2
+
3
+ import time
4
+ import typing
5
+ from typing import Any
6
+
7
+ import requests
8
+
9
+ from digitalhub.entities._base.crud import (
10
+ list_entity_api_base,
11
+ list_entity_api_ctx,
12
+ logs_api,
13
+ read_entity_api_ctx,
14
+ resume_api,
15
+ stop_api,
16
+ )
17
+ from digitalhub.entities._base.entity.unversioned import UnversionedEntity
18
+ from digitalhub.entities._base.state import State
19
+ from digitalhub.entities._builders.spec import build_spec
20
+ from digitalhub.entities._builders.status import build_status
21
+ from digitalhub.entities.entity_types import EntityTypes
22
+ from digitalhub.registry.registry import registry
23
+ from digitalhub.runtimes.builder import build_runtime
24
+ from digitalhub.utils.exceptions import EntityError
25
+ from digitalhub.utils.logger import LOGGER
26
+
27
+ if typing.TYPE_CHECKING:
28
+ from digitalhub.entities._base.entity.material import MaterialEntity
29
+ from digitalhub.entities._base.metadata import Metadata
30
+ from digitalhub.entities.run.spec import RunSpec
31
+ from digitalhub.entities.run.status import RunStatus
32
+ from digitalhub.runtimes.base import Runtime
33
+
34
+
35
+ class Run(UnversionedEntity):
36
+ """
37
+ A class representing a run.
38
+ """
39
+
40
+ ENTITY_TYPE = EntityTypes.RUN.value
41
+
42
+ def __init__(
43
+ self,
44
+ project: str,
45
+ uuid: str,
46
+ kind: str,
47
+ metadata: Metadata,
48
+ spec: RunSpec,
49
+ status: RunStatus,
50
+ user: str | None = None,
51
+ ) -> None:
52
+ super().__init__(project, uuid, kind, metadata, spec, status, user)
53
+
54
+ self.spec: RunSpec
55
+ self.status: RunStatus
56
+
57
+ ##############################
58
+ # Run Methods
59
+ ##############################
60
+
61
+ def build(self) -> None:
62
+ """
63
+ Build run.
64
+
65
+ Returns
66
+ -------
67
+ None
68
+ """
69
+ runtime = self._get_runtime()
70
+ executable = self._get_executable(runtime)
71
+ task = self._get_task(runtime)
72
+ new_spec = runtime.build(executable, task, self.to_dict())
73
+ self.spec = build_spec(
74
+ self.kind,
75
+ **new_spec,
76
+ )
77
+ self._set_state(State.BUILT.value)
78
+ self.save()
79
+
80
+ def run(self) -> Run:
81
+ """
82
+ Run run.
83
+
84
+ Returns
85
+ -------
86
+ Run
87
+ Run object.
88
+ """
89
+ self.refresh()
90
+ if self.spec.local_execution:
91
+ if not self._is_ready_to_run():
92
+ raise EntityError("Run is not in a state to run.")
93
+ self._set_state(State.RUNNING.value)
94
+ self.save(update=True)
95
+
96
+ # Try to get inputs if they exist
97
+ try:
98
+ self.spec.inputs = self.inputs(as_dict=True)
99
+ except EntityError:
100
+ pass
101
+
102
+ try:
103
+ status = self._get_runtime().run(self.to_dict())
104
+ except Exception as e:
105
+ self.refresh()
106
+ if self.spec.local_execution:
107
+ self._set_state(State.ERROR.value)
108
+ self._set_message(str(e))
109
+ self.save(update=True)
110
+ raise e
111
+
112
+ self.refresh()
113
+ if not self.spec.local_execution:
114
+ status.pop("state", None)
115
+ new_status = {**self.status.to_dict(), **status}
116
+ self._set_status(new_status)
117
+ self.save(update=True)
118
+ return self
119
+
120
+ def wait(self, log_info: bool = True) -> Run:
121
+ """
122
+ Wait for run to finish.
123
+
124
+ Parameters
125
+ ----------
126
+ log_info : bool
127
+ If True, log information.
128
+
129
+ Returns
130
+ -------
131
+ Run
132
+ Run object.
133
+ """
134
+ start = time.time()
135
+ while True:
136
+ if log_info:
137
+ LOGGER.info(f"Waiting for run {self.id} to finish...")
138
+ self.refresh()
139
+ time.sleep(5)
140
+ if self.status.state in [
141
+ State.STOPPED.value,
142
+ State.ERROR.value,
143
+ State.COMPLETED.value,
144
+ ]:
145
+ if log_info:
146
+ current = time.time() - start
147
+ LOGGER.info(f"Run {self.id} finished in {current:.2f} seconds.")
148
+ return self
149
+
150
+ def inputs(self, as_dict: bool = False) -> list[dict]:
151
+ """
152
+ Get inputs passed in spec as objects or as dictionaries.
153
+
154
+ Parameters
155
+ ----------
156
+ as_dict : bool
157
+ If True, return inputs as dictionaries.
158
+
159
+ Returns
160
+ -------
161
+ list[dict]
162
+ List of input objects.
163
+ """
164
+ try:
165
+ return self.spec.get_inputs(as_dict=as_dict)
166
+ except AttributeError:
167
+ msg = f"Run of type {self.kind} has no inputs."
168
+ raise EntityError(msg)
169
+
170
+ def results(self) -> dict:
171
+ """
172
+ Get results from runtime execution.
173
+
174
+ Returns
175
+ -------
176
+ dict
177
+ Results.
178
+ """
179
+ try:
180
+ return self.status.get_results()
181
+ except AttributeError:
182
+ msg = f"Run of type {self.kind} has no results."
183
+ raise EntityError(msg)
184
+
185
+ def result(self, key: str) -> Any:
186
+ """
187
+ Get result from runtime execution by key.
188
+
189
+ Parameters
190
+ ----------
191
+ key : str
192
+ Key of the result.
193
+
194
+ Returns
195
+ -------
196
+ Any
197
+ Result.
198
+ """
199
+ return self.results().get(key)
200
+
201
+ def outputs(self, as_key: bool = False, as_dict: bool = False) -> dict:
202
+ """
203
+ Get run objects results.
204
+
205
+ Parameters
206
+ ----------
207
+ as_key : bool
208
+ If True, return results as keys.
209
+ as_dict : bool
210
+ If True, return results as dictionaries.
211
+
212
+ Returns
213
+ -------
214
+ dict
215
+ List of output objects.
216
+ """
217
+ try:
218
+ return self.status.get_outputs(as_key=as_key, as_dict=as_dict)
219
+ except AttributeError:
220
+ msg = f"Run of type {self.kind} has no outputs."
221
+ raise EntityError(msg)
222
+
223
+ def output(self, key: str, as_key: bool = False, as_dict: bool = False) -> MaterialEntity | dict | str | None:
224
+ """
225
+ Get run object result by key.
226
+
227
+ Parameters
228
+ ----------
229
+ key : str
230
+ Key of the result.
231
+ as_key : bool
232
+ If True, return result as key.
233
+ as_dict : bool
234
+ If True, return result as dictionary.
235
+
236
+ Returns
237
+ -------
238
+ Entity | dict | str | None
239
+ Result.
240
+ """
241
+ return self.outputs(as_key=as_key, as_dict=as_dict).get(key)
242
+
243
+ def values(self) -> dict:
244
+ """
245
+ Get values from runtime execution.
246
+
247
+ Returns
248
+ -------
249
+ dict
250
+ Values from backend.
251
+ """
252
+ try:
253
+ value_list = getattr(self.spec, "values", [])
254
+ value_list = value_list if value_list is not None else []
255
+ return self.status.get_values(value_list)
256
+ except AttributeError:
257
+ msg = f"Run of type {self.kind} has no values."
258
+ raise EntityError(msg)
259
+
260
+ def logs(self) -> dict:
261
+ """
262
+ Get object from backend.
263
+ Returns empty dictionary if context is local.
264
+
265
+ Returns
266
+ -------
267
+ dict
268
+ Logs from backend.
269
+ """
270
+ if self._context().local:
271
+ return {}
272
+ return logs_api(self.project, self.ENTITY_TYPE, self.id)
273
+
274
+ def stop(self) -> None:
275
+ """
276
+ Stop run.
277
+
278
+ Returns
279
+ -------
280
+ None
281
+ """
282
+ if not self._context().local and not self.spec.local_execution:
283
+ return stop_api(self.project, self.ENTITY_TYPE, self.id)
284
+ try:
285
+ self.status.stop()
286
+ except AttributeError:
287
+ raise EntityError("Stop is not supported in local execution.")
288
+ return
289
+
290
+ def resume(self) -> None:
291
+ """
292
+ Resume run.
293
+
294
+ Returns
295
+ -------
296
+ None
297
+ """
298
+ if not self._context().local and not self.spec.local_execution:
299
+ return resume_api(self.project, self.ENTITY_TYPE, self.id)
300
+
301
+ try:
302
+ self.status.resume()
303
+ except AttributeError:
304
+ raise EntityError("Resume is not supported in local execution.")
305
+ return
306
+ # re-run
307
+ # TODO verify the logic and order
308
+ self.run()
309
+
310
+ def invoke(self, **kwargs) -> requests.Response:
311
+ """
312
+ Invoke run.
313
+
314
+ Parameters
315
+ ----------
316
+ kwargs
317
+ Keyword arguments to pass to the request.
318
+
319
+ Returns
320
+ -------
321
+ requests.Response
322
+ Response from service.
323
+ """
324
+ try:
325
+ if not self._context().local and not self.spec.local_execution:
326
+ local = False
327
+ else:
328
+ local = True
329
+ if kwargs is None:
330
+ kwargs = {}
331
+ return self.status.invoke(local, **kwargs)
332
+ except AttributeError:
333
+ msg = f"Run of type {self.kind} has no invoke operation."
334
+ raise EntityError(msg)
335
+
336
+ ##############################
337
+ # Helpers
338
+ ##############################
339
+
340
+ def _is_ready_to_run(self) -> bool:
341
+ """
342
+ Check if run is in a state ready for running (BUILT or STOPPED).
343
+
344
+ Returns
345
+ -------
346
+ bool
347
+ True if run is in runnable state, False otherwise.
348
+ """
349
+ return (self.status.state == State.BUILT.value) or (self.status.state == State.STOPPED.value)
350
+
351
+ def _set_status(self, status: dict) -> None:
352
+ """
353
+ Set run status.
354
+
355
+ Parameters
356
+ ----------
357
+ status : dict
358
+ Status to set.
359
+
360
+ Returns
361
+ -------
362
+ None
363
+ """
364
+ self.status: RunStatus = build_status(self.kind, **status)
365
+
366
+ def _set_state(self, state: str) -> None:
367
+ """
368
+ Update run state.
369
+
370
+ Parameters
371
+ ----------
372
+ state : str
373
+ State to set.
374
+
375
+ Returns
376
+ -------
377
+ None
378
+ """
379
+ self.status.state = state
380
+
381
+ def _set_message(self, message: str) -> None:
382
+ """
383
+ Update run message.
384
+
385
+ Parameters
386
+ ----------
387
+ message : str
388
+ Message to set.
389
+
390
+ Returns
391
+ -------
392
+ None
393
+ """
394
+ self.status.message = message
395
+
396
+ def _get_runtime(self) -> Runtime:
397
+ """
398
+ Build runtime to build run or execute it.
399
+
400
+ Returns
401
+ -------
402
+ Runtime
403
+ Runtime object.
404
+ """
405
+ return build_runtime(self.kind, self.project)
406
+
407
+ def _get_executable(self, runtime: Runtime) -> dict:
408
+ """
409
+ Get object from backend. Reimplemented to avoid circular imports.
410
+
411
+ Parameters
412
+ ----------
413
+ runtime : Runtime
414
+ Runtime object.
415
+
416
+ Returns
417
+ -------
418
+ dict
419
+ Executable (function or workflow) from backend.
420
+ """
421
+ exec_kind = runtime.get_executable_kind()
422
+ entity_type = registry.get_entity_type(exec_kind)
423
+ splitted = self.spec.task.split("/")
424
+ exec_name = splitted[-1].split(":")[0]
425
+ exec_id = splitted[-1].split(":")[1]
426
+ return read_entity_api_ctx(
427
+ exec_name,
428
+ entity_type=entity_type,
429
+ project=self.project,
430
+ entity_id=exec_id,
431
+ )
432
+
433
+ def _get_task(self, runtime: Runtime) -> dict:
434
+ """
435
+ Get object from backend. Reimplemented to avoid circular imports.
436
+
437
+ Parameters
438
+ ----------
439
+ runtime : Runtime
440
+ Runtime object.
441
+
442
+ Returns
443
+ -------
444
+ dict
445
+ Task from backend.
446
+ """
447
+ executable_kind = runtime.get_executable_kind()
448
+ exec_string = f"{executable_kind}://{self.spec.task.split('://')[1]}"
449
+
450
+ # Local backend
451
+ if self._context().local:
452
+ tasks = list_entity_api_base(self._context().client, EntityTypes.TASK.value)
453
+ for i in tasks:
454
+ if i.get("spec").get("function") == exec_string:
455
+ return i
456
+ raise EntityError("Task not found.")
457
+
458
+ # Remote backend
459
+ task_kind = self.spec.task.split("://")[0]
460
+ params = {"function": exec_string, "kind": task_kind}
461
+ return list_entity_api_ctx(self.project, EntityTypes.TASK.value, params=params)[0]
@@ -0,0 +1,153 @@
1
+ from __future__ import annotations
2
+
3
+ import typing
4
+
5
+ from digitalhub.entities._base.spec.base import Spec, SpecParams
6
+ from digitalhub.entities.artifact.crud import get_artifact
7
+ from digitalhub.entities.dataitem.crud import get_dataitem
8
+ from digitalhub.entities.entity_types import EntityTypes
9
+ from digitalhub.entities.model.crud import get_model
10
+ from digitalhub.entities.task.models import K8s
11
+ from digitalhub.entities.utils import parse_entity_key
12
+
13
+ if typing.TYPE_CHECKING:
14
+ from digitalhub.entities._base.entity.base import Entity
15
+
16
+
17
+ ENTITY_FUNC = {
18
+ EntityTypes.ARTIFACT.value: get_artifact,
19
+ EntityTypes.DATAITEM.value: get_dataitem,
20
+ EntityTypes.MODEL.value: get_model,
21
+ }
22
+
23
+
24
+ class RunSpec(Spec):
25
+ """Run specification."""
26
+
27
+ def __init__(
28
+ self,
29
+ task: str,
30
+ local_execution: bool = False,
31
+ function: str | None = None,
32
+ node_selector: dict | None = None,
33
+ volumes: list | None = None,
34
+ resources: dict | None = None,
35
+ affinity: dict | None = None,
36
+ tolerations: list | None = None,
37
+ envs: list | None = None,
38
+ secrets: list | None = None,
39
+ profile: str | None = None,
40
+ **kwargs,
41
+ ) -> None:
42
+ self.task = task
43
+ self.local_execution = local_execution
44
+ self.function = function
45
+ self.node_selector = node_selector
46
+ self.volumes = volumes
47
+ self.resources = resources
48
+ self.affinity = affinity
49
+ self.tolerations = tolerations
50
+ self.envs = envs
51
+ self.secrets = secrets
52
+ self.profile = profile
53
+
54
+ def get_inputs(self, as_dict: bool = False) -> dict:
55
+ """
56
+ Get inputs.
57
+
58
+ Returns
59
+ -------
60
+ dict
61
+ The inputs.
62
+ """
63
+ inputs = {}
64
+ if not hasattr(self, "inputs") or self.inputs is None:
65
+ return inputs
66
+
67
+ for parameter, item in self.inputs.items():
68
+ parameter_type = self._parse_parameter(parameter)
69
+
70
+ # Get entity from key
71
+ if parameter_type == "key":
72
+ key = self._collect_key(item)
73
+ entity = self._collect_entity(key)
74
+ if as_dict:
75
+ entity = entity.to_dict()
76
+ inputs[parameter] = entity
77
+
78
+ # Create entity from parameter
79
+ elif parameter_type == "create":
80
+ raise NotImplementedError
81
+
82
+ return inputs
83
+
84
+ @staticmethod
85
+ def _parse_parameter(parameter: str) -> str:
86
+ """
87
+ Parse parameter.
88
+
89
+ Parameters
90
+ ----------
91
+ parameter : str
92
+ Parameter.
93
+
94
+ Returns
95
+ -------
96
+ str
97
+ The parsed parameter.
98
+ """
99
+ if len(parameter.split(":")) == 1:
100
+ return "key"
101
+ return "create"
102
+
103
+ @staticmethod
104
+ def _collect_key(item: str | dict) -> str:
105
+ """
106
+ Collect key from item.
107
+
108
+ Parameters
109
+ ----------
110
+ item : str | dict
111
+ Key or dict representation of the entity.
112
+
113
+ Returns
114
+ -------
115
+ str
116
+ The key.
117
+ """
118
+ if isinstance(item, str):
119
+ return item
120
+ return item.get("key")
121
+
122
+ @staticmethod
123
+ def _collect_entity(key: str) -> Entity:
124
+ """
125
+ Collect entity from key.
126
+
127
+ Parameters
128
+ ----------
129
+ key : str
130
+ Key of the entity.
131
+
132
+ Returns
133
+ -------
134
+ Entity
135
+ The entity.
136
+ """
137
+ _, entity_type, _, _, _ = parse_entity_key(key)
138
+ return ENTITY_FUNC[entity_type](key)
139
+
140
+
141
+ class RunParams(SpecParams, K8s):
142
+ """
143
+ Run parameters.
144
+ """
145
+
146
+ function: str = None
147
+ """The function associated with the run."""
148
+
149
+ task: str = None
150
+ """The task string associated with the run."""
151
+
152
+ local_execution: bool = False
153
+ """Flag to indicate if the run will be executed locally."""
@@ -0,0 +1,114 @@
1
+ from __future__ import annotations
2
+
3
+ import typing
4
+
5
+ from digitalhub.entities._base.status.base import Status
6
+ from digitalhub.entities.artifact.crud import get_artifact
7
+ from digitalhub.entities.utils import parse_entity_key
8
+
9
+ if typing.TYPE_CHECKING:
10
+ pass
11
+
12
+ ENTITY_FUNC = {
13
+ "artifacts": get_artifact,
14
+ }
15
+
16
+
17
+ class RunStatus(Status):
18
+ """
19
+ Status class for run entities.
20
+ """
21
+
22
+ def __init__(
23
+ self,
24
+ state: str,
25
+ message: str | None = None,
26
+ outputs: list | None = None,
27
+ results: dict | None = None,
28
+ **kwargs,
29
+ ) -> None:
30
+ super().__init__(state, message)
31
+ self.outputs = outputs
32
+ self.results = results
33
+
34
+ self._any_setter(**kwargs)
35
+
36
+ def get_results(self) -> dict:
37
+ """
38
+ Get results.
39
+
40
+ Returns
41
+ -------
42
+ dict
43
+ The results.
44
+ """
45
+ if not hasattr(self, "results") or self.results is None:
46
+ return {}
47
+ return self.results
48
+
49
+ def get_outputs(self, as_key: bool = False, as_dict: bool = False) -> dict:
50
+ """
51
+ Get outputs.
52
+
53
+ Parameters
54
+ ----------
55
+ as_key : bool
56
+ If True, return outputs as keys.
57
+ as_dict : bool
58
+ If True, return outputs as dictionaries.
59
+
60
+ Returns
61
+ -------
62
+ dict
63
+ The outputs.
64
+ """
65
+ outputs = {}
66
+ if not hasattr(self, "outputs") or self.outputs is None:
67
+ return outputs
68
+
69
+ for parameter, key in self.outputs.items():
70
+ entity_type = self._get_entity_type(key)
71
+ entity = ENTITY_FUNC[entity_type](key)
72
+ if as_key:
73
+ entity = entity.key
74
+ if as_dict:
75
+ entity = entity.to_dict()
76
+ outputs[parameter] = entity
77
+
78
+ return outputs
79
+
80
+ @staticmethod
81
+ def _get_entity_type(key: str) -> str:
82
+ """
83
+ Get entity type.
84
+
85
+ Parameters
86
+ ----------
87
+ key : str
88
+ The key of the entity.
89
+
90
+ Returns
91
+ -------
92
+ str
93
+ The entity type.
94
+ """
95
+ _, entity_type, _, _, _ = parse_entity_key(key)
96
+ return entity_type
97
+
98
+ def get_values(self, values_list: list) -> dict:
99
+ """
100
+ Get values.
101
+
102
+ Parameters
103
+ ----------
104
+ values_list : list
105
+ The values list to search in.
106
+
107
+ Returns
108
+ -------
109
+ dict
110
+ The values.
111
+ """
112
+ if not hasattr(self, "results") or self.results is None:
113
+ return {}
114
+ return {k: v for k, v in self.get_results().items() if k in values_list}