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.
- digitalhub/__init__.py +4 -1
- digitalhub/context/api.py +4 -0
- digitalhub/context/builder.py +4 -0
- digitalhub/context/context.py +4 -0
- digitalhub/entities/__init__.py +3 -0
- digitalhub/entities/_base/__init__.py +3 -0
- digitalhub/entities/_base/_base/__init__.py +3 -0
- digitalhub/entities/_base/_base/entity.py +4 -0
- digitalhub/entities/_base/context/__init__.py +3 -0
- digitalhub/entities/_base/context/entity.py +4 -0
- digitalhub/entities/_base/entity/__init__.py +3 -0
- digitalhub/entities/_base/entity/_constructors/__init__.py +3 -0
- digitalhub/entities/_base/entity/_constructors/metadata.py +4 -0
- digitalhub/entities/_base/entity/_constructors/name.py +4 -0
- digitalhub/entities/_base/entity/_constructors/spec.py +4 -0
- digitalhub/entities/_base/entity/_constructors/status.py +4 -0
- digitalhub/entities/_base/entity/_constructors/uuid.py +4 -0
- digitalhub/entities/_base/entity/builder.py +4 -0
- digitalhub/entities/_base/entity/entity.py +4 -0
- digitalhub/entities/_base/entity/metadata.py +4 -0
- digitalhub/entities/_base/entity/spec.py +4 -0
- digitalhub/entities/_base/entity/status.py +4 -0
- digitalhub/entities/_base/executable/__init__.py +3 -0
- digitalhub/entities/_base/executable/entity.py +11 -0
- digitalhub/entities/_base/material/__init__.py +3 -0
- digitalhub/entities/_base/material/entity.py +12 -15
- digitalhub/entities/_base/material/spec.py +4 -0
- digitalhub/entities/_base/material/status.py +4 -0
- digitalhub/entities/_base/material/utils.py +5 -1
- digitalhub/entities/_base/runtime_entity/__init__.py +3 -0
- digitalhub/entities/_base/runtime_entity/builder.py +4 -0
- digitalhub/entities/_base/unversioned/__init__.py +3 -0
- digitalhub/entities/_base/unversioned/builder.py +4 -0
- digitalhub/entities/_base/unversioned/entity.py +4 -0
- digitalhub/entities/_base/versioned/__init__.py +3 -0
- digitalhub/entities/_base/versioned/builder.py +4 -0
- digitalhub/entities/_base/versioned/entity.py +4 -0
- digitalhub/entities/_commons/__init__.py +3 -0
- digitalhub/entities/_commons/enums.py +4 -0
- digitalhub/entities/_commons/metrics.py +4 -0
- digitalhub/entities/_commons/types.py +4 -0
- digitalhub/entities/_commons/utils.py +4 -0
- digitalhub/entities/_processors/__init__.py +3 -0
- digitalhub/entities/_processors/base.py +4 -0
- digitalhub/entities/_processors/context.py +5 -1
- digitalhub/entities/_processors/utils.py +4 -0
- digitalhub/entities/artifact/__init__.py +3 -0
- digitalhub/entities/artifact/_base/__init__.py +3 -0
- digitalhub/entities/artifact/_base/builder.py +4 -0
- digitalhub/entities/artifact/_base/entity.py +4 -0
- digitalhub/entities/artifact/_base/spec.py +4 -0
- digitalhub/entities/artifact/_base/status.py +4 -0
- digitalhub/entities/artifact/artifact/__init__.py +3 -0
- digitalhub/entities/artifact/artifact/builder.py +4 -0
- digitalhub/entities/artifact/artifact/entity.py +4 -0
- digitalhub/entities/artifact/artifact/spec.py +4 -0
- digitalhub/entities/artifact/artifact/status.py +4 -0
- digitalhub/entities/artifact/crud.py +4 -0
- digitalhub/entities/artifact/utils.py +4 -0
- digitalhub/entities/builders.py +4 -0
- digitalhub/entities/dataitem/__init__.py +3 -0
- digitalhub/entities/dataitem/_base/__init__.py +3 -0
- digitalhub/entities/dataitem/_base/builder.py +4 -0
- digitalhub/entities/dataitem/_base/entity.py +4 -0
- digitalhub/entities/dataitem/_base/spec.py +4 -0
- digitalhub/entities/dataitem/_base/status.py +4 -0
- digitalhub/entities/dataitem/crud.py +4 -0
- digitalhub/entities/dataitem/dataitem/__init__.py +3 -0
- digitalhub/entities/dataitem/dataitem/builder.py +4 -0
- digitalhub/entities/dataitem/dataitem/entity.py +4 -0
- digitalhub/entities/dataitem/dataitem/spec.py +4 -0
- digitalhub/entities/dataitem/dataitem/status.py +4 -0
- digitalhub/entities/dataitem/iceberg/__init__.py +3 -0
- digitalhub/entities/dataitem/iceberg/builder.py +4 -0
- digitalhub/entities/dataitem/iceberg/entity.py +4 -0
- digitalhub/entities/dataitem/iceberg/spec.py +4 -0
- digitalhub/entities/dataitem/iceberg/status.py +4 -0
- digitalhub/entities/dataitem/table/__init__.py +3 -0
- digitalhub/entities/dataitem/table/builder.py +4 -0
- digitalhub/entities/dataitem/table/entity.py +4 -0
- digitalhub/entities/dataitem/table/models.py +4 -0
- digitalhub/entities/dataitem/table/spec.py +4 -0
- digitalhub/entities/dataitem/table/status.py +4 -0
- digitalhub/entities/dataitem/table/utils.py +4 -0
- digitalhub/entities/dataitem/utils.py +4 -0
- digitalhub/entities/function/__init__.py +3 -0
- digitalhub/entities/function/_base/__init__.py +3 -0
- digitalhub/entities/function/_base/builder.py +4 -0
- digitalhub/entities/function/_base/entity.py +4 -0
- digitalhub/entities/function/_base/spec.py +4 -0
- digitalhub/entities/function/_base/status.py +4 -0
- digitalhub/entities/function/crud.py +4 -0
- digitalhub/entities/model/__init__.py +3 -0
- digitalhub/entities/model/_base/__init__.py +3 -0
- digitalhub/entities/model/_base/builder.py +4 -0
- digitalhub/entities/model/_base/entity.py +4 -0
- digitalhub/entities/model/_base/spec.py +4 -0
- digitalhub/entities/model/_base/status.py +4 -0
- digitalhub/entities/model/crud.py +4 -0
- digitalhub/entities/model/huggingface/__init__.py +3 -0
- digitalhub/entities/model/huggingface/builder.py +4 -0
- digitalhub/entities/model/huggingface/entity.py +4 -0
- digitalhub/entities/model/huggingface/spec.py +4 -0
- digitalhub/entities/model/huggingface/status.py +4 -0
- digitalhub/entities/model/mlflow/__init__.py +3 -0
- digitalhub/entities/model/mlflow/builder.py +4 -0
- digitalhub/entities/model/mlflow/entity.py +4 -0
- digitalhub/entities/model/mlflow/models.py +4 -0
- digitalhub/entities/model/mlflow/spec.py +4 -0
- digitalhub/entities/model/mlflow/status.py +4 -0
- digitalhub/entities/model/mlflow/utils.py +4 -0
- digitalhub/entities/model/model/__init__.py +3 -0
- digitalhub/entities/model/model/builder.py +4 -0
- digitalhub/entities/model/model/entity.py +4 -0
- digitalhub/entities/model/model/spec.py +4 -0
- digitalhub/entities/model/model/status.py +4 -0
- digitalhub/entities/model/sklearn/__init__.py +3 -0
- digitalhub/entities/model/sklearn/builder.py +4 -0
- digitalhub/entities/model/sklearn/entity.py +4 -0
- digitalhub/entities/model/sklearn/spec.py +4 -0
- digitalhub/entities/model/sklearn/status.py +4 -0
- digitalhub/entities/model/utils.py +4 -0
- digitalhub/entities/project/__init__.py +3 -0
- digitalhub/entities/project/_base/__init__.py +3 -0
- digitalhub/entities/project/_base/builder.py +4 -0
- digitalhub/entities/project/_base/entity.py +4 -0
- digitalhub/entities/project/_base/models.py +4 -0
- digitalhub/entities/project/_base/spec.py +4 -0
- digitalhub/entities/project/_base/status.py +4 -0
- digitalhub/entities/project/crud.py +4 -0
- digitalhub/entities/project/utils.py +4 -0
- digitalhub/entities/run/__init__.py +3 -0
- digitalhub/entities/run/_base/__init__.py +3 -0
- digitalhub/entities/run/_base/builder.py +4 -0
- digitalhub/entities/run/_base/entity.py +4 -0
- digitalhub/entities/run/_base/spec.py +4 -0
- digitalhub/entities/run/_base/status.py +4 -0
- digitalhub/entities/run/crud.py +4 -0
- digitalhub/entities/secret/__init__.py +3 -0
- digitalhub/entities/secret/_base/__init__.py +3 -0
- digitalhub/entities/secret/_base/builder.py +4 -0
- digitalhub/entities/secret/_base/entity.py +4 -0
- digitalhub/entities/secret/_base/spec.py +4 -0
- digitalhub/entities/secret/_base/status.py +4 -0
- digitalhub/entities/secret/crud.py +4 -0
- digitalhub/entities/task/__init__.py +3 -0
- digitalhub/entities/task/_base/__init__.py +3 -0
- digitalhub/entities/task/_base/builder.py +4 -0
- digitalhub/entities/task/_base/entity.py +4 -0
- digitalhub/entities/task/_base/models.py +4 -0
- digitalhub/entities/task/_base/spec.py +4 -0
- digitalhub/entities/task/_base/status.py +4 -0
- digitalhub/entities/task/_base/utils.py +4 -0
- digitalhub/entities/task/crud.py +4 -0
- digitalhub/entities/trigger/__init__.py +3 -0
- digitalhub/entities/trigger/_base/__init__.py +3 -0
- digitalhub/entities/trigger/_base/builder.py +4 -0
- digitalhub/entities/trigger/_base/entity.py +4 -0
- digitalhub/entities/trigger/_base/spec.py +4 -0
- digitalhub/entities/trigger/_base/status.py +4 -0
- digitalhub/entities/trigger/crud.py +4 -0
- digitalhub/entities/trigger/lifecycle/__init__.py +3 -0
- digitalhub/entities/trigger/lifecycle/builder.py +4 -0
- digitalhub/entities/trigger/lifecycle/entity.py +4 -0
- digitalhub/entities/trigger/lifecycle/spec.py +4 -0
- digitalhub/entities/trigger/lifecycle/status.py +4 -0
- digitalhub/entities/trigger/scheduler/__init__.py +3 -0
- digitalhub/entities/trigger/scheduler/builder.py +4 -0
- digitalhub/entities/trigger/scheduler/entity.py +4 -0
- digitalhub/entities/trigger/scheduler/spec.py +4 -0
- digitalhub/entities/trigger/scheduler/status.py +4 -0
- digitalhub/entities/workflow/__init__.py +3 -0
- digitalhub/entities/workflow/_base/__init__.py +3 -0
- digitalhub/entities/workflow/_base/builder.py +4 -0
- digitalhub/entities/workflow/_base/entity.py +4 -0
- digitalhub/entities/workflow/_base/spec.py +4 -0
- digitalhub/entities/workflow/_base/status.py +4 -0
- digitalhub/entities/workflow/crud.py +4 -0
- digitalhub/factory/__init__.py +3 -0
- digitalhub/factory/factory.py +4 -0
- digitalhub/factory/utils.py +4 -0
- digitalhub/runtimes/__init__.py +3 -0
- digitalhub/runtimes/_base.py +4 -0
- digitalhub/runtimes/builder.py +4 -0
- digitalhub/runtimes/enums.py +4 -0
- digitalhub/stores/__init__.py +3 -0
- digitalhub/stores/client/__init__.py +3 -0
- digitalhub/stores/client/_base/__init__.py +3 -0
- digitalhub/stores/client/_base/api_builder.py +4 -0
- digitalhub/stores/client/_base/client.py +4 -0
- digitalhub/stores/client/_base/key_builder.py +4 -0
- digitalhub/stores/client/_base/params_builder.py +4 -0
- digitalhub/stores/client/api.py +4 -0
- digitalhub/stores/client/builder.py +4 -0
- digitalhub/stores/client/dhcore/__init__.py +3 -0
- digitalhub/stores/client/dhcore/api_builder.py +4 -0
- digitalhub/stores/client/dhcore/client.py +60 -19
- digitalhub/stores/client/dhcore/configurator.py +282 -183
- digitalhub/stores/client/dhcore/enums.py +6 -0
- digitalhub/stores/client/dhcore/error_parser.py +4 -0
- digitalhub/stores/client/dhcore/key_builder.py +4 -0
- digitalhub/stores/client/dhcore/models.py +4 -0
- digitalhub/stores/client/dhcore/params_builder.py +4 -0
- digitalhub/stores/client/dhcore/utils.py +12 -8
- digitalhub/stores/client/local/__init__.py +3 -0
- digitalhub/stores/client/local/api_builder.py +4 -0
- digitalhub/stores/client/local/client.py +4 -0
- digitalhub/stores/client/local/enums.py +4 -0
- digitalhub/stores/client/local/key_builder.py +4 -0
- digitalhub/stores/client/local/params_builder.py +4 -0
- digitalhub/stores/credentials/__init__.py +3 -0
- digitalhub/stores/{configurator → credentials}/api.py +7 -3
- digitalhub/stores/credentials/configurator.py +37 -0
- digitalhub/stores/credentials/enums.py +54 -0
- digitalhub/stores/credentials/handler.py +148 -0
- digitalhub/stores/{configurator → credentials}/ini_module.py +5 -1
- digitalhub/stores/credentials/store.py +49 -0
- digitalhub/stores/data/__init__.py +3 -0
- digitalhub/stores/data/_base/__init__.py +3 -0
- digitalhub/stores/data/_base/store.py +23 -6
- digitalhub/stores/data/api.py +41 -1
- digitalhub/stores/data/builder.py +50 -53
- digitalhub/stores/data/enums.py +4 -0
- digitalhub/stores/data/local/__init__.py +3 -0
- digitalhub/stores/data/local/store.py +8 -7
- digitalhub/stores/data/remote/__init__.py +3 -0
- digitalhub/stores/data/remote/store.py +8 -7
- digitalhub/stores/data/s3/__init__.py +3 -0
- digitalhub/stores/data/s3/configurator.py +40 -92
- digitalhub/stores/data/s3/store.py +46 -57
- digitalhub/stores/data/s3/utils.py +5 -1
- digitalhub/stores/data/sql/__init__.py +3 -0
- digitalhub/stores/data/sql/configurator.py +39 -83
- digitalhub/stores/data/sql/store.py +19 -15
- digitalhub/stores/readers/__init__.py +3 -0
- digitalhub/stores/readers/data/__init__.py +3 -0
- digitalhub/stores/readers/data/_base/__init__.py +3 -0
- digitalhub/stores/readers/data/_base/builder.py +4 -0
- digitalhub/stores/readers/data/_base/reader.py +4 -0
- digitalhub/stores/readers/data/api.py +4 -0
- digitalhub/stores/readers/data/factory.py +4 -0
- digitalhub/stores/readers/data/pandas/__init__.py +3 -0
- digitalhub/stores/readers/data/pandas/builder.py +4 -0
- digitalhub/stores/readers/data/pandas/reader.py +4 -0
- digitalhub/stores/readers/query/__init__.py +3 -0
- digitalhub/utils/__init__.py +3 -0
- digitalhub/utils/enums.py +4 -0
- digitalhub/utils/exceptions.py +4 -0
- digitalhub/utils/file_utils.py +4 -0
- digitalhub/utils/generic_utils.py +4 -0
- digitalhub/utils/git_utils.py +4 -0
- digitalhub/utils/io_utils.py +4 -0
- digitalhub/utils/logger.py +4 -0
- digitalhub/utils/types.py +4 -0
- digitalhub/utils/uri_utils.py +4 -0
- digitalhub-0.13.0b0.dist-info/METADATA +301 -0
- digitalhub-0.13.0b0.dist-info/RECORD +260 -0
- digitalhub-0.13.0b0.dist-info/licenses/AUTHORS +5 -0
- digitalhub-0.13.0b0.dist-info/licenses/LICENSE +201 -0
- digitalhub/stores/configurator/__init__.py +0 -0
- digitalhub/stores/configurator/configurator.py +0 -198
- digitalhub/stores/configurator/credentials_store.py +0 -65
- digitalhub/stores/configurator/enums.py +0 -21
- digitalhub/stores/data/s3/enums.py +0 -16
- digitalhub/stores/data/sql/enums.py +0 -16
- digitalhub/stores/data/utils.py +0 -34
- digitalhub-0.11.0b7.dist-info/METADATA +0 -259
- digitalhub-0.11.0b7.dist-info/RECORD +0 -261
- digitalhub-0.11.0b7.dist-info/licenses/LICENSE.txt +0 -216
- {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.
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
store_type :
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
-
|
|
64
|
+
env_profile = get_current_env()
|
|
85
65
|
store_type = map_uri_scheme(uri)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
self.
|
|
90
|
-
|
|
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)
|
digitalhub/stores/data/enums.py
CHANGED
|
@@ -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
|
-
|
|
37
|
-
|
|
39
|
+
src : str
|
|
40
|
+
Path of the material entity.
|
|
38
41
|
dst : str
|
|
39
|
-
The destination of the
|
|
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
|
|
49
|
+
Destination path of the downloaded files.
|
|
49
50
|
"""
|
|
50
51
|
raise StoreError("Local store does not support download.")
|
|
51
52
|
|
|
@@ -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
|
-
|
|
36
|
-
|
|
38
|
+
src : str
|
|
39
|
+
Path of the material entity.
|
|
37
40
|
dst : str
|
|
38
|
-
The destination of the
|
|
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
|
|
48
|
+
Destination path of the downloaded files.
|
|
48
49
|
"""
|
|
49
50
|
# Handle destination
|
|
50
51
|
if dst is None:
|
|
@@ -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.
|
|
6
|
-
from digitalhub.stores.
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
|
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
|
-
|
|
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[
|
|
55
|
-
"aws_access_key_id": creds[
|
|
56
|
-
"aws_secret_access_key": creds[
|
|
57
|
-
"aws_session_token": creds[
|
|
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[
|
|
60
|
-
signature_version=creds[
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
51
|
-
|
|
60
|
+
src : str
|
|
61
|
+
Path of the material entity.
|
|
52
62
|
dst : str
|
|
53
|
-
The destination of the
|
|
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
|
|
70
|
+
Destination path of the downloaded files.
|
|
63
71
|
"""
|
|
64
|
-
client, bucket = self._check_factory(
|
|
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(
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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(
|
|
83
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|