digitalhub 0.14.0b3__py3-none-any.whl → 0.14.0b5__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.
Files changed (39) hide show
  1. digitalhub/context/context.py +15 -1
  2. digitalhub/entities/_base/executable/entity.py +160 -58
  3. digitalhub/entities/_base/material/entity.py +4 -0
  4. digitalhub/entities/_base/material/utils.py +28 -0
  5. digitalhub/entities/_commons/enums.py +0 -31
  6. digitalhub/entities/_constructors/_resources.py +151 -0
  7. digitalhub/entities/_constructors/name.py +18 -0
  8. digitalhub/entities/_processors/base/crud.py +1 -1
  9. digitalhub/entities/_processors/base/special_ops.py +1 -1
  10. digitalhub/entities/_processors/context/crud.py +25 -25
  11. digitalhub/entities/_processors/context/special_ops.py +1 -1
  12. digitalhub/entities/_processors/utils.py +2 -1
  13. digitalhub/entities/artifact/crud.py +37 -17
  14. digitalhub/entities/dataitem/crud.py +37 -13
  15. digitalhub/entities/dataitem/table/entity.py +3 -0
  16. digitalhub/entities/function/crud.py +39 -19
  17. digitalhub/entities/model/crud.py +37 -17
  18. digitalhub/entities/project/_base/entity.py +5 -5
  19. digitalhub/entities/project/crud.py +6 -20
  20. digitalhub/entities/run/_base/entity.py +1 -1
  21. digitalhub/entities/run/crud.py +54 -21
  22. digitalhub/entities/secret/crud.py +6 -20
  23. digitalhub/entities/task/crud.py +40 -25
  24. digitalhub/entities/trigger/crud.py +43 -19
  25. digitalhub/entities/workflow/crud.py +39 -16
  26. digitalhub/stores/client/_base/enums.py +39 -0
  27. digitalhub/stores/client/_base/key_builder.py +1 -1
  28. digitalhub/stores/client/_base/params_builder.py +48 -0
  29. digitalhub/stores/client/dhcore/api_builder.py +2 -1
  30. digitalhub/stores/client/dhcore/client.py +67 -55
  31. digitalhub/stores/client/dhcore/params_builder.py +130 -75
  32. digitalhub/stores/client/local/api_builder.py +1 -1
  33. digitalhub/stores/client/local/params_builder.py +18 -41
  34. digitalhub/stores/data/s3/store.py +8 -5
  35. {digitalhub-0.14.0b3.dist-info → digitalhub-0.14.0b5.dist-info}/METADATA +1 -1
  36. {digitalhub-0.14.0b3.dist-info → digitalhub-0.14.0b5.dist-info}/RECORD +39 -37
  37. {digitalhub-0.14.0b3.dist-info → digitalhub-0.14.0b5.dist-info}/WHEEL +0 -0
  38. {digitalhub-0.14.0b3.dist-info → digitalhub-0.14.0b5.dist-info}/licenses/AUTHORS +0 -0
  39. {digitalhub-0.14.0b3.dist-info → digitalhub-0.14.0b5.dist-info}/licenses/LICENSE +0 -0
@@ -4,9 +4,13 @@
4
4
 
5
5
  from __future__ import annotations
6
6
 
7
- from digitalhub.entities._commons.enums import ApiCategories, BackendOperations
7
+ from digitalhub.stores.client._base.enums import ApiCategories, BackendOperations
8
8
  from digitalhub.stores.client._base.params_builder import ClientParametersBuilder
9
9
 
10
+ DEFAULT_START_PAGE = 0
11
+ DEFAULT_SIZE = 25
12
+ DEFAULT_SORT = "metadata.updated,DESC"
13
+
10
14
 
11
15
  class ClientDHCoreParametersBuilder(ClientParametersBuilder):
12
16
  """
@@ -33,11 +37,6 @@ class ClientDHCoreParametersBuilder(ClientParametersBuilder):
33
37
  """
34
38
  Build HTTP request parameters for DHCore API calls.
35
39
 
36
- Routes parameter building to appropriate method based on API category
37
- (base or context operations) and applies operation-specific transformations.
38
- Acts as dispatcher, initializing parameter dictionaries with 'params' key
39
- for query parameters.
40
-
41
40
  Parameters
42
41
  ----------
43
42
  category : str
@@ -61,108 +60,105 @@ class ClientDHCoreParametersBuilder(ClientParametersBuilder):
61
60
 
62
61
  def build_parameters_base(self, operation: str, **kwargs) -> dict:
63
62
  """
64
- Build parameters for base-level API operations.
65
-
66
- Constructs HTTP request parameters for project-level operations and
67
- entity sharing functionality. Handles CASCADE (boolean to lowercase string),
68
- SHARE (user parameter to query params), and UNSHARE (requires unshare=True
69
- and entity id).
63
+ Constructs HTTP request parameters for project operations.
70
64
 
71
65
  Parameters
72
66
  ----------
73
67
  operation : str
74
- API operation: DELETE (project deletion with optional cascade)
75
- or SHARE (entity sharing/unsharing with users).
68
+ API operation.
76
69
  **kwargs : dict
77
- Operation-specific parameters:
78
- - cascade (bool): For DELETE, whether to cascade delete
79
- - user (str): For SHARE, target user for sharing
80
- - unshare (bool): For SHARE, whether to unshare instead
81
- - id (str): For SHARE unshare, entity ID to unshare
82
-
70
+ Operation-specific parameters.
83
71
  Returns
84
72
  -------
85
73
  dict
86
74
  Formatted parameters with 'params' containing query parameters.
87
75
  """
88
- kwargs = self._set_params(**kwargs)
76
+ kwargs = self._ensure_params(**kwargs)
77
+
78
+ # Handle delete
89
79
  if operation == BackendOperations.DELETE.value:
90
80
  if (cascade := kwargs.pop("cascade", None)) is not None:
91
- kwargs["params"]["cascade"] = str(cascade).lower()
81
+ kwargs = self._add_param("cascade", str(cascade).lower(), **kwargs)
82
+
83
+ # Handle share
92
84
  elif operation == BackendOperations.SHARE.value:
93
- kwargs["params"]["user"] = kwargs.pop("user")
85
+ kwargs = self._add_param("user", kwargs.pop("user"), **kwargs)
94
86
  if kwargs.pop("unshare", False):
95
- kwargs["params"]["id"] = kwargs.pop("id")
87
+ kwargs = self._add_param("id", kwargs.pop("id"), **kwargs)
96
88
 
97
89
  return kwargs
98
90
 
99
91
  def build_parameters_context(self, operation: str, **kwargs) -> dict:
100
92
  """
101
- Build parameters for context-level API operations.
102
-
103
93
  Constructs HTTP request parameters for entity management and search within
104
- projects. Handles search filters via 'filter' parameter, pagination with
105
- 'page' and 'size', result ordering with 'sort' parameter. READ supports
106
- embedded entity inclusion, DELETE requires entity 'id' parameter.
94
+ projects.
107
95
 
108
96
  Parameters
109
97
  ----------
110
98
  operation : str
111
- API operation: SEARCH (search entities with filtering), READ_MANY
112
- (retrieve multiple with pagination), DELETE (delete by ID),
113
- READ (read by ID with optional embedded).
99
+ API operation.
114
100
  **kwargs : dict
115
- Operation-specific parameters:
116
- - params (dict): Search filters and conditions
117
- - page (int): Page number for pagination (default: 0)
118
- - size (int): Items per page (default: 20)
119
- - order_by (str): Field to order results by
120
- - order (str): Order direction ('asc' or 'desc')
121
- - embedded (bool): For READ, whether to include embedded entities
122
- - id (str): For READ/DELETE, entity identifier
101
+ Operation-specific parameters.
123
102
 
124
103
  Returns
125
104
  -------
126
105
  dict
127
- Formatted parameters with 'params' for query parameters and
128
- other request-specific parameters like 'id' for entity operations.
106
+ Formatted parameters with 'params'.
129
107
  """
130
- kwargs = self._set_params(**kwargs)
108
+ kwargs = self._ensure_params(**kwargs)
131
109
 
132
110
  # Handle read
133
111
  if operation == BackendOperations.READ.value:
134
- name = kwargs.pop("entity_name", None)
135
- if name is not None:
136
- kwargs["params"]["name"] = name
112
+ if (name := kwargs.pop("name", None)) is not None:
113
+ kwargs = self._add_param("name", name, **kwargs)
114
+
115
+ # Handle read all versions
137
116
  elif operation == BackendOperations.READ_ALL_VERSIONS.value:
138
- kwargs["params"]["versions"] = "all"
139
- kwargs["params"]["name"] = kwargs.pop("entity_name")
117
+ kwargs = self._add_param("versions", "all", **kwargs)
118
+ kwargs = self._add_param("name", kwargs.pop("name"), **kwargs)
119
+
120
+ # Handle list
121
+ elif operation == BackendOperations.LIST.value:
122
+ possible_list_params = [
123
+ "q",
124
+ "name",
125
+ "kind",
126
+ "user",
127
+ "state",
128
+ "created",
129
+ "updated",
130
+ "versions",
131
+ "function",
132
+ "workflow",
133
+ "action",
134
+ "task",
135
+ ]
136
+ list_params = {k: kwargs.get(k, None) for k in possible_list_params}
137
+ list_params = self._filter_none_params(**list_params)
138
+ for k, v in list_params.items():
139
+ kwargs = self._add_param(k, v, **kwargs)
140
+ for k in possible_list_params:
141
+ kwargs.pop(k, None)
142
+
140
143
  # Handle delete
141
144
  elif operation == BackendOperations.DELETE.value:
142
- # Handle cascade
143
145
  if (cascade := kwargs.pop("cascade", None)) is not None:
144
- kwargs["params"]["cascade"] = str(cascade).lower()
145
-
146
- # Handle delete all versions
147
- entity_id = kwargs.pop("entity_id")
148
- entity_name = kwargs.pop("entity_name")
149
- if not kwargs.pop("delete_all_versions", False):
150
- if entity_id is None:
151
- raise ValueError(
152
- "If `delete_all_versions` is False, `entity_id` must be provided,"
153
- " either as an argument or in key `identifier`.",
154
- )
155
- else:
156
- kwargs["params"]["name"] = entity_name
146
+ kwargs = self._add_param("cascade", str(cascade).lower(), **kwargs)
147
+
148
+ elif operation == BackendOperations.DELETE_ALL_VERSIONS.value:
149
+ if (cascade := kwargs.pop("cascade", None)) is not None:
150
+ kwargs = self._add_param("cascade", str(cascade).lower(), **kwargs)
151
+ kwargs = self._add_param("name", kwargs.pop("name"), **kwargs)
152
+
157
153
  # Handle search
158
154
  elif operation == BackendOperations.SEARCH.value:
159
155
  # Handle fq
160
156
  if (fq := kwargs.pop("fq", None)) is not None:
161
- kwargs["params"]["fq"] = fq
157
+ kwargs = self._add_param("fq", fq, **kwargs)
162
158
 
163
159
  # Add search query
164
160
  if (query := kwargs.pop("query", None)) is not None:
165
- kwargs["params"]["q"] = query
161
+ kwargs = self._add_param("q", query, **kwargs)
166
162
 
167
163
  # Add search filters
168
164
  fq = []
@@ -205,17 +201,63 @@ class ClientDHCoreParametersBuilder(ClientParametersBuilder):
205
201
  fq.append(f"metadata.labels:({labels})")
206
202
 
207
203
  # Add filters
208
- kwargs["params"]["fq"] = fq
204
+ kwargs = self._add_param("fq", fq, **kwargs)
205
+
206
+ return kwargs
207
+
208
+ def set_pagination(self, partial: bool = False, **kwargs) -> dict:
209
+ """
210
+ Ensure pagination parameters are set in kwargs.
211
+
212
+ Parameters
213
+ ----------
214
+ **kwargs : dict
215
+ Keyword arguments to format. May be empty or contain various
216
+ parameters for API operations.
217
+
218
+ Returns
219
+ -------
220
+ dict
221
+ Pagination parameters set in 'params' of kwargs.
222
+ """
223
+ kwargs = self._ensure_params(**kwargs)
224
+
225
+ if "page" not in kwargs["params"]:
226
+ kwargs["params"]["page"] = DEFAULT_START_PAGE
227
+
228
+ if partial:
229
+ return kwargs
230
+
231
+ if "size" not in kwargs["params"]:
232
+ kwargs["params"]["size"] = DEFAULT_SIZE
233
+
234
+ if "sort" not in kwargs["params"]:
235
+ kwargs["params"]["sort"] = DEFAULT_SORT
209
236
 
210
237
  return kwargs
211
238
 
212
239
  @staticmethod
213
- def _set_params(**kwargs) -> dict:
240
+ def read_page_number(**kwargs) -> int:
241
+ """
242
+ Read current page number from kwargs.
243
+
244
+ Parameters
245
+ ----------
246
+ **kwargs : dict
247
+ Keyword arguments to format. May be empty or contain various
248
+ parameters for API operations.
249
+
250
+ Returns
251
+ -------
252
+ int
253
+ Current page number.
214
254
  """
215
- Initialize parameter dictionary with query parameters structure.
255
+ return kwargs["params"]["page"]
216
256
 
217
- Ensures parameter dictionary has 'params' key for HTTP query parameters,
218
- guaranteeing consistent structure for all parameter building methods.
257
+ @staticmethod
258
+ def increment_page_number(**kwargs) -> dict:
259
+ """
260
+ Increment page number in kwargs.
219
261
 
220
262
  Parameters
221
263
  ----------
@@ -226,11 +268,24 @@ class ClientDHCoreParametersBuilder(ClientParametersBuilder):
226
268
  Returns
227
269
  -------
228
270
  dict
229
- Parameters dictionary with guaranteed 'params' key containing
230
- empty dict if not already present.
271
+ Parameters dictionary with incremented 'page' number in 'params'.
231
272
  """
232
- if not kwargs:
233
- kwargs = {}
234
- if "params" not in kwargs:
235
- kwargs["params"] = {}
273
+ kwargs["params"]["page"] += 1
236
274
  return kwargs
275
+
276
+ @staticmethod
277
+ def _filter_none_params(**kwargs) -> dict:
278
+ """
279
+ Filter out None values from kwargs.
280
+
281
+ Parameters
282
+ ----------
283
+ **kwargs : dict
284
+ Keyword arguments to filter.
285
+
286
+ Returns
287
+ -------
288
+ dict
289
+ Filtered kwargs.
290
+ """
291
+ return {k: v for k, v in kwargs.items() if v is not None}
@@ -4,8 +4,8 @@
4
4
 
5
5
  from __future__ import annotations
6
6
 
7
- from digitalhub.entities._commons.enums import ApiCategories, BackendOperations
8
7
  from digitalhub.stores.client._base.api_builder import ClientApiBuilder
8
+ from digitalhub.stores.client._base.enums import ApiCategories, BackendOperations
9
9
  from digitalhub.stores.client.local.enums import LocalClientVar
10
10
  from digitalhub.utils.exceptions import BackendError
11
11
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  from __future__ import annotations
6
6
 
7
- from digitalhub.entities._commons.enums import ApiCategories, BackendOperations
7
+ from digitalhub.stores.client._base.enums import ApiCategories, BackendOperations
8
8
  from digitalhub.stores.client._base.params_builder import ClientParametersBuilder
9
9
 
10
10
 
@@ -51,10 +51,13 @@ class ClientLocalParametersBuilder(ClientParametersBuilder):
51
51
  dict
52
52
  Parameters formatted.
53
53
  """
54
- kwargs = self._set_params(**kwargs)
54
+ kwargs = self._ensure_params(**kwargs)
55
+
56
+ # Handle delete
55
57
  if operation == BackendOperations.DELETE.value:
56
58
  if (cascade := kwargs.pop("cascade", None)) is not None:
57
- kwargs["params"]["cascade"] = str(cascade).lower()
59
+ kwargs = self._add_param("cascade", str(cascade).lower(), **kwargs)
60
+
58
61
  return kwargs
59
62
 
60
63
  def build_parameters_context(self, operation: str, **kwargs) -> dict:
@@ -73,48 +76,22 @@ class ClientLocalParametersBuilder(ClientParametersBuilder):
73
76
  dict
74
77
  Parameters formatted.
75
78
  """
76
- kwargs = self._set_params(**kwargs)
79
+ kwargs = self._ensure_params(**kwargs)
77
80
 
78
- # Handle read
81
+ # Handle read all versions
79
82
  if operation == BackendOperations.READ_ALL_VERSIONS.value:
80
- kwargs["params"]["versions"] = "all"
81
- kwargs["params"]["name"] = kwargs.pop("entity_name")
83
+ kwargs = self._add_param("versions", "all", **kwargs)
84
+ kwargs = self._add_param("name", kwargs.pop("name"), **kwargs)
85
+
82
86
  # Handle delete
83
87
  elif operation == BackendOperations.DELETE.value:
84
- # Handle cascade
85
- if cascade := kwargs.pop("cascade", None) is not None:
86
- kwargs["params"]["cascade"] = str(cascade).lower()
87
-
88
- # Handle delete all versions
89
- entity_id = kwargs.pop("entity_id")
90
- entity_name = kwargs.pop("entity_name")
91
- if not kwargs.pop("delete_all_versions", False):
92
- if entity_id is None:
93
- raise ValueError(
94
- "If `delete_all_versions` is False, `entity_id` must be provided,"
95
- " either as an argument or in key `identifier`.",
96
- )
97
- else:
98
- kwargs["params"]["name"] = entity_name
99
- return kwargs
100
-
101
- @staticmethod
102
- def _set_params(**kwargs) -> dict:
103
- """
104
- Format params parameter.
88
+ if (cascade := kwargs.pop("cascade", None)) is not None:
89
+ kwargs = self._add_param("cascade", str(cascade).lower(), **kwargs)
105
90
 
106
- Parameters
107
- ----------
108
- **kwargs : dict
109
- Keyword arguments.
91
+ # Handle delete all versions
92
+ elif operation == BackendOperations.DELETE_ALL_VERSIONS.value:
93
+ if (cascade := kwargs.pop("cascade", None)) is not None:
94
+ kwargs = self._add_param("cascade", str(cascade).lower(), **kwargs)
95
+ kwargs = self._add_param("name", kwargs.pop("name"), **kwargs)
110
96
 
111
- Returns
112
- -------
113
- dict
114
- Parameters with initialized params.
115
- """
116
- if not kwargs:
117
- kwargs = {}
118
- if "params" not in kwargs:
119
- kwargs["params"] = {}
120
97
  return kwargs
@@ -29,6 +29,8 @@ if typing.TYPE_CHECKING:
29
29
  # Type aliases
30
30
  S3Client = Type["botocore.client.S3"]
31
31
 
32
+ MULTIPART_THRESHOLD = 100 * 1024 * 1024
33
+
32
34
 
33
35
  class S3Store(Store):
34
36
  """
@@ -331,10 +333,11 @@ class S3Store(Store):
331
333
  str
332
334
  The S3 path where the dataframe was saved.
333
335
  """
334
- fileobj = BytesIO()
335
336
  reader = get_reader_by_object(df)
336
- reader.write_df(df, fileobj, extension=extension, **kwargs)
337
- return self.upload_fileobject(fileobj, dst)
337
+ with BytesIO() as fileobj:
338
+ reader.write_df(df, fileobj, extension=extension, **kwargs)
339
+ fileobj.seek(0)
340
+ return self.upload_fileobject(fileobj, dst)
338
341
 
339
342
  ##############################
340
343
  # Wrapper methods
@@ -581,7 +584,7 @@ class S3Store(Store):
581
584
  Bucket=bucket,
582
585
  Key=key,
583
586
  ExtraArgs=extra_args,
584
- Config=TransferConfig(multipart_threshold=100 * 1024 * 1024),
587
+ Config=TransferConfig(multipart_threshold=MULTIPART_THRESHOLD),
585
588
  )
586
589
 
587
590
  @staticmethod
@@ -609,7 +612,7 @@ class S3Store(Store):
609
612
  Fileobj=fileobj,
610
613
  Bucket=bucket,
611
614
  Key=key,
612
- Config=TransferConfig(multipart_threshold=100 * 1024 * 1024),
615
+ Config=TransferConfig(multipart_threshold=MULTIPART_THRESHOLD),
613
616
  )
614
617
 
615
618
  ##############################
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: digitalhub
3
- Version: 0.14.0b3
3
+ Version: 0.14.0b5
4
4
  Summary: Python SDK for Digitalhub
5
5
  Project-URL: Homepage, https://github.com/scc-digitalhub/digitalhub-sdk
6
6
  Author-email: Fondazione Bruno Kessler <digitalhub@fbk.eu>, Matteo Martini <mmartini@fbk.eu>