digitalhub 0.9.2__py3-none-any.whl → 0.10.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 +2 -3
- digitalhub/client/_base/client.py +3 -2
- digitalhub/client/dhcore/api_builder.py +5 -0
- digitalhub/client/dhcore/client.py +27 -399
- digitalhub/client/dhcore/configurator.py +339 -0
- digitalhub/client/dhcore/error_parser.py +107 -0
- digitalhub/client/dhcore/models.py +13 -23
- digitalhub/client/dhcore/utils.py +4 -44
- digitalhub/client/local/api_builder.py +9 -17
- digitalhub/client/local/client.py +12 -2
- digitalhub/client/local/enums.py +11 -0
- digitalhub/configurator/api.py +31 -0
- digitalhub/configurator/configurator.py +194 -0
- digitalhub/configurator/credentials_store.py +65 -0
- digitalhub/configurator/ini_module.py +74 -0
- digitalhub/entities/_base/_base/entity.py +2 -2
- digitalhub/entities/_base/material/entity.py +19 -6
- digitalhub/entities/_base/material/utils.py +2 -2
- digitalhub/entities/_commons/enums.py +1 -0
- digitalhub/entities/_commons/models.py +9 -0
- digitalhub/entities/_commons/utils.py +25 -0
- digitalhub/entities/_operations/processor.py +103 -107
- digitalhub/entities/artifact/crud.py +3 -3
- digitalhub/entities/dataitem/_base/entity.py +2 -2
- digitalhub/entities/dataitem/crud.py +3 -3
- digitalhub/entities/dataitem/table/entity.py +2 -2
- digitalhub/{utils/data_utils.py → entities/dataitem/table/utils.py} +43 -51
- digitalhub/entities/dataitem/utils.py +6 -3
- digitalhub/entities/model/_base/entity.py +172 -0
- digitalhub/entities/model/_base/spec.py +0 -10
- digitalhub/entities/model/_base/status.py +10 -0
- digitalhub/entities/model/crud.py +3 -3
- digitalhub/entities/model/huggingface/spec.py +6 -3
- digitalhub/entities/model/mlflow/models.py +2 -2
- digitalhub/entities/model/mlflow/spec.py +1 -3
- digitalhub/entities/model/mlflow/utils.py +44 -5
- digitalhub/entities/run/_base/entity.py +149 -0
- digitalhub/entities/run/_base/status.py +12 -0
- digitalhub/entities/task/_base/spec.py +2 -0
- digitalhub/entities/task/crud.py +4 -0
- digitalhub/readers/{_commons → pandas}/enums.py +4 -0
- digitalhub/readers/pandas/reader.py +58 -10
- digitalhub/stores/_base/store.py +1 -49
- digitalhub/stores/api.py +8 -33
- digitalhub/stores/builder.py +44 -161
- digitalhub/stores/local/store.py +4 -18
- digitalhub/stores/remote/store.py +3 -10
- digitalhub/stores/s3/configurator.py +107 -0
- digitalhub/stores/s3/enums.py +17 -0
- digitalhub/stores/s3/models.py +21 -0
- digitalhub/stores/s3/store.py +8 -28
- digitalhub/{utils/s3_utils.py → stores/s3/utils.py} +7 -3
- digitalhub/stores/sql/configurator.py +88 -0
- digitalhub/stores/sql/enums.py +16 -0
- digitalhub/stores/sql/models.py +24 -0
- digitalhub/stores/sql/store.py +14 -57
- digitalhub/utils/exceptions.py +6 -0
- digitalhub/utils/generic_utils.py +9 -8
- digitalhub/utils/uri_utils.py +1 -1
- {digitalhub-0.9.2.dist-info → digitalhub-0.10.0b0.dist-info}/METADATA +5 -6
- {digitalhub-0.9.2.dist-info → digitalhub-0.10.0b0.dist-info}/RECORD +66 -53
- test/local/imports/test_imports.py +0 -1
- digitalhub/client/dhcore/env.py +0 -23
- /digitalhub/{readers/_commons → configurator}/__init__.py +0 -0
- {digitalhub-0.9.2.dist-info → digitalhub-0.10.0b0.dist-info}/LICENSE.txt +0 -0
- {digitalhub-0.9.2.dist-info → digitalhub-0.10.0b0.dist-info}/WHEEL +0 -0
- {digitalhub-0.9.2.dist-info → digitalhub-0.10.0b0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from digitalhub.configurator.configurator import configurator
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def set_current_env(environment: str) -> None:
|
|
7
|
+
"""
|
|
8
|
+
Set the current credentials set.
|
|
9
|
+
|
|
10
|
+
Parameters
|
|
11
|
+
----------
|
|
12
|
+
environment : str
|
|
13
|
+
Credentials set name.
|
|
14
|
+
|
|
15
|
+
Returns
|
|
16
|
+
-------
|
|
17
|
+
None
|
|
18
|
+
"""
|
|
19
|
+
configurator.set_current_env(environment)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def get_current_env() -> str:
|
|
23
|
+
"""
|
|
24
|
+
Get the current credentials set.
|
|
25
|
+
|
|
26
|
+
Returns
|
|
27
|
+
-------
|
|
28
|
+
str
|
|
29
|
+
Credentials set name.
|
|
30
|
+
"""
|
|
31
|
+
return configurator.get_current_env()
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
from digitalhub.configurator.credentials_store import CredentialsStore
|
|
6
|
+
from digitalhub.configurator.ini_module import load_from_config, write_config
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class EnvConfigurator:
|
|
10
|
+
"""
|
|
11
|
+
Configurator object used to configure clients and store credentials.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def __init__(self) -> None:
|
|
15
|
+
# Store
|
|
16
|
+
self._creds_store = CredentialsStore()
|
|
17
|
+
|
|
18
|
+
# Current credentials set (__default by default)
|
|
19
|
+
self._environment = "__default"
|
|
20
|
+
|
|
21
|
+
##############################
|
|
22
|
+
# Public methods
|
|
23
|
+
##############################
|
|
24
|
+
|
|
25
|
+
def set_current_env(self, creds_set: str) -> None:
|
|
26
|
+
"""
|
|
27
|
+
Set the current credentials set.
|
|
28
|
+
|
|
29
|
+
Parameters
|
|
30
|
+
----------
|
|
31
|
+
creds_set : str
|
|
32
|
+
Credentials set name.
|
|
33
|
+
|
|
34
|
+
Returns
|
|
35
|
+
-------
|
|
36
|
+
None
|
|
37
|
+
"""
|
|
38
|
+
self._environment = creds_set
|
|
39
|
+
|
|
40
|
+
def get_current_env(self) -> str:
|
|
41
|
+
"""
|
|
42
|
+
Get the current credentials set.
|
|
43
|
+
|
|
44
|
+
Returns
|
|
45
|
+
-------
|
|
46
|
+
str
|
|
47
|
+
Credentials set name.
|
|
48
|
+
"""
|
|
49
|
+
return self._environment
|
|
50
|
+
|
|
51
|
+
##############################
|
|
52
|
+
# Private methods
|
|
53
|
+
##############################
|
|
54
|
+
|
|
55
|
+
def load_var(self, var_name: str) -> str | None:
|
|
56
|
+
"""
|
|
57
|
+
Get env variable from credentials store, env or file (in order).
|
|
58
|
+
|
|
59
|
+
Parameters
|
|
60
|
+
----------
|
|
61
|
+
var_name : str
|
|
62
|
+
Environment variable name.
|
|
63
|
+
|
|
64
|
+
Returns
|
|
65
|
+
-------
|
|
66
|
+
str | None
|
|
67
|
+
Environment variable value.
|
|
68
|
+
"""
|
|
69
|
+
var = self.get_credentials(var_name)
|
|
70
|
+
if var is None:
|
|
71
|
+
var = self.load_from_env(var_name)
|
|
72
|
+
if var is None:
|
|
73
|
+
var = self.load_from_config(var_name)
|
|
74
|
+
return var
|
|
75
|
+
|
|
76
|
+
def load_from_env(self, var: str) -> str | None:
|
|
77
|
+
"""
|
|
78
|
+
Load variable from env.
|
|
79
|
+
|
|
80
|
+
Parameters
|
|
81
|
+
----------
|
|
82
|
+
var : str
|
|
83
|
+
Environment variable name.
|
|
84
|
+
|
|
85
|
+
Returns
|
|
86
|
+
-------
|
|
87
|
+
str | None
|
|
88
|
+
Environment variable value.
|
|
89
|
+
"""
|
|
90
|
+
env_var = os.getenv(var)
|
|
91
|
+
if env_var != "":
|
|
92
|
+
return env_var
|
|
93
|
+
|
|
94
|
+
def load_from_config(self, var: str) -> str | None:
|
|
95
|
+
"""
|
|
96
|
+
Load variable from config file.
|
|
97
|
+
|
|
98
|
+
Parameters
|
|
99
|
+
----------
|
|
100
|
+
var : str
|
|
101
|
+
Environment variable name.
|
|
102
|
+
|
|
103
|
+
Returns
|
|
104
|
+
-------
|
|
105
|
+
str | None
|
|
106
|
+
Environment variable value.
|
|
107
|
+
"""
|
|
108
|
+
return load_from_config(var)
|
|
109
|
+
|
|
110
|
+
def write_env(self, key_to_include: list[str] | None = None) -> None:
|
|
111
|
+
"""
|
|
112
|
+
Write the env variables to the .dhcore file.
|
|
113
|
+
It will overwrite any existing env variables.
|
|
114
|
+
|
|
115
|
+
Parameters
|
|
116
|
+
----------
|
|
117
|
+
key_to_include : list[str]
|
|
118
|
+
List of keys to include.
|
|
119
|
+
|
|
120
|
+
Returns
|
|
121
|
+
-------
|
|
122
|
+
None
|
|
123
|
+
"""
|
|
124
|
+
if key_to_include is None:
|
|
125
|
+
key_to_include = []
|
|
126
|
+
creds = self.get_cred_list(key_to_include)
|
|
127
|
+
write_config(creds, self._environment)
|
|
128
|
+
|
|
129
|
+
##############################
|
|
130
|
+
# Credentials store methods
|
|
131
|
+
##############################
|
|
132
|
+
|
|
133
|
+
def set_credential(self, key: str, value: str) -> None:
|
|
134
|
+
"""
|
|
135
|
+
Register a credential value.
|
|
136
|
+
|
|
137
|
+
Parameters
|
|
138
|
+
----------
|
|
139
|
+
key : str
|
|
140
|
+
The key.
|
|
141
|
+
value : str
|
|
142
|
+
The value.
|
|
143
|
+
|
|
144
|
+
Returns
|
|
145
|
+
-------
|
|
146
|
+
None
|
|
147
|
+
"""
|
|
148
|
+
self._creds_store.set(self._environment, key, value)
|
|
149
|
+
|
|
150
|
+
def get_credentials(self, key: str) -> dict:
|
|
151
|
+
"""
|
|
152
|
+
Get the credentials.
|
|
153
|
+
|
|
154
|
+
Parameters
|
|
155
|
+
----------
|
|
156
|
+
key : str
|
|
157
|
+
The key.
|
|
158
|
+
|
|
159
|
+
Returns
|
|
160
|
+
-------
|
|
161
|
+
dict
|
|
162
|
+
The credentials.
|
|
163
|
+
"""
|
|
164
|
+
return self._creds_store.get(self._environment, key)
|
|
165
|
+
|
|
166
|
+
def get_all_cred(self) -> dict:
|
|
167
|
+
"""
|
|
168
|
+
Get all the credentials.
|
|
169
|
+
|
|
170
|
+
Returns
|
|
171
|
+
-------
|
|
172
|
+
dict
|
|
173
|
+
The credentials.
|
|
174
|
+
"""
|
|
175
|
+
return self._creds_store.get_all(self._environment)
|
|
176
|
+
|
|
177
|
+
def get_cred_list(self, keys: list[str]) -> list[str]:
|
|
178
|
+
"""
|
|
179
|
+
Get the list of credentials.
|
|
180
|
+
|
|
181
|
+
Parameters
|
|
182
|
+
----------
|
|
183
|
+
keys : list[str]
|
|
184
|
+
The list of keys.
|
|
185
|
+
|
|
186
|
+
Returns
|
|
187
|
+
-------
|
|
188
|
+
list[str]
|
|
189
|
+
The list of credentials.
|
|
190
|
+
"""
|
|
191
|
+
return {k: v for k, v in self.get_all_cred().items() if k in keys}
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
configurator = EnvConfigurator()
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class CredentialsStore:
|
|
5
|
+
"""
|
|
6
|
+
Credentials store to store and retrieve credentials.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
def __init__(self) -> None:
|
|
10
|
+
self._credentials: dict[str, dict] = {}
|
|
11
|
+
|
|
12
|
+
def set(self, profile: str, key: str, value: str) -> None:
|
|
13
|
+
"""
|
|
14
|
+
Set credentials.
|
|
15
|
+
|
|
16
|
+
Parameters
|
|
17
|
+
----------
|
|
18
|
+
profile : str
|
|
19
|
+
The profile of the credentials.
|
|
20
|
+
key : str
|
|
21
|
+
The key of the credentials.
|
|
22
|
+
value : str
|
|
23
|
+
The value of the credentials.
|
|
24
|
+
|
|
25
|
+
Returns
|
|
26
|
+
-------
|
|
27
|
+
None
|
|
28
|
+
"""
|
|
29
|
+
if profile not in self._credentials:
|
|
30
|
+
self._credentials[profile] = {}
|
|
31
|
+
self._credentials[profile][key] = value
|
|
32
|
+
|
|
33
|
+
def get(self, profile: str, key: str) -> str | None:
|
|
34
|
+
"""
|
|
35
|
+
Get credentials.
|
|
36
|
+
|
|
37
|
+
Parameters
|
|
38
|
+
----------
|
|
39
|
+
profile : str
|
|
40
|
+
The profile of the credentials.
|
|
41
|
+
key : str
|
|
42
|
+
The key of the credentials.
|
|
43
|
+
|
|
44
|
+
Returns
|
|
45
|
+
-------
|
|
46
|
+
str | None
|
|
47
|
+
The value of the credentials.
|
|
48
|
+
"""
|
|
49
|
+
return self._credentials.get(profile, {}).get(key)
|
|
50
|
+
|
|
51
|
+
def get_all(self, profile: str) -> dict[str, str]:
|
|
52
|
+
"""
|
|
53
|
+
Get all credentials.
|
|
54
|
+
|
|
55
|
+
Parameters
|
|
56
|
+
----------
|
|
57
|
+
profile : str
|
|
58
|
+
The profile of the credentials.
|
|
59
|
+
|
|
60
|
+
Returns
|
|
61
|
+
-------
|
|
62
|
+
dict[str, str]
|
|
63
|
+
The credentials.
|
|
64
|
+
"""
|
|
65
|
+
return self._credentials.get(profile, {})
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from configparser import ConfigParser
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from digitalhub.utils.exceptions import ClientError
|
|
7
|
+
|
|
8
|
+
# File where to write DHCORE_ACCESS_TOKEN and DHCORE_REFRESH_TOKEN
|
|
9
|
+
# It's used because we inject the variables in jupyter env,
|
|
10
|
+
# but refresh token is only available once. Is it's used, we cannot
|
|
11
|
+
# overwrite it with coder, so we need to store the new one in a file,
|
|
12
|
+
# preserved for jupyter restart
|
|
13
|
+
ENV_FILE = Path.home() / ".dhcore.ini"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def load_from_config(var: str) -> str | None:
|
|
17
|
+
"""
|
|
18
|
+
Load variable from config file.
|
|
19
|
+
|
|
20
|
+
Parameters
|
|
21
|
+
----------
|
|
22
|
+
profile : str
|
|
23
|
+
Credentials set name.
|
|
24
|
+
var : str
|
|
25
|
+
Environment variable name.
|
|
26
|
+
|
|
27
|
+
Returns
|
|
28
|
+
-------
|
|
29
|
+
str | None
|
|
30
|
+
Environment variable value.
|
|
31
|
+
"""
|
|
32
|
+
cfg = ConfigParser()
|
|
33
|
+
cfg.read(ENV_FILE)
|
|
34
|
+
try:
|
|
35
|
+
profile = cfg["DEFAULT"]["current_environment"]
|
|
36
|
+
return cfg[profile].get(var)
|
|
37
|
+
except KeyError:
|
|
38
|
+
return
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def write_config(creds: dict, environment: str) -> None:
|
|
42
|
+
"""
|
|
43
|
+
Write the env variables to the .dhcore.ini file.
|
|
44
|
+
It will overwrite any existing env variables.
|
|
45
|
+
|
|
46
|
+
Parameters
|
|
47
|
+
----------
|
|
48
|
+
creds : dict
|
|
49
|
+
Credentials.
|
|
50
|
+
environment : str
|
|
51
|
+
Credentials set name.
|
|
52
|
+
|
|
53
|
+
Returns
|
|
54
|
+
-------
|
|
55
|
+
None
|
|
56
|
+
"""
|
|
57
|
+
try:
|
|
58
|
+
cfg = ConfigParser()
|
|
59
|
+
cfg.read(ENV_FILE)
|
|
60
|
+
|
|
61
|
+
sections = cfg.sections()
|
|
62
|
+
if environment not in sections:
|
|
63
|
+
cfg.add_section(environment)
|
|
64
|
+
|
|
65
|
+
cfg["DEFAULT"]["current_environment"] = environment
|
|
66
|
+
for k, v in creds.items():
|
|
67
|
+
cfg[environment][k] = v
|
|
68
|
+
|
|
69
|
+
ENV_FILE.touch(exist_ok=True)
|
|
70
|
+
with open(ENV_FILE, "w") as inifile:
|
|
71
|
+
cfg.write(inifile)
|
|
72
|
+
|
|
73
|
+
except Exception as e:
|
|
74
|
+
raise ClientError(f"Failed to write env file: {e}")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from digitalhub.utils.generic_utils import
|
|
3
|
+
from digitalhub.utils.generic_utils import dump_json
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class Base:
|
|
@@ -40,7 +40,7 @@ class Base:
|
|
|
40
40
|
str
|
|
41
41
|
A json string containing the attributes of the entity instance.
|
|
42
42
|
"""
|
|
43
|
-
return
|
|
43
|
+
return dump_json(self.to_dict())
|
|
44
44
|
|
|
45
45
|
def _any_setter(self, **kwargs) -> None:
|
|
46
46
|
"""
|
|
@@ -34,6 +34,9 @@ class MaterialEntity(VersionedEntity):
|
|
|
34
34
|
self.spec: MaterialSpec
|
|
35
35
|
self.status: MaterialStatus
|
|
36
36
|
|
|
37
|
+
# Init files info
|
|
38
|
+
self._init_files_info()
|
|
39
|
+
|
|
37
40
|
def save(self, update: bool = False) -> MaterialEntity:
|
|
38
41
|
"""
|
|
39
42
|
Save entity into backend.
|
|
@@ -77,7 +80,7 @@ class MaterialEntity(VersionedEntity):
|
|
|
77
80
|
list[str]
|
|
78
81
|
List of file paths.
|
|
79
82
|
"""
|
|
80
|
-
store = get_store(self.spec.path)
|
|
83
|
+
store = get_store(self.project, self.spec.path)
|
|
81
84
|
paths = self.get_file_paths()
|
|
82
85
|
dst = store._build_temp()
|
|
83
86
|
return store.download(self.spec.path, dst=dst, src=paths)
|
|
@@ -126,7 +129,7 @@ class MaterialEntity(VersionedEntity):
|
|
|
126
129
|
>>> print(path)
|
|
127
130
|
dataitem/data.csv
|
|
128
131
|
"""
|
|
129
|
-
store = get_store(self.spec.path)
|
|
132
|
+
store = get_store(self.project, self.spec.path)
|
|
130
133
|
paths = self.get_file_paths()
|
|
131
134
|
|
|
132
135
|
if destination is None:
|
|
@@ -164,7 +167,7 @@ class MaterialEntity(VersionedEntity):
|
|
|
164
167
|
>>> entity.upload('./data')
|
|
165
168
|
"""
|
|
166
169
|
# Get store and upload object
|
|
167
|
-
store = get_store(self.spec.path)
|
|
170
|
+
store = get_store(self.project, self.spec.path)
|
|
168
171
|
paths = store.upload(source, self.spec.path)
|
|
169
172
|
|
|
170
173
|
# Update files info
|
|
@@ -175,6 +178,17 @@ class MaterialEntity(VersionedEntity):
|
|
|
175
178
|
# Public Helpers
|
|
176
179
|
##############################
|
|
177
180
|
|
|
181
|
+
def _init_files_info(self) -> None:
|
|
182
|
+
"""
|
|
183
|
+
Initialize files info.
|
|
184
|
+
|
|
185
|
+
Returns
|
|
186
|
+
-------
|
|
187
|
+
None
|
|
188
|
+
"""
|
|
189
|
+
if self.status.files is None:
|
|
190
|
+
self.status.files = []
|
|
191
|
+
|
|
178
192
|
def add_files_info(self, files: list[dict]) -> None:
|
|
179
193
|
"""
|
|
180
194
|
Add a file to the status.
|
|
@@ -202,8 +216,6 @@ class MaterialEntity(VersionedEntity):
|
|
|
202
216
|
list[str]
|
|
203
217
|
Paths of the files in the status.
|
|
204
218
|
"""
|
|
205
|
-
if self.status.files is None:
|
|
206
|
-
self.status.files = []
|
|
207
219
|
return [f.get("path") for f in self.status.files]
|
|
208
220
|
|
|
209
221
|
##############################
|
|
@@ -225,7 +237,8 @@ class MaterialEntity(VersionedEntity):
|
|
|
225
237
|
"""
|
|
226
238
|
if files_info is None:
|
|
227
239
|
return
|
|
228
|
-
self.
|
|
240
|
+
if self.status.files:
|
|
241
|
+
self.refresh()
|
|
229
242
|
self.add_files_info(files_info)
|
|
230
243
|
self.save(update=True)
|
|
231
244
|
|
|
@@ -2,8 +2,8 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
|
|
5
|
+
from digitalhub.stores.s3.utils import get_s3_bucket_from_env
|
|
5
6
|
from digitalhub.utils.file_utils import eval_zip_type
|
|
6
|
-
from digitalhub.utils.s3_utils import get_s3_bucket
|
|
7
7
|
from digitalhub.utils.uri_utils import S3Schemes, has_local_scheme
|
|
8
8
|
|
|
9
9
|
|
|
@@ -91,7 +91,7 @@ def build_log_path_from_source(
|
|
|
91
91
|
Log path.
|
|
92
92
|
"""
|
|
93
93
|
scheme = eval_zip_sources(source)
|
|
94
|
-
path = f"{scheme}://{
|
|
94
|
+
path = f"{scheme}://{get_s3_bucket_from_env()}/{project}/{entity_type}/{name}/{uuid}"
|
|
95
95
|
|
|
96
96
|
if isinstance(source, list) and len(source) >= 1:
|
|
97
97
|
if len(source) > 1:
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from pydantic import ValidationError
|
|
6
|
+
|
|
3
7
|
from digitalhub.entities._commons.enums import EntityTypes
|
|
8
|
+
from digitalhub.entities._commons.models import Metric
|
|
4
9
|
|
|
5
10
|
|
|
6
11
|
def parse_entity_key(key: str) -> tuple[str]:
|
|
@@ -81,3 +86,23 @@ def get_project_from_key(key: str) -> str:
|
|
|
81
86
|
"""
|
|
82
87
|
project, _, _, _, _ = parse_entity_key(key)
|
|
83
88
|
return project
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def validate_metric_value(value: Any) -> float | int | list[float | int]:
|
|
92
|
+
"""
|
|
93
|
+
Validate metric value.
|
|
94
|
+
|
|
95
|
+
Parameters
|
|
96
|
+
----------
|
|
97
|
+
value : Any
|
|
98
|
+
The value to validate.
|
|
99
|
+
|
|
100
|
+
Returns
|
|
101
|
+
-------
|
|
102
|
+
float | int | list[float | int]
|
|
103
|
+
The validated value.
|
|
104
|
+
"""
|
|
105
|
+
try:
|
|
106
|
+
return Metric(value=value).value
|
|
107
|
+
except ValidationError as e:
|
|
108
|
+
raise ValueError("Invalid metric value. Must be a list of floats or ints or a float or an int.") from e
|