digitalhub 0.8.0b15__py3-none-any.whl → 0.9.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of digitalhub might be problematic. Click here for more details.
- digitalhub/__init__.py +19 -2
- digitalhub/client/_base/api_builder.py +16 -0
- digitalhub/client/_base/client.py +67 -0
- digitalhub/client/_base/key_builder.py +52 -0
- digitalhub/client/api.py +2 -38
- digitalhub/client/dhcore/api_builder.py +100 -0
- digitalhub/client/dhcore/client.py +100 -48
- digitalhub/client/dhcore/enums.py +27 -0
- digitalhub/client/dhcore/env.py +4 -2
- digitalhub/client/dhcore/key_builder.py +58 -0
- digitalhub/client/dhcore/utils.py +17 -17
- digitalhub/client/local/api_builder.py +100 -0
- digitalhub/client/local/client.py +22 -0
- digitalhub/client/local/key_builder.py +58 -0
- digitalhub/context/api.py +3 -38
- digitalhub/context/builder.py +10 -23
- digitalhub/context/context.py +20 -92
- digitalhub/entities/_base/context/entity.py +30 -22
- digitalhub/entities/_base/entity/_constructors/metadata.py +12 -1
- digitalhub/entities/_base/entity/_constructors/name.py +1 -1
- digitalhub/entities/_base/entity/_constructors/spec.py +1 -1
- digitalhub/entities/_base/entity/_constructors/status.py +3 -2
- digitalhub/entities/_base/entity/_constructors/uuid.py +1 -1
- digitalhub/entities/_base/entity/builder.py +6 -1
- digitalhub/entities/_base/entity/entity.py +32 -10
- digitalhub/entities/_base/entity/metadata.py +22 -0
- digitalhub/entities/_base/entity/spec.py +7 -2
- digitalhub/entities/_base/executable/entity.py +8 -8
- digitalhub/entities/_base/material/entity.py +49 -17
- digitalhub/entities/_base/material/status.py +0 -31
- digitalhub/entities/_base/material/utils.py +106 -0
- digitalhub/entities/_base/project/entity.py +341 -0
- digitalhub/entities/_base/unversioned/entity.py +3 -24
- digitalhub/entities/_base/versioned/entity.py +2 -26
- digitalhub/entities/_commons/enums.py +103 -0
- digitalhub/entities/_commons/utils.py +83 -0
- digitalhub/entities/_operations/processor.py +1873 -0
- digitalhub/entities/artifact/_base/builder.py +1 -1
- digitalhub/entities/artifact/_base/entity.py +1 -1
- digitalhub/entities/artifact/artifact/builder.py +2 -1
- digitalhub/entities/artifact/crud.py +46 -29
- digitalhub/entities/artifact/utils.py +62 -0
- digitalhub/entities/dataitem/_base/builder.py +1 -1
- digitalhub/entities/dataitem/_base/entity.py +6 -6
- digitalhub/entities/dataitem/crud.py +50 -66
- digitalhub/entities/dataitem/dataitem/builder.py +2 -1
- digitalhub/entities/dataitem/iceberg/builder.py +2 -1
- digitalhub/entities/dataitem/table/builder.py +2 -1
- digitalhub/entities/dataitem/table/entity.py +5 -10
- digitalhub/entities/dataitem/table/models.py +4 -5
- digitalhub/entities/dataitem/utils.py +137 -0
- digitalhub/entities/function/_base/builder.py +1 -1
- digitalhub/entities/function/_base/entity.py +6 -2
- digitalhub/entities/function/crud.py +36 -17
- digitalhub/entities/model/_base/builder.py +1 -1
- digitalhub/entities/model/_base/entity.py +1 -1
- digitalhub/entities/model/crud.py +46 -29
- digitalhub/entities/model/huggingface/builder.py +2 -1
- digitalhub/entities/model/huggingface/spec.py +4 -2
- digitalhub/entities/model/mlflow/builder.py +2 -1
- digitalhub/entities/model/mlflow/models.py +17 -9
- digitalhub/entities/model/mlflow/spec.py +6 -1
- digitalhub/entities/model/mlflow/utils.py +4 -2
- digitalhub/entities/model/model/builder.py +2 -1
- digitalhub/entities/model/sklearn/builder.py +2 -1
- digitalhub/entities/model/utils.py +62 -0
- digitalhub/entities/project/_base/builder.py +2 -2
- digitalhub/entities/project/_base/entity.py +82 -272
- digitalhub/entities/project/crud.py +110 -89
- digitalhub/entities/project/utils.py +35 -0
- digitalhub/entities/run/_base/builder.py +3 -1
- digitalhub/entities/run/_base/entity.py +52 -54
- digitalhub/entities/run/_base/spec.py +15 -7
- digitalhub/entities/run/crud.py +35 -17
- digitalhub/entities/secret/_base/builder.py +2 -2
- digitalhub/entities/secret/_base/entity.py +4 -10
- digitalhub/entities/secret/crud.py +36 -21
- digitalhub/entities/task/_base/builder.py +14 -14
- digitalhub/entities/task/_base/entity.py +21 -14
- digitalhub/entities/task/_base/models.py +35 -6
- digitalhub/entities/task/_base/spec.py +50 -13
- digitalhub/entities/task/_base/utils.py +18 -0
- digitalhub/entities/task/crud.py +35 -15
- digitalhub/entities/workflow/_base/builder.py +1 -1
- digitalhub/entities/workflow/_base/entity.py +22 -6
- digitalhub/entities/workflow/crud.py +36 -17
- digitalhub/factory/utils.py +1 -1
- digitalhub/readers/_base/reader.py +2 -2
- digitalhub/readers/_commons/enums.py +13 -0
- digitalhub/readers/api.py +3 -2
- digitalhub/readers/factory.py +12 -6
- digitalhub/readers/pandas/reader.py +20 -8
- digitalhub/runtimes/_base.py +0 -7
- digitalhub/runtimes/enums.py +12 -0
- digitalhub/stores/_base/store.py +59 -11
- digitalhub/stores/builder.py +5 -5
- digitalhub/stores/local/store.py +43 -4
- digitalhub/stores/remote/store.py +31 -5
- digitalhub/stores/s3/store.py +136 -57
- digitalhub/stores/sql/store.py +122 -47
- digitalhub/utils/exceptions.py +6 -0
- digitalhub/utils/file_utils.py +60 -2
- digitalhub/utils/generic_utils.py +45 -4
- digitalhub/utils/io_utils.py +18 -0
- digitalhub/utils/s3_utils.py +17 -0
- digitalhub/utils/uri_utils.py +153 -15
- {digitalhub-0.8.0b15.dist-info → digitalhub-0.9.0.dist-info}/LICENSE.txt +1 -1
- {digitalhub-0.8.0b15.dist-info → digitalhub-0.9.0.dist-info}/METADATA +11 -11
- {digitalhub-0.8.0b15.dist-info → digitalhub-0.9.0.dist-info}/RECORD +117 -115
- {digitalhub-0.8.0b15.dist-info → digitalhub-0.9.0.dist-info}/WHEEL +1 -1
- test/local/instances/test_validate.py +55 -0
- test/testkfp.py +4 -1
- digitalhub/datastores/_base/datastore.py +0 -85
- digitalhub/datastores/api.py +0 -37
- digitalhub/datastores/builder.py +0 -110
- digitalhub/datastores/local/datastore.py +0 -50
- digitalhub/datastores/remote/__init__.py +0 -0
- digitalhub/datastores/remote/datastore.py +0 -31
- digitalhub/datastores/s3/__init__.py +0 -0
- digitalhub/datastores/s3/datastore.py +0 -46
- digitalhub/datastores/sql/__init__.py +0 -0
- digitalhub/datastores/sql/datastore.py +0 -68
- digitalhub/entities/_base/api_utils.py +0 -620
- digitalhub/entities/_base/crud.py +0 -468
- digitalhub/entities/function/_base/models.py +0 -118
- digitalhub/entities/utils/__init__.py +0 -0
- digitalhub/entities/utils/api.py +0 -346
- digitalhub/entities/utils/entity_types.py +0 -19
- digitalhub/entities/utils/state.py +0 -31
- digitalhub/entities/utils/utils.py +0 -202
- /digitalhub/{context → entities/_base/project}/__init__.py +0 -0
- /digitalhub/{datastores → entities/_commons}/__init__.py +0 -0
- /digitalhub/{datastores/_base → entities/_operations}/__init__.py +0 -0
- /digitalhub/{datastores/local → readers/_commons}/__init__.py +0 -0
- {digitalhub-0.8.0b15.dist-info → digitalhub-0.9.0.dist-info}/top_level.txt +0 -0
|
@@ -3,9 +3,10 @@ from __future__ import annotations
|
|
|
3
3
|
import typing
|
|
4
4
|
|
|
5
5
|
from digitalhub.context.api import get_context
|
|
6
|
-
from digitalhub.entities._base.api_utils import create_entity_api_ctx, read_entity_api_ctx, update_entity_api_ctx
|
|
7
6
|
from digitalhub.entities._base.entity.entity import Entity
|
|
7
|
+
from digitalhub.entities._operations.processor import processor
|
|
8
8
|
from digitalhub.utils.generic_utils import get_timestamp
|
|
9
|
+
from digitalhub.utils.io_utils import write_yaml
|
|
9
10
|
|
|
10
11
|
if typing.TYPE_CHECKING:
|
|
11
12
|
from digitalhub.context.context import Context
|
|
@@ -26,7 +27,11 @@ class ContextEntity(Entity):
|
|
|
26
27
|
) -> None:
|
|
27
28
|
super().__init__(kind, metadata, spec, status, user)
|
|
28
29
|
self.project = project
|
|
29
|
-
self.
|
|
30
|
+
self.name: str
|
|
31
|
+
self.id: str
|
|
32
|
+
|
|
33
|
+
# Different behaviour for versioned and unversioned
|
|
34
|
+
self._obj_attr.extend(["project", "id", "name"])
|
|
30
35
|
|
|
31
36
|
##############################
|
|
32
37
|
# Save / Refresh / Export
|
|
@@ -46,49 +51,52 @@ class ContextEntity(Entity):
|
|
|
46
51
|
ContextEntity
|
|
47
52
|
Entity saved.
|
|
48
53
|
"""
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
return self._update(obj)
|
|
54
|
+
if update:
|
|
55
|
+
return self._update()
|
|
56
|
+
return self._save()
|
|
53
57
|
|
|
54
|
-
def _save(self
|
|
58
|
+
def _save(self) -> ContextEntity:
|
|
55
59
|
"""
|
|
56
60
|
Save entity into backend.
|
|
57
61
|
|
|
58
|
-
Parameters
|
|
59
|
-
----------
|
|
60
|
-
obj : dict
|
|
61
|
-
Object instance as dictionary.
|
|
62
|
-
|
|
63
62
|
Returns
|
|
64
63
|
-------
|
|
65
64
|
ContextEntity
|
|
66
65
|
Entity saved.
|
|
67
66
|
"""
|
|
68
|
-
new_obj =
|
|
67
|
+
new_obj = processor.create_context_entity(_entity=self)
|
|
69
68
|
self._update_attributes(new_obj)
|
|
70
69
|
return self
|
|
71
70
|
|
|
72
|
-
def _update(self
|
|
71
|
+
def _update(self) -> ContextEntity:
|
|
73
72
|
"""
|
|
74
73
|
Update entity in backend.
|
|
75
74
|
|
|
76
|
-
Parameters
|
|
77
|
-
----------
|
|
78
|
-
obj : dict
|
|
79
|
-
Object instance as dictionary.
|
|
80
|
-
|
|
81
75
|
Returns
|
|
82
76
|
-------
|
|
83
77
|
ContextEntity
|
|
84
78
|
Entity updated.
|
|
85
79
|
"""
|
|
86
80
|
if self._context().local:
|
|
87
|
-
self.metadata.updated =
|
|
88
|
-
new_obj =
|
|
81
|
+
self.metadata.updated = self.metadata.updated = get_timestamp()
|
|
82
|
+
new_obj = processor.update_context_entity(self.project, self.ENTITY_TYPE, self.id, self.to_dict())
|
|
89
83
|
self._update_attributes(new_obj)
|
|
90
84
|
return self
|
|
91
85
|
|
|
86
|
+
def export(self) -> str:
|
|
87
|
+
"""
|
|
88
|
+
Export object as a YAML file in the context folder.
|
|
89
|
+
|
|
90
|
+
Returns
|
|
91
|
+
-------
|
|
92
|
+
str
|
|
93
|
+
Exported filepath.
|
|
94
|
+
"""
|
|
95
|
+
obj = self.to_dict()
|
|
96
|
+
pth = self._context().root / f"{self.ENTITY_TYPE}s-{self.id}.yaml"
|
|
97
|
+
write_yaml(pth, obj)
|
|
98
|
+
return str(pth)
|
|
99
|
+
|
|
92
100
|
def refresh(self) -> ContextEntity:
|
|
93
101
|
"""
|
|
94
102
|
Refresh object from backend.
|
|
@@ -98,7 +106,7 @@ class ContextEntity(Entity):
|
|
|
98
106
|
ContextEntity
|
|
99
107
|
Entity refreshed.
|
|
100
108
|
"""
|
|
101
|
-
new_obj =
|
|
109
|
+
new_obj = processor.read_context_entity(self.key)
|
|
102
110
|
self._update_attributes(new_obj)
|
|
103
111
|
return self
|
|
104
112
|
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from pydantic import ValidationError
|
|
4
|
+
|
|
5
|
+
from digitalhub.entities._base.entity.metadata import Metadata, RelationshipValidator
|
|
6
|
+
from digitalhub.utils.exceptions import BuilderError
|
|
4
7
|
from digitalhub.utils.generic_utils import get_timestamp
|
|
5
8
|
|
|
6
9
|
|
|
@@ -41,4 +44,12 @@ def parse_arguments(**kwargs) -> dict:
|
|
|
41
44
|
kwargs["created"] = get_timestamp()
|
|
42
45
|
if "updated" not in kwargs or kwargs["updated"] is None:
|
|
43
46
|
kwargs["updated"] = kwargs["created"]
|
|
47
|
+
if "relationships" in kwargs:
|
|
48
|
+
if not isinstance(kwargs["relationships"], list):
|
|
49
|
+
raise BuilderError("Invalid relationships format. Must be a list of maps.")
|
|
50
|
+
for relationship in kwargs["relationships"]:
|
|
51
|
+
try:
|
|
52
|
+
RelationshipValidator(**relationship)
|
|
53
|
+
except ValidationError as e:
|
|
54
|
+
raise BuilderError(f"Malformed relationship: {e}") from e
|
|
44
55
|
return kwargs
|
|
@@ -29,5 +29,5 @@ def build_spec(spec_cls: Spec, spec_validator: SpecValidator, validate: bool = T
|
|
|
29
29
|
Spec object.
|
|
30
30
|
"""
|
|
31
31
|
if validate:
|
|
32
|
-
kwargs = spec_validator(**kwargs).
|
|
32
|
+
kwargs = spec_validator(**kwargs).to_dict()
|
|
33
33
|
return spec_cls(**kwargs)
|
|
@@ -2,7 +2,8 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import typing
|
|
4
4
|
|
|
5
|
-
from digitalhub.entities.
|
|
5
|
+
from digitalhub.entities._commons.enums import State
|
|
6
|
+
from digitalhub.utils.exceptions import BuilderError
|
|
6
7
|
|
|
7
8
|
if typing.TYPE_CHECKING:
|
|
8
9
|
from digitalhub.entities._base.entity.status import Status
|
|
@@ -48,5 +49,5 @@ def parse_arguments(**kwargs) -> dict:
|
|
|
48
49
|
kwargs["state"] = State.CREATED.value
|
|
49
50
|
else:
|
|
50
51
|
if kwargs["state"] not in State.__members__:
|
|
51
|
-
raise
|
|
52
|
+
raise BuilderError(f"Invalid state: {state}")
|
|
52
53
|
return kwargs
|
|
@@ -106,7 +106,12 @@ class EntityBuilder:
|
|
|
106
106
|
Spec
|
|
107
107
|
Spec object.
|
|
108
108
|
"""
|
|
109
|
-
return build_spec(
|
|
109
|
+
return build_spec(
|
|
110
|
+
self.ENTITY_SPEC_CLASS,
|
|
111
|
+
self.ENTITY_SPEC_VALIDATOR,
|
|
112
|
+
validate=validate,
|
|
113
|
+
**kwargs,
|
|
114
|
+
)
|
|
110
115
|
|
|
111
116
|
def build_status(self, **kwargs) -> Status:
|
|
112
117
|
"""
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import typing
|
|
4
|
-
from abc import
|
|
4
|
+
from abc import abstractmethod
|
|
5
5
|
|
|
6
6
|
from digitalhub.entities._base._base.entity import Base
|
|
7
|
-
from digitalhub.factory.api import build_entity_from_dict
|
|
8
7
|
|
|
9
8
|
if typing.TYPE_CHECKING:
|
|
10
9
|
from digitalhub.entities._base.entity.metadata import Metadata
|
|
@@ -12,7 +11,7 @@ if typing.TYPE_CHECKING:
|
|
|
12
11
|
from digitalhub.entities._base.entity.status import Status
|
|
13
12
|
|
|
14
13
|
|
|
15
|
-
class Entity(Base
|
|
14
|
+
class Entity(Base):
|
|
16
15
|
"""
|
|
17
16
|
Abstract class for entities.
|
|
18
17
|
|
|
@@ -56,7 +55,7 @@ class Entity(Base, metaclass=ABCMeta):
|
|
|
56
55
|
Abstract refresh method.
|
|
57
56
|
"""
|
|
58
57
|
|
|
59
|
-
def _update_attributes(self, obj:
|
|
58
|
+
def _update_attributes(self, obj: Entity) -> None:
|
|
60
59
|
"""
|
|
61
60
|
Update attributes.
|
|
62
61
|
|
|
@@ -69,18 +68,41 @@ class Entity(Base, metaclass=ABCMeta):
|
|
|
69
68
|
-------
|
|
70
69
|
None
|
|
71
70
|
"""
|
|
72
|
-
|
|
73
|
-
self.
|
|
74
|
-
self.
|
|
75
|
-
self.
|
|
76
|
-
self.user = new_obj.user
|
|
71
|
+
self.metadata = obj.metadata
|
|
72
|
+
self.spec = obj.spec
|
|
73
|
+
self.status = obj.status
|
|
74
|
+
self.user = obj.user
|
|
77
75
|
|
|
78
76
|
@abstractmethod
|
|
79
|
-
def export(self
|
|
77
|
+
def export(self) -> str:
|
|
80
78
|
"""
|
|
81
79
|
Abstract export method.
|
|
82
80
|
"""
|
|
83
81
|
|
|
82
|
+
def add_relationship(self, relation: str, dest: str, source: str | None = None) -> None:
|
|
83
|
+
"""
|
|
84
|
+
Add relationship to entity metadata.
|
|
85
|
+
|
|
86
|
+
Parameters
|
|
87
|
+
----------
|
|
88
|
+
relation : str
|
|
89
|
+
The type of relationship.
|
|
90
|
+
dest : str
|
|
91
|
+
The target entity.
|
|
92
|
+
source : str
|
|
93
|
+
The source entity.
|
|
94
|
+
|
|
95
|
+
Returns
|
|
96
|
+
-------
|
|
97
|
+
None
|
|
98
|
+
"""
|
|
99
|
+
if self.metadata.relationships is None:
|
|
100
|
+
self.metadata.relationships = []
|
|
101
|
+
obj = {"type": relation, "dest": dest}
|
|
102
|
+
if source is not None:
|
|
103
|
+
obj["source"] = source
|
|
104
|
+
self.metadata.relationships.append(obj)
|
|
105
|
+
|
|
84
106
|
def to_dict(self) -> dict:
|
|
85
107
|
"""
|
|
86
108
|
Override default to_dict method to add the possibility to exclude
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
4
|
+
|
|
3
5
|
from digitalhub.entities._base._base.entity import Base
|
|
6
|
+
from digitalhub.entities._commons.enums import Relationship
|
|
4
7
|
|
|
5
8
|
|
|
6
9
|
class Metadata(Base):
|
|
@@ -24,6 +27,7 @@ class Metadata(Base):
|
|
|
24
27
|
updated: str | None = None,
|
|
25
28
|
updated_by: str | None = None,
|
|
26
29
|
embedded: bool | None = None,
|
|
30
|
+
relationships: list[dict] | None = None,
|
|
27
31
|
ref: str | None = None,
|
|
28
32
|
**kwargs,
|
|
29
33
|
) -> None:
|
|
@@ -37,6 +41,7 @@ class Metadata(Base):
|
|
|
37
41
|
self.created_by = created_by
|
|
38
42
|
self.updated_by = updated_by
|
|
39
43
|
self.embedded = embedded
|
|
44
|
+
self.relationships = relationships
|
|
40
45
|
self.ref = ref
|
|
41
46
|
|
|
42
47
|
self._any_setter(**kwargs)
|
|
@@ -57,3 +62,20 @@ class Metadata(Base):
|
|
|
57
62
|
An entity metadata object.
|
|
58
63
|
"""
|
|
59
64
|
return cls(**obj)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class RelationshipValidator(BaseModel):
|
|
68
|
+
"""
|
|
69
|
+
A class representing the relationship of an entity.
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
model_config = ConfigDict(use_enum_values=True)
|
|
73
|
+
|
|
74
|
+
type_: Relationship = Field(default=None, alias="type")
|
|
75
|
+
"""The type of relationship."""
|
|
76
|
+
|
|
77
|
+
source: str = None
|
|
78
|
+
"""The source entity."""
|
|
79
|
+
|
|
80
|
+
dest: str = None
|
|
81
|
+
"""The target entity."""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from pydantic import BaseModel
|
|
3
|
+
from pydantic import BaseModel, ConfigDict
|
|
4
4
|
|
|
5
5
|
from digitalhub.entities._base._base.entity import Base
|
|
6
6
|
|
|
@@ -30,7 +30,7 @@ class Spec(Base):
|
|
|
30
30
|
return cls(**obj)
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
class SpecValidator(BaseModel
|
|
33
|
+
class SpecValidator(BaseModel):
|
|
34
34
|
"""
|
|
35
35
|
A class representing the parameters of an entity.
|
|
36
36
|
This base class is used to define the parameters of an entity
|
|
@@ -38,6 +38,11 @@ class SpecValidator(BaseModel, extra="ignore"):
|
|
|
38
38
|
to the constructor.
|
|
39
39
|
"""
|
|
40
40
|
|
|
41
|
+
model_config = ConfigDict(extra="ignore", use_enum_values=True)
|
|
42
|
+
|
|
43
|
+
def to_dict(self) -> dict:
|
|
44
|
+
return self.model_dump(by_alias=True, exclude_none=True)
|
|
45
|
+
|
|
41
46
|
|
|
42
47
|
class MaterialSpec(Spec):
|
|
43
48
|
"""
|
|
@@ -2,11 +2,11 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import typing
|
|
4
4
|
|
|
5
|
-
from digitalhub.entities._base.api_utils import list_entity_api_ctx
|
|
6
5
|
from digitalhub.entities._base.versioned.entity import VersionedEntity
|
|
6
|
+
from digitalhub.entities._commons.enums import EntityTypes
|
|
7
|
+
from digitalhub.entities._operations.processor import processor
|
|
7
8
|
from digitalhub.entities.run.crud import delete_run, get_run, list_runs
|
|
8
9
|
from digitalhub.entities.task.crud import delete_task
|
|
9
|
-
from digitalhub.entities.utils.entity_types import EntityTypes
|
|
10
10
|
from digitalhub.factory.api import build_entity_from_dict, build_entity_from_params
|
|
11
11
|
from digitalhub.utils.exceptions import EntityAlreadyExistsError, EntityError
|
|
12
12
|
|
|
@@ -141,7 +141,7 @@ class ExecutableEntity(VersionedEntity):
|
|
|
141
141
|
|
|
142
142
|
# Override kwargs
|
|
143
143
|
kwargs["project"] = self.project
|
|
144
|
-
kwargs[
|
|
144
|
+
kwargs[self.ENTITY_TYPE] = self._get_executable_string()
|
|
145
145
|
kwargs["kind"] = task_kind
|
|
146
146
|
|
|
147
147
|
# Create object instance
|
|
@@ -176,7 +176,7 @@ class ExecutableEntity(VersionedEntity):
|
|
|
176
176
|
resp = self._get_task_from_backend(kind)
|
|
177
177
|
if not resp:
|
|
178
178
|
raise EntityError(f"Task {kind} is not created")
|
|
179
|
-
self._tasks[kind] =
|
|
179
|
+
self._tasks[kind] = resp[0]
|
|
180
180
|
return self._tasks[kind]
|
|
181
181
|
|
|
182
182
|
def update_task(self, kind: str, **kwargs) -> Task:
|
|
@@ -203,7 +203,7 @@ class ExecutableEntity(VersionedEntity):
|
|
|
203
203
|
# Update kwargs
|
|
204
204
|
kwargs["project"] = self.project
|
|
205
205
|
kwargs["kind"] = kind
|
|
206
|
-
kwargs[
|
|
206
|
+
kwargs[self.ENTITY_TYPE] = self._get_executable_string()
|
|
207
207
|
kwargs["uuid"] = self._tasks[kind].id
|
|
208
208
|
|
|
209
209
|
# Update task
|
|
@@ -246,8 +246,8 @@ class ExecutableEntity(VersionedEntity):
|
|
|
246
246
|
list
|
|
247
247
|
Response from backend.
|
|
248
248
|
"""
|
|
249
|
-
params = {
|
|
250
|
-
return
|
|
249
|
+
params = {self.ENTITY_TYPE: self._get_executable_string(), "kind": kind}
|
|
250
|
+
return processor.list_context_entities(self.project, EntityTypes.TASK.value, params=params)
|
|
251
251
|
|
|
252
252
|
def _check_task_in_backend(self, kind: str) -> bool:
|
|
253
253
|
"""
|
|
@@ -370,7 +370,7 @@ class ExecutableEntity(VersionedEntity):
|
|
|
370
370
|
"""
|
|
371
371
|
if kwargs is None:
|
|
372
372
|
kwargs = {}
|
|
373
|
-
kwargs["params"] = {
|
|
373
|
+
kwargs["params"] = {self.ENTITY_TYPE: self._get_executable_string()}
|
|
374
374
|
return list_runs(self.project, **kwargs)
|
|
375
375
|
|
|
376
376
|
def delete_run(
|
|
@@ -3,8 +3,8 @@ from __future__ import annotations
|
|
|
3
3
|
import typing
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
|
|
6
|
-
from digitalhub.entities._base.api_utils import files_info_get_api, files_info_put_api
|
|
7
6
|
from digitalhub.entities._base.versioned.entity import VersionedEntity
|
|
7
|
+
from digitalhub.entities._operations.processor import processor
|
|
8
8
|
from digitalhub.stores.api import get_store
|
|
9
9
|
|
|
10
10
|
if typing.TYPE_CHECKING:
|
|
@@ -48,23 +48,20 @@ class MaterialEntity(VersionedEntity):
|
|
|
48
48
|
MaterialEntity
|
|
49
49
|
Entity saved.
|
|
50
50
|
"""
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
# Evaluate files info list length
|
|
53
52
|
files = None
|
|
54
53
|
if self.status.files is not None and len(self.status.files) > 5 and not self._context().local:
|
|
55
|
-
files =
|
|
54
|
+
files = self.status.files
|
|
55
|
+
self.status.files = []
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
new_obj: MaterialEntity = self._save(obj)
|
|
59
|
-
else:
|
|
60
|
-
new_obj: MaterialEntity = self._update(obj)
|
|
57
|
+
obj: MaterialEntity = super().save(update)
|
|
61
58
|
|
|
62
59
|
# Handle files info
|
|
63
60
|
if files is not None:
|
|
64
|
-
|
|
65
|
-
self.
|
|
61
|
+
processor.update_files_info(self.project, self.ENTITY_TYPE, self.id, files)
|
|
62
|
+
self.add_files_info(files)
|
|
66
63
|
|
|
67
|
-
return
|
|
64
|
+
return obj
|
|
68
65
|
|
|
69
66
|
##############################
|
|
70
67
|
# I/O Methods
|
|
@@ -81,7 +78,7 @@ class MaterialEntity(VersionedEntity):
|
|
|
81
78
|
List of file paths.
|
|
82
79
|
"""
|
|
83
80
|
store = get_store(self.spec.path)
|
|
84
|
-
paths = self.
|
|
81
|
+
paths = self.get_file_paths()
|
|
85
82
|
dst = store._build_temp()
|
|
86
83
|
return store.download(self.spec.path, dst=dst, src=paths)
|
|
87
84
|
|
|
@@ -130,7 +127,7 @@ class MaterialEntity(VersionedEntity):
|
|
|
130
127
|
dataitem/data.csv
|
|
131
128
|
"""
|
|
132
129
|
store = get_store(self.spec.path)
|
|
133
|
-
paths = self.
|
|
130
|
+
paths = self.get_file_paths()
|
|
134
131
|
|
|
135
132
|
if destination is None:
|
|
136
133
|
dst = self._context().root / self.ENTITY_TYPE
|
|
@@ -171,9 +168,44 @@ class MaterialEntity(VersionedEntity):
|
|
|
171
168
|
paths = store.upload(source, self.spec.path)
|
|
172
169
|
|
|
173
170
|
# Update files info
|
|
174
|
-
files_info = store.get_file_info(paths)
|
|
171
|
+
files_info = store.get_file_info(self.spec.path, paths)
|
|
175
172
|
self._update_files_info(files_info)
|
|
176
173
|
|
|
174
|
+
##############################
|
|
175
|
+
# Public Helpers
|
|
176
|
+
##############################
|
|
177
|
+
|
|
178
|
+
def add_files_info(self, files: list[dict]) -> None:
|
|
179
|
+
"""
|
|
180
|
+
Add a file to the status.
|
|
181
|
+
|
|
182
|
+
Parameters
|
|
183
|
+
----------
|
|
184
|
+
files : list[dict]
|
|
185
|
+
Files to add.
|
|
186
|
+
|
|
187
|
+
Returns
|
|
188
|
+
-------
|
|
189
|
+
None
|
|
190
|
+
"""
|
|
191
|
+
path_list = self.get_file_paths()
|
|
192
|
+
for f in files:
|
|
193
|
+
if f.get("path") not in path_list:
|
|
194
|
+
self.status.files.append(f)
|
|
195
|
+
|
|
196
|
+
def get_file_paths(self) -> list[str]:
|
|
197
|
+
"""
|
|
198
|
+
Get the paths of the files in the status.
|
|
199
|
+
|
|
200
|
+
Returns
|
|
201
|
+
-------
|
|
202
|
+
list[str]
|
|
203
|
+
Paths of the files in the status.
|
|
204
|
+
"""
|
|
205
|
+
if self.status.files is None:
|
|
206
|
+
self.status.files = []
|
|
207
|
+
return [f.get("path") for f in self.status.files]
|
|
208
|
+
|
|
177
209
|
##############################
|
|
178
210
|
# Private Helpers
|
|
179
211
|
##############################
|
|
@@ -194,7 +226,7 @@ class MaterialEntity(VersionedEntity):
|
|
|
194
226
|
if files_info is None:
|
|
195
227
|
return
|
|
196
228
|
self.refresh()
|
|
197
|
-
self.
|
|
229
|
+
self.add_files_info(files_info)
|
|
198
230
|
self.save(update=True)
|
|
199
231
|
|
|
200
232
|
def _get_files_info(self) -> None:
|
|
@@ -206,9 +238,9 @@ class MaterialEntity(VersionedEntity):
|
|
|
206
238
|
None
|
|
207
239
|
"""
|
|
208
240
|
if not self._context().local and not self.status.files:
|
|
209
|
-
files =
|
|
241
|
+
files = processor.read_files_info(
|
|
210
242
|
project=self.project,
|
|
211
243
|
entity_type=self.ENTITY_TYPE,
|
|
212
244
|
entity_id=self.id,
|
|
213
245
|
)
|
|
214
|
-
self.
|
|
246
|
+
self.add_files_info(files)
|
|
@@ -15,35 +15,4 @@ class MaterialStatus(Status):
|
|
|
15
15
|
files: list[dict] | None = None,
|
|
16
16
|
) -> None:
|
|
17
17
|
super().__init__(state, message)
|
|
18
|
-
if files is None:
|
|
19
|
-
files = []
|
|
20
18
|
self.files = files
|
|
21
|
-
|
|
22
|
-
def add_files_info(self, files: list[dict]) -> None:
|
|
23
|
-
"""
|
|
24
|
-
Add a file to the status.
|
|
25
|
-
|
|
26
|
-
Parameters
|
|
27
|
-
----------
|
|
28
|
-
files : list[dict]
|
|
29
|
-
Files to add.
|
|
30
|
-
|
|
31
|
-
Returns
|
|
32
|
-
-------
|
|
33
|
-
None
|
|
34
|
-
"""
|
|
35
|
-
path_list = self.get_file_paths()
|
|
36
|
-
for f in files:
|
|
37
|
-
if f.get("path") not in path_list:
|
|
38
|
-
self.files.append(f)
|
|
39
|
-
|
|
40
|
-
def get_file_paths(self) -> list[str]:
|
|
41
|
-
"""
|
|
42
|
-
Get the paths of the files in the status.
|
|
43
|
-
|
|
44
|
-
Returns
|
|
45
|
-
-------
|
|
46
|
-
list[str]
|
|
47
|
-
Paths of the files in the status.
|
|
48
|
-
"""
|
|
49
|
-
return [f.get("path") for f in self.files]
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from digitalhub.utils.file_utils import eval_zip_type
|
|
6
|
+
from digitalhub.utils.s3_utils import get_s3_bucket
|
|
7
|
+
from digitalhub.utils.uri_utils import S3Schemes, has_local_scheme
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def eval_local_source(source: str | list[str]) -> None:
|
|
11
|
+
"""
|
|
12
|
+
Evaluate if source is local.
|
|
13
|
+
|
|
14
|
+
Parameters
|
|
15
|
+
----------
|
|
16
|
+
source : str | list[str]
|
|
17
|
+
Source(s).
|
|
18
|
+
|
|
19
|
+
Returns
|
|
20
|
+
-------
|
|
21
|
+
None
|
|
22
|
+
"""
|
|
23
|
+
if isinstance(source, list):
|
|
24
|
+
if not source:
|
|
25
|
+
raise ValueError("Empty list of sources.")
|
|
26
|
+
source_is_local = all(has_local_scheme(s) for s in source)
|
|
27
|
+
for s in source:
|
|
28
|
+
if Path(s).is_dir():
|
|
29
|
+
raise ValueError(f"Invalid source path: {s}. List of paths must be list of files, not directories.")
|
|
30
|
+
else:
|
|
31
|
+
source_is_local = has_local_scheme(source)
|
|
32
|
+
|
|
33
|
+
if not source_is_local:
|
|
34
|
+
raise ValueError("Invalid source path. Source must be a local path.")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def eval_zip_sources(source: str | list[str]) -> str:
|
|
38
|
+
"""
|
|
39
|
+
Evaluate zip sources.
|
|
40
|
+
|
|
41
|
+
Parameters
|
|
42
|
+
----------
|
|
43
|
+
source : str | list[str]
|
|
44
|
+
Source(s).
|
|
45
|
+
|
|
46
|
+
Returns
|
|
47
|
+
-------
|
|
48
|
+
str
|
|
49
|
+
S3Schemes.
|
|
50
|
+
"""
|
|
51
|
+
if isinstance(source, list):
|
|
52
|
+
if len(source) > 1:
|
|
53
|
+
return S3Schemes.S3.value
|
|
54
|
+
path = source[0]
|
|
55
|
+
else:
|
|
56
|
+
if Path(source).is_dir():
|
|
57
|
+
return S3Schemes.S3.value
|
|
58
|
+
path = source
|
|
59
|
+
|
|
60
|
+
if not eval_zip_type(path):
|
|
61
|
+
return S3Schemes.S3.value
|
|
62
|
+
return S3Schemes.ZIP_S3.value
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def build_log_path_from_source(
|
|
66
|
+
project: str,
|
|
67
|
+
entity_type: str,
|
|
68
|
+
name: str,
|
|
69
|
+
uuid: str,
|
|
70
|
+
source: str | list[str],
|
|
71
|
+
) -> str:
|
|
72
|
+
"""
|
|
73
|
+
Build log path.
|
|
74
|
+
|
|
75
|
+
Parameters
|
|
76
|
+
----------
|
|
77
|
+
project : str
|
|
78
|
+
Project name.
|
|
79
|
+
entity_type : str
|
|
80
|
+
Entity type.
|
|
81
|
+
name : str
|
|
82
|
+
Object name.
|
|
83
|
+
uuid : str
|
|
84
|
+
Object UUID.
|
|
85
|
+
source : str | list[str]
|
|
86
|
+
Source(s).
|
|
87
|
+
|
|
88
|
+
Returns
|
|
89
|
+
-------
|
|
90
|
+
str
|
|
91
|
+
Log path.
|
|
92
|
+
"""
|
|
93
|
+
scheme = eval_zip_sources(source)
|
|
94
|
+
path = f"{scheme}://{get_s3_bucket()}/{project}/{entity_type}/{name}/{uuid}"
|
|
95
|
+
|
|
96
|
+
if isinstance(source, list) and len(source) >= 1:
|
|
97
|
+
if len(source) > 1:
|
|
98
|
+
path += "/"
|
|
99
|
+
else:
|
|
100
|
+
path += f"/{Path(source[0]).name}"
|
|
101
|
+
elif Path(source).is_dir():
|
|
102
|
+
path += "/"
|
|
103
|
+
elif Path(source).is_file():
|
|
104
|
+
path += f"/{Path(source).name}"
|
|
105
|
+
|
|
106
|
+
return path
|