digitalhub 0.9.2__py3-none-any.whl → 0.10.0b1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of digitalhub might be problematic. Click here for more details.

Files changed (68) hide show
  1. digitalhub/__init__.py +2 -3
  2. digitalhub/client/_base/client.py +3 -2
  3. digitalhub/client/dhcore/api_builder.py +5 -0
  4. digitalhub/client/dhcore/client.py +27 -399
  5. digitalhub/client/dhcore/configurator.py +339 -0
  6. digitalhub/client/dhcore/error_parser.py +107 -0
  7. digitalhub/client/dhcore/models.py +13 -23
  8. digitalhub/client/dhcore/utils.py +4 -44
  9. digitalhub/client/local/api_builder.py +9 -17
  10. digitalhub/client/local/client.py +12 -2
  11. digitalhub/client/local/enums.py +11 -0
  12. digitalhub/configurator/api.py +31 -0
  13. digitalhub/configurator/configurator.py +194 -0
  14. digitalhub/configurator/credentials_store.py +65 -0
  15. digitalhub/configurator/ini_module.py +74 -0
  16. digitalhub/entities/_base/_base/entity.py +2 -2
  17. digitalhub/entities/_base/material/entity.py +19 -6
  18. digitalhub/entities/_base/material/utils.py +2 -2
  19. digitalhub/entities/_commons/enums.py +1 -0
  20. digitalhub/entities/_commons/models.py +9 -0
  21. digitalhub/entities/_commons/utils.py +25 -0
  22. digitalhub/entities/_operations/processor.py +103 -107
  23. digitalhub/entities/artifact/crud.py +3 -3
  24. digitalhub/entities/artifact/utils.py +1 -1
  25. digitalhub/entities/dataitem/_base/entity.py +2 -2
  26. digitalhub/entities/dataitem/crud.py +3 -3
  27. digitalhub/entities/dataitem/table/entity.py +2 -2
  28. digitalhub/{utils/data_utils.py → entities/dataitem/table/utils.py} +43 -51
  29. digitalhub/entities/dataitem/utils.py +6 -3
  30. digitalhub/entities/model/_base/entity.py +172 -0
  31. digitalhub/entities/model/_base/spec.py +0 -10
  32. digitalhub/entities/model/_base/status.py +10 -0
  33. digitalhub/entities/model/crud.py +3 -3
  34. digitalhub/entities/model/huggingface/spec.py +6 -3
  35. digitalhub/entities/model/mlflow/models.py +2 -2
  36. digitalhub/entities/model/mlflow/spec.py +1 -3
  37. digitalhub/entities/model/mlflow/utils.py +44 -5
  38. digitalhub/entities/run/_base/entity.py +149 -0
  39. digitalhub/entities/run/_base/status.py +12 -0
  40. digitalhub/entities/task/_base/spec.py +2 -0
  41. digitalhub/entities/task/crud.py +4 -0
  42. digitalhub/readers/{_commons → pandas}/enums.py +4 -0
  43. digitalhub/readers/pandas/reader.py +58 -10
  44. digitalhub/stores/_base/store.py +1 -49
  45. digitalhub/stores/api.py +8 -33
  46. digitalhub/stores/builder.py +44 -161
  47. digitalhub/stores/local/store.py +4 -18
  48. digitalhub/stores/remote/store.py +3 -10
  49. digitalhub/stores/s3/configurator.py +107 -0
  50. digitalhub/stores/s3/enums.py +17 -0
  51. digitalhub/stores/s3/models.py +21 -0
  52. digitalhub/stores/s3/store.py +8 -28
  53. digitalhub/{utils/s3_utils.py → stores/s3/utils.py} +7 -3
  54. digitalhub/stores/sql/configurator.py +88 -0
  55. digitalhub/stores/sql/enums.py +16 -0
  56. digitalhub/stores/sql/models.py +24 -0
  57. digitalhub/stores/sql/store.py +14 -57
  58. digitalhub/utils/exceptions.py +6 -0
  59. digitalhub/utils/generic_utils.py +9 -8
  60. digitalhub/utils/uri_utils.py +1 -1
  61. {digitalhub-0.9.2.dist-info → digitalhub-0.10.0b1.dist-info}/METADATA +5 -6
  62. {digitalhub-0.9.2.dist-info → digitalhub-0.10.0b1.dist-info}/RECORD +67 -54
  63. test/local/imports/test_imports.py +0 -1
  64. digitalhub/client/dhcore/env.py +0 -23
  65. /digitalhub/{readers/_commons → configurator}/__init__.py +0 -0
  66. {digitalhub-0.9.2.dist-info → digitalhub-0.10.0b1.dist-info}/LICENSE.txt +0 -0
  67. {digitalhub-0.9.2.dist-info → digitalhub-0.10.0b1.dist-info}/WHEEL +0 -0
  68. {digitalhub-0.9.2.dist-info → digitalhub-0.10.0b1.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 dict_to_json
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 dict_to_json(self.to_dict())
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.refresh()
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}://{get_s3_bucket()}/{project}/{entity_type}/{name}/{uuid}"
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:
@@ -84,6 +84,7 @@ class BackendOperations(Enum):
84
84
  LOGS = "logs"
85
85
  SEARCH = "search"
86
86
  SHARE = "share"
87
+ METRICS = "metrics"
87
88
 
88
89
 
89
90
  class EntityKinds(Enum):
@@ -0,0 +1,9 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Union
4
+
5
+ from pydantic import BaseModel
6
+
7
+
8
+ class Metric(BaseModel):
9
+ value: Union[float, int, list[Union[float, int]]]
@@ -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