digitalhub 0.14.0b3__py3-none-any.whl → 0.14.0b4__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/entities/_base/executable/entity.py +160 -58
- digitalhub/entities/_base/material/entity.py +4 -0
- digitalhub/entities/_base/material/utils.py +28 -0
- digitalhub/entities/_commons/enums.py +0 -31
- digitalhub/entities/_constructors/_resources.py +151 -0
- digitalhub/entities/_constructors/name.py +18 -0
- digitalhub/entities/_processors/base/crud.py +1 -1
- digitalhub/entities/_processors/base/special_ops.py +1 -1
- digitalhub/entities/_processors/context/crud.py +25 -25
- digitalhub/entities/_processors/context/special_ops.py +1 -1
- digitalhub/entities/_processors/utils.py +2 -1
- digitalhub/entities/artifact/crud.py +37 -17
- digitalhub/entities/dataitem/crud.py +37 -13
- digitalhub/entities/dataitem/table/entity.py +3 -0
- digitalhub/entities/function/crud.py +39 -19
- digitalhub/entities/model/crud.py +37 -17
- digitalhub/entities/project/_base/entity.py +5 -5
- digitalhub/entities/project/crud.py +6 -20
- digitalhub/entities/run/_base/entity.py +1 -1
- digitalhub/entities/run/crud.py +54 -21
- digitalhub/entities/secret/crud.py +6 -20
- digitalhub/entities/task/crud.py +40 -25
- digitalhub/entities/trigger/crud.py +43 -19
- digitalhub/entities/workflow/crud.py +39 -16
- digitalhub/stores/client/_base/enums.py +39 -0
- digitalhub/stores/client/_base/key_builder.py +1 -1
- digitalhub/stores/client/_base/params_builder.py +48 -0
- digitalhub/stores/client/dhcore/api_builder.py +2 -1
- digitalhub/stores/client/dhcore/client.py +67 -55
- digitalhub/stores/client/dhcore/params_builder.py +130 -75
- digitalhub/stores/client/local/api_builder.py +1 -1
- digitalhub/stores/client/local/params_builder.py +18 -41
- digitalhub/stores/data/s3/store.py +8 -5
- {digitalhub-0.14.0b3.dist-info → digitalhub-0.14.0b4.dist-info}/METADATA +1 -1
- {digitalhub-0.14.0b3.dist-info → digitalhub-0.14.0b4.dist-info}/RECORD +38 -36
- {digitalhub-0.14.0b3.dist-info → digitalhub-0.14.0b4.dist-info}/WHEEL +0 -0
- {digitalhub-0.14.0b3.dist-info → digitalhub-0.14.0b4.dist-info}/licenses/AUTHORS +0 -0
- {digitalhub-0.14.0b3.dist-info → digitalhub-0.14.0b4.dist-info}/licenses/LICENSE +0 -0
|
@@ -75,7 +75,6 @@ def get_workflow(
|
|
|
75
75
|
identifier: str,
|
|
76
76
|
project: str | None = None,
|
|
77
77
|
entity_id: str | None = None,
|
|
78
|
-
**kwargs,
|
|
79
78
|
) -> Workflow:
|
|
80
79
|
"""
|
|
81
80
|
Get object from backend.
|
|
@@ -88,8 +87,6 @@ def get_workflow(
|
|
|
88
87
|
Project name.
|
|
89
88
|
entity_id : str
|
|
90
89
|
Entity ID.
|
|
91
|
-
**kwargs : dict
|
|
92
|
-
Parameters to pass to the API call.
|
|
93
90
|
|
|
94
91
|
Returns
|
|
95
92
|
-------
|
|
@@ -107,18 +104,16 @@ def get_workflow(
|
|
|
107
104
|
>>> entity_id="my-workflow-id")
|
|
108
105
|
"""
|
|
109
106
|
return context_processor.read_context_entity(
|
|
110
|
-
identifier,
|
|
107
|
+
identifier=identifier,
|
|
111
108
|
entity_type=ENTITY_TYPE,
|
|
112
109
|
project=project,
|
|
113
110
|
entity_id=entity_id,
|
|
114
|
-
**kwargs,
|
|
115
111
|
)
|
|
116
112
|
|
|
117
113
|
|
|
118
114
|
def get_workflow_versions(
|
|
119
115
|
identifier: str,
|
|
120
116
|
project: str | None = None,
|
|
121
|
-
**kwargs,
|
|
122
117
|
) -> list[Workflow]:
|
|
123
118
|
"""
|
|
124
119
|
Get object versions from backend.
|
|
@@ -129,8 +124,6 @@ def get_workflow_versions(
|
|
|
129
124
|
Entity key (store://...) or entity name.
|
|
130
125
|
project : str
|
|
131
126
|
Project name.
|
|
132
|
-
**kwargs : dict
|
|
133
|
-
Parameters to pass to the API call.
|
|
134
127
|
|
|
135
128
|
Returns
|
|
136
129
|
-------
|
|
@@ -147,14 +140,23 @@ def get_workflow_versions(
|
|
|
147
140
|
>>> project="my-project")
|
|
148
141
|
"""
|
|
149
142
|
return context_processor.read_context_entity_versions(
|
|
150
|
-
identifier,
|
|
143
|
+
identifier=identifier,
|
|
151
144
|
entity_type=ENTITY_TYPE,
|
|
152
145
|
project=project,
|
|
153
|
-
**kwargs,
|
|
154
146
|
)
|
|
155
147
|
|
|
156
148
|
|
|
157
|
-
def list_workflows(
|
|
149
|
+
def list_workflows(
|
|
150
|
+
project: str,
|
|
151
|
+
q: str | None = None,
|
|
152
|
+
name: str | None = None,
|
|
153
|
+
kind: str | None = None,
|
|
154
|
+
user: str | None = None,
|
|
155
|
+
state: str | None = None,
|
|
156
|
+
created: str | None = None,
|
|
157
|
+
updated: str | None = None,
|
|
158
|
+
version: str | None = None,
|
|
159
|
+
) -> list[Workflow]:
|
|
158
160
|
"""
|
|
159
161
|
List all latest version objects from backend.
|
|
160
162
|
|
|
@@ -162,8 +164,22 @@ def list_workflows(project: str, **kwargs) -> list[Workflow]:
|
|
|
162
164
|
----------
|
|
163
165
|
project : str
|
|
164
166
|
Project name.
|
|
165
|
-
|
|
166
|
-
|
|
167
|
+
q : str
|
|
168
|
+
Query string to filter objects.
|
|
169
|
+
name : str
|
|
170
|
+
Object name.
|
|
171
|
+
kind : str
|
|
172
|
+
Kind of the object.
|
|
173
|
+
user : str
|
|
174
|
+
User that created the object.
|
|
175
|
+
state : str
|
|
176
|
+
Object state.
|
|
177
|
+
created : str
|
|
178
|
+
Creation date filter.
|
|
179
|
+
updated : str
|
|
180
|
+
Update date filter.
|
|
181
|
+
version : str
|
|
182
|
+
Object version, default is latest.
|
|
167
183
|
|
|
168
184
|
Returns
|
|
169
185
|
-------
|
|
@@ -177,7 +193,14 @@ def list_workflows(project: str, **kwargs) -> list[Workflow]:
|
|
|
177
193
|
return context_processor.list_context_entities(
|
|
178
194
|
project=project,
|
|
179
195
|
entity_type=ENTITY_TYPE,
|
|
180
|
-
|
|
196
|
+
q=q,
|
|
197
|
+
name=name,
|
|
198
|
+
kind=kind,
|
|
199
|
+
user=user,
|
|
200
|
+
state=state,
|
|
201
|
+
created=created,
|
|
202
|
+
updated=updated,
|
|
203
|
+
version=version,
|
|
181
204
|
)
|
|
182
205
|
|
|
183
206
|
|
|
@@ -280,7 +303,8 @@ def delete_workflow(
|
|
|
280
303
|
entity_id : str
|
|
281
304
|
Entity ID.
|
|
282
305
|
delete_all_versions : bool
|
|
283
|
-
Delete all versions of the named entity.
|
|
306
|
+
Delete all versions of the named entity.
|
|
307
|
+
If True, use entity name instead of entity key as identifier.
|
|
284
308
|
cascade : bool
|
|
285
309
|
Cascade delete.
|
|
286
310
|
**kwargs : dict
|
|
@@ -308,5 +332,4 @@ def delete_workflow(
|
|
|
308
332
|
entity_id=entity_id,
|
|
309
333
|
delete_all_versions=delete_all_versions,
|
|
310
334
|
cascade=cascade,
|
|
311
|
-
**kwargs,
|
|
312
335
|
)
|
|
@@ -0,0 +1,39 @@
|
|
|
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 ApiCategories(Enum):
|
|
11
|
+
"""
|
|
12
|
+
API categories.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
BASE = "base"
|
|
16
|
+
CONTEXT = "context"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class BackendOperations(Enum):
|
|
20
|
+
"""
|
|
21
|
+
Backend operations.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
CREATE = "create"
|
|
25
|
+
READ = "read"
|
|
26
|
+
READ_ALL_VERSIONS = "read_all_versions"
|
|
27
|
+
UPDATE = "update"
|
|
28
|
+
DELETE = "delete"
|
|
29
|
+
DELETE_ALL_VERSIONS = "delete_all_versions"
|
|
30
|
+
LIST = "list"
|
|
31
|
+
LIST_FIRST = "list_first"
|
|
32
|
+
STOP = "stop"
|
|
33
|
+
RESUME = "resume"
|
|
34
|
+
DATA = "data"
|
|
35
|
+
FILES = "files"
|
|
36
|
+
LOGS = "logs"
|
|
37
|
+
SEARCH = "search"
|
|
38
|
+
SHARE = "share"
|
|
39
|
+
METRICS = "metrics"
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
7
|
from abc import abstractmethod
|
|
8
|
+
from typing import Any
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
class ClientParametersBuilder:
|
|
@@ -32,3 +33,50 @@ class ClientParametersBuilder:
|
|
|
32
33
|
dict
|
|
33
34
|
The formatted parameters for the client call.
|
|
34
35
|
"""
|
|
36
|
+
|
|
37
|
+
@staticmethod
|
|
38
|
+
def _ensure_params(**kwargs) -> dict:
|
|
39
|
+
"""
|
|
40
|
+
Initialize parameter dictionary with query parameters structure.
|
|
41
|
+
|
|
42
|
+
Ensures parameter dictionary has 'params' key for HTTP query parameters,
|
|
43
|
+
guaranteeing consistent structure for all parameter building methods.
|
|
44
|
+
|
|
45
|
+
Parameters
|
|
46
|
+
----------
|
|
47
|
+
**kwargs : dict
|
|
48
|
+
Keyword arguments to format. May be empty or contain various
|
|
49
|
+
parameters for API operations.
|
|
50
|
+
|
|
51
|
+
Returns
|
|
52
|
+
-------
|
|
53
|
+
dict
|
|
54
|
+
Parameters dictionary with guaranteed 'params' key containing
|
|
55
|
+
empty dict if not already present.
|
|
56
|
+
"""
|
|
57
|
+
if "params" not in kwargs:
|
|
58
|
+
kwargs["params"] = {}
|
|
59
|
+
return kwargs
|
|
60
|
+
|
|
61
|
+
@staticmethod
|
|
62
|
+
def _add_param(key: str, value: Any | None, **kwargs) -> dict:
|
|
63
|
+
"""
|
|
64
|
+
Add a single query parameter to kwargs.
|
|
65
|
+
|
|
66
|
+
Parameters
|
|
67
|
+
----------
|
|
68
|
+
key : str
|
|
69
|
+
Parameter key.
|
|
70
|
+
value : Any
|
|
71
|
+
Parameter value.
|
|
72
|
+
**kwargs : dict
|
|
73
|
+
Keyword arguments to format. May be empty or contain various
|
|
74
|
+
parameters for API operations.
|
|
75
|
+
|
|
76
|
+
Returns
|
|
77
|
+
-------
|
|
78
|
+
dict
|
|
79
|
+
Parameters dictionary with added key-value pair in 'params'.
|
|
80
|
+
"""
|
|
81
|
+
kwargs["params"][key] = value
|
|
82
|
+
return kwargs
|
|
@@ -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.utils.exceptions import BackendError
|
|
10
10
|
|
|
11
11
|
API_BASE = "/api/v1"
|
|
@@ -100,6 +100,7 @@ class ClientDHCoreApiBuilder(ClientApiBuilder):
|
|
|
100
100
|
if operation in (
|
|
101
101
|
BackendOperations.CREATE.value,
|
|
102
102
|
BackendOperations.LIST.value,
|
|
103
|
+
BackendOperations.DELETE_ALL_VERSIONS.value,
|
|
103
104
|
):
|
|
104
105
|
return f"{API_CONTEXT}/{project}/{entity_type}"
|
|
105
106
|
elif operation in (
|
|
@@ -29,6 +29,9 @@ MAX_API_LEVEL = 20
|
|
|
29
29
|
MIN_API_LEVEL = 14
|
|
30
30
|
LIB_VERSION = 14
|
|
31
31
|
|
|
32
|
+
# Default timeout for requests (in seconds)
|
|
33
|
+
DEFAULT_TIMEOUT = 60
|
|
34
|
+
|
|
32
35
|
|
|
33
36
|
class ClientDHCore(Client):
|
|
34
37
|
"""
|
|
@@ -73,13 +76,13 @@ class ClientDHCore(Client):
|
|
|
73
76
|
super().__init__()
|
|
74
77
|
|
|
75
78
|
# API builder
|
|
76
|
-
self._api_builder = ClientDHCoreApiBuilder()
|
|
79
|
+
self._api_builder: ClientDHCoreApiBuilder = ClientDHCoreApiBuilder()
|
|
77
80
|
|
|
78
81
|
# Key builder
|
|
79
|
-
self._key_builder = ClientDHCoreKeyBuilder()
|
|
82
|
+
self._key_builder: ClientDHCoreKeyBuilder = ClientDHCoreKeyBuilder()
|
|
80
83
|
|
|
81
84
|
# Parameters builder
|
|
82
|
-
self._params_builder = ClientDHCoreParametersBuilder()
|
|
85
|
+
self._params_builder: ClientDHCoreParametersBuilder = ClientDHCoreParametersBuilder()
|
|
83
86
|
|
|
84
87
|
# Error parser
|
|
85
88
|
self._error_parser = ErrorParser()
|
|
@@ -118,9 +121,7 @@ class ClientDHCore(Client):
|
|
|
118
121
|
ClientError
|
|
119
122
|
If there are client-side configuration issues.
|
|
120
123
|
"""
|
|
121
|
-
|
|
122
|
-
kwargs["headers"] = {}
|
|
123
|
-
kwargs["headers"]["Content-Type"] = "application/json"
|
|
124
|
+
kwargs = self._set_application_json_header(**kwargs)
|
|
124
125
|
kwargs["data"] = dump_json(obj)
|
|
125
126
|
return self._prepare_call("POST", api, **kwargs)
|
|
126
127
|
|
|
@@ -178,9 +179,7 @@ class ClientDHCore(Client):
|
|
|
178
179
|
EntityNotExistsError
|
|
179
180
|
If the object to update does not exist.
|
|
180
181
|
"""
|
|
181
|
-
|
|
182
|
-
kwargs["headers"] = {}
|
|
183
|
-
kwargs["headers"]["Content-Type"] = "application/json"
|
|
182
|
+
kwargs = self._set_application_json_header(**kwargs)
|
|
184
183
|
kwargs["data"] = dump_json(obj)
|
|
185
184
|
return self._prepare_call("PUT", api, **kwargs)
|
|
186
185
|
|
|
@@ -240,22 +239,17 @@ class ClientDHCore(Client):
|
|
|
240
239
|
BackendError
|
|
241
240
|
If the backend returns an error response.
|
|
242
241
|
"""
|
|
243
|
-
|
|
244
|
-
kwargs["params"] = {}
|
|
245
|
-
|
|
246
|
-
start_page = 0
|
|
247
|
-
if "page" not in kwargs["params"]:
|
|
248
|
-
kwargs["params"]["page"] = start_page
|
|
242
|
+
kwargs = self._params_builder.set_pagination(partial=True, **kwargs)
|
|
249
243
|
|
|
250
244
|
objects = []
|
|
251
245
|
while True:
|
|
252
246
|
resp = self._prepare_call("GET", api, **kwargs)
|
|
253
247
|
contents = resp["content"]
|
|
254
248
|
total_pages = resp["totalPages"]
|
|
255
|
-
if not contents or kwargs["params"]["page"] >= total_pages:
|
|
256
|
-
break
|
|
257
249
|
objects.extend(contents)
|
|
258
|
-
kwargs
|
|
250
|
+
if not contents or self._params_builder.read_page_number(**kwargs) >= (total_pages - 1):
|
|
251
|
+
break
|
|
252
|
+
self._params_builder.increment_page_number(**kwargs)
|
|
259
253
|
|
|
260
254
|
return objects
|
|
261
255
|
|
|
@@ -314,29 +308,16 @@ class ClientDHCore(Client):
|
|
|
314
308
|
BackendError
|
|
315
309
|
If the backend returns an error response.
|
|
316
310
|
"""
|
|
317
|
-
|
|
318
|
-
kwargs["params"] = {}
|
|
319
|
-
|
|
320
|
-
start_page = 0
|
|
321
|
-
if "page" not in kwargs["params"]:
|
|
322
|
-
kwargs["params"]["page"] = start_page
|
|
323
|
-
|
|
324
|
-
if "size" not in kwargs["params"]:
|
|
325
|
-
kwargs["params"]["size"] = 10
|
|
326
|
-
|
|
327
|
-
# Add sorting
|
|
328
|
-
if "sort" not in kwargs["params"]:
|
|
329
|
-
kwargs["params"]["sort"] = "metadata.updated,DESC"
|
|
330
|
-
|
|
311
|
+
kwargs = self._params_builder.set_pagination(**kwargs)
|
|
331
312
|
objects_with_highlights: list[dict] = []
|
|
332
313
|
while True:
|
|
333
314
|
resp = self._prepare_call("GET", api, **kwargs)
|
|
334
315
|
contents = resp["content"]
|
|
335
316
|
total_pages = resp["totalPages"]
|
|
336
|
-
if not contents or kwargs["params"]["page"] >= total_pages:
|
|
337
|
-
break
|
|
338
317
|
objects_with_highlights.extend(contents)
|
|
339
|
-
kwargs
|
|
318
|
+
if not contents or self._params_builder.read_page_number(**kwargs) >= (total_pages - 1):
|
|
319
|
+
break
|
|
320
|
+
self._params_builder.increment_page_number(**kwargs)
|
|
340
321
|
|
|
341
322
|
objects = []
|
|
342
323
|
for obj in objects_with_highlights:
|
|
@@ -381,25 +362,6 @@ class ClientDHCore(Client):
|
|
|
381
362
|
full_kwargs = self._configurator.get_auth_parameters(kwargs)
|
|
382
363
|
return self._make_call(call_type, url, **full_kwargs)
|
|
383
364
|
|
|
384
|
-
def _build_url(self, api: str) -> str:
|
|
385
|
-
"""
|
|
386
|
-
Build the complete URL for an API call.
|
|
387
|
-
|
|
388
|
-
Combines the configured endpoint with the API path to create
|
|
389
|
-
the full URL for the HTTP request. Automatically removes leading
|
|
390
|
-
slashes from the API path to ensure proper URL construction.
|
|
391
|
-
|
|
392
|
-
Parameters
|
|
393
|
-
----------
|
|
394
|
-
api : str
|
|
395
|
-
The API endpoint path. Leading slashes are automatically handled.
|
|
396
|
-
|
|
397
|
-
Returns
|
|
398
|
-
-------
|
|
399
|
-
str
|
|
400
|
-
The complete URL for the API call.
|
|
401
|
-
"""
|
|
402
|
-
|
|
403
365
|
def _build_url(self, api: str) -> str:
|
|
404
366
|
"""
|
|
405
367
|
Build complete URL for API call.
|
|
@@ -454,7 +416,7 @@ class ClientDHCore(Client):
|
|
|
454
416
|
If authentication fails and token refresh not possible.
|
|
455
417
|
"""
|
|
456
418
|
# Call the API
|
|
457
|
-
response = request(call_type, url, timeout=
|
|
419
|
+
response = request(call_type, url, timeout=DEFAULT_TIMEOUT, **kwargs)
|
|
458
420
|
|
|
459
421
|
# Evaluate DHCore API version
|
|
460
422
|
self._check_core_version(response)
|
|
@@ -539,3 +501,53 @@ class ClientDHCore(Client):
|
|
|
539
501
|
False, indicating this client communicates with remote DHCore backend.
|
|
540
502
|
"""
|
|
541
503
|
return False
|
|
504
|
+
|
|
505
|
+
##############################
|
|
506
|
+
# Utility methods
|
|
507
|
+
##############################
|
|
508
|
+
|
|
509
|
+
@staticmethod
|
|
510
|
+
def _ensure_header(**kwargs) -> dict:
|
|
511
|
+
"""
|
|
512
|
+
Initialize header dictionary.
|
|
513
|
+
|
|
514
|
+
Ensures parameter dictionary has 'headers' key for HTTP headers,
|
|
515
|
+
guaranteeing consistent structure for all parameter building methods.
|
|
516
|
+
|
|
517
|
+
Parameters
|
|
518
|
+
----------
|
|
519
|
+
**kwargs : dict
|
|
520
|
+
Keyword arguments to format. May be empty or contain various
|
|
521
|
+
parameters for API operations.
|
|
522
|
+
|
|
523
|
+
Returns
|
|
524
|
+
-------
|
|
525
|
+
dict
|
|
526
|
+
Headers dictionary with guaranteed 'headers' key containing
|
|
527
|
+
empty dict if not already present.
|
|
528
|
+
"""
|
|
529
|
+
if "headers" not in kwargs:
|
|
530
|
+
kwargs["headers"] = {}
|
|
531
|
+
return kwargs
|
|
532
|
+
|
|
533
|
+
def _set_application_json_header(self, **kwargs) -> dict:
|
|
534
|
+
"""
|
|
535
|
+
Set Content-Type header to application/json.
|
|
536
|
+
|
|
537
|
+
Ensures that the 'Content-Type' header is set to 'application/json'
|
|
538
|
+
for requests that require JSON payloads.
|
|
539
|
+
|
|
540
|
+
Parameters
|
|
541
|
+
----------
|
|
542
|
+
**kwargs : dict
|
|
543
|
+
Keyword arguments to format. May be empty or contain various
|
|
544
|
+
parameters for API operations.
|
|
545
|
+
|
|
546
|
+
Returns
|
|
547
|
+
-------
|
|
548
|
+
dict
|
|
549
|
+
Headers dictionary with 'Content-Type' set to 'application/json'.
|
|
550
|
+
"""
|
|
551
|
+
kwargs = self._ensure_header(**kwargs)
|
|
552
|
+
kwargs["headers"]["Content-Type"] = "application/json"
|
|
553
|
+
return kwargs
|