digitalhub 0.9.2__py3-none-any.whl → 0.10.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.

Files changed (121) hide show
  1. digitalhub/__init__.py +2 -3
  2. digitalhub/client/_base/api_builder.py +1 -1
  3. digitalhub/client/_base/client.py +25 -2
  4. digitalhub/client/_base/params_builder.py +16 -0
  5. digitalhub/client/dhcore/api_builder.py +9 -3
  6. digitalhub/client/dhcore/client.py +30 -398
  7. digitalhub/client/dhcore/configurator.py +361 -0
  8. digitalhub/client/dhcore/error_parser.py +107 -0
  9. digitalhub/client/dhcore/models.py +13 -23
  10. digitalhub/client/dhcore/params_builder.py +178 -0
  11. digitalhub/client/dhcore/utils.py +4 -44
  12. digitalhub/client/local/api_builder.py +13 -18
  13. digitalhub/client/local/client.py +18 -2
  14. digitalhub/client/local/enums.py +11 -0
  15. digitalhub/client/local/params_builder.py +116 -0
  16. digitalhub/configurator/api.py +31 -0
  17. digitalhub/configurator/configurator.py +195 -0
  18. digitalhub/configurator/credentials_store.py +65 -0
  19. digitalhub/configurator/ini_module.py +74 -0
  20. digitalhub/entities/_base/_base/entity.py +2 -2
  21. digitalhub/entities/_base/context/entity.py +4 -4
  22. digitalhub/entities/_base/entity/builder.py +5 -5
  23. digitalhub/entities/_base/executable/entity.py +2 -2
  24. digitalhub/entities/_base/material/entity.py +12 -12
  25. digitalhub/entities/_base/material/status.py +1 -1
  26. digitalhub/entities/_base/material/utils.py +2 -2
  27. digitalhub/entities/_base/unversioned/entity.py +2 -2
  28. digitalhub/entities/_base/versioned/entity.py +2 -2
  29. digitalhub/entities/_commons/enums.py +2 -0
  30. digitalhub/entities/_commons/metrics.py +164 -0
  31. digitalhub/entities/_commons/types.py +5 -0
  32. digitalhub/entities/_commons/utils.py +2 -2
  33. digitalhub/entities/_processors/base.py +527 -0
  34. digitalhub/entities/{_operations/processor.py → _processors/context.py} +212 -837
  35. digitalhub/entities/_processors/utils.py +158 -0
  36. digitalhub/entities/artifact/artifact/spec.py +3 -1
  37. digitalhub/entities/artifact/crud.py +13 -12
  38. digitalhub/entities/artifact/utils.py +1 -1
  39. digitalhub/entities/builders.py +6 -18
  40. digitalhub/entities/dataitem/_base/entity.py +0 -41
  41. digitalhub/entities/dataitem/crud.py +27 -15
  42. digitalhub/entities/dataitem/table/entity.py +49 -35
  43. digitalhub/entities/dataitem/table/models.py +4 -3
  44. digitalhub/{utils/data_utils.py → entities/dataitem/table/utils.py} +46 -54
  45. digitalhub/entities/dataitem/utils.py +58 -10
  46. digitalhub/entities/function/crud.py +9 -9
  47. digitalhub/entities/model/_base/entity.py +120 -0
  48. digitalhub/entities/model/_base/spec.py +6 -17
  49. digitalhub/entities/model/_base/status.py +10 -0
  50. digitalhub/entities/model/crud.py +13 -12
  51. digitalhub/entities/model/huggingface/spec.py +9 -4
  52. digitalhub/entities/model/mlflow/models.py +2 -2
  53. digitalhub/entities/model/mlflow/spec.py +7 -7
  54. digitalhub/entities/model/mlflow/utils.py +44 -5
  55. digitalhub/entities/project/_base/entity.py +317 -9
  56. digitalhub/entities/project/_base/spec.py +8 -6
  57. digitalhub/entities/project/crud.py +12 -11
  58. digitalhub/entities/run/_base/entity.py +103 -6
  59. digitalhub/entities/run/_base/spec.py +4 -2
  60. digitalhub/entities/run/_base/status.py +12 -0
  61. digitalhub/entities/run/crud.py +8 -8
  62. digitalhub/entities/secret/_base/entity.py +3 -3
  63. digitalhub/entities/secret/_base/spec.py +4 -2
  64. digitalhub/entities/secret/crud.py +11 -9
  65. digitalhub/entities/task/_base/entity.py +4 -4
  66. digitalhub/entities/task/_base/models.py +51 -40
  67. digitalhub/entities/task/_base/spec.py +2 -0
  68. digitalhub/entities/task/_base/utils.py +2 -2
  69. digitalhub/entities/task/crud.py +12 -8
  70. digitalhub/entities/workflow/crud.py +9 -9
  71. digitalhub/factory/utils.py +9 -9
  72. digitalhub/readers/{_base → data/_base}/builder.py +1 -1
  73. digitalhub/readers/{_base → data/_base}/reader.py +16 -4
  74. digitalhub/readers/{api.py → data/api.py} +2 -2
  75. digitalhub/readers/{factory.py → data/factory.py} +3 -3
  76. digitalhub/readers/{pandas → data/pandas}/builder.py +2 -2
  77. digitalhub/readers/{pandas → data/pandas}/reader.py +110 -30
  78. digitalhub/readers/query/__init__.py +0 -0
  79. digitalhub/stores/_base/store.py +59 -69
  80. digitalhub/stores/api.py +8 -33
  81. digitalhub/stores/builder.py +44 -161
  82. digitalhub/stores/local/store.py +106 -89
  83. digitalhub/stores/remote/store.py +86 -11
  84. digitalhub/stores/s3/configurator.py +108 -0
  85. digitalhub/stores/s3/enums.py +17 -0
  86. digitalhub/stores/s3/models.py +21 -0
  87. digitalhub/stores/s3/store.py +154 -70
  88. digitalhub/{utils/s3_utils.py → stores/s3/utils.py} +7 -3
  89. digitalhub/stores/sql/configurator.py +88 -0
  90. digitalhub/stores/sql/enums.py +16 -0
  91. digitalhub/stores/sql/models.py +24 -0
  92. digitalhub/stores/sql/store.py +106 -85
  93. digitalhub/{readers/_commons → utils}/enums.py +5 -1
  94. digitalhub/utils/exceptions.py +6 -0
  95. digitalhub/utils/file_utils.py +8 -7
  96. digitalhub/utils/generic_utils.py +28 -15
  97. digitalhub/utils/git_utils.py +16 -9
  98. digitalhub/utils/types.py +5 -0
  99. digitalhub/utils/uri_utils.py +2 -2
  100. {digitalhub-0.9.2.dist-info → digitalhub-0.10.0.dist-info}/METADATA +25 -31
  101. {digitalhub-0.9.2.dist-info → digitalhub-0.10.0.dist-info}/RECORD +108 -99
  102. {digitalhub-0.9.2.dist-info → digitalhub-0.10.0.dist-info}/WHEEL +1 -2
  103. digitalhub/client/dhcore/env.py +0 -23
  104. digitalhub/entities/_base/project/entity.py +0 -341
  105. digitalhub-0.9.2.dist-info/top_level.txt +0 -2
  106. test/local/CRUD/test_artifacts.py +0 -96
  107. test/local/CRUD/test_dataitems.py +0 -96
  108. test/local/CRUD/test_models.py +0 -95
  109. test/local/imports/test_imports.py +0 -66
  110. test/local/instances/test_validate.py +0 -55
  111. test/test_crud_functions.py +0 -109
  112. test/test_crud_runs.py +0 -86
  113. test/test_crud_tasks.py +0 -81
  114. test/testkfp.py +0 -37
  115. test/testkfp_pipeline.py +0 -22
  116. /digitalhub/{entities/_base/project → configurator}/__init__.py +0 -0
  117. /digitalhub/entities/{_operations → _processors}/__init__.py +0 -0
  118. /digitalhub/readers/{_base → data}/__init__.py +0 -0
  119. /digitalhub/readers/{_commons → data/_base}/__init__.py +0 -0
  120. /digitalhub/readers/{pandas → data/pandas}/__init__.py +0 -0
  121. {digitalhub-0.9.2.dist-info → digitalhub-0.10.0.dist-info/licenses}/LICENSE.txt +0 -0
@@ -1,15 +1,18 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import typing
3
4
  from abc import abstractmethod
4
5
  from pathlib import Path
5
6
  from tempfile import mkdtemp
6
7
  from typing import Any
7
8
 
8
- from pydantic import BaseModel, ConfigDict
9
-
10
- from digitalhub.readers.api import get_reader_by_engine
9
+ from digitalhub.readers.data.api import get_reader_by_engine
11
10
  from digitalhub.utils.exceptions import StoreError
12
- from digitalhub.utils.uri_utils import SchemeCategory, has_local_scheme
11
+ from digitalhub.utils.types import SourcesOrListOfSources
12
+ from digitalhub.utils.uri_utils import has_local_scheme
13
+
14
+ if typing.TYPE_CHECKING:
15
+ from digitalhub.readers.data._base.reader import DataframeReader
13
16
 
14
17
 
15
18
  class Store:
@@ -17,24 +20,6 @@ class Store:
17
20
  Store abstract class.
18
21
  """
19
22
 
20
- def __init__(self, name: str, store_type: str) -> None:
21
- """
22
- Constructor.
23
-
24
- Parameters
25
- ----------
26
- name : str
27
- Store name.
28
- store_type : str
29
- Store type. Used to choose the right store implementation.
30
-
31
- Returns
32
- -------
33
- None
34
- """
35
- self.name = name
36
- self.type = store_type
37
-
38
23
  ##############################
39
24
  # I/O methods
40
25
  ##############################
@@ -52,7 +37,7 @@ class Store:
52
37
  """
53
38
 
54
39
  @abstractmethod
55
- def upload(self, src: str | list[str], dst: str) -> list[tuple[str, str]]:
40
+ def upload(self, src: SourcesOrListOfSources, dst: str) -> list[tuple[str, str]]:
56
41
  """
57
42
  Method to upload artifact to storage.
58
43
  """
@@ -72,39 +57,32 @@ class Store:
72
57
  ##############################
73
58
 
74
59
  @abstractmethod
75
- def write_df(self, df: Any, dst: str, extension: str | None = None, **kwargs) -> str:
76
- """
77
- Write DataFrame as parquet or csv.
78
- """
79
-
80
60
  def read_df(
81
61
  self,
82
- path: str | list[str],
83
- extension: str,
62
+ path: SourcesOrListOfSources,
63
+ file_format: str | None = None,
84
64
  engine: str | None = None,
85
65
  **kwargs,
86
66
  ) -> Any:
87
67
  """
88
68
  Read DataFrame from path.
69
+ """
89
70
 
90
- Parameters
91
- ----------
92
- path : str | list[str]
93
- Path(s) to read DataFrame from.
94
- extension : str
95
- Extension of the file.
96
- engine : str
97
- Dataframe engine (pandas, polars, etc.).
98
- **kwargs : dict
99
- Keyword arguments.
71
+ @abstractmethod
72
+ def query(
73
+ self,
74
+ query: str,
75
+ engine: str | None = None,
76
+ ) -> Any:
77
+ """
78
+ Query data from database.
79
+ """
100
80
 
101
- Returns
102
- -------
103
- Any
104
- DataFrame.
81
+ @abstractmethod
82
+ def write_df(self, df: Any, dst: str, extension: str | None = None, **kwargs) -> str:
83
+ """
84
+ Write DataFrame as parquet or csv.
105
85
  """
106
- reader = get_reader_by_engine(engine)
107
- return reader.read_df(path, extension, **kwargs)
108
86
 
109
87
  ##############################
110
88
  # Helpers methods
@@ -182,7 +160,7 @@ class Store:
182
160
 
183
161
  Parameters
184
162
  ----------
185
- path : str
163
+ path : str | Path
186
164
  The path to build.
187
165
 
188
166
  Returns
@@ -208,30 +186,42 @@ class Store:
208
186
  tmpdir = mkdtemp()
209
187
  return Path(tmpdir)
210
188
 
189
+ @staticmethod
190
+ def _get_reader(engine: str | None = None) -> DataframeReader:
191
+ """
192
+ Get Dataframe reader.
211
193
 
212
- class StoreConfig(BaseModel):
213
- """
214
- Store configuration base class.
215
- """
216
-
217
- model_config = ConfigDict(use_enum_values=True)
218
-
219
-
220
- class StoreParameters(BaseModel):
221
- """
222
- Store configuration class.
223
- """
224
-
225
- model_config = ConfigDict(use_enum_values=True)
194
+ Parameters
195
+ ----------
196
+ engine : str
197
+ Dataframe engine (pandas, polars, etc.).
226
198
 
227
- name: str
228
- """Store id."""
199
+ Returns
200
+ -------
201
+ Any
202
+ Reader object.
203
+ """
204
+ return get_reader_by_engine(engine)
229
205
 
230
- type: SchemeCategory
231
- """Store type to instantiate."""
206
+ @staticmethod
207
+ def _get_extension(extension: str | None = None, path: str | None = None) -> str:
208
+ """
209
+ Get extension from path.
232
210
 
233
- config: StoreConfig = None
234
- """Configuration for the store."""
211
+ Parameters
212
+ ----------
213
+ extension : str
214
+ The extension to get.
215
+ path : str
216
+ The path to get the extension from.
235
217
 
236
- is_default: bool = False
237
- """Flag to determine if the store is the default one."""
218
+ Returns
219
+ -------
220
+ str
221
+ The extension.
222
+ """
223
+ if extension is not None:
224
+ return extension
225
+ if path is not None:
226
+ return Path(path).suffix.removeprefix(".")
227
+ raise ValueError("Extension or path must be provided.")
digitalhub/stores/api.py CHANGED
@@ -5,50 +5,25 @@ import typing
5
5
  from digitalhub.stores.builder import store_builder
6
6
 
7
7
  if typing.TYPE_CHECKING:
8
- from digitalhub.stores._base.store import Store, StoreParameters
8
+ from digitalhub.stores._base.store import Store
9
9
 
10
10
 
11
- def set_store(store_cfg: StoreParameters) -> None:
11
+ def get_store(project: str, uri: str, config: dict | None = None) -> Store:
12
12
  """
13
- Set a new store instance with the given configuration.
14
-
15
- Parameters
16
- ----------
17
- store_cfg : StoreParameters
18
- Store configuration.
19
-
20
- Returns
21
- -------
22
- None
23
- """
24
- store_builder.build(store_cfg)
25
-
26
-
27
- def get_store(uri: str) -> Store:
28
- """
29
- Get store instance by uri.
13
+ Get store instance by URI.
30
14
 
31
15
  Parameters
32
16
  ---------
17
+ project : str
18
+ Project name.
33
19
  uri : str
34
20
  URI to parse.
21
+ config : dict
22
+ Store configuration.
35
23
 
36
24
  Returns
37
25
  -------
38
26
  Store
39
27
  Store instance.
40
28
  """
41
- return store_builder.get(uri)
42
-
43
-
44
- def get_default_store() -> Store:
45
- """
46
- Get the default store instance. The default store is the one that
47
- can persist artifacts and dataitems.
48
-
49
- Returns
50
- -------
51
- Store
52
- Default store instance.
53
- """
54
- return store_builder.default()
29
+ return store_builder.get(uri, config)
@@ -1,28 +1,41 @@
1
1
  from __future__ import annotations
2
2
 
3
- import os
4
3
  import typing
5
4
 
6
- from pydantic import ValidationError
7
-
8
- from digitalhub.stores._base.store import StoreParameters
9
- from digitalhub.stores.local.store import LocalStore, LocalStoreConfig
10
- from digitalhub.stores.remote.store import RemoteStore, RemoteStoreConfig
11
- from digitalhub.stores.s3.store import S3Store, S3StoreConfig
12
- from digitalhub.stores.sql.store import SqlStore, SQLStoreConfig
13
- from digitalhub.utils.exceptions import StoreError
5
+ from digitalhub.configurator.api import get_current_env
6
+ from digitalhub.stores.local.store import LocalStore
7
+ from digitalhub.stores.remote.store import RemoteStore
8
+ from digitalhub.stores.s3.store import S3Store
9
+ from digitalhub.stores.sql.store import SqlStore
14
10
  from digitalhub.utils.uri_utils import SchemeCategory, map_uri_scheme
15
11
 
16
12
  if typing.TYPE_CHECKING:
17
13
  from digitalhub.stores._base.store import Store
18
14
 
19
15
 
20
- REGISTRY_STORES = {
21
- "local": LocalStore,
22
- "s3": S3Store,
23
- "remote": RemoteStore,
24
- "sql": SqlStore,
25
- }
16
+ def _get_class_from_type(type: str) -> Store:
17
+ """
18
+ Get a store class from its type.
19
+
20
+ Parameters
21
+ ----------
22
+ type : str
23
+ Store type.
24
+
25
+ Returns
26
+ -------
27
+ Store
28
+ The store class.
29
+ """
30
+ if type == SchemeCategory.LOCAL.value:
31
+ return LocalStore
32
+ if type == SchemeCategory.S3.value:
33
+ return S3Store
34
+ if type == SchemeCategory.REMOTE.value:
35
+ return RemoteStore
36
+ if type == SchemeCategory.SQL.value:
37
+ return SqlStore
38
+ raise ValueError(f"Unknown store type: {type}")
26
39
 
27
40
 
28
41
  class StoreBuilder:
@@ -32,27 +45,28 @@ class StoreBuilder:
32
45
 
33
46
  def __init__(self) -> None:
34
47
  self._instances: dict[str, Store] = {}
35
- self._default: Store | None = None
36
- self._def_scheme = "s3"
37
48
 
38
- def build(self, store_cfg: StoreParameters) -> None:
49
+ def build(self, store_type: str, config: dict | None = None) -> None:
39
50
  """
40
51
  Build a store instance and register it.
41
- It overrides any existing instance.
42
52
 
43
53
  Parameters
44
54
  ----------
45
- store_cfg : StoreParameters
55
+ store_type : str
56
+ Store type.
57
+ config : dict
46
58
  Store configuration.
47
59
 
48
60
  Returns
49
61
  -------
50
62
  None
51
63
  """
52
- scheme = map_uri_scheme(store_cfg.type)
53
- self._instances[scheme] = self.build_store(store_cfg)
64
+ env = get_current_env()
65
+ if env not in self._instances:
66
+ self._instances[env] = {}
67
+ self._instances[env][store_type] = _get_class_from_type(store_type)(config)
54
68
 
55
- def get(self, uri: str) -> Store:
69
+ def get(self, uri: str, config: dict | None = None) -> Store:
56
70
  """
57
71
  Get a store instance by URI.
58
72
 
@@ -60,152 +74,21 @@ class StoreBuilder:
60
74
  ----------
61
75
  uri : str
62
76
  URI to parse.
63
-
64
- Returns
65
- -------
66
- Store
67
- The store instance.
68
- """
69
- scheme = map_uri_scheme(uri)
70
- if scheme not in self._instances:
71
- store_cfg = get_env_store_config(scheme)
72
- self._instances[scheme] = self.build_store(store_cfg)
73
- return self._instances[scheme]
74
-
75
- def default(self) -> Store:
76
- """
77
- Get the default store instance.
78
-
79
- Returns
80
- -------
81
- Store
82
- The default store instance.
83
-
84
- Raises
85
- ------
86
- StoreError
87
- If no default store is set.
88
- """
89
- if self._default is None:
90
- store_cfg = get_env_store_config(self._def_scheme)
91
- self._default = self.build_store(store_cfg)
92
- return self._default
93
-
94
- def build_store(self, cfg: StoreParameters) -> Store:
95
- """
96
- Build a store instance.
97
-
98
- Parameters
99
- ----------
100
- cfg : StoreParameters
77
+ config : dict
101
78
  Store configuration.
102
79
 
103
80
  Returns
104
81
  -------
105
82
  Store
106
83
  The store instance.
107
-
108
- Raises
109
- ------
110
- NotImplementedError
111
- If the store type is not implemented.
112
84
  """
85
+ env = get_current_env()
86
+ store_type = map_uri_scheme(uri)
113
87
  try:
114
- obj = REGISTRY_STORES[cfg.type](cfg.name, cfg.type, cfg.config)
115
- if cfg.is_default and self._default is not None:
116
- raise StoreError("Only one default store!")
117
- return obj
118
- except KeyError as e:
119
- raise NotImplementedError from e
120
-
121
- @staticmethod
122
- def _check_config(config: StoreParameters | dict) -> StoreParameters:
123
- """
124
- Check the store configuration validity.
125
-
126
- Parameters
127
- ----------
128
- config : StoreParameters | dict
129
- The store configuration.
130
-
131
- Returns
132
- -------
133
- StoreParameters
134
- The store configuration.
135
-
136
- Raises
137
- ------
138
- TypeError
139
- If the config parameter is not a StoreParameters instance or a well-formed dictionary.
140
- """
141
- if not isinstance(config, StoreParameters):
142
- try:
143
- return StoreParameters(**config)
144
- except TypeError as e:
145
- raise StoreError("Invalid store configuration type.") from e
146
- except ValidationError as e:
147
- raise StoreError("Malformed store configuration parameters.") from e
148
- return config
149
-
150
-
151
- def get_env_store_config(scheme: str) -> StoreParameters:
152
- """
153
- Get a store configuration from the environment.
154
-
155
- Parameters
156
- ----------
157
- scheme : str
158
- URI scheme.
159
-
160
- Returns
161
- -------
162
- StoreParameters
163
- The store configuration based on the scheme.
164
-
165
- Raises
166
- ------
167
- ValueError
168
- If the scheme is not supported.
169
- """
170
- if scheme == SchemeCategory.S3.value:
171
- return StoreParameters(
172
- name="s3",
173
- type="s3",
174
- config=S3StoreConfig(
175
- endpoint_url=os.getenv("S3_ENDPOINT_URL"), # type: ignore
176
- aws_access_key_id=os.getenv("AWS_ACCESS_KEY_ID"), # type: ignore
177
- aws_secret_access_key=os.getenv("AWS_SECRET_ACCESS_KEY"), # type: ignore
178
- bucket_name=os.getenv("S3_BUCKET_NAME"), # type: ignore
179
- ),
180
- )
181
- if scheme == SchemeCategory.SQL.value:
182
- return StoreParameters(
183
- name="sql",
184
- type="sql",
185
- config=SQLStoreConfig(
186
- host=os.getenv("POSTGRES_HOST"), # type: ignore
187
- port=os.getenv("POSTGRES_PORT"), # type: ignore
188
- user=os.getenv("POSTGRES_USER"), # type: ignore
189
- password=os.getenv("POSTGRES_PASSWORD"), # type: ignore
190
- database=os.getenv("POSTGRES_DATABASE"), # type: ignore
191
- pg_schema=os.getenv("POSTGRES_SCHEMA"), # type: ignore
192
- ),
193
- )
194
- if scheme == SchemeCategory.REMOTE.value:
195
- return StoreParameters(
196
- name="remote",
197
- type="remote",
198
- config=RemoteStoreConfig(),
199
- )
200
- if scheme == SchemeCategory.LOCAL.value:
201
- return StoreParameters(
202
- name="local",
203
- type="local",
204
- config=LocalStoreConfig(
205
- path="tempsdk",
206
- ),
207
- )
208
- raise ValueError(f"Unsupported scheme {scheme}")
88
+ return self._instances[env][store_type]
89
+ except KeyError:
90
+ self.build(store_type, config)
91
+ return self._instances[env][store_type]
209
92
 
210
93
 
211
94
  store_builder = StoreBuilder()