digitalhub 0.11.0b7__py3-none-any.whl → 0.13.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 (272) hide show
  1. digitalhub/__init__.py +4 -1
  2. digitalhub/context/api.py +9 -5
  3. digitalhub/context/builder.py +7 -5
  4. digitalhub/context/context.py +13 -1
  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 +109 -57
  25. digitalhub/entities/_base/material/__init__.py +3 -0
  26. digitalhub/entities/_base/material/entity.py +15 -18
  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 +68 -30
  41. digitalhub/entities/_commons/utils.py +40 -9
  42. digitalhub/entities/_processors/__init__.py +3 -0
  43. digitalhub/entities/_processors/base.py +154 -79
  44. digitalhub/entities/_processors/context.py +370 -215
  45. digitalhub/entities/_processors/utils.py +78 -30
  46. digitalhub/entities/artifact/__init__.py +3 -0
  47. digitalhub/entities/artifact/_base/__init__.py +3 -0
  48. digitalhub/entities/artifact/_base/builder.py +4 -0
  49. digitalhub/entities/artifact/_base/entity.py +4 -0
  50. digitalhub/entities/artifact/_base/spec.py +4 -0
  51. digitalhub/entities/artifact/_base/status.py +4 -0
  52. digitalhub/entities/artifact/artifact/__init__.py +3 -0
  53. digitalhub/entities/artifact/artifact/builder.py +4 -0
  54. digitalhub/entities/artifact/artifact/entity.py +4 -0
  55. digitalhub/entities/artifact/artifact/spec.py +4 -0
  56. digitalhub/entities/artifact/artifact/status.py +4 -0
  57. digitalhub/entities/artifact/crud.py +8 -0
  58. digitalhub/entities/artifact/utils.py +32 -13
  59. digitalhub/entities/builders.py +4 -0
  60. digitalhub/entities/dataitem/__init__.py +3 -0
  61. digitalhub/entities/dataitem/_base/__init__.py +3 -0
  62. digitalhub/entities/dataitem/_base/builder.py +4 -0
  63. digitalhub/entities/dataitem/_base/entity.py +4 -0
  64. digitalhub/entities/dataitem/_base/spec.py +4 -0
  65. digitalhub/entities/dataitem/_base/status.py +4 -0
  66. digitalhub/entities/dataitem/crud.py +18 -2
  67. digitalhub/entities/dataitem/dataitem/__init__.py +3 -0
  68. digitalhub/entities/dataitem/dataitem/builder.py +4 -0
  69. digitalhub/entities/dataitem/dataitem/entity.py +4 -0
  70. digitalhub/entities/dataitem/dataitem/spec.py +4 -0
  71. digitalhub/entities/dataitem/dataitem/status.py +4 -0
  72. digitalhub/entities/dataitem/iceberg/__init__.py +3 -0
  73. digitalhub/entities/dataitem/iceberg/builder.py +4 -0
  74. digitalhub/entities/dataitem/iceberg/entity.py +4 -0
  75. digitalhub/entities/dataitem/iceberg/spec.py +4 -0
  76. digitalhub/entities/dataitem/iceberg/status.py +4 -0
  77. digitalhub/entities/dataitem/table/__init__.py +3 -0
  78. digitalhub/entities/dataitem/table/builder.py +4 -0
  79. digitalhub/entities/dataitem/table/entity.py +7 -3
  80. digitalhub/entities/dataitem/table/models.py +4 -0
  81. digitalhub/entities/dataitem/table/spec.py +4 -0
  82. digitalhub/entities/dataitem/table/status.py +4 -0
  83. digitalhub/entities/dataitem/table/utils.py +4 -0
  84. digitalhub/entities/dataitem/utils.py +88 -35
  85. digitalhub/entities/function/__init__.py +3 -0
  86. digitalhub/entities/function/_base/__init__.py +3 -0
  87. digitalhub/entities/function/_base/builder.py +4 -0
  88. digitalhub/entities/function/_base/entity.py +4 -0
  89. digitalhub/entities/function/_base/spec.py +4 -0
  90. digitalhub/entities/function/_base/status.py +4 -0
  91. digitalhub/entities/function/crud.py +4 -0
  92. digitalhub/entities/model/__init__.py +3 -0
  93. digitalhub/entities/model/_base/__init__.py +3 -0
  94. digitalhub/entities/model/_base/builder.py +4 -0
  95. digitalhub/entities/model/_base/entity.py +4 -0
  96. digitalhub/entities/model/_base/spec.py +4 -0
  97. digitalhub/entities/model/_base/status.py +4 -0
  98. digitalhub/entities/model/crud.py +8 -0
  99. digitalhub/entities/model/huggingface/__init__.py +3 -0
  100. digitalhub/entities/model/huggingface/builder.py +4 -0
  101. digitalhub/entities/model/huggingface/entity.py +4 -0
  102. digitalhub/entities/model/huggingface/spec.py +4 -0
  103. digitalhub/entities/model/huggingface/status.py +4 -0
  104. digitalhub/entities/model/mlflow/__init__.py +3 -0
  105. digitalhub/entities/model/mlflow/builder.py +4 -0
  106. digitalhub/entities/model/mlflow/entity.py +4 -0
  107. digitalhub/entities/model/mlflow/models.py +4 -0
  108. digitalhub/entities/model/mlflow/spec.py +4 -0
  109. digitalhub/entities/model/mlflow/status.py +4 -0
  110. digitalhub/entities/model/mlflow/utils.py +4 -0
  111. digitalhub/entities/model/model/__init__.py +3 -0
  112. digitalhub/entities/model/model/builder.py +4 -0
  113. digitalhub/entities/model/model/entity.py +4 -0
  114. digitalhub/entities/model/model/spec.py +4 -0
  115. digitalhub/entities/model/model/status.py +4 -0
  116. digitalhub/entities/model/sklearn/__init__.py +3 -0
  117. digitalhub/entities/model/sklearn/builder.py +4 -0
  118. digitalhub/entities/model/sklearn/entity.py +4 -0
  119. digitalhub/entities/model/sklearn/spec.py +4 -0
  120. digitalhub/entities/model/sklearn/status.py +4 -0
  121. digitalhub/entities/model/utils.py +32 -13
  122. digitalhub/entities/project/__init__.py +3 -0
  123. digitalhub/entities/project/_base/__init__.py +3 -0
  124. digitalhub/entities/project/_base/builder.py +4 -0
  125. digitalhub/entities/project/_base/entity.py +4 -2
  126. digitalhub/entities/project/_base/models.py +4 -0
  127. digitalhub/entities/project/_base/spec.py +4 -0
  128. digitalhub/entities/project/_base/status.py +4 -0
  129. digitalhub/entities/project/crud.py +4 -0
  130. digitalhub/entities/project/utils.py +4 -0
  131. digitalhub/entities/run/__init__.py +3 -0
  132. digitalhub/entities/run/_base/__init__.py +3 -0
  133. digitalhub/entities/run/_base/builder.py +4 -0
  134. digitalhub/entities/run/_base/entity.py +6 -2
  135. digitalhub/entities/run/_base/spec.py +4 -0
  136. digitalhub/entities/run/_base/status.py +4 -0
  137. digitalhub/entities/run/crud.py +4 -0
  138. digitalhub/entities/secret/__init__.py +3 -0
  139. digitalhub/entities/secret/_base/__init__.py +3 -0
  140. digitalhub/entities/secret/_base/builder.py +4 -0
  141. digitalhub/entities/secret/_base/entity.py +4 -0
  142. digitalhub/entities/secret/_base/spec.py +4 -0
  143. digitalhub/entities/secret/_base/status.py +4 -0
  144. digitalhub/entities/secret/crud.py +4 -0
  145. digitalhub/entities/task/__init__.py +3 -0
  146. digitalhub/entities/task/_base/__init__.py +3 -0
  147. digitalhub/entities/task/_base/builder.py +4 -0
  148. digitalhub/entities/task/_base/entity.py +4 -0
  149. digitalhub/entities/task/_base/models.py +16 -3
  150. digitalhub/entities/task/_base/spec.py +4 -0
  151. digitalhub/entities/task/_base/status.py +4 -0
  152. digitalhub/entities/task/_base/utils.py +4 -0
  153. digitalhub/entities/task/crud.py +4 -0
  154. digitalhub/entities/trigger/__init__.py +3 -0
  155. digitalhub/entities/trigger/_base/__init__.py +3 -0
  156. digitalhub/entities/trigger/_base/builder.py +4 -0
  157. digitalhub/entities/trigger/_base/entity.py +15 -0
  158. digitalhub/entities/trigger/_base/spec.py +4 -0
  159. digitalhub/entities/trigger/_base/status.py +4 -0
  160. digitalhub/entities/trigger/crud.py +4 -0
  161. digitalhub/entities/trigger/lifecycle/__init__.py +3 -0
  162. digitalhub/entities/trigger/lifecycle/builder.py +4 -0
  163. digitalhub/entities/trigger/lifecycle/entity.py +4 -0
  164. digitalhub/entities/trigger/lifecycle/spec.py +4 -0
  165. digitalhub/entities/trigger/lifecycle/status.py +4 -0
  166. digitalhub/entities/trigger/scheduler/__init__.py +3 -0
  167. digitalhub/entities/trigger/scheduler/builder.py +4 -0
  168. digitalhub/entities/trigger/scheduler/entity.py +4 -0
  169. digitalhub/entities/trigger/scheduler/spec.py +4 -0
  170. digitalhub/entities/trigger/scheduler/status.py +4 -0
  171. digitalhub/entities/workflow/__init__.py +3 -0
  172. digitalhub/entities/workflow/_base/__init__.py +3 -0
  173. digitalhub/entities/workflow/_base/builder.py +4 -0
  174. digitalhub/entities/workflow/_base/entity.py +4 -0
  175. digitalhub/entities/workflow/_base/spec.py +4 -0
  176. digitalhub/entities/workflow/_base/status.py +4 -0
  177. digitalhub/entities/workflow/crud.py +4 -0
  178. digitalhub/factory/__init__.py +3 -0
  179. digitalhub/factory/factory.py +29 -3
  180. digitalhub/factory/utils.py +15 -3
  181. digitalhub/runtimes/__init__.py +3 -0
  182. digitalhub/runtimes/_base.py +5 -1
  183. digitalhub/runtimes/builder.py +22 -1
  184. digitalhub/runtimes/enums.py +4 -0
  185. digitalhub/stores/__init__.py +3 -0
  186. digitalhub/stores/client/__init__.py +15 -0
  187. digitalhub/stores/client/_base/__init__.py +3 -0
  188. digitalhub/stores/client/_base/api_builder.py +18 -0
  189. digitalhub/stores/client/_base/client.py +97 -0
  190. digitalhub/stores/client/_base/key_builder.py +32 -0
  191. digitalhub/stores/client/_base/params_builder.py +18 -0
  192. digitalhub/stores/client/api.py +14 -5
  193. digitalhub/stores/client/builder.py +7 -1
  194. digitalhub/stores/client/dhcore/__init__.py +3 -0
  195. digitalhub/stores/client/dhcore/api_builder.py +21 -0
  196. digitalhub/stores/client/dhcore/client.py +329 -70
  197. digitalhub/stores/client/dhcore/configurator.py +489 -193
  198. digitalhub/stores/client/dhcore/enums.py +7 -0
  199. digitalhub/stores/client/dhcore/error_parser.py +39 -1
  200. digitalhub/stores/client/dhcore/key_builder.py +4 -0
  201. digitalhub/stores/client/dhcore/models.py +4 -0
  202. digitalhub/stores/client/dhcore/params_builder.py +117 -17
  203. digitalhub/stores/client/dhcore/utils.py +44 -22
  204. digitalhub/stores/client/local/__init__.py +3 -0
  205. digitalhub/stores/client/local/api_builder.py +21 -0
  206. digitalhub/stores/client/local/client.py +10 -8
  207. digitalhub/stores/client/local/enums.py +4 -0
  208. digitalhub/stores/client/local/key_builder.py +4 -0
  209. digitalhub/stores/client/local/params_builder.py +4 -0
  210. digitalhub/stores/credentials/__init__.py +3 -0
  211. digitalhub/stores/credentials/api.py +35 -0
  212. digitalhub/stores/credentials/configurator.py +210 -0
  213. digitalhub/stores/credentials/enums.py +68 -0
  214. digitalhub/stores/credentials/handler.py +176 -0
  215. digitalhub/stores/credentials/ini_module.py +164 -0
  216. digitalhub/stores/credentials/store.py +81 -0
  217. digitalhub/stores/data/__init__.py +3 -0
  218. digitalhub/stores/data/_base/__init__.py +3 -0
  219. digitalhub/stores/data/_base/store.py +31 -9
  220. digitalhub/stores/data/api.py +53 -9
  221. digitalhub/stores/data/builder.py +94 -41
  222. digitalhub/stores/data/enums.py +4 -0
  223. digitalhub/stores/data/local/__init__.py +3 -0
  224. digitalhub/stores/data/local/store.py +8 -7
  225. digitalhub/stores/data/remote/__init__.py +3 -0
  226. digitalhub/stores/data/remote/store.py +8 -7
  227. digitalhub/stores/data/s3/__init__.py +3 -0
  228. digitalhub/stores/data/s3/configurator.py +69 -80
  229. digitalhub/stores/data/s3/store.py +73 -81
  230. digitalhub/stores/data/s3/utils.py +14 -10
  231. digitalhub/stores/data/sql/__init__.py +3 -0
  232. digitalhub/stores/data/sql/configurator.py +80 -73
  233. digitalhub/stores/data/sql/store.py +195 -102
  234. digitalhub/stores/readers/__init__.py +3 -0
  235. digitalhub/stores/readers/data/__init__.py +3 -0
  236. digitalhub/stores/readers/data/_base/__init__.py +3 -0
  237. digitalhub/stores/readers/data/_base/builder.py +4 -0
  238. digitalhub/stores/readers/data/_base/reader.py +4 -0
  239. digitalhub/stores/readers/data/api.py +4 -0
  240. digitalhub/stores/readers/data/factory.py +4 -0
  241. digitalhub/stores/readers/data/pandas/__init__.py +3 -0
  242. digitalhub/stores/readers/data/pandas/builder.py +4 -0
  243. digitalhub/stores/readers/data/pandas/reader.py +4 -0
  244. digitalhub/stores/readers/query/__init__.py +3 -0
  245. digitalhub/utils/__init__.py +3 -0
  246. digitalhub/utils/enums.py +4 -0
  247. digitalhub/utils/exceptions.py +10 -0
  248. digitalhub/utils/file_utils.py +57 -30
  249. digitalhub/utils/generic_utils.py +45 -33
  250. digitalhub/utils/git_utils.py +28 -14
  251. digitalhub/utils/io_utils.py +23 -18
  252. digitalhub/utils/logger.py +4 -0
  253. digitalhub/utils/types.py +4 -0
  254. digitalhub/utils/uri_utils.py +35 -31
  255. digitalhub-0.13.0.dist-info/METADATA +301 -0
  256. digitalhub-0.13.0.dist-info/RECORD +259 -0
  257. digitalhub-0.13.0.dist-info/licenses/AUTHORS +5 -0
  258. digitalhub-0.13.0.dist-info/licenses/LICENSE +201 -0
  259. digitalhub/entities/_commons/types.py +0 -5
  260. digitalhub/stores/configurator/__init__.py +0 -0
  261. digitalhub/stores/configurator/api.py +0 -31
  262. digitalhub/stores/configurator/configurator.py +0 -198
  263. digitalhub/stores/configurator/credentials_store.py +0 -65
  264. digitalhub/stores/configurator/enums.py +0 -21
  265. digitalhub/stores/configurator/ini_module.py +0 -128
  266. digitalhub/stores/data/s3/enums.py +0 -16
  267. digitalhub/stores/data/sql/enums.py +0 -16
  268. digitalhub/stores/data/utils.py +0 -34
  269. digitalhub-0.11.0b7.dist-info/METADATA +0 -259
  270. digitalhub-0.11.0b7.dist-info/RECORD +0 -261
  271. digitalhub-0.11.0b7.dist-info/licenses/LICENSE.txt +0 -216
  272. {digitalhub-0.11.0b7.dist-info → digitalhub-0.13.0.dist-info}/WHEEL +0 -0
@@ -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,21 @@ 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
13
18
  from digitalhub.stores.data._base.store import Store
14
- from digitalhub.stores.data.s3.configurator import S3StoreConfigurator
15
19
  from digitalhub.stores.data.s3.utils import get_bucket_name
16
20
  from digitalhub.stores.readers.data.api import get_reader_by_object
17
- from digitalhub.utils.exceptions import StoreError
21
+ from digitalhub.utils.exceptions import ConfigError, StoreError
18
22
  from digitalhub.utils.file_utils import get_file_info_from_s3, get_file_mime_type
19
23
  from digitalhub.utils.types import SourcesOrListOfSources
20
24
 
25
+ if typing.TYPE_CHECKING:
26
+ from digitalhub.stores.credentials.configurator import Configurator
27
+ from digitalhub.stores.data.s3.configurator import S3StoreConfigurator
28
+
29
+
21
30
  # Type aliases
22
31
  S3Client = Type["botocore.client.S3"]
23
32
 
@@ -28,8 +37,9 @@ class S3Store(Store):
28
37
  artifacts on S3 based storage.
29
38
  """
30
39
 
31
- def __init__(self) -> None:
32
- self._configurator = S3StoreConfigurator()
40
+ def __init__(self, configurator: Configurator | None = None) -> None:
41
+ super().__init__(configurator)
42
+ self._configurator: S3StoreConfigurator
33
43
 
34
44
  ##############################
35
45
  # I/O methods
@@ -37,9 +47,8 @@ class S3Store(Store):
37
47
 
38
48
  def download(
39
49
  self,
40
- root: str,
50
+ src: str,
41
51
  dst: Path,
42
- src: list[str],
43
52
  overwrite: bool = False,
44
53
  ) -> str:
45
54
  """
@@ -47,21 +56,19 @@ class S3Store(Store):
47
56
 
48
57
  Parameters
49
58
  ----------
50
- root : str
51
- The root path of the artifact.
59
+ src : str
60
+ Path of the material entity.
52
61
  dst : str
53
- The destination of the artifact on local filesystem.
54
- src : list[str]
55
- List of sources.
62
+ The destination of the material entity on local filesystem.
56
63
  overwrite : bool
57
64
  Specify if overwrite existing file(s).
58
65
 
59
66
  Returns
60
67
  -------
61
68
  str
62
- Destination path of the downloaded artifact.
69
+ Destination path of the downloaded files.
63
70
  """
64
- client, bucket = self._check_factory(root)
71
+ client, bucket = self._check_factory(src)
65
72
 
66
73
  # Build destination directory
67
74
  if dst.suffix == "":
@@ -70,20 +77,13 @@ class S3Store(Store):
70
77
  dst.parent.mkdir(parents=True, exist_ok=True)
71
78
 
72
79
  # 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]
80
+ if self.is_partition(src):
81
+ keys = self._list_objects(client, bucket, src)
82
+ strip_root = self._get_key(src)
83
+ trees = [k.removeprefix(strip_root) for k in keys]
81
84
  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]
85
+ keys = [self._get_key(src)]
86
+ trees = [Path(self._get_key(src)).name]
87
87
 
88
88
  if len(keys) != len(trees):
89
89
  raise StoreError("Keys and trees must have the same length.")
@@ -124,7 +124,7 @@ class S3Store(Store):
124
124
  src : SourcesOrListOfSources
125
125
  Source(s).
126
126
  dst : str
127
- The destination of the artifact on storage.
127
+ The destination of the material entity on storage.
128
128
 
129
129
  Returns
130
130
  -------
@@ -410,7 +410,7 @@ class S3Store(Store):
410
410
  src : str
411
411
  List of sources.
412
412
  dst : str
413
- The destination of the artifact on storage.
413
+ The destination of the material entity on storage.
414
414
  client : S3Client
415
415
  The S3 client object.
416
416
  bucket : str
@@ -453,7 +453,7 @@ class S3Store(Store):
453
453
  src : list
454
454
  List of sources.
455
455
  dst : str
456
- The destination of the artifact on storage.
456
+ The destination of the material entity on storage.
457
457
  client : S3Client
458
458
  The S3 client object.
459
459
  bucket : str
@@ -493,7 +493,7 @@ class S3Store(Store):
493
493
  src : str
494
494
  List of sources.
495
495
  dst : str
496
- The destination of the artifact on storage.
496
+ The destination of the material entity on storage.
497
497
  client : S3Client
498
498
  The S3 client object.
499
499
  bucket : str
@@ -542,7 +542,13 @@ class S3Store(Store):
542
542
  mime_type = get_file_mime_type(src)
543
543
  if mime_type is not None:
544
544
  extra_args["ContentType"] = mime_type
545
- client.upload_file(Filename=src, Bucket=bucket, Key=key, ExtraArgs=extra_args)
545
+ client.upload_file(
546
+ Filename=src,
547
+ Bucket=bucket,
548
+ Key=key,
549
+ ExtraArgs=extra_args,
550
+ Config=TransferConfig(multipart_threshold=100 * 1024 * 1024),
551
+ )
546
552
 
547
553
  @staticmethod
548
554
  def _upload_fileobject(
@@ -569,7 +575,12 @@ class S3Store(Store):
569
575
  -------
570
576
  None
571
577
  """
572
- client.put_object(Bucket=bucket, Key=key, Body=fileobj.getvalue())
578
+ client.upload_fileobj(
579
+ Fileobj=fileobj,
580
+ Bucket=bucket,
581
+ Key=key,
582
+ Config=TransferConfig(multipart_threshold=100 * 1024 * 1024),
583
+ )
573
584
 
574
585
  ##############################
575
586
  # Helper methods
@@ -602,55 +613,59 @@ class S3Store(Store):
602
613
  """
603
614
  return boto3.client("s3", **cfg)
604
615
 
605
- def _check_factory(self, root: str) -> tuple[S3Client, str]:
616
+ def _check_factory(self, s3_path: str, retry: bool = True) -> tuple[S3Client, str]:
606
617
  """
607
- Check if the S3 bucket is accessible by sending a head_bucket request.
618
+ Checks if the S3 bucket collected from the URI is accessible.
619
+
620
+ Parameters
621
+ ----------
622
+ s3_path : str
623
+ Path to the S3 bucket (e.g., 's3://bucket/path').
624
+ retry : bool, optional
625
+ Whether to retry the operation if a ConfigError is raised. Default is True.
608
626
 
609
627
  Returns
610
628
  -------
611
- tuple[S3Client, str]
612
- A tuple containing the S3 client object and the name of the S3 bucket.
613
- """
614
- bucket = self._get_bucket(root)
629
+ tuple of S3Client and str
630
+ Tuple containing the S3 client object and the name of the S3 bucket.
615
631
 
616
- # Try to get client from environment variables
632
+ Raises
633
+ ------
634
+ ConfigError
635
+ If access to the specified bucket is not available and retry is False.
636
+ """
637
+ bucket = self._get_bucket(s3_path)
617
638
  try:
618
- cfg = self._configurator.get_boto3_client_config(CredsOrigin.ENV.value)
639
+ cfg = self._configurator.get_client_config()
619
640
  client = self._get_client(cfg)
620
641
  self._check_access_to_storage(client, bucket)
621
-
622
- # Fallback to file
623
- except StoreError:
624
- cfg = self._configurator.get_boto3_client_config(CredsOrigin.FILE.value)
625
- client = self._get_client(cfg)
626
- self._check_access_to_storage(client, bucket)
627
-
628
- return client, bucket
642
+ return client, bucket
643
+ except ConfigError as e:
644
+ if retry:
645
+ self._configurator.eval_change_origin()
646
+ return self._check_factory(s3_path, False)
647
+ raise e
629
648
 
630
649
  def _check_access_to_storage(self, client: S3Client, bucket: str) -> None:
631
650
  """
632
- Check if the S3 bucket is accessible by sending a head_bucket request.
651
+ Checks if the S3 bucket is accessible by sending a head_bucket request.
633
652
 
634
653
  Parameters
635
654
  ----------
636
655
  client : S3Client
637
- The S3 client object.
656
+ S3 client object.
638
657
  bucket : str
639
- The name of the S3 bucket.
640
-
641
- Returns
642
- -------
643
- None
658
+ Name of the S3 bucket.
644
659
 
645
660
  Raises
646
661
  ------
647
- ClientError:
662
+ ConfigError
648
663
  If access to the specified bucket is not available.
649
664
  """
650
665
  try:
651
666
  client.head_bucket(Bucket=bucket)
652
667
  except (ClientError, NoCredentialsError) as err:
653
- raise StoreError(f"No access to s3 bucket! Error: {err}")
668
+ raise ConfigError(f"No access to s3 bucket! Error: {err}")
654
669
 
655
670
  @staticmethod
656
671
  def _get_key(path: str) -> str:
@@ -672,29 +687,6 @@ class S3Store(Store):
672
687
  key = key[1:]
673
688
  return key
674
689
 
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
690
  def _list_objects(self, client: S3Client, bucket: str, partition: str) -> list[str]:
699
691
  """
700
692
  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,41 +9,41 @@ 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
 
12
16
 
13
17
  def get_bucket_name(path: str) -> str:
14
18
  """
15
- Get bucket name from path.
19
+ Extract the bucket name from an S3 path.
16
20
 
17
21
  Parameters
18
22
  ----------
19
23
  path : str
20
- The source path to get the key from.
24
+ S3 URI (e.g., 's3://bucket/key').
21
25
 
22
26
  Returns
23
27
  -------
24
28
  str
25
- The bucket name.
29
+ The bucket name extracted from the URI.
26
30
  """
27
31
  return urlparse(path).netloc
28
32
 
29
33
 
30
34
  def get_bucket_and_key(path: str) -> tuple[str, str]:
31
35
  """
32
- Get bucket and key from path.
36
+ Extract the bucket name and key from an S3 path.
33
37
 
34
38
  Parameters
35
39
  ----------
36
40
  path : str
37
- The source path to get the key from.
41
+ S3 URI (e.g., 's3://bucket/key').
38
42
 
39
43
  Returns
40
44
  -------
41
- tuple[str, str]
42
- The bucket and key.
45
+ tuple of str
46
+ Tuple containing (bucket, key) extracted from the URI.
43
47
  """
44
48
  parsed = urlparse(path)
45
49
  return parsed.netloc, parsed.path
@@ -47,7 +51,7 @@ def get_bucket_and_key(path: str) -> tuple[str, str]:
47
51
 
48
52
  def get_s3_source(bucket: str, key: str, filename: Path) -> None:
49
53
  """
50
- Get S3 source.
54
+ Download an object from S3 and save it to a local file.
51
55
 
52
56
  Parameters
53
57
  ----------
@@ -56,7 +60,7 @@ def get_s3_source(bucket: str, key: str, filename: Path) -> None:
56
60
  key : str
57
61
  S3 object key.
58
62
  filename : Path
59
- Path where to save the function source.
63
+ Local path where the downloaded object will be saved.
60
64
 
61
65
  Returns
62
66
  -------
@@ -0,0 +1,3 @@
1
+ # SPDX-FileCopyrightText: © 2025 DSLab - Fondazione Bruno Kessler
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
@@ -1,113 +1,120 @@
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
- from digitalhub.stores.configurator.configurator import configurator
4
- from digitalhub.stores.configurator.enums import CredsOrigin
5
- from digitalhub.stores.data.sql.enums import SqlStoreEnv
6
- from digitalhub.utils.exceptions import StoreError
7
+ from digitalhub.stores.credentials.configurator import Configurator
8
+ from digitalhub.stores.credentials.enums import CredsEnvVar
7
9
 
8
10
 
9
- class SqlStoreConfigurator:
11
+ class SqlStoreConfigurator(Configurator):
10
12
  """
11
- Configure the store by getting the credentials from user
12
- provided config or from environment.
13
+ SQL store configuration manager for database connections.
14
+
15
+ Handles credential management and configuration for SQL database
16
+ connections. Loads credentials from environment variables or
17
+ configuration files and provides connection string generation
18
+ for database access.
19
+
20
+ Attributes
21
+ ----------
22
+ keys : list[str]
23
+ List of all supported credential keys for SQL connections.
24
+ required_keys : list[str]
25
+ List of mandatory credential keys that must be provided.
13
26
  """
14
27
 
15
- required_vars = [
16
- SqlStoreEnv.USERNAME,
17
- SqlStoreEnv.PASSWORD,
18
- SqlStoreEnv.HOST,
19
- SqlStoreEnv.PORT,
20
- SqlStoreEnv.DATABASE,
28
+ keys = [
29
+ CredsEnvVar.DB_USERNAME.value,
30
+ CredsEnvVar.DB_PASSWORD.value,
31
+ CredsEnvVar.DB_HOST.value,
32
+ CredsEnvVar.DB_PORT.value,
33
+ CredsEnvVar.DB_DATABASE.value,
34
+ CredsEnvVar.DB_PLATFORM.value,
35
+ ]
36
+ required_keys = [
37
+ CredsEnvVar.DB_USERNAME.value,
38
+ CredsEnvVar.DB_PASSWORD.value,
39
+ CredsEnvVar.DB_HOST.value,
40
+ CredsEnvVar.DB_PORT.value,
41
+ CredsEnvVar.DB_DATABASE.value,
21
42
  ]
22
43
 
44
+ def __init__(self):
45
+ super().__init__()
46
+ self.load_configs()
47
+
23
48
  ##############################
24
49
  # Configuration methods
25
50
  ##############################
26
51
 
27
- def get_sql_conn_string(self, origin: str) -> str:
52
+ def load_env_vars(self) -> None:
28
53
  """
29
- Get the connection string from environment variables.
54
+ Load database credentials from environment variables.
30
55
 
31
- Parameters
32
- ----------
33
- origin : str
34
- The origin of the credentials.
56
+ Retrieves SQL database connection credentials from the system
57
+ environment variables and stores them in the configurator's
58
+ credential handler for use in database connections.
35
59
 
36
60
  Returns
37
61
  -------
38
- str
39
- The connection string.
62
+ None
40
63
  """
41
- if origin == CredsOrigin.ENV.value:
42
- creds = self._get_env_config()
43
- elif origin == CredsOrigin.FILE.value:
44
- creds = self._get_file_config()
45
- else:
46
- raise StoreError(f"Unknown origin: {origin}")
47
-
48
- user = creds[SqlStoreEnv.USERNAME.value]
49
- password = creds[SqlStoreEnv.PASSWORD.value]
50
- host = creds[SqlStoreEnv.HOST.value]
51
- port = creds[SqlStoreEnv.PORT.value]
52
- database = creds[SqlStoreEnv.DATABASE.value]
53
- return f"postgresql://{user}:{password}@{host}:{port}/{database}"
64
+ env_creds = self._creds_handler.load_from_env(self.keys)
65
+ self._creds_handler.set_credentials(self._env, env_creds)
54
66
 
55
- def _get_env_config(self) -> dict:
67
+ def load_file_vars(self) -> None:
56
68
  """
57
- Get the store configuration from environment variables.
69
+ Load database credentials from configuration file.
58
70
 
59
- Returns
60
- -------
61
- dict
62
- The credentials.
63
- """
64
- credentials = {var.value: configurator.load_from_env(var.value) for var in self.required_vars}
65
- self._set_credentials(credentials)
66
- return credentials
67
-
68
- def _get_file_config(self) -> dict:
69
- """
70
- Get the store configuration from file.
71
+ Retrieves SQL database connection credentials from a
72
+ configuration file and stores them in the configurator's
73
+ credential handler for use in database connections.
71
74
 
72
75
  Returns
73
76
  -------
74
- dict
75
- The credentials.
77
+ None
76
78
  """
77
- credentials = {var.value: configurator.load_from_file(var.value) for var in self.required_vars}
78
- self._set_credentials(credentials)
79
- return credentials
79
+ file_creds = self._creds_handler.load_from_file(self.keys)
80
+ self._creds_handler.set_credentials(self._file, file_creds)
80
81
 
81
- def _check_credentials(self, credentials: dict) -> None:
82
+ def get_sql_conn_string(self) -> str:
82
83
  """
83
- Check for missing credentials.
84
+ Generate PostgreSQL connection string from stored credentials.
84
85
 
85
- Parameters
86
- ----------
87
- credentials : dict
88
- The credentials.
86
+ Constructs a PostgreSQL connection string using the configured
87
+ database credentials including username, password, host, port,
88
+ and database name.
89
89
 
90
90
  Returns
91
91
  -------
92
- None
92
+ str
93
+ A PostgreSQL connection string in the format:
94
+ 'postgresql://username:password@host:port/database'
93
95
  """
94
- missing_vars = [key for key, value in credentials.items() if value is None and key in self.required_vars]
95
- if missing_vars:
96
- raise StoreError(f"Missing credentials for SQL store: {', '.join(missing_vars)}")
96
+ creds = self.get_sql_credentials()
97
+ user = creds[CredsEnvVar.DB_USERNAME.value]
98
+ password = creds[CredsEnvVar.DB_PASSWORD.value]
99
+ host = creds[CredsEnvVar.DB_HOST.value]
100
+ port = creds[CredsEnvVar.DB_PORT.value]
101
+ database = creds[CredsEnvVar.DB_DATABASE.value]
102
+ return f"postgresql://{user}:{password}@{host}:{port}/{database}"
97
103
 
98
- def _set_credentials(self, credentials: dict) -> None:
104
+ def get_sql_credentials(self) -> dict:
99
105
  """
100
- Set the store credentials into the configurator.
106
+ Get all configured database credentials as a dictionary.
101
107
 
102
- Parameters
103
- ----------
104
- credentials : dict
105
- The credentials.
108
+ Retrieves all available database credentials from the configured
109
+ source and returns them as a dictionary with all credential keys
110
+ from self.keys mapped to their values.
106
111
 
107
112
  Returns
108
113
  -------
109
- None
114
+ dict
115
+ Dictionary containing all credential key-value pairs from self.keys.
116
+ Keys correspond to database connection parameters such as
117
+ username, password, host, port, database, and platform.
110
118
  """
111
- # Set credentials
112
- for key, value in credentials.items():
113
- configurator.set_credential(key, value)
119
+ creds = self.get_credentials(self._origin)
120
+ return {key: creds.get(key) for key in self.keys}