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.

Files changed (232) hide show
  1. digitalhub/__init__.py +63 -93
  2. digitalhub/client/__init__.py +0 -0
  3. digitalhub/client/_base/__init__.py +0 -0
  4. digitalhub/client/_base/client.py +56 -0
  5. digitalhub/client/api.py +63 -0
  6. digitalhub/client/builder.py +50 -0
  7. digitalhub/client/dhcore/__init__.py +0 -0
  8. digitalhub/client/dhcore/client.py +669 -0
  9. digitalhub/client/dhcore/env.py +21 -0
  10. digitalhub/client/dhcore/models.py +46 -0
  11. digitalhub/client/dhcore/utils.py +111 -0
  12. digitalhub/client/local/__init__.py +0 -0
  13. digitalhub/client/local/client.py +533 -0
  14. digitalhub/context/__init__.py +0 -0
  15. digitalhub/context/api.py +93 -0
  16. digitalhub/context/builder.py +94 -0
  17. digitalhub/context/context.py +136 -0
  18. digitalhub/datastores/__init__.py +0 -0
  19. digitalhub/datastores/_base/__init__.py +0 -0
  20. digitalhub/datastores/_base/datastore.py +85 -0
  21. digitalhub/datastores/api.py +37 -0
  22. digitalhub/datastores/builder.py +110 -0
  23. digitalhub/datastores/local/__init__.py +0 -0
  24. digitalhub/datastores/local/datastore.py +50 -0
  25. digitalhub/datastores/remote/__init__.py +0 -0
  26. digitalhub/datastores/remote/datastore.py +31 -0
  27. digitalhub/datastores/s3/__init__.py +0 -0
  28. digitalhub/datastores/s3/datastore.py +46 -0
  29. digitalhub/datastores/sql/__init__.py +0 -0
  30. digitalhub/datastores/sql/datastore.py +68 -0
  31. digitalhub/entities/__init__.py +0 -0
  32. digitalhub/entities/_base/__init__.py +0 -0
  33. digitalhub/entities/_base/_base/__init__.py +0 -0
  34. digitalhub/entities/_base/_base/entity.py +82 -0
  35. digitalhub/entities/_base/api_utils.py +620 -0
  36. digitalhub/entities/_base/context/__init__.py +0 -0
  37. digitalhub/entities/_base/context/entity.py +118 -0
  38. digitalhub/entities/_base/crud.py +468 -0
  39. digitalhub/entities/_base/entity/__init__.py +0 -0
  40. digitalhub/entities/_base/entity/_constructors/__init__.py +0 -0
  41. digitalhub/entities/_base/entity/_constructors/metadata.py +44 -0
  42. digitalhub/entities/_base/entity/_constructors/name.py +31 -0
  43. digitalhub/entities/_base/entity/_constructors/spec.py +33 -0
  44. digitalhub/entities/_base/entity/_constructors/status.py +52 -0
  45. digitalhub/entities/_base/entity/_constructors/uuid.py +26 -0
  46. digitalhub/entities/_base/entity/builder.py +175 -0
  47. digitalhub/entities/_base/entity/entity.py +106 -0
  48. digitalhub/entities/_base/entity/metadata.py +59 -0
  49. digitalhub/entities/_base/entity/spec.py +58 -0
  50. digitalhub/entities/_base/entity/status.py +43 -0
  51. digitalhub/entities/_base/executable/__init__.py +0 -0
  52. digitalhub/entities/_base/executable/entity.py +405 -0
  53. digitalhub/entities/_base/material/__init__.py +0 -0
  54. digitalhub/entities/_base/material/entity.py +214 -0
  55. digitalhub/entities/_base/material/spec.py +22 -0
  56. digitalhub/entities/_base/material/status.py +49 -0
  57. digitalhub/entities/_base/runtime_entity/__init__.py +0 -0
  58. digitalhub/entities/_base/runtime_entity/builder.py +106 -0
  59. digitalhub/entities/_base/unversioned/__init__.py +0 -0
  60. digitalhub/entities/_base/unversioned/builder.py +66 -0
  61. digitalhub/entities/_base/unversioned/entity.py +49 -0
  62. digitalhub/entities/_base/versioned/__init__.py +0 -0
  63. digitalhub/entities/_base/versioned/builder.py +68 -0
  64. digitalhub/entities/_base/versioned/entity.py +53 -0
  65. digitalhub/entities/artifact/__init__.py +0 -0
  66. digitalhub/entities/artifact/_base/__init__.py +0 -0
  67. digitalhub/entities/artifact/_base/builder.py +86 -0
  68. digitalhub/entities/artifact/_base/entity.py +39 -0
  69. digitalhub/entities/artifact/_base/spec.py +15 -0
  70. digitalhub/entities/artifact/_base/status.py +9 -0
  71. digitalhub/entities/artifact/artifact/__init__.py +0 -0
  72. digitalhub/entities/artifact/artifact/builder.py +18 -0
  73. digitalhub/entities/artifact/artifact/entity.py +32 -0
  74. digitalhub/entities/artifact/artifact/spec.py +27 -0
  75. digitalhub/entities/artifact/artifact/status.py +15 -0
  76. digitalhub/entities/artifact/crud.py +332 -0
  77. digitalhub/entities/builders.py +63 -0
  78. digitalhub/entities/dataitem/__init__.py +0 -0
  79. digitalhub/entities/dataitem/_base/__init__.py +0 -0
  80. digitalhub/entities/dataitem/_base/builder.py +86 -0
  81. digitalhub/entities/dataitem/_base/entity.py +75 -0
  82. digitalhub/entities/dataitem/_base/spec.py +15 -0
  83. digitalhub/entities/dataitem/_base/status.py +20 -0
  84. digitalhub/entities/dataitem/crud.py +372 -0
  85. digitalhub/entities/dataitem/dataitem/__init__.py +0 -0
  86. digitalhub/entities/dataitem/dataitem/builder.py +18 -0
  87. digitalhub/entities/dataitem/dataitem/entity.py +32 -0
  88. digitalhub/entities/dataitem/dataitem/spec.py +15 -0
  89. digitalhub/entities/dataitem/dataitem/status.py +9 -0
  90. digitalhub/entities/dataitem/iceberg/__init__.py +0 -0
  91. digitalhub/entities/dataitem/iceberg/builder.py +18 -0
  92. digitalhub/entities/dataitem/iceberg/entity.py +32 -0
  93. digitalhub/entities/dataitem/iceberg/spec.py +15 -0
  94. digitalhub/entities/dataitem/iceberg/status.py +9 -0
  95. digitalhub/entities/dataitem/table/__init__.py +0 -0
  96. digitalhub/entities/dataitem/table/builder.py +18 -0
  97. digitalhub/entities/dataitem/table/entity.py +146 -0
  98. digitalhub/entities/dataitem/table/models.py +62 -0
  99. digitalhub/entities/dataitem/table/spec.py +25 -0
  100. digitalhub/entities/dataitem/table/status.py +9 -0
  101. digitalhub/entities/function/__init__.py +0 -0
  102. digitalhub/entities/function/_base/__init__.py +0 -0
  103. digitalhub/entities/function/_base/builder.py +79 -0
  104. digitalhub/entities/function/_base/entity.py +98 -0
  105. digitalhub/entities/function/_base/models.py +118 -0
  106. digitalhub/entities/function/_base/spec.py +15 -0
  107. digitalhub/entities/function/_base/status.py +9 -0
  108. digitalhub/entities/function/crud.py +279 -0
  109. digitalhub/entities/model/__init__.py +0 -0
  110. digitalhub/entities/model/_base/__init__.py +0 -0
  111. digitalhub/entities/model/_base/builder.py +86 -0
  112. digitalhub/entities/model/_base/entity.py +34 -0
  113. digitalhub/entities/model/_base/spec.py +49 -0
  114. digitalhub/entities/model/_base/status.py +9 -0
  115. digitalhub/entities/model/crud.py +331 -0
  116. digitalhub/entities/model/huggingface/__init__.py +0 -0
  117. digitalhub/entities/model/huggingface/builder.py +18 -0
  118. digitalhub/entities/model/huggingface/entity.py +32 -0
  119. digitalhub/entities/model/huggingface/spec.py +36 -0
  120. digitalhub/entities/model/huggingface/status.py +9 -0
  121. digitalhub/entities/model/mlflow/__init__.py +0 -0
  122. digitalhub/entities/model/mlflow/builder.py +18 -0
  123. digitalhub/entities/model/mlflow/entity.py +32 -0
  124. digitalhub/entities/model/mlflow/models.py +26 -0
  125. digitalhub/entities/model/mlflow/spec.py +44 -0
  126. digitalhub/entities/model/mlflow/status.py +9 -0
  127. digitalhub/entities/model/mlflow/utils.py +81 -0
  128. digitalhub/entities/model/model/__init__.py +0 -0
  129. digitalhub/entities/model/model/builder.py +18 -0
  130. digitalhub/entities/model/model/entity.py +32 -0
  131. digitalhub/entities/model/model/spec.py +15 -0
  132. digitalhub/entities/model/model/status.py +9 -0
  133. digitalhub/entities/model/sklearn/__init__.py +0 -0
  134. digitalhub/entities/model/sklearn/builder.py +18 -0
  135. digitalhub/entities/model/sklearn/entity.py +32 -0
  136. digitalhub/entities/model/sklearn/spec.py +15 -0
  137. digitalhub/entities/model/sklearn/status.py +9 -0
  138. digitalhub/entities/project/__init__.py +0 -0
  139. digitalhub/entities/project/_base/__init__.py +0 -0
  140. digitalhub/entities/project/_base/builder.py +128 -0
  141. digitalhub/entities/project/_base/entity.py +2078 -0
  142. digitalhub/entities/project/_base/spec.py +50 -0
  143. digitalhub/entities/project/_base/status.py +9 -0
  144. digitalhub/entities/project/crud.py +357 -0
  145. digitalhub/entities/run/__init__.py +0 -0
  146. digitalhub/entities/run/_base/__init__.py +0 -0
  147. digitalhub/entities/run/_base/builder.py +94 -0
  148. digitalhub/entities/run/_base/entity.py +307 -0
  149. digitalhub/entities/run/_base/spec.py +50 -0
  150. digitalhub/entities/run/_base/status.py +9 -0
  151. digitalhub/entities/run/crud.py +219 -0
  152. digitalhub/entities/secret/__init__.py +0 -0
  153. digitalhub/entities/secret/_base/__init__.py +0 -0
  154. digitalhub/entities/secret/_base/builder.py +81 -0
  155. digitalhub/entities/secret/_base/entity.py +74 -0
  156. digitalhub/entities/secret/_base/spec.py +35 -0
  157. digitalhub/entities/secret/_base/status.py +9 -0
  158. digitalhub/entities/secret/crud.py +290 -0
  159. digitalhub/entities/task/__init__.py +0 -0
  160. digitalhub/entities/task/_base/__init__.py +0 -0
  161. digitalhub/entities/task/_base/builder.py +91 -0
  162. digitalhub/entities/task/_base/entity.py +136 -0
  163. digitalhub/entities/task/_base/models.py +208 -0
  164. digitalhub/entities/task/_base/spec.py +53 -0
  165. digitalhub/entities/task/_base/status.py +9 -0
  166. digitalhub/entities/task/crud.py +228 -0
  167. digitalhub/entities/utils/__init__.py +0 -0
  168. digitalhub/entities/utils/api.py +346 -0
  169. digitalhub/entities/utils/entity_types.py +19 -0
  170. digitalhub/entities/utils/state.py +31 -0
  171. digitalhub/entities/utils/utils.py +202 -0
  172. digitalhub/entities/workflow/__init__.py +0 -0
  173. digitalhub/entities/workflow/_base/__init__.py +0 -0
  174. digitalhub/entities/workflow/_base/builder.py +79 -0
  175. digitalhub/entities/workflow/_base/entity.py +74 -0
  176. digitalhub/entities/workflow/_base/spec.py +15 -0
  177. digitalhub/entities/workflow/_base/status.py +9 -0
  178. digitalhub/entities/workflow/crud.py +278 -0
  179. digitalhub/factory/__init__.py +0 -0
  180. digitalhub/factory/api.py +277 -0
  181. digitalhub/factory/factory.py +268 -0
  182. digitalhub/factory/utils.py +90 -0
  183. digitalhub/readers/__init__.py +0 -0
  184. digitalhub/readers/_base/__init__.py +0 -0
  185. digitalhub/readers/_base/builder.py +26 -0
  186. digitalhub/readers/_base/reader.py +70 -0
  187. digitalhub/readers/api.py +80 -0
  188. digitalhub/readers/factory.py +133 -0
  189. digitalhub/readers/pandas/__init__.py +0 -0
  190. digitalhub/readers/pandas/builder.py +29 -0
  191. digitalhub/readers/pandas/reader.py +207 -0
  192. digitalhub/runtimes/__init__.py +0 -0
  193. digitalhub/runtimes/_base.py +102 -0
  194. digitalhub/runtimes/builder.py +32 -0
  195. digitalhub/stores/__init__.py +0 -0
  196. digitalhub/stores/_base/__init__.py +0 -0
  197. digitalhub/stores/_base/store.py +189 -0
  198. digitalhub/stores/api.py +54 -0
  199. digitalhub/stores/builder.py +211 -0
  200. digitalhub/stores/local/__init__.py +0 -0
  201. digitalhub/stores/local/store.py +230 -0
  202. digitalhub/stores/remote/__init__.py +0 -0
  203. digitalhub/stores/remote/store.py +143 -0
  204. digitalhub/stores/s3/__init__.py +0 -0
  205. digitalhub/stores/s3/store.py +563 -0
  206. digitalhub/stores/sql/__init__.py +0 -0
  207. digitalhub/stores/sql/store.py +328 -0
  208. digitalhub/utils/__init__.py +0 -0
  209. digitalhub/utils/data_utils.py +127 -0
  210. digitalhub/utils/exceptions.py +67 -0
  211. digitalhub/utils/file_utils.py +204 -0
  212. digitalhub/utils/generic_utils.py +183 -0
  213. digitalhub/utils/git_utils.py +148 -0
  214. digitalhub/utils/io_utils.py +116 -0
  215. digitalhub/utils/logger.py +17 -0
  216. digitalhub/utils/s3_utils.py +58 -0
  217. digitalhub/utils/uri_utils.py +56 -0
  218. {digitalhub-0.7.0b2.dist-info → digitalhub-0.8.0.dist-info}/METADATA +30 -13
  219. digitalhub-0.8.0.dist-info/RECORD +231 -0
  220. {digitalhub-0.7.0b2.dist-info → digitalhub-0.8.0.dist-info}/WHEEL +1 -1
  221. test/local/CRUD/test_artifacts.py +96 -0
  222. test/local/CRUD/test_dataitems.py +96 -0
  223. test/local/CRUD/test_models.py +95 -0
  224. test/test_crud_functions.py +1 -1
  225. test/test_crud_runs.py +1 -1
  226. test/test_crud_tasks.py +1 -1
  227. digitalhub-0.7.0b2.dist-info/RECORD +0 -14
  228. test/test_crud_artifacts.py +0 -96
  229. test/test_crud_dataitems.py +0 -96
  230. {digitalhub-0.7.0b2.dist-info → digitalhub-0.8.0.dist-info}/LICENSE.txt +0 -0
  231. {digitalhub-0.7.0b2.dist-info → digitalhub-0.8.0.dist-info}/top_level.txt +0 -0
  232. /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."""
@@ -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()