digitalhub 0.7.0b2__py3-none-any.whl → 0.8.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 (232) hide show
  1. digitalhub/__init__.py +63 -93
  2. digitalhub/client/__init__.py +0 -0
  3. digitalhub/client/_base/__init__.py +0 -0
  4. digitalhub/client/_base/client.py +56 -0
  5. digitalhub/client/api.py +63 -0
  6. digitalhub/client/builder.py +50 -0
  7. digitalhub/client/dhcore/__init__.py +0 -0
  8. digitalhub/client/dhcore/client.py +669 -0
  9. digitalhub/client/dhcore/env.py +21 -0
  10. digitalhub/client/dhcore/models.py +46 -0
  11. digitalhub/client/dhcore/utils.py +111 -0
  12. digitalhub/client/local/__init__.py +0 -0
  13. digitalhub/client/local/client.py +533 -0
  14. digitalhub/context/__init__.py +0 -0
  15. digitalhub/context/api.py +93 -0
  16. digitalhub/context/builder.py +94 -0
  17. digitalhub/context/context.py +136 -0
  18. digitalhub/datastores/__init__.py +0 -0
  19. digitalhub/datastores/_base/__init__.py +0 -0
  20. digitalhub/datastores/_base/datastore.py +85 -0
  21. digitalhub/datastores/api.py +37 -0
  22. digitalhub/datastores/builder.py +110 -0
  23. digitalhub/datastores/local/__init__.py +0 -0
  24. digitalhub/datastores/local/datastore.py +50 -0
  25. digitalhub/datastores/remote/__init__.py +0 -0
  26. digitalhub/datastores/remote/datastore.py +31 -0
  27. digitalhub/datastores/s3/__init__.py +0 -0
  28. digitalhub/datastores/s3/datastore.py +46 -0
  29. digitalhub/datastores/sql/__init__.py +0 -0
  30. digitalhub/datastores/sql/datastore.py +68 -0
  31. digitalhub/entities/__init__.py +0 -0
  32. digitalhub/entities/_base/__init__.py +0 -0
  33. digitalhub/entities/_base/_base/__init__.py +0 -0
  34. digitalhub/entities/_base/_base/entity.py +82 -0
  35. digitalhub/entities/_base/api_utils.py +620 -0
  36. digitalhub/entities/_base/context/__init__.py +0 -0
  37. digitalhub/entities/_base/context/entity.py +118 -0
  38. digitalhub/entities/_base/crud.py +468 -0
  39. digitalhub/entities/_base/entity/__init__.py +0 -0
  40. digitalhub/entities/_base/entity/_constructors/__init__.py +0 -0
  41. digitalhub/entities/_base/entity/_constructors/metadata.py +44 -0
  42. digitalhub/entities/_base/entity/_constructors/name.py +31 -0
  43. digitalhub/entities/_base/entity/_constructors/spec.py +33 -0
  44. digitalhub/entities/_base/entity/_constructors/status.py +52 -0
  45. digitalhub/entities/_base/entity/_constructors/uuid.py +26 -0
  46. digitalhub/entities/_base/entity/builder.py +175 -0
  47. digitalhub/entities/_base/entity/entity.py +106 -0
  48. digitalhub/entities/_base/entity/metadata.py +59 -0
  49. digitalhub/entities/_base/entity/spec.py +58 -0
  50. digitalhub/entities/_base/entity/status.py +43 -0
  51. digitalhub/entities/_base/executable/__init__.py +0 -0
  52. digitalhub/entities/_base/executable/entity.py +405 -0
  53. digitalhub/entities/_base/material/__init__.py +0 -0
  54. digitalhub/entities/_base/material/entity.py +214 -0
  55. digitalhub/entities/_base/material/spec.py +22 -0
  56. digitalhub/entities/_base/material/status.py +49 -0
  57. digitalhub/entities/_base/runtime_entity/__init__.py +0 -0
  58. digitalhub/entities/_base/runtime_entity/builder.py +106 -0
  59. digitalhub/entities/_base/unversioned/__init__.py +0 -0
  60. digitalhub/entities/_base/unversioned/builder.py +66 -0
  61. digitalhub/entities/_base/unversioned/entity.py +49 -0
  62. digitalhub/entities/_base/versioned/__init__.py +0 -0
  63. digitalhub/entities/_base/versioned/builder.py +68 -0
  64. digitalhub/entities/_base/versioned/entity.py +53 -0
  65. digitalhub/entities/artifact/__init__.py +0 -0
  66. digitalhub/entities/artifact/_base/__init__.py +0 -0
  67. digitalhub/entities/artifact/_base/builder.py +86 -0
  68. digitalhub/entities/artifact/_base/entity.py +39 -0
  69. digitalhub/entities/artifact/_base/spec.py +15 -0
  70. digitalhub/entities/artifact/_base/status.py +9 -0
  71. digitalhub/entities/artifact/artifact/__init__.py +0 -0
  72. digitalhub/entities/artifact/artifact/builder.py +18 -0
  73. digitalhub/entities/artifact/artifact/entity.py +32 -0
  74. digitalhub/entities/artifact/artifact/spec.py +27 -0
  75. digitalhub/entities/artifact/artifact/status.py +15 -0
  76. digitalhub/entities/artifact/crud.py +332 -0
  77. digitalhub/entities/builders.py +63 -0
  78. digitalhub/entities/dataitem/__init__.py +0 -0
  79. digitalhub/entities/dataitem/_base/__init__.py +0 -0
  80. digitalhub/entities/dataitem/_base/builder.py +86 -0
  81. digitalhub/entities/dataitem/_base/entity.py +75 -0
  82. digitalhub/entities/dataitem/_base/spec.py +15 -0
  83. digitalhub/entities/dataitem/_base/status.py +20 -0
  84. digitalhub/entities/dataitem/crud.py +372 -0
  85. digitalhub/entities/dataitem/dataitem/__init__.py +0 -0
  86. digitalhub/entities/dataitem/dataitem/builder.py +18 -0
  87. digitalhub/entities/dataitem/dataitem/entity.py +32 -0
  88. digitalhub/entities/dataitem/dataitem/spec.py +15 -0
  89. digitalhub/entities/dataitem/dataitem/status.py +9 -0
  90. digitalhub/entities/dataitem/iceberg/__init__.py +0 -0
  91. digitalhub/entities/dataitem/iceberg/builder.py +18 -0
  92. digitalhub/entities/dataitem/iceberg/entity.py +32 -0
  93. digitalhub/entities/dataitem/iceberg/spec.py +15 -0
  94. digitalhub/entities/dataitem/iceberg/status.py +9 -0
  95. digitalhub/entities/dataitem/table/__init__.py +0 -0
  96. digitalhub/entities/dataitem/table/builder.py +18 -0
  97. digitalhub/entities/dataitem/table/entity.py +146 -0
  98. digitalhub/entities/dataitem/table/models.py +62 -0
  99. digitalhub/entities/dataitem/table/spec.py +25 -0
  100. digitalhub/entities/dataitem/table/status.py +9 -0
  101. digitalhub/entities/function/__init__.py +0 -0
  102. digitalhub/entities/function/_base/__init__.py +0 -0
  103. digitalhub/entities/function/_base/builder.py +79 -0
  104. digitalhub/entities/function/_base/entity.py +98 -0
  105. digitalhub/entities/function/_base/models.py +118 -0
  106. digitalhub/entities/function/_base/spec.py +15 -0
  107. digitalhub/entities/function/_base/status.py +9 -0
  108. digitalhub/entities/function/crud.py +279 -0
  109. digitalhub/entities/model/__init__.py +0 -0
  110. digitalhub/entities/model/_base/__init__.py +0 -0
  111. digitalhub/entities/model/_base/builder.py +86 -0
  112. digitalhub/entities/model/_base/entity.py +34 -0
  113. digitalhub/entities/model/_base/spec.py +49 -0
  114. digitalhub/entities/model/_base/status.py +9 -0
  115. digitalhub/entities/model/crud.py +331 -0
  116. digitalhub/entities/model/huggingface/__init__.py +0 -0
  117. digitalhub/entities/model/huggingface/builder.py +18 -0
  118. digitalhub/entities/model/huggingface/entity.py +32 -0
  119. digitalhub/entities/model/huggingface/spec.py +36 -0
  120. digitalhub/entities/model/huggingface/status.py +9 -0
  121. digitalhub/entities/model/mlflow/__init__.py +0 -0
  122. digitalhub/entities/model/mlflow/builder.py +18 -0
  123. digitalhub/entities/model/mlflow/entity.py +32 -0
  124. digitalhub/entities/model/mlflow/models.py +26 -0
  125. digitalhub/entities/model/mlflow/spec.py +44 -0
  126. digitalhub/entities/model/mlflow/status.py +9 -0
  127. digitalhub/entities/model/mlflow/utils.py +81 -0
  128. digitalhub/entities/model/model/__init__.py +0 -0
  129. digitalhub/entities/model/model/builder.py +18 -0
  130. digitalhub/entities/model/model/entity.py +32 -0
  131. digitalhub/entities/model/model/spec.py +15 -0
  132. digitalhub/entities/model/model/status.py +9 -0
  133. digitalhub/entities/model/sklearn/__init__.py +0 -0
  134. digitalhub/entities/model/sklearn/builder.py +18 -0
  135. digitalhub/entities/model/sklearn/entity.py +32 -0
  136. digitalhub/entities/model/sklearn/spec.py +15 -0
  137. digitalhub/entities/model/sklearn/status.py +9 -0
  138. digitalhub/entities/project/__init__.py +0 -0
  139. digitalhub/entities/project/_base/__init__.py +0 -0
  140. digitalhub/entities/project/_base/builder.py +128 -0
  141. digitalhub/entities/project/_base/entity.py +2078 -0
  142. digitalhub/entities/project/_base/spec.py +50 -0
  143. digitalhub/entities/project/_base/status.py +9 -0
  144. digitalhub/entities/project/crud.py +357 -0
  145. digitalhub/entities/run/__init__.py +0 -0
  146. digitalhub/entities/run/_base/__init__.py +0 -0
  147. digitalhub/entities/run/_base/builder.py +94 -0
  148. digitalhub/entities/run/_base/entity.py +307 -0
  149. digitalhub/entities/run/_base/spec.py +50 -0
  150. digitalhub/entities/run/_base/status.py +9 -0
  151. digitalhub/entities/run/crud.py +219 -0
  152. digitalhub/entities/secret/__init__.py +0 -0
  153. digitalhub/entities/secret/_base/__init__.py +0 -0
  154. digitalhub/entities/secret/_base/builder.py +81 -0
  155. digitalhub/entities/secret/_base/entity.py +74 -0
  156. digitalhub/entities/secret/_base/spec.py +35 -0
  157. digitalhub/entities/secret/_base/status.py +9 -0
  158. digitalhub/entities/secret/crud.py +290 -0
  159. digitalhub/entities/task/__init__.py +0 -0
  160. digitalhub/entities/task/_base/__init__.py +0 -0
  161. digitalhub/entities/task/_base/builder.py +91 -0
  162. digitalhub/entities/task/_base/entity.py +136 -0
  163. digitalhub/entities/task/_base/models.py +208 -0
  164. digitalhub/entities/task/_base/spec.py +53 -0
  165. digitalhub/entities/task/_base/status.py +9 -0
  166. digitalhub/entities/task/crud.py +228 -0
  167. digitalhub/entities/utils/__init__.py +0 -0
  168. digitalhub/entities/utils/api.py +346 -0
  169. digitalhub/entities/utils/entity_types.py +19 -0
  170. digitalhub/entities/utils/state.py +31 -0
  171. digitalhub/entities/utils/utils.py +202 -0
  172. digitalhub/entities/workflow/__init__.py +0 -0
  173. digitalhub/entities/workflow/_base/__init__.py +0 -0
  174. digitalhub/entities/workflow/_base/builder.py +79 -0
  175. digitalhub/entities/workflow/_base/entity.py +74 -0
  176. digitalhub/entities/workflow/_base/spec.py +15 -0
  177. digitalhub/entities/workflow/_base/status.py +9 -0
  178. digitalhub/entities/workflow/crud.py +278 -0
  179. digitalhub/factory/__init__.py +0 -0
  180. digitalhub/factory/api.py +277 -0
  181. digitalhub/factory/factory.py +268 -0
  182. digitalhub/factory/utils.py +90 -0
  183. digitalhub/readers/__init__.py +0 -0
  184. digitalhub/readers/_base/__init__.py +0 -0
  185. digitalhub/readers/_base/builder.py +26 -0
  186. digitalhub/readers/_base/reader.py +70 -0
  187. digitalhub/readers/api.py +80 -0
  188. digitalhub/readers/factory.py +133 -0
  189. digitalhub/readers/pandas/__init__.py +0 -0
  190. digitalhub/readers/pandas/builder.py +29 -0
  191. digitalhub/readers/pandas/reader.py +207 -0
  192. digitalhub/runtimes/__init__.py +0 -0
  193. digitalhub/runtimes/_base.py +102 -0
  194. digitalhub/runtimes/builder.py +32 -0
  195. digitalhub/stores/__init__.py +0 -0
  196. digitalhub/stores/_base/__init__.py +0 -0
  197. digitalhub/stores/_base/store.py +189 -0
  198. digitalhub/stores/api.py +54 -0
  199. digitalhub/stores/builder.py +211 -0
  200. digitalhub/stores/local/__init__.py +0 -0
  201. digitalhub/stores/local/store.py +230 -0
  202. digitalhub/stores/remote/__init__.py +0 -0
  203. digitalhub/stores/remote/store.py +143 -0
  204. digitalhub/stores/s3/__init__.py +0 -0
  205. digitalhub/stores/s3/store.py +563 -0
  206. digitalhub/stores/sql/__init__.py +0 -0
  207. digitalhub/stores/sql/store.py +328 -0
  208. digitalhub/utils/__init__.py +0 -0
  209. digitalhub/utils/data_utils.py +127 -0
  210. digitalhub/utils/exceptions.py +67 -0
  211. digitalhub/utils/file_utils.py +204 -0
  212. digitalhub/utils/generic_utils.py +183 -0
  213. digitalhub/utils/git_utils.py +148 -0
  214. digitalhub/utils/io_utils.py +116 -0
  215. digitalhub/utils/logger.py +17 -0
  216. digitalhub/utils/s3_utils.py +58 -0
  217. digitalhub/utils/uri_utils.py +56 -0
  218. {digitalhub-0.7.0b2.dist-info → digitalhub-0.8.0.dist-info}/METADATA +30 -13
  219. digitalhub-0.8.0.dist-info/RECORD +231 -0
  220. {digitalhub-0.7.0b2.dist-info → digitalhub-0.8.0.dist-info}/WHEEL +1 -1
  221. test/local/CRUD/test_artifacts.py +96 -0
  222. test/local/CRUD/test_dataitems.py +96 -0
  223. test/local/CRUD/test_models.py +95 -0
  224. test/test_crud_functions.py +1 -1
  225. test/test_crud_runs.py +1 -1
  226. test/test_crud_tasks.py +1 -1
  227. digitalhub-0.7.0b2.dist-info/RECORD +0 -14
  228. test/test_crud_artifacts.py +0 -96
  229. test/test_crud_dataitems.py +0 -96
  230. {digitalhub-0.7.0b2.dist-info → digitalhub-0.8.0.dist-info}/LICENSE.txt +0 -0
  231. {digitalhub-0.7.0b2.dist-info → digitalhub-0.8.0.dist-info}/top_level.txt +0 -0
  232. /test/{test_imports.py → local/imports/test_imports.py} +0 -0
@@ -0,0 +1,183 @@
1
+ from __future__ import annotations
2
+
3
+ import base64
4
+ import json
5
+ from datetime import datetime
6
+ from pathlib import Path
7
+ from typing import Any
8
+ from zipfile import ZipFile
9
+
10
+ import numpy as np
11
+ from requests import get as requests_get
12
+ from slugify import slugify
13
+
14
+ from digitalhub.utils.io_utils import read_text
15
+
16
+
17
+ def get_timestamp() -> str:
18
+ """
19
+ Get the current timestamp timezoned.
20
+
21
+ Returns
22
+ -------
23
+ str
24
+ The current timestamp.
25
+ """
26
+ return datetime.now().astimezone().isoformat()
27
+
28
+
29
+ def decode_string(string: str) -> str:
30
+ """
31
+ Decode a string from base64.
32
+
33
+ Parameters
34
+ ----------
35
+ string : str
36
+ The string to decode.
37
+
38
+ Returns
39
+ -------
40
+ str
41
+ The string decoded from base64.
42
+ """
43
+ return base64.b64decode(string).decode()
44
+
45
+
46
+ def encode_string(string: str) -> str:
47
+ """
48
+ Encode a string in base64.
49
+
50
+ Parameters
51
+ ----------
52
+ string : str
53
+ The string to encode.
54
+
55
+ Returns
56
+ -------
57
+ str
58
+ The string encoded in base64.
59
+ """
60
+ return base64.b64encode(string.encode()).decode()
61
+
62
+
63
+ def encode_source(path: str) -> str:
64
+ """
65
+ Read a file and encode in base64 the content.
66
+
67
+ Parameters
68
+ ----------
69
+ path : str
70
+ The file path to read.
71
+
72
+ Returns
73
+ -------
74
+ str
75
+ The file content encoded in base64.
76
+ """
77
+ return encode_string(read_text(path))
78
+
79
+
80
+ def requests_chunk_download(source: str, filename: Path) -> None:
81
+ """
82
+ Download a file in chunks.
83
+
84
+ Parameters
85
+ ----------
86
+ source : str
87
+ URL to download the file.
88
+ filename : Path
89
+ Path where to save the file.
90
+
91
+ Returns
92
+ -------
93
+ None
94
+ """
95
+ with requests_get(source, stream=True) as r:
96
+ r.raise_for_status()
97
+ with filename.open("wb") as f:
98
+ for chunk in r.iter_content(chunk_size=8192):
99
+ f.write(chunk)
100
+
101
+
102
+ def extract_archive(path: Path, filename: Path) -> None:
103
+ """
104
+ Extract a zip archive.
105
+
106
+ Parameters
107
+ ----------
108
+ path : Path
109
+ Path where to extract the archive.
110
+ filename : Path
111
+ Path to the archive.
112
+
113
+ Returns
114
+ -------
115
+ None
116
+ """
117
+ with ZipFile(filename, "r") as zip_file:
118
+ zip_file.extractall(path)
119
+
120
+
121
+ class MyEncoder(json.JSONEncoder):
122
+ """
123
+ Custom JSON encoder to handle numpy types.
124
+ """
125
+
126
+ def default(self, obj: Any) -> Any:
127
+ """
128
+ Convert numpy types to json.
129
+
130
+ Parameters
131
+ ----------
132
+ obj : Any
133
+ The object to convert.
134
+
135
+ Returns
136
+ -------
137
+ Any
138
+ The object converted to json.
139
+ """
140
+ if isinstance(obj, (int, str, float, list, dict)):
141
+ return obj
142
+ elif isinstance(obj, (np.integer, np.int64)):
143
+ return int(obj)
144
+ elif isinstance(obj, (np.floating, np.float64)):
145
+ return float(obj)
146
+ elif isinstance(obj, np.ndarray):
147
+ return obj.tolist()
148
+ else:
149
+ return str(obj)
150
+
151
+
152
+ def dict_to_json(struct: dict) -> str:
153
+ """
154
+ Convert a dict to json.
155
+
156
+ Parameters
157
+ ----------
158
+ struct : dict
159
+ The dict to convert.
160
+
161
+ Returns
162
+ -------
163
+ str
164
+ The json string.
165
+ """
166
+ return json.dumps(struct, cls=MyEncoder)
167
+
168
+
169
+ def slugify_string(filename: str) -> str:
170
+ """
171
+ Sanitize a filename.
172
+
173
+ Parameters
174
+ ----------
175
+ filename : str
176
+ The filename to sanitize.
177
+
178
+ Returns
179
+ -------
180
+ str
181
+ The sanitized filename.
182
+ """
183
+ return slugify(filename, max_length=255)
@@ -0,0 +1,148 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ import shutil
5
+ import warnings
6
+ from pathlib import Path
7
+ from urllib.parse import urlparse
8
+
9
+ try:
10
+ from git import Repo
11
+ except ImportError as e:
12
+ if "Bad git executable." in e.args[0]:
13
+ warnings.warn("git is not installed. Please install git and try again.", RuntimeWarning)
14
+
15
+
16
+ def clone_repository(url: str, path: Path) -> None:
17
+ """
18
+ Clone git repository.
19
+
20
+ Parameters
21
+ ----------
22
+ url : str
23
+ URL of the repository.
24
+ path : Path
25
+ Path where to save the repository.
26
+
27
+ Returns
28
+ -------
29
+ None
30
+ """
31
+ clean_path(path)
32
+ checkout_object = get_checkout_object(url)
33
+ url = add_credentials_git_remote_url(url)
34
+ repo = clone_from_url(url, path)
35
+ if checkout_object != "":
36
+ repo.git.checkout(checkout_object)
37
+
38
+
39
+ def get_checkout_object(url: str) -> str:
40
+ """
41
+ Get checkout object from url fragment.
42
+
43
+ Parameters
44
+ ----------
45
+ url : str
46
+ URL of the repository.
47
+
48
+ Returns
49
+ -------
50
+ str
51
+ Checkout object (branch, tag, commit).
52
+ """
53
+ return urlparse(url).fragment
54
+
55
+
56
+ def clean_path(path: Path) -> None:
57
+ """
58
+ Clean path from any files.
59
+
60
+ Parameters
61
+ ----------
62
+ path : Path
63
+
64
+ Returns
65
+ -------
66
+ None
67
+ """
68
+
69
+ shutil.rmtree(path, ignore_errors=True)
70
+
71
+
72
+ def get_git_username_password_from_token(token: str) -> tuple[str, str]:
73
+ """
74
+ Parse token to get username and password. The token
75
+ can be one of the following:
76
+
77
+ - GitHub/GitLab personal access token (github_pat_.../glpat...)
78
+ - GitHub/GitLab access token
79
+ - Other generic token
80
+
81
+ Parameters
82
+ ----------
83
+ token : str
84
+ Token to parse.
85
+
86
+ Returns
87
+ -------
88
+ tuple[str, str]
89
+ Username and password.
90
+ """
91
+ # Mutued from mlrun
92
+ if token.startswith("github_pat_") or token.startswith("glpat"):
93
+ username = "oauth2"
94
+ password = token
95
+ else:
96
+ username = token
97
+ password = "x-oauth-basic"
98
+ return username, password
99
+
100
+
101
+ def add_credentials_git_remote_url(url: str) -> str:
102
+ """
103
+ Add credentials to git remote url.
104
+
105
+ Parameters
106
+ ----------
107
+ url : str
108
+ URL of the repository.
109
+
110
+ Returns
111
+ -------
112
+ str
113
+ URL with credentials.
114
+ """
115
+ url_obj = urlparse(url)
116
+
117
+ # Get credentials from environment variables
118
+ username = os.getenv("GIT_USERNAME")
119
+ password = os.getenv("GIT_PASSWORD")
120
+ token = os.getenv("GIT_TOKEN")
121
+
122
+ # Get credentials from token. Override username and password
123
+ if token is not None:
124
+ username, password = get_git_username_password_from_token(token)
125
+
126
+ # Add credentials to url if needed
127
+ if username is not None and password is not None:
128
+ return f"https://{username}:{password}@{url_obj.hostname}{url_obj.path}"
129
+ return f"https://{url_obj.hostname}{url_obj.path}"
130
+
131
+
132
+ def clone_from_url(url: str, path: Path) -> Repo:
133
+ """
134
+ Clone repository from url. Wraps git.Repo.clone_from.
135
+
136
+ Parameters
137
+ ----------
138
+ url : str
139
+ HTTP(S) URL of the repository.
140
+ path : Path
141
+ Path where to save the repository.
142
+
143
+ Returns
144
+ -------
145
+ Repo
146
+ Cloned repository.
147
+ """
148
+ return Repo.clone_from(url=url, to_path=path)
@@ -0,0 +1,116 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+ import yaml
6
+
7
+ ##############################
8
+ # Writers
9
+ ##############################
10
+
11
+
12
+ def write_yaml(filepath: str | Path, obj: dict | list[dict]) -> None:
13
+ """
14
+ Write a dict or a list of dict to a yaml file.
15
+
16
+ Parameters
17
+ ----------
18
+ filepath : str | Path
19
+ The yaml file path to write.
20
+ obj : dict
21
+ The dict to write.
22
+
23
+ Returns
24
+ -------
25
+ None
26
+ """
27
+ if isinstance(obj, list):
28
+ with open(filepath, "w", encoding="utf-8") as out_file:
29
+ yaml.dump_all(obj, out_file, sort_keys=False, default_flow_style=False)
30
+ else:
31
+ with open(filepath, "w", encoding="utf-8") as out_file:
32
+ yaml.dump(obj, out_file, sort_keys=False)
33
+
34
+
35
+ ##############################
36
+ # Readers
37
+ ##############################
38
+
39
+
40
+ class NoDatesSafeLoader(yaml.SafeLoader):
41
+ """
42
+ Loader implementation to exclude implicit resolvers.
43
+
44
+ Taken from https://stackoverflow.com/a/37958106
45
+ """
46
+
47
+ @classmethod
48
+ def remove_implicit_resolver(cls, tag_to_remove: str) -> None:
49
+ """
50
+ Remove implicit resolvers for a particular tag
51
+ Takes care not to modify resolvers in super classes.
52
+ We want to load datetimes as strings, not dates, because we
53
+ go on to serialise as json which doesn't have the advanced types
54
+ of yaml, and leads to incompatibilities down the track.
55
+
56
+ Parameters
57
+ ----------
58
+ tag_to_remove : str
59
+ The tag to remove
60
+
61
+ Returns
62
+ -------
63
+ None
64
+ """
65
+ if "yaml_implicit_resolvers" not in cls.__dict__:
66
+ cls.yaml_implicit_resolvers = cls.yaml_implicit_resolvers.copy()
67
+
68
+ for first_letter, mappings in cls.yaml_implicit_resolvers.items():
69
+ cls.yaml_implicit_resolvers[first_letter] = [
70
+ (tag, regexp) for tag, regexp in mappings if tag != tag_to_remove
71
+ ]
72
+
73
+
74
+ NoDatesSafeLoader.remove_implicit_resolver("tag:yaml.org,2002:timestamp")
75
+
76
+
77
+ def read_yaml(filepath: str | Path) -> dict | list[dict]:
78
+ """
79
+ Read a yaml file and return a dict or a list of dict.
80
+
81
+ Parameters
82
+ ----------
83
+ filepath : str | Path
84
+ The yaml file path to read.
85
+
86
+ Returns
87
+ -------
88
+ dict | list[dict]
89
+ The yaml file content.
90
+ """
91
+ try:
92
+ with open(filepath, "r", encoding="utf-8") as in_file:
93
+ data = yaml.load(in_file, Loader=NoDatesSafeLoader)
94
+
95
+ # If yaml contains multiple documents
96
+ except yaml.composer.ComposerError:
97
+ with open(filepath, "r", encoding="utf-8") as in_file:
98
+ data = list(yaml.load_all(in_file, Loader=NoDatesSafeLoader))
99
+ return data
100
+
101
+
102
+ def read_text(filepath: str | Path) -> str:
103
+ """
104
+ Read a file and return the text.
105
+
106
+ Parameters
107
+ ----------
108
+ filepath : str | Path
109
+ The file path to read.
110
+
111
+ Returns
112
+ -------
113
+ str
114
+ The file content.
115
+ """
116
+ return Path(filepath).read_text(encoding="utf-8")
@@ -0,0 +1,17 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+
5
+ # Create logger
6
+ LOGGER = logging.getLogger("digitalhub-core")
7
+ LOGGER.setLevel(logging.INFO)
8
+
9
+ # Create formatter
10
+ formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
11
+
12
+ # Create console handler and set formatter
13
+ console_handler = logging.StreamHandler()
14
+ console_handler.setFormatter(formatter)
15
+
16
+ # Set console handler to the logger
17
+ LOGGER.addHandler(console_handler)
@@ -0,0 +1,58 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from pathlib import Path
5
+ from urllib.parse import urlparse
6
+
7
+ from boto3 import client as boto3_client
8
+
9
+
10
+ def get_bucket_and_key(path: str) -> tuple[str, str]:
11
+ """
12
+ Get bucket and key from path.
13
+
14
+ Parameters
15
+ ----------
16
+ path : str
17
+ The source path to get the key from.
18
+
19
+ Returns
20
+ -------
21
+ tuple[str, str]
22
+ The bucket and key.
23
+ """
24
+ parsed = urlparse(path)
25
+ return parsed.netloc, parsed.path
26
+
27
+
28
+ def get_s3_source(bucket: str, key: str, filename: Path) -> None:
29
+ """
30
+ Get S3 source.
31
+
32
+ Parameters
33
+ ----------
34
+ bucket : str
35
+ S3 bucket name.
36
+ key : str
37
+ S3 object key.
38
+ filename : Path
39
+ Path where to save the function source.
40
+
41
+ Returns
42
+ -------
43
+ None
44
+ """
45
+ s3 = boto3_client("s3", endpoint_url=os.getenv("S3_ENDPOINT_URL"))
46
+ s3.download_file(bucket, key, filename)
47
+
48
+
49
+ def get_s3_bucket() -> str | None:
50
+ """
51
+ Function to get S3 bucket name.
52
+
53
+ Returns
54
+ -------
55
+ str
56
+ The S3 bucket name.
57
+ """
58
+ return os.getenv("S3_BUCKET_NAME", "datalake")
@@ -0,0 +1,56 @@
1
+ from __future__ import annotations
2
+
3
+ from urllib.parse import urlparse
4
+
5
+
6
+ def map_uri_scheme(uri: str) -> str:
7
+ """
8
+ Map an URI scheme to a common scheme.
9
+
10
+ Parameters
11
+ ----------
12
+ uri : str
13
+ URI.
14
+
15
+ Returns
16
+ -------
17
+ str
18
+ Mapped scheme type.
19
+
20
+ Raises
21
+ ------
22
+ ValueError
23
+ If the scheme is unknown.
24
+ """
25
+ scheme = urlparse(uri).scheme
26
+ if scheme in [""]:
27
+ return "local"
28
+ if scheme in ["file", "local"]:
29
+ raise ValueError("For local path, do not use any scheme")
30
+ if scheme in ["http", "https"]:
31
+ return "remote"
32
+ if scheme in ["s3", "s3a", "s3n", "zip+s3"]:
33
+ return "s3"
34
+ if scheme in ["sql", "postgresql"]:
35
+ return "sql"
36
+ if scheme in ["git", "git+http", "git+https"]:
37
+ return "git"
38
+ raise ValueError(f"Unknown scheme '{scheme}'!")
39
+
40
+
41
+ def check_local_path(path: str) -> bool:
42
+ """
43
+ Check if path is local.
44
+
45
+ Parameters
46
+ ----------
47
+ path : str
48
+ Path of some source.
49
+
50
+ Returns
51
+ -------
52
+ bool
53
+ True if path is local.
54
+ """
55
+ scheme = map_uri_scheme(path)
56
+ return scheme == "local"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: digitalhub
3
- Version: 0.7.0b2
3
+ Version: 0.8.0
4
4
  Summary: Python SDK for Digitalhub
5
5
  Author-email: Fondazione Bruno Kessler <dslab@fbk.eu>, Matteo Martini <mmartini@fbk.eu>
6
6
  License: Apache License
@@ -225,25 +225,42 @@ Keywords: data,dataops,kubernetes
225
225
  Classifier: License :: OSI Approved :: Apache Software License
226
226
  Classifier: Programming Language :: Python :: 3.9
227
227
  Classifier: Programming Language :: Python :: 3.10
228
+ Classifier: Programming Language :: Python :: 3.11
228
229
  Requires-Python: >=3.9
229
230
  Description-Content-Type: text/markdown
230
231
  License-File: LICENSE.txt
231
- Requires-Dist: digitalhub-core<0.8,>=0.7.0b
232
- Provides-Extra: all
233
- Requires-Dist: digitalhub-data<0.8,>=0.7.0b; extra == "all"
234
- Requires-Dist: digitalhub-ml<0.8,>=0.7.0b; extra == "all"
235
- Provides-Extra: data
236
- Requires-Dist: digitalhub-data<0.8,>=0.7.0b; extra == "data"
232
+ Requires-Dist: boto3
233
+ Requires-Dist: pydantic<2
234
+ Requires-Dist: sqlalchemy<2
235
+ Requires-Dist: pyarrow
236
+ Requires-Dist: numpy<2
237
+ Requires-Dist: requests
238
+ Requires-Dist: PyYAML
239
+ Requires-Dist: python-dotenv
240
+ Requires-Dist: GitPython>=3
241
+ Requires-Dist: psycopg2-binary
242
+ Requires-Dist: python-slugify
243
+ Provides-Extra: dev
244
+ Requires-Dist: black; extra == "dev"
245
+ Requires-Dist: pytest; extra == "dev"
246
+ Requires-Dist: bumpver; extra == "dev"
247
+ Requires-Dist: ruff; extra == "dev"
248
+ Requires-Dist: moto; extra == "dev"
249
+ Provides-Extra: docs
250
+ Requires-Dist: Sphinx>=7; extra == "docs"
251
+ Requires-Dist: pydata-sphinx-theme>=0.15; extra == "docs"
252
+ Requires-Dist: numpydoc>=1.6; extra == "docs"
237
253
  Provides-Extra: full
238
- Requires-Dist: digitalhub-core[full]<0.8,>=0.7.0b; extra == "full"
239
- Requires-Dist: digitalhub-data[pandas]<0.8,>=0.7.0b; extra == "full"
240
- Requires-Dist: digitalhub-ml[mlflow]<0.8,>=0.7.0b; extra == "full"
241
- Provides-Extra: ml
242
- Requires-Dist: digitalhub-ml<0.8,>=0.7.0b; extra == "ml"
254
+ Requires-Dist: pandas<2.2,>=1.2; extra == "full"
255
+ Requires-Dist: mlflow; extra == "full"
256
+ Provides-Extra: mlflow
257
+ Requires-Dist: mlflow; extra == "mlflow"
258
+ Provides-Extra: pandas
259
+ Requires-Dist: pandas<2.2,>=1.2; extra == "pandas"
243
260
 
244
261
  # Digitalhub Library
245
262
 
246
263
  The Digitalhub SDK library is used to manage entities and executions in Digitalhub from Python.
247
264
  It comes with a suite of tools to help you manage your projects and executions. It exposes CRUD methods to create, read, update and delete entities, and objects methods to excute functions or workflows, collect or store execution results and data.
248
265
 
249
- A more detailed description of the library can be found in the [official documentation](https://scc-digitalhub.github.io/docs/) of Digitalhub.
266
+ A more detailed description of the library can be found in the [official documentation](https://scc-digitalhub.github.io/sdk-docs/).