digitalhub 0.9.1__py3-none-any.whl → 0.10.0b0__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 (67) hide show
  1. digitalhub/__init__.py +2 -3
  2. digitalhub/client/_base/client.py +3 -2
  3. digitalhub/client/dhcore/api_builder.py +6 -1
  4. digitalhub/client/dhcore/client.py +27 -399
  5. digitalhub/client/dhcore/configurator.py +339 -0
  6. digitalhub/client/dhcore/error_parser.py +107 -0
  7. digitalhub/client/dhcore/models.py +13 -23
  8. digitalhub/client/dhcore/utils.py +4 -44
  9. digitalhub/client/local/api_builder.py +9 -17
  10. digitalhub/client/local/client.py +12 -2
  11. digitalhub/client/local/enums.py +11 -0
  12. digitalhub/configurator/api.py +31 -0
  13. digitalhub/configurator/configurator.py +194 -0
  14. digitalhub/configurator/credentials_store.py +65 -0
  15. digitalhub/configurator/ini_module.py +74 -0
  16. digitalhub/entities/_base/_base/entity.py +2 -2
  17. digitalhub/entities/_base/material/entity.py +19 -6
  18. digitalhub/entities/_base/material/utils.py +2 -2
  19. digitalhub/entities/_commons/enums.py +1 -0
  20. digitalhub/entities/_commons/models.py +9 -0
  21. digitalhub/entities/_commons/utils.py +25 -0
  22. digitalhub/entities/_operations/processor.py +103 -107
  23. digitalhub/entities/artifact/crud.py +3 -3
  24. digitalhub/entities/dataitem/_base/entity.py +2 -2
  25. digitalhub/entities/dataitem/crud.py +3 -3
  26. digitalhub/entities/dataitem/table/entity.py +2 -2
  27. digitalhub/{utils/data_utils.py → entities/dataitem/table/utils.py} +43 -51
  28. digitalhub/entities/dataitem/utils.py +6 -3
  29. digitalhub/entities/model/_base/entity.py +172 -0
  30. digitalhub/entities/model/_base/spec.py +0 -10
  31. digitalhub/entities/model/_base/status.py +10 -0
  32. digitalhub/entities/model/crud.py +3 -3
  33. digitalhub/entities/model/huggingface/spec.py +6 -3
  34. digitalhub/entities/model/mlflow/models.py +2 -2
  35. digitalhub/entities/model/mlflow/spec.py +1 -3
  36. digitalhub/entities/model/mlflow/utils.py +44 -5
  37. digitalhub/entities/run/_base/entity.py +149 -0
  38. digitalhub/entities/run/_base/status.py +12 -0
  39. digitalhub/entities/task/_base/spec.py +2 -0
  40. digitalhub/entities/task/crud.py +4 -0
  41. digitalhub/readers/{_commons → pandas}/enums.py +4 -0
  42. digitalhub/readers/pandas/reader.py +58 -10
  43. digitalhub/stores/_base/store.py +1 -49
  44. digitalhub/stores/api.py +8 -33
  45. digitalhub/stores/builder.py +44 -161
  46. digitalhub/stores/local/store.py +4 -18
  47. digitalhub/stores/remote/store.py +3 -10
  48. digitalhub/stores/s3/configurator.py +107 -0
  49. digitalhub/stores/s3/enums.py +17 -0
  50. digitalhub/stores/s3/models.py +21 -0
  51. digitalhub/stores/s3/store.py +8 -28
  52. digitalhub/{utils/s3_utils.py → stores/s3/utils.py} +7 -3
  53. digitalhub/stores/sql/configurator.py +88 -0
  54. digitalhub/stores/sql/enums.py +16 -0
  55. digitalhub/stores/sql/models.py +24 -0
  56. digitalhub/stores/sql/store.py +14 -57
  57. digitalhub/utils/exceptions.py +6 -0
  58. digitalhub/utils/generic_utils.py +9 -8
  59. digitalhub/utils/uri_utils.py +1 -1
  60. {digitalhub-0.9.1.dist-info → digitalhub-0.10.0b0.dist-info}/METADATA +5 -6
  61. {digitalhub-0.9.1.dist-info → digitalhub-0.10.0b0.dist-info}/RECORD +66 -53
  62. test/local/imports/test_imports.py +0 -1
  63. digitalhub/client/dhcore/env.py +0 -23
  64. /digitalhub/{readers/_commons → configurator}/__init__.py +0 -0
  65. {digitalhub-0.9.1.dist-info → digitalhub-0.10.0b0.dist-info}/LICENSE.txt +0 -0
  66. {digitalhub-0.9.1.dist-info → digitalhub-0.10.0b0.dist-info}/WHEEL +0 -0
  67. {digitalhub-0.9.1.dist-info → digitalhub-0.10.0b0.dist-info}/top_level.txt +0 -0
@@ -4,6 +4,8 @@ import typing
4
4
 
5
5
  from digitalhub.entities._base.material.entity import MaterialEntity
6
6
  from digitalhub.entities._commons.enums import EntityTypes
7
+ from digitalhub.entities._commons.utils import validate_metric_value
8
+ from digitalhub.entities._operations.processor import processor
7
9
 
8
10
  if typing.TYPE_CHECKING:
9
11
  from digitalhub.entities._base.entity.metadata import Metadata
@@ -32,3 +34,173 @@ class Model(MaterialEntity):
32
34
  super().__init__(project, name, uuid, kind, metadata, spec, status, user)
33
35
  self.spec: ModelSpec
34
36
  self.status: ModelStatus
37
+
38
+ # Initialize metrics
39
+ self._init_metrics()
40
+
41
+ def save(self, update: bool = False) -> Model:
42
+ """
43
+ Save entity into backend.
44
+
45
+ Parameters
46
+ ----------
47
+ update : bool
48
+ Flag to indicate update.
49
+
50
+ Returns
51
+ -------
52
+ Model
53
+ Entity saved.
54
+ """
55
+ obj: Model = super().save(update)
56
+ obj._get_metrics()
57
+ return obj
58
+
59
+ def log_metric(
60
+ self,
61
+ key: str,
62
+ value: list[float | int] | float | int,
63
+ overwrite: bool = False,
64
+ single_value: bool = False,
65
+ ) -> None:
66
+ """
67
+ Log metric into entity status.
68
+ A metric is named by a key and value (single number or list of numbers).
69
+ The metric by default is put in a list or appended to an existing list.
70
+ If single_value is True, the value will be a single number.
71
+
72
+ Parameters
73
+ ----------
74
+ key : str
75
+ Key of the metric.
76
+ value : list[float | int] | float | int
77
+ Value of the metric.
78
+ overwrite : bool
79
+ If True, overwrite existing metric.
80
+ single_value : bool
81
+ If True, value is a single value.
82
+
83
+ Returns
84
+ -------
85
+ None
86
+
87
+ Examples
88
+ --------
89
+ Log a new value in a list
90
+ >>> entity.log_metric("loss", 0.002)
91
+
92
+ Append a new value in a list
93
+ >>> entity.log_metric("loss", 0.0019)
94
+
95
+ Log a list of values and append them to existing metric:
96
+ >>> entity.log_metric("loss", [0.0018, 0.0015])
97
+
98
+ Log a single value (not represented as list):
99
+ >>> entity.log_metric("accuracy", 0.9, single_value=True)
100
+
101
+ Log a list of values and overwrite existing metric:
102
+ >>> entity.log_metric("accuracy", [0.8, 0.9], overwrite=True)
103
+ """
104
+ value = validate_metric_value(value)
105
+
106
+ if isinstance(value, list):
107
+ self._handle_metric_list(key, value, overwrite)
108
+ elif single_value:
109
+ self._handle_metric_single(key, value, overwrite)
110
+ else:
111
+ self._handle_metric_list_append(key, value, overwrite)
112
+
113
+ processor.update_metric(self.project, self.ENTITY_TYPE, self.id, key, self.status.metrics[key])
114
+
115
+ ##############################
116
+ # Helper methods
117
+ ##############################
118
+
119
+ def _init_metrics(self) -> None:
120
+ """
121
+ Initialize metrics.
122
+
123
+ Returns
124
+ -------
125
+ None
126
+ """
127
+ if self.status.metrics is None:
128
+ self.status.metrics = {}
129
+
130
+ def _get_metrics(self) -> None:
131
+ """
132
+ Get model metrics from backend.
133
+
134
+ Returns
135
+ -------
136
+ None
137
+ """
138
+ self.status.metrics = processor.read_metrics(
139
+ project=self.project,
140
+ entity_type=self.ENTITY_TYPE,
141
+ entity_id=self.id,
142
+ )
143
+
144
+ def _handle_metric_single(self, key: str, value: float | int, overwrite: bool = False) -> None:
145
+ """
146
+ Handle metric single value.
147
+
148
+ Parameters
149
+ ----------
150
+ key : str
151
+ Key of the metric.
152
+ value : float
153
+ Value of the metric.
154
+ overwrite : bool
155
+ If True, overwrite existing metric.
156
+
157
+ Returns
158
+ -------
159
+ None
160
+ """
161
+ if key not in self.status.metrics or overwrite:
162
+ self.status.metrics[key] = value
163
+
164
+ def _handle_metric_list_append(self, key: str, value: float | int, overwrite: bool = False) -> None:
165
+ """
166
+ Handle metric list append.
167
+
168
+ Parameters
169
+ ----------
170
+ key : str
171
+ Key of the metric.
172
+ value : float
173
+ Value of the metric.
174
+ overwrite : bool
175
+ If True, overwrite existing metric.
176
+
177
+ Returns
178
+ -------
179
+ None
180
+ """
181
+ if key not in self.status.metrics or overwrite:
182
+ self.status.metrics[key] = [value]
183
+ else:
184
+ self.status.metrics[key].append(value)
185
+
186
+ def _handle_metric_list(self, key: str, value: list[int | float], overwrite: bool = False) -> None:
187
+ """
188
+ Handle metric list.
189
+
190
+ Parameters
191
+ ----------
192
+ key : str
193
+ Key of the metric.
194
+ value : list[int | float]
195
+ Value of the metric.
196
+ overwrite : bool
197
+ If True, overwrite existing metric.
198
+
199
+ Returns
200
+ -------
201
+ None
202
+ """
203
+ if key not in self.status.metrics or overwrite:
204
+ self.status.metrics[key] = value
205
+ else:
206
+ self.status.metrics[key].extend(value)
@@ -13,16 +13,12 @@ class ModelSpec(MaterialSpec):
13
13
  path: str,
14
14
  framework: str | None = None,
15
15
  algorithm: str | None = None,
16
- base_model: str | None = None,
17
16
  parameters: dict | None = None,
18
- metrics: dict | None = None,
19
17
  ) -> None:
20
18
  self.path = path
21
19
  self.framework = framework
22
20
  self.algorithm = algorithm
23
- self.base_model = base_model
24
21
  self.parameters = parameters
25
- self.metrics = metrics
26
22
 
27
23
 
28
24
  class ModelValidator(MaterialValidator):
@@ -39,11 +35,5 @@ class ModelValidator(MaterialValidator):
39
35
  algorithm: str = None
40
36
  """Model algorithm (e.g. 'resnet')."""
41
37
 
42
- base_model: str = None
43
- """Base model."""
44
-
45
38
  parameters: dict = None
46
39
  """Model validator."""
47
-
48
- metrics: dict = None
49
- """Model metrics."""
@@ -7,3 +7,13 @@ class ModelStatus(MaterialStatus):
7
7
  """
8
8
  ModelStatus status.
9
9
  """
10
+
11
+ def __init__(
12
+ self,
13
+ state: str,
14
+ message: str | None = None,
15
+ files: list[dict] | None = None,
16
+ metrics: dict | None = None,
17
+ ):
18
+ super().__init__(state, message, files)
19
+ self.metrics = metrics
@@ -157,7 +157,7 @@ def get_model(
157
157
  >>> project="my-project",
158
158
  >>> entity_id="my-model-id")
159
159
  """
160
- return processor.read_material_entity(
160
+ return processor.read_context_entity(
161
161
  identifier=identifier,
162
162
  entity_type=ENTITY_TYPE,
163
163
  project=project,
@@ -197,7 +197,7 @@ def get_model_versions(
197
197
  >>> objs = get_model_versions("my-model-name",
198
198
  >>> project="my-project")
199
199
  """
200
- return processor.read_material_entity_versions(
200
+ return processor.read_context_entity_versions(
201
201
  identifier=identifier,
202
202
  entity_type=ENTITY_TYPE,
203
203
  project=project,
@@ -225,7 +225,7 @@ def list_models(project: str, **kwargs) -> list[Model]:
225
225
  --------
226
226
  >>> objs = list_models(project="my-project")
227
227
  """
228
- return processor.list_material_entities(
228
+ return processor.list_context_entities(
229
229
  project=project,
230
230
  entity_type=ENTITY_TYPE,
231
231
  **kwargs,
@@ -15,13 +15,13 @@ class ModelSpecHuggingface(ModelSpec):
15
15
  path: str,
16
16
  framework: str | None = None,
17
17
  algorithm: str | None = None,
18
- base_model: str | None = None,
19
18
  parameters: dict | None = None,
20
- metrics: dict | None = None,
19
+ base_model: str | None = None,
21
20
  model_id: str | None = None,
22
21
  model_revision: str = None,
23
22
  ) -> None:
24
- super().__init__(path, framework, algorithm, base_model, parameters, metrics)
23
+ super().__init__(path, framework, algorithm, parameters)
24
+ self.base_model = base_model
25
25
  self.model_id = model_id
26
26
  self.model_revision = model_revision
27
27
 
@@ -31,6 +31,9 @@ class ModelValidatorHuggingface(ModelValidator):
31
31
  ModelValidatorHuggingface validator.
32
32
  """
33
33
 
34
+ base_model: str = None
35
+ """Base model."""
36
+
34
37
  placeholder_model_id: str = Field(default=None, alias="model_id")
35
38
  """Huggingface model id. If not specified, the model is loaded from the model path."""
36
39
 
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from typing import Optional
4
4
 
5
- from pydantic import BaseModel, Field
5
+ from pydantic import BaseModel
6
6
 
7
7
 
8
8
  class Signature(BaseModel):
@@ -26,7 +26,7 @@ class Dataset(BaseModel):
26
26
  name: Optional[str] = None
27
27
  digest: Optional[str] = None
28
28
  profile: Optional[str] = None
29
- schema_: Optional[str] = Field(default=None, alias="schema")
29
+ dataset_schema: Optional[str] = None
30
30
  source: Optional[str] = None
31
31
  source_type: Optional[str] = None
32
32
 
@@ -16,15 +16,13 @@ class ModelSpecMlflow(ModelSpec):
16
16
  path: str,
17
17
  framework: str | None = None,
18
18
  algorithm: str | None = None,
19
- base_model: str | None = None,
20
19
  parameters: dict | None = None,
21
- metrics: dict | None = None,
22
20
  flavor: str | None = None,
23
21
  model_config: dict | None = None,
24
22
  input_datasets: list[Dataset] | None = None,
25
23
  signature: Signature = None,
26
24
  ) -> None:
27
- super().__init__(path, framework, algorithm, base_model, parameters, metrics)
25
+ super().__init__(path, framework, algorithm, parameters)
28
26
  self.flavor = flavor
29
27
  self.model_config = model_config
30
28
  self.input_datasets = input_datasets
@@ -1,11 +1,32 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import typing
3
4
  from urllib.parse import urlparse
4
5
 
5
6
  import mlflow
6
7
 
7
8
  from digitalhub.entities.model.mlflow.models import Dataset, Signature
8
9
 
10
+ if typing.TYPE_CHECKING:
11
+ from mlflow.entities import Run
12
+
13
+
14
+ def get_mlflow_run(run_id: str) -> Run:
15
+ """
16
+ Get MLFlow run.
17
+
18
+ Parameters
19
+ ----------
20
+ run_id : str
21
+ The id of the mlflow run.
22
+
23
+ Returns
24
+ -------
25
+ Run
26
+ The extracted run.
27
+ """
28
+ return mlflow.MlflowClient().get_run(run_id)
29
+
9
30
 
10
31
  def from_mlflow_run(run_id: str) -> dict:
11
32
  """
@@ -23,13 +44,11 @@ def from_mlflow_run(run_id: str) -> dict:
23
44
  """
24
45
 
25
46
  # Get MLFlow run
26
- client = mlflow.MlflowClient()
27
- run = client.get_run(run_id)
47
+ run = get_mlflow_run(run_id)
28
48
 
29
49
  # Extract spec
30
50
  data = run.data
31
51
  parameters = data.params
32
- metrics = data.metrics
33
52
  source_path = urlparse(run.info.artifact_uri).path
34
53
  model_uri = f"runs:/{run_id}/model"
35
54
  model = mlflow.pyfunc.load_model(model_uri=model_uri)
@@ -56,7 +75,7 @@ def from_mlflow_run(run_id: str) -> dict:
56
75
  name=d.dataset.name,
57
76
  digest=d.dataset.digest,
58
77
  profile=d.dataset.profile,
59
- schema=d.dataset.schema,
78
+ dataset_schema=d.dataset.schema,
60
79
  source=d.dataset.source,
61
80
  source_type=d.dataset.source_type,
62
81
  ).to_dict()
@@ -72,7 +91,6 @@ def from_mlflow_run(run_id: str) -> dict:
72
91
  # common properties
73
92
  model_params["framework"] = flavor
74
93
  model_params["parameters"] = parameters
75
- model_params["metrics"] = metrics
76
94
 
77
95
  # specific to MLFlow
78
96
  model_params["flavor"] = flavor
@@ -81,3 +99,24 @@ def from_mlflow_run(run_id: str) -> dict:
81
99
  model_params["signature"] = signature
82
100
 
83
101
  return model_params
102
+
103
+
104
+ def get_mlflow_model_metrics(run_id: str) -> dict:
105
+ """
106
+ Get MLFlow model metrics for a given run id.
107
+
108
+ Parameters
109
+ ----------
110
+ run_id : str
111
+ The id of the mlflow run.
112
+
113
+ Returns
114
+ -------
115
+ dict
116
+ The extracted metrics.
117
+ """
118
+ # Get MLFlow run
119
+ run = get_mlflow_run(run_id)
120
+
121
+ # Extract metrics
122
+ return run.data.metrics
@@ -5,6 +5,7 @@ import typing
5
5
 
6
6
  from digitalhub.entities._base.unversioned.entity import UnversionedEntity
7
7
  from digitalhub.entities._commons.enums import EntityTypes, State
8
+ from digitalhub.entities._commons.utils import validate_metric_value
8
9
  from digitalhub.entities._operations.processor import processor
9
10
  from digitalhub.factory.api import (
10
11
  build_runtime,
@@ -45,6 +46,9 @@ class Run(UnversionedEntity):
45
46
  self.spec: RunSpec
46
47
  self.status: RunStatus
47
48
 
49
+ # Initialize metrics
50
+ self._init_metrics()
51
+
48
52
  ##############################
49
53
  # Run Methods
50
54
  ##############################
@@ -161,6 +165,62 @@ class Run(UnversionedEntity):
161
165
  if not self.spec.local_execution:
162
166
  return processor.resume_run(self.project, self.ENTITY_TYPE, self.id)
163
167
 
168
+ def log_metric(
169
+ self,
170
+ key: str,
171
+ value: list[float | int] | float | int,
172
+ overwrite: bool = False,
173
+ single_value: bool = False,
174
+ ) -> None:
175
+ """
176
+ Log metric into entity status.
177
+ A metric is named by a key and value (single number or list of numbers).
178
+ The metric by default is put in a list or appended to an existing list.
179
+ If single_value is True, the value will be a single number.
180
+
181
+ Parameters
182
+ ----------
183
+ key : str
184
+ Key of the metric.
185
+ value : list[float | int] | float | int
186
+ Value of the metric.
187
+ overwrite : bool
188
+ If True, overwrite existing metric.
189
+ single_value : bool
190
+ If True, value is a single value.
191
+
192
+ Returns
193
+ -------
194
+ None
195
+
196
+ Examples
197
+ --------
198
+ Log a new value in a list
199
+ >>> entity.log_metric("loss", 0.002)
200
+
201
+ Append a new value in a list
202
+ >>> entity.log_metric("loss", 0.0019)
203
+
204
+ Log a list of values and append them to existing metric:
205
+ >>> entity.log_metric("loss", [0.0018, 0.0015])
206
+
207
+ Log a single value (not represented as list):
208
+ >>> entity.log_metric("accuracy", 0.9, single_value=True)
209
+
210
+ Log a list of values and overwrite existing metric:
211
+ >>> entity.log_metric("accuracy", [0.8, 0.9], overwrite=True)
212
+ """
213
+ value = validate_metric_value(value)
214
+
215
+ if isinstance(value, list):
216
+ self._handle_metric_list(key, value, overwrite)
217
+ elif single_value:
218
+ self._handle_metric_single(key, value, overwrite)
219
+ else:
220
+ self._handle_metric_list_append(key, value, overwrite)
221
+
222
+ processor.update_metric(self.project, self.ENTITY_TYPE, self.id, key, self.status.metrics[key])
223
+
164
224
  ##############################
165
225
  # Helpers
166
226
  ##############################
@@ -303,3 +363,92 @@ class Run(UnversionedEntity):
303
363
  entity_type=EntityTypes.TASK.value,
304
364
  project=self.project,
305
365
  ).to_dict()
366
+
367
+ def _init_metrics(self) -> None:
368
+ """
369
+ Initialize metrics.
370
+
371
+ Returns
372
+ -------
373
+ None
374
+ """
375
+ if self.status.metrics is None:
376
+ self.status.metrics = {}
377
+
378
+ def _get_metrics(self) -> None:
379
+ """
380
+ Get run metrics from backend.
381
+
382
+ Returns
383
+ -------
384
+ None
385
+ """
386
+ self.status.metrics = processor.read_metrics(
387
+ project=self.project,
388
+ entity_type=self.ENTITY_TYPE,
389
+ entity_id=self.id,
390
+ )
391
+
392
+ def _handle_metric_single(self, key: str, value: float | int, overwrite: bool = False) -> None:
393
+ """
394
+ Handle metric single value.
395
+
396
+ Parameters
397
+ ----------
398
+ key : str
399
+ Key of the metric.
400
+ value : float
401
+ Value of the metric.
402
+ overwrite : bool
403
+ If True, overwrite existing metric.
404
+
405
+ Returns
406
+ -------
407
+ None
408
+ """
409
+ if key not in self.status.metrics or overwrite:
410
+ self.status.metrics[key] = value
411
+
412
+ def _handle_metric_list_append(self, key: str, value: float | int, overwrite: bool = False) -> None:
413
+ """
414
+ Handle metric list append.
415
+
416
+ Parameters
417
+ ----------
418
+ key : str
419
+ Key of the metric.
420
+ value : float
421
+ Value of the metric.
422
+ overwrite : bool
423
+ If True, overwrite existing metric.
424
+
425
+ Returns
426
+ -------
427
+ None
428
+ """
429
+ if key not in self.status.metrics or overwrite:
430
+ self.status.metrics[key] = [value]
431
+ else:
432
+ self.status.metrics[key].append(value)
433
+
434
+ def _handle_metric_list(self, key: str, value: list[int | float], overwrite: bool = False) -> None:
435
+ """
436
+ Handle metric list.
437
+
438
+ Parameters
439
+ ----------
440
+ key : str
441
+ Key of the metric.
442
+ value : list[int | float]
443
+ Value of the metric.
444
+ overwrite : bool
445
+ If True, overwrite existing metric.
446
+
447
+ Returns
448
+ -------
449
+ None
450
+ """
451
+ if key not in self.status.metrics or overwrite:
452
+ self.status.metrics[key] = value
453
+ else:
454
+ self.status.metrics[key].extend(value)
@@ -7,3 +7,15 @@ class RunStatus(Status):
7
7
  """
8
8
  RunStatus status.
9
9
  """
10
+
11
+ def __init__(
12
+ self,
13
+ state: str,
14
+ message: str | None = None,
15
+ transitions: list[dict] | None = None,
16
+ k8s: dict | None = None,
17
+ metrics: dict | None = None,
18
+ **kwargs,
19
+ ) -> None:
20
+ super().__init__(state, message, transitions, k8s, **kwargs)
21
+ self.metrics = metrics
@@ -66,6 +66,8 @@ class TaskSpecWorkflow(TaskSpec):
66
66
  self.envs = envs
67
67
  self.secrets = secrets
68
68
  self.profile = profile
69
+ self.runtime_class = runtime_class
70
+ self.priority_class = priority_class
69
71
 
70
72
 
71
73
  class TaskValidator(SpecValidator):
@@ -19,6 +19,7 @@ def new_task(
19
19
  uuid: str | None = None,
20
20
  labels: list[str] | None = None,
21
21
  function: str | None = None,
22
+ workflow: str | None = None,
22
23
  **kwargs,
23
24
  ) -> Task:
24
25
  """
@@ -36,6 +37,8 @@ def new_task(
36
37
  List of labels.
37
38
  function : str
38
39
  Name of the executable associated with the task.
40
+ workflow : str
41
+ Name of the workflow associated with the task.
39
42
  **kwargs : dict
40
43
  Spec keyword arguments.
41
44
 
@@ -56,6 +59,7 @@ def new_task(
56
59
  uuid=uuid,
57
60
  labels=labels,
58
61
  function=function,
62
+ workflow=workflow,
59
63
  **kwargs,
60
64
  )
61
65
 
@@ -10,4 +10,8 @@ class Extensions(Enum):
10
10
 
11
11
  CSV = "csv"
12
12
  PARQUET = "parquet"
13
+ JSON = "json"
14
+ EXCEL_OLD = "xls"
15
+ EXCEL = "xlsx"
16
+ TXT = "txt"
13
17
  FILE = "file"