digitalhub 0.11.0b7__py3-none-any.whl → 0.13.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 (270) hide show
  1. digitalhub/__init__.py +4 -1
  2. digitalhub/context/api.py +4 -0
  3. digitalhub/context/builder.py +4 -0
  4. digitalhub/context/context.py +4 -0
  5. digitalhub/entities/__init__.py +3 -0
  6. digitalhub/entities/_base/__init__.py +3 -0
  7. digitalhub/entities/_base/_base/__init__.py +3 -0
  8. digitalhub/entities/_base/_base/entity.py +4 -0
  9. digitalhub/entities/_base/context/__init__.py +3 -0
  10. digitalhub/entities/_base/context/entity.py +4 -0
  11. digitalhub/entities/_base/entity/__init__.py +3 -0
  12. digitalhub/entities/_base/entity/_constructors/__init__.py +3 -0
  13. digitalhub/entities/_base/entity/_constructors/metadata.py +4 -0
  14. digitalhub/entities/_base/entity/_constructors/name.py +4 -0
  15. digitalhub/entities/_base/entity/_constructors/spec.py +4 -0
  16. digitalhub/entities/_base/entity/_constructors/status.py +4 -0
  17. digitalhub/entities/_base/entity/_constructors/uuid.py +4 -0
  18. digitalhub/entities/_base/entity/builder.py +4 -0
  19. digitalhub/entities/_base/entity/entity.py +4 -0
  20. digitalhub/entities/_base/entity/metadata.py +4 -0
  21. digitalhub/entities/_base/entity/spec.py +4 -0
  22. digitalhub/entities/_base/entity/status.py +4 -0
  23. digitalhub/entities/_base/executable/__init__.py +3 -0
  24. digitalhub/entities/_base/executable/entity.py +11 -0
  25. digitalhub/entities/_base/material/__init__.py +3 -0
  26. digitalhub/entities/_base/material/entity.py +12 -15
  27. digitalhub/entities/_base/material/spec.py +4 -0
  28. digitalhub/entities/_base/material/status.py +4 -0
  29. digitalhub/entities/_base/material/utils.py +5 -1
  30. digitalhub/entities/_base/runtime_entity/__init__.py +3 -0
  31. digitalhub/entities/_base/runtime_entity/builder.py +4 -0
  32. digitalhub/entities/_base/unversioned/__init__.py +3 -0
  33. digitalhub/entities/_base/unversioned/builder.py +4 -0
  34. digitalhub/entities/_base/unversioned/entity.py +4 -0
  35. digitalhub/entities/_base/versioned/__init__.py +3 -0
  36. digitalhub/entities/_base/versioned/builder.py +4 -0
  37. digitalhub/entities/_base/versioned/entity.py +4 -0
  38. digitalhub/entities/_commons/__init__.py +3 -0
  39. digitalhub/entities/_commons/enums.py +4 -0
  40. digitalhub/entities/_commons/metrics.py +4 -0
  41. digitalhub/entities/_commons/types.py +4 -0
  42. digitalhub/entities/_commons/utils.py +4 -0
  43. digitalhub/entities/_processors/__init__.py +3 -0
  44. digitalhub/entities/_processors/base.py +4 -0
  45. digitalhub/entities/_processors/context.py +5 -1
  46. digitalhub/entities/_processors/utils.py +4 -0
  47. digitalhub/entities/artifact/__init__.py +3 -0
  48. digitalhub/entities/artifact/_base/__init__.py +3 -0
  49. digitalhub/entities/artifact/_base/builder.py +4 -0
  50. digitalhub/entities/artifact/_base/entity.py +4 -0
  51. digitalhub/entities/artifact/_base/spec.py +4 -0
  52. digitalhub/entities/artifact/_base/status.py +4 -0
  53. digitalhub/entities/artifact/artifact/__init__.py +3 -0
  54. digitalhub/entities/artifact/artifact/builder.py +4 -0
  55. digitalhub/entities/artifact/artifact/entity.py +4 -0
  56. digitalhub/entities/artifact/artifact/spec.py +4 -0
  57. digitalhub/entities/artifact/artifact/status.py +4 -0
  58. digitalhub/entities/artifact/crud.py +4 -0
  59. digitalhub/entities/artifact/utils.py +4 -0
  60. digitalhub/entities/builders.py +4 -0
  61. digitalhub/entities/dataitem/__init__.py +3 -0
  62. digitalhub/entities/dataitem/_base/__init__.py +3 -0
  63. digitalhub/entities/dataitem/_base/builder.py +4 -0
  64. digitalhub/entities/dataitem/_base/entity.py +4 -0
  65. digitalhub/entities/dataitem/_base/spec.py +4 -0
  66. digitalhub/entities/dataitem/_base/status.py +4 -0
  67. digitalhub/entities/dataitem/crud.py +4 -0
  68. digitalhub/entities/dataitem/dataitem/__init__.py +3 -0
  69. digitalhub/entities/dataitem/dataitem/builder.py +4 -0
  70. digitalhub/entities/dataitem/dataitem/entity.py +4 -0
  71. digitalhub/entities/dataitem/dataitem/spec.py +4 -0
  72. digitalhub/entities/dataitem/dataitem/status.py +4 -0
  73. digitalhub/entities/dataitem/iceberg/__init__.py +3 -0
  74. digitalhub/entities/dataitem/iceberg/builder.py +4 -0
  75. digitalhub/entities/dataitem/iceberg/entity.py +4 -0
  76. digitalhub/entities/dataitem/iceberg/spec.py +4 -0
  77. digitalhub/entities/dataitem/iceberg/status.py +4 -0
  78. digitalhub/entities/dataitem/table/__init__.py +3 -0
  79. digitalhub/entities/dataitem/table/builder.py +4 -0
  80. digitalhub/entities/dataitem/table/entity.py +4 -0
  81. digitalhub/entities/dataitem/table/models.py +4 -0
  82. digitalhub/entities/dataitem/table/spec.py +4 -0
  83. digitalhub/entities/dataitem/table/status.py +4 -0
  84. digitalhub/entities/dataitem/table/utils.py +4 -0
  85. digitalhub/entities/dataitem/utils.py +4 -0
  86. digitalhub/entities/function/__init__.py +3 -0
  87. digitalhub/entities/function/_base/__init__.py +3 -0
  88. digitalhub/entities/function/_base/builder.py +4 -0
  89. digitalhub/entities/function/_base/entity.py +4 -0
  90. digitalhub/entities/function/_base/spec.py +4 -0
  91. digitalhub/entities/function/_base/status.py +4 -0
  92. digitalhub/entities/function/crud.py +4 -0
  93. digitalhub/entities/model/__init__.py +3 -0
  94. digitalhub/entities/model/_base/__init__.py +3 -0
  95. digitalhub/entities/model/_base/builder.py +4 -0
  96. digitalhub/entities/model/_base/entity.py +4 -0
  97. digitalhub/entities/model/_base/spec.py +4 -0
  98. digitalhub/entities/model/_base/status.py +4 -0
  99. digitalhub/entities/model/crud.py +4 -0
  100. digitalhub/entities/model/huggingface/__init__.py +3 -0
  101. digitalhub/entities/model/huggingface/builder.py +4 -0
  102. digitalhub/entities/model/huggingface/entity.py +4 -0
  103. digitalhub/entities/model/huggingface/spec.py +4 -0
  104. digitalhub/entities/model/huggingface/status.py +4 -0
  105. digitalhub/entities/model/mlflow/__init__.py +3 -0
  106. digitalhub/entities/model/mlflow/builder.py +4 -0
  107. digitalhub/entities/model/mlflow/entity.py +4 -0
  108. digitalhub/entities/model/mlflow/models.py +4 -0
  109. digitalhub/entities/model/mlflow/spec.py +4 -0
  110. digitalhub/entities/model/mlflow/status.py +4 -0
  111. digitalhub/entities/model/mlflow/utils.py +4 -0
  112. digitalhub/entities/model/model/__init__.py +3 -0
  113. digitalhub/entities/model/model/builder.py +4 -0
  114. digitalhub/entities/model/model/entity.py +4 -0
  115. digitalhub/entities/model/model/spec.py +4 -0
  116. digitalhub/entities/model/model/status.py +4 -0
  117. digitalhub/entities/model/sklearn/__init__.py +3 -0
  118. digitalhub/entities/model/sklearn/builder.py +4 -0
  119. digitalhub/entities/model/sklearn/entity.py +4 -0
  120. digitalhub/entities/model/sklearn/spec.py +4 -0
  121. digitalhub/entities/model/sklearn/status.py +4 -0
  122. digitalhub/entities/model/utils.py +4 -0
  123. digitalhub/entities/project/__init__.py +3 -0
  124. digitalhub/entities/project/_base/__init__.py +3 -0
  125. digitalhub/entities/project/_base/builder.py +4 -0
  126. digitalhub/entities/project/_base/entity.py +4 -0
  127. digitalhub/entities/project/_base/models.py +4 -0
  128. digitalhub/entities/project/_base/spec.py +4 -0
  129. digitalhub/entities/project/_base/status.py +4 -0
  130. digitalhub/entities/project/crud.py +4 -0
  131. digitalhub/entities/project/utils.py +4 -0
  132. digitalhub/entities/run/__init__.py +3 -0
  133. digitalhub/entities/run/_base/__init__.py +3 -0
  134. digitalhub/entities/run/_base/builder.py +4 -0
  135. digitalhub/entities/run/_base/entity.py +4 -0
  136. digitalhub/entities/run/_base/spec.py +4 -0
  137. digitalhub/entities/run/_base/status.py +4 -0
  138. digitalhub/entities/run/crud.py +4 -0
  139. digitalhub/entities/secret/__init__.py +3 -0
  140. digitalhub/entities/secret/_base/__init__.py +3 -0
  141. digitalhub/entities/secret/_base/builder.py +4 -0
  142. digitalhub/entities/secret/_base/entity.py +4 -0
  143. digitalhub/entities/secret/_base/spec.py +4 -0
  144. digitalhub/entities/secret/_base/status.py +4 -0
  145. digitalhub/entities/secret/crud.py +4 -0
  146. digitalhub/entities/task/__init__.py +3 -0
  147. digitalhub/entities/task/_base/__init__.py +3 -0
  148. digitalhub/entities/task/_base/builder.py +4 -0
  149. digitalhub/entities/task/_base/entity.py +4 -0
  150. digitalhub/entities/task/_base/models.py +4 -0
  151. digitalhub/entities/task/_base/spec.py +4 -0
  152. digitalhub/entities/task/_base/status.py +4 -0
  153. digitalhub/entities/task/_base/utils.py +4 -0
  154. digitalhub/entities/task/crud.py +4 -0
  155. digitalhub/entities/trigger/__init__.py +3 -0
  156. digitalhub/entities/trigger/_base/__init__.py +3 -0
  157. digitalhub/entities/trigger/_base/builder.py +4 -0
  158. digitalhub/entities/trigger/_base/entity.py +4 -0
  159. digitalhub/entities/trigger/_base/spec.py +4 -0
  160. digitalhub/entities/trigger/_base/status.py +4 -0
  161. digitalhub/entities/trigger/crud.py +4 -0
  162. digitalhub/entities/trigger/lifecycle/__init__.py +3 -0
  163. digitalhub/entities/trigger/lifecycle/builder.py +4 -0
  164. digitalhub/entities/trigger/lifecycle/entity.py +4 -0
  165. digitalhub/entities/trigger/lifecycle/spec.py +4 -0
  166. digitalhub/entities/trigger/lifecycle/status.py +4 -0
  167. digitalhub/entities/trigger/scheduler/__init__.py +3 -0
  168. digitalhub/entities/trigger/scheduler/builder.py +4 -0
  169. digitalhub/entities/trigger/scheduler/entity.py +4 -0
  170. digitalhub/entities/trigger/scheduler/spec.py +4 -0
  171. digitalhub/entities/trigger/scheduler/status.py +4 -0
  172. digitalhub/entities/workflow/__init__.py +3 -0
  173. digitalhub/entities/workflow/_base/__init__.py +3 -0
  174. digitalhub/entities/workflow/_base/builder.py +4 -0
  175. digitalhub/entities/workflow/_base/entity.py +4 -0
  176. digitalhub/entities/workflow/_base/spec.py +4 -0
  177. digitalhub/entities/workflow/_base/status.py +4 -0
  178. digitalhub/entities/workflow/crud.py +4 -0
  179. digitalhub/factory/__init__.py +3 -0
  180. digitalhub/factory/factory.py +4 -0
  181. digitalhub/factory/utils.py +4 -0
  182. digitalhub/runtimes/__init__.py +3 -0
  183. digitalhub/runtimes/_base.py +4 -0
  184. digitalhub/runtimes/builder.py +4 -0
  185. digitalhub/runtimes/enums.py +4 -0
  186. digitalhub/stores/__init__.py +3 -0
  187. digitalhub/stores/client/__init__.py +3 -0
  188. digitalhub/stores/client/_base/__init__.py +3 -0
  189. digitalhub/stores/client/_base/api_builder.py +4 -0
  190. digitalhub/stores/client/_base/client.py +4 -0
  191. digitalhub/stores/client/_base/key_builder.py +4 -0
  192. digitalhub/stores/client/_base/params_builder.py +4 -0
  193. digitalhub/stores/client/api.py +4 -0
  194. digitalhub/stores/client/builder.py +4 -0
  195. digitalhub/stores/client/dhcore/__init__.py +3 -0
  196. digitalhub/stores/client/dhcore/api_builder.py +4 -0
  197. digitalhub/stores/client/dhcore/client.py +60 -19
  198. digitalhub/stores/client/dhcore/configurator.py +282 -183
  199. digitalhub/stores/client/dhcore/enums.py +6 -0
  200. digitalhub/stores/client/dhcore/error_parser.py +4 -0
  201. digitalhub/stores/client/dhcore/key_builder.py +4 -0
  202. digitalhub/stores/client/dhcore/models.py +4 -0
  203. digitalhub/stores/client/dhcore/params_builder.py +4 -0
  204. digitalhub/stores/client/dhcore/utils.py +12 -8
  205. digitalhub/stores/client/local/__init__.py +3 -0
  206. digitalhub/stores/client/local/api_builder.py +4 -0
  207. digitalhub/stores/client/local/client.py +4 -0
  208. digitalhub/stores/client/local/enums.py +4 -0
  209. digitalhub/stores/client/local/key_builder.py +4 -0
  210. digitalhub/stores/client/local/params_builder.py +4 -0
  211. digitalhub/stores/credentials/__init__.py +3 -0
  212. digitalhub/stores/{configurator → credentials}/api.py +7 -3
  213. digitalhub/stores/credentials/configurator.py +37 -0
  214. digitalhub/stores/credentials/enums.py +54 -0
  215. digitalhub/stores/credentials/handler.py +148 -0
  216. digitalhub/stores/{configurator → credentials}/ini_module.py +5 -1
  217. digitalhub/stores/credentials/store.py +49 -0
  218. digitalhub/stores/data/__init__.py +3 -0
  219. digitalhub/stores/data/_base/__init__.py +3 -0
  220. digitalhub/stores/data/_base/store.py +23 -6
  221. digitalhub/stores/data/api.py +41 -1
  222. digitalhub/stores/data/builder.py +50 -53
  223. digitalhub/stores/data/enums.py +4 -0
  224. digitalhub/stores/data/local/__init__.py +3 -0
  225. digitalhub/stores/data/local/store.py +8 -7
  226. digitalhub/stores/data/remote/__init__.py +3 -0
  227. digitalhub/stores/data/remote/store.py +8 -7
  228. digitalhub/stores/data/s3/__init__.py +3 -0
  229. digitalhub/stores/data/s3/configurator.py +40 -92
  230. digitalhub/stores/data/s3/store.py +46 -57
  231. digitalhub/stores/data/s3/utils.py +5 -1
  232. digitalhub/stores/data/sql/__init__.py +3 -0
  233. digitalhub/stores/data/sql/configurator.py +39 -83
  234. digitalhub/stores/data/sql/store.py +19 -15
  235. digitalhub/stores/readers/__init__.py +3 -0
  236. digitalhub/stores/readers/data/__init__.py +3 -0
  237. digitalhub/stores/readers/data/_base/__init__.py +3 -0
  238. digitalhub/stores/readers/data/_base/builder.py +4 -0
  239. digitalhub/stores/readers/data/_base/reader.py +4 -0
  240. digitalhub/stores/readers/data/api.py +4 -0
  241. digitalhub/stores/readers/data/factory.py +4 -0
  242. digitalhub/stores/readers/data/pandas/__init__.py +3 -0
  243. digitalhub/stores/readers/data/pandas/builder.py +4 -0
  244. digitalhub/stores/readers/data/pandas/reader.py +4 -0
  245. digitalhub/stores/readers/query/__init__.py +3 -0
  246. digitalhub/utils/__init__.py +3 -0
  247. digitalhub/utils/enums.py +4 -0
  248. digitalhub/utils/exceptions.py +4 -0
  249. digitalhub/utils/file_utils.py +4 -0
  250. digitalhub/utils/generic_utils.py +4 -0
  251. digitalhub/utils/git_utils.py +4 -0
  252. digitalhub/utils/io_utils.py +4 -0
  253. digitalhub/utils/logger.py +4 -0
  254. digitalhub/utils/types.py +4 -0
  255. digitalhub/utils/uri_utils.py +4 -0
  256. digitalhub-0.13.0b0.dist-info/METADATA +301 -0
  257. digitalhub-0.13.0b0.dist-info/RECORD +260 -0
  258. digitalhub-0.13.0b0.dist-info/licenses/AUTHORS +5 -0
  259. digitalhub-0.13.0b0.dist-info/licenses/LICENSE +201 -0
  260. digitalhub/stores/configurator/__init__.py +0 -0
  261. digitalhub/stores/configurator/configurator.py +0 -198
  262. digitalhub/stores/configurator/credentials_store.py +0 -65
  263. digitalhub/stores/configurator/enums.py +0 -21
  264. digitalhub/stores/data/s3/enums.py +0 -16
  265. digitalhub/stores/data/sql/enums.py +0 -16
  266. digitalhub/stores/data/utils.py +0 -34
  267. digitalhub-0.11.0b7.dist-info/METADATA +0 -259
  268. digitalhub-0.11.0b7.dist-info/RECORD +0 -261
  269. digitalhub-0.11.0b7.dist-info/licenses/LICENSE.txt +0 -216
  270. {digitalhub-0.11.0b7.dist-info → digitalhub-0.13.0b0.dist-info}/WHEEL +0 -0
@@ -1,41 +1,30 @@
1
+ # SPDX-FileCopyrightText: © 2025 DSLab - Fondazione Bruno Kessler
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
1
5
  from __future__ import annotations
2
6
 
3
7
  import typing
4
8
 
5
- from digitalhub.stores.configurator.api import get_current_env
9
+ from digitalhub.stores.credentials.api import get_current_env
6
10
  from digitalhub.stores.data.local.store import LocalStore
7
11
  from digitalhub.stores.data.remote.store import RemoteStore
12
+ from digitalhub.stores.data.s3.configurator import S3StoreConfigurator
8
13
  from digitalhub.stores.data.s3.store import S3Store
14
+ from digitalhub.stores.data.sql.configurator import SqlStoreConfigurator
9
15
  from digitalhub.stores.data.sql.store import SqlStore
10
16
  from digitalhub.utils.uri_utils import SchemeCategory, map_uri_scheme
11
17
 
12
18
  if typing.TYPE_CHECKING:
19
+ from digitalhub.stores.credentials.configurator import Configurator
13
20
  from digitalhub.stores.data._base.store import Store
21
+ from digitalhub.utils.exceptions import StoreError
14
22
 
15
23
 
16
- def _get_class_from_type(type: str) -> Store:
17
- """
18
- Get a store class from its type.
19
-
20
- Parameters
21
- ----------
22
- type : str
23
- Store type.
24
-
25
- Returns
26
- -------
27
- Store
28
- The store class.
29
- """
30
- if type == SchemeCategory.LOCAL.value:
31
- return LocalStore
32
- if type == SchemeCategory.S3.value:
33
- return S3Store
34
- if type == SchemeCategory.REMOTE.value:
35
- return RemoteStore
36
- if type == SchemeCategory.SQL.value:
37
- return SqlStore
38
- raise ValueError(f"Unknown store type: {type}")
24
+ class StoreInfo:
25
+ def __init__(self, store: Store, configurator: Configurator | None = None) -> None:
26
+ self._store = store
27
+ self._configurator = configurator
39
28
 
40
29
 
41
30
  class StoreBuilder:
@@ -44,50 +33,58 @@ class StoreBuilder:
44
33
  """
45
34
 
46
35
  def __init__(self) -> None:
36
+ self._builders: dict[str, StoreInfo] = {}
47
37
  self._instances: dict[str, dict[str, Store]] = {}
48
38
 
49
- def build(self, project: str, store_type: str) -> None:
50
- """
51
- Build a store instance and register it.
52
-
53
- Parameters
54
- ----------
55
- store_type : str
56
- Store type.
57
- config : dict
58
-
59
- Returns
60
- -------
61
- None
62
- """
63
- env = get_current_env()
64
- if env not in self._instances:
65
- self._instances[env] = {}
66
- self._instances[env][store_type] = _get_class_from_type(store_type)()
67
-
68
- def get(self, project: str, uri: str) -> Store:
39
+ def register(
40
+ self,
41
+ store_type: str,
42
+ store: Store,
43
+ configurator: Configurator | None = None,
44
+ ) -> None:
45
+ if store_type not in self._builders:
46
+ self._builders[store_type] = StoreInfo(store, configurator)
47
+ else:
48
+ raise StoreError(f"Store type {store_type} already registered")
49
+
50
+ def get(self, uri: str) -> Store:
69
51
  """
70
- Get a store instance by URI.
52
+ Get a store instance by URI, building it if necessary.
71
53
 
72
54
  Parameters
73
55
  ----------
74
56
  uri : str
75
57
  URI to parse.
76
- config : dict
77
- Store configuration.
78
58
 
79
59
  Returns
80
60
  -------
81
61
  Store
82
62
  The store instance.
83
63
  """
84
- env = get_current_env()
64
+ env_profile = get_current_env()
85
65
  store_type = map_uri_scheme(uri)
86
- try:
87
- return self._instances[env][store_type]
88
- except KeyError:
89
- self.build(project, store_type)
90
- return self._instances[env][store_type]
66
+
67
+ # Ensure env exists in _instances
68
+ if env_profile not in self._instances:
69
+ self._instances[env_profile] = {}
70
+
71
+ # Build the store instance if not already present
72
+ if store_type not in self._instances[env_profile]:
73
+ store_info = self._builders[store_type]
74
+ store_cls = store_info._store
75
+ cfgrt_cls = store_info._configurator
76
+
77
+ if cfgrt_cls is None:
78
+ store = store_cls()
79
+ else:
80
+ store = store_cls(cfgrt_cls())
81
+ self._instances[env_profile][store_type] = store
82
+
83
+ return self._instances[env_profile][store_type]
91
84
 
92
85
 
93
86
  store_builder = StoreBuilder()
87
+ store_builder.register(SchemeCategory.S3.value, S3Store, S3StoreConfigurator)
88
+ store_builder.register(SchemeCategory.SQL.value, SqlStore, SqlStoreConfigurator)
89
+ store_builder.register(SchemeCategory.LOCAL.value, LocalStore)
90
+ store_builder.register(SchemeCategory.REMOTE.value, RemoteStore)
@@ -1,3 +1,7 @@
1
+ # SPDX-FileCopyrightText: © 2025 DSLab - Fondazione Bruno Kessler
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
1
5
  from __future__ import annotations
2
6
 
3
7
  from enum import Enum
@@ -0,0 +1,3 @@
1
+ # SPDX-FileCopyrightText: © 2025 DSLab - Fondazione Bruno Kessler
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
@@ -1,3 +1,7 @@
1
+ # SPDX-FileCopyrightText: © 2025 DSLab - Fondazione Bruno Kessler
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
1
5
  from __future__ import annotations
2
6
 
3
7
  import shutil
@@ -25,7 +29,6 @@ class LocalStore(Store):
25
29
  self,
26
30
  root: str,
27
31
  dst: Path,
28
- src: list[str],
29
32
  overwrite: bool = False,
30
33
  ) -> str:
31
34
  """
@@ -33,19 +36,17 @@ class LocalStore(Store):
33
36
 
34
37
  Parameters
35
38
  ----------
36
- root : str
37
- The root path of the artifact.
39
+ src : str
40
+ Path of the material entity.
38
41
  dst : str
39
- The destination of the artifact on local filesystem.
40
- src : list[str]
41
- List of sources.
42
+ The destination of the material entity on local filesystem.
42
43
  overwrite : bool
43
44
  Specify if overwrite existing file(s).
44
45
 
45
46
  Returns
46
47
  -------
47
48
  str
48
- Destination path of the downloaded artifact.
49
+ Destination path of the downloaded files.
49
50
  """
50
51
  raise StoreError("Local store does not support download.")
51
52
 
@@ -0,0 +1,3 @@
1
+ # SPDX-FileCopyrightText: © 2025 DSLab - Fondazione Bruno Kessler
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
@@ -1,3 +1,7 @@
1
+ # SPDX-FileCopyrightText: © 2025 DSLab - Fondazione Bruno Kessler
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
1
5
  from __future__ import annotations
2
6
 
3
7
  from pathlib import Path
@@ -24,7 +28,6 @@ class RemoteStore(Store):
24
28
  self,
25
29
  root: str,
26
30
  dst: Path,
27
- src: list[str],
28
31
  overwrite: bool = False,
29
32
  ) -> str:
30
33
  """
@@ -32,19 +35,17 @@ class RemoteStore(Store):
32
35
 
33
36
  Parameters
34
37
  ----------
35
- root : str
36
- The root path of the artifact.
38
+ src : str
39
+ Path of the material entity.
37
40
  dst : str
38
- The destination of the artifact on local filesystem.
39
- src : list[str]
40
- List of sources.
41
+ The destination of the material entity on local filesystem.
41
42
  overwrite : bool
42
43
  Specify if overwrite existing file(s).
43
44
 
44
45
  Returns
45
46
  -------
46
47
  str
47
- Destination path of the downloaded artifact.
48
+ Destination path of the downloaded files.
48
49
  """
49
50
  # Handle destination
50
51
  if dst is None:
@@ -0,0 +1,3 @@
1
+ # SPDX-FileCopyrightText: © 2025 DSLab - Fondazione Bruno Kessler
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
@@ -1,38 +1,55 @@
1
+ # SPDX-FileCopyrightText: © 2025 DSLab - Fondazione Bruno Kessler
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
1
5
  from __future__ import annotations
2
6
 
3
7
  from botocore.config import Config
4
8
 
5
- from digitalhub.stores.configurator.configurator import configurator
6
- from digitalhub.stores.configurator.enums import CredsOrigin
7
- from digitalhub.stores.data.s3.enums import S3StoreEnv
8
- from digitalhub.utils.exceptions import StoreError
9
+ from digitalhub.stores.credentials.configurator import Configurator
10
+ from digitalhub.stores.credentials.enums import CredsEnvVar
9
11
 
10
12
 
11
- class S3StoreConfigurator:
13
+ class S3StoreConfigurator(Configurator):
12
14
  """
13
15
  Configure the store by getting the credentials from user
14
16
  provided config or from environment.
15
17
  """
16
18
 
17
- required_vars = [
18
- S3StoreEnv.ENDPOINT_URL,
19
- S3StoreEnv.ACCESS_KEY_ID,
20
- S3StoreEnv.SECRET_ACCESS_KEY,
19
+ keys = [
20
+ CredsEnvVar.S3_ENDPOINT_URL,
21
+ CredsEnvVar.S3_ACCESS_KEY_ID,
22
+ CredsEnvVar.S3_SECRET_ACCESS_KEY,
23
+ CredsEnvVar.S3_REGION,
24
+ CredsEnvVar.S3_SIGNATURE_VERSION,
25
+ CredsEnvVar.S3_SESSION_TOKEN,
21
26
  ]
22
- optional_vars = [
23
- S3StoreEnv.REGION,
24
- S3StoreEnv.SIGNATURE_VERSION,
25
- S3StoreEnv.SESSION_TOKEN,
27
+ required_keys = [
28
+ CredsEnvVar.S3_ENDPOINT_URL,
29
+ CredsEnvVar.S3_ACCESS_KEY_ID,
30
+ CredsEnvVar.S3_SECRET_ACCESS_KEY,
26
31
  ]
27
32
 
33
+ def __init__(self):
34
+ super().__init__()
35
+ self.load_configs()
36
+
28
37
  ##############################
29
38
  # Configuration methods
30
39
  ##############################
31
40
 
32
- def get_boto3_client_config(self, origin: str) -> dict:
41
+ def load_configs(self) -> None:
42
+ # Load from env
43
+ env_creds = {var.value: self._creds_handler.load_from_env(var.value) for var in self.keys}
44
+ self._creds_handler.set_credentials(self._env, env_creds)
45
+
46
+ # Load from file
47
+ file_creds = {var.value: self._creds_handler.load_from_file(var.value) for var in self.keys}
48
+ self._creds_handler.set_credentials(self._file, file_creds)
49
+
50
+ def get_client_config(self, origin: str) -> dict:
33
51
  """
34
- Get S3 credentials (access key, secret key,
35
- session token and other config).
52
+ Get S3 credentials (access key, secret key, session token and other config).
36
53
 
37
54
  Parameters
38
55
  ----------
@@ -44,83 +61,14 @@ class S3StoreConfigurator:
44
61
  dict
45
62
  The credentials.
46
63
  """
47
- if origin == CredsOrigin.ENV.value:
48
- creds = self._get_env_config()
49
- elif origin == CredsOrigin.FILE.value:
50
- creds = self._get_file_config()
51
- else:
52
- raise StoreError(f"Unknown origin: {origin}")
64
+ creds = self.get_credentials(origin)
53
65
  return {
54
- "endpoint_url": creds[S3StoreEnv.ENDPOINT_URL.value],
55
- "aws_access_key_id": creds[S3StoreEnv.ACCESS_KEY_ID.value],
56
- "aws_secret_access_key": creds[S3StoreEnv.SECRET_ACCESS_KEY.value],
57
- "aws_session_token": creds[S3StoreEnv.SESSION_TOKEN.value],
66
+ "endpoint_url": creds[CredsEnvVar.S3_ENDPOINT_URL.value],
67
+ "aws_access_key_id": creds[CredsEnvVar.S3_ACCESS_KEY_ID.value],
68
+ "aws_secret_access_key": creds[CredsEnvVar.S3_SECRET_ACCESS_KEY.value],
69
+ "aws_session_token": creds[CredsEnvVar.S3_SESSION_TOKEN.value],
58
70
  "config": Config(
59
- region_name=creds[S3StoreEnv.REGION.value],
60
- signature_version=creds[S3StoreEnv.SIGNATURE_VERSION.value],
71
+ region_name=creds[CredsEnvVar.S3_REGION.value],
72
+ signature_version=creds[CredsEnvVar.S3_SIGNATURE_VERSION.value],
61
73
  ),
62
74
  }
63
-
64
- def _get_env_config(self) -> dict:
65
- """
66
- Get the store configuration from environment variables.
67
-
68
- Returns
69
- -------
70
- dict
71
- The credentials.
72
- """
73
- credentials = {
74
- var.value: configurator.load_from_env(var.value) for var in self.required_vars + self.optional_vars
75
- }
76
- self._set_credentials(credentials)
77
- return credentials
78
-
79
- def _get_file_config(self) -> dict:
80
- """
81
- Get the store configuration from file.
82
-
83
- Returns
84
- -------
85
- dict
86
- The credentials.
87
- """
88
- credentials = {
89
- var.value: configurator.load_from_file(var.value) for var in self.required_vars + self.optional_vars
90
- }
91
- self._set_credentials(credentials)
92
- return credentials
93
-
94
- def _check_credentials(self, credentials: dict) -> None:
95
- """
96
- Check for missing credentials.
97
-
98
- Parameters
99
- ----------
100
- credentials : dict
101
- The credentials.
102
-
103
- Returns
104
- -------
105
- None
106
- """
107
- missing_vars = [key for key, value in credentials.items() if value is None and key in self.required_vars]
108
- if missing_vars:
109
- raise StoreError(f"Missing credentials for S3 store: {', '.join(missing_vars)}")
110
-
111
- def _set_credentials(self, credentials: dict) -> None:
112
- """
113
- Set the store credentials into the configurator.
114
-
115
- Parameters
116
- ----------
117
- credentials : dict
118
- The credentials.
119
-
120
- Returns
121
- -------
122
- None
123
- """
124
- # Set credentials
125
- for key, value in credentials.items():
126
- configurator.set_credential(key, value)
@@ -1,5 +1,10 @@
1
+ # SPDX-FileCopyrightText: © 2025 DSLab - Fondazione Bruno Kessler
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
1
5
  from __future__ import annotations
2
6
 
7
+ import typing
3
8
  from io import BytesIO
4
9
  from pathlib import Path
5
10
  from typing import Any, Type
@@ -7,17 +12,22 @@ from urllib.parse import urlparse
7
12
 
8
13
  import boto3
9
14
  import botocore.client # pylint: disable=unused-import
15
+ from boto3.s3.transfer import TransferConfig
10
16
  from botocore.exceptions import ClientError, NoCredentialsError
11
17
 
12
- from digitalhub.stores.configurator.enums import CredsOrigin
18
+ from digitalhub.stores.credentials.enums import CredsOrigin
13
19
  from digitalhub.stores.data._base.store import Store
14
- from digitalhub.stores.data.s3.configurator import S3StoreConfigurator
15
20
  from digitalhub.stores.data.s3.utils import get_bucket_name
16
21
  from digitalhub.stores.readers.data.api import get_reader_by_object
17
22
  from digitalhub.utils.exceptions import StoreError
18
23
  from digitalhub.utils.file_utils import get_file_info_from_s3, get_file_mime_type
19
24
  from digitalhub.utils.types import SourcesOrListOfSources
20
25
 
26
+ if typing.TYPE_CHECKING:
27
+ from digitalhub.stores.credentials.configurator import Configurator
28
+ from digitalhub.stores.data.s3.configurator import S3StoreConfigurator
29
+
30
+
21
31
  # Type aliases
22
32
  S3Client = Type["botocore.client.S3"]
23
33
 
@@ -28,8 +38,9 @@ class S3Store(Store):
28
38
  artifacts on S3 based storage.
29
39
  """
30
40
 
31
- def __init__(self) -> None:
32
- self._configurator = S3StoreConfigurator()
41
+ def __init__(self, configurator: Configurator | None = None) -> None:
42
+ super().__init__(configurator)
43
+ self._configurator: S3StoreConfigurator
33
44
 
34
45
  ##############################
35
46
  # I/O methods
@@ -37,9 +48,8 @@ class S3Store(Store):
37
48
 
38
49
  def download(
39
50
  self,
40
- root: str,
51
+ src: str,
41
52
  dst: Path,
42
- src: list[str],
43
53
  overwrite: bool = False,
44
54
  ) -> str:
45
55
  """
@@ -47,21 +57,19 @@ class S3Store(Store):
47
57
 
48
58
  Parameters
49
59
  ----------
50
- root : str
51
- The root path of the artifact.
60
+ src : str
61
+ Path of the material entity.
52
62
  dst : str
53
- The destination of the artifact on local filesystem.
54
- src : list[str]
55
- List of sources.
63
+ The destination of the material entity on local filesystem.
56
64
  overwrite : bool
57
65
  Specify if overwrite existing file(s).
58
66
 
59
67
  Returns
60
68
  -------
61
69
  str
62
- Destination path of the downloaded artifact.
70
+ Destination path of the downloaded files.
63
71
  """
64
- client, bucket = self._check_factory(root)
72
+ client, bucket = self._check_factory(src)
65
73
 
66
74
  # Build destination directory
67
75
  if dst.suffix == "":
@@ -70,20 +78,13 @@ class S3Store(Store):
70
78
  dst.parent.mkdir(parents=True, exist_ok=True)
71
79
 
72
80
  # Handle src and tree destination
73
- if self.is_partition(root):
74
- if not src:
75
- keys = self._list_objects(client, bucket, root)
76
- strip_root = self._get_key(root)
77
- trees = [k.removeprefix(strip_root) for k in keys]
78
- else:
79
- keys = self._build_key_from_root(root, src)
80
- trees = [s for s in src]
81
+ if self.is_partition(src):
82
+ keys = self._list_objects(client, bucket, src)
83
+ strip_root = self._get_key(src)
84
+ trees = [k.removeprefix(strip_root) for k in keys]
81
85
  else:
82
- keys = [self._get_key(root)]
83
- if not src:
84
- trees = [Path(self._get_key(root)).name]
85
- else:
86
- trees = [s for s in src]
86
+ keys = [self._get_key(src)]
87
+ trees = [Path(self._get_key(src)).name]
87
88
 
88
89
  if len(keys) != len(trees):
89
90
  raise StoreError("Keys and trees must have the same length.")
@@ -124,7 +125,7 @@ class S3Store(Store):
124
125
  src : SourcesOrListOfSources
125
126
  Source(s).
126
127
  dst : str
127
- The destination of the artifact on storage.
128
+ The destination of the material entity on storage.
128
129
 
129
130
  Returns
130
131
  -------
@@ -410,7 +411,7 @@ class S3Store(Store):
410
411
  src : str
411
412
  List of sources.
412
413
  dst : str
413
- The destination of the artifact on storage.
414
+ The destination of the material entity on storage.
414
415
  client : S3Client
415
416
  The S3 client object.
416
417
  bucket : str
@@ -453,7 +454,7 @@ class S3Store(Store):
453
454
  src : list
454
455
  List of sources.
455
456
  dst : str
456
- The destination of the artifact on storage.
457
+ The destination of the material entity on storage.
457
458
  client : S3Client
458
459
  The S3 client object.
459
460
  bucket : str
@@ -493,7 +494,7 @@ class S3Store(Store):
493
494
  src : str
494
495
  List of sources.
495
496
  dst : str
496
- The destination of the artifact on storage.
497
+ The destination of the material entity on storage.
497
498
  client : S3Client
498
499
  The S3 client object.
499
500
  bucket : str
@@ -542,7 +543,13 @@ class S3Store(Store):
542
543
  mime_type = get_file_mime_type(src)
543
544
  if mime_type is not None:
544
545
  extra_args["ContentType"] = mime_type
545
- client.upload_file(Filename=src, Bucket=bucket, Key=key, ExtraArgs=extra_args)
546
+ client.upload_file(
547
+ Filename=src,
548
+ Bucket=bucket,
549
+ Key=key,
550
+ ExtraArgs=extra_args,
551
+ Config=TransferConfig(multipart_threshold=100 * 1024 * 1024),
552
+ )
546
553
 
547
554
  @staticmethod
548
555
  def _upload_fileobject(
@@ -569,7 +576,12 @@ class S3Store(Store):
569
576
  -------
570
577
  None
571
578
  """
572
- client.put_object(Bucket=bucket, Key=key, Body=fileobj.getvalue())
579
+ client.upload_fileobj(
580
+ Fileobj=fileobj,
581
+ Bucket=bucket,
582
+ Key=key,
583
+ Config=TransferConfig(multipart_threshold=100 * 1024 * 1024),
584
+ )
573
585
 
574
586
  ##############################
575
587
  # Helper methods
@@ -615,13 +627,13 @@ class S3Store(Store):
615
627
 
616
628
  # Try to get client from environment variables
617
629
  try:
618
- cfg = self._configurator.get_boto3_client_config(CredsOrigin.ENV.value)
630
+ cfg = self._configurator.get_client_config(CredsOrigin.ENV.value)
619
631
  client = self._get_client(cfg)
620
632
  self._check_access_to_storage(client, bucket)
621
633
 
622
634
  # Fallback to file
623
635
  except StoreError:
624
- cfg = self._configurator.get_boto3_client_config(CredsOrigin.FILE.value)
636
+ cfg = self._configurator.get_client_config(CredsOrigin.FILE.value)
625
637
  client = self._get_client(cfg)
626
638
  self._check_access_to_storage(client, bucket)
627
639
 
@@ -672,29 +684,6 @@ class S3Store(Store):
672
684
  key = key[1:]
673
685
  return key
674
686
 
675
- def _build_key_from_root(self, root: str, paths: list[str]) -> list[str]:
676
- """
677
- Method to build object path.
678
-
679
- Parameters
680
- ----------
681
- root : str
682
- The root of the object path.
683
- paths : list[str]
684
- The path to build.
685
-
686
- Returns
687
- -------
688
- list[str]
689
- List of keys.
690
- """
691
- keys = []
692
- for path in paths:
693
- clean_path = self._get_key(path)
694
- key = self._get_key(f"{root}{clean_path}")
695
- keys.append(key)
696
- return keys
697
-
698
687
  def _list_objects(self, client: S3Client, bucket: str, partition: str) -> list[str]:
699
688
  """
700
689
  List objects in a S3 partition.
@@ -1,3 +1,7 @@
1
+ # SPDX-FileCopyrightText: © 2025 DSLab - Fondazione Bruno Kessler
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
1
5
  from __future__ import annotations
2
6
 
3
7
  from pathlib import Path
@@ -5,7 +9,7 @@ from urllib.parse import urlparse
5
9
 
6
10
  from boto3 import client as boto3_client
7
11
 
8
- from digitalhub.stores.configurator.enums import CredsOrigin
12
+ from digitalhub.stores.credentials.enums import CredsOrigin
9
13
  from digitalhub.stores.data.s3.configurator import S3StoreConfigurator
10
14
  from digitalhub.utils.exceptions import StoreError
11
15
 
@@ -0,0 +1,3 @@
1
+ # SPDX-FileCopyrightText: © 2025 DSLab - Fondazione Bruno Kessler
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0