digitalhub 0.8.1__py3-none-any.whl → 0.9.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.

Files changed (134) hide show
  1. digitalhub/__init__.py +19 -2
  2. digitalhub/client/_base/api_builder.py +16 -0
  3. digitalhub/client/_base/client.py +67 -0
  4. digitalhub/client/_base/key_builder.py +52 -0
  5. digitalhub/client/api.py +2 -38
  6. digitalhub/client/dhcore/api_builder.py +100 -0
  7. digitalhub/client/dhcore/client.py +81 -25
  8. digitalhub/client/dhcore/enums.py +27 -0
  9. digitalhub/client/dhcore/env.py +2 -2
  10. digitalhub/client/dhcore/key_builder.py +58 -0
  11. digitalhub/client/dhcore/utils.py +17 -17
  12. digitalhub/client/local/api_builder.py +100 -0
  13. digitalhub/client/local/client.py +22 -0
  14. digitalhub/client/local/key_builder.py +58 -0
  15. digitalhub/context/api.py +3 -38
  16. digitalhub/context/builder.py +10 -23
  17. digitalhub/context/context.py +20 -92
  18. digitalhub/entities/_base/context/entity.py +30 -22
  19. digitalhub/entities/_base/entity/_constructors/metadata.py +12 -1
  20. digitalhub/entities/_base/entity/_constructors/name.py +1 -1
  21. digitalhub/entities/_base/entity/_constructors/spec.py +1 -1
  22. digitalhub/entities/_base/entity/_constructors/status.py +3 -2
  23. digitalhub/entities/_base/entity/builder.py +6 -1
  24. digitalhub/entities/_base/entity/entity.py +32 -10
  25. digitalhub/entities/_base/entity/metadata.py +22 -0
  26. digitalhub/entities/_base/entity/spec.py +7 -2
  27. digitalhub/entities/_base/executable/entity.py +8 -8
  28. digitalhub/entities/_base/material/entity.py +49 -17
  29. digitalhub/entities/_base/material/status.py +0 -31
  30. digitalhub/entities/_base/material/utils.py +106 -0
  31. digitalhub/entities/_base/project/entity.py +341 -0
  32. digitalhub/entities/_base/unversioned/entity.py +3 -24
  33. digitalhub/entities/_base/versioned/entity.py +2 -26
  34. digitalhub/entities/_commons/enums.py +103 -0
  35. digitalhub/entities/_commons/utils.py +83 -0
  36. digitalhub/entities/_operations/processor.py +1873 -0
  37. digitalhub/entities/artifact/_base/builder.py +1 -1
  38. digitalhub/entities/artifact/_base/entity.py +1 -1
  39. digitalhub/entities/artifact/artifact/builder.py +2 -1
  40. digitalhub/entities/artifact/crud.py +46 -29
  41. digitalhub/entities/artifact/utils.py +62 -0
  42. digitalhub/entities/dataitem/_base/builder.py +1 -1
  43. digitalhub/entities/dataitem/_base/entity.py +6 -6
  44. digitalhub/entities/dataitem/crud.py +50 -66
  45. digitalhub/entities/dataitem/dataitem/builder.py +2 -1
  46. digitalhub/entities/dataitem/iceberg/builder.py +2 -1
  47. digitalhub/entities/dataitem/table/builder.py +2 -1
  48. digitalhub/entities/dataitem/table/entity.py +5 -10
  49. digitalhub/entities/dataitem/table/models.py +4 -5
  50. digitalhub/entities/dataitem/utils.py +137 -0
  51. digitalhub/entities/function/_base/builder.py +1 -1
  52. digitalhub/entities/function/_base/entity.py +6 -2
  53. digitalhub/entities/function/crud.py +36 -17
  54. digitalhub/entities/model/_base/builder.py +1 -1
  55. digitalhub/entities/model/_base/entity.py +1 -1
  56. digitalhub/entities/model/crud.py +46 -29
  57. digitalhub/entities/model/huggingface/builder.py +2 -1
  58. digitalhub/entities/model/huggingface/spec.py +4 -2
  59. digitalhub/entities/model/mlflow/builder.py +2 -1
  60. digitalhub/entities/model/mlflow/models.py +17 -9
  61. digitalhub/entities/model/mlflow/spec.py +6 -1
  62. digitalhub/entities/model/mlflow/utils.py +4 -2
  63. digitalhub/entities/model/model/builder.py +2 -1
  64. digitalhub/entities/model/sklearn/builder.py +2 -1
  65. digitalhub/entities/model/utils.py +62 -0
  66. digitalhub/entities/project/_base/builder.py +2 -2
  67. digitalhub/entities/project/_base/entity.py +82 -272
  68. digitalhub/entities/project/crud.py +110 -91
  69. digitalhub/entities/project/utils.py +35 -0
  70. digitalhub/entities/run/_base/builder.py +3 -1
  71. digitalhub/entities/run/_base/entity.py +52 -54
  72. digitalhub/entities/run/_base/spec.py +15 -7
  73. digitalhub/entities/run/crud.py +35 -17
  74. digitalhub/entities/secret/_base/builder.py +2 -2
  75. digitalhub/entities/secret/_base/entity.py +4 -10
  76. digitalhub/entities/secret/crud.py +36 -21
  77. digitalhub/entities/task/_base/builder.py +14 -14
  78. digitalhub/entities/task/_base/entity.py +21 -14
  79. digitalhub/entities/task/_base/models.py +35 -6
  80. digitalhub/entities/task/_base/spec.py +50 -13
  81. digitalhub/entities/task/_base/utils.py +18 -0
  82. digitalhub/entities/task/crud.py +35 -15
  83. digitalhub/entities/workflow/_base/builder.py +1 -1
  84. digitalhub/entities/workflow/_base/entity.py +22 -6
  85. digitalhub/entities/workflow/crud.py +36 -17
  86. digitalhub/factory/utils.py +1 -1
  87. digitalhub/readers/_base/reader.py +2 -2
  88. digitalhub/readers/_commons/enums.py +13 -0
  89. digitalhub/readers/api.py +3 -2
  90. digitalhub/readers/factory.py +12 -6
  91. digitalhub/readers/pandas/reader.py +20 -8
  92. digitalhub/runtimes/_base.py +0 -7
  93. digitalhub/runtimes/enums.py +12 -0
  94. digitalhub/stores/_base/store.py +59 -11
  95. digitalhub/stores/builder.py +5 -5
  96. digitalhub/stores/local/store.py +43 -4
  97. digitalhub/stores/remote/store.py +31 -5
  98. digitalhub/stores/s3/store.py +129 -48
  99. digitalhub/stores/sql/store.py +122 -47
  100. digitalhub/utils/exceptions.py +6 -0
  101. digitalhub/utils/file_utils.py +60 -2
  102. digitalhub/utils/generic_utils.py +45 -4
  103. digitalhub/utils/io_utils.py +18 -0
  104. digitalhub/utils/s3_utils.py +17 -0
  105. digitalhub/utils/uri_utils.py +153 -15
  106. {digitalhub-0.8.1.dist-info → digitalhub-0.9.0.dist-info}/LICENSE.txt +1 -1
  107. {digitalhub-0.8.1.dist-info → digitalhub-0.9.0.dist-info}/METADATA +3 -3
  108. {digitalhub-0.8.1.dist-info → digitalhub-0.9.0.dist-info}/RECORD +116 -114
  109. test/local/instances/test_validate.py +55 -0
  110. test/testkfp.py +4 -1
  111. digitalhub/datastores/_base/datastore.py +0 -85
  112. digitalhub/datastores/api.py +0 -37
  113. digitalhub/datastores/builder.py +0 -110
  114. digitalhub/datastores/local/datastore.py +0 -50
  115. digitalhub/datastores/remote/__init__.py +0 -0
  116. digitalhub/datastores/remote/datastore.py +0 -31
  117. digitalhub/datastores/s3/__init__.py +0 -0
  118. digitalhub/datastores/s3/datastore.py +0 -46
  119. digitalhub/datastores/sql/__init__.py +0 -0
  120. digitalhub/datastores/sql/datastore.py +0 -68
  121. digitalhub/entities/_base/api_utils.py +0 -620
  122. digitalhub/entities/_base/crud.py +0 -468
  123. digitalhub/entities/function/_base/models.py +0 -118
  124. digitalhub/entities/utils/__init__.py +0 -0
  125. digitalhub/entities/utils/api.py +0 -346
  126. digitalhub/entities/utils/entity_types.py +0 -19
  127. digitalhub/entities/utils/state.py +0 -31
  128. digitalhub/entities/utils/utils.py +0 -202
  129. /digitalhub/{context → entities/_base/project}/__init__.py +0 -0
  130. /digitalhub/{datastores → entities/_commons}/__init__.py +0 -0
  131. /digitalhub/{datastores/_base → entities/_operations}/__init__.py +0 -0
  132. /digitalhub/{datastores/local → readers/_commons}/__init__.py +0 -0
  133. {digitalhub-0.8.1.dist-info → digitalhub-0.9.0.dist-info}/WHEEL +0 -0
  134. {digitalhub-0.8.1.dist-info → digitalhub-0.9.0.dist-info}/top_level.txt +0 -0
digitalhub/__init__.py CHANGED
@@ -1,9 +1,11 @@
1
+ __version__ = "0.9.0b0"
1
2
  from digitalhub.entities.artifact.crud import (
2
3
  delete_artifact,
3
4
  get_artifact,
4
5
  get_artifact_versions,
5
6
  import_artifact,
6
7
  list_artifacts,
8
+ load_artifact,
7
9
  log_artifact,
8
10
  new_artifact,
9
11
  update_artifact,
@@ -14,6 +16,7 @@ from digitalhub.entities.dataitem.crud import (
14
16
  get_dataitem_versions,
15
17
  import_dataitem,
16
18
  list_dataitems,
19
+ load_dataitem,
17
20
  log_dataitem,
18
21
  new_dataitem,
19
22
  update_dataitem,
@@ -24,6 +27,7 @@ from digitalhub.entities.function.crud import (
24
27
  get_function_versions,
25
28
  import_function,
26
29
  list_functions,
30
+ load_function,
27
31
  new_function,
28
32
  update_function,
29
33
  )
@@ -33,6 +37,7 @@ from digitalhub.entities.model.crud import (
33
37
  get_model_versions,
34
38
  import_model,
35
39
  list_models,
40
+ load_model,
36
41
  log_model,
37
42
  new_model,
38
43
  update_model,
@@ -42,27 +47,39 @@ from digitalhub.entities.project.crud import (
42
47
  get_or_create_project,
43
48
  get_project,
44
49
  import_project,
50
+ list_projects,
45
51
  load_project,
46
52
  new_project,
53
+ search_entity,
47
54
  update_project,
48
55
  )
49
- from digitalhub.entities.run.crud import delete_run, get_run, import_run, list_runs, new_run, update_run
56
+ from digitalhub.entities.run.crud import delete_run, get_run, import_run, list_runs, load_run, new_run, update_run
50
57
  from digitalhub.entities.secret.crud import (
51
58
  delete_secret,
52
59
  get_secret,
53
60
  get_secret_versions,
54
61
  import_secret,
55
62
  list_secrets,
63
+ load_secret,
56
64
  new_secret,
57
65
  update_secret,
58
66
  )
59
- from digitalhub.entities.task.crud import delete_task, get_task, import_task, list_tasks, new_task, update_task
67
+ from digitalhub.entities.task.crud import (
68
+ delete_task,
69
+ get_task,
70
+ import_task,
71
+ list_tasks,
72
+ load_task,
73
+ new_task,
74
+ update_task,
75
+ )
60
76
  from digitalhub.entities.workflow.crud import (
61
77
  delete_workflow,
62
78
  get_workflow,
63
79
  get_workflow_versions,
64
80
  import_workflow,
65
81
  list_workflows,
82
+ load_workflow,
66
83
  new_workflow,
67
84
  update_workflow,
68
85
  )
@@ -0,0 +1,16 @@
1
+ from __future__ import annotations
2
+
3
+ from abc import abstractmethod
4
+
5
+
6
+ class ClientApiBuilder:
7
+ """
8
+ This class is used to build the API for the client.
9
+ Depending on the client, the API is built differently.
10
+ """
11
+
12
+ @abstractmethod
13
+ def build_api(self) -> str:
14
+ """
15
+ Build the API for the client.
16
+ """
@@ -1,7 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import typing
3
4
  from abc import abstractmethod
4
5
 
6
+ if typing.TYPE_CHECKING:
7
+ from digitalhub.client._base.api_builder import ClientApiBuilder
8
+ from digitalhub.client._base.key_builder import ClientKeyBuilder
9
+
5
10
 
6
11
  class Client:
7
12
  """
@@ -12,6 +17,14 @@ class Client:
12
17
  listing of objects and comes into two subclasses: Local and DHCore.
13
18
  """
14
19
 
20
+ def __init__(self) -> None:
21
+ self._api_builder: ClientApiBuilder = None
22
+ self._key_builder: ClientKeyBuilder = None
23
+
24
+ ##############################
25
+ # CRUD methods
26
+ ##############################
27
+
15
28
  @abstractmethod
16
29
  def create_object(self, api: str, obj: dict, **kwargs) -> dict:
17
30
  """
@@ -48,6 +61,60 @@ class Client:
48
61
  Read first object method.
49
62
  """
50
63
 
64
+ @abstractmethod
65
+ def search_objects(self, api: str, **kwargs) -> dict:
66
+ """
67
+ Search objects method.
68
+ """
69
+
70
+ ##############################
71
+ # Build methods
72
+ ##############################
73
+
74
+ def build_api(self, category: str, operation: str, **kwargs) -> str:
75
+ """
76
+ Build the API for the client.
77
+
78
+ Parameters
79
+ ----------
80
+ category : str
81
+ API category.
82
+ operation : str
83
+ API operation.
84
+ **kwargs : dict
85
+ Additional parameters.
86
+
87
+ Returns
88
+ -------
89
+ str
90
+ API formatted.
91
+ """
92
+ return self._api_builder.build_api(category, operation, **kwargs)
93
+
94
+ def build_key(self, category: str, *args, **kwargs) -> str:
95
+ """
96
+ Build the key for the client.
97
+
98
+ Parameters
99
+ ----------
100
+ category : str
101
+ Key category.
102
+ *args : tuple
103
+ Additional arguments.
104
+ **kwargs : dict
105
+ Additional parameters.
106
+
107
+ Returns
108
+ -------
109
+ str
110
+ Key formatted.
111
+ """
112
+ return self._key_builder.build_key(category, *args, **kwargs)
113
+
114
+ ##############################
115
+ # Interface methods
116
+ ##############################
117
+
51
118
  @staticmethod
52
119
  @abstractmethod
53
120
  def is_local() -> bool:
@@ -0,0 +1,52 @@
1
+ from __future__ import annotations
2
+
3
+ from abc import abstractmethod
4
+
5
+ from digitalhub.entities._commons.enums import ApiCategories
6
+
7
+
8
+ class ClientKeyBuilder:
9
+ """
10
+ Class that build the key of entities.
11
+ """
12
+
13
+ def build_key(self, category: str, *args, **kwargs) -> str:
14
+ """
15
+ Build key.
16
+
17
+ Parameters
18
+ ----------
19
+ category : str
20
+ Key category.
21
+ *args : tuple
22
+ Positional arguments.
23
+ **kwargs : dict
24
+ Keyword arguments.
25
+
26
+ Returns
27
+ -------
28
+ str
29
+ Key.
30
+ """
31
+ if category == ApiCategories.BASE.value:
32
+ return self.base_entity_key(*args, **kwargs)
33
+ return self.context_entity_key(*args, **kwargs)
34
+
35
+ @abstractmethod
36
+ def base_entity_key(self, entity_id: str) -> str:
37
+ """
38
+ Build for base entity key.
39
+ """
40
+
41
+ @abstractmethod
42
+ def context_entity_key(
43
+ self,
44
+ project: str,
45
+ entity_type: str,
46
+ entity_kind: str,
47
+ entity_name: str,
48
+ entity_id: str | None = None,
49
+ ) -> str:
50
+ """
51
+ Build for context entity key.
52
+ """
digitalhub/client/api.py CHANGED
@@ -8,26 +8,7 @@ if typing.TYPE_CHECKING:
8
8
  from digitalhub.client._base.client import Client
9
9
 
10
10
 
11
- def check_client_exists(local: bool = False) -> bool:
12
- """
13
- Check if client exists.
14
-
15
- Parameters
16
- ----------
17
- local : bool
18
- Check client existence by local.
19
-
20
- Returns
21
- -------
22
- bool
23
- True if client exists, False otherwise.
24
- """
25
- if local:
26
- return client_builder._local is not None
27
- return client_builder._dhcore is not None
28
-
29
-
30
- def build_client(local: bool = False, config: dict | None = None) -> None:
11
+ def get_client(local: bool = False, config: dict | None = None) -> Client:
31
12
  """
32
13
  Wrapper around ClientBuilder.build.
33
14
 
@@ -43,21 +24,4 @@ def build_client(local: bool = False, config: dict | None = None) -> None:
43
24
  Client
44
25
  The client instance.
45
26
  """
46
- client_builder.build(local, config)
47
-
48
-
49
- def get_client(local: bool = False) -> Client:
50
- """
51
- Wrapper around ClientBuilder.build.
52
-
53
- Parameters
54
- ----------
55
- local : bool
56
- Whether to create a local client or not.
57
-
58
- Returns
59
- -------
60
- Client
61
- The client instance.
62
- """
63
- return client_builder.build(local)
27
+ return client_builder.build(local, config)
@@ -0,0 +1,100 @@
1
+ from __future__ import annotations
2
+
3
+ from digitalhub.client._base.api_builder import ClientApiBuilder
4
+ from digitalhub.entities._commons.enums import ApiCategories, BackendOperations
5
+ from digitalhub.utils.exceptions import BackendError
6
+
7
+ API_BASE = "/api/v1"
8
+ API_CONTEXT = f"{API_BASE}/-"
9
+
10
+
11
+ class ClientDHCoreApiBuilder(ClientApiBuilder):
12
+ """
13
+ This class is used to build the API for the DHCore client.
14
+ """
15
+
16
+ def build_api(self, category: str, operation: str, **kwargs) -> str:
17
+ """
18
+ Build the API for the client.
19
+
20
+ Parameters
21
+ ----------
22
+ category : str
23
+ API category.
24
+ operation : str
25
+ API operation.
26
+ **kwargs : dict
27
+ Additional parameters.
28
+
29
+ Returns
30
+ -------
31
+ str
32
+ API formatted.
33
+ """
34
+ if category == ApiCategories.BASE.value:
35
+ return self.build_api_base(operation, **kwargs)
36
+ return self.build_api_context(operation, **kwargs)
37
+
38
+ def build_api_base(self, operation: str, **kwargs) -> str:
39
+ """
40
+ Build the base API for the client.
41
+
42
+ Parameters
43
+ ----------
44
+ operation : str
45
+ API operation.
46
+ **kwargs : dict
47
+ Additional parameters.
48
+
49
+ Returns
50
+ -------
51
+ str
52
+ API formatted.
53
+ """
54
+ entity_type = kwargs["entity_type"] + "s"
55
+ if operation in (
56
+ BackendOperations.CREATE.value,
57
+ BackendOperations.LIST.value,
58
+ ):
59
+ return f"{API_BASE}/{entity_type}"
60
+ elif operation in (
61
+ BackendOperations.READ.value,
62
+ BackendOperations.UPDATE.value,
63
+ BackendOperations.DELETE.value,
64
+ ):
65
+ return f"{API_BASE}/{entity_type}/{kwargs['entity_name']}"
66
+ elif operation == BackendOperations.SHARE.value:
67
+ return f"{API_BASE}/{entity_type}/{kwargs['entity_name']}/share"
68
+ raise BackendError(f"Invalid operation '{operation}' for entity type '{entity_type}' in DHCore.")
69
+
70
+ def build_api_context(self, operation: str, **kwargs) -> str:
71
+ """
72
+ Build the context API for the client.
73
+ """
74
+ entity_type = kwargs["entity_type"] + "s"
75
+ project = kwargs["project"]
76
+ if operation in (
77
+ BackendOperations.CREATE.value,
78
+ BackendOperations.LIST.value,
79
+ ):
80
+ return f"{API_CONTEXT}/{project}/{entity_type}"
81
+ elif operation in (
82
+ BackendOperations.READ.value,
83
+ BackendOperations.UPDATE.value,
84
+ BackendOperations.DELETE.value,
85
+ ):
86
+ return f"{API_CONTEXT}/{project}/{entity_type}/{kwargs['entity_id']}"
87
+ elif operation == BackendOperations.LOGS.value:
88
+ return f"{API_CONTEXT}/{project}/{entity_type}/{kwargs['entity_id']}/logs"
89
+ elif operation == BackendOperations.STOP.value:
90
+ return f"{API_CONTEXT}/{project}/{entity_type}/{kwargs['entity_id']}/stop"
91
+ elif operation == BackendOperations.RESUME.value:
92
+ return f"{API_CONTEXT}/{project}/{entity_type}/{kwargs['entity_id']}/resume"
93
+ elif operation == BackendOperations.DATA.value:
94
+ return f"{API_CONTEXT}/{project}/{entity_type}/{kwargs['entity_id']}/data"
95
+ elif operation == BackendOperations.FILES.value:
96
+ return f"{API_CONTEXT}/{project}/{entity_type}/{kwargs['entity_id']}/files/info"
97
+ elif operation == BackendOperations.SEARCH.value:
98
+ return f"{API_CONTEXT}/{project}/solr/search/item"
99
+
100
+ raise BackendError(f"Invalid operation '{operation}' for entity type '{entity_type}' in DHCore.")
@@ -4,7 +4,6 @@ import datetime
4
4
  import json
5
5
  import os
6
6
  import typing
7
- from urllib.parse import urlparse
8
7
  from warnings import warn
9
8
 
10
9
  from dotenv import get_key, set_key
@@ -12,7 +11,10 @@ from requests import request
12
11
  from requests.exceptions import HTTPError, JSONDecodeError, RequestException
13
12
 
14
13
  from digitalhub.client._base.client import Client
15
- from digitalhub.client.dhcore.env import ENV_FILE, FALLBACK_USER, MAX_API_LEVEL, MIN_API_LEVEL, LIB_VERSION
14
+ from digitalhub.client.dhcore.api_builder import ClientDHCoreApiBuilder
15
+ from digitalhub.client.dhcore.enums import AuthType, DhcoreEnvVar
16
+ from digitalhub.client.dhcore.env import ENV_FILE, FALLBACK_USER, LIB_VERSION, MAX_API_LEVEL, MIN_API_LEVEL
17
+ from digitalhub.client.dhcore.key_builder import ClientDHCoreKeyBuilder
16
18
  from digitalhub.client.dhcore.models import BasicAuth, OAuth2TokenAuth
17
19
  from digitalhub.utils.exceptions import (
18
20
  BackendError,
@@ -23,6 +25,7 @@ from digitalhub.utils.exceptions import (
23
25
  MissingSpecError,
24
26
  UnauthorizedError,
25
27
  )
28
+ from digitalhub.utils.uri_utils import has_remote_scheme
26
29
 
27
30
  if typing.TYPE_CHECKING:
28
31
  from requests import Response
@@ -47,6 +50,12 @@ class ClientDHCore(Client):
47
50
  def __init__(self, config: dict | None = None) -> None:
48
51
  super().__init__()
49
52
 
53
+ # API builder
54
+ self._api_builder = ClientDHCoreApiBuilder()
55
+
56
+ # Key builder
57
+ self._key_builder = ClientDHCoreKeyBuilder()
58
+
50
59
  # Endpoints
51
60
  self._endpoint_core: str | None = None
52
61
  self._endpoint_issuer: str | None = None
@@ -214,6 +223,56 @@ class ClientDHCore(Client):
214
223
  except IndexError:
215
224
  raise BackendError("No object found.")
216
225
 
226
+ def search_objects(self, api: str, **kwargs) -> list[dict]:
227
+ """
228
+ Search objects from DHCore.
229
+
230
+ Parameters
231
+ ----------
232
+ api : str
233
+ Search API.
234
+ **kwargs : dict
235
+ Keyword arguments to pass to the request.
236
+
237
+ Returns
238
+ -------
239
+ list[dict]
240
+ Response objects.
241
+ """
242
+ if kwargs is None:
243
+ kwargs = {}
244
+
245
+ if "params" not in kwargs:
246
+ kwargs["params"] = {}
247
+
248
+ start_page = 0
249
+ if "page" not in kwargs["params"]:
250
+ kwargs["params"]["page"] = start_page
251
+
252
+ if "size" not in kwargs["params"]:
253
+ kwargs["params"]["size"] = 10
254
+
255
+ # Add sorting
256
+ if "sort" not in kwargs["params"]:
257
+ kwargs["params"]["sort"] = "metadata.updated,DESC"
258
+
259
+ objects_with_highlights = []
260
+ while True:
261
+ resp = self._prepare_call("GET", api, **kwargs)
262
+ contents = resp["content"]
263
+ total_pages = resp["totalPages"]
264
+ if not contents or kwargs["params"]["page"] >= total_pages:
265
+ break
266
+ objects_with_highlights.extend(contents)
267
+ kwargs["params"]["page"] += 1
268
+
269
+ objects = []
270
+ for obj in objects_with_highlights:
271
+ obj.pop("highlights", None)
272
+ objects.append(obj)
273
+
274
+ return objects
275
+
217
276
  ##############################
218
277
  # Call methods
219
278
  ##############################
@@ -275,9 +334,9 @@ class ClientDHCore(Client):
275
334
  dict
276
335
  Keyword arguments with the authentication parameters.
277
336
  """
278
- if self._auth_type == "basic":
337
+ if self._auth_type == AuthType.BASIC.value:
279
338
  kwargs["auth"] = self._user, self._password
280
- elif self._auth_type == "oauth2":
339
+ elif self._auth_type == AuthType.OAUTH2.value:
281
340
  if "headers" not in kwargs:
282
341
  kwargs["headers"] = {}
283
342
  kwargs["headers"]["Authorization"] = f"Bearer {self._access_token}"
@@ -465,7 +524,6 @@ class ClientDHCore(Client):
465
524
  -------
466
525
  None
467
526
  """
468
-
469
527
  self._get_endpoints_from_env()
470
528
 
471
529
  if config is not None:
@@ -475,21 +533,20 @@ class ClientDHCore(Client):
475
533
  self._access_token = config.access_token
476
534
  self._refresh_token = config.refresh_token
477
535
  self._client_id = config.client_id
478
- self._auth_type = "oauth2"
536
+ self._auth_type = AuthType.OAUTH2.value
479
537
 
480
538
  elif config.get("user") is not None and config.get("password") is not None:
481
539
  config = BasicAuth(**config)
482
540
  self._user = config.user
483
541
  self._password = config.password
484
- self._auth_type = "basic"
542
+ self._auth_type = AuthType.BASIC.value
485
543
 
486
544
  return
487
545
 
488
546
  self._get_auth_from_env()
489
547
 
490
548
  # Propagate access and refresh token to env file
491
- if not ENV_FILE.exists():
492
- self._write_env()
549
+ self._write_env()
493
550
 
494
551
  def _get_endpoints_from_env(self) -> None:
495
552
  """
@@ -504,12 +561,12 @@ class ClientDHCore(Client):
504
561
  Exception
505
562
  If the endpoint of DHCore is not set in the env variables.
506
563
  """
507
- core_endpt = os.getenv("DHCORE_ENDPOINT")
564
+ core_endpt = os.getenv(DhcoreEnvVar.ENDPOINT.value)
508
565
  if core_endpt is None:
509
566
  raise BackendError("Endpoint not set as environment variables.")
510
567
  self._endpoint_core = self._sanitize_endpoint(core_endpt)
511
568
 
512
- issr_endpt = os.getenv("DHCORE_ISSUER")
569
+ issr_endpt = os.getenv(DhcoreEnvVar.ISSUER.value)
513
570
  if issr_endpt is not None:
514
571
  self._endpoint_issuer = self._sanitize_endpoint(issr_endpt)
515
572
 
@@ -521,9 +578,8 @@ class ClientDHCore(Client):
521
578
  -------
522
579
  None
523
580
  """
524
- parsed = urlparse(endpoint)
525
- if parsed.scheme not in ["http", "https"]:
526
- raise BackendError("Invalid endpoint scheme.")
581
+ if not has_remote_scheme(endpoint):
582
+ raise BackendError("Invalid endpoint scheme. Must start with http:// or https://.")
527
583
 
528
584
  endpoint = endpoint.strip()
529
585
  return endpoint.removesuffix("/")
@@ -536,19 +592,19 @@ class ClientDHCore(Client):
536
592
  -------
537
593
  None
538
594
  """
539
- self._user = os.getenv("DHCORE_USER", FALLBACK_USER)
540
- self._refresh_token = os.getenv("DHCORE_REFRESH_TOKEN")
541
- self._client_id = os.getenv("DHCORE_CLIENT_ID")
595
+ self._user = os.getenv(DhcoreEnvVar.USER.value, FALLBACK_USER)
596
+ self._refresh_token = os.getenv(DhcoreEnvVar.REFRESH_TOKEN.value)
597
+ self._client_id = os.getenv(DhcoreEnvVar.CLIENT_ID.value)
542
598
 
543
- token = os.getenv("DHCORE_ACCESS_TOKEN")
599
+ token = os.getenv(DhcoreEnvVar.ACCESS_TOKEN.value)
544
600
  if token is not None and token != "":
545
- self._auth_type = "oauth2"
601
+ self._auth_type = AuthType.OAUTH2.value
546
602
  self._access_token = token
547
603
  return
548
604
 
549
- password = os.getenv("DHCORE_PASSWORD")
605
+ password = os.getenv(DhcoreEnvVar.PASSWORD.value)
550
606
  if self._user is not None and password is not None:
551
- self._auth_type = "basic"
607
+ self._auth_type = AuthType.BASIC.value
552
608
  self._password = password
553
609
  return
554
610
 
@@ -566,12 +622,12 @@ class ClientDHCore(Client):
566
622
 
567
623
  # Call refresh token endpoint
568
624
  # Try token from env
569
- refresh_token = os.getenv("DHCORE_REFRESH_TOKEN")
625
+ refresh_token = os.getenv(DhcoreEnvVar.REFRESH_TOKEN.value)
570
626
  response = self._call_refresh_token_endpoint(url, refresh_token)
571
627
 
572
628
  # Otherwise try token from file
573
629
  if response.status_code in (400, 401, 403):
574
- refresh_token = get_key(ENV_FILE, "DHCORE_REFRESH_TOKEN")
630
+ refresh_token = get_key(ENV_FILE, DhcoreEnvVar.REFRESH_TOKEN.value)
575
631
  response = self._call_refresh_token_endpoint(url, refresh_token)
576
632
 
577
633
  response.raise_for_status()
@@ -641,9 +697,9 @@ class ClientDHCore(Client):
641
697
  """
642
698
  keys = {}
643
699
  if self._access_token is not None:
644
- keys["DHCORE_ACCESS_TOKEN"] = self._access_token
700
+ keys[DhcoreEnvVar.ACCESS_TOKEN.value] = self._access_token
645
701
  if self._refresh_token is not None:
646
- keys["DHCORE_REFRESH_TOKEN"] = self._refresh_token
702
+ keys[DhcoreEnvVar.REFRESH_TOKEN.value] = self._refresh_token
647
703
 
648
704
  for k, v in keys.items():
649
705
  set_key(dotenv_path=ENV_FILE, key_to_set=k, value_to_set=v)
@@ -0,0 +1,27 @@
1
+ from __future__ import annotations
2
+
3
+ from enum import Enum
4
+
5
+
6
+ class DhcoreEnvVar(Enum):
7
+ """
8
+ Environment variables.
9
+ """
10
+
11
+ ENDPOINT = "DHCORE_ENDPOINT"
12
+ ISSUER = "DHCORE_ISSUER"
13
+ USER = "DHCORE_USER"
14
+ PASSWORD = "DHCORE_PASSWORD"
15
+ CLIENT_ID = "DHCORE_CLIENT_ID"
16
+ ACCESS_TOKEN = "DHCORE_ACCESS_TOKEN"
17
+ REFRESH_TOKEN = "DHCORE_REFRESH_TOKEN"
18
+ WORKFLOW_IMAGE = "DHCORE_WORKFLOW_IMAGE"
19
+
20
+
21
+ class AuthType(Enum):
22
+ """
23
+ Authentication types.
24
+ """
25
+
26
+ BASIC = "basic"
27
+ OAUTH2 = "oauth2"
@@ -19,5 +19,5 @@ ENV_FILE = Path.home() / ".dhcore"
19
19
 
20
20
  # API levels that are supported
21
21
  MAX_API_LEVEL = 20
22
- MIN_API_LEVEL = 8
23
- LIB_VERSION = 8
22
+ MIN_API_LEVEL = 9
23
+ LIB_VERSION = 9