digitalhub 0.13.0b3__py3-none-any.whl → 0.14.9__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.
- digitalhub/__init__.py +3 -8
- digitalhub/context/api.py +43 -6
- digitalhub/context/builder.py +1 -5
- digitalhub/context/context.py +28 -13
- digitalhub/entities/_base/_base/entity.py +0 -15
- digitalhub/entities/_base/context/entity.py +1 -4
- digitalhub/entities/_base/entity/builder.py +5 -5
- digitalhub/entities/_base/entity/entity.py +0 -8
- digitalhub/entities/_base/executable/entity.py +195 -87
- digitalhub/entities/_base/material/entity.py +11 -23
- digitalhub/entities/_base/material/utils.py +28 -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/metrics.py +64 -30
- digitalhub/entities/_commons/utils.py +119 -30
- digitalhub/entities/_constructors/_resources.py +151 -0
- digitalhub/entities/{_base/entity/_constructors → _constructors}/name.py +18 -0
- digitalhub/entities/_processors/base/crud.py +381 -0
- digitalhub/entities/_processors/base/import_export.py +118 -0
- digitalhub/entities/_processors/base/processor.py +299 -0
- digitalhub/entities/_processors/base/special_ops.py +104 -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 +38 -102
- digitalhub/entities/artifact/crud.py +58 -22
- digitalhub/entities/artifact/utils.py +28 -13
- digitalhub/entities/builders.py +2 -0
- digitalhub/entities/dataitem/crud.py +63 -20
- digitalhub/entities/dataitem/table/entity.py +27 -22
- digitalhub/entities/dataitem/utils.py +82 -32
- digitalhub/entities/function/_base/entity.py +3 -6
- digitalhub/entities/function/crud.py +55 -24
- digitalhub/entities/model/_base/entity.py +62 -20
- digitalhub/entities/model/crud.py +59 -23
- digitalhub/entities/model/mlflow/utils.py +29 -20
- digitalhub/entities/model/utils.py +28 -13
- digitalhub/entities/project/_base/builder.py +0 -6
- digitalhub/entities/project/_base/entity.py +337 -164
- digitalhub/entities/project/_base/spec.py +4 -4
- digitalhub/entities/project/crud.py +28 -71
- digitalhub/entities/project/utils.py +7 -3
- 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 +31 -28
- 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 +89 -30
- digitalhub/entities/workflow/_base/entity.py +3 -8
- digitalhub/entities/workflow/crud.py +55 -24
- 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/{dhcore/api_builder.py → api_builder.py} +3 -3
- digitalhub/stores/client/builder.py +19 -31
- digitalhub/stores/client/client.py +322 -0
- digitalhub/stores/client/configurator.py +408 -0
- digitalhub/stores/client/enums.py +50 -0
- digitalhub/stores/client/{dhcore/error_parser.py → error_parser.py} +0 -4
- digitalhub/stores/client/header_manager.py +61 -0
- digitalhub/stores/client/http_handler.py +152 -0
- digitalhub/stores/client/{_base/key_builder.py → key_builder.py} +14 -14
- digitalhub/stores/client/params_builder.py +330 -0
- digitalhub/stores/client/response_processor.py +102 -0
- digitalhub/stores/client/utils.py +35 -0
- digitalhub/stores/{credentials → configurator}/api.py +5 -9
- digitalhub/stores/configurator/configurator.py +123 -0
- digitalhub/stores/{credentials → configurator}/enums.py +27 -10
- digitalhub/stores/configurator/handler.py +213 -0
- digitalhub/stores/{credentials → configurator}/ini_module.py +31 -22
- digitalhub/stores/data/_base/store.py +0 -20
- digitalhub/stores/data/api.py +5 -7
- digitalhub/stores/data/builder.py +53 -27
- digitalhub/stores/data/local/store.py +0 -103
- digitalhub/stores/data/remote/store.py +0 -4
- digitalhub/stores/data/s3/configurator.py +39 -77
- digitalhub/stores/data/s3/store.py +57 -37
- digitalhub/stores/data/sql/configurator.py +66 -46
- digitalhub/stores/data/sql/store.py +171 -104
- digitalhub/stores/readers/data/factory.py +0 -8
- digitalhub/stores/readers/data/pandas/reader.py +9 -19
- digitalhub/utils/file_utils.py +0 -17
- digitalhub/utils/generic_utils.py +1 -14
- digitalhub/utils/git_utils.py +0 -8
- digitalhub/utils/io_utils.py +0 -12
- digitalhub/utils/store_utils.py +44 -0
- {digitalhub-0.13.0b3.dist-info → digitalhub-0.14.9.dist-info}/METADATA +5 -4
- {digitalhub-0.13.0b3.dist-info → digitalhub-0.14.9.dist-info}/RECORD +112 -113
- {digitalhub-0.13.0b3.dist-info → digitalhub-0.14.9.dist-info}/WHEEL +1 -1
- digitalhub/entities/_commons/types.py +0 -9
- digitalhub/entities/_processors/base.py +0 -531
- digitalhub/entities/_processors/context.py +0 -1299
- digitalhub/entities/task/_base/utils.py +0 -22
- digitalhub/factory/factory.py +0 -381
- digitalhub/stores/client/_base/api_builder.py +0 -34
- digitalhub/stores/client/_base/client.py +0 -243
- digitalhub/stores/client/_base/params_builder.py +0 -34
- digitalhub/stores/client/api.py +0 -36
- digitalhub/stores/client/dhcore/client.py +0 -613
- digitalhub/stores/client/dhcore/configurator.py +0 -675
- digitalhub/stores/client/dhcore/enums.py +0 -34
- digitalhub/stores/client/dhcore/key_builder.py +0 -62
- digitalhub/stores/client/dhcore/models.py +0 -40
- digitalhub/stores/client/dhcore/params_builder.py +0 -278
- digitalhub/stores/client/dhcore/utils.py +0 -94
- digitalhub/stores/client/local/api_builder.py +0 -116
- digitalhub/stores/client/local/client.py +0 -573
- digitalhub/stores/client/local/enums.py +0 -15
- digitalhub/stores/client/local/key_builder.py +0 -62
- digitalhub/stores/client/local/params_builder.py +0 -120
- digitalhub/stores/credentials/__init__.py +0 -3
- digitalhub/stores/credentials/configurator.py +0 -210
- digitalhub/stores/credentials/handler.py +0 -176
- digitalhub/stores/credentials/store.py +0 -81
- digitalhub/stores/data/enums.py +0 -15
- 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/{stores/client/_base → entities/_processors/base}/__init__.py +0 -0
- /digitalhub/{stores/client/dhcore → entities/_processors/context}/__init__.py +0 -0
- /digitalhub/stores/{client/local → configurator}/__init__.py +0 -0
- {digitalhub-0.13.0b3.dist-info → digitalhub-0.14.9.dist-info}/licenses/AUTHORS +0 -0
- {digitalhub-0.13.0b3.dist-info → digitalhub-0.14.9.dist-info}/licenses/LICENSE +0 -0
digitalhub/stores/client/api.py
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: © 2025 DSLab - Fondazione Bruno Kessler
|
|
2
|
-
#
|
|
3
|
-
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
|
|
5
|
-
from __future__ import annotations
|
|
6
|
-
|
|
7
|
-
import typing
|
|
8
|
-
|
|
9
|
-
from digitalhub.stores.client.builder import client_builder
|
|
10
|
-
|
|
11
|
-
if typing.TYPE_CHECKING:
|
|
12
|
-
from digitalhub.stores.client._base.client import Client
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def get_client(local: bool = False, config: dict | None = None) -> Client:
|
|
16
|
-
"""
|
|
17
|
-
Wrapper around ClientBuilder.build.
|
|
18
|
-
|
|
19
|
-
Parameters
|
|
20
|
-
----------
|
|
21
|
-
local : bool, default False
|
|
22
|
-
Whether to create a local client or not. If True, creates a
|
|
23
|
-
ClientLocal instance that operates in-memory. If False, creates
|
|
24
|
-
a ClientDHCore instance that communicates with a remote backend.
|
|
25
|
-
config : dict, optional
|
|
26
|
-
DHCore environment configuration. Only used when local=False.
|
|
27
|
-
If None, configuration will be loaded from environment variables
|
|
28
|
-
and configuration files.
|
|
29
|
-
|
|
30
|
-
Returns
|
|
31
|
-
-------
|
|
32
|
-
Client
|
|
33
|
-
The client instance. Either ClientLocal or ClientDHCore depending
|
|
34
|
-
on the local parameter.
|
|
35
|
-
"""
|
|
36
|
-
return client_builder.build(local, config)
|
|
@@ -1,613 +0,0 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: © 2025 DSLab - Fondazione Bruno Kessler
|
|
2
|
-
#
|
|
3
|
-
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
|
|
5
|
-
from __future__ import annotations
|
|
6
|
-
|
|
7
|
-
import typing
|
|
8
|
-
from typing import Any
|
|
9
|
-
from warnings import warn
|
|
10
|
-
|
|
11
|
-
from requests import request
|
|
12
|
-
from requests.exceptions import JSONDecodeError
|
|
13
|
-
|
|
14
|
-
from digitalhub.stores.client._base.client import Client
|
|
15
|
-
from digitalhub.stores.client.dhcore.api_builder import ClientDHCoreApiBuilder
|
|
16
|
-
from digitalhub.stores.client.dhcore.configurator import ClientDHCoreConfigurator
|
|
17
|
-
from digitalhub.stores.client.dhcore.error_parser import ErrorParser
|
|
18
|
-
from digitalhub.stores.client.dhcore.key_builder import ClientDHCoreKeyBuilder
|
|
19
|
-
from digitalhub.stores.client.dhcore.params_builder import ClientDHCoreParametersBuilder
|
|
20
|
-
from digitalhub.utils.exceptions import BackendError, ClientError
|
|
21
|
-
from digitalhub.utils.generic_utils import dump_json
|
|
22
|
-
|
|
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
|
-
|
|
33
|
-
class ClientDHCore(Client):
|
|
34
|
-
"""
|
|
35
|
-
DHCore client for remote DigitalHub Core backend communication.
|
|
36
|
-
|
|
37
|
-
The DHCore client is used to communicate with the DigitalHub Core
|
|
38
|
-
backend API via REST. The client supports multiple authentication methods:
|
|
39
|
-
- Basic authentication (username/password)
|
|
40
|
-
- OAuth2 token authentication with automatic token refresh
|
|
41
|
-
- Personal access token exchange
|
|
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
|
|
85
|
-
"""
|
|
86
|
-
|
|
87
|
-
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
|
-
super().__init__()
|
|
106
|
-
|
|
107
|
-
# API builder
|
|
108
|
-
self._api_builder = ClientDHCoreApiBuilder()
|
|
109
|
-
|
|
110
|
-
# Key builder
|
|
111
|
-
self._key_builder = ClientDHCoreKeyBuilder()
|
|
112
|
-
|
|
113
|
-
# Parameters builder
|
|
114
|
-
self._params_builder = ClientDHCoreParametersBuilder()
|
|
115
|
-
|
|
116
|
-
# Error parser
|
|
117
|
-
self._error_parser = ErrorParser()
|
|
118
|
-
|
|
119
|
-
# Client Configurator
|
|
120
|
-
self._configurator = ClientDHCoreConfigurator()
|
|
121
|
-
|
|
122
|
-
##############################
|
|
123
|
-
# CRUD methods
|
|
124
|
-
##############################
|
|
125
|
-
|
|
126
|
-
def create_object(self, api: str, obj: Any, **kwargs) -> dict:
|
|
127
|
-
"""
|
|
128
|
-
Create an object in DHCore.
|
|
129
|
-
|
|
130
|
-
Sends a POST request to the DHCore backend to create a new object.
|
|
131
|
-
Automatically sets the appropriate Content-Type header and serializes
|
|
132
|
-
the object to JSON format.
|
|
133
|
-
|
|
134
|
-
Parameters
|
|
135
|
-
----------
|
|
136
|
-
api : str
|
|
137
|
-
The API endpoint path for creating the object.
|
|
138
|
-
obj : Any
|
|
139
|
-
The object to create. Will be serialized to JSON.
|
|
140
|
-
**kwargs : dict
|
|
141
|
-
Additional keyword arguments to pass to the HTTP request,
|
|
142
|
-
such as headers, params, etc.
|
|
143
|
-
|
|
144
|
-
Returns
|
|
145
|
-
-------
|
|
146
|
-
dict
|
|
147
|
-
The created object as returned by the backend.
|
|
148
|
-
|
|
149
|
-
Raises
|
|
150
|
-
------
|
|
151
|
-
BackendError
|
|
152
|
-
If the backend returns an error response.
|
|
153
|
-
ClientError
|
|
154
|
-
If there are client-side configuration issues.
|
|
155
|
-
"""
|
|
156
|
-
if "headers" not in kwargs:
|
|
157
|
-
kwargs["headers"] = {}
|
|
158
|
-
kwargs["headers"]["Content-Type"] = "application/json"
|
|
159
|
-
kwargs["data"] = dump_json(obj)
|
|
160
|
-
return self._prepare_call("POST", api, **kwargs)
|
|
161
|
-
|
|
162
|
-
def read_object(self, api: str, **kwargs) -> dict:
|
|
163
|
-
"""
|
|
164
|
-
Get an object from DHCore.
|
|
165
|
-
|
|
166
|
-
Sends a GET request to the DHCore backend to retrieve an existing object.
|
|
167
|
-
|
|
168
|
-
Parameters
|
|
169
|
-
----------
|
|
170
|
-
api : str
|
|
171
|
-
The API endpoint path for reading the object.
|
|
172
|
-
**kwargs : dict
|
|
173
|
-
Additional keyword arguments to pass to the HTTP request,
|
|
174
|
-
such as headers, params, etc.
|
|
175
|
-
|
|
176
|
-
Returns
|
|
177
|
-
-------
|
|
178
|
-
dict
|
|
179
|
-
The retrieved object as returned by the backend.
|
|
180
|
-
|
|
181
|
-
Raises
|
|
182
|
-
------
|
|
183
|
-
BackendError
|
|
184
|
-
If the backend returns an error response.
|
|
185
|
-
EntityNotExistsError
|
|
186
|
-
If the requested object does not exist.
|
|
187
|
-
"""
|
|
188
|
-
return self._prepare_call("GET", api, **kwargs)
|
|
189
|
-
|
|
190
|
-
def update_object(self, api: str, obj: Any, **kwargs) -> dict:
|
|
191
|
-
"""
|
|
192
|
-
Update an object in DHCore.
|
|
193
|
-
|
|
194
|
-
Sends a PUT request to the DHCore backend to update an existing object.
|
|
195
|
-
Automatically sets the appropriate Content-Type header and serializes
|
|
196
|
-
the object to JSON format.
|
|
197
|
-
|
|
198
|
-
Parameters
|
|
199
|
-
----------
|
|
200
|
-
api : str
|
|
201
|
-
The API endpoint path for updating the object.
|
|
202
|
-
obj : Any
|
|
203
|
-
The updated object data. Will be serialized to JSON.
|
|
204
|
-
**kwargs : dict
|
|
205
|
-
Additional keyword arguments to pass to the HTTP request,
|
|
206
|
-
such as headers, params, etc.
|
|
207
|
-
|
|
208
|
-
Returns
|
|
209
|
-
-------
|
|
210
|
-
dict
|
|
211
|
-
The updated object as returned by the backend.
|
|
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.
|
|
219
|
-
"""
|
|
220
|
-
if "headers" not in kwargs:
|
|
221
|
-
kwargs["headers"] = {}
|
|
222
|
-
kwargs["headers"]["Content-Type"] = "application/json"
|
|
223
|
-
kwargs["data"] = dump_json(obj)
|
|
224
|
-
return self._prepare_call("PUT", api, **kwargs)
|
|
225
|
-
|
|
226
|
-
def delete_object(self, api: str, **kwargs) -> dict:
|
|
227
|
-
"""
|
|
228
|
-
Delete an object from DHCore.
|
|
229
|
-
|
|
230
|
-
Sends a DELETE request to the DHCore backend to remove an object.
|
|
231
|
-
If the backend returns a boolean response, it will be wrapped in
|
|
232
|
-
a dictionary with a "deleted" key.
|
|
233
|
-
|
|
234
|
-
Parameters
|
|
235
|
-
----------
|
|
236
|
-
api : str
|
|
237
|
-
The API endpoint path for deleting the object.
|
|
238
|
-
**kwargs : dict
|
|
239
|
-
Additional keyword arguments to pass to the HTTP request,
|
|
240
|
-
such as headers, params, cascade options, etc.
|
|
241
|
-
|
|
242
|
-
Returns
|
|
243
|
-
-------
|
|
244
|
-
dict
|
|
245
|
-
The deletion result. Either the backend response or
|
|
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.
|
|
254
|
-
"""
|
|
255
|
-
resp = self._prepare_call("DELETE", api, **kwargs)
|
|
256
|
-
if isinstance(resp, bool):
|
|
257
|
-
resp = {"deleted": resp}
|
|
258
|
-
return resp
|
|
259
|
-
|
|
260
|
-
def list_objects(self, api: str, **kwargs) -> list[dict]:
|
|
261
|
-
"""
|
|
262
|
-
List objects from DHCore.
|
|
263
|
-
|
|
264
|
-
Sends GET requests to the DHCore backend to retrieve a paginated list
|
|
265
|
-
of objects. Automatically handles pagination by making multiple requests
|
|
266
|
-
until all objects are retrieved.
|
|
267
|
-
|
|
268
|
-
Parameters
|
|
269
|
-
----------
|
|
270
|
-
api : str
|
|
271
|
-
The API endpoint path for listing objects.
|
|
272
|
-
**kwargs : dict
|
|
273
|
-
Additional keyword arguments to pass to the HTTP request.
|
|
274
|
-
Can include 'params' dict with pagination parameters.
|
|
275
|
-
|
|
276
|
-
Returns
|
|
277
|
-
-------
|
|
278
|
-
list[dict]
|
|
279
|
-
A list containing all objects from all pages.
|
|
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.
|
|
290
|
-
"""
|
|
291
|
-
if "params" not in kwargs:
|
|
292
|
-
kwargs["params"] = {}
|
|
293
|
-
|
|
294
|
-
start_page = 0
|
|
295
|
-
if "page" not in kwargs["params"]:
|
|
296
|
-
kwargs["params"]["page"] = start_page
|
|
297
|
-
|
|
298
|
-
objects = []
|
|
299
|
-
while True:
|
|
300
|
-
resp = self._prepare_call("GET", api, **kwargs)
|
|
301
|
-
contents = resp["content"]
|
|
302
|
-
total_pages = resp["totalPages"]
|
|
303
|
-
if not contents or kwargs["params"]["page"] >= total_pages:
|
|
304
|
-
break
|
|
305
|
-
objects.extend(contents)
|
|
306
|
-
kwargs["params"]["page"] += 1
|
|
307
|
-
|
|
308
|
-
return objects
|
|
309
|
-
|
|
310
|
-
def list_first_object(self, api: str, **kwargs) -> dict:
|
|
311
|
-
"""
|
|
312
|
-
Get the first object from a list in DHCore.
|
|
313
|
-
|
|
314
|
-
Retrieves the first object from a paginated list by calling
|
|
315
|
-
list_objects and returning the first item.
|
|
316
|
-
|
|
317
|
-
Parameters
|
|
318
|
-
----------
|
|
319
|
-
api : str
|
|
320
|
-
The API endpoint path for listing objects.
|
|
321
|
-
**kwargs : dict
|
|
322
|
-
Additional keyword arguments to pass to the HTTP request.
|
|
323
|
-
|
|
324
|
-
Returns
|
|
325
|
-
-------
|
|
326
|
-
dict
|
|
327
|
-
The first object from the list.
|
|
328
|
-
|
|
329
|
-
Raises
|
|
330
|
-
------
|
|
331
|
-
BackendError
|
|
332
|
-
If no objects are found or if the backend returns an error.
|
|
333
|
-
"""
|
|
334
|
-
try:
|
|
335
|
-
return self.list_objects(api, **kwargs)[0]
|
|
336
|
-
except IndexError:
|
|
337
|
-
raise BackendError("No object found.")
|
|
338
|
-
|
|
339
|
-
def search_objects(self, api: str, **kwargs) -> list[dict]:
|
|
340
|
-
"""
|
|
341
|
-
Search objects from DHCore.
|
|
342
|
-
|
|
343
|
-
Performs a search query against the DHCore backend using Solr search
|
|
344
|
-
capabilities. Handles pagination and removes search highlights from
|
|
345
|
-
the returned objects.
|
|
346
|
-
|
|
347
|
-
Parameters
|
|
348
|
-
----------
|
|
349
|
-
api : str
|
|
350
|
-
The API endpoint path for searching objects (usually Solr search).
|
|
351
|
-
**kwargs : dict
|
|
352
|
-
Additional keyword arguments to pass to the HTTP request.
|
|
353
|
-
Can include search parameters, filters, pagination options, etc.
|
|
354
|
-
|
|
355
|
-
Returns
|
|
356
|
-
-------
|
|
357
|
-
list[dict]
|
|
358
|
-
A list of objects matching the search criteria, with search
|
|
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.
|
|
371
|
-
"""
|
|
372
|
-
if "params" not in kwargs:
|
|
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
|
-
|
|
386
|
-
objects_with_highlights: list[dict] = []
|
|
387
|
-
while True:
|
|
388
|
-
resp = self._prepare_call("GET", api, **kwargs)
|
|
389
|
-
contents = resp["content"]
|
|
390
|
-
total_pages = resp["totalPages"]
|
|
391
|
-
if not contents or kwargs["params"]["page"] >= total_pages:
|
|
392
|
-
break
|
|
393
|
-
objects_with_highlights.extend(contents)
|
|
394
|
-
kwargs["params"]["page"] += 1
|
|
395
|
-
|
|
396
|
-
objects = []
|
|
397
|
-
for obj in objects_with_highlights:
|
|
398
|
-
obj.pop("highlights", None)
|
|
399
|
-
objects.append(obj)
|
|
400
|
-
|
|
401
|
-
return objects
|
|
402
|
-
|
|
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
|
-
##############################
|
|
591
|
-
# Interface methods
|
|
592
|
-
##############################
|
|
593
|
-
|
|
594
|
-
@staticmethod
|
|
595
|
-
def is_local() -> bool:
|
|
596
|
-
"""
|
|
597
|
-
Check if this client operates locally.
|
|
598
|
-
|
|
599
|
-
Returns a flag indicating whether this client instance operates
|
|
600
|
-
on local data or communicates with a remote backend.
|
|
601
|
-
|
|
602
|
-
Returns
|
|
603
|
-
-------
|
|
604
|
-
bool
|
|
605
|
-
False, indicating this client communicates with a remote
|
|
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.
|
|
612
|
-
"""
|
|
613
|
-
return False
|