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.
- digitalhub/__init__.py +1 -1
- digitalhub/context/api.py +5 -5
- digitalhub/context/builder.py +3 -5
- digitalhub/context/context.py +9 -1
- digitalhub/entities/_base/material/entity.py +3 -3
- digitalhub/entities/_commons/metrics.py +64 -30
- digitalhub/entities/_commons/utils.py +36 -9
- digitalhub/entities/_processors/base.py +150 -79
- digitalhub/entities/_processors/context.py +363 -212
- digitalhub/entities/_processors/utils.py +74 -30
- digitalhub/entities/artifact/utils.py +28 -13
- digitalhub/entities/dataitem/crud.py +10 -2
- digitalhub/entities/dataitem/table/entity.py +3 -3
- digitalhub/entities/dataitem/utils.py +84 -35
- digitalhub/entities/model/utils.py +28 -13
- digitalhub/entities/task/_base/models.py +12 -3
- digitalhub/factory/factory.py +25 -3
- digitalhub/factory/utils.py +11 -3
- digitalhub/runtimes/_base.py +1 -1
- digitalhub/runtimes/builder.py +18 -1
- digitalhub/stores/client/__init__.py +12 -0
- digitalhub/stores/client/_base/api_builder.py +14 -0
- digitalhub/stores/client/_base/client.py +93 -0
- digitalhub/stores/client/_base/key_builder.py +28 -0
- digitalhub/stores/client/_base/params_builder.py +14 -0
- digitalhub/stores/client/api.py +10 -5
- digitalhub/stores/client/builder.py +3 -1
- digitalhub/stores/client/dhcore/api_builder.py +17 -0
- digitalhub/stores/client/dhcore/client.py +276 -58
- digitalhub/stores/client/dhcore/configurator.py +336 -141
- digitalhub/stores/client/dhcore/error_parser.py +35 -1
- digitalhub/stores/client/dhcore/params_builder.py +113 -17
- digitalhub/stores/client/dhcore/utils.py +32 -14
- digitalhub/stores/client/local/api_builder.py +17 -0
- digitalhub/stores/client/local/client.py +6 -8
- digitalhub/stores/credentials/api.py +8 -8
- digitalhub/stores/credentials/configurator.py +176 -3
- digitalhub/stores/credentials/enums.py +17 -3
- digitalhub/stores/credentials/handler.py +73 -45
- digitalhub/stores/credentials/ini_module.py +59 -27
- digitalhub/stores/credentials/store.py +33 -1
- digitalhub/stores/data/_base/store.py +8 -3
- digitalhub/stores/data/api.py +20 -16
- digitalhub/stores/data/builder.py +69 -13
- digitalhub/stores/data/s3/configurator.py +64 -23
- digitalhub/stores/data/s3/store.py +30 -27
- digitalhub/stores/data/s3/utils.py +9 -9
- digitalhub/stores/data/sql/configurator.py +76 -25
- digitalhub/stores/data/sql/store.py +180 -91
- digitalhub/utils/exceptions.py +6 -0
- digitalhub/utils/file_utils.py +53 -30
- digitalhub/utils/generic_utils.py +41 -33
- digitalhub/utils/git_utils.py +24 -14
- digitalhub/utils/io_utils.py +19 -18
- digitalhub/utils/uri_utils.py +31 -31
- {digitalhub-0.13.0b2.dist-info → digitalhub-0.13.0b4.dist-info}/METADATA +1 -1
- {digitalhub-0.13.0b2.dist-info → digitalhub-0.13.0b4.dist-info}/RECORD +60 -61
- digitalhub/entities/_commons/types.py +0 -9
- {digitalhub-0.13.0b2.dist-info → digitalhub-0.13.0b4.dist-info}/WHEEL +0 -0
- {digitalhub-0.13.0b2.dist-info → digitalhub-0.13.0b4.dist-info}/licenses/AUTHORS +0 -0
- {digitalhub-0.13.0b2.dist-info → digitalhub-0.13.0b4.dist-info}/licenses/LICENSE +0 -0
digitalhub/utils/file_utils.py
CHANGED
|
@@ -16,6 +16,21 @@ from pydantic import BaseModel
|
|
|
16
16
|
class FileInfo(BaseModel):
|
|
17
17
|
"""
|
|
18
18
|
File info class.
|
|
19
|
+
|
|
20
|
+
Attributes
|
|
21
|
+
----------
|
|
22
|
+
path : str or None
|
|
23
|
+
Path to the file.
|
|
24
|
+
name : str or None
|
|
25
|
+
Name of the file.
|
|
26
|
+
content_type : str or None
|
|
27
|
+
MIME type of the file.
|
|
28
|
+
size : int or None
|
|
29
|
+
Size of the file in bytes.
|
|
30
|
+
hash : str or None
|
|
31
|
+
Hash of the file contents.
|
|
32
|
+
last_modified : str or None
|
|
33
|
+
Last modified date/time in ISO format.
|
|
19
34
|
"""
|
|
20
35
|
|
|
21
36
|
path: Optional[str] = None
|
|
@@ -25,13 +40,21 @@ class FileInfo(BaseModel):
|
|
|
25
40
|
hash: Optional[str] = None
|
|
26
41
|
last_modified: Optional[str] = None
|
|
27
42
|
|
|
28
|
-
def to_dict(self):
|
|
43
|
+
def to_dict(self) -> dict:
|
|
44
|
+
"""
|
|
45
|
+
Convert FileInfo to dictionary.
|
|
46
|
+
|
|
47
|
+
Returns
|
|
48
|
+
-------
|
|
49
|
+
dict
|
|
50
|
+
Dictionary representation of the FileInfo object.
|
|
51
|
+
"""
|
|
29
52
|
return self.model_dump()
|
|
30
53
|
|
|
31
54
|
|
|
32
55
|
def calculate_blob_hash(data_path: str) -> str:
|
|
33
56
|
"""
|
|
34
|
-
Calculate the hash of a file.
|
|
57
|
+
Calculate the SHA-256 hash of a file.
|
|
35
58
|
|
|
36
59
|
Parameters
|
|
37
60
|
----------
|
|
@@ -41,7 +64,7 @@ def calculate_blob_hash(data_path: str) -> str:
|
|
|
41
64
|
Returns
|
|
42
65
|
-------
|
|
43
66
|
str
|
|
44
|
-
The hash of the file.
|
|
67
|
+
The SHA-256 hash of the file, prefixed with 'sha256:'.
|
|
45
68
|
"""
|
|
46
69
|
with open(data_path, "rb") as f:
|
|
47
70
|
data = f.read()
|
|
@@ -50,7 +73,7 @@ def calculate_blob_hash(data_path: str) -> str:
|
|
|
50
73
|
|
|
51
74
|
def get_file_size(data_path: str) -> int:
|
|
52
75
|
"""
|
|
53
|
-
Get the size of a file.
|
|
76
|
+
Get the size of a file in bytes.
|
|
54
77
|
|
|
55
78
|
Parameters
|
|
56
79
|
----------
|
|
@@ -60,14 +83,14 @@ def get_file_size(data_path: str) -> int:
|
|
|
60
83
|
Returns
|
|
61
84
|
-------
|
|
62
85
|
int
|
|
63
|
-
|
|
86
|
+
Size of the file in bytes.
|
|
64
87
|
"""
|
|
65
88
|
return Path(data_path).stat().st_size
|
|
66
89
|
|
|
67
90
|
|
|
68
91
|
def get_file_mime_type(data_path: str) -> str | None:
|
|
69
92
|
"""
|
|
70
|
-
Get the
|
|
93
|
+
Get the MIME type of a file.
|
|
71
94
|
|
|
72
95
|
Parameters
|
|
73
96
|
----------
|
|
@@ -76,15 +99,15 @@ def get_file_mime_type(data_path: str) -> str | None:
|
|
|
76
99
|
|
|
77
100
|
Returns
|
|
78
101
|
-------
|
|
79
|
-
str
|
|
80
|
-
The
|
|
102
|
+
str or None
|
|
103
|
+
The MIME type of the file, or None if unknown.
|
|
81
104
|
"""
|
|
82
105
|
return guess_type(data_path)[0]
|
|
83
106
|
|
|
84
107
|
|
|
85
108
|
def get_path_name(data_path: str) -> str:
|
|
86
109
|
"""
|
|
87
|
-
Get the name of a file.
|
|
110
|
+
Get the name of a file from its path.
|
|
88
111
|
|
|
89
112
|
Parameters
|
|
90
113
|
----------
|
|
@@ -101,7 +124,7 @@ def get_path_name(data_path: str) -> str:
|
|
|
101
124
|
|
|
102
125
|
def get_last_modified(data_path: str) -> str:
|
|
103
126
|
"""
|
|
104
|
-
Get the last modified date of a file.
|
|
127
|
+
Get the last modified date/time of a file in ISO format.
|
|
105
128
|
|
|
106
129
|
Parameters
|
|
107
130
|
----------
|
|
@@ -111,7 +134,7 @@ def get_last_modified(data_path: str) -> str:
|
|
|
111
134
|
Returns
|
|
112
135
|
-------
|
|
113
136
|
str
|
|
114
|
-
The last modified date
|
|
137
|
+
The last modified date/time in ISO format.
|
|
115
138
|
"""
|
|
116
139
|
path = Path(data_path)
|
|
117
140
|
timestamp = path.stat().st_mtime
|
|
@@ -120,7 +143,7 @@ def get_last_modified(data_path: str) -> str:
|
|
|
120
143
|
|
|
121
144
|
def get_s3_path(src_path: str) -> str:
|
|
122
145
|
"""
|
|
123
|
-
Get the S3
|
|
146
|
+
Get the S3 URI of a file path.
|
|
124
147
|
|
|
125
148
|
Parameters
|
|
126
149
|
----------
|
|
@@ -130,26 +153,26 @@ def get_s3_path(src_path: str) -> str:
|
|
|
130
153
|
Returns
|
|
131
154
|
-------
|
|
132
155
|
str
|
|
133
|
-
The S3
|
|
156
|
+
The S3 URI of the file.
|
|
134
157
|
"""
|
|
135
158
|
return Path(src_path).as_uri()
|
|
136
159
|
|
|
137
160
|
|
|
138
161
|
def get_file_info_from_local(path: str, src_path: str) -> None | dict:
|
|
139
162
|
"""
|
|
140
|
-
Get file info from path.
|
|
163
|
+
Get file info from a local path.
|
|
141
164
|
|
|
142
165
|
Parameters
|
|
143
166
|
----------
|
|
144
167
|
path : str
|
|
145
168
|
Target path of the object.
|
|
146
169
|
src_path : str
|
|
147
|
-
Local path of
|
|
170
|
+
Local path of the source file.
|
|
148
171
|
|
|
149
172
|
Returns
|
|
150
173
|
-------
|
|
151
|
-
dict
|
|
152
|
-
File info.
|
|
174
|
+
dict or None
|
|
175
|
+
File info dictionary, or None if an error occurs.
|
|
153
176
|
"""
|
|
154
177
|
try:
|
|
155
178
|
name = get_path_name(path)
|
|
@@ -172,19 +195,19 @@ def get_file_info_from_local(path: str, src_path: str) -> None | dict:
|
|
|
172
195
|
|
|
173
196
|
def get_file_info_from_s3(path: str, metadata: dict) -> None | dict:
|
|
174
197
|
"""
|
|
175
|
-
Get file info from
|
|
198
|
+
Get file info from S3 metadata.
|
|
176
199
|
|
|
177
200
|
Parameters
|
|
178
201
|
----------
|
|
179
202
|
path : str
|
|
180
203
|
Object source path.
|
|
181
204
|
metadata : dict
|
|
182
|
-
Metadata of the object from S3.
|
|
205
|
+
Metadata dictionary of the object from S3.
|
|
183
206
|
|
|
184
207
|
Returns
|
|
185
208
|
-------
|
|
186
|
-
dict
|
|
187
|
-
File info.
|
|
209
|
+
dict or None
|
|
210
|
+
File info dictionary, or None if an error occurs.
|
|
188
211
|
"""
|
|
189
212
|
try:
|
|
190
213
|
size = metadata["ContentLength"]
|
|
@@ -214,17 +237,17 @@ def get_file_info_from_s3(path: str, metadata: dict) -> None | dict:
|
|
|
214
237
|
|
|
215
238
|
def eval_zip_type(source: str) -> bool:
|
|
216
239
|
"""
|
|
217
|
-
Evaluate zip
|
|
240
|
+
Evaluate whether the source is a zip file.
|
|
218
241
|
|
|
219
242
|
Parameters
|
|
220
243
|
----------
|
|
221
244
|
source : str
|
|
222
|
-
Source.
|
|
245
|
+
Source file path.
|
|
223
246
|
|
|
224
247
|
Returns
|
|
225
248
|
-------
|
|
226
249
|
bool
|
|
227
|
-
True if path is zip.
|
|
250
|
+
True if the path is a zip file, False otherwise.
|
|
228
251
|
"""
|
|
229
252
|
extension = source.endswith(".zip")
|
|
230
253
|
mime_zip = get_file_mime_type(source) == "application/zip"
|
|
@@ -233,34 +256,34 @@ def eval_zip_type(source: str) -> bool:
|
|
|
233
256
|
|
|
234
257
|
def eval_text_type(source: str) -> bool:
|
|
235
258
|
"""
|
|
236
|
-
Evaluate text
|
|
259
|
+
Evaluate whether the source is a plain text file.
|
|
237
260
|
|
|
238
261
|
Parameters
|
|
239
262
|
----------
|
|
240
263
|
source : str
|
|
241
|
-
Source.
|
|
264
|
+
Source file path.
|
|
242
265
|
|
|
243
266
|
Returns
|
|
244
267
|
-------
|
|
245
268
|
bool
|
|
246
|
-
True if path is text.
|
|
269
|
+
True if the path is a plain text file, False otherwise.
|
|
247
270
|
"""
|
|
248
271
|
return get_file_mime_type(source) == "text/plain"
|
|
249
272
|
|
|
250
273
|
|
|
251
274
|
def eval_py_type(source: str) -> bool:
|
|
252
275
|
"""
|
|
253
|
-
Evaluate
|
|
276
|
+
Evaluate whether the source is a Python file.
|
|
254
277
|
|
|
255
278
|
Parameters
|
|
256
279
|
----------
|
|
257
280
|
source : str
|
|
258
|
-
Source.
|
|
281
|
+
Source file path.
|
|
259
282
|
|
|
260
283
|
Returns
|
|
261
284
|
-------
|
|
262
285
|
bool
|
|
263
|
-
True if path is
|
|
286
|
+
True if the path is a Python file, False otherwise.
|
|
264
287
|
"""
|
|
265
288
|
extension = source.endswith(".py")
|
|
266
289
|
mime_py = get_file_mime_type(source) == "text/x-python"
|
|
@@ -24,29 +24,29 @@ from digitalhub.utils.io_utils import read_text
|
|
|
24
24
|
|
|
25
25
|
def get_timestamp() -> str:
|
|
26
26
|
"""
|
|
27
|
-
Get the current timestamp
|
|
27
|
+
Get the current timestamp in ISO format with timezone.
|
|
28
28
|
|
|
29
29
|
Returns
|
|
30
30
|
-------
|
|
31
31
|
str
|
|
32
|
-
The current timestamp.
|
|
32
|
+
The current timestamp in ISO format with timezone.
|
|
33
33
|
"""
|
|
34
34
|
return datetime.now().astimezone().isoformat()
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
def decode_base64_string(string: str) -> str:
|
|
38
38
|
"""
|
|
39
|
-
Decode a string from base64.
|
|
39
|
+
Decode a string from base64 encoding.
|
|
40
40
|
|
|
41
41
|
Parameters
|
|
42
42
|
----------
|
|
43
43
|
string : str
|
|
44
|
-
The string to decode.
|
|
44
|
+
The base64-encoded string to decode.
|
|
45
45
|
|
|
46
46
|
Returns
|
|
47
47
|
-------
|
|
48
48
|
str
|
|
49
|
-
The
|
|
49
|
+
The decoded string.
|
|
50
50
|
"""
|
|
51
51
|
return base64.b64decode(string).decode()
|
|
52
52
|
|
|
@@ -63,14 +63,14 @@ def encode_string(string: str) -> str:
|
|
|
63
63
|
Returns
|
|
64
64
|
-------
|
|
65
65
|
str
|
|
66
|
-
The
|
|
66
|
+
The base64-encoded string.
|
|
67
67
|
"""
|
|
68
68
|
return base64.b64encode(string.encode()).decode()
|
|
69
69
|
|
|
70
70
|
|
|
71
71
|
def encode_source(path: str) -> str:
|
|
72
72
|
"""
|
|
73
|
-
Read a file and encode in base64
|
|
73
|
+
Read a file and encode its content in base64.
|
|
74
74
|
|
|
75
75
|
Parameters
|
|
76
76
|
----------
|
|
@@ -87,14 +87,14 @@ def encode_source(path: str) -> str:
|
|
|
87
87
|
|
|
88
88
|
def requests_chunk_download(source: str, filename: Path) -> None:
|
|
89
89
|
"""
|
|
90
|
-
Download a file in chunks.
|
|
90
|
+
Download a file from a URL in chunks and save to disk.
|
|
91
91
|
|
|
92
92
|
Parameters
|
|
93
93
|
----------
|
|
94
94
|
source : str
|
|
95
|
-
URL to download the file.
|
|
95
|
+
URL to download the file from.
|
|
96
96
|
filename : Path
|
|
97
|
-
Path where to save the file.
|
|
97
|
+
Path where to save the downloaded file.
|
|
98
98
|
|
|
99
99
|
Returns
|
|
100
100
|
-------
|
|
@@ -109,14 +109,14 @@ def requests_chunk_download(source: str, filename: Path) -> None:
|
|
|
109
109
|
|
|
110
110
|
def extract_archive(path: Path, filename: Path) -> None:
|
|
111
111
|
"""
|
|
112
|
-
Extract a zip archive.
|
|
112
|
+
Extract a zip archive to a specified directory.
|
|
113
113
|
|
|
114
114
|
Parameters
|
|
115
115
|
----------
|
|
116
116
|
path : Path
|
|
117
|
-
|
|
117
|
+
Directory where to extract the archive.
|
|
118
118
|
filename : Path
|
|
119
|
-
Path to the archive.
|
|
119
|
+
Path to the zip archive file.
|
|
120
120
|
|
|
121
121
|
Returns
|
|
122
122
|
-------
|
|
@@ -128,12 +128,12 @@ def extract_archive(path: Path, filename: Path) -> None:
|
|
|
128
128
|
|
|
129
129
|
class CustomJsonEncoder(json.JSONEncoder):
|
|
130
130
|
"""
|
|
131
|
-
Custom JSON encoder to handle
|
|
131
|
+
Custom JSON encoder to handle serialization of special types.
|
|
132
132
|
"""
|
|
133
133
|
|
|
134
134
|
def default(self, obj: Any) -> Any:
|
|
135
135
|
"""
|
|
136
|
-
Convert an object to
|
|
136
|
+
Convert an object to a JSON-serializable format.
|
|
137
137
|
|
|
138
138
|
Parameters
|
|
139
139
|
----------
|
|
@@ -143,7 +143,7 @@ class CustomJsonEncoder(json.JSONEncoder):
|
|
|
143
143
|
Returns
|
|
144
144
|
-------
|
|
145
145
|
Any
|
|
146
|
-
The object converted to
|
|
146
|
+
The object converted to a JSON-serializable format.
|
|
147
147
|
"""
|
|
148
148
|
if isinstance(obj, (int, str, float, list, dict)):
|
|
149
149
|
return obj
|
|
@@ -160,24 +160,24 @@ class CustomJsonEncoder(json.JSONEncoder):
|
|
|
160
160
|
|
|
161
161
|
def dump_json(struct: Any) -> str:
|
|
162
162
|
"""
|
|
163
|
-
Convert a
|
|
163
|
+
Convert a Python object to a JSON string using CustomJsonEncoder.
|
|
164
164
|
|
|
165
165
|
Parameters
|
|
166
166
|
----------
|
|
167
|
-
struct :
|
|
168
|
-
The
|
|
167
|
+
struct : Any
|
|
168
|
+
The object to convert to JSON.
|
|
169
169
|
|
|
170
170
|
Returns
|
|
171
171
|
-------
|
|
172
172
|
str
|
|
173
|
-
The
|
|
173
|
+
The JSON string representation of the object.
|
|
174
174
|
"""
|
|
175
175
|
return json.dumps(struct, cls=CustomJsonEncoder)
|
|
176
176
|
|
|
177
177
|
|
|
178
178
|
def slugify_string(filename: str) -> str:
|
|
179
179
|
"""
|
|
180
|
-
Sanitize a filename.
|
|
180
|
+
Sanitize a filename using slugify.
|
|
181
181
|
|
|
182
182
|
Parameters
|
|
183
183
|
----------
|
|
@@ -187,26 +187,31 @@ def slugify_string(filename: str) -> str:
|
|
|
187
187
|
Returns
|
|
188
188
|
-------
|
|
189
189
|
str
|
|
190
|
-
The sanitized filename.
|
|
190
|
+
The sanitized filename (max length 255).
|
|
191
191
|
"""
|
|
192
192
|
return slugify(filename, max_length=255)
|
|
193
193
|
|
|
194
194
|
|
|
195
195
|
def import_function(path: Path, handler: str) -> Callable:
|
|
196
196
|
"""
|
|
197
|
-
Import a function from a module.
|
|
197
|
+
Import a function from a Python module file.
|
|
198
198
|
|
|
199
199
|
Parameters
|
|
200
200
|
----------
|
|
201
201
|
path : Path
|
|
202
|
-
Path
|
|
202
|
+
Path to the Python module file.
|
|
203
203
|
handler : str
|
|
204
|
-
|
|
204
|
+
Name of the function to import.
|
|
205
205
|
|
|
206
206
|
Returns
|
|
207
207
|
-------
|
|
208
208
|
Callable
|
|
209
|
-
|
|
209
|
+
The imported function.
|
|
210
|
+
|
|
211
|
+
Raises
|
|
212
|
+
------
|
|
213
|
+
RuntimeError
|
|
214
|
+
If the module or function cannot be loaded or is not callable.
|
|
210
215
|
"""
|
|
211
216
|
spec = imputil.spec_from_file_location(path.stem, path)
|
|
212
217
|
if spec is None:
|
|
@@ -226,7 +231,7 @@ def import_function(path: Path, handler: str) -> Callable:
|
|
|
226
231
|
|
|
227
232
|
def list_enum(enum: EnumMeta) -> list[Any]:
|
|
228
233
|
"""
|
|
229
|
-
Get all values of an enum.
|
|
234
|
+
Get all values of an enum class.
|
|
230
235
|
|
|
231
236
|
Parameters
|
|
232
237
|
----------
|
|
@@ -235,7 +240,7 @@ def list_enum(enum: EnumMeta) -> list[Any]:
|
|
|
235
240
|
|
|
236
241
|
Returns
|
|
237
242
|
-------
|
|
238
|
-
list
|
|
243
|
+
list
|
|
239
244
|
List of enum values.
|
|
240
245
|
"""
|
|
241
246
|
vals: MappingProxyType[str, Enum] = enum.__members__
|
|
@@ -244,7 +249,8 @@ def list_enum(enum: EnumMeta) -> list[Any]:
|
|
|
244
249
|
|
|
245
250
|
def carriage_return_warn(string: str) -> None:
|
|
246
251
|
"""
|
|
247
|
-
Print a warning message if string contains
|
|
252
|
+
Print a warning message if the string contains
|
|
253
|
+
a carriage return (\r\n).
|
|
248
254
|
|
|
249
255
|
Parameters
|
|
250
256
|
----------
|
|
@@ -256,22 +262,24 @@ def carriage_return_warn(string: str) -> None:
|
|
|
256
262
|
None
|
|
257
263
|
"""
|
|
258
264
|
if "\r\n" in string:
|
|
259
|
-
warn("String contains a carriage return.
|
|
265
|
+
warn("String contains a carriage return. "
|
|
266
|
+
"It may not be parsed correctly from remote runtimes.")
|
|
260
267
|
|
|
261
268
|
|
|
262
269
|
def read_source(path: str) -> str:
|
|
263
270
|
"""
|
|
264
|
-
Read a file
|
|
271
|
+
Read a file and encode its content in base64,
|
|
272
|
+
warning if carriage returns are present.
|
|
265
273
|
|
|
266
274
|
Parameters
|
|
267
275
|
----------
|
|
268
|
-
path :
|
|
276
|
+
path : str
|
|
269
277
|
Path to the file.
|
|
270
278
|
|
|
271
279
|
Returns
|
|
272
280
|
-------
|
|
273
281
|
str
|
|
274
|
-
|
|
282
|
+
Base64-encoded file content.
|
|
275
283
|
"""
|
|
276
284
|
text = read_text(path)
|
|
277
285
|
carriage_return_warn(text)
|
digitalhub/utils/git_utils.py
CHANGED
|
@@ -21,6 +21,15 @@ except ImportError as e:
|
|
|
21
21
|
class GitCredentialsType(Enum):
|
|
22
22
|
"""
|
|
23
23
|
Supported git credentials types.
|
|
24
|
+
|
|
25
|
+
Attributes
|
|
26
|
+
----------
|
|
27
|
+
USERNAME : str
|
|
28
|
+
Environment variable name for git username.
|
|
29
|
+
PASSWORD : str
|
|
30
|
+
Environment variable name for git password.
|
|
31
|
+
TOKEN : str
|
|
32
|
+
Environment variable name for git token.
|
|
24
33
|
"""
|
|
25
34
|
|
|
26
35
|
USERNAME = "GIT_USERNAME"
|
|
@@ -30,7 +39,7 @@ class GitCredentialsType(Enum):
|
|
|
30
39
|
|
|
31
40
|
def clone_repository(path: Path, url: str) -> None:
|
|
32
41
|
"""
|
|
33
|
-
Clone git repository.
|
|
42
|
+
Clone a git repository to a local path.
|
|
34
43
|
|
|
35
44
|
Parameters
|
|
36
45
|
----------
|
|
@@ -53,7 +62,7 @@ def clone_repository(path: Path, url: str) -> None:
|
|
|
53
62
|
|
|
54
63
|
def get_checkout_object(url: str) -> str:
|
|
55
64
|
"""
|
|
56
|
-
Get checkout object from
|
|
65
|
+
Get checkout object (branch, tag, commit) from URL fragment.
|
|
57
66
|
|
|
58
67
|
Parameters
|
|
59
68
|
----------
|
|
@@ -63,18 +72,19 @@ def get_checkout_object(url: str) -> str:
|
|
|
63
72
|
Returns
|
|
64
73
|
-------
|
|
65
74
|
str
|
|
66
|
-
Checkout object (branch, tag, commit).
|
|
75
|
+
Checkout object (branch, tag, commit) or empty string if not present.
|
|
67
76
|
"""
|
|
68
77
|
return urlparse(url).fragment
|
|
69
78
|
|
|
70
79
|
|
|
71
80
|
def clean_path(path: Path) -> None:
|
|
72
81
|
"""
|
|
73
|
-
|
|
82
|
+
Remove all files and directories at the given path.
|
|
74
83
|
|
|
75
84
|
Parameters
|
|
76
85
|
----------
|
|
77
86
|
path : Path
|
|
87
|
+
Path to clean.
|
|
78
88
|
|
|
79
89
|
Returns
|
|
80
90
|
-------
|
|
@@ -86,12 +96,12 @@ def clean_path(path: Path) -> None:
|
|
|
86
96
|
|
|
87
97
|
def get_git_username_password_from_token(token: str) -> tuple[str, str]:
|
|
88
98
|
"""
|
|
89
|
-
Parse token to get username and password
|
|
90
|
-
can be one of the following:
|
|
99
|
+
Parse a token to get username and password for git authentication.
|
|
91
100
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
101
|
+
The token can be one of the following:
|
|
102
|
+
- GitHub/GitLab personal access token (github_pat_.../glpat...)
|
|
103
|
+
- GitHub/GitLab access token
|
|
104
|
+
- Other generic token
|
|
95
105
|
|
|
96
106
|
Parameters
|
|
97
107
|
----------
|
|
@@ -101,7 +111,7 @@ def get_git_username_password_from_token(token: str) -> tuple[str, str]:
|
|
|
101
111
|
Returns
|
|
102
112
|
-------
|
|
103
113
|
tuple[str, str]
|
|
104
|
-
Username and password.
|
|
114
|
+
Username and password for git authentication.
|
|
105
115
|
"""
|
|
106
116
|
# Mutued from mlrun
|
|
107
117
|
if token.startswith("github_pat_") or token.startswith("glpat"):
|
|
@@ -111,7 +121,7 @@ def get_git_username_password_from_token(token: str) -> tuple[str, str]:
|
|
|
111
121
|
|
|
112
122
|
def add_credentials_git_remote_url(url: str) -> str:
|
|
113
123
|
"""
|
|
114
|
-
Add credentials to git remote
|
|
124
|
+
Add credentials to a git remote URL using environment variables or token.
|
|
115
125
|
|
|
116
126
|
Parameters
|
|
117
127
|
----------
|
|
@@ -121,7 +131,7 @@ def add_credentials_git_remote_url(url: str) -> str:
|
|
|
121
131
|
Returns
|
|
122
132
|
-------
|
|
123
133
|
str
|
|
124
|
-
URL with credentials.
|
|
134
|
+
URL with credentials included if available.
|
|
125
135
|
"""
|
|
126
136
|
url_obj = urlparse(url)
|
|
127
137
|
|
|
@@ -142,7 +152,7 @@ def add_credentials_git_remote_url(url: str) -> str:
|
|
|
142
152
|
|
|
143
153
|
def clone_from_url(url: str, path: Path) -> Repo:
|
|
144
154
|
"""
|
|
145
|
-
Clone repository from
|
|
155
|
+
Clone a git repository from a URL to a local path.
|
|
146
156
|
|
|
147
157
|
Parameters
|
|
148
158
|
----------
|
|
@@ -154,6 +164,6 @@ def clone_from_url(url: str, path: Path) -> Repo:
|
|
|
154
164
|
Returns
|
|
155
165
|
-------
|
|
156
166
|
Repo
|
|
157
|
-
|
|
167
|
+
The cloned git repository object.
|
|
158
168
|
"""
|
|
159
169
|
return Repo.clone_from(url=url, to_path=path)
|
digitalhub/utils/io_utils.py
CHANGED
|
@@ -15,14 +15,14 @@ import yaml
|
|
|
15
15
|
|
|
16
16
|
def write_yaml(filepath: str | Path, obj: dict | list[dict]) -> None:
|
|
17
17
|
"""
|
|
18
|
-
Write a dict or a list of
|
|
18
|
+
Write a dict or a list of dicts to a YAML file.
|
|
19
19
|
|
|
20
20
|
Parameters
|
|
21
21
|
----------
|
|
22
|
-
filepath : str
|
|
23
|
-
The
|
|
24
|
-
obj : dict
|
|
25
|
-
The dict to write.
|
|
22
|
+
filepath : str or Path
|
|
23
|
+
The YAML file path to write.
|
|
24
|
+
obj : dict or list of dict
|
|
25
|
+
The dict or list of dicts to write.
|
|
26
26
|
|
|
27
27
|
Returns
|
|
28
28
|
-------
|
|
@@ -61,7 +61,7 @@ def write_text(filepath: Path, text: str) -> None:
|
|
|
61
61
|
|
|
62
62
|
class NoDatesSafeLoader(yaml.SafeLoader):
|
|
63
63
|
"""
|
|
64
|
-
Loader implementation to exclude implicit resolvers.
|
|
64
|
+
Loader implementation to exclude implicit resolvers for YAML timestamps.
|
|
65
65
|
|
|
66
66
|
Taken from https://stackoverflow.com/a/37958106
|
|
67
67
|
"""
|
|
@@ -69,16 +69,17 @@ class NoDatesSafeLoader(yaml.SafeLoader):
|
|
|
69
69
|
@classmethod
|
|
70
70
|
def remove_implicit_resolver(cls, tag_to_remove: str) -> None:
|
|
71
71
|
"""
|
|
72
|
-
Remove implicit resolvers for a particular tag
|
|
72
|
+
Remove implicit resolvers for a particular tag.
|
|
73
|
+
|
|
73
74
|
Takes care not to modify resolvers in super classes.
|
|
74
75
|
We want to load datetimes as strings, not dates, because we
|
|
75
|
-
go on to
|
|
76
|
-
of
|
|
76
|
+
go on to serialize as JSON which doesn't have the advanced types
|
|
77
|
+
of YAML, and leads to incompatibilities down the track.
|
|
77
78
|
|
|
78
79
|
Parameters
|
|
79
80
|
----------
|
|
80
81
|
tag_to_remove : str
|
|
81
|
-
The tag to remove
|
|
82
|
+
The tag to remove.
|
|
82
83
|
|
|
83
84
|
Returns
|
|
84
85
|
-------
|
|
@@ -98,17 +99,17 @@ NoDatesSafeLoader.remove_implicit_resolver("tag:yaml.org,2002:timestamp")
|
|
|
98
99
|
|
|
99
100
|
def read_yaml(filepath: str | Path) -> dict | list[dict]:
|
|
100
101
|
"""
|
|
101
|
-
Read a
|
|
102
|
+
Read a YAML file and return its content as a dict or a list of dicts.
|
|
102
103
|
|
|
103
104
|
Parameters
|
|
104
105
|
----------
|
|
105
|
-
filepath : str
|
|
106
|
-
The
|
|
106
|
+
filepath : str or Path
|
|
107
|
+
The YAML file path to read.
|
|
107
108
|
|
|
108
109
|
Returns
|
|
109
110
|
-------
|
|
110
|
-
dict
|
|
111
|
-
The
|
|
111
|
+
dict or list of dict
|
|
112
|
+
The YAML file content.
|
|
112
113
|
"""
|
|
113
114
|
try:
|
|
114
115
|
with open(filepath, "r", encoding="utf-8") as in_file:
|
|
@@ -123,16 +124,16 @@ def read_yaml(filepath: str | Path) -> dict | list[dict]:
|
|
|
123
124
|
|
|
124
125
|
def read_text(filepath: str | Path) -> str:
|
|
125
126
|
"""
|
|
126
|
-
Read a file and return
|
|
127
|
+
Read a file and return its text content.
|
|
127
128
|
|
|
128
129
|
Parameters
|
|
129
130
|
----------
|
|
130
|
-
filepath : str
|
|
131
|
+
filepath : str or Path
|
|
131
132
|
The file path to read.
|
|
132
133
|
|
|
133
134
|
Returns
|
|
134
135
|
-------
|
|
135
136
|
str
|
|
136
|
-
The file content.
|
|
137
|
+
The file content as a string.
|
|
137
138
|
"""
|
|
138
139
|
return Path(filepath).read_text(encoding="utf-8")
|