digitalhub 0.13.0b2__py3-none-any.whl → 0.13.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.

Files changed (61) hide show
  1. digitalhub/__init__.py +1 -1
  2. digitalhub/context/api.py +5 -5
  3. digitalhub/context/builder.py +3 -5
  4. digitalhub/context/context.py +9 -1
  5. digitalhub/entities/_base/material/entity.py +3 -3
  6. digitalhub/entities/_commons/metrics.py +64 -30
  7. digitalhub/entities/_commons/utils.py +36 -9
  8. digitalhub/entities/_processors/base.py +150 -79
  9. digitalhub/entities/_processors/context.py +363 -212
  10. digitalhub/entities/_processors/utils.py +74 -30
  11. digitalhub/entities/artifact/utils.py +28 -13
  12. digitalhub/entities/dataitem/crud.py +10 -2
  13. digitalhub/entities/dataitem/table/entity.py +3 -3
  14. digitalhub/entities/dataitem/utils.py +84 -35
  15. digitalhub/entities/model/utils.py +28 -13
  16. digitalhub/entities/task/_base/models.py +12 -3
  17. digitalhub/factory/factory.py +25 -3
  18. digitalhub/factory/utils.py +11 -3
  19. digitalhub/runtimes/_base.py +1 -1
  20. digitalhub/runtimes/builder.py +18 -1
  21. digitalhub/stores/client/__init__.py +12 -0
  22. digitalhub/stores/client/_base/api_builder.py +14 -0
  23. digitalhub/stores/client/_base/client.py +93 -0
  24. digitalhub/stores/client/_base/key_builder.py +28 -0
  25. digitalhub/stores/client/_base/params_builder.py +14 -0
  26. digitalhub/stores/client/api.py +10 -5
  27. digitalhub/stores/client/builder.py +3 -1
  28. digitalhub/stores/client/dhcore/api_builder.py +17 -0
  29. digitalhub/stores/client/dhcore/client.py +276 -58
  30. digitalhub/stores/client/dhcore/configurator.py +336 -141
  31. digitalhub/stores/client/dhcore/error_parser.py +35 -1
  32. digitalhub/stores/client/dhcore/params_builder.py +113 -17
  33. digitalhub/stores/client/dhcore/utils.py +32 -14
  34. digitalhub/stores/client/local/api_builder.py +17 -0
  35. digitalhub/stores/client/local/client.py +6 -8
  36. digitalhub/stores/credentials/api.py +8 -8
  37. digitalhub/stores/credentials/configurator.py +176 -3
  38. digitalhub/stores/credentials/enums.py +17 -3
  39. digitalhub/stores/credentials/handler.py +73 -45
  40. digitalhub/stores/credentials/ini_module.py +59 -27
  41. digitalhub/stores/credentials/store.py +33 -1
  42. digitalhub/stores/data/_base/store.py +8 -3
  43. digitalhub/stores/data/api.py +20 -16
  44. digitalhub/stores/data/builder.py +69 -13
  45. digitalhub/stores/data/s3/configurator.py +64 -23
  46. digitalhub/stores/data/s3/store.py +30 -27
  47. digitalhub/stores/data/s3/utils.py +9 -9
  48. digitalhub/stores/data/sql/configurator.py +76 -25
  49. digitalhub/stores/data/sql/store.py +180 -91
  50. digitalhub/utils/exceptions.py +6 -0
  51. digitalhub/utils/file_utils.py +53 -30
  52. digitalhub/utils/generic_utils.py +41 -33
  53. digitalhub/utils/git_utils.py +24 -14
  54. digitalhub/utils/io_utils.py +19 -18
  55. digitalhub/utils/uri_utils.py +31 -31
  56. {digitalhub-0.13.0b2.dist-info → digitalhub-0.13.0b4.dist-info}/METADATA +1 -1
  57. {digitalhub-0.13.0b2.dist-info → digitalhub-0.13.0b4.dist-info}/RECORD +60 -61
  58. digitalhub/entities/_commons/types.py +0 -9
  59. {digitalhub-0.13.0b2.dist-info → digitalhub-0.13.0b4.dist-info}/WHEEL +0 -0
  60. {digitalhub-0.13.0b2.dist-info → digitalhub-0.13.0b4.dist-info}/licenses/AUTHORS +0 -0
  61. {digitalhub-0.13.0b2.dist-info → digitalhub-0.13.0b4.dist-info}/licenses/LICENSE +0 -0
@@ -32,21 +32,76 @@ LIB_VERSION = 13
32
32
 
33
33
  class ClientDHCore(Client):
34
34
  """
35
- DHCore client.
36
-
37
- The DHCore client is used to communicate with the Digitalhub Core
38
- backendAPI via REST. The client supports basic authentication and
39
- OAuth2 token authentication with token refresh.
40
- At creation, the client tries to get the endpoint and authentication
41
- parameters from the .dhcore file and the environment variables. In
42
- case the user incours into an authentication/endpoint error during
43
- the client creation, the user has the possibility to update the
44
- correct parameters using the `set_dhcore_env` function. If the DHCore
45
- client is already initialized, this function will override the
46
- configuration, otherwise it simply set the environment variables.
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
47
85
  """
48
86
 
49
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
+ """
50
105
  super().__init__()
51
106
 
52
107
  # API builder
@@ -72,19 +127,31 @@ class ClientDHCore(Client):
72
127
  """
73
128
  Create an object in DHCore.
74
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
+
75
134
  Parameters
76
135
  ----------
77
136
  api : str
78
- Create API.
137
+ The API endpoint path for creating the object.
79
138
  obj : Any
80
- Object to create.
139
+ The object to create. Will be serialized to JSON.
81
140
  **kwargs : dict
82
- Keyword arguments to pass to the request.
141
+ Additional keyword arguments to pass to the HTTP request,
142
+ such as headers, params, etc.
83
143
 
84
144
  Returns
85
145
  -------
86
146
  dict
87
- Response object.
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.
88
155
  """
89
156
  if "headers" not in kwargs:
90
157
  kwargs["headers"] = {}
@@ -96,17 +163,27 @@ class ClientDHCore(Client):
96
163
  """
97
164
  Get an object from DHCore.
98
165
 
166
+ Sends a GET request to the DHCore backend to retrieve an existing object.
167
+
99
168
  Parameters
100
169
  ----------
101
170
  api : str
102
- Read API.
171
+ The API endpoint path for reading the object.
103
172
  **kwargs : dict
104
- Keyword arguments to pass to the request.
173
+ Additional keyword arguments to pass to the HTTP request,
174
+ such as headers, params, etc.
105
175
 
106
176
  Returns
107
177
  -------
108
178
  dict
109
- Response object.
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.
110
187
  """
111
188
  return self._prepare_call("GET", api, **kwargs)
112
189
 
@@ -114,19 +191,31 @@ class ClientDHCore(Client):
114
191
  """
115
192
  Update an object in DHCore.
116
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
+
117
198
  Parameters
118
199
  ----------
119
200
  api : str
120
- Update API.
121
- obj : dict
122
- Object to update.
201
+ The API endpoint path for updating the object.
202
+ obj : Any
203
+ The updated object data. Will be serialized to JSON.
123
204
  **kwargs : dict
124
- Keyword arguments to pass to the request.
205
+ Additional keyword arguments to pass to the HTTP request,
206
+ such as headers, params, etc.
125
207
 
126
208
  Returns
127
209
  -------
128
210
  dict
129
- Response object.
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.
130
219
  """
131
220
  if "headers" not in kwargs:
132
221
  kwargs["headers"] = {}
@@ -138,17 +227,30 @@ class ClientDHCore(Client):
138
227
  """
139
228
  Delete an object from DHCore.
140
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
+
141
234
  Parameters
142
235
  ----------
143
236
  api : str
144
- Delete API.
237
+ The API endpoint path for deleting the object.
145
238
  **kwargs : dict
146
- Keyword arguments to pass to the request.
239
+ Additional keyword arguments to pass to the HTTP request,
240
+ such as headers, params, cascade options, etc.
147
241
 
148
242
  Returns
149
243
  -------
150
244
  dict
151
- Response object.
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.
152
254
  """
153
255
  resp = self._prepare_call("DELETE", api, **kwargs)
154
256
  if isinstance(resp, bool):
@@ -159,17 +261,32 @@ class ClientDHCore(Client):
159
261
  """
160
262
  List objects from DHCore.
161
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
+
162
268
  Parameters
163
269
  ----------
164
270
  api : str
165
- List API.
271
+ The API endpoint path for listing objects.
166
272
  **kwargs : dict
167
- Keyword arguments to pass to the request.
273
+ Additional keyword arguments to pass to the HTTP request.
274
+ Can include 'params' dict with pagination parameters.
168
275
 
169
276
  Returns
170
277
  -------
171
278
  list[dict]
172
- Response objects.
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.
173
290
  """
174
291
  if "params" not in kwargs:
175
292
  kwargs["params"] = {}
@@ -192,19 +309,27 @@ class ClientDHCore(Client):
192
309
 
193
310
  def list_first_object(self, api: str, **kwargs) -> dict:
194
311
  """
195
- List first objects.
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.
196
316
 
197
317
  Parameters
198
318
  ----------
199
319
  api : str
200
- The api to list the objects with.
320
+ The API endpoint path for listing objects.
201
321
  **kwargs : dict
202
- Keyword arguments passed to the request.
322
+ Additional keyword arguments to pass to the HTTP request.
203
323
 
204
324
  Returns
205
325
  -------
206
326
  dict
207
- The list of objects.
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.
208
333
  """
209
334
  try:
210
335
  return self.list_objects(api, **kwargs)[0]
@@ -215,17 +340,34 @@ class ClientDHCore(Client):
215
340
  """
216
341
  Search objects from DHCore.
217
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
+
218
347
  Parameters
219
348
  ----------
220
349
  api : str
221
- Search API.
350
+ The API endpoint path for searching objects (usually Solr search).
222
351
  **kwargs : dict
223
- Keyword arguments to pass to the request.
352
+ Additional keyword arguments to pass to the HTTP request.
353
+ Can include search parameters, filters, pagination options, etc.
224
354
 
225
355
  Returns
226
356
  -------
227
357
  list[dict]
228
- Response objects.
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.
229
371
  """
230
372
  if "params" not in kwargs:
231
373
  kwargs["params"] = {}
@@ -266,19 +408,29 @@ class ClientDHCore(Client):
266
408
  """
267
409
  Prepare a call to the DHCore API.
268
410
 
411
+ Handles the preparation of an API call by checking configuration,
412
+ building the URL, and adding authentication parameters.
413
+
269
414
  Parameters
270
415
  ----------
271
416
  call_type : str
272
- The type of call to prepare.
417
+ The HTTP method type (GET, POST, PUT, DELETE, etc.).
273
418
  api : str
274
- The api to call.
419
+ The API endpoint path to call.
275
420
  **kwargs : dict
276
- Keyword arguments to pass to the request.
421
+ Additional keyword arguments to pass to the HTTP request.
277
422
 
278
423
  Returns
279
424
  -------
280
425
  dict
281
- Response object.
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.
282
434
  """
283
435
  self._configurator.check_config()
284
436
  url = self._build_url(api)
@@ -287,17 +439,25 @@ class ClientDHCore(Client):
287
439
 
288
440
  def _build_url(self, api: str) -> str:
289
441
  """
290
- Build the url.
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.
291
446
 
292
447
  Parameters
293
448
  ----------
294
449
  api : str
295
- The api to call.
450
+ The API endpoint path. Leading slashes are automatically handled.
296
451
 
297
452
  Returns
298
453
  -------
299
454
  str
300
- The url.
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.
301
461
  """
302
462
  endpoint = self._configurator.get_endpoint()
303
463
  return f"{endpoint}/{api.removeprefix('/')}"
@@ -306,21 +466,43 @@ class ClientDHCore(Client):
306
466
  """
307
467
  Make a call to the DHCore API.
308
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
+
309
473
  Parameters
310
474
  ----------
311
475
  call_type : str
312
- The type of call to make.
476
+ The HTTP method type (GET, POST, PUT, DELETE, etc.).
313
477
  url : str
314
- The URL to call.
315
- refresh : bool
316
- Whether to refresh the access token.
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.
317
482
  **kwargs : dict
318
- Keyword arguments to pass to the request.
483
+ Additional keyword arguments to pass to the HTTP request.
319
484
 
320
485
  Returns
321
486
  -------
322
487
  dict
323
- Response object.
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
324
506
  """
325
507
  # Call the API
326
508
  response = request(call_type, url, timeout=60, **kwargs)
@@ -330,7 +512,7 @@ class ClientDHCore(Client):
330
512
 
331
513
  # Handle token refresh (redo call)
332
514
  if (response.status_code in [401]) and (refresh) and self._configurator.refreshable_auth_types():
333
- self._configurator.get_new_access_token(change_origin=True)
515
+ self._configurator.refresh_credentials(change_origin=True)
334
516
  kwargs = self._configurator.get_auth_parameters(kwargs)
335
517
  return self._make_call(call_type, url, refresh=False, **kwargs)
336
518
 
@@ -339,16 +521,30 @@ class ClientDHCore(Client):
339
521
 
340
522
  def _check_core_version(self, response: Response) -> None:
341
523
  """
342
- Raise an exception if DHCore API version is not supported.
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.
343
529
 
344
530
  Parameters
345
531
  ----------
346
532
  response : Response
347
- The response object.
533
+ The HTTP response object containing the X-Api-Level header.
348
534
 
349
535
  Returns
350
536
  -------
351
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}
352
548
  """
353
549
  if "X-Api-Level" in response.headers:
354
550
  core_api_level = int(response.headers["X-Api-Level"])
@@ -359,17 +555,30 @@ class ClientDHCore(Client):
359
555
 
360
556
  def _dictify_response(self, response: Response) -> dict:
361
557
  """
362
- Return dict from response.
558
+ Parse HTTP response to dictionary.
559
+
560
+ Converts the HTTP response body from JSON to a Python dictionary.
561
+ Handles empty responses gracefully.
363
562
 
364
563
  Parameters
365
564
  ----------
366
565
  response : Response
367
- The response object.
566
+ The HTTP response object to parse.
368
567
 
369
568
  Returns
370
569
  -------
371
570
  dict
372
- The parsed response object.
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.
373
582
  """
374
583
  try:
375
584
  return response.json()
@@ -385,11 +594,20 @@ class ClientDHCore(Client):
385
594
  @staticmethod
386
595
  def is_local() -> bool:
387
596
  """
388
- Declare if Client is local.
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.
389
601
 
390
602
  Returns
391
603
  -------
392
604
  bool
393
- False
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.
394
612
  """
395
613
  return False