digitalhub 0.12.0__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.
- digitalhub/__init__.py +1 -1
- digitalhub/context/api.py +5 -5
- digitalhub/context/builder.py +3 -5
- digitalhub/context/context.py +9 -1
- digitalhub/entities/_base/executable/entity.py +105 -57
- digitalhub/entities/_base/material/entity.py +11 -18
- digitalhub/entities/_base/material/utils.py +1 -1
- digitalhub/entities/_commons/metrics.py +64 -30
- digitalhub/entities/_commons/utils.py +36 -9
- digitalhub/entities/_processors/base.py +150 -79
- digitalhub/entities/_processors/context.py +366 -215
- digitalhub/entities/_processors/utils.py +74 -30
- digitalhub/entities/artifact/crud.py +4 -0
- digitalhub/entities/artifact/utils.py +28 -13
- digitalhub/entities/dataitem/crud.py +14 -2
- digitalhub/entities/dataitem/table/entity.py +3 -3
- digitalhub/entities/dataitem/utils.py +84 -35
- digitalhub/entities/model/crud.py +4 -0
- digitalhub/entities/model/utils.py +28 -13
- digitalhub/entities/project/_base/entity.py +0 -2
- digitalhub/entities/run/_base/entity.py +2 -2
- digitalhub/entities/task/_base/models.py +12 -3
- digitalhub/entities/trigger/_base/entity.py +11 -0
- digitalhub/factory/factory.py +25 -3
- digitalhub/factory/utils.py +11 -3
- digitalhub/runtimes/_base.py +1 -1
- digitalhub/runtimes/builder.py +18 -1
- digitalhub/stores/client/__init__.py +12 -0
- digitalhub/stores/client/_base/api_builder.py +14 -0
- digitalhub/stores/client/_base/client.py +93 -0
- digitalhub/stores/client/_base/key_builder.py +28 -0
- digitalhub/stores/client/_base/params_builder.py +14 -0
- digitalhub/stores/client/api.py +10 -5
- digitalhub/stores/client/builder.py +3 -1
- digitalhub/stores/client/dhcore/api_builder.py +17 -0
- digitalhub/stores/client/dhcore/client.py +325 -70
- digitalhub/stores/client/dhcore/configurator.py +485 -193
- digitalhub/stores/client/dhcore/enums.py +3 -0
- digitalhub/stores/client/dhcore/error_parser.py +35 -1
- digitalhub/stores/client/dhcore/params_builder.py +113 -17
- digitalhub/stores/client/dhcore/utils.py +40 -22
- digitalhub/stores/client/local/api_builder.py +17 -0
- digitalhub/stores/client/local/client.py +6 -8
- digitalhub/stores/credentials/api.py +35 -0
- digitalhub/stores/credentials/configurator.py +210 -0
- digitalhub/stores/credentials/enums.py +68 -0
- digitalhub/stores/credentials/handler.py +176 -0
- digitalhub/stores/{configurator → credentials}/ini_module.py +60 -28
- digitalhub/stores/credentials/store.py +81 -0
- digitalhub/stores/data/_base/store.py +27 -9
- digitalhub/stores/data/api.py +49 -9
- digitalhub/stores/data/builder.py +90 -41
- digitalhub/stores/data/local/store.py +4 -7
- digitalhub/stores/data/remote/store.py +4 -7
- digitalhub/stores/data/s3/configurator.py +65 -80
- digitalhub/stores/data/s3/store.py +69 -81
- digitalhub/stores/data/s3/utils.py +10 -10
- digitalhub/stores/data/sql/configurator.py +76 -73
- digitalhub/stores/data/sql/store.py +191 -102
- digitalhub/utils/exceptions.py +6 -0
- digitalhub/utils/file_utils.py +53 -30
- digitalhub/utils/generic_utils.py +41 -33
- digitalhub/utils/git_utils.py +24 -14
- digitalhub/utils/io_utils.py +19 -18
- digitalhub/utils/uri_utils.py +31 -31
- {digitalhub-0.12.0.dist-info → digitalhub-0.13.0.dist-info}/METADATA +1 -1
- {digitalhub-0.12.0.dist-info → digitalhub-0.13.0.dist-info}/RECORD +71 -74
- digitalhub/entities/_commons/types.py +0 -9
- digitalhub/stores/configurator/api.py +0 -35
- digitalhub/stores/configurator/configurator.py +0 -202
- digitalhub/stores/configurator/credentials_store.py +0 -69
- digitalhub/stores/configurator/enums.py +0 -25
- digitalhub/stores/data/s3/enums.py +0 -20
- digitalhub/stores/data/sql/enums.py +0 -20
- digitalhub/stores/data/utils.py +0 -38
- /digitalhub/stores/{configurator → credentials}/__init__.py +0 -0
- {digitalhub-0.12.0.dist-info → digitalhub-0.13.0.dist-info}/WHEEL +0 -0
- {digitalhub-0.12.0.dist-info → digitalhub-0.13.0.dist-info}/licenses/AUTHORS +0 -0
- {digitalhub-0.12.0.dist-info → digitalhub-0.13.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: © 2025 DSLab - Fondazione Bruno Kessler
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from enum import Enum
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class CredsOrigin(Enum):
|
|
11
|
+
"""
|
|
12
|
+
Credential origins for configuration.
|
|
13
|
+
|
|
14
|
+
Attributes
|
|
15
|
+
----------
|
|
16
|
+
ENV : str
|
|
17
|
+
Credentials from environment variables.
|
|
18
|
+
FILE : str
|
|
19
|
+
Credentials from configuration file.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
ENV = "env"
|
|
23
|
+
FILE = "file"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class SetCreds(Enum):
|
|
27
|
+
"""
|
|
28
|
+
Supported credential environments.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
DEFAULT = "__default"
|
|
32
|
+
DH_PROFILE = "DH_NAME"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class CredsEnvVar(Enum):
|
|
36
|
+
"""
|
|
37
|
+
Supported credential environment variables.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
# S3
|
|
41
|
+
S3_ENDPOINT_URL = "AWS_ENDPOINT_URL"
|
|
42
|
+
S3_ACCESS_KEY_ID = "AWS_ACCESS_KEY_ID"
|
|
43
|
+
S3_SECRET_ACCESS_KEY = "AWS_SECRET_ACCESS_KEY"
|
|
44
|
+
S3_SESSION_TOKEN = "AWS_SESSION_TOKEN"
|
|
45
|
+
S3_REGION = "AWS_REGION"
|
|
46
|
+
S3_SIGNATURE_VERSION = "S3_SIGNATURE_VERSION"
|
|
47
|
+
S3_CREDENTIALS_EXPIRATION = "AWS_CREDENTIALS_EXPIRATION"
|
|
48
|
+
S3_PATH_STYLE = "S3_PATH_STYLE"
|
|
49
|
+
|
|
50
|
+
# SQL
|
|
51
|
+
DB_HOST = "DB_HOST"
|
|
52
|
+
DB_PORT = "DB_PORT"
|
|
53
|
+
DB_USERNAME = "DB_USERNAME"
|
|
54
|
+
DB_PASSWORD = "DB_PASSWORD"
|
|
55
|
+
DB_DATABASE = "DB_DATABASE"
|
|
56
|
+
DB_PLATFORM = "DB_PLATFORM"
|
|
57
|
+
DB_PG_SCHEMA = "DB_SCHEMA"
|
|
58
|
+
|
|
59
|
+
# DHCORE
|
|
60
|
+
DHCORE_ENDPOINT = "DHCORE_ENDPOINT"
|
|
61
|
+
DHCORE_ISSUER = "DHCORE_ISSUER"
|
|
62
|
+
DHCORE_USER = "DHCORE_USER"
|
|
63
|
+
DHCORE_PASSWORD = "DHCORE_PASSWORD"
|
|
64
|
+
DHCORE_CLIENT_ID = "DHCORE_CLIENT_ID"
|
|
65
|
+
DHCORE_ACCESS_TOKEN = "DHCORE_ACCESS_TOKEN"
|
|
66
|
+
DHCORE_REFRESH_TOKEN = "DHCORE_REFRESH_TOKEN"
|
|
67
|
+
DHCORE_PERSONAL_ACCESS_TOKEN = "DHCORE_PERSONAL_ACCESS_TOKEN"
|
|
68
|
+
DHCORE_WORKFLOW_IMAGE = "DHCORE_WORKFLOW_IMAGE"
|
|
@@ -0,0 +1,176 @@
|
|
|
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
|
+
|
|
9
|
+
from digitalhub.stores.credentials.enums import SetCreds
|
|
10
|
+
from digitalhub.stores.credentials.ini_module import (
|
|
11
|
+
load_file,
|
|
12
|
+
load_key,
|
|
13
|
+
load_profile,
|
|
14
|
+
set_current_profile,
|
|
15
|
+
write_config,
|
|
16
|
+
)
|
|
17
|
+
from digitalhub.stores.credentials.store import CredentialsStore
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class CredentialHandler:
|
|
21
|
+
"""
|
|
22
|
+
Handler for configuring clients and managing credentials.
|
|
23
|
+
|
|
24
|
+
Attributes
|
|
25
|
+
----------
|
|
26
|
+
_creds_store : CredentialsStore
|
|
27
|
+
Store for credentials.
|
|
28
|
+
_profile : str
|
|
29
|
+
Current credentials profile name.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def __init__(self) -> None:
|
|
33
|
+
self._creds_store = CredentialsStore()
|
|
34
|
+
self._profile = self._read_current_profile()
|
|
35
|
+
|
|
36
|
+
@staticmethod
|
|
37
|
+
def _read_current_profile() -> str:
|
|
38
|
+
"""
|
|
39
|
+
Read the current credentials profile name.
|
|
40
|
+
|
|
41
|
+
Returns
|
|
42
|
+
-------
|
|
43
|
+
str
|
|
44
|
+
Name of the credentials profile.
|
|
45
|
+
"""
|
|
46
|
+
profile = os.getenv(SetCreds.DH_PROFILE.value)
|
|
47
|
+
if profile is not None:
|
|
48
|
+
return profile
|
|
49
|
+
file = load_file()
|
|
50
|
+
profile = load_profile(file)
|
|
51
|
+
if profile is not None:
|
|
52
|
+
return profile
|
|
53
|
+
return SetCreds.DEFAULT.value
|
|
54
|
+
|
|
55
|
+
##############################
|
|
56
|
+
# Public methods
|
|
57
|
+
##############################
|
|
58
|
+
|
|
59
|
+
def set_current_profile(self, creds_set: str) -> None:
|
|
60
|
+
"""
|
|
61
|
+
Set the current credentials profile name.
|
|
62
|
+
|
|
63
|
+
Parameters
|
|
64
|
+
----------
|
|
65
|
+
creds_set : str
|
|
66
|
+
Name of the credentials profile to set.
|
|
67
|
+
|
|
68
|
+
Returns
|
|
69
|
+
-------
|
|
70
|
+
None
|
|
71
|
+
"""
|
|
72
|
+
self._profile = creds_set
|
|
73
|
+
set_current_profile(creds_set)
|
|
74
|
+
|
|
75
|
+
def get_current_profile(self) -> str:
|
|
76
|
+
"""
|
|
77
|
+
Get the current credentials profile name.
|
|
78
|
+
|
|
79
|
+
Returns
|
|
80
|
+
-------
|
|
81
|
+
str
|
|
82
|
+
Name of the current credentials profile.
|
|
83
|
+
"""
|
|
84
|
+
return self._profile
|
|
85
|
+
|
|
86
|
+
def load_from_env(self, vars: list[str]) -> dict:
|
|
87
|
+
"""
|
|
88
|
+
Load variables from environment.
|
|
89
|
+
|
|
90
|
+
Parameters
|
|
91
|
+
----------
|
|
92
|
+
vars : list of str
|
|
93
|
+
List of environment variable names to load.
|
|
94
|
+
|
|
95
|
+
Returns
|
|
96
|
+
-------
|
|
97
|
+
dict
|
|
98
|
+
Dictionary of environment variable values.
|
|
99
|
+
"""
|
|
100
|
+
return {var: os.getenv(var) for var in vars}
|
|
101
|
+
|
|
102
|
+
def load_from_file(self, vars: list[str]) -> dict:
|
|
103
|
+
"""
|
|
104
|
+
Load variables from credentials config file.
|
|
105
|
+
|
|
106
|
+
Parameters
|
|
107
|
+
----------
|
|
108
|
+
vars : list of str
|
|
109
|
+
List of variable names to load from file.
|
|
110
|
+
|
|
111
|
+
Returns
|
|
112
|
+
-------
|
|
113
|
+
dict
|
|
114
|
+
Dictionary of variable values from file.
|
|
115
|
+
"""
|
|
116
|
+
file = load_file()
|
|
117
|
+
profile = load_profile(file)
|
|
118
|
+
if profile is not None:
|
|
119
|
+
self._profile = profile
|
|
120
|
+
return {var: load_key(file, self._profile, var) for var in vars}
|
|
121
|
+
|
|
122
|
+
def write_env(self, creds: dict) -> None:
|
|
123
|
+
"""
|
|
124
|
+
Write credentials to the .dhcore file for the current profile.
|
|
125
|
+
|
|
126
|
+
Parameters
|
|
127
|
+
----------
|
|
128
|
+
creds : dict
|
|
129
|
+
Credentials to write.
|
|
130
|
+
|
|
131
|
+
Returns
|
|
132
|
+
-------
|
|
133
|
+
None
|
|
134
|
+
"""
|
|
135
|
+
write_config(creds, self._profile)
|
|
136
|
+
|
|
137
|
+
##############################
|
|
138
|
+
# Credentials store methods
|
|
139
|
+
##############################
|
|
140
|
+
|
|
141
|
+
def set_credentials(self, origin: str, creds: dict) -> None:
|
|
142
|
+
"""
|
|
143
|
+
Set credentials for the current profile and origin.
|
|
144
|
+
|
|
145
|
+
Parameters
|
|
146
|
+
----------
|
|
147
|
+
origin : str
|
|
148
|
+
The origin of the credentials ('env' or 'file').
|
|
149
|
+
creds : dict
|
|
150
|
+
Credentials to set.
|
|
151
|
+
|
|
152
|
+
Returns
|
|
153
|
+
-------
|
|
154
|
+
None
|
|
155
|
+
"""
|
|
156
|
+
self._creds_store.set_credentials(self._profile, origin, creds)
|
|
157
|
+
|
|
158
|
+
def get_credentials(self, origin: str) -> dict:
|
|
159
|
+
"""
|
|
160
|
+
Get credentials for the current profile from the specified origin.
|
|
161
|
+
|
|
162
|
+
Parameters
|
|
163
|
+
----------
|
|
164
|
+
origin : str
|
|
165
|
+
The origin to get credentials from ('env' or 'file').
|
|
166
|
+
|
|
167
|
+
Returns
|
|
168
|
+
-------
|
|
169
|
+
dict
|
|
170
|
+
Dictionary of credentials.
|
|
171
|
+
"""
|
|
172
|
+
return self._creds_store.get_credentials(self._profile, origin)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
# Define global credential handler
|
|
176
|
+
creds_handler = CredentialHandler()
|
|
@@ -9,22 +9,23 @@ from pathlib import Path
|
|
|
9
9
|
|
|
10
10
|
from digitalhub.utils.exceptions import ClientError
|
|
11
11
|
|
|
12
|
-
# File where to write
|
|
13
|
-
# It's used because we inject the variables in jupyter env,
|
|
14
|
-
# but refresh token is only available once. Is it's used, we cannot
|
|
15
|
-
# overwrite it with coder, so we need to store the new one in a file,
|
|
16
|
-
# preserved for jupyter restart
|
|
12
|
+
# File where to write credementials
|
|
17
13
|
ENV_FILE = Path.home() / ".dhcore.ini"
|
|
18
14
|
|
|
19
15
|
|
|
20
16
|
def load_file() -> ConfigParser:
|
|
21
17
|
"""
|
|
22
|
-
Load
|
|
18
|
+
Load the credentials configuration from the .dhcore.ini file.
|
|
23
19
|
|
|
24
20
|
Returns
|
|
25
21
|
-------
|
|
26
22
|
ConfigParser
|
|
27
|
-
|
|
23
|
+
Parsed configuration file object.
|
|
24
|
+
|
|
25
|
+
Raises
|
|
26
|
+
------
|
|
27
|
+
ClientError
|
|
28
|
+
If the file cannot be read.
|
|
28
29
|
"""
|
|
29
30
|
try:
|
|
30
31
|
file = ConfigParser()
|
|
@@ -34,45 +35,71 @@ def load_file() -> ConfigParser:
|
|
|
34
35
|
raise ClientError(f"Failed to read env file: {e}")
|
|
35
36
|
|
|
36
37
|
|
|
37
|
-
def
|
|
38
|
+
def load_profile(file: ConfigParser) -> str | None:
|
|
38
39
|
"""
|
|
39
|
-
Load
|
|
40
|
+
Load the current credentials profile name from the .dhcore.ini file.
|
|
40
41
|
|
|
41
42
|
Parameters
|
|
42
43
|
----------
|
|
44
|
+
file : ConfigParser
|
|
45
|
+
Parsed configuration file object.
|
|
46
|
+
|
|
47
|
+
Returns
|
|
48
|
+
-------
|
|
49
|
+
str or None
|
|
50
|
+
Name of the credentials profile, or None if not found.
|
|
51
|
+
"""
|
|
52
|
+
try:
|
|
53
|
+
return file["DEFAULT"]["current_environment"]
|
|
54
|
+
except KeyError:
|
|
55
|
+
return
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def load_key(file: ConfigParser, profile: str, key: str) -> str | None:
|
|
59
|
+
"""
|
|
60
|
+
Load a specific key value from the credentials profile in the
|
|
61
|
+
.dhcore.ini file.
|
|
62
|
+
|
|
63
|
+
Parameters
|
|
64
|
+
----------
|
|
65
|
+
file : ConfigParser
|
|
66
|
+
Parsed configuration file object.
|
|
43
67
|
profile : str
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
68
|
+
Name of the credentials profile.
|
|
69
|
+
key : str
|
|
70
|
+
Name of the key to retrieve.
|
|
47
71
|
|
|
48
72
|
Returns
|
|
49
73
|
-------
|
|
50
|
-
str
|
|
51
|
-
|
|
74
|
+
str or None
|
|
75
|
+
Value of the key, or None if not found.
|
|
52
76
|
"""
|
|
53
77
|
try:
|
|
54
|
-
|
|
55
|
-
profile = cfg["DEFAULT"]["current_environment"]
|
|
56
|
-
return cfg[profile].get(var)
|
|
78
|
+
return file[profile][key]
|
|
57
79
|
except KeyError:
|
|
58
80
|
return
|
|
59
81
|
|
|
60
82
|
|
|
61
83
|
def write_config(creds: dict, environment: str) -> None:
|
|
62
84
|
"""
|
|
63
|
-
Write
|
|
64
|
-
|
|
85
|
+
Write credentials to the .dhcore.ini file for the specified environment.
|
|
86
|
+
Overwrites any existing values for that environment.
|
|
65
87
|
|
|
66
88
|
Parameters
|
|
67
89
|
----------
|
|
68
90
|
creds : dict
|
|
69
|
-
|
|
91
|
+
Dictionary of credentials to write.
|
|
70
92
|
environment : str
|
|
71
|
-
|
|
93
|
+
Name of the credentials profile/environment.
|
|
72
94
|
|
|
73
95
|
Returns
|
|
74
96
|
-------
|
|
75
97
|
None
|
|
98
|
+
|
|
99
|
+
Raises
|
|
100
|
+
------
|
|
101
|
+
ClientError
|
|
102
|
+
If the file cannot be written.
|
|
76
103
|
"""
|
|
77
104
|
try:
|
|
78
105
|
cfg = load_file()
|
|
@@ -83,7 +110,7 @@ def write_config(creds: dict, environment: str) -> None:
|
|
|
83
110
|
|
|
84
111
|
cfg["DEFAULT"]["current_environment"] = environment
|
|
85
112
|
for k, v in creds.items():
|
|
86
|
-
cfg[environment][k] = v
|
|
113
|
+
cfg[environment][k] = str(v)
|
|
87
114
|
|
|
88
115
|
ENV_FILE.touch(exist_ok=True)
|
|
89
116
|
with open(ENV_FILE, "w") as inifile:
|
|
@@ -93,18 +120,23 @@ def write_config(creds: dict, environment: str) -> None:
|
|
|
93
120
|
raise ClientError(f"Failed to write env file: {e}")
|
|
94
121
|
|
|
95
122
|
|
|
96
|
-
def
|
|
123
|
+
def set_current_profile(environment: str) -> None:
|
|
97
124
|
"""
|
|
98
|
-
Set the current credentials
|
|
125
|
+
Set the current credentials profile in the .dhcore.ini file.
|
|
99
126
|
|
|
100
127
|
Parameters
|
|
101
128
|
----------
|
|
102
129
|
environment : str
|
|
103
|
-
|
|
130
|
+
Name of the credentials profile to set as current.
|
|
104
131
|
|
|
105
132
|
Returns
|
|
106
133
|
-------
|
|
107
134
|
None
|
|
135
|
+
|
|
136
|
+
Raises
|
|
137
|
+
------
|
|
138
|
+
ClientError
|
|
139
|
+
If the file cannot be written.
|
|
108
140
|
"""
|
|
109
141
|
try:
|
|
110
142
|
cfg = load_file()
|
|
@@ -118,12 +150,12 @@ def set_current_env(environment: str) -> None:
|
|
|
118
150
|
|
|
119
151
|
def read_env_from_file() -> str | None:
|
|
120
152
|
"""
|
|
121
|
-
Read the current credentials
|
|
153
|
+
Read the current credentials profile name from the .dhcore.ini file.
|
|
122
154
|
|
|
123
155
|
Returns
|
|
124
156
|
-------
|
|
125
|
-
str
|
|
126
|
-
|
|
157
|
+
str or None
|
|
158
|
+
Name of the current credentials profile, or None if not found.
|
|
127
159
|
"""
|
|
128
160
|
try:
|
|
129
161
|
cfg = load_file()
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: © 2025 DSLab - Fondazione Bruno Kessler
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from digitalhub.stores.credentials.enums import CredsOrigin
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class CredentialsStore:
|
|
13
|
+
"""
|
|
14
|
+
Store and retrieve credentials for different profiles and origins.
|
|
15
|
+
|
|
16
|
+
Attributes
|
|
17
|
+
----------
|
|
18
|
+
_file_creds : dict of str to dict
|
|
19
|
+
Credentials stored by profile from file origin.
|
|
20
|
+
_env_creds : dict of str to Any
|
|
21
|
+
Credentials stored from environment origin.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(self) -> None:
|
|
25
|
+
self._file_creds: dict[str, dict[str, Any]] = {}
|
|
26
|
+
self._env_creds: dict[str, Any] = {}
|
|
27
|
+
|
|
28
|
+
def set_credentials(
|
|
29
|
+
self,
|
|
30
|
+
profile: str,
|
|
31
|
+
origin: str,
|
|
32
|
+
credentials: dict[str, Any],
|
|
33
|
+
) -> None:
|
|
34
|
+
"""
|
|
35
|
+
Set all credentials for a given profile and origin.
|
|
36
|
+
|
|
37
|
+
Parameters
|
|
38
|
+
----------
|
|
39
|
+
profile : str
|
|
40
|
+
Name of the credentials profile.
|
|
41
|
+
origin : str
|
|
42
|
+
Origin of the credentials ('env' or 'file').
|
|
43
|
+
credentials : dict of str to Any
|
|
44
|
+
Dictionary of credentials to set.
|
|
45
|
+
|
|
46
|
+
Returns
|
|
47
|
+
-------
|
|
48
|
+
None
|
|
49
|
+
"""
|
|
50
|
+
if origin == CredsOrigin.ENV.value:
|
|
51
|
+
for key, value in credentials.items():
|
|
52
|
+
self._env_creds[key] = value
|
|
53
|
+
return
|
|
54
|
+
if profile not in self._file_creds:
|
|
55
|
+
self._file_creds[profile] = {}
|
|
56
|
+
for key, value in credentials.items():
|
|
57
|
+
self._file_creds[profile][key] = value
|
|
58
|
+
|
|
59
|
+
def get_credentials(
|
|
60
|
+
self,
|
|
61
|
+
profile: str,
|
|
62
|
+
origin: str,
|
|
63
|
+
) -> dict[str, Any]:
|
|
64
|
+
"""
|
|
65
|
+
Get all credentials for a given profile and origin.
|
|
66
|
+
|
|
67
|
+
Parameters
|
|
68
|
+
----------
|
|
69
|
+
profile : str
|
|
70
|
+
Name of the credentials profile.
|
|
71
|
+
origin : str
|
|
72
|
+
Origin of the credentials ('env' or 'file').
|
|
73
|
+
|
|
74
|
+
Returns
|
|
75
|
+
-------
|
|
76
|
+
dict of str to Any
|
|
77
|
+
Dictionary of credentials for the profile and origin.
|
|
78
|
+
"""
|
|
79
|
+
if origin == CredsOrigin.ENV.value:
|
|
80
|
+
return self._env_creds
|
|
81
|
+
return self._file_creds[profile]
|
|
@@ -16,6 +16,7 @@ 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
|
|
19
20
|
from digitalhub.stores.readers.data._base.reader import DataframeReader
|
|
20
21
|
|
|
21
22
|
|
|
@@ -24,6 +25,9 @@ class Store:
|
|
|
24
25
|
Store abstract class.
|
|
25
26
|
"""
|
|
26
27
|
|
|
28
|
+
def __init__(self, configurator: Configurator | None = None) -> None:
|
|
29
|
+
self._configurator = configurator
|
|
30
|
+
|
|
27
31
|
##############################
|
|
28
32
|
# I/O methods
|
|
29
33
|
##############################
|
|
@@ -31,19 +35,22 @@ class Store:
|
|
|
31
35
|
@abstractmethod
|
|
32
36
|
def download(
|
|
33
37
|
self,
|
|
34
|
-
|
|
38
|
+
src: str,
|
|
35
39
|
dst: Path,
|
|
36
|
-
src: list[str],
|
|
37
40
|
overwrite: bool = False,
|
|
38
41
|
) -> str:
|
|
39
42
|
"""
|
|
40
|
-
Method to download
|
|
43
|
+
Method to download material entity from storage.
|
|
41
44
|
"""
|
|
42
45
|
|
|
43
46
|
@abstractmethod
|
|
44
|
-
def upload(
|
|
47
|
+
def upload(
|
|
48
|
+
self,
|
|
49
|
+
src: SourcesOrListOfSources,
|
|
50
|
+
dst: str,
|
|
51
|
+
) -> list[tuple[str, str]]:
|
|
45
52
|
"""
|
|
46
|
-
Method to upload
|
|
53
|
+
Method to upload material entity to storage.
|
|
47
54
|
"""
|
|
48
55
|
|
|
49
56
|
@abstractmethod
|
|
@@ -83,7 +90,13 @@ class Store:
|
|
|
83
90
|
"""
|
|
84
91
|
|
|
85
92
|
@abstractmethod
|
|
86
|
-
def write_df(
|
|
93
|
+
def write_df(
|
|
94
|
+
self,
|
|
95
|
+
df: Any,
|
|
96
|
+
dst: str,
|
|
97
|
+
extension: str | None = None,
|
|
98
|
+
**kwargs,
|
|
99
|
+
) -> str:
|
|
87
100
|
"""
|
|
88
101
|
Write DataFrame as parquet or csv.
|
|
89
102
|
"""
|
|
@@ -173,9 +186,14 @@ class Store:
|
|
|
173
186
|
"""
|
|
174
187
|
if not isinstance(path, Path):
|
|
175
188
|
path = Path(path)
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
189
|
+
# If the path does not exist, we need to infer if it's a file or directory
|
|
190
|
+
if path.suffix and not path.name.startswith("."):
|
|
191
|
+
# Looks like a file, use parent
|
|
192
|
+
dir_path = path.parent
|
|
193
|
+
else:
|
|
194
|
+
# Looks like a directory (even if it contains dots)
|
|
195
|
+
dir_path = path
|
|
196
|
+
dir_path.mkdir(parents=True, exist_ok=True)
|
|
179
197
|
|
|
180
198
|
@staticmethod
|
|
181
199
|
def _build_temp() -> Path:
|
digitalhub/stores/data/api.py
CHANGED
|
@@ -6,28 +6,68 @@ from __future__ import annotations
|
|
|
6
6
|
|
|
7
7
|
import typing
|
|
8
8
|
|
|
9
|
+
from digitalhub.context.api import get_context
|
|
10
|
+
from digitalhub.stores.credentials.handler import creds_handler
|
|
9
11
|
from digitalhub.stores.data.builder import store_builder
|
|
12
|
+
from digitalhub.stores.data.enums import StoreEnv
|
|
10
13
|
|
|
11
14
|
if typing.TYPE_CHECKING:
|
|
12
15
|
from digitalhub.stores.data._base.store import Store
|
|
13
16
|
|
|
14
17
|
|
|
15
|
-
def
|
|
18
|
+
def get_default_store(project: str) -> str:
|
|
16
19
|
"""
|
|
17
|
-
|
|
20
|
+
Returns the default store URI for a given project.
|
|
18
21
|
|
|
19
22
|
Parameters
|
|
20
|
-
|
|
23
|
+
----------
|
|
21
24
|
project : str
|
|
22
|
-
|
|
25
|
+
The name of the project.
|
|
26
|
+
|
|
27
|
+
Returns
|
|
28
|
+
-------
|
|
29
|
+
str
|
|
30
|
+
The default store URI.
|
|
31
|
+
|
|
32
|
+
Raises
|
|
33
|
+
------
|
|
34
|
+
ValueError
|
|
35
|
+
If no default store is found.
|
|
36
|
+
"""
|
|
37
|
+
var = StoreEnv.DEFAULT_FILES_STORE.value
|
|
38
|
+
|
|
39
|
+
context = get_context(project)
|
|
40
|
+
store = context.config.get(var.lower().replace("dhcore_", ""))
|
|
41
|
+
if store is not None:
|
|
42
|
+
return store
|
|
43
|
+
|
|
44
|
+
store = creds_handler.load_from_env([var]).get(var)
|
|
45
|
+
if store is None:
|
|
46
|
+
store = creds_handler.load_from_file([var]).get(var)
|
|
47
|
+
|
|
48
|
+
if store is None or store == "":
|
|
49
|
+
raise ValueError(
|
|
50
|
+
"No default store found. "
|
|
51
|
+
"Please set a default store "
|
|
52
|
+
f"in your environment (e.g. export {var}=) "
|
|
53
|
+
" in the .dhcore.ini file "
|
|
54
|
+
"or set it in project config."
|
|
55
|
+
)
|
|
56
|
+
return store
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def get_store(uri: str) -> Store:
|
|
60
|
+
"""
|
|
61
|
+
Returns a store instance for the given URI.
|
|
62
|
+
|
|
63
|
+
Parameters
|
|
64
|
+
----------
|
|
23
65
|
uri : str
|
|
24
|
-
URI to parse.
|
|
25
|
-
config : dict
|
|
26
|
-
Store configuration.
|
|
66
|
+
The URI to parse.
|
|
27
67
|
|
|
28
68
|
Returns
|
|
29
69
|
-------
|
|
30
70
|
Store
|
|
31
|
-
|
|
71
|
+
The store instance corresponding to the URI.
|
|
32
72
|
"""
|
|
33
|
-
return store_builder.get(
|
|
73
|
+
return store_builder.get(uri)
|