digitalhub 0.7.0b2__py3-none-any.whl → 0.8.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of digitalhub might be problematic. Click here for more details.
- digitalhub/__init__.py +63 -93
- digitalhub/client/__init__.py +0 -0
- digitalhub/client/_base/__init__.py +0 -0
- digitalhub/client/_base/client.py +56 -0
- digitalhub/client/api.py +63 -0
- digitalhub/client/builder.py +50 -0
- digitalhub/client/dhcore/__init__.py +0 -0
- digitalhub/client/dhcore/client.py +669 -0
- digitalhub/client/dhcore/env.py +21 -0
- digitalhub/client/dhcore/models.py +46 -0
- digitalhub/client/dhcore/utils.py +111 -0
- digitalhub/client/local/__init__.py +0 -0
- digitalhub/client/local/client.py +533 -0
- digitalhub/context/__init__.py +0 -0
- digitalhub/context/api.py +93 -0
- digitalhub/context/builder.py +94 -0
- digitalhub/context/context.py +136 -0
- digitalhub/datastores/__init__.py +0 -0
- digitalhub/datastores/_base/__init__.py +0 -0
- digitalhub/datastores/_base/datastore.py +85 -0
- digitalhub/datastores/api.py +37 -0
- digitalhub/datastores/builder.py +110 -0
- digitalhub/datastores/local/__init__.py +0 -0
- digitalhub/datastores/local/datastore.py +50 -0
- digitalhub/datastores/remote/__init__.py +0 -0
- digitalhub/datastores/remote/datastore.py +31 -0
- digitalhub/datastores/s3/__init__.py +0 -0
- digitalhub/datastores/s3/datastore.py +46 -0
- digitalhub/datastores/sql/__init__.py +0 -0
- digitalhub/datastores/sql/datastore.py +68 -0
- digitalhub/entities/__init__.py +0 -0
- digitalhub/entities/_base/__init__.py +0 -0
- digitalhub/entities/_base/_base/__init__.py +0 -0
- digitalhub/entities/_base/_base/entity.py +82 -0
- digitalhub/entities/_base/api_utils.py +620 -0
- digitalhub/entities/_base/context/__init__.py +0 -0
- digitalhub/entities/_base/context/entity.py +118 -0
- digitalhub/entities/_base/crud.py +468 -0
- digitalhub/entities/_base/entity/__init__.py +0 -0
- digitalhub/entities/_base/entity/_constructors/__init__.py +0 -0
- digitalhub/entities/_base/entity/_constructors/metadata.py +44 -0
- digitalhub/entities/_base/entity/_constructors/name.py +31 -0
- digitalhub/entities/_base/entity/_constructors/spec.py +33 -0
- digitalhub/entities/_base/entity/_constructors/status.py +52 -0
- digitalhub/entities/_base/entity/_constructors/uuid.py +26 -0
- digitalhub/entities/_base/entity/builder.py +175 -0
- digitalhub/entities/_base/entity/entity.py +106 -0
- digitalhub/entities/_base/entity/metadata.py +59 -0
- digitalhub/entities/_base/entity/spec.py +58 -0
- digitalhub/entities/_base/entity/status.py +43 -0
- digitalhub/entities/_base/executable/__init__.py +0 -0
- digitalhub/entities/_base/executable/entity.py +405 -0
- digitalhub/entities/_base/material/__init__.py +0 -0
- digitalhub/entities/_base/material/entity.py +214 -0
- digitalhub/entities/_base/material/spec.py +22 -0
- digitalhub/entities/_base/material/status.py +49 -0
- digitalhub/entities/_base/runtime_entity/__init__.py +0 -0
- digitalhub/entities/_base/runtime_entity/builder.py +106 -0
- digitalhub/entities/_base/unversioned/__init__.py +0 -0
- digitalhub/entities/_base/unversioned/builder.py +66 -0
- digitalhub/entities/_base/unversioned/entity.py +49 -0
- digitalhub/entities/_base/versioned/__init__.py +0 -0
- digitalhub/entities/_base/versioned/builder.py +68 -0
- digitalhub/entities/_base/versioned/entity.py +53 -0
- digitalhub/entities/artifact/__init__.py +0 -0
- digitalhub/entities/artifact/_base/__init__.py +0 -0
- digitalhub/entities/artifact/_base/builder.py +86 -0
- digitalhub/entities/artifact/_base/entity.py +39 -0
- digitalhub/entities/artifact/_base/spec.py +15 -0
- digitalhub/entities/artifact/_base/status.py +9 -0
- digitalhub/entities/artifact/artifact/__init__.py +0 -0
- digitalhub/entities/artifact/artifact/builder.py +18 -0
- digitalhub/entities/artifact/artifact/entity.py +32 -0
- digitalhub/entities/artifact/artifact/spec.py +27 -0
- digitalhub/entities/artifact/artifact/status.py +15 -0
- digitalhub/entities/artifact/crud.py +332 -0
- digitalhub/entities/builders.py +63 -0
- digitalhub/entities/dataitem/__init__.py +0 -0
- digitalhub/entities/dataitem/_base/__init__.py +0 -0
- digitalhub/entities/dataitem/_base/builder.py +86 -0
- digitalhub/entities/dataitem/_base/entity.py +75 -0
- digitalhub/entities/dataitem/_base/spec.py +15 -0
- digitalhub/entities/dataitem/_base/status.py +20 -0
- digitalhub/entities/dataitem/crud.py +372 -0
- digitalhub/entities/dataitem/dataitem/__init__.py +0 -0
- digitalhub/entities/dataitem/dataitem/builder.py +18 -0
- digitalhub/entities/dataitem/dataitem/entity.py +32 -0
- digitalhub/entities/dataitem/dataitem/spec.py +15 -0
- digitalhub/entities/dataitem/dataitem/status.py +9 -0
- digitalhub/entities/dataitem/iceberg/__init__.py +0 -0
- digitalhub/entities/dataitem/iceberg/builder.py +18 -0
- digitalhub/entities/dataitem/iceberg/entity.py +32 -0
- digitalhub/entities/dataitem/iceberg/spec.py +15 -0
- digitalhub/entities/dataitem/iceberg/status.py +9 -0
- digitalhub/entities/dataitem/table/__init__.py +0 -0
- digitalhub/entities/dataitem/table/builder.py +18 -0
- digitalhub/entities/dataitem/table/entity.py +146 -0
- digitalhub/entities/dataitem/table/models.py +62 -0
- digitalhub/entities/dataitem/table/spec.py +25 -0
- digitalhub/entities/dataitem/table/status.py +9 -0
- digitalhub/entities/function/__init__.py +0 -0
- digitalhub/entities/function/_base/__init__.py +0 -0
- digitalhub/entities/function/_base/builder.py +79 -0
- digitalhub/entities/function/_base/entity.py +98 -0
- digitalhub/entities/function/_base/models.py +118 -0
- digitalhub/entities/function/_base/spec.py +15 -0
- digitalhub/entities/function/_base/status.py +9 -0
- digitalhub/entities/function/crud.py +279 -0
- digitalhub/entities/model/__init__.py +0 -0
- digitalhub/entities/model/_base/__init__.py +0 -0
- digitalhub/entities/model/_base/builder.py +86 -0
- digitalhub/entities/model/_base/entity.py +34 -0
- digitalhub/entities/model/_base/spec.py +49 -0
- digitalhub/entities/model/_base/status.py +9 -0
- digitalhub/entities/model/crud.py +331 -0
- digitalhub/entities/model/huggingface/__init__.py +0 -0
- digitalhub/entities/model/huggingface/builder.py +18 -0
- digitalhub/entities/model/huggingface/entity.py +32 -0
- digitalhub/entities/model/huggingface/spec.py +36 -0
- digitalhub/entities/model/huggingface/status.py +9 -0
- digitalhub/entities/model/mlflow/__init__.py +0 -0
- digitalhub/entities/model/mlflow/builder.py +18 -0
- digitalhub/entities/model/mlflow/entity.py +32 -0
- digitalhub/entities/model/mlflow/models.py +26 -0
- digitalhub/entities/model/mlflow/spec.py +44 -0
- digitalhub/entities/model/mlflow/status.py +9 -0
- digitalhub/entities/model/mlflow/utils.py +81 -0
- digitalhub/entities/model/model/__init__.py +0 -0
- digitalhub/entities/model/model/builder.py +18 -0
- digitalhub/entities/model/model/entity.py +32 -0
- digitalhub/entities/model/model/spec.py +15 -0
- digitalhub/entities/model/model/status.py +9 -0
- digitalhub/entities/model/sklearn/__init__.py +0 -0
- digitalhub/entities/model/sklearn/builder.py +18 -0
- digitalhub/entities/model/sklearn/entity.py +32 -0
- digitalhub/entities/model/sklearn/spec.py +15 -0
- digitalhub/entities/model/sklearn/status.py +9 -0
- digitalhub/entities/project/__init__.py +0 -0
- digitalhub/entities/project/_base/__init__.py +0 -0
- digitalhub/entities/project/_base/builder.py +128 -0
- digitalhub/entities/project/_base/entity.py +2078 -0
- digitalhub/entities/project/_base/spec.py +50 -0
- digitalhub/entities/project/_base/status.py +9 -0
- digitalhub/entities/project/crud.py +357 -0
- digitalhub/entities/run/__init__.py +0 -0
- digitalhub/entities/run/_base/__init__.py +0 -0
- digitalhub/entities/run/_base/builder.py +94 -0
- digitalhub/entities/run/_base/entity.py +307 -0
- digitalhub/entities/run/_base/spec.py +50 -0
- digitalhub/entities/run/_base/status.py +9 -0
- digitalhub/entities/run/crud.py +219 -0
- digitalhub/entities/secret/__init__.py +0 -0
- digitalhub/entities/secret/_base/__init__.py +0 -0
- digitalhub/entities/secret/_base/builder.py +81 -0
- digitalhub/entities/secret/_base/entity.py +74 -0
- digitalhub/entities/secret/_base/spec.py +35 -0
- digitalhub/entities/secret/_base/status.py +9 -0
- digitalhub/entities/secret/crud.py +290 -0
- digitalhub/entities/task/__init__.py +0 -0
- digitalhub/entities/task/_base/__init__.py +0 -0
- digitalhub/entities/task/_base/builder.py +91 -0
- digitalhub/entities/task/_base/entity.py +136 -0
- digitalhub/entities/task/_base/models.py +208 -0
- digitalhub/entities/task/_base/spec.py +53 -0
- digitalhub/entities/task/_base/status.py +9 -0
- digitalhub/entities/task/crud.py +228 -0
- digitalhub/entities/utils/__init__.py +0 -0
- digitalhub/entities/utils/api.py +346 -0
- digitalhub/entities/utils/entity_types.py +19 -0
- digitalhub/entities/utils/state.py +31 -0
- digitalhub/entities/utils/utils.py +202 -0
- digitalhub/entities/workflow/__init__.py +0 -0
- digitalhub/entities/workflow/_base/__init__.py +0 -0
- digitalhub/entities/workflow/_base/builder.py +79 -0
- digitalhub/entities/workflow/_base/entity.py +74 -0
- digitalhub/entities/workflow/_base/spec.py +15 -0
- digitalhub/entities/workflow/_base/status.py +9 -0
- digitalhub/entities/workflow/crud.py +278 -0
- digitalhub/factory/__init__.py +0 -0
- digitalhub/factory/api.py +277 -0
- digitalhub/factory/factory.py +268 -0
- digitalhub/factory/utils.py +90 -0
- digitalhub/readers/__init__.py +0 -0
- digitalhub/readers/_base/__init__.py +0 -0
- digitalhub/readers/_base/builder.py +26 -0
- digitalhub/readers/_base/reader.py +70 -0
- digitalhub/readers/api.py +80 -0
- digitalhub/readers/factory.py +133 -0
- digitalhub/readers/pandas/__init__.py +0 -0
- digitalhub/readers/pandas/builder.py +29 -0
- digitalhub/readers/pandas/reader.py +207 -0
- digitalhub/runtimes/__init__.py +0 -0
- digitalhub/runtimes/_base.py +102 -0
- digitalhub/runtimes/builder.py +32 -0
- digitalhub/stores/__init__.py +0 -0
- digitalhub/stores/_base/__init__.py +0 -0
- digitalhub/stores/_base/store.py +189 -0
- digitalhub/stores/api.py +54 -0
- digitalhub/stores/builder.py +211 -0
- digitalhub/stores/local/__init__.py +0 -0
- digitalhub/stores/local/store.py +230 -0
- digitalhub/stores/remote/__init__.py +0 -0
- digitalhub/stores/remote/store.py +143 -0
- digitalhub/stores/s3/__init__.py +0 -0
- digitalhub/stores/s3/store.py +563 -0
- digitalhub/stores/sql/__init__.py +0 -0
- digitalhub/stores/sql/store.py +328 -0
- digitalhub/utils/__init__.py +0 -0
- digitalhub/utils/data_utils.py +127 -0
- digitalhub/utils/exceptions.py +67 -0
- digitalhub/utils/file_utils.py +204 -0
- digitalhub/utils/generic_utils.py +183 -0
- digitalhub/utils/git_utils.py +148 -0
- digitalhub/utils/io_utils.py +116 -0
- digitalhub/utils/logger.py +17 -0
- digitalhub/utils/s3_utils.py +58 -0
- digitalhub/utils/uri_utils.py +56 -0
- {digitalhub-0.7.0b2.dist-info → digitalhub-0.8.0.dist-info}/METADATA +30 -13
- digitalhub-0.8.0.dist-info/RECORD +231 -0
- {digitalhub-0.7.0b2.dist-info → digitalhub-0.8.0.dist-info}/WHEEL +1 -1
- test/local/CRUD/test_artifacts.py +96 -0
- test/local/CRUD/test_dataitems.py +96 -0
- test/local/CRUD/test_models.py +95 -0
- test/test_crud_functions.py +1 -1
- test/test_crud_runs.py +1 -1
- test/test_crud_tasks.py +1 -1
- digitalhub-0.7.0b2.dist-info/RECORD +0 -14
- test/test_crud_artifacts.py +0 -96
- test/test_crud_dataitems.py +0 -96
- {digitalhub-0.7.0b2.dist-info → digitalhub-0.8.0.dist-info}/LICENSE.txt +0 -0
- {digitalhub-0.7.0b2.dist-info → digitalhub-0.8.0.dist-info}/top_level.txt +0 -0
- /test/{test_imports.py → local/imports/test_imports.py} +0 -0
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from io import BytesIO
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
import pandas as pd
|
|
8
|
+
from pandas.errors import ParserError
|
|
9
|
+
|
|
10
|
+
from digitalhub.readers._base.reader import DataframeReader
|
|
11
|
+
from digitalhub.utils.data_utils import build_data_preview, get_data_preview
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class DataframeReaderPandas(DataframeReader):
|
|
15
|
+
"""
|
|
16
|
+
Pandas reader class.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
##############################
|
|
20
|
+
# Read methods
|
|
21
|
+
##############################
|
|
22
|
+
|
|
23
|
+
def read_df(self, path: str | list[str], extension: str, **kwargs) -> pd.DataFrame:
|
|
24
|
+
"""
|
|
25
|
+
Read DataFrame from path.
|
|
26
|
+
|
|
27
|
+
Parameters
|
|
28
|
+
----------
|
|
29
|
+
path : str | list[str]
|
|
30
|
+
Path(s) to read DataFrame from.
|
|
31
|
+
extension : str
|
|
32
|
+
Extension of the file.
|
|
33
|
+
**kwargs : dict
|
|
34
|
+
Keyword arguments.
|
|
35
|
+
|
|
36
|
+
Returns
|
|
37
|
+
-------
|
|
38
|
+
pd.DataFrame
|
|
39
|
+
Pandas DataFrame.
|
|
40
|
+
"""
|
|
41
|
+
if extension == "csv":
|
|
42
|
+
method = pd.read_csv
|
|
43
|
+
elif extension == "parquet":
|
|
44
|
+
method = pd.read_parquet
|
|
45
|
+
elif extension == "file":
|
|
46
|
+
try:
|
|
47
|
+
return self.read_df(path, "csv", **kwargs)
|
|
48
|
+
except ParserError:
|
|
49
|
+
raise ValueError(f"Unable to read from {path}.")
|
|
50
|
+
|
|
51
|
+
if isinstance(path, list):
|
|
52
|
+
dfs = [method(p, **kwargs) for p in path]
|
|
53
|
+
return pd.concat(dfs)
|
|
54
|
+
return method(path, **kwargs)
|
|
55
|
+
|
|
56
|
+
##############################
|
|
57
|
+
# Write methods
|
|
58
|
+
##############################
|
|
59
|
+
|
|
60
|
+
def write_df(self, df: pd.DataFrame, dst: str | BytesIO, extension: str | None = None, **kwargs) -> None:
|
|
61
|
+
"""
|
|
62
|
+
Write DataFrame as parquet.
|
|
63
|
+
|
|
64
|
+
Parameters
|
|
65
|
+
----------
|
|
66
|
+
df : pd.DataFrame
|
|
67
|
+
The dataframe to write.
|
|
68
|
+
dst : str | BytesIO
|
|
69
|
+
The destination of the dataframe.
|
|
70
|
+
**kwargs : dict
|
|
71
|
+
Keyword arguments.
|
|
72
|
+
|
|
73
|
+
Returns
|
|
74
|
+
-------
|
|
75
|
+
None
|
|
76
|
+
"""
|
|
77
|
+
if extension == "csv":
|
|
78
|
+
return self.write_csv(df, dst, **kwargs)
|
|
79
|
+
self.write_parquet(df, dst, **kwargs)
|
|
80
|
+
|
|
81
|
+
@staticmethod
|
|
82
|
+
def write_csv(df: pd.DataFrame, dst: str | BytesIO, **kwargs) -> None:
|
|
83
|
+
"""
|
|
84
|
+
Write DataFrame as csv.
|
|
85
|
+
|
|
86
|
+
Parameters
|
|
87
|
+
----------
|
|
88
|
+
df : pd.DataFrame
|
|
89
|
+
The dataframe to write.
|
|
90
|
+
dst : str | BytesIO
|
|
91
|
+
The destination of the dataframe.
|
|
92
|
+
**kwargs : dict
|
|
93
|
+
Keyword arguments.
|
|
94
|
+
|
|
95
|
+
Returns
|
|
96
|
+
-------
|
|
97
|
+
None
|
|
98
|
+
"""
|
|
99
|
+
df.to_csv(dst, index=False, **kwargs)
|
|
100
|
+
|
|
101
|
+
@staticmethod
|
|
102
|
+
def write_parquet(df: pd.DataFrame, dst: str | BytesIO, **kwargs) -> None:
|
|
103
|
+
"""
|
|
104
|
+
Write DataFrame as parquet.
|
|
105
|
+
|
|
106
|
+
Parameters
|
|
107
|
+
----------
|
|
108
|
+
df : pd.DataFrame
|
|
109
|
+
The dataframe to write.
|
|
110
|
+
dst : str | BytesIO
|
|
111
|
+
The destination of the dataframe.
|
|
112
|
+
**kwargs : dict
|
|
113
|
+
Keyword arguments.
|
|
114
|
+
|
|
115
|
+
Returns
|
|
116
|
+
-------
|
|
117
|
+
None
|
|
118
|
+
"""
|
|
119
|
+
df.to_parquet(dst, index=False, **kwargs)
|
|
120
|
+
|
|
121
|
+
@staticmethod
|
|
122
|
+
def write_table(df: pd.DataFrame, table: str, engine: Any, schema: str, **kwargs) -> None:
|
|
123
|
+
"""
|
|
124
|
+
Write DataFrame as table.
|
|
125
|
+
|
|
126
|
+
Parameters
|
|
127
|
+
----------
|
|
128
|
+
df : pd.DataFrame
|
|
129
|
+
The dataframe to write.
|
|
130
|
+
table : str
|
|
131
|
+
The destination table.
|
|
132
|
+
engine : Any
|
|
133
|
+
The SQLAlchemy engine.
|
|
134
|
+
schema : str
|
|
135
|
+
The destination schema.
|
|
136
|
+
**kwargs : dict
|
|
137
|
+
Keyword arguments.
|
|
138
|
+
|
|
139
|
+
Returns
|
|
140
|
+
-------
|
|
141
|
+
None
|
|
142
|
+
"""
|
|
143
|
+
df.to_sql(table, engine, schema=schema, index=False, **kwargs)
|
|
144
|
+
|
|
145
|
+
##############################
|
|
146
|
+
# Utils
|
|
147
|
+
##############################
|
|
148
|
+
|
|
149
|
+
@staticmethod
|
|
150
|
+
def get_schema(df: pd.DataFrame) -> Any:
|
|
151
|
+
"""
|
|
152
|
+
Get schema.
|
|
153
|
+
|
|
154
|
+
Parameters
|
|
155
|
+
----------
|
|
156
|
+
df : pd.DataFrame
|
|
157
|
+
The dataframe.
|
|
158
|
+
|
|
159
|
+
Returns
|
|
160
|
+
-------
|
|
161
|
+
Any
|
|
162
|
+
The schema.
|
|
163
|
+
"""
|
|
164
|
+
schema = {"fields": []}
|
|
165
|
+
|
|
166
|
+
for column_name, dtype in df.dtypes.items():
|
|
167
|
+
field = {"name": str(column_name), "type": ""}
|
|
168
|
+
|
|
169
|
+
if pd.api.types.is_integer_dtype(dtype):
|
|
170
|
+
field["type"] = "integer"
|
|
171
|
+
elif pd.api.types.is_float_dtype(dtype):
|
|
172
|
+
field["type"] = "number"
|
|
173
|
+
elif pd.api.types.is_bool_dtype(dtype):
|
|
174
|
+
field["type"] = "boolean"
|
|
175
|
+
elif pd.api.types.is_string_dtype(dtype):
|
|
176
|
+
field["type"] = "string"
|
|
177
|
+
elif pd.api.types.is_datetime64_any_dtype(dtype):
|
|
178
|
+
field["type"] = "datetime"
|
|
179
|
+
else:
|
|
180
|
+
field["type"] = "any"
|
|
181
|
+
|
|
182
|
+
schema["fields"].append(field)
|
|
183
|
+
|
|
184
|
+
return schema
|
|
185
|
+
|
|
186
|
+
@staticmethod
|
|
187
|
+
def get_preview(df: pd.DataFrame) -> Any:
|
|
188
|
+
"""
|
|
189
|
+
Get preview.
|
|
190
|
+
|
|
191
|
+
Parameters
|
|
192
|
+
----------
|
|
193
|
+
df : pd.DataFrame
|
|
194
|
+
The dataframe.
|
|
195
|
+
|
|
196
|
+
Returns
|
|
197
|
+
-------
|
|
198
|
+
Any
|
|
199
|
+
The preview.
|
|
200
|
+
"""
|
|
201
|
+
columns = [str(col) for col, _ in df.dtypes.items()]
|
|
202
|
+
head = df.head(10)
|
|
203
|
+
head = head.replace({np.nan: None})
|
|
204
|
+
head = head.values.tolist()
|
|
205
|
+
preview = get_data_preview(columns, head)
|
|
206
|
+
len_df = len(df)
|
|
207
|
+
return build_data_preview(preview, len_df)
|
|
File without changes
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from abc import abstractmethod
|
|
4
|
+
from typing import Any, Callable
|
|
5
|
+
|
|
6
|
+
from digitalhub.factory.api import get_action_from_task_kind
|
|
7
|
+
from digitalhub.utils.exceptions import EntityError
|
|
8
|
+
from digitalhub.utils.logger import LOGGER
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Runtime:
|
|
12
|
+
"""
|
|
13
|
+
Base Runtime class.
|
|
14
|
+
|
|
15
|
+
Runtimes are the entities responsible for the actual execution
|
|
16
|
+
of a given run. They are highly specialized components which
|
|
17
|
+
can translate the representation of a given execution as expressed
|
|
18
|
+
in the run into an actual execution operation performed via
|
|
19
|
+
libraries, code, external tools etc.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(self, project: str) -> None:
|
|
23
|
+
self.project = project
|
|
24
|
+
|
|
25
|
+
@abstractmethod
|
|
26
|
+
def build(self, executable: dict, task: dict, run: dict) -> dict:
|
|
27
|
+
"""
|
|
28
|
+
Build run spec.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
@abstractmethod
|
|
32
|
+
def run(self, run: dict) -> dict:
|
|
33
|
+
"""
|
|
34
|
+
Execute run task.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
@staticmethod
|
|
38
|
+
@abstractmethod
|
|
39
|
+
def _get_executable(action: str) -> Callable:
|
|
40
|
+
"""
|
|
41
|
+
Get executable from action.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
##############################
|
|
45
|
+
# Private methods
|
|
46
|
+
##############################
|
|
47
|
+
|
|
48
|
+
def _validate_task(self, run: dict) -> str:
|
|
49
|
+
"""
|
|
50
|
+
Check if task is allowed. This presumes that the
|
|
51
|
+
runtime holds a list of allowed actions in the self.allowed_actions
|
|
52
|
+
attribute.
|
|
53
|
+
|
|
54
|
+
Parameters
|
|
55
|
+
----------
|
|
56
|
+
run : dict
|
|
57
|
+
Run object dictionary.
|
|
58
|
+
|
|
59
|
+
Returns
|
|
60
|
+
-------
|
|
61
|
+
str
|
|
62
|
+
Action to execute.
|
|
63
|
+
"""
|
|
64
|
+
try:
|
|
65
|
+
task_kind = run["spec"]["task"].split(":")[0]
|
|
66
|
+
except (KeyError, IndexError):
|
|
67
|
+
msg = "Malformed run spec."
|
|
68
|
+
LOGGER.exception(msg)
|
|
69
|
+
raise RuntimeError(msg)
|
|
70
|
+
|
|
71
|
+
try:
|
|
72
|
+
return get_action_from_task_kind(task_kind, task_kind)
|
|
73
|
+
except EntityError:
|
|
74
|
+
msg = f"Task {task_kind} not allowed."
|
|
75
|
+
LOGGER.exception(msg)
|
|
76
|
+
raise RuntimeError(msg)
|
|
77
|
+
|
|
78
|
+
@staticmethod
|
|
79
|
+
def _execute(func: Callable, *args, **kwargs) -> Any:
|
|
80
|
+
"""
|
|
81
|
+
Execute function.
|
|
82
|
+
|
|
83
|
+
Parameters
|
|
84
|
+
----------
|
|
85
|
+
func : Callable
|
|
86
|
+
Function to execute.
|
|
87
|
+
*args
|
|
88
|
+
Function arguments.
|
|
89
|
+
**kwargs : dict
|
|
90
|
+
Function keyword arguments.
|
|
91
|
+
|
|
92
|
+
Returns
|
|
93
|
+
-------
|
|
94
|
+
Any
|
|
95
|
+
Function result.
|
|
96
|
+
"""
|
|
97
|
+
try:
|
|
98
|
+
return func(*args, **kwargs)
|
|
99
|
+
except Exception:
|
|
100
|
+
msg = "Something got wrong during function execution."
|
|
101
|
+
LOGGER.exception(msg)
|
|
102
|
+
raise RuntimeError(msg)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import typing
|
|
4
|
+
|
|
5
|
+
from digitalhub.utils.exceptions import BuilderError
|
|
6
|
+
|
|
7
|
+
if typing.TYPE_CHECKING:
|
|
8
|
+
from digitalhub.runtimes._base import Runtime
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class RuntimeBuilder:
|
|
12
|
+
"""
|
|
13
|
+
Builder class for building runtimes.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
# Class variables
|
|
17
|
+
RUNTIME_CLASS: Runtime = None
|
|
18
|
+
|
|
19
|
+
def __init__(self) -> None:
|
|
20
|
+
if self.RUNTIME_CLASS is None:
|
|
21
|
+
raise BuilderError("RUNTIME_CLASS must be set")
|
|
22
|
+
|
|
23
|
+
def build(self, project: str, *args, **kwargs) -> Runtime:
|
|
24
|
+
"""
|
|
25
|
+
Build runtime object.
|
|
26
|
+
|
|
27
|
+
Returns
|
|
28
|
+
-------
|
|
29
|
+
Runtime
|
|
30
|
+
Runtime object.
|
|
31
|
+
"""
|
|
32
|
+
return self.RUNTIME_CLASS(project, *args, **kwargs)
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from abc import ABCMeta, abstractmethod
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from tempfile import mkdtemp
|
|
6
|
+
from typing import Literal
|
|
7
|
+
|
|
8
|
+
from pydantic import BaseModel
|
|
9
|
+
|
|
10
|
+
from digitalhub.utils.exceptions import StoreError
|
|
11
|
+
from digitalhub.utils.uri_utils import map_uri_scheme
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Store(metaclass=ABCMeta):
|
|
15
|
+
"""
|
|
16
|
+
Store abstract class.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(self, name: str, store_type: str) -> None:
|
|
20
|
+
"""
|
|
21
|
+
Constructor.
|
|
22
|
+
|
|
23
|
+
Parameters
|
|
24
|
+
----------
|
|
25
|
+
name : str
|
|
26
|
+
Store name.
|
|
27
|
+
store_type : str
|
|
28
|
+
Store type. Used to choose the right store implementation.
|
|
29
|
+
|
|
30
|
+
Returns
|
|
31
|
+
-------
|
|
32
|
+
None
|
|
33
|
+
"""
|
|
34
|
+
self.name = name
|
|
35
|
+
self.type = store_type
|
|
36
|
+
|
|
37
|
+
##############################
|
|
38
|
+
# IO methods
|
|
39
|
+
##############################
|
|
40
|
+
|
|
41
|
+
@abstractmethod
|
|
42
|
+
def download(
|
|
43
|
+
self,
|
|
44
|
+
root: str,
|
|
45
|
+
dst: Path,
|
|
46
|
+
src: list[str],
|
|
47
|
+
overwrite: bool = False,
|
|
48
|
+
) -> str:
|
|
49
|
+
"""
|
|
50
|
+
Method to download artifact from storage.
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
@abstractmethod
|
|
54
|
+
def upload(self, src: str | list[str], dst: str | None = None) -> list[tuple[str, str]]:
|
|
55
|
+
"""
|
|
56
|
+
Method to upload artifact to storage.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
@abstractmethod
|
|
60
|
+
def get_file_info(self, paths: list[str]) -> list[dict]:
|
|
61
|
+
"""
|
|
62
|
+
Method to get file metadata.
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
##############################
|
|
66
|
+
# Helpers methods
|
|
67
|
+
##############################
|
|
68
|
+
|
|
69
|
+
def _check_local_src(self, src: str) -> None:
|
|
70
|
+
"""
|
|
71
|
+
Check if the source path is local.
|
|
72
|
+
|
|
73
|
+
Parameters
|
|
74
|
+
----------
|
|
75
|
+
src : str
|
|
76
|
+
The source path.
|
|
77
|
+
|
|
78
|
+
Returns
|
|
79
|
+
-------
|
|
80
|
+
None
|
|
81
|
+
|
|
82
|
+
Raises
|
|
83
|
+
------
|
|
84
|
+
StoreError
|
|
85
|
+
If the source is not a local path.
|
|
86
|
+
"""
|
|
87
|
+
if map_uri_scheme(src) != "local":
|
|
88
|
+
raise StoreError(f"Source '{src}' is not a local path.")
|
|
89
|
+
|
|
90
|
+
def _check_local_dst(self, dst: str) -> None:
|
|
91
|
+
"""
|
|
92
|
+
Check if the destination path is local.
|
|
93
|
+
|
|
94
|
+
Parameters
|
|
95
|
+
----------
|
|
96
|
+
dst : str
|
|
97
|
+
The destination path.
|
|
98
|
+
|
|
99
|
+
Returns
|
|
100
|
+
-------
|
|
101
|
+
None
|
|
102
|
+
|
|
103
|
+
Raises
|
|
104
|
+
------
|
|
105
|
+
StoreError
|
|
106
|
+
If the destination is not a local path.
|
|
107
|
+
"""
|
|
108
|
+
if map_uri_scheme(dst) != "local":
|
|
109
|
+
raise StoreError(f"Destination '{dst}' is not a local path.")
|
|
110
|
+
|
|
111
|
+
def _check_overwrite(self, dst: Path, overwrite: bool) -> None:
|
|
112
|
+
"""
|
|
113
|
+
Check if destination path exists for overwrite.
|
|
114
|
+
|
|
115
|
+
Parameters
|
|
116
|
+
----------
|
|
117
|
+
dst : Path
|
|
118
|
+
Destination path as filename.
|
|
119
|
+
overwrite : bool
|
|
120
|
+
Specify if overwrite an existing file.
|
|
121
|
+
|
|
122
|
+
Returns
|
|
123
|
+
-------
|
|
124
|
+
None
|
|
125
|
+
|
|
126
|
+
Raises
|
|
127
|
+
------
|
|
128
|
+
StoreError
|
|
129
|
+
If destination path exists and overwrite is False.
|
|
130
|
+
"""
|
|
131
|
+
if dst.exists() and not overwrite:
|
|
132
|
+
raise StoreError(f"Destination {str(dst)} already exists.")
|
|
133
|
+
|
|
134
|
+
@staticmethod
|
|
135
|
+
def _build_path(path: str | Path) -> None:
|
|
136
|
+
"""
|
|
137
|
+
Get path from store path and path.
|
|
138
|
+
|
|
139
|
+
Parameters
|
|
140
|
+
----------
|
|
141
|
+
path : str
|
|
142
|
+
The path to build.
|
|
143
|
+
|
|
144
|
+
Returns
|
|
145
|
+
-------
|
|
146
|
+
None
|
|
147
|
+
"""
|
|
148
|
+
if not isinstance(path, Path):
|
|
149
|
+
path = Path(path)
|
|
150
|
+
if path.suffix != "":
|
|
151
|
+
path = path.parent
|
|
152
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
153
|
+
|
|
154
|
+
@staticmethod
|
|
155
|
+
def _build_temp() -> Path:
|
|
156
|
+
"""
|
|
157
|
+
Build a temporary path.
|
|
158
|
+
|
|
159
|
+
Returns
|
|
160
|
+
-------
|
|
161
|
+
Path
|
|
162
|
+
Temporary path.
|
|
163
|
+
"""
|
|
164
|
+
tmpdir = mkdtemp()
|
|
165
|
+
return Path(tmpdir)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
class StoreConfig(BaseModel):
|
|
169
|
+
"""
|
|
170
|
+
Store configuration base class.
|
|
171
|
+
"""
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
class StoreParameters(BaseModel):
|
|
175
|
+
"""
|
|
176
|
+
Store configuration class.
|
|
177
|
+
"""
|
|
178
|
+
|
|
179
|
+
name: str
|
|
180
|
+
"""Store id."""
|
|
181
|
+
|
|
182
|
+
type: Literal["local", "s3", "remote", "sql"]
|
|
183
|
+
"""Store type to instantiate."""
|
|
184
|
+
|
|
185
|
+
config: StoreConfig = None
|
|
186
|
+
"""Configuration for the store."""
|
|
187
|
+
|
|
188
|
+
is_default: bool = False
|
|
189
|
+
"""Flag to determine if the store is the default one."""
|
digitalhub/stores/api.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import typing
|
|
4
|
+
|
|
5
|
+
from digitalhub.stores.builder import store_builder
|
|
6
|
+
|
|
7
|
+
if typing.TYPE_CHECKING:
|
|
8
|
+
from digitalhub.stores._base.store import Store, StoreParameters
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def set_store(store_cfg: StoreParameters) -> None:
|
|
12
|
+
"""
|
|
13
|
+
Set a new store instance with the given configuration.
|
|
14
|
+
|
|
15
|
+
Parameters
|
|
16
|
+
----------
|
|
17
|
+
store_cfg : StoreParameters
|
|
18
|
+
Store configuration.
|
|
19
|
+
|
|
20
|
+
Returns
|
|
21
|
+
-------
|
|
22
|
+
None
|
|
23
|
+
"""
|
|
24
|
+
store_builder.build(store_cfg)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def get_store(uri: str) -> Store:
|
|
28
|
+
"""
|
|
29
|
+
Get store instance by uri.
|
|
30
|
+
|
|
31
|
+
Parameters
|
|
32
|
+
---------
|
|
33
|
+
uri : str
|
|
34
|
+
URI to parse.
|
|
35
|
+
|
|
36
|
+
Returns
|
|
37
|
+
-------
|
|
38
|
+
Store
|
|
39
|
+
Store instance.
|
|
40
|
+
"""
|
|
41
|
+
return store_builder.get(uri)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def get_default_store() -> Store:
|
|
45
|
+
"""
|
|
46
|
+
Get the default store instance. The default store is the one that
|
|
47
|
+
can persist artifacts and dataitems.
|
|
48
|
+
|
|
49
|
+
Returns
|
|
50
|
+
-------
|
|
51
|
+
Store
|
|
52
|
+
Default store instance.
|
|
53
|
+
"""
|
|
54
|
+
return store_builder.default()
|