digitalhub 0.9.1__py3-none-any.whl → 0.10.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 +2 -3
- digitalhub/client/_base/api_builder.py +1 -1
- digitalhub/client/_base/client.py +25 -2
- digitalhub/client/_base/params_builder.py +16 -0
- digitalhub/client/dhcore/api_builder.py +10 -4
- digitalhub/client/dhcore/client.py +30 -398
- digitalhub/client/dhcore/configurator.py +361 -0
- digitalhub/client/dhcore/error_parser.py +107 -0
- digitalhub/client/dhcore/models.py +13 -23
- digitalhub/client/dhcore/params_builder.py +178 -0
- digitalhub/client/dhcore/utils.py +4 -44
- digitalhub/client/local/api_builder.py +13 -18
- digitalhub/client/local/client.py +18 -2
- digitalhub/client/local/enums.py +11 -0
- digitalhub/client/local/params_builder.py +116 -0
- digitalhub/configurator/api.py +31 -0
- digitalhub/configurator/configurator.py +195 -0
- digitalhub/configurator/credentials_store.py +65 -0
- digitalhub/configurator/ini_module.py +74 -0
- digitalhub/entities/_base/_base/entity.py +2 -2
- digitalhub/entities/_base/context/entity.py +4 -4
- digitalhub/entities/_base/entity/builder.py +5 -5
- digitalhub/entities/_base/executable/entity.py +2 -2
- digitalhub/entities/_base/material/entity.py +12 -12
- digitalhub/entities/_base/material/status.py +1 -1
- digitalhub/entities/_base/material/utils.py +2 -2
- digitalhub/entities/_base/unversioned/entity.py +2 -2
- digitalhub/entities/_base/versioned/entity.py +2 -2
- digitalhub/entities/_commons/enums.py +2 -0
- digitalhub/entities/_commons/metrics.py +164 -0
- digitalhub/entities/_commons/types.py +5 -0
- digitalhub/entities/_commons/utils.py +2 -2
- digitalhub/entities/_processors/base.py +527 -0
- digitalhub/entities/{_operations/processor.py → _processors/context.py} +212 -837
- digitalhub/entities/_processors/utils.py +158 -0
- digitalhub/entities/artifact/artifact/spec.py +3 -1
- digitalhub/entities/artifact/crud.py +13 -12
- digitalhub/entities/artifact/utils.py +1 -1
- digitalhub/entities/builders.py +6 -18
- digitalhub/entities/dataitem/_base/entity.py +0 -41
- digitalhub/entities/dataitem/crud.py +27 -15
- digitalhub/entities/dataitem/table/entity.py +49 -35
- digitalhub/entities/dataitem/table/models.py +4 -3
- digitalhub/{utils/data_utils.py → entities/dataitem/table/utils.py} +46 -54
- digitalhub/entities/dataitem/utils.py +58 -10
- digitalhub/entities/function/crud.py +9 -9
- digitalhub/entities/model/_base/entity.py +120 -0
- digitalhub/entities/model/_base/spec.py +6 -17
- digitalhub/entities/model/_base/status.py +10 -0
- digitalhub/entities/model/crud.py +13 -12
- digitalhub/entities/model/huggingface/spec.py +9 -4
- digitalhub/entities/model/mlflow/models.py +2 -2
- digitalhub/entities/model/mlflow/spec.py +7 -7
- digitalhub/entities/model/mlflow/utils.py +44 -5
- digitalhub/entities/project/_base/entity.py +317 -9
- digitalhub/entities/project/_base/spec.py +8 -6
- digitalhub/entities/project/crud.py +12 -11
- digitalhub/entities/run/_base/entity.py +103 -6
- digitalhub/entities/run/_base/spec.py +4 -2
- digitalhub/entities/run/_base/status.py +12 -0
- digitalhub/entities/run/crud.py +8 -8
- digitalhub/entities/secret/_base/entity.py +3 -3
- digitalhub/entities/secret/_base/spec.py +4 -2
- digitalhub/entities/secret/crud.py +11 -9
- digitalhub/entities/task/_base/entity.py +4 -4
- digitalhub/entities/task/_base/models.py +51 -40
- digitalhub/entities/task/_base/spec.py +2 -0
- digitalhub/entities/task/_base/utils.py +2 -2
- digitalhub/entities/task/crud.py +12 -8
- digitalhub/entities/workflow/crud.py +9 -9
- digitalhub/factory/utils.py +9 -9
- digitalhub/readers/{_base → data/_base}/builder.py +1 -1
- digitalhub/readers/{_base → data/_base}/reader.py +16 -4
- digitalhub/readers/{api.py → data/api.py} +2 -2
- digitalhub/readers/{factory.py → data/factory.py} +3 -3
- digitalhub/readers/{pandas → data/pandas}/builder.py +2 -2
- digitalhub/readers/{pandas → data/pandas}/reader.py +110 -30
- digitalhub/readers/query/__init__.py +0 -0
- digitalhub/stores/_base/store.py +59 -69
- digitalhub/stores/api.py +8 -33
- digitalhub/stores/builder.py +44 -161
- digitalhub/stores/local/store.py +106 -89
- digitalhub/stores/remote/store.py +86 -11
- digitalhub/stores/s3/configurator.py +108 -0
- digitalhub/stores/s3/enums.py +17 -0
- digitalhub/stores/s3/models.py +21 -0
- digitalhub/stores/s3/store.py +154 -70
- digitalhub/{utils/s3_utils.py → stores/s3/utils.py} +7 -3
- digitalhub/stores/sql/configurator.py +88 -0
- digitalhub/stores/sql/enums.py +16 -0
- digitalhub/stores/sql/models.py +24 -0
- digitalhub/stores/sql/store.py +106 -85
- digitalhub/{readers/_commons → utils}/enums.py +5 -1
- digitalhub/utils/exceptions.py +6 -0
- digitalhub/utils/file_utils.py +8 -7
- digitalhub/utils/generic_utils.py +28 -15
- digitalhub/utils/git_utils.py +16 -9
- digitalhub/utils/types.py +5 -0
- digitalhub/utils/uri_utils.py +2 -2
- {digitalhub-0.9.1.dist-info → digitalhub-0.10.0.dist-info}/METADATA +25 -31
- {digitalhub-0.9.1.dist-info → digitalhub-0.10.0.dist-info}/RECORD +108 -99
- {digitalhub-0.9.1.dist-info → digitalhub-0.10.0.dist-info}/WHEEL +1 -2
- digitalhub/client/dhcore/env.py +0 -23
- digitalhub/entities/_base/project/entity.py +0 -341
- digitalhub-0.9.1.dist-info/top_level.txt +0 -2
- test/local/CRUD/test_artifacts.py +0 -96
- test/local/CRUD/test_dataitems.py +0 -96
- test/local/CRUD/test_models.py +0 -95
- test/local/imports/test_imports.py +0 -66
- test/local/instances/test_validate.py +0 -55
- test/test_crud_functions.py +0 -109
- test/test_crud_runs.py +0 -86
- test/test_crud_tasks.py +0 -81
- test/testkfp.py +0 -37
- test/testkfp_pipeline.py +0 -22
- /digitalhub/{entities/_base/project → configurator}/__init__.py +0 -0
- /digitalhub/entities/{_operations → _processors}/__init__.py +0 -0
- /digitalhub/readers/{_base → data}/__init__.py +0 -0
- /digitalhub/readers/{_commons → data/_base}/__init__.py +0 -0
- /digitalhub/readers/{pandas → data/pandas}/__init__.py +0 -0
- {digitalhub-0.9.1.dist-info → digitalhub-0.10.0.dist-info/licenses}/LICENSE.txt +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from enum import Enum
|
|
4
|
+
from typing import Optional
|
|
4
5
|
|
|
5
6
|
from pydantic import BaseModel, ConfigDict, Field
|
|
6
7
|
|
|
@@ -40,16 +41,16 @@ class TableSchemaFieldEntry(BaseModel):
|
|
|
40
41
|
type_: FieldType = Field(alias="type")
|
|
41
42
|
"""Field type."""
|
|
42
43
|
|
|
43
|
-
title: str = None
|
|
44
|
+
title: Optional[str] = None
|
|
44
45
|
"""Field title."""
|
|
45
46
|
|
|
46
47
|
format_: str = Field(default=None, alias="format")
|
|
47
48
|
"""Field format."""
|
|
48
49
|
|
|
49
|
-
example: str = None
|
|
50
|
+
example: Optional[str] = None
|
|
50
51
|
"""Field example."""
|
|
51
52
|
|
|
52
|
-
description: str = None
|
|
53
|
+
description: Optional[str] = None
|
|
53
54
|
"""Field description."""
|
|
54
55
|
|
|
55
56
|
|
|
@@ -1,49 +1,23 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
from digitalhub.utils.generic_utils import dump_json
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
def
|
|
6
|
+
def prepare_data(data: list[list], columnar: bool = False) -> list[list]:
|
|
7
7
|
"""
|
|
8
|
-
|
|
8
|
+
Prepare data.
|
|
9
9
|
|
|
10
10
|
Parameters
|
|
11
11
|
----------
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
Row count.
|
|
16
|
-
|
|
17
|
-
Returns
|
|
18
|
-
-------
|
|
19
|
-
dict
|
|
20
|
-
Data preview.
|
|
21
|
-
"""
|
|
22
|
-
dict_ = {}
|
|
23
|
-
if preview is not None:
|
|
24
|
-
dict_["cols"] = preview
|
|
25
|
-
if rows_count is not None:
|
|
26
|
-
dict_["rows"] = rows_count
|
|
27
|
-
return dict_
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def get_data_preview(columns: list, data: list[list], columnar: bool = False) -> list[dict]:
|
|
31
|
-
"""
|
|
32
|
-
Prepare preview.
|
|
33
|
-
|
|
34
|
-
Parameters
|
|
35
|
-
----------
|
|
36
|
-
columns : list
|
|
37
|
-
Columns names.
|
|
38
|
-
data : list[list]
|
|
39
|
-
Data to preview.
|
|
40
|
-
columnar : bool
|
|
12
|
+
data : list
|
|
13
|
+
Data.
|
|
14
|
+
columnar : bool | None
|
|
41
15
|
If data are arranged in columns. If False, data are arranged in rows.
|
|
42
16
|
|
|
43
17
|
Returns
|
|
44
18
|
-------
|
|
45
|
-
list[
|
|
46
|
-
|
|
19
|
+
list[list]
|
|
20
|
+
Prepared data.
|
|
47
21
|
"""
|
|
48
22
|
# Reduce data to 10 rows
|
|
49
23
|
if not columnar:
|
|
@@ -56,17 +30,10 @@ def get_data_preview(columns: list, data: list[list], columnar: bool = False) ->
|
|
|
56
30
|
if not columnar:
|
|
57
31
|
data = list(map(list, list(zip(*data))))
|
|
58
32
|
|
|
59
|
-
|
|
60
|
-
data_dict = prepare_preview(columns, data)
|
|
61
|
-
|
|
62
|
-
# Filter memoryview values
|
|
63
|
-
filtered_memview = filter_memoryview(data_dict)
|
|
64
|
-
|
|
65
|
-
# Check the size of the preview data
|
|
66
|
-
return check_preview_size(filtered_memview)
|
|
33
|
+
return data
|
|
67
34
|
|
|
68
35
|
|
|
69
|
-
def prepare_preview(
|
|
36
|
+
def prepare_preview(columns: list, data: list[list]) -> list[dict]:
|
|
70
37
|
"""
|
|
71
38
|
Get preview.
|
|
72
39
|
|
|
@@ -80,9 +47,10 @@ def prepare_preview(column_names: list, data: list[list]) -> list[dict]:
|
|
|
80
47
|
list[dict]
|
|
81
48
|
Preview.
|
|
82
49
|
"""
|
|
83
|
-
if len(
|
|
50
|
+
if len(columns) != len(data):
|
|
84
51
|
raise ValueError("Column names and data must have the same length")
|
|
85
|
-
|
|
52
|
+
preview = [{"name": column, "value": values} for column, values in zip(columns, data)]
|
|
53
|
+
return filter_memoryview(preview)
|
|
86
54
|
|
|
87
55
|
|
|
88
56
|
def filter_memoryview(data: list[dict]) -> list[dict]:
|
|
@@ -91,13 +59,13 @@ def filter_memoryview(data: list[dict]) -> list[dict]:
|
|
|
91
59
|
|
|
92
60
|
Parameters
|
|
93
61
|
----------
|
|
94
|
-
data :
|
|
62
|
+
data : list[dict]
|
|
95
63
|
Data.
|
|
96
64
|
|
|
97
65
|
Returns
|
|
98
66
|
-------
|
|
99
|
-
list[
|
|
100
|
-
|
|
67
|
+
list[dict]
|
|
68
|
+
Preview.
|
|
101
69
|
"""
|
|
102
70
|
key_to_filter = []
|
|
103
71
|
for i in data:
|
|
@@ -108,20 +76,44 @@ def filter_memoryview(data: list[dict]) -> list[dict]:
|
|
|
108
76
|
return data
|
|
109
77
|
|
|
110
78
|
|
|
111
|
-
def check_preview_size(preview:
|
|
79
|
+
def check_preview_size(preview: dict) -> dict:
|
|
112
80
|
"""
|
|
113
|
-
Check preview size. If it's too big, return empty
|
|
81
|
+
Check preview size. If it's too big, return empty dict.
|
|
114
82
|
|
|
115
83
|
Parameters
|
|
116
84
|
----------
|
|
117
|
-
preview :
|
|
85
|
+
preview : dict
|
|
118
86
|
Preview.
|
|
119
87
|
|
|
120
88
|
Returns
|
|
121
89
|
-------
|
|
122
|
-
|
|
90
|
+
dict
|
|
123
91
|
Preview.
|
|
124
92
|
"""
|
|
125
|
-
if len(
|
|
126
|
-
return
|
|
93
|
+
if len(dump_json(preview)) >= 64000:
|
|
94
|
+
return {}
|
|
127
95
|
return preview
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def finalize_preview(preview: list[dict] | None = None, rows_count: int | None = None) -> dict:
|
|
99
|
+
"""
|
|
100
|
+
Finalize preview.
|
|
101
|
+
|
|
102
|
+
Parameters
|
|
103
|
+
----------
|
|
104
|
+
preview : list[dict]
|
|
105
|
+
Preview.
|
|
106
|
+
rows_count : int
|
|
107
|
+
Row count.
|
|
108
|
+
|
|
109
|
+
Returns
|
|
110
|
+
-------
|
|
111
|
+
dict
|
|
112
|
+
Data preview.
|
|
113
|
+
"""
|
|
114
|
+
data: dict[str, list[dict] | int] = {}
|
|
115
|
+
if preview is not None:
|
|
116
|
+
data["cols"] = preview
|
|
117
|
+
if rows_count is not None:
|
|
118
|
+
data["rows"] = rows_count
|
|
119
|
+
return data
|
|
@@ -8,16 +8,21 @@ from digitalhub.context.api import get_context
|
|
|
8
8
|
from digitalhub.entities._base.entity._constructors.uuid import build_uuid
|
|
9
9
|
from digitalhub.entities._base.material.utils import build_log_path_from_source, eval_local_source
|
|
10
10
|
from digitalhub.entities._commons.enums import EntityKinds, EntityTypes
|
|
11
|
-
from digitalhub.readers.
|
|
12
|
-
from digitalhub.
|
|
11
|
+
from digitalhub.readers.data.api import get_reader_by_object
|
|
12
|
+
from digitalhub.stores.api import get_store
|
|
13
|
+
from digitalhub.utils.enums import FileExtensions
|
|
13
14
|
from digitalhub.utils.generic_utils import slugify_string
|
|
15
|
+
from digitalhub.utils.types import SourcesOrListOfSources
|
|
14
16
|
|
|
15
17
|
if typing.TYPE_CHECKING:
|
|
16
18
|
from digitalhub.entities.dataitem._base.entity import Dataitem
|
|
17
19
|
|
|
18
20
|
|
|
21
|
+
DEFAULT_EXTENSION = FileExtensions.PARQUET.value
|
|
22
|
+
|
|
23
|
+
|
|
19
24
|
def eval_source(
|
|
20
|
-
source:
|
|
25
|
+
source: SourcesOrListOfSources | None = None,
|
|
21
26
|
data: Any | None = None,
|
|
22
27
|
kind: str | None = None,
|
|
23
28
|
name: str | None = None,
|
|
@@ -28,7 +33,7 @@ def eval_source(
|
|
|
28
33
|
|
|
29
34
|
Parameters
|
|
30
35
|
----------
|
|
31
|
-
source :
|
|
36
|
+
source : SourcesOrListOfSources
|
|
32
37
|
Source(s).
|
|
33
38
|
|
|
34
39
|
Returns
|
|
@@ -39,11 +44,12 @@ def eval_source(
|
|
|
39
44
|
raise ValueError("You must provide source or data.")
|
|
40
45
|
|
|
41
46
|
if source is not None:
|
|
42
|
-
|
|
47
|
+
eval_local_source(source)
|
|
48
|
+
return source
|
|
43
49
|
|
|
44
50
|
if kind == EntityKinds.DATAITEM_TABLE.value:
|
|
45
51
|
ctx = get_context(project)
|
|
46
|
-
pth = ctx.root / f"{slugify_string(name)}.{
|
|
52
|
+
pth = ctx.root / f"{slugify_string(name)}.{DEFAULT_EXTENSION}"
|
|
47
53
|
reader = get_reader_by_object(data)
|
|
48
54
|
reader.write_parquet(data, pth)
|
|
49
55
|
return str(pth)
|
|
@@ -51,11 +57,49 @@ def eval_source(
|
|
|
51
57
|
raise NotImplementedError
|
|
52
58
|
|
|
53
59
|
|
|
60
|
+
def eval_data(
|
|
61
|
+
project: str,
|
|
62
|
+
kind: str,
|
|
63
|
+
source: SourcesOrListOfSources,
|
|
64
|
+
data: Any | None = None,
|
|
65
|
+
file_format: str | None = None,
|
|
66
|
+
engine: str | None = None,
|
|
67
|
+
) -> Any:
|
|
68
|
+
"""
|
|
69
|
+
Evaluate data is loaded.
|
|
70
|
+
|
|
71
|
+
Parameters
|
|
72
|
+
----------
|
|
73
|
+
project : str
|
|
74
|
+
Project name.
|
|
75
|
+
source : str
|
|
76
|
+
Source(s).
|
|
77
|
+
data : Any
|
|
78
|
+
Dataframe to log. Alternative to source.
|
|
79
|
+
file_format : str
|
|
80
|
+
Extension of the file.
|
|
81
|
+
engine : str
|
|
82
|
+
Engine to use.
|
|
83
|
+
|
|
84
|
+
Returns
|
|
85
|
+
-------
|
|
86
|
+
None
|
|
87
|
+
"""
|
|
88
|
+
if kind == EntityKinds.DATAITEM_TABLE.value:
|
|
89
|
+
if data is None:
|
|
90
|
+
return get_store(project, source).read_df(
|
|
91
|
+
source,
|
|
92
|
+
file_format=file_format,
|
|
93
|
+
engine=engine,
|
|
94
|
+
)
|
|
95
|
+
return data
|
|
96
|
+
|
|
97
|
+
|
|
54
98
|
def process_kwargs(
|
|
55
99
|
project: str,
|
|
56
100
|
name: str,
|
|
57
101
|
kind: str,
|
|
58
|
-
source:
|
|
102
|
+
source: SourcesOrListOfSources,
|
|
59
103
|
data: Any | None = None,
|
|
60
104
|
path: str | None = None,
|
|
61
105
|
**kwargs,
|
|
@@ -71,7 +115,7 @@ def process_kwargs(
|
|
|
71
115
|
Object name.
|
|
72
116
|
kind : str
|
|
73
117
|
Kind the object.
|
|
74
|
-
source :
|
|
118
|
+
source : SourcesOrListOfSources
|
|
75
119
|
Source(s).
|
|
76
120
|
data : Any
|
|
77
121
|
Dataframe to log. Alternative to source.
|
|
@@ -98,19 +142,23 @@ def process_kwargs(
|
|
|
98
142
|
return kwargs
|
|
99
143
|
|
|
100
144
|
|
|
101
|
-
def clean_tmp_path(pth:
|
|
145
|
+
def clean_tmp_path(pth: SourcesOrListOfSources) -> None:
|
|
102
146
|
"""
|
|
103
147
|
Clean temporary path.
|
|
104
148
|
|
|
105
149
|
Parameters
|
|
106
150
|
----------
|
|
107
|
-
pth :
|
|
151
|
+
pth : SourcesOrListOfSources
|
|
108
152
|
Path to clean.
|
|
109
153
|
|
|
110
154
|
Returns
|
|
111
155
|
-------
|
|
112
156
|
None
|
|
113
157
|
"""
|
|
158
|
+
if isinstance(pth, list):
|
|
159
|
+
for p in pth:
|
|
160
|
+
shutil.rmtree(p, ignore_errors=True)
|
|
161
|
+
return
|
|
114
162
|
shutil.rmtree(pth, ignore_errors=True)
|
|
115
163
|
|
|
116
164
|
|
|
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import typing
|
|
4
4
|
|
|
5
5
|
from digitalhub.entities._commons.enums import EntityTypes
|
|
6
|
-
from digitalhub.entities.
|
|
6
|
+
from digitalhub.entities._processors.context import context_processor
|
|
7
7
|
|
|
8
8
|
if typing.TYPE_CHECKING:
|
|
9
9
|
from digitalhub.entities.function._base.entity import Function
|
|
@@ -56,7 +56,7 @@ def new_function(
|
|
|
56
56
|
>>> code_src="function.py",
|
|
57
57
|
>>> handler="function-handler")
|
|
58
58
|
"""
|
|
59
|
-
return
|
|
59
|
+
return context_processor.create_context_entity(
|
|
60
60
|
project=project,
|
|
61
61
|
name=name,
|
|
62
62
|
kind=kind,
|
|
@@ -103,7 +103,7 @@ def get_function(
|
|
|
103
103
|
>>> project="my-project",
|
|
104
104
|
>>> entity_id="my-function-id")
|
|
105
105
|
"""
|
|
106
|
-
return
|
|
106
|
+
return context_processor.read_context_entity(
|
|
107
107
|
identifier,
|
|
108
108
|
entity_type=ENTITY_TYPE,
|
|
109
109
|
project=project,
|
|
@@ -143,7 +143,7 @@ def get_function_versions(
|
|
|
143
143
|
>>> obj = get_function_versions("my-function-name"
|
|
144
144
|
>>> project="my-project")
|
|
145
145
|
"""
|
|
146
|
-
return
|
|
146
|
+
return context_processor.read_context_entity_versions(
|
|
147
147
|
identifier,
|
|
148
148
|
entity_type=ENTITY_TYPE,
|
|
149
149
|
project=project,
|
|
@@ -171,7 +171,7 @@ def list_functions(project: str, **kwargs) -> list[Function]:
|
|
|
171
171
|
--------
|
|
172
172
|
>>> objs = list_functions(project="my-project")
|
|
173
173
|
"""
|
|
174
|
-
return
|
|
174
|
+
return context_processor.list_context_entities(
|
|
175
175
|
project=project,
|
|
176
176
|
entity_type=ENTITY_TYPE,
|
|
177
177
|
**kwargs,
|
|
@@ -196,7 +196,7 @@ def import_function(file: str) -> Function:
|
|
|
196
196
|
--------
|
|
197
197
|
>>> obj = import_function("my-function.yaml")
|
|
198
198
|
"""
|
|
199
|
-
return
|
|
199
|
+
return context_processor.import_executable_entity(file)
|
|
200
200
|
|
|
201
201
|
|
|
202
202
|
def load_function(file: str) -> Function:
|
|
@@ -217,7 +217,7 @@ def load_function(file: str) -> Function:
|
|
|
217
217
|
--------
|
|
218
218
|
>>> obj = load_function("my-function.yaml")
|
|
219
219
|
"""
|
|
220
|
-
return
|
|
220
|
+
return context_processor.load_executable_entity(file)
|
|
221
221
|
|
|
222
222
|
|
|
223
223
|
def update_function(entity: Function) -> Function:
|
|
@@ -238,7 +238,7 @@ def update_function(entity: Function) -> Function:
|
|
|
238
238
|
--------
|
|
239
239
|
>>> obj = update_function(obj)
|
|
240
240
|
"""
|
|
241
|
-
return
|
|
241
|
+
return context_processor.update_context_entity(
|
|
242
242
|
project=entity.project,
|
|
243
243
|
entity_type=entity.ENTITY_TYPE,
|
|
244
244
|
entity_id=entity.id,
|
|
@@ -287,7 +287,7 @@ def delete_function(
|
|
|
287
287
|
>>> project="my-project",
|
|
288
288
|
>>> delete_all_versions=True)
|
|
289
289
|
"""
|
|
290
|
-
return
|
|
290
|
+
return context_processor.delete_context_entity(
|
|
291
291
|
identifier=identifier,
|
|
292
292
|
entity_type=ENTITY_TYPE,
|
|
293
293
|
project=project,
|
|
@@ -4,6 +4,8 @@ import typing
|
|
|
4
4
|
|
|
5
5
|
from digitalhub.entities._base.material.entity import MaterialEntity
|
|
6
6
|
from digitalhub.entities._commons.enums import EntityTypes
|
|
7
|
+
from digitalhub.entities._commons.metrics import MetricType, set_metrics, validate_metric_value
|
|
8
|
+
from digitalhub.entities._processors.context import context_processor
|
|
7
9
|
|
|
8
10
|
if typing.TYPE_CHECKING:
|
|
9
11
|
from digitalhub.entities._base.entity.metadata import Metadata
|
|
@@ -32,3 +34,121 @@ class Model(MaterialEntity):
|
|
|
32
34
|
super().__init__(project, name, uuid, kind, metadata, spec, status, user)
|
|
33
35
|
self.spec: ModelSpec
|
|
34
36
|
self.status: ModelStatus
|
|
37
|
+
|
|
38
|
+
def save(self, update: bool = False) -> Model:
|
|
39
|
+
"""
|
|
40
|
+
Save entity into backend.
|
|
41
|
+
|
|
42
|
+
Parameters
|
|
43
|
+
----------
|
|
44
|
+
update : bool
|
|
45
|
+
Flag to indicate update.
|
|
46
|
+
|
|
47
|
+
Returns
|
|
48
|
+
-------
|
|
49
|
+
Model
|
|
50
|
+
Entity saved.
|
|
51
|
+
"""
|
|
52
|
+
obj: Model = super().save(update)
|
|
53
|
+
obj._get_metrics()
|
|
54
|
+
return obj
|
|
55
|
+
|
|
56
|
+
def log_metric(
|
|
57
|
+
self,
|
|
58
|
+
key: str,
|
|
59
|
+
value: MetricType,
|
|
60
|
+
overwrite: bool = False,
|
|
61
|
+
single_value: bool = False,
|
|
62
|
+
) -> None:
|
|
63
|
+
"""
|
|
64
|
+
Log metric into entity status.
|
|
65
|
+
A metric is named by a key and value (single number or list of numbers).
|
|
66
|
+
The metric by default is put in a list or appended to an existing list.
|
|
67
|
+
If single_value is True, the value will be a single number.
|
|
68
|
+
|
|
69
|
+
Parameters
|
|
70
|
+
----------
|
|
71
|
+
key : str
|
|
72
|
+
Key of the metric.
|
|
73
|
+
value : MetricType
|
|
74
|
+
Value of the metric.
|
|
75
|
+
overwrite : bool
|
|
76
|
+
If True, overwrite existing metric.
|
|
77
|
+
single_value : bool
|
|
78
|
+
If True, value is a single value.
|
|
79
|
+
|
|
80
|
+
Returns
|
|
81
|
+
-------
|
|
82
|
+
None
|
|
83
|
+
|
|
84
|
+
Examples
|
|
85
|
+
--------
|
|
86
|
+
Log a new value in a list
|
|
87
|
+
>>> entity.log_metric("loss", 0.002)
|
|
88
|
+
|
|
89
|
+
Append a new value in a list
|
|
90
|
+
>>> entity.log_metric("loss", 0.0019)
|
|
91
|
+
|
|
92
|
+
Log a list of values and append them to existing metric:
|
|
93
|
+
>>> entity.log_metric("loss", [0.0018, 0.0015])
|
|
94
|
+
|
|
95
|
+
Log a single value (not represented as list):
|
|
96
|
+
>>> entity.log_metric("accuracy", 0.9, single_value=True)
|
|
97
|
+
|
|
98
|
+
Log a list of values and overwrite existing metric:
|
|
99
|
+
>>> entity.log_metric("accuracy", [0.8, 0.9], overwrite=True)
|
|
100
|
+
"""
|
|
101
|
+
self._set_metrics(key, value, overwrite, single_value)
|
|
102
|
+
context_processor.update_metric(self.project, self.ENTITY_TYPE, self.id, key, self.status.metrics[key])
|
|
103
|
+
|
|
104
|
+
##############################
|
|
105
|
+
# Helper methods
|
|
106
|
+
##############################
|
|
107
|
+
|
|
108
|
+
def _get_metrics(self) -> None:
|
|
109
|
+
"""
|
|
110
|
+
Get model metrics from backend.
|
|
111
|
+
|
|
112
|
+
Returns
|
|
113
|
+
-------
|
|
114
|
+
None
|
|
115
|
+
"""
|
|
116
|
+
self.status.metrics = context_processor.read_metrics(
|
|
117
|
+
project=self.project,
|
|
118
|
+
entity_type=self.ENTITY_TYPE,
|
|
119
|
+
entity_id=self.id,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
def _set_metrics(
|
|
123
|
+
self,
|
|
124
|
+
key: str,
|
|
125
|
+
value: MetricType,
|
|
126
|
+
overwrite: bool,
|
|
127
|
+
single_value: bool,
|
|
128
|
+
) -> None:
|
|
129
|
+
"""
|
|
130
|
+
Set model metrics.
|
|
131
|
+
|
|
132
|
+
Parameters
|
|
133
|
+
----------
|
|
134
|
+
key : str
|
|
135
|
+
Key of the metric.
|
|
136
|
+
value : MetricType
|
|
137
|
+
Value of the metric.
|
|
138
|
+
overwrite : bool
|
|
139
|
+
If True, overwrite existing metric.
|
|
140
|
+
single_value : bool
|
|
141
|
+
If True, value is a single value.
|
|
142
|
+
|
|
143
|
+
Returns
|
|
144
|
+
-------
|
|
145
|
+
None
|
|
146
|
+
"""
|
|
147
|
+
value = validate_metric_value(value)
|
|
148
|
+
self.status.metrics = set_metrics(
|
|
149
|
+
self.status.metrics,
|
|
150
|
+
key,
|
|
151
|
+
value,
|
|
152
|
+
overwrite,
|
|
153
|
+
single_value,
|
|
154
|
+
)
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
3
5
|
from digitalhub.entities._base.material.spec import MaterialSpec, MaterialValidator
|
|
4
6
|
|
|
5
7
|
|
|
@@ -13,16 +15,12 @@ class ModelSpec(MaterialSpec):
|
|
|
13
15
|
path: str,
|
|
14
16
|
framework: str | None = None,
|
|
15
17
|
algorithm: str | None = None,
|
|
16
|
-
base_model: str | None = None,
|
|
17
18
|
parameters: dict | None = None,
|
|
18
|
-
metrics: dict | None = None,
|
|
19
19
|
) -> None:
|
|
20
|
-
|
|
20
|
+
super().__init__(path)
|
|
21
21
|
self.framework = framework
|
|
22
22
|
self.algorithm = algorithm
|
|
23
|
-
self.base_model = base_model
|
|
24
23
|
self.parameters = parameters
|
|
25
|
-
self.metrics = metrics
|
|
26
24
|
|
|
27
25
|
|
|
28
26
|
class ModelValidator(MaterialValidator):
|
|
@@ -30,20 +28,11 @@ class ModelValidator(MaterialValidator):
|
|
|
30
28
|
ModelValidator validator.
|
|
31
29
|
"""
|
|
32
30
|
|
|
33
|
-
|
|
34
|
-
"""Path to the model."""
|
|
35
|
-
|
|
36
|
-
framework: str = None
|
|
31
|
+
framework: Optional[str] = None
|
|
37
32
|
"""Model framework (e.g. 'pytorch')."""
|
|
38
33
|
|
|
39
|
-
algorithm: str = None
|
|
34
|
+
algorithm: Optional[str] = None
|
|
40
35
|
"""Model algorithm (e.g. 'resnet')."""
|
|
41
36
|
|
|
42
|
-
|
|
43
|
-
"""Base model."""
|
|
44
|
-
|
|
45
|
-
parameters: dict = None
|
|
37
|
+
parameters: Optional[dict] = None
|
|
46
38
|
"""Model validator."""
|
|
47
|
-
|
|
48
|
-
metrics: dict = None
|
|
49
|
-
"""Model metrics."""
|
|
@@ -7,3 +7,13 @@ class ModelStatus(MaterialStatus):
|
|
|
7
7
|
"""
|
|
8
8
|
ModelStatus status.
|
|
9
9
|
"""
|
|
10
|
+
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
state: str,
|
|
14
|
+
message: str | None = None,
|
|
15
|
+
files: list[dict] | None = None,
|
|
16
|
+
metrics: dict | None = None,
|
|
17
|
+
):
|
|
18
|
+
super().__init__(state, message, files)
|
|
19
|
+
self.metrics = metrics if metrics is not None else {}
|
|
@@ -3,8 +3,9 @@ from __future__ import annotations
|
|
|
3
3
|
import typing
|
|
4
4
|
|
|
5
5
|
from digitalhub.entities._commons.enums import EntityTypes
|
|
6
|
-
from digitalhub.entities.
|
|
6
|
+
from digitalhub.entities._processors.context import context_processor
|
|
7
7
|
from digitalhub.entities.artifact.utils import eval_source, process_kwargs
|
|
8
|
+
from digitalhub.utils.types import SourcesOrListOfSources
|
|
8
9
|
|
|
9
10
|
if typing.TYPE_CHECKING:
|
|
10
11
|
from digitalhub.entities.model._base.entity import Model
|
|
@@ -60,7 +61,7 @@ def new_model(
|
|
|
60
61
|
>>> kind="model",
|
|
61
62
|
>>> path="s3://my-bucket/my-key")
|
|
62
63
|
"""
|
|
63
|
-
return
|
|
64
|
+
return context_processor.create_context_entity(
|
|
64
65
|
project=project,
|
|
65
66
|
name=name,
|
|
66
67
|
kind=kind,
|
|
@@ -77,7 +78,7 @@ def log_model(
|
|
|
77
78
|
project: str,
|
|
78
79
|
name: str,
|
|
79
80
|
kind: str,
|
|
80
|
-
source:
|
|
81
|
+
source: SourcesOrListOfSources,
|
|
81
82
|
path: str | None = None,
|
|
82
83
|
**kwargs,
|
|
83
84
|
) -> Model:
|
|
@@ -92,7 +93,7 @@ def log_model(
|
|
|
92
93
|
Object name.
|
|
93
94
|
kind : str
|
|
94
95
|
Kind the object.
|
|
95
|
-
source :
|
|
96
|
+
source : SourcesOrListOfSources
|
|
96
97
|
Model location on local path.
|
|
97
98
|
path : str
|
|
98
99
|
Destination path of the model. If not provided, it's generated.
|
|
@@ -113,7 +114,7 @@ def log_model(
|
|
|
113
114
|
"""
|
|
114
115
|
eval_source(source)
|
|
115
116
|
kwargs = process_kwargs(project, name, source=source, path=path, **kwargs)
|
|
116
|
-
return
|
|
117
|
+
return context_processor.log_material_entity(
|
|
117
118
|
source=source,
|
|
118
119
|
project=project,
|
|
119
120
|
name=name,
|
|
@@ -157,7 +158,7 @@ def get_model(
|
|
|
157
158
|
>>> project="my-project",
|
|
158
159
|
>>> entity_id="my-model-id")
|
|
159
160
|
"""
|
|
160
|
-
return
|
|
161
|
+
return context_processor.read_context_entity(
|
|
161
162
|
identifier=identifier,
|
|
162
163
|
entity_type=ENTITY_TYPE,
|
|
163
164
|
project=project,
|
|
@@ -197,7 +198,7 @@ def get_model_versions(
|
|
|
197
198
|
>>> objs = get_model_versions("my-model-name",
|
|
198
199
|
>>> project="my-project")
|
|
199
200
|
"""
|
|
200
|
-
return
|
|
201
|
+
return context_processor.read_context_entity_versions(
|
|
201
202
|
identifier=identifier,
|
|
202
203
|
entity_type=ENTITY_TYPE,
|
|
203
204
|
project=project,
|
|
@@ -225,7 +226,7 @@ def list_models(project: str, **kwargs) -> list[Model]:
|
|
|
225
226
|
--------
|
|
226
227
|
>>> objs = list_models(project="my-project")
|
|
227
228
|
"""
|
|
228
|
-
return
|
|
229
|
+
return context_processor.list_context_entities(
|
|
229
230
|
project=project,
|
|
230
231
|
entity_type=ENTITY_TYPE,
|
|
231
232
|
**kwargs,
|
|
@@ -250,7 +251,7 @@ def import_model(file: str) -> Model:
|
|
|
250
251
|
--------
|
|
251
252
|
>>> obj = import_model("my-model.yaml")
|
|
252
253
|
"""
|
|
253
|
-
return
|
|
254
|
+
return context_processor.import_context_entity(file)
|
|
254
255
|
|
|
255
256
|
|
|
256
257
|
def load_model(file: str) -> Model:
|
|
@@ -271,7 +272,7 @@ def load_model(file: str) -> Model:
|
|
|
271
272
|
--------
|
|
272
273
|
>>> obj = load_model("my-model.yaml")
|
|
273
274
|
"""
|
|
274
|
-
return
|
|
275
|
+
return context_processor.load_context_entity(file)
|
|
275
276
|
|
|
276
277
|
|
|
277
278
|
def update_model(entity: Model) -> Model:
|
|
@@ -292,7 +293,7 @@ def update_model(entity: Model) -> Model:
|
|
|
292
293
|
--------
|
|
293
294
|
>>> obj = get_model("store://my-model-key")
|
|
294
295
|
"""
|
|
295
|
-
return
|
|
296
|
+
return context_processor.update_context_entity(
|
|
296
297
|
project=entity.project,
|
|
297
298
|
entity_type=entity.ENTITY_TYPE,
|
|
298
299
|
entity_id=entity.id,
|
|
@@ -338,7 +339,7 @@ def delete_model(
|
|
|
338
339
|
>>> project="my-project",
|
|
339
340
|
>>> delete_all_versions=True)
|
|
340
341
|
"""
|
|
341
|
-
return
|
|
342
|
+
return context_processor.delete_context_entity(
|
|
342
343
|
identifier=identifier,
|
|
343
344
|
entity_type=ENTITY_TYPE,
|
|
344
345
|
project=project,
|