digitalhub 0.13.0b3__py3-none-any.whl → 0.14.9__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.
- digitalhub/__init__.py +3 -8
- digitalhub/context/api.py +43 -6
- digitalhub/context/builder.py +1 -5
- digitalhub/context/context.py +28 -13
- digitalhub/entities/_base/_base/entity.py +0 -15
- digitalhub/entities/_base/context/entity.py +1 -4
- digitalhub/entities/_base/entity/builder.py +5 -5
- digitalhub/entities/_base/entity/entity.py +0 -8
- digitalhub/entities/_base/executable/entity.py +195 -87
- digitalhub/entities/_base/material/entity.py +11 -23
- digitalhub/entities/_base/material/utils.py +28 -4
- digitalhub/entities/_base/runtime_entity/builder.py +53 -18
- digitalhub/entities/_base/unversioned/entity.py +1 -1
- digitalhub/entities/_base/versioned/entity.py +1 -1
- digitalhub/entities/_commons/enums.py +1 -31
- digitalhub/entities/_commons/metrics.py +64 -30
- digitalhub/entities/_commons/utils.py +119 -30
- digitalhub/entities/_constructors/_resources.py +151 -0
- digitalhub/entities/{_base/entity/_constructors → _constructors}/name.py +18 -0
- digitalhub/entities/_processors/base/crud.py +381 -0
- digitalhub/entities/_processors/base/import_export.py +118 -0
- digitalhub/entities/_processors/base/processor.py +299 -0
- digitalhub/entities/_processors/base/special_ops.py +104 -0
- digitalhub/entities/_processors/context/crud.py +652 -0
- digitalhub/entities/_processors/context/import_export.py +242 -0
- digitalhub/entities/_processors/context/material.py +123 -0
- digitalhub/entities/_processors/context/processor.py +400 -0
- digitalhub/entities/_processors/context/special_ops.py +476 -0
- digitalhub/entities/_processors/processors.py +12 -0
- digitalhub/entities/_processors/utils.py +38 -102
- digitalhub/entities/artifact/crud.py +58 -22
- digitalhub/entities/artifact/utils.py +28 -13
- digitalhub/entities/builders.py +2 -0
- digitalhub/entities/dataitem/crud.py +63 -20
- digitalhub/entities/dataitem/table/entity.py +27 -22
- digitalhub/entities/dataitem/utils.py +82 -32
- digitalhub/entities/function/_base/entity.py +3 -6
- digitalhub/entities/function/crud.py +55 -24
- digitalhub/entities/model/_base/entity.py +62 -20
- digitalhub/entities/model/crud.py +59 -23
- digitalhub/entities/model/mlflow/utils.py +29 -20
- digitalhub/entities/model/utils.py +28 -13
- digitalhub/entities/project/_base/builder.py +0 -6
- digitalhub/entities/project/_base/entity.py +337 -164
- digitalhub/entities/project/_base/spec.py +4 -4
- digitalhub/entities/project/crud.py +28 -71
- digitalhub/entities/project/utils.py +7 -3
- digitalhub/entities/run/_base/builder.py +0 -4
- digitalhub/entities/run/_base/entity.py +70 -63
- digitalhub/entities/run/crud.py +79 -26
- digitalhub/entities/secret/_base/entity.py +1 -5
- digitalhub/entities/secret/crud.py +31 -28
- digitalhub/entities/task/_base/builder.py +0 -4
- digitalhub/entities/task/_base/entity.py +5 -5
- digitalhub/entities/task/_base/models.py +13 -16
- digitalhub/entities/task/crud.py +61 -29
- digitalhub/entities/trigger/_base/entity.py +1 -5
- digitalhub/entities/trigger/crud.py +89 -30
- digitalhub/entities/workflow/_base/entity.py +3 -8
- digitalhub/entities/workflow/crud.py +55 -24
- digitalhub/factory/entity.py +283 -0
- digitalhub/factory/enums.py +18 -0
- digitalhub/factory/registry.py +197 -0
- digitalhub/factory/runtime.py +44 -0
- digitalhub/factory/utils.py +3 -54
- digitalhub/runtimes/_base.py +2 -2
- digitalhub/stores/client/{dhcore/api_builder.py → api_builder.py} +3 -3
- digitalhub/stores/client/builder.py +19 -31
- digitalhub/stores/client/client.py +322 -0
- digitalhub/stores/client/configurator.py +408 -0
- digitalhub/stores/client/enums.py +50 -0
- digitalhub/stores/client/{dhcore/error_parser.py → error_parser.py} +0 -4
- digitalhub/stores/client/header_manager.py +61 -0
- digitalhub/stores/client/http_handler.py +152 -0
- digitalhub/stores/client/{_base/key_builder.py → key_builder.py} +14 -14
- digitalhub/stores/client/params_builder.py +330 -0
- digitalhub/stores/client/response_processor.py +102 -0
- digitalhub/stores/client/utils.py +35 -0
- digitalhub/stores/{credentials → configurator}/api.py +5 -9
- digitalhub/stores/configurator/configurator.py +123 -0
- digitalhub/stores/{credentials → configurator}/enums.py +27 -10
- digitalhub/stores/configurator/handler.py +213 -0
- digitalhub/stores/{credentials → configurator}/ini_module.py +31 -22
- digitalhub/stores/data/_base/store.py +0 -20
- digitalhub/stores/data/api.py +5 -7
- digitalhub/stores/data/builder.py +53 -27
- digitalhub/stores/data/local/store.py +0 -103
- digitalhub/stores/data/remote/store.py +0 -4
- digitalhub/stores/data/s3/configurator.py +39 -77
- digitalhub/stores/data/s3/store.py +57 -37
- digitalhub/stores/data/sql/configurator.py +66 -46
- digitalhub/stores/data/sql/store.py +171 -104
- digitalhub/stores/readers/data/factory.py +0 -8
- digitalhub/stores/readers/data/pandas/reader.py +9 -19
- digitalhub/utils/file_utils.py +0 -17
- digitalhub/utils/generic_utils.py +1 -14
- digitalhub/utils/git_utils.py +0 -8
- digitalhub/utils/io_utils.py +0 -12
- digitalhub/utils/store_utils.py +44 -0
- {digitalhub-0.13.0b3.dist-info → digitalhub-0.14.9.dist-info}/METADATA +5 -4
- {digitalhub-0.13.0b3.dist-info → digitalhub-0.14.9.dist-info}/RECORD +112 -113
- {digitalhub-0.13.0b3.dist-info → digitalhub-0.14.9.dist-info}/WHEEL +1 -1
- digitalhub/entities/_commons/types.py +0 -9
- digitalhub/entities/_processors/base.py +0 -531
- digitalhub/entities/_processors/context.py +0 -1299
- digitalhub/entities/task/_base/utils.py +0 -22
- digitalhub/factory/factory.py +0 -381
- digitalhub/stores/client/_base/api_builder.py +0 -34
- digitalhub/stores/client/_base/client.py +0 -243
- digitalhub/stores/client/_base/params_builder.py +0 -34
- digitalhub/stores/client/api.py +0 -36
- digitalhub/stores/client/dhcore/client.py +0 -613
- digitalhub/stores/client/dhcore/configurator.py +0 -675
- digitalhub/stores/client/dhcore/enums.py +0 -34
- digitalhub/stores/client/dhcore/key_builder.py +0 -62
- digitalhub/stores/client/dhcore/models.py +0 -40
- digitalhub/stores/client/dhcore/params_builder.py +0 -278
- digitalhub/stores/client/dhcore/utils.py +0 -94
- digitalhub/stores/client/local/api_builder.py +0 -116
- digitalhub/stores/client/local/client.py +0 -573
- digitalhub/stores/client/local/enums.py +0 -15
- digitalhub/stores/client/local/key_builder.py +0 -62
- digitalhub/stores/client/local/params_builder.py +0 -120
- digitalhub/stores/credentials/__init__.py +0 -3
- digitalhub/stores/credentials/configurator.py +0 -210
- digitalhub/stores/credentials/handler.py +0 -176
- digitalhub/stores/credentials/store.py +0 -81
- digitalhub/stores/data/enums.py +0 -15
- digitalhub/stores/data/s3/utils.py +0 -78
- /digitalhub/entities/{_base/entity/_constructors → _constructors}/__init__.py +0 -0
- /digitalhub/entities/{_base/entity/_constructors → _constructors}/metadata.py +0 -0
- /digitalhub/entities/{_base/entity/_constructors → _constructors}/spec.py +0 -0
- /digitalhub/entities/{_base/entity/_constructors → _constructors}/status.py +0 -0
- /digitalhub/entities/{_base/entity/_constructors → _constructors}/uuid.py +0 -0
- /digitalhub/{stores/client/_base → entities/_processors/base}/__init__.py +0 -0
- /digitalhub/{stores/client/dhcore → entities/_processors/context}/__init__.py +0 -0
- /digitalhub/stores/{client/local → configurator}/__init__.py +0 -0
- {digitalhub-0.13.0b3.dist-info → digitalhub-0.14.9.dist-info}/licenses/AUTHORS +0 -0
- {digitalhub-0.13.0b3.dist-info → digitalhub-0.14.9.dist-info}/licenses/LICENSE +0 -0
|
@@ -32,25 +32,20 @@ class SetCreds(Enum):
|
|
|
32
32
|
DH_PROFILE = "DH_NAME"
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
class
|
|
35
|
+
class ConfigurationVars(Enum):
|
|
36
36
|
"""
|
|
37
|
-
|
|
37
|
+
List of supported configuration variables.
|
|
38
38
|
"""
|
|
39
|
+
|
|
39
40
|
# S3
|
|
40
41
|
S3_ENDPOINT_URL = "AWS_ENDPOINT_URL"
|
|
41
|
-
S3_ACCESS_KEY_ID = "AWS_ACCESS_KEY_ID"
|
|
42
|
-
S3_SECRET_ACCESS_KEY = "AWS_SECRET_ACCESS_KEY"
|
|
43
|
-
S3_SESSION_TOKEN = "AWS_SESSION_TOKEN"
|
|
44
42
|
S3_REGION = "AWS_REGION"
|
|
45
43
|
S3_SIGNATURE_VERSION = "S3_SIGNATURE_VERSION"
|
|
46
|
-
S3_CREDENTIALS_EXPIRATION = "AWS_CREDENTIALS_EXPIRATION"
|
|
47
44
|
S3_PATH_STYLE = "S3_PATH_STYLE"
|
|
48
45
|
|
|
49
46
|
# SQL
|
|
50
47
|
DB_HOST = "DB_HOST"
|
|
51
48
|
DB_PORT = "DB_PORT"
|
|
52
|
-
DB_USERNAME = "DB_USERNAME"
|
|
53
|
-
DB_PASSWORD = "DB_PASSWORD"
|
|
54
49
|
DB_DATABASE = "DB_DATABASE"
|
|
55
50
|
DB_PLATFORM = "DB_PLATFORM"
|
|
56
51
|
DB_PG_SCHEMA = "DB_SCHEMA"
|
|
@@ -58,10 +53,32 @@ class CredsEnvVar(Enum):
|
|
|
58
53
|
# DHCORE
|
|
59
54
|
DHCORE_ENDPOINT = "DHCORE_ENDPOINT"
|
|
60
55
|
DHCORE_ISSUER = "DHCORE_ISSUER"
|
|
56
|
+
DHCORE_WORKFLOW_IMAGE = "DHCORE_WORKFLOW_IMAGE"
|
|
57
|
+
DHCORE_CLIENT_ID = "DHCORE_CLIENT_ID"
|
|
58
|
+
DEFAULT_FILES_STORE = "DHCORE_DEFAULT_FILES_STORE"
|
|
59
|
+
|
|
60
|
+
# OAUTH2
|
|
61
|
+
OAUTH2_TOKEN_ENDPOINT = "OAUTH2_TOKEN_ENDPOINT"
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class CredentialsVars(Enum):
|
|
65
|
+
"""
|
|
66
|
+
List of supported credential variables.
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
# S3
|
|
70
|
+
S3_ACCESS_KEY_ID = "AWS_ACCESS_KEY_ID"
|
|
71
|
+
S3_SECRET_ACCESS_KEY = "AWS_SECRET_ACCESS_KEY"
|
|
72
|
+
S3_SESSION_TOKEN = "AWS_SESSION_TOKEN"
|
|
73
|
+
S3_CREDENTIALS_EXPIRATION = "AWS_CREDENTIALS_EXPIRATION"
|
|
74
|
+
|
|
75
|
+
# SQL
|
|
76
|
+
DB_USERNAME = "DB_USERNAME"
|
|
77
|
+
DB_PASSWORD = "DB_PASSWORD"
|
|
78
|
+
|
|
79
|
+
# DHCORE
|
|
61
80
|
DHCORE_USER = "DHCORE_USER"
|
|
62
81
|
DHCORE_PASSWORD = "DHCORE_PASSWORD"
|
|
63
|
-
DHCORE_CLIENT_ID = "DHCORE_CLIENT_ID"
|
|
64
82
|
DHCORE_ACCESS_TOKEN = "DHCORE_ACCESS_TOKEN"
|
|
65
83
|
DHCORE_REFRESH_TOKEN = "DHCORE_REFRESH_TOKEN"
|
|
66
84
|
DHCORE_PERSONAL_ACCESS_TOKEN = "DHCORE_PERSONAL_ACCESS_TOKEN"
|
|
67
|
-
DHCORE_WORKFLOW_IMAGE = "DHCORE_WORKFLOW_IMAGE"
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: © 2025 DSLab - Fondazione Bruno Kessler
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from digitalhub.stores.configurator.enums import ConfigurationVars, CredentialsVars, SetCreds
|
|
11
|
+
from digitalhub.stores.configurator.ini_module import (
|
|
12
|
+
load_file,
|
|
13
|
+
load_key,
|
|
14
|
+
load_profile,
|
|
15
|
+
set_current_profile,
|
|
16
|
+
write_file,
|
|
17
|
+
)
|
|
18
|
+
from digitalhub.utils.generic_utils import list_enum
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ConfigurationHandler:
|
|
22
|
+
"""
|
|
23
|
+
Handler for loading and writing configuration variables.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __init__(self):
|
|
27
|
+
self._current_profile = self._read_current_profile()
|
|
28
|
+
self._configuration: dict[str, Any] = self.load_configuration()
|
|
29
|
+
self._credentials: dict[str, Any] = self.load_credentials()
|
|
30
|
+
|
|
31
|
+
@staticmethod
|
|
32
|
+
def _read_env(variables: list) -> dict:
|
|
33
|
+
"""
|
|
34
|
+
Read configuration variables from the .dhcore file.
|
|
35
|
+
|
|
36
|
+
Parameters
|
|
37
|
+
----------
|
|
38
|
+
variables : list
|
|
39
|
+
List of environment variable names to read.
|
|
40
|
+
|
|
41
|
+
Returns
|
|
42
|
+
-------
|
|
43
|
+
dict
|
|
44
|
+
Dictionary of environment variables.
|
|
45
|
+
"""
|
|
46
|
+
return {var: os.getenv(var) for var in variables}
|
|
47
|
+
|
|
48
|
+
@staticmethod
|
|
49
|
+
def _read_file(variables: list, profile: str) -> dict:
|
|
50
|
+
"""
|
|
51
|
+
Read configuration variables from the .dhcore file.
|
|
52
|
+
|
|
53
|
+
Parameters
|
|
54
|
+
----------
|
|
55
|
+
variables : list
|
|
56
|
+
List of environment variable names to read.
|
|
57
|
+
profile : str
|
|
58
|
+
Profile name to read from.
|
|
59
|
+
|
|
60
|
+
Returns
|
|
61
|
+
-------
|
|
62
|
+
dict
|
|
63
|
+
Dictionary of configuration variables.
|
|
64
|
+
"""
|
|
65
|
+
file = load_file()
|
|
66
|
+
return {var: load_key(file, profile, var) for var in variables}
|
|
67
|
+
|
|
68
|
+
##############################
|
|
69
|
+
# Configuration methods
|
|
70
|
+
##############################
|
|
71
|
+
|
|
72
|
+
def load_configuration(self) -> dict[str, Any]:
|
|
73
|
+
"""
|
|
74
|
+
Load configuration with env > file precedence.
|
|
75
|
+
|
|
76
|
+
Returns
|
|
77
|
+
-------
|
|
78
|
+
dict
|
|
79
|
+
Merged configuration dictionary.
|
|
80
|
+
"""
|
|
81
|
+
profile = self.get_current_profile()
|
|
82
|
+
variables = list_enum(ConfigurationVars)
|
|
83
|
+
env_config = self._read_env(variables)
|
|
84
|
+
file_config = self._read_file(variables, profile)
|
|
85
|
+
return {**file_config, **{k: v for k, v in env_config.items() if v is not None}}
|
|
86
|
+
|
|
87
|
+
def reload_configuration(self) -> None:
|
|
88
|
+
"""
|
|
89
|
+
Reload configuration from environment and file.
|
|
90
|
+
"""
|
|
91
|
+
self._configuration = self.load_configuration()
|
|
92
|
+
|
|
93
|
+
def get_configuration(self) -> dict[str, Any]:
|
|
94
|
+
"""
|
|
95
|
+
Get the merged configuration dictionary.
|
|
96
|
+
|
|
97
|
+
Returns
|
|
98
|
+
-------
|
|
99
|
+
dict[str, Any]
|
|
100
|
+
The configuration dictionary.
|
|
101
|
+
"""
|
|
102
|
+
return self._configuration
|
|
103
|
+
|
|
104
|
+
##############################
|
|
105
|
+
# Credentials methods
|
|
106
|
+
##############################
|
|
107
|
+
|
|
108
|
+
def load_credentials(self) -> dict[str, Any]:
|
|
109
|
+
"""
|
|
110
|
+
Load credentials with file > env precedence.
|
|
111
|
+
|
|
112
|
+
Parameters
|
|
113
|
+
----------
|
|
114
|
+
profile : str
|
|
115
|
+
Profile name to load credentials from.
|
|
116
|
+
|
|
117
|
+
Returns
|
|
118
|
+
-------
|
|
119
|
+
dict
|
|
120
|
+
Merged credentials dictionary.
|
|
121
|
+
"""
|
|
122
|
+
variables = list_enum(CredentialsVars)
|
|
123
|
+
env_config = self._read_env(variables)
|
|
124
|
+
file_config = self._read_file(variables, self.get_current_profile())
|
|
125
|
+
return {**env_config, **{k: v for k, v in file_config.items() if v is not None}}
|
|
126
|
+
|
|
127
|
+
def reload_credentials(self) -> None:
|
|
128
|
+
"""
|
|
129
|
+
Reload credentials from environment and file.
|
|
130
|
+
"""
|
|
131
|
+
self._credentials = self.load_credentials()
|
|
132
|
+
|
|
133
|
+
def reload_credentials_from_env(self) -> None:
|
|
134
|
+
"""
|
|
135
|
+
Reload credentials from environment where env > file precedence.
|
|
136
|
+
Its a partial reload only from env variables used as fallback.
|
|
137
|
+
"""
|
|
138
|
+
variables = list_enum(CredentialsVars)
|
|
139
|
+
env_config = self._read_env(variables)
|
|
140
|
+
file_config = self._read_file(variables, self.get_current_profile())
|
|
141
|
+
self._credentials = {**file_config, **{k: v for k, v in env_config.items() if v is not None}}
|
|
142
|
+
|
|
143
|
+
def get_credentials(self) -> dict[str, Any]:
|
|
144
|
+
"""
|
|
145
|
+
Get the merged credentials dictionary.
|
|
146
|
+
|
|
147
|
+
Returns
|
|
148
|
+
-------
|
|
149
|
+
dict[str, Any]
|
|
150
|
+
The credentials dictionary.
|
|
151
|
+
"""
|
|
152
|
+
return self._credentials
|
|
153
|
+
|
|
154
|
+
##############################
|
|
155
|
+
# Profile Methods
|
|
156
|
+
##############################
|
|
157
|
+
|
|
158
|
+
@staticmethod
|
|
159
|
+
def _read_current_profile() -> str:
|
|
160
|
+
"""
|
|
161
|
+
Read the current credentials profile name.
|
|
162
|
+
|
|
163
|
+
Returns
|
|
164
|
+
-------
|
|
165
|
+
str
|
|
166
|
+
Name of the credentials profile.
|
|
167
|
+
"""
|
|
168
|
+
profile = os.getenv(SetCreds.DH_PROFILE.value)
|
|
169
|
+
if profile is not None:
|
|
170
|
+
return profile
|
|
171
|
+
file = load_file()
|
|
172
|
+
profile = load_profile(file)
|
|
173
|
+
if profile is not None:
|
|
174
|
+
return profile
|
|
175
|
+
return SetCreds.DEFAULT.value
|
|
176
|
+
|
|
177
|
+
def set_current_profile(self, profile: str) -> None:
|
|
178
|
+
"""
|
|
179
|
+
Set the current credentials profile name.
|
|
180
|
+
|
|
181
|
+
Parameters
|
|
182
|
+
----------
|
|
183
|
+
profile : str
|
|
184
|
+
Name of the credentials profile to set.
|
|
185
|
+
"""
|
|
186
|
+
self._current_profile = profile
|
|
187
|
+
set_current_profile(profile)
|
|
188
|
+
self.reload_configuration()
|
|
189
|
+
self.reload_credentials()
|
|
190
|
+
|
|
191
|
+
def get_current_profile(self) -> str:
|
|
192
|
+
"""
|
|
193
|
+
Get the current credentials profile name.
|
|
194
|
+
|
|
195
|
+
Returns
|
|
196
|
+
-------
|
|
197
|
+
str
|
|
198
|
+
Name of the current credentials profile.
|
|
199
|
+
"""
|
|
200
|
+
return self._current_profile
|
|
201
|
+
|
|
202
|
+
def write_file(self, variables: dict) -> None:
|
|
203
|
+
"""
|
|
204
|
+
Write variables to the .dhcore file for the current profile.
|
|
205
|
+
|
|
206
|
+
Parameters
|
|
207
|
+
----------
|
|
208
|
+
infos : dict
|
|
209
|
+
Information to write.
|
|
210
|
+
profile : str
|
|
211
|
+
Profile name to write to.
|
|
212
|
+
"""
|
|
213
|
+
write_file(variables, self._current_profile)
|
|
@@ -92,9 +92,6 @@ def write_config(creds: dict, environment: str) -> None:
|
|
|
92
92
|
environment : str
|
|
93
93
|
Name of the credentials profile/environment.
|
|
94
94
|
|
|
95
|
-
Returns
|
|
96
|
-
-------
|
|
97
|
-
None
|
|
98
95
|
|
|
99
96
|
Raises
|
|
100
97
|
------
|
|
@@ -120,6 +117,37 @@ def write_config(creds: dict, environment: str) -> None:
|
|
|
120
117
|
raise ClientError(f"Failed to write env file: {e}")
|
|
121
118
|
|
|
122
119
|
|
|
120
|
+
def write_file(variables: dict, profile: str) -> None:
|
|
121
|
+
"""
|
|
122
|
+
Write variables to the .dhcore.ini file for the specified profile.
|
|
123
|
+
Overwrites any existing values for that profile.
|
|
124
|
+
|
|
125
|
+
Parameters
|
|
126
|
+
----------
|
|
127
|
+
variables : dict
|
|
128
|
+
Dictionary of variables to write.
|
|
129
|
+
profile : str
|
|
130
|
+
Name of the credentials profile to write to.
|
|
131
|
+
"""
|
|
132
|
+
try:
|
|
133
|
+
cfg = load_file()
|
|
134
|
+
|
|
135
|
+
sections = cfg.sections()
|
|
136
|
+
if profile not in sections:
|
|
137
|
+
cfg.add_section(profile)
|
|
138
|
+
|
|
139
|
+
cfg["DEFAULT"]["current_environment"] = profile
|
|
140
|
+
for k, v in variables.items():
|
|
141
|
+
cfg[profile][k] = str(v)
|
|
142
|
+
|
|
143
|
+
ENV_FILE.touch(exist_ok=True)
|
|
144
|
+
with open(ENV_FILE, "w") as inifile:
|
|
145
|
+
cfg.write(inifile)
|
|
146
|
+
|
|
147
|
+
except Exception as e:
|
|
148
|
+
raise ClientError(f"Failed to write env file: {e}")
|
|
149
|
+
|
|
150
|
+
|
|
123
151
|
def set_current_profile(environment: str) -> None:
|
|
124
152
|
"""
|
|
125
153
|
Set the current credentials profile in the .dhcore.ini file.
|
|
@@ -129,9 +157,6 @@ def set_current_profile(environment: str) -> None:
|
|
|
129
157
|
environment : str
|
|
130
158
|
Name of the credentials profile to set as current.
|
|
131
159
|
|
|
132
|
-
Returns
|
|
133
|
-
-------
|
|
134
|
-
None
|
|
135
160
|
|
|
136
161
|
Raises
|
|
137
162
|
------
|
|
@@ -146,19 +171,3 @@ def set_current_profile(environment: str) -> None:
|
|
|
146
171
|
|
|
147
172
|
except Exception as e:
|
|
148
173
|
raise ClientError(f"Failed to write env file: {e}")
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
def read_env_from_file() -> str | None:
|
|
152
|
-
"""
|
|
153
|
-
Read the current credentials profile name from the .dhcore.ini file.
|
|
154
|
-
|
|
155
|
-
Returns
|
|
156
|
-
-------
|
|
157
|
-
str or None
|
|
158
|
-
Name of the current credentials profile, or None if not found.
|
|
159
|
-
"""
|
|
160
|
-
try:
|
|
161
|
-
cfg = load_file()
|
|
162
|
-
return cfg["DEFAULT"]["current_environment"]
|
|
163
|
-
except Exception:
|
|
164
|
-
return None
|
|
@@ -16,7 +16,6 @@ from digitalhub.utils.types import SourcesOrListOfSources
|
|
|
16
16
|
from digitalhub.utils.uri_utils import has_local_scheme
|
|
17
17
|
|
|
18
18
|
if typing.TYPE_CHECKING:
|
|
19
|
-
from digitalhub.stores.credentials.configurator import Configurator
|
|
20
19
|
from digitalhub.stores.readers.data._base.reader import DataframeReader
|
|
21
20
|
|
|
22
21
|
|
|
@@ -25,9 +24,6 @@ class Store:
|
|
|
25
24
|
Store abstract class.
|
|
26
25
|
"""
|
|
27
26
|
|
|
28
|
-
def __init__(self, configurator: Configurator | None = None) -> None:
|
|
29
|
-
self._configurator = configurator
|
|
30
|
-
|
|
31
27
|
##############################
|
|
32
28
|
# I/O methods
|
|
33
29
|
##############################
|
|
@@ -114,10 +110,6 @@ class Store:
|
|
|
114
110
|
src : str
|
|
115
111
|
The source path.
|
|
116
112
|
|
|
117
|
-
Returns
|
|
118
|
-
-------
|
|
119
|
-
None
|
|
120
|
-
|
|
121
113
|
Raises
|
|
122
114
|
------
|
|
123
115
|
StoreError
|
|
@@ -135,10 +127,6 @@ class Store:
|
|
|
135
127
|
dst : str
|
|
136
128
|
The destination path.
|
|
137
129
|
|
|
138
|
-
Returns
|
|
139
|
-
-------
|
|
140
|
-
None
|
|
141
|
-
|
|
142
130
|
Raises
|
|
143
131
|
------
|
|
144
132
|
StoreError
|
|
@@ -158,10 +146,6 @@ class Store:
|
|
|
158
146
|
overwrite : bool
|
|
159
147
|
Specify if overwrite an existing file.
|
|
160
148
|
|
|
161
|
-
Returns
|
|
162
|
-
-------
|
|
163
|
-
None
|
|
164
|
-
|
|
165
149
|
Raises
|
|
166
150
|
------
|
|
167
151
|
StoreError
|
|
@@ -179,10 +163,6 @@ class Store:
|
|
|
179
163
|
----------
|
|
180
164
|
path : str | Path
|
|
181
165
|
The path to build.
|
|
182
|
-
|
|
183
|
-
Returns
|
|
184
|
-
-------
|
|
185
|
-
None
|
|
186
166
|
"""
|
|
187
167
|
if not isinstance(path, Path):
|
|
188
168
|
path = Path(path)
|
digitalhub/stores/data/api.py
CHANGED
|
@@ -7,9 +7,9 @@ from __future__ import annotations
|
|
|
7
7
|
import typing
|
|
8
8
|
|
|
9
9
|
from digitalhub.context.api import get_context
|
|
10
|
-
from digitalhub.stores.
|
|
10
|
+
from digitalhub.stores.configurator.configurator import configurator
|
|
11
|
+
from digitalhub.stores.configurator.enums import ConfigurationVars
|
|
11
12
|
from digitalhub.stores.data.builder import store_builder
|
|
12
|
-
from digitalhub.stores.data.enums import StoreEnv
|
|
13
13
|
|
|
14
14
|
if typing.TYPE_CHECKING:
|
|
15
15
|
from digitalhub.stores.data._base.store import Store
|
|
@@ -34,16 +34,14 @@ def get_default_store(project: str) -> str:
|
|
|
34
34
|
ValueError
|
|
35
35
|
If no default store is found.
|
|
36
36
|
"""
|
|
37
|
-
var =
|
|
37
|
+
var = ConfigurationVars.DEFAULT_FILES_STORE.value
|
|
38
38
|
|
|
39
39
|
context = get_context(project)
|
|
40
|
-
store = context.config.get(var.lower())
|
|
40
|
+
store = context.config.get(var.lower().replace("dhcore_", ""))
|
|
41
41
|
if store is not None:
|
|
42
42
|
return store
|
|
43
43
|
|
|
44
|
-
store =
|
|
45
|
-
if store is None:
|
|
46
|
-
store = creds_handler.load_from_file([var]).get(var)
|
|
44
|
+
store = configurator.get_configuration().get(var)
|
|
47
45
|
|
|
48
46
|
if store is None or store == "":
|
|
49
47
|
raise ValueError(
|
|
@@ -8,77 +8,103 @@ import typing
|
|
|
8
8
|
|
|
9
9
|
from digitalhub.stores.data.local.store import LocalStore
|
|
10
10
|
from digitalhub.stores.data.remote.store import RemoteStore
|
|
11
|
-
from digitalhub.stores.data.s3.configurator import S3StoreConfigurator
|
|
12
11
|
from digitalhub.stores.data.s3.store import S3Store
|
|
13
|
-
from digitalhub.stores.data.sql.configurator import SqlStoreConfigurator
|
|
14
12
|
from digitalhub.stores.data.sql.store import SqlStore
|
|
15
13
|
from digitalhub.utils.uri_utils import SchemeCategory, map_uri_scheme
|
|
16
14
|
|
|
17
15
|
if typing.TYPE_CHECKING:
|
|
18
|
-
from digitalhub.stores.credentials.configurator import Configurator
|
|
19
16
|
from digitalhub.stores.data._base.store import Store
|
|
20
17
|
from digitalhub.utils.exceptions import StoreError
|
|
21
18
|
|
|
22
19
|
|
|
23
|
-
class StoreInfo:
|
|
24
|
-
def __init__(self, store: Store, configurator: Configurator | None = None) -> None:
|
|
25
|
-
self._store = store
|
|
26
|
-
self._configurator = configurator
|
|
27
|
-
|
|
28
|
-
|
|
29
20
|
class StoreBuilder:
|
|
30
21
|
"""
|
|
31
|
-
Store
|
|
22
|
+
Store factory and registry for managing data store instances.
|
|
23
|
+
|
|
24
|
+
Provides registration, instantiation, and caching of data store
|
|
25
|
+
instances based on URI schemes. Supports various store types
|
|
26
|
+
including S3, SQL, local, and remote stores with their respective
|
|
27
|
+
configurators.
|
|
28
|
+
|
|
29
|
+
Attributes
|
|
30
|
+
----------
|
|
31
|
+
_builders : dict[str, StoreInfo]
|
|
32
|
+
Registry of store types mapped to their StoreInfo instances.
|
|
33
|
+
_instances : dict[str, Store]
|
|
34
|
+
Cache of instantiated store instances by store type.
|
|
32
35
|
"""
|
|
33
36
|
|
|
34
37
|
def __init__(self) -> None:
|
|
35
|
-
self._builders: dict[str,
|
|
38
|
+
self._builders: dict[str, Store] = {}
|
|
36
39
|
self._instances: dict[str, dict[str, Store]] = {}
|
|
37
40
|
|
|
38
41
|
def register(
|
|
39
42
|
self,
|
|
40
43
|
store_type: str,
|
|
41
44
|
store: Store,
|
|
42
|
-
configurator: Configurator | None = None,
|
|
43
45
|
) -> None:
|
|
46
|
+
"""
|
|
47
|
+
Register a store type with its class and optional configurator.
|
|
48
|
+
|
|
49
|
+
Adds a new store type to the builder registry, associating it
|
|
50
|
+
with a store class and optional configurator for later instantiation.
|
|
51
|
+
|
|
52
|
+
Parameters
|
|
53
|
+
----------
|
|
54
|
+
store_type : str
|
|
55
|
+
The unique identifier for the store type (e.g., 's3', 'sql').
|
|
56
|
+
store : Store
|
|
57
|
+
The store class to register for this type.
|
|
58
|
+
configurator : Configurator
|
|
59
|
+
The configurator class for store configuration.
|
|
60
|
+
If None, the store will be instantiated without configuration.
|
|
61
|
+
|
|
62
|
+
Raises
|
|
63
|
+
------
|
|
64
|
+
StoreError
|
|
65
|
+
If the store type is already registered in the builder.
|
|
66
|
+
"""
|
|
44
67
|
if store_type not in self._builders:
|
|
45
|
-
self._builders[store_type] =
|
|
68
|
+
self._builders[store_type] = store
|
|
46
69
|
else:
|
|
47
70
|
raise StoreError(f"Store type {store_type} already registered")
|
|
48
71
|
|
|
49
72
|
def get(self, uri: str) -> Store:
|
|
50
73
|
"""
|
|
51
|
-
Get a store instance
|
|
74
|
+
Get or create a store instance based on URI scheme.
|
|
75
|
+
|
|
76
|
+
Determines the appropriate store type from the URI scheme,
|
|
77
|
+
instantiates the store if not already cached, and returns
|
|
78
|
+
the store instance. Store instances are cached for reuse.
|
|
52
79
|
|
|
53
80
|
Parameters
|
|
54
81
|
----------
|
|
55
82
|
uri : str
|
|
56
|
-
URI to parse.
|
|
83
|
+
The URI to parse for determining the store type.
|
|
84
|
+
The scheme (e.g., 's3://', 'sql://') determines which
|
|
85
|
+
store type to instantiate.
|
|
57
86
|
|
|
58
87
|
Returns
|
|
59
88
|
-------
|
|
60
89
|
Store
|
|
61
|
-
The store instance.
|
|
90
|
+
The store instance appropriate for handling the given URI.
|
|
91
|
+
|
|
92
|
+
Raises
|
|
93
|
+
------
|
|
94
|
+
KeyError
|
|
95
|
+
If no store is registered for the URI scheme.
|
|
62
96
|
"""
|
|
63
97
|
store_type = map_uri_scheme(uri)
|
|
64
98
|
|
|
65
99
|
# Build the store instance if not already present
|
|
66
100
|
if store_type not in self._instances:
|
|
67
|
-
|
|
68
|
-
store_cls = store_info._store
|
|
69
|
-
cfgrt_cls = store_info._configurator
|
|
70
|
-
|
|
71
|
-
if cfgrt_cls is None:
|
|
72
|
-
store = store_cls()
|
|
73
|
-
else:
|
|
74
|
-
store = store_cls(cfgrt_cls())
|
|
75
|
-
self._instances[store_type] = store
|
|
101
|
+
self._instances[store_type] = self._builders[store_type]()
|
|
76
102
|
|
|
77
103
|
return self._instances[store_type]
|
|
78
104
|
|
|
79
105
|
|
|
80
106
|
store_builder = StoreBuilder()
|
|
81
|
-
store_builder.register(SchemeCategory.S3.value, S3Store
|
|
82
|
-
store_builder.register(SchemeCategory.SQL.value, SqlStore
|
|
107
|
+
store_builder.register(SchemeCategory.S3.value, S3Store)
|
|
108
|
+
store_builder.register(SchemeCategory.SQL.value, SqlStore)
|
|
83
109
|
store_builder.register(SchemeCategory.LOCAL.value, LocalStore)
|
|
84
110
|
store_builder.register(SchemeCategory.REMOTE.value, RemoteStore)
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
|
-
import shutil
|
|
8
7
|
from pathlib import Path
|
|
9
8
|
from typing import Any
|
|
10
9
|
|
|
@@ -180,105 +179,3 @@ class LocalStore(Store):
|
|
|
180
179
|
reader = get_reader_by_object(df)
|
|
181
180
|
reader.write_df(df, dst, extension=extension, **kwargs)
|
|
182
181
|
return dst
|
|
183
|
-
|
|
184
|
-
##############################
|
|
185
|
-
# Private I/O methods
|
|
186
|
-
##############################
|
|
187
|
-
|
|
188
|
-
def _get_src_dst_files(self, src: Path, dst: Path) -> list[str]:
|
|
189
|
-
"""
|
|
190
|
-
Copy files from source to destination.
|
|
191
|
-
|
|
192
|
-
Parameters
|
|
193
|
-
----------
|
|
194
|
-
src : Path
|
|
195
|
-
The source path.
|
|
196
|
-
dst : Path
|
|
197
|
-
The destination path.
|
|
198
|
-
|
|
199
|
-
Returns
|
|
200
|
-
-------
|
|
201
|
-
list[str]
|
|
202
|
-
Returns the list of destination and source paths of the
|
|
203
|
-
copied files.
|
|
204
|
-
"""
|
|
205
|
-
return [self._get_src_dst_file(i, dst) for i in src.rglob("*") if i.is_file()]
|
|
206
|
-
|
|
207
|
-
def _get_src_dst_file(self, src: Path, dst: Path) -> str:
|
|
208
|
-
"""
|
|
209
|
-
Copy file from source to destination.
|
|
210
|
-
|
|
211
|
-
Parameters
|
|
212
|
-
----------
|
|
213
|
-
src : Path
|
|
214
|
-
The source path.
|
|
215
|
-
dst : Path
|
|
216
|
-
The destination path.
|
|
217
|
-
|
|
218
|
-
Returns
|
|
219
|
-
-------
|
|
220
|
-
str
|
|
221
|
-
"""
|
|
222
|
-
dst_pth = self._copy_file(src, dst, True)
|
|
223
|
-
return str(dst_pth), str(src)
|
|
224
|
-
|
|
225
|
-
def _copy_dir(self, src: Path, dst: Path, overwrite: bool) -> list[str]:
|
|
226
|
-
"""
|
|
227
|
-
Download file from source to destination.
|
|
228
|
-
|
|
229
|
-
Parameters
|
|
230
|
-
----------
|
|
231
|
-
src : Path
|
|
232
|
-
The source path.
|
|
233
|
-
dst : Path
|
|
234
|
-
The destination path.
|
|
235
|
-
|
|
236
|
-
Returns
|
|
237
|
-
-------
|
|
238
|
-
list[str]
|
|
239
|
-
"""
|
|
240
|
-
dst = self._rebuild_path(dst, src)
|
|
241
|
-
shutil.copytree(src, dst, dirs_exist_ok=overwrite)
|
|
242
|
-
return [str(i) for i in dst.rglob("*") if i.is_file()]
|
|
243
|
-
|
|
244
|
-
def _copy_file(self, src: Path, dst: Path, overwrite: bool) -> str:
|
|
245
|
-
"""
|
|
246
|
-
Copy file from source to destination.
|
|
247
|
-
|
|
248
|
-
Parameters
|
|
249
|
-
----------
|
|
250
|
-
src : Path
|
|
251
|
-
The source path.
|
|
252
|
-
dst : Path
|
|
253
|
-
The destination path.
|
|
254
|
-
|
|
255
|
-
Returns
|
|
256
|
-
-------
|
|
257
|
-
str
|
|
258
|
-
"""
|
|
259
|
-
dst = self._rebuild_path(dst, src)
|
|
260
|
-
self._check_overwrite(dst, overwrite)
|
|
261
|
-
return str(shutil.copy2(src, dst))
|
|
262
|
-
|
|
263
|
-
def _rebuild_path(self, dst: Path, src: Path) -> Path:
|
|
264
|
-
"""
|
|
265
|
-
Rebuild path.
|
|
266
|
-
|
|
267
|
-
Parameters
|
|
268
|
-
----------
|
|
269
|
-
dst : Path
|
|
270
|
-
The destination path.
|
|
271
|
-
src : Path
|
|
272
|
-
The source path.
|
|
273
|
-
|
|
274
|
-
Returns
|
|
275
|
-
-------
|
|
276
|
-
Path
|
|
277
|
-
The rebuilt path.
|
|
278
|
-
"""
|
|
279
|
-
if dst.is_dir():
|
|
280
|
-
if src.is_absolute():
|
|
281
|
-
raise StoreError("Source must be a relative path if the destination is a directory.")
|
|
282
|
-
dst = dst / src
|
|
283
|
-
self._build_path(dst)
|
|
284
|
-
return dst
|