digitalhub 0.13.3__py3-none-any.whl → 0.14.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.
- digitalhub/__init__.py +3 -8
- digitalhub/context/api.py +1 -5
- digitalhub/context/builder.py +1 -5
- digitalhub/context/context.py +15 -9
- digitalhub/entities/_base/_base/entity.py +0 -15
- digitalhub/entities/_base/context/entity.py +1 -1
- digitalhub/entities/_base/entity/builder.py +5 -5
- digitalhub/entities/_base/entity/entity.py +0 -8
- digitalhub/entities/_base/executable/entity.py +169 -79
- digitalhub/entities/_base/material/entity.py +6 -22
- digitalhub/entities/_base/material/utils.py +1 -4
- digitalhub/entities/_base/runtime_entity/builder.py +53 -18
- digitalhub/entities/_base/unversioned/entity.py +1 -1
- digitalhub/entities/_base/versioned/entity.py +1 -1
- digitalhub/entities/_commons/enums.py +1 -31
- digitalhub/entities/_commons/utils.py +83 -21
- digitalhub/entities/_constructors/_resources.py +151 -0
- digitalhub/entities/{_base/entity/_constructors → _constructors}/name.py +18 -0
- digitalhub/entities/_processors/base/__init__.py +3 -0
- digitalhub/entities/_processors/{base.py → base/crud.py} +14 -226
- digitalhub/entities/_processors/base/import_export.py +123 -0
- digitalhub/entities/_processors/base/processor.py +302 -0
- digitalhub/entities/_processors/base/special_ops.py +108 -0
- digitalhub/entities/_processors/context/__init__.py +3 -0
- digitalhub/entities/_processors/context/crud.py +652 -0
- digitalhub/entities/_processors/context/import_export.py +242 -0
- digitalhub/entities/_processors/context/material.py +123 -0
- digitalhub/entities/_processors/context/processor.py +400 -0
- digitalhub/entities/_processors/context/special_ops.py +476 -0
- digitalhub/entities/_processors/processors.py +12 -0
- digitalhub/entities/_processors/utils.py +12 -11
- digitalhub/entities/artifact/crud.py +58 -22
- digitalhub/entities/artifact/utils.py +3 -3
- digitalhub/entities/dataitem/crud.py +63 -20
- digitalhub/entities/dataitem/table/entity.py +24 -22
- digitalhub/entities/dataitem/utils.py +15 -15
- digitalhub/entities/function/_base/entity.py +3 -3
- digitalhub/entities/function/crud.py +55 -24
- digitalhub/entities/model/_base/entity.py +62 -20
- digitalhub/entities/model/crud.py +58 -22
- digitalhub/entities/model/utils.py +3 -3
- digitalhub/entities/project/_base/entity.py +321 -152
- digitalhub/entities/project/crud.py +15 -23
- digitalhub/entities/run/_base/builder.py +0 -4
- digitalhub/entities/run/_base/entity.py +70 -63
- digitalhub/entities/run/crud.py +79 -26
- digitalhub/entities/secret/_base/entity.py +1 -5
- digitalhub/entities/secret/crud.py +29 -26
- digitalhub/entities/task/_base/builder.py +0 -4
- digitalhub/entities/task/_base/entity.py +5 -5
- digitalhub/entities/task/_base/models.py +13 -16
- digitalhub/entities/task/crud.py +61 -29
- digitalhub/entities/trigger/_base/entity.py +1 -5
- digitalhub/entities/trigger/crud.py +64 -24
- digitalhub/entities/workflow/_base/entity.py +3 -3
- digitalhub/entities/workflow/crud.py +55 -21
- digitalhub/factory/entity.py +283 -0
- digitalhub/factory/enums.py +18 -0
- digitalhub/factory/registry.py +197 -0
- digitalhub/factory/runtime.py +44 -0
- digitalhub/factory/utils.py +3 -54
- digitalhub/runtimes/_base.py +2 -2
- digitalhub/stores/client/_base/enums.py +39 -0
- digitalhub/stores/client/_base/key_builder.py +2 -2
- digitalhub/stores/client/_base/params_builder.py +48 -0
- digitalhub/stores/client/api.py +6 -10
- digitalhub/stores/client/builder.py +4 -4
- digitalhub/stores/client/dhcore/api_builder.py +2 -1
- digitalhub/stores/client/dhcore/client.py +85 -429
- digitalhub/stores/client/dhcore/configurator.py +109 -328
- digitalhub/stores/client/dhcore/enums.py +0 -16
- digitalhub/stores/client/dhcore/error_parser.py +0 -4
- digitalhub/stores/client/dhcore/header_manager.py +61 -0
- digitalhub/stores/client/dhcore/http_handler.py +133 -0
- digitalhub/stores/client/dhcore/params_builder.py +147 -134
- digitalhub/stores/client/dhcore/response_processor.py +102 -0
- digitalhub/stores/client/dhcore/utils.py +6 -72
- digitalhub/stores/client/local/api_builder.py +1 -1
- digitalhub/stores/client/local/client.py +79 -47
- digitalhub/stores/client/local/params_builder.py +18 -41
- digitalhub/stores/credentials/api.py +0 -4
- digitalhub/stores/credentials/configurator.py +2 -28
- digitalhub/stores/credentials/enums.py +3 -0
- digitalhub/stores/credentials/handler.py +0 -12
- digitalhub/stores/credentials/ini_module.py +0 -22
- digitalhub/stores/credentials/store.py +0 -4
- digitalhub/stores/data/_base/store.py +0 -16
- digitalhub/stores/data/builder.py +1 -5
- digitalhub/stores/data/local/store.py +0 -103
- digitalhub/stores/data/remote/store.py +0 -4
- digitalhub/stores/data/s3/configurator.py +60 -14
- digitalhub/stores/data/s3/store.py +49 -16
- digitalhub/stores/data/sql/configurator.py +0 -8
- digitalhub/stores/data/sql/store.py +21 -10
- digitalhub/stores/readers/data/factory.py +0 -8
- digitalhub/stores/readers/data/pandas/reader.py +0 -16
- digitalhub/utils/file_utils.py +0 -17
- digitalhub/utils/generic_utils.py +0 -12
- digitalhub/utils/git_utils.py +0 -8
- digitalhub/utils/io_utils.py +0 -12
- digitalhub/utils/store_utils.py +44 -0
- {digitalhub-0.13.3.dist-info → digitalhub-0.14.0.dist-info}/METADATA +3 -2
- {digitalhub-0.13.3.dist-info → digitalhub-0.14.0.dist-info}/RECORD +111 -95
- digitalhub/entities/_processors/context.py +0 -1450
- digitalhub/entities/task/_base/utils.py +0 -22
- digitalhub/factory/factory.py +0 -381
- digitalhub/stores/client/dhcore/models.py +0 -40
- digitalhub/stores/data/s3/utils.py +0 -78
- /digitalhub/entities/{_base/entity/_constructors → _constructors}/__init__.py +0 -0
- /digitalhub/entities/{_base/entity/_constructors → _constructors}/metadata.py +0 -0
- /digitalhub/entities/{_base/entity/_constructors → _constructors}/spec.py +0 -0
- /digitalhub/entities/{_base/entity/_constructors → _constructors}/status.py +0 -0
- /digitalhub/entities/{_base/entity/_constructors → _constructors}/uuid.py +0 -0
- {digitalhub-0.13.3.dist-info → digitalhub-0.14.0.dist-info}/WHEEL +0 -0
- {digitalhub-0.13.3.dist-info → digitalhub-0.14.0.dist-info}/licenses/AUTHORS +0 -0
- {digitalhub-0.13.3.dist-info → digitalhub-0.14.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -4,120 +4,39 @@
|
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
|
-
import typing
|
|
8
7
|
from typing import Any
|
|
9
|
-
from warnings import warn
|
|
10
|
-
|
|
11
|
-
from requests import request
|
|
12
|
-
from requests.exceptions import JSONDecodeError
|
|
13
8
|
|
|
14
9
|
from digitalhub.stores.client._base.client import Client
|
|
15
10
|
from digitalhub.stores.client.dhcore.api_builder import ClientDHCoreApiBuilder
|
|
16
|
-
from digitalhub.stores.client.dhcore.
|
|
17
|
-
from digitalhub.stores.client.dhcore.
|
|
11
|
+
from digitalhub.stores.client.dhcore.header_manager import HeaderManager
|
|
12
|
+
from digitalhub.stores.client.dhcore.http_handler import HttpRequestHandler
|
|
18
13
|
from digitalhub.stores.client.dhcore.key_builder import ClientDHCoreKeyBuilder
|
|
19
14
|
from digitalhub.stores.client.dhcore.params_builder import ClientDHCoreParametersBuilder
|
|
20
|
-
from digitalhub.utils.exceptions import BackendError
|
|
15
|
+
from digitalhub.utils.exceptions import BackendError
|
|
21
16
|
from digitalhub.utils.generic_utils import dump_json
|
|
22
17
|
|
|
23
|
-
if typing.TYPE_CHECKING:
|
|
24
|
-
from requests import Response
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
# API levels that are supported
|
|
28
|
-
MAX_API_LEVEL = 20
|
|
29
|
-
MIN_API_LEVEL = 13
|
|
30
|
-
LIB_VERSION = 13
|
|
31
|
-
|
|
32
18
|
|
|
33
19
|
class ClientDHCore(Client):
|
|
34
20
|
"""
|
|
35
21
|
DHCore client for remote DigitalHub Core backend communication.
|
|
36
22
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
At initialization, the client attempts to load endpoint and authentication
|
|
44
|
-
parameters from environment variables and the .dhcore configuration file.
|
|
45
|
-
If authentication or endpoint errors occur during client creation, users
|
|
46
|
-
can update the configuration using the `set_dhcore_env` function from
|
|
47
|
-
the utils module.
|
|
48
|
-
|
|
49
|
-
The client automatically handles:
|
|
50
|
-
- API version compatibility checking
|
|
51
|
-
- Pagination for list operations
|
|
52
|
-
- Token refresh on authentication errors
|
|
53
|
-
- Error parsing and exception mapping
|
|
54
|
-
- JSON serialization/deserialization
|
|
55
|
-
|
|
56
|
-
Parameters
|
|
57
|
-
----------
|
|
58
|
-
config : dict, optional
|
|
59
|
-
DHCore environment configuration. If None, configuration will
|
|
60
|
-
be loaded from environment variables and configuration files.
|
|
61
|
-
|
|
62
|
-
Attributes
|
|
63
|
-
----------
|
|
64
|
-
_api_builder : ClientDHCoreApiBuilder
|
|
65
|
-
Builds API endpoint URLs for different operations.
|
|
66
|
-
_key_builder : ClientDHCoreKeyBuilder
|
|
67
|
-
Builds storage keys for entities.
|
|
68
|
-
_params_builder : ClientDHCoreParametersBuilder
|
|
69
|
-
Builds request parameters for API calls.
|
|
70
|
-
_error_parser : ErrorParser
|
|
71
|
-
Parses backend responses and raises appropriate exceptions.
|
|
72
|
-
_configurator : ClientDHCoreConfigurator
|
|
73
|
-
Manages client configuration and authentication.
|
|
74
|
-
|
|
75
|
-
Notes
|
|
76
|
-
-----
|
|
77
|
-
Supported DHCore API versions: {MIN_API_LEVEL} to {MAX_API_LEVEL}
|
|
78
|
-
Current library API version: {LIB_VERSION}
|
|
79
|
-
|
|
80
|
-
Examples
|
|
81
|
-
--------
|
|
82
|
-
>>> from digitalhub.stores.client.api import get_client
|
|
83
|
-
>>> client = get_client(local=False)
|
|
84
|
-
>>> # Client is now ready for API operations
|
|
23
|
+
Provides REST API communication with DigitalHub Core backend supporting
|
|
24
|
+
multiple authentication methods: Basic (username/password), OAuth2 (token
|
|
25
|
+
with refresh), and Personal Access Token exchange. Automatically handles
|
|
26
|
+
API version compatibility, pagination, token refresh, error parsing, and
|
|
27
|
+
JSON serialization.
|
|
85
28
|
"""
|
|
86
29
|
|
|
87
30
|
def __init__(self, config: dict | None = None) -> None:
|
|
88
|
-
"""
|
|
89
|
-
Initialize DHCore client.
|
|
90
|
-
|
|
91
|
-
Creates a new DHCore client instance with all necessary components
|
|
92
|
-
for communicating with the DigitalHub Core backend. Sets up API
|
|
93
|
-
builders, configurators, and error handling.
|
|
94
|
-
|
|
95
|
-
Parameters
|
|
96
|
-
----------
|
|
97
|
-
config : dict, optional
|
|
98
|
-
DHCore environment configuration. If None, configuration will
|
|
99
|
-
be loaded from environment variables and configuration files.
|
|
100
|
-
|
|
101
|
-
Returns
|
|
102
|
-
-------
|
|
103
|
-
None
|
|
104
|
-
"""
|
|
105
31
|
super().__init__()
|
|
106
32
|
|
|
107
|
-
# API
|
|
108
|
-
self._api_builder = ClientDHCoreApiBuilder()
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
self._key_builder = ClientDHCoreKeyBuilder()
|
|
112
|
-
|
|
113
|
-
# Parameters builder
|
|
114
|
-
self._params_builder = ClientDHCoreParametersBuilder()
|
|
33
|
+
# API, key and parameters builders
|
|
34
|
+
self._api_builder: ClientDHCoreApiBuilder = ClientDHCoreApiBuilder()
|
|
35
|
+
self._key_builder: ClientDHCoreKeyBuilder = ClientDHCoreKeyBuilder()
|
|
36
|
+
self._params_builder: ClientDHCoreParametersBuilder = ClientDHCoreParametersBuilder()
|
|
115
37
|
|
|
116
|
-
#
|
|
117
|
-
self.
|
|
118
|
-
|
|
119
|
-
# Client Configurator
|
|
120
|
-
self._configurator = ClientDHCoreConfigurator()
|
|
38
|
+
# HTTP request handling
|
|
39
|
+
self._http_handler = HttpRequestHandler()
|
|
121
40
|
|
|
122
41
|
##############################
|
|
123
42
|
# CRUD methods
|
|
@@ -125,39 +44,27 @@ class ClientDHCore(Client):
|
|
|
125
44
|
|
|
126
45
|
def create_object(self, api: str, obj: Any, **kwargs) -> dict:
|
|
127
46
|
"""
|
|
128
|
-
Create an object in DHCore.
|
|
47
|
+
Create an object in DHCore via POST request.
|
|
129
48
|
|
|
130
|
-
|
|
131
|
-
Automatically sets the appropriate Content-Type header and serializes
|
|
132
|
-
the object to JSON format.
|
|
49
|
+
Automatically sets Content-Type header and serializes object to JSON.
|
|
133
50
|
|
|
134
51
|
Parameters
|
|
135
52
|
----------
|
|
136
53
|
api : str
|
|
137
|
-
|
|
54
|
+
API endpoint path for creating the object.
|
|
138
55
|
obj : Any
|
|
139
|
-
|
|
56
|
+
Object to create. Will be serialized to JSON.
|
|
140
57
|
**kwargs : dict
|
|
141
|
-
Additional
|
|
142
|
-
such as headers, params, etc.
|
|
58
|
+
Additional HTTP request arguments.
|
|
143
59
|
|
|
144
60
|
Returns
|
|
145
61
|
-------
|
|
146
62
|
dict
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
Raises
|
|
150
|
-
------
|
|
151
|
-
BackendError
|
|
152
|
-
If the backend returns an error response.
|
|
153
|
-
ClientError
|
|
154
|
-
If there are client-side configuration issues.
|
|
63
|
+
Created object as returned by the backend.
|
|
155
64
|
"""
|
|
156
|
-
|
|
157
|
-
kwargs["headers"] = {}
|
|
158
|
-
kwargs["headers"]["Content-Type"] = "application/json"
|
|
65
|
+
kwargs = HeaderManager.set_json_content_type(**kwargs)
|
|
159
66
|
kwargs["data"] = dump_json(obj)
|
|
160
|
-
return self.
|
|
67
|
+
return self._http_handler.prepare_request("POST", api, **kwargs)
|
|
161
68
|
|
|
162
69
|
def read_object(self, api: str, **kwargs) -> dict:
|
|
163
70
|
"""
|
|
@@ -168,15 +75,14 @@ class ClientDHCore(Client):
|
|
|
168
75
|
Parameters
|
|
169
76
|
----------
|
|
170
77
|
api : str
|
|
171
|
-
|
|
78
|
+
API endpoint path for reading the object.
|
|
172
79
|
**kwargs : dict
|
|
173
|
-
Additional
|
|
174
|
-
such as headers, params, etc.
|
|
80
|
+
Additional HTTP request arguments.
|
|
175
81
|
|
|
176
82
|
Returns
|
|
177
83
|
-------
|
|
178
84
|
dict
|
|
179
|
-
|
|
85
|
+
Retrieved object as returned by the backend.
|
|
180
86
|
|
|
181
87
|
Raises
|
|
182
88
|
------
|
|
@@ -185,151 +91,108 @@ class ClientDHCore(Client):
|
|
|
185
91
|
EntityNotExistsError
|
|
186
92
|
If the requested object does not exist.
|
|
187
93
|
"""
|
|
188
|
-
return self.
|
|
94
|
+
return self._http_handler.prepare_request("GET", api, **kwargs)
|
|
189
95
|
|
|
190
96
|
def update_object(self, api: str, obj: Any, **kwargs) -> dict:
|
|
191
97
|
"""
|
|
192
|
-
Update an object in DHCore.
|
|
98
|
+
Update an object in DHCore via PUT request.
|
|
193
99
|
|
|
194
|
-
|
|
195
|
-
Automatically sets the appropriate Content-Type header and serializes
|
|
196
|
-
the object to JSON format.
|
|
100
|
+
Automatically sets Content-Type header and serializes object to JSON.
|
|
197
101
|
|
|
198
102
|
Parameters
|
|
199
103
|
----------
|
|
200
104
|
api : str
|
|
201
|
-
|
|
105
|
+
API endpoint path for updating the object.
|
|
202
106
|
obj : Any
|
|
203
|
-
|
|
107
|
+
Updated object data. Will be serialized to JSON.
|
|
204
108
|
**kwargs : dict
|
|
205
|
-
Additional
|
|
206
|
-
such as headers, params, etc.
|
|
109
|
+
Additional HTTP request arguments.
|
|
207
110
|
|
|
208
111
|
Returns
|
|
209
112
|
-------
|
|
210
113
|
dict
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
Raises
|
|
214
|
-
------
|
|
215
|
-
BackendError
|
|
216
|
-
If the backend returns an error response.
|
|
217
|
-
EntityNotExistsError
|
|
218
|
-
If the object to update does not exist.
|
|
114
|
+
Updated object as returned by the backend.
|
|
219
115
|
"""
|
|
220
|
-
|
|
221
|
-
kwargs["headers"] = {}
|
|
222
|
-
kwargs["headers"]["Content-Type"] = "application/json"
|
|
116
|
+
kwargs = HeaderManager.set_json_content_type(**kwargs)
|
|
223
117
|
kwargs["data"] = dump_json(obj)
|
|
224
|
-
return self.
|
|
118
|
+
return self._http_handler.prepare_request("PUT", api, **kwargs)
|
|
225
119
|
|
|
226
120
|
def delete_object(self, api: str, **kwargs) -> dict:
|
|
227
121
|
"""
|
|
228
122
|
Delete an object from DHCore.
|
|
229
123
|
|
|
230
|
-
Sends
|
|
231
|
-
|
|
232
|
-
a dictionary with a "deleted" key.
|
|
124
|
+
Sends DELETE request to remove an object. Wraps boolean responses
|
|
125
|
+
in {"deleted": True/False} dictionary.
|
|
233
126
|
|
|
234
127
|
Parameters
|
|
235
128
|
----------
|
|
236
129
|
api : str
|
|
237
|
-
|
|
130
|
+
API endpoint path for deleting the object.
|
|
238
131
|
**kwargs : dict
|
|
239
|
-
Additional
|
|
240
|
-
such as headers, params, cascade options, etc.
|
|
132
|
+
Additional HTTP request arguments.
|
|
241
133
|
|
|
242
134
|
Returns
|
|
243
135
|
-------
|
|
244
136
|
dict
|
|
245
|
-
|
|
246
|
-
{"deleted": True/False} if backend returns a boolean.
|
|
247
|
-
|
|
248
|
-
Raises
|
|
249
|
-
------
|
|
250
|
-
BackendError
|
|
251
|
-
If the backend returns an error response.
|
|
252
|
-
EntityNotExistsError
|
|
253
|
-
If the object to delete does not exist.
|
|
137
|
+
Deletion result from backend or {"deleted": bool} wrapper.
|
|
254
138
|
"""
|
|
255
|
-
resp = self.
|
|
139
|
+
resp = self._http_handler.prepare_request("DELETE", api, **kwargs)
|
|
256
140
|
if isinstance(resp, bool):
|
|
257
141
|
resp = {"deleted": resp}
|
|
258
142
|
return resp
|
|
259
143
|
|
|
260
144
|
def list_objects(self, api: str, **kwargs) -> list[dict]:
|
|
261
145
|
"""
|
|
262
|
-
List objects from DHCore.
|
|
146
|
+
List objects from DHCore with automatic pagination.
|
|
263
147
|
|
|
264
|
-
Sends GET requests to
|
|
265
|
-
|
|
266
|
-
until all objects are retrieved.
|
|
148
|
+
Sends GET requests to retrieve paginated objects, automatically handling
|
|
149
|
+
pagination (starting from page 0) until all objects are retrieved.
|
|
267
150
|
|
|
268
151
|
Parameters
|
|
269
152
|
----------
|
|
270
153
|
api : str
|
|
271
|
-
|
|
154
|
+
API endpoint path for listing objects.
|
|
272
155
|
**kwargs : dict
|
|
273
|
-
Additional
|
|
274
|
-
|
|
156
|
+
Additional HTTP request arguments. Can include 'params' dict
|
|
157
|
+
with pagination parameters.
|
|
275
158
|
|
|
276
159
|
Returns
|
|
277
160
|
-------
|
|
278
161
|
list[dict]
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
Raises
|
|
282
|
-
------
|
|
283
|
-
BackendError
|
|
284
|
-
If the backend returns an error response.
|
|
285
|
-
|
|
286
|
-
Notes
|
|
287
|
-
-----
|
|
288
|
-
This method automatically handles pagination starting from page 0
|
|
289
|
-
and continues until all pages are retrieved.
|
|
162
|
+
List containing all objects from all pages.
|
|
290
163
|
"""
|
|
291
|
-
|
|
292
|
-
kwargs["params"] = {}
|
|
293
|
-
|
|
294
|
-
start_page = 0
|
|
295
|
-
if "page" not in kwargs["params"]:
|
|
296
|
-
kwargs["params"]["page"] = start_page
|
|
164
|
+
kwargs = self._params_builder.set_pagination(partial=True, **kwargs)
|
|
297
165
|
|
|
298
166
|
objects = []
|
|
299
167
|
while True:
|
|
300
|
-
resp = self.
|
|
168
|
+
resp = self._http_handler.prepare_request("GET", api, **kwargs)
|
|
301
169
|
contents = resp["content"]
|
|
302
170
|
total_pages = resp["totalPages"]
|
|
303
|
-
if not contents or kwargs["params"]["page"] >= total_pages:
|
|
304
|
-
break
|
|
305
171
|
objects.extend(contents)
|
|
306
|
-
kwargs
|
|
172
|
+
if not contents or self._params_builder.read_page_number(**kwargs) >= (total_pages - 1):
|
|
173
|
+
break
|
|
174
|
+
self._params_builder.increment_page_number(**kwargs)
|
|
307
175
|
|
|
308
176
|
return objects
|
|
309
177
|
|
|
310
178
|
def list_first_object(self, api: str, **kwargs) -> dict:
|
|
311
179
|
"""
|
|
312
|
-
Get the first object from a list
|
|
180
|
+
Get the first object from a DHCore list.
|
|
313
181
|
|
|
314
|
-
Retrieves the first object
|
|
315
|
-
|
|
182
|
+
Retrieves the first object by calling list_objects and returning
|
|
183
|
+
the first item.
|
|
316
184
|
|
|
317
185
|
Parameters
|
|
318
186
|
----------
|
|
319
187
|
api : str
|
|
320
|
-
|
|
188
|
+
API endpoint path for listing objects.
|
|
321
189
|
**kwargs : dict
|
|
322
|
-
Additional
|
|
190
|
+
Additional HTTP request arguments.
|
|
323
191
|
|
|
324
192
|
Returns
|
|
325
193
|
-------
|
|
326
194
|
dict
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
Raises
|
|
330
|
-
------
|
|
331
|
-
BackendError
|
|
332
|
-
If no objects are found or if the backend returns an error.
|
|
195
|
+
First object from the list.
|
|
333
196
|
"""
|
|
334
197
|
try:
|
|
335
198
|
return self.list_objects(api, **kwargs)[0]
|
|
@@ -338,60 +201,35 @@ class ClientDHCore(Client):
|
|
|
338
201
|
|
|
339
202
|
def search_objects(self, api: str, **kwargs) -> list[dict]:
|
|
340
203
|
"""
|
|
341
|
-
Search objects from DHCore.
|
|
204
|
+
Search objects from DHCore using Solr capabilities.
|
|
342
205
|
|
|
343
|
-
Performs
|
|
344
|
-
|
|
345
|
-
|
|
206
|
+
Performs search query with pagination and removes search highlights.
|
|
207
|
+
Sets default pagination (page=0, size=10) and sorting (metadata.updated DESC)
|
|
208
|
+
if not provided.
|
|
346
209
|
|
|
347
210
|
Parameters
|
|
348
211
|
----------
|
|
349
212
|
api : str
|
|
350
|
-
|
|
213
|
+
API endpoint path for searching objects (usually Solr search).
|
|
351
214
|
**kwargs : dict
|
|
352
|
-
Additional
|
|
353
|
-
|
|
215
|
+
Additional HTTP request arguments including search parameters,
|
|
216
|
+
filters, and pagination options.
|
|
354
217
|
|
|
355
218
|
Returns
|
|
356
219
|
-------
|
|
357
220
|
list[dict]
|
|
358
|
-
|
|
359
|
-
highlights removed.
|
|
360
|
-
|
|
361
|
-
Raises
|
|
362
|
-
------
|
|
363
|
-
BackendError
|
|
364
|
-
If the backend returns an error response.
|
|
365
|
-
|
|
366
|
-
Notes
|
|
367
|
-
-----
|
|
368
|
-
This method sets default values for pagination (page=0, size=10)
|
|
369
|
-
and sorting (by metadata.updated descending) if not provided.
|
|
370
|
-
Search highlights are automatically removed from results.
|
|
221
|
+
List of matching objects with search highlights removed.
|
|
371
222
|
"""
|
|
372
|
-
|
|
373
|
-
kwargs["params"] = {}
|
|
374
|
-
|
|
375
|
-
start_page = 0
|
|
376
|
-
if "page" not in kwargs["params"]:
|
|
377
|
-
kwargs["params"]["page"] = start_page
|
|
378
|
-
|
|
379
|
-
if "size" not in kwargs["params"]:
|
|
380
|
-
kwargs["params"]["size"] = 10
|
|
381
|
-
|
|
382
|
-
# Add sorting
|
|
383
|
-
if "sort" not in kwargs["params"]:
|
|
384
|
-
kwargs["params"]["sort"] = "metadata.updated,DESC"
|
|
385
|
-
|
|
223
|
+
kwargs = self._params_builder.set_pagination(**kwargs)
|
|
386
224
|
objects_with_highlights: list[dict] = []
|
|
387
225
|
while True:
|
|
388
|
-
resp = self.
|
|
226
|
+
resp = self._http_handler.prepare_request("GET", api, **kwargs)
|
|
389
227
|
contents = resp["content"]
|
|
390
228
|
total_pages = resp["totalPages"]
|
|
391
|
-
if not contents or kwargs["params"]["page"] >= total_pages:
|
|
392
|
-
break
|
|
393
229
|
objects_with_highlights.extend(contents)
|
|
394
|
-
kwargs
|
|
230
|
+
if not contents or self._params_builder.read_page_number(**kwargs) >= (total_pages - 1):
|
|
231
|
+
break
|
|
232
|
+
self._params_builder.increment_page_number(**kwargs)
|
|
395
233
|
|
|
396
234
|
objects = []
|
|
397
235
|
for obj in objects_with_highlights:
|
|
@@ -400,193 +238,6 @@ class ClientDHCore(Client):
|
|
|
400
238
|
|
|
401
239
|
return objects
|
|
402
240
|
|
|
403
|
-
##############################
|
|
404
|
-
# Call methods
|
|
405
|
-
##############################
|
|
406
|
-
|
|
407
|
-
def _prepare_call(self, call_type: str, api: str, **kwargs) -> dict:
|
|
408
|
-
"""
|
|
409
|
-
Prepare a call to the DHCore API.
|
|
410
|
-
|
|
411
|
-
Handles the preparation of an API call by checking configuration,
|
|
412
|
-
building the URL, and adding authentication parameters.
|
|
413
|
-
|
|
414
|
-
Parameters
|
|
415
|
-
----------
|
|
416
|
-
call_type : str
|
|
417
|
-
The HTTP method type (GET, POST, PUT, DELETE, etc.).
|
|
418
|
-
api : str
|
|
419
|
-
The API endpoint path to call.
|
|
420
|
-
**kwargs : dict
|
|
421
|
-
Additional keyword arguments to pass to the HTTP request.
|
|
422
|
-
|
|
423
|
-
Returns
|
|
424
|
-
-------
|
|
425
|
-
dict
|
|
426
|
-
The response from the API call.
|
|
427
|
-
|
|
428
|
-
Raises
|
|
429
|
-
------
|
|
430
|
-
ClientError
|
|
431
|
-
If the client configuration is invalid.
|
|
432
|
-
BackendError
|
|
433
|
-
If the backend returns an error response.
|
|
434
|
-
"""
|
|
435
|
-
self._configurator.check_config()
|
|
436
|
-
url = self._build_url(api)
|
|
437
|
-
full_kwargs = self._configurator.get_auth_parameters(kwargs)
|
|
438
|
-
return self._make_call(call_type, url, **full_kwargs)
|
|
439
|
-
|
|
440
|
-
def _build_url(self, api: str) -> str:
|
|
441
|
-
"""
|
|
442
|
-
Build the complete URL for an API call.
|
|
443
|
-
|
|
444
|
-
Combines the configured endpoint with the API path to create
|
|
445
|
-
the full URL for the HTTP request.
|
|
446
|
-
|
|
447
|
-
Parameters
|
|
448
|
-
----------
|
|
449
|
-
api : str
|
|
450
|
-
The API endpoint path. Leading slashes are automatically handled.
|
|
451
|
-
|
|
452
|
-
Returns
|
|
453
|
-
-------
|
|
454
|
-
str
|
|
455
|
-
The complete URL for the API call.
|
|
456
|
-
|
|
457
|
-
Notes
|
|
458
|
-
-----
|
|
459
|
-
This method automatically removes leading slashes from the API path
|
|
460
|
-
to ensure proper URL construction.
|
|
461
|
-
"""
|
|
462
|
-
endpoint = self._configurator.get_endpoint()
|
|
463
|
-
return f"{endpoint}/{api.removeprefix('/')}"
|
|
464
|
-
|
|
465
|
-
def _make_call(self, call_type: str, url: str, refresh: bool = True, **kwargs) -> dict:
|
|
466
|
-
"""
|
|
467
|
-
Make a call to the DHCore API.
|
|
468
|
-
|
|
469
|
-
Executes the actual HTTP request to the DHCore backend, handles
|
|
470
|
-
API version checking, automatic token refresh on 401 errors,
|
|
471
|
-
and error parsing.
|
|
472
|
-
|
|
473
|
-
Parameters
|
|
474
|
-
----------
|
|
475
|
-
call_type : str
|
|
476
|
-
The HTTP method type (GET, POST, PUT, DELETE, etc.).
|
|
477
|
-
url : str
|
|
478
|
-
The complete URL to call.
|
|
479
|
-
refresh : bool, default True
|
|
480
|
-
Whether to attempt token refresh on authentication errors.
|
|
481
|
-
Set to False to prevent infinite recursion during refresh.
|
|
482
|
-
**kwargs : dict
|
|
483
|
-
Additional keyword arguments to pass to the HTTP request.
|
|
484
|
-
|
|
485
|
-
Returns
|
|
486
|
-
-------
|
|
487
|
-
dict
|
|
488
|
-
The parsed response from the backend as a dictionary.
|
|
489
|
-
|
|
490
|
-
Raises
|
|
491
|
-
------
|
|
492
|
-
ClientError
|
|
493
|
-
If the backend API version is not supported.
|
|
494
|
-
BackendError
|
|
495
|
-
If the backend returns an error response or response parsing fails.
|
|
496
|
-
UnauthorizedError
|
|
497
|
-
If authentication fails and token refresh is not possible.
|
|
498
|
-
|
|
499
|
-
Notes
|
|
500
|
-
-----
|
|
501
|
-
This method automatically handles:
|
|
502
|
-
- API version compatibility checking
|
|
503
|
-
- OAuth2 token refresh on 401 errors
|
|
504
|
-
- Response parsing and error handling
|
|
505
|
-
- 60-second timeout for all requests
|
|
506
|
-
"""
|
|
507
|
-
# Call the API
|
|
508
|
-
response = request(call_type, url, timeout=60, **kwargs)
|
|
509
|
-
|
|
510
|
-
# Evaluate DHCore API version
|
|
511
|
-
self._check_core_version(response)
|
|
512
|
-
|
|
513
|
-
# Handle token refresh (redo call)
|
|
514
|
-
if (response.status_code in [401]) and (refresh) and self._configurator.refreshable_auth_types():
|
|
515
|
-
self._configurator.refresh_credentials(change_origin=True)
|
|
516
|
-
kwargs = self._configurator.get_auth_parameters(kwargs)
|
|
517
|
-
return self._make_call(call_type, url, refresh=False, **kwargs)
|
|
518
|
-
|
|
519
|
-
self._error_parser.parse(response)
|
|
520
|
-
return self._dictify_response(response)
|
|
521
|
-
|
|
522
|
-
def _check_core_version(self, response: Response) -> None:
|
|
523
|
-
"""
|
|
524
|
-
Check DHCore API version compatibility.
|
|
525
|
-
|
|
526
|
-
Validates that the DHCore backend API version is compatible with
|
|
527
|
-
this client library. Issues warnings if the backend version is
|
|
528
|
-
newer than the library version.
|
|
529
|
-
|
|
530
|
-
Parameters
|
|
531
|
-
----------
|
|
532
|
-
response : Response
|
|
533
|
-
The HTTP response object containing the X-Api-Level header.
|
|
534
|
-
|
|
535
|
-
Returns
|
|
536
|
-
-------
|
|
537
|
-
None
|
|
538
|
-
|
|
539
|
-
Raises
|
|
540
|
-
------
|
|
541
|
-
ClientError
|
|
542
|
-
If the backend API level is not supported by this client.
|
|
543
|
-
|
|
544
|
-
Notes
|
|
545
|
-
-----
|
|
546
|
-
Supported API levels: {MIN_API_LEVEL} to {MAX_API_LEVEL}
|
|
547
|
-
Current library version: {LIB_VERSION}
|
|
548
|
-
"""
|
|
549
|
-
if "X-Api-Level" in response.headers:
|
|
550
|
-
core_api_level = int(response.headers["X-Api-Level"])
|
|
551
|
-
if not (MIN_API_LEVEL <= core_api_level <= MAX_API_LEVEL):
|
|
552
|
-
raise ClientError("Backend API level not supported.")
|
|
553
|
-
if LIB_VERSION < core_api_level:
|
|
554
|
-
warn("Backend API level is higher than library version. You should consider updating the library.")
|
|
555
|
-
|
|
556
|
-
def _dictify_response(self, response: Response) -> dict:
|
|
557
|
-
"""
|
|
558
|
-
Parse HTTP response to dictionary.
|
|
559
|
-
|
|
560
|
-
Converts the HTTP response body from JSON to a Python dictionary.
|
|
561
|
-
Handles empty responses gracefully.
|
|
562
|
-
|
|
563
|
-
Parameters
|
|
564
|
-
----------
|
|
565
|
-
response : Response
|
|
566
|
-
The HTTP response object to parse.
|
|
567
|
-
|
|
568
|
-
Returns
|
|
569
|
-
-------
|
|
570
|
-
dict
|
|
571
|
-
The parsed response body as a dictionary. Returns empty dict
|
|
572
|
-
if response body is empty.
|
|
573
|
-
|
|
574
|
-
Raises
|
|
575
|
-
------
|
|
576
|
-
BackendError
|
|
577
|
-
If the response cannot be parsed as JSON.
|
|
578
|
-
|
|
579
|
-
Notes
|
|
580
|
-
-----
|
|
581
|
-
Empty response bodies are treated as valid and return an empty dict.
|
|
582
|
-
"""
|
|
583
|
-
try:
|
|
584
|
-
return response.json()
|
|
585
|
-
except JSONDecodeError:
|
|
586
|
-
if response.text == "":
|
|
587
|
-
return {}
|
|
588
|
-
raise BackendError("Backend response could not be parsed.")
|
|
589
|
-
|
|
590
241
|
##############################
|
|
591
242
|
# Interface methods
|
|
592
243
|
##############################
|
|
@@ -596,18 +247,23 @@ class ClientDHCore(Client):
|
|
|
596
247
|
"""
|
|
597
248
|
Check if this client operates locally.
|
|
598
249
|
|
|
599
|
-
|
|
600
|
-
|
|
250
|
+
Used to distinguish between ClientDHCore (remote) and ClientLocal
|
|
251
|
+
implementations.
|
|
601
252
|
|
|
602
253
|
Returns
|
|
603
254
|
-------
|
|
604
255
|
bool
|
|
605
|
-
False, indicating this client communicates with
|
|
606
|
-
DHCore backend, not local storage.
|
|
607
|
-
|
|
608
|
-
Notes
|
|
609
|
-
-----
|
|
610
|
-
This method is used to distinguish between ClientDHCore (returns False)
|
|
611
|
-
and ClientLocal (returns True) implementations.
|
|
256
|
+
False, indicating this client communicates with remote DHCore backend.
|
|
612
257
|
"""
|
|
613
258
|
return False
|
|
259
|
+
|
|
260
|
+
##############################
|
|
261
|
+
# Utility methods
|
|
262
|
+
##############################
|
|
263
|
+
|
|
264
|
+
def refresh_token(self) -> None:
|
|
265
|
+
"""
|
|
266
|
+
Manually trigger OAuth2 token refresh.
|
|
267
|
+
"""
|
|
268
|
+
self._http_handler._configurator.check_config()
|
|
269
|
+
self._http_handler._configurator.refresh_credentials()
|