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