zenml-nightly 0.70.0.dev20241128__py3-none-any.whl → 0.70.0.dev20241130__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.
- zenml/VERSION +1 -1
- zenml/artifacts/artifact_config.py +7 -1
- zenml/artifacts/utils.py +55 -30
- zenml/cli/__init__.py +15 -0
- zenml/cli/base.py +4 -4
- zenml/cli/pipeline.py +80 -0
- zenml/cli/server.py +1 -1
- zenml/cli/stack.py +0 -3
- zenml/cli/stack_components.py +0 -1
- zenml/cli/utils.py +0 -5
- zenml/client.py +8 -18
- zenml/config/compiler.py +12 -3
- zenml/config/pipeline_configurations.py +20 -0
- zenml/config/pipeline_run_configuration.py +1 -0
- zenml/config/step_configurations.py +21 -0
- zenml/enums.py +1 -0
- zenml/integrations/feast/__init__.py +1 -1
- zenml/integrations/feast/feature_stores/feast_feature_store.py +13 -9
- zenml/materializers/built_in_materializer.py +18 -1
- zenml/materializers/structured_string_materializer.py +8 -3
- zenml/model/model.py +11 -3
- zenml/model/utils.py +18 -16
- zenml/models/__init__.py +6 -0
- zenml/models/v2/core/artifact_version.py +6 -3
- zenml/models/v2/core/component.py +0 -22
- zenml/models/v2/core/model_version.py +6 -3
- zenml/models/v2/core/pipeline_run.py +19 -3
- zenml/models/v2/core/run_metadata.py +30 -9
- zenml/models/v2/core/step_run.py +6 -4
- zenml/models/v2/misc/run_metadata.py +38 -0
- zenml/orchestrators/input_utils.py +19 -6
- zenml/orchestrators/publish_utils.py +12 -5
- zenml/orchestrators/step_launcher.py +7 -3
- zenml/orchestrators/step_run_utils.py +18 -6
- zenml/orchestrators/step_runner.py +39 -2
- zenml/orchestrators/utils.py +0 -21
- zenml/pipelines/pipeline_decorator.py +4 -0
- zenml/pipelines/pipeline_definition.py +14 -3
- zenml/pipelines/run_utils.py +9 -5
- zenml/steps/base_step.py +11 -1
- zenml/steps/entrypoint_function_utils.py +4 -2
- zenml/steps/step_decorator.py +4 -0
- zenml/steps/utils.py +23 -7
- zenml/types.py +4 -0
- zenml/utils/metadata_utils.py +186 -153
- zenml/utils/string_utils.py +41 -16
- zenml/utils/visualization_utils.py +4 -1
- zenml/zen_server/routers/workspaces_endpoints.py +19 -19
- zenml/zen_server/template_execution/utils.py +1 -0
- zenml/zen_stores/migrations/versions/b73bc71f1106_remove_component_spec_path.py +36 -0
- zenml/zen_stores/migrations/versions/cc269488e5a9_separate_run_metadata.py +135 -0
- zenml/zen_stores/schemas/__init__.py +5 -1
- zenml/zen_stores/schemas/artifact_schemas.py +12 -11
- zenml/zen_stores/schemas/component_schemas.py +0 -3
- zenml/zen_stores/schemas/model_schemas.py +13 -11
- zenml/zen_stores/schemas/pipeline_run_schemas.py +44 -16
- zenml/zen_stores/schemas/run_metadata_schemas.py +66 -31
- zenml/zen_stores/schemas/step_run_schemas.py +32 -12
- zenml/zen_stores/schemas/utils.py +47 -3
- zenml/zen_stores/sql_zen_store.py +117 -34
- {zenml_nightly-0.70.0.dev20241128.dist-info → zenml_nightly-0.70.0.dev20241130.dist-info}/METADATA +1 -1
- {zenml_nightly-0.70.0.dev20241128.dist-info → zenml_nightly-0.70.0.dev20241130.dist-info}/RECORD +65 -62
- {zenml_nightly-0.70.0.dev20241128.dist-info → zenml_nightly-0.70.0.dev20241130.dist-info}/LICENSE +0 -0
- {zenml_nightly-0.70.0.dev20241128.dist-info → zenml_nightly-0.70.0.dev20241130.dist-info}/WHEEL +0 -0
- {zenml_nightly-0.70.0.dev20241128.dist-info → zenml_nightly-0.70.0.dev20241130.dist-info}/entry_points.txt +0 -0
@@ -28,7 +28,7 @@ from typing import (
|
|
28
28
|
)
|
29
29
|
|
30
30
|
from zenml.artifact_stores.base_artifact_store import BaseArtifactStore
|
31
|
-
from zenml.enums import ArtifactType
|
31
|
+
from zenml.enums import ArtifactType, VisualizationType
|
32
32
|
from zenml.logger import get_logger
|
33
33
|
from zenml.materializers.base_materializer import BaseMaterializer
|
34
34
|
from zenml.materializers.materializer_registry import materializer_registry
|
@@ -415,6 +415,23 @@ class BuiltInContainerMaterializer(BaseMaterializer):
|
|
415
415
|
self.artifact_store.rmtree(entry["path"])
|
416
416
|
raise e
|
417
417
|
|
418
|
+
# save dict type objects to JSON file with JSON visualization type
|
419
|
+
def save_visualizations(self, data: Any) -> Dict[str, "VisualizationType"]:
|
420
|
+
"""Save visualizations for the given data.
|
421
|
+
|
422
|
+
Args:
|
423
|
+
data: The data to save visualizations for.
|
424
|
+
|
425
|
+
Returns:
|
426
|
+
A dictionary of visualization URIs and their types.
|
427
|
+
"""
|
428
|
+
# dict/list type objects are always saved as JSON files
|
429
|
+
# doesn't work for non-serializable types as they
|
430
|
+
# are saved as list of lists in different files
|
431
|
+
if _is_serializable(data):
|
432
|
+
return {self.data_path: VisualizationType.JSON}
|
433
|
+
return {}
|
434
|
+
|
418
435
|
def extract_metadata(self, data: Any) -> Dict[str, "MetadataType"]:
|
419
436
|
"""Extract metadata from the given built-in container object.
|
420
437
|
|
@@ -19,22 +19,23 @@ from typing import Dict, Type, Union
|
|
19
19
|
from zenml.enums import ArtifactType, VisualizationType
|
20
20
|
from zenml.logger import get_logger
|
21
21
|
from zenml.materializers.base_materializer import BaseMaterializer
|
22
|
-
from zenml.types import CSVString, HTMLString, MarkdownString
|
22
|
+
from zenml.types import CSVString, HTMLString, JSONString, MarkdownString
|
23
23
|
|
24
24
|
logger = get_logger(__name__)
|
25
25
|
|
26
26
|
|
27
|
-
STRUCTURED_STRINGS = Union[CSVString, HTMLString, MarkdownString]
|
27
|
+
STRUCTURED_STRINGS = Union[CSVString, HTMLString, MarkdownString, JSONString]
|
28
28
|
|
29
29
|
HTML_FILENAME = "output.html"
|
30
30
|
MARKDOWN_FILENAME = "output.md"
|
31
31
|
CSV_FILENAME = "output.csv"
|
32
|
+
JSON_FILENAME = "output.json"
|
32
33
|
|
33
34
|
|
34
35
|
class StructuredStringMaterializer(BaseMaterializer):
|
35
36
|
"""Materializer for HTML or Markdown strings."""
|
36
37
|
|
37
|
-
ASSOCIATED_TYPES = (CSVString, HTMLString, MarkdownString)
|
38
|
+
ASSOCIATED_TYPES = (CSVString, HTMLString, MarkdownString, JSONString)
|
38
39
|
ASSOCIATED_ARTIFACT_TYPE = ArtifactType.DATA_ANALYSIS
|
39
40
|
|
40
41
|
def load(self, data_type: Type[STRUCTURED_STRINGS]) -> STRUCTURED_STRINGS:
|
@@ -94,6 +95,8 @@ class StructuredStringMaterializer(BaseMaterializer):
|
|
94
95
|
filename = HTML_FILENAME
|
95
96
|
elif issubclass(data_type, MarkdownString):
|
96
97
|
filename = MARKDOWN_FILENAME
|
98
|
+
elif issubclass(data_type, JSONString):
|
99
|
+
filename = JSON_FILENAME
|
97
100
|
else:
|
98
101
|
raise ValueError(
|
99
102
|
f"Data type {data_type} is not supported by this materializer."
|
@@ -120,6 +123,8 @@ class StructuredStringMaterializer(BaseMaterializer):
|
|
120
123
|
return VisualizationType.HTML
|
121
124
|
elif issubclass(data_type, MarkdownString):
|
122
125
|
return VisualizationType.MARKDOWN
|
126
|
+
elif issubclass(data_type, JSONString):
|
127
|
+
return VisualizationType.JSON
|
123
128
|
else:
|
124
129
|
raise ValueError(
|
125
130
|
f"Data type {data_type} is not supported by this materializer."
|
zenml/model/model.py
CHANGED
@@ -57,7 +57,9 @@ class Model(BaseModel):
|
|
57
57
|
ethics: The ethical implications of the model.
|
58
58
|
tags: Tags associated with the model.
|
59
59
|
version: The version name, version number or stage is optional and points model context
|
60
|
-
to a specific version/stage. If skipped new version will be created.
|
60
|
+
to a specific version/stage. If skipped new version will be created. `version`
|
61
|
+
also supports placeholders: standard `{date}` and `{time}` and any custom placeholders
|
62
|
+
that are passed as substitutions in the pipeline or step decorators.
|
61
63
|
save_models_to_registry: Whether to save all ModelArtifacts to Model Registry,
|
62
64
|
if available in active stack.
|
63
65
|
"""
|
@@ -334,12 +336,16 @@ class Model(BaseModel):
|
|
334
336
|
metadata: The metadata to log.
|
335
337
|
"""
|
336
338
|
from zenml.client import Client
|
339
|
+
from zenml.models import RunMetadataResource
|
337
340
|
|
338
341
|
response = self._get_or_create_model_version()
|
339
342
|
Client().create_run_metadata(
|
340
343
|
metadata=metadata,
|
341
|
-
|
342
|
-
|
344
|
+
resources=[
|
345
|
+
RunMetadataResource(
|
346
|
+
id=response.id, type=MetadataResourceTypes.MODEL_VERSION
|
347
|
+
)
|
348
|
+
],
|
343
349
|
)
|
344
350
|
|
345
351
|
@property
|
@@ -534,6 +540,8 @@ class Model(BaseModel):
|
|
534
540
|
from zenml.models import ModelRequest
|
535
541
|
|
536
542
|
zenml_client = Client()
|
543
|
+
# backup logic, if the Model class is used directly from the code
|
544
|
+
self.name = format_name_template(self.name)
|
537
545
|
if self.model_version_id:
|
538
546
|
mv = zenml_client.get_model_version(
|
539
547
|
model_version_name_or_number_or_id=self.model_version_id,
|
zenml/model/utils.py
CHANGED
@@ -52,29 +52,31 @@ def log_model_metadata(
|
|
52
52
|
`model` in decorator.
|
53
53
|
|
54
54
|
Raises:
|
55
|
-
ValueError: If
|
56
|
-
called inside a step with configured `model` in decorator.
|
55
|
+
ValueError: If the function is not called with proper input.
|
57
56
|
"""
|
58
57
|
logger.warning(
|
59
58
|
"The `log_model_metadata` function is deprecated and will soon be "
|
60
59
|
"removed. Please use `log_metadata` instead."
|
61
60
|
)
|
62
61
|
|
63
|
-
|
64
|
-
from zenml import Model
|
62
|
+
from zenml import log_metadata
|
65
63
|
|
66
|
-
|
64
|
+
if model_name and model_version:
|
65
|
+
log_metadata(
|
66
|
+
metadata=metadata,
|
67
|
+
model_version=model_version,
|
68
|
+
model_name=model_name,
|
69
|
+
)
|
70
|
+
elif model_name is None and model_version is None:
|
71
|
+
log_metadata(
|
72
|
+
metadata=metadata,
|
73
|
+
infer_model=True,
|
74
|
+
)
|
67
75
|
else:
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
"Model name and version must be provided unless the function is "
|
73
|
-
"called inside a step with configured `model` in decorator."
|
74
|
-
)
|
75
|
-
mv = step_context.model
|
76
|
-
|
77
|
-
mv.log_metadata(metadata)
|
76
|
+
raise ValueError(
|
77
|
+
"You can call `log_model_metadata` by either providing both "
|
78
|
+
"`model_name` and `model_version` or keeping both of them None."
|
79
|
+
)
|
78
80
|
|
79
81
|
|
80
82
|
def link_artifact_version_to_model_version(
|
@@ -107,7 +109,7 @@ def link_artifact_to_model(
|
|
107
109
|
model: The model to link to.
|
108
110
|
|
109
111
|
Raises:
|
110
|
-
RuntimeError: If called outside
|
112
|
+
RuntimeError: If called outside a step.
|
111
113
|
"""
|
112
114
|
if not model:
|
113
115
|
is_issue = False
|
zenml/models/__init__.py
CHANGED
@@ -372,6 +372,10 @@ from zenml.models.v2.misc.auth_models import (
|
|
372
372
|
OAuthRedirectResponse,
|
373
373
|
OAuthTokenResponse,
|
374
374
|
)
|
375
|
+
from zenml.models.v2.misc.run_metadata import (
|
376
|
+
RunMetadataEntry,
|
377
|
+
RunMetadataResource,
|
378
|
+
)
|
375
379
|
from zenml.models.v2.misc.server_models import (
|
376
380
|
ServerModel,
|
377
381
|
ServerDatabaseType,
|
@@ -752,4 +756,6 @@ __all__ = [
|
|
752
756
|
"ServiceConnectorInfo",
|
753
757
|
"ServiceConnectorResourcesInfo",
|
754
758
|
"ResourcesInfo",
|
759
|
+
"RunMetadataEntry",
|
760
|
+
"RunMetadataResource",
|
755
761
|
]
|
@@ -576,6 +576,7 @@ class ArtifactVersionFilter(WorkspaceScopedTaggableFilter):
|
|
576
576
|
ModelVersionArtifactSchema,
|
577
577
|
ModelVersionSchema,
|
578
578
|
PipelineRunSchema,
|
579
|
+
RunMetadataResourceSchema,
|
579
580
|
RunMetadataSchema,
|
580
581
|
StepRunInputArtifactSchema,
|
581
582
|
StepRunOutputArtifactSchema,
|
@@ -679,10 +680,12 @@ class ArtifactVersionFilter(WorkspaceScopedTaggableFilter):
|
|
679
680
|
|
680
681
|
for key, value in self.run_metadata.items():
|
681
682
|
additional_filter = and_(
|
682
|
-
|
683
|
-
|
683
|
+
RunMetadataResourceSchema.resource_id
|
684
|
+
== ArtifactVersionSchema.id,
|
685
|
+
RunMetadataResourceSchema.resource_type
|
684
686
|
== MetadataResourceTypes.ARTIFACT_VERSION,
|
685
|
-
|
687
|
+
RunMetadataResourceSchema.run_metadata_id
|
688
|
+
== RunMetadataSchema.id,
|
686
689
|
self.generate_custom_query_conditions_for_column(
|
687
690
|
value=value,
|
688
691
|
table=RunMetadataSchema,
|
@@ -81,11 +81,6 @@ class ComponentBase(BaseModel):
|
|
81
81
|
title="The stack component labels.",
|
82
82
|
)
|
83
83
|
|
84
|
-
component_spec_path: Optional[str] = Field(
|
85
|
-
default=None,
|
86
|
-
title="The path to the component spec used for mlstacks deployments.",
|
87
|
-
)
|
88
|
-
|
89
84
|
|
90
85
|
# ------------------ Request Model ------------------
|
91
86
|
|
@@ -155,10 +150,6 @@ class ComponentUpdate(BaseUpdate):
|
|
155
150
|
title="The stack component labels.",
|
156
151
|
default=None,
|
157
152
|
)
|
158
|
-
component_spec_path: Optional[str] = Field(
|
159
|
-
title="The path to the component spec used for mlstacks deployments.",
|
160
|
-
default=None,
|
161
|
-
)
|
162
153
|
connector: Optional[UUID] = Field(
|
163
154
|
title="The service connector linked to this stack component.",
|
164
155
|
default=None,
|
@@ -201,10 +192,6 @@ class ComponentResponseMetadata(WorkspaceScopedResponseMetadata):
|
|
201
192
|
default=None,
|
202
193
|
title="The stack component labels.",
|
203
194
|
)
|
204
|
-
component_spec_path: Optional[str] = Field(
|
205
|
-
default=None,
|
206
|
-
title="The path to the component spec used for mlstacks deployments.",
|
207
|
-
)
|
208
195
|
connector_resource_id: Optional[str] = Field(
|
209
196
|
default=None,
|
210
197
|
description="The ID of a specific resource instance to "
|
@@ -325,15 +312,6 @@ class ComponentResponse(
|
|
325
312
|
"""
|
326
313
|
return self.get_metadata().labels
|
327
314
|
|
328
|
-
@property
|
329
|
-
def component_spec_path(self) -> Optional[str]:
|
330
|
-
"""The `component_spec_path` property.
|
331
|
-
|
332
|
-
Returns:
|
333
|
-
the value of the property.
|
334
|
-
"""
|
335
|
-
return self.get_metadata().component_spec_path
|
336
|
-
|
337
315
|
@property
|
338
316
|
def connector_resource_id(self) -> Optional[str]:
|
339
317
|
"""The `connector_resource_id` property.
|
@@ -652,6 +652,7 @@ class ModelVersionFilter(WorkspaceScopedTaggableFilter):
|
|
652
652
|
|
653
653
|
from zenml.zen_stores.schemas import (
|
654
654
|
ModelVersionSchema,
|
655
|
+
RunMetadataResourceSchema,
|
655
656
|
RunMetadataSchema,
|
656
657
|
UserSchema,
|
657
658
|
)
|
@@ -672,10 +673,12 @@ class ModelVersionFilter(WorkspaceScopedTaggableFilter):
|
|
672
673
|
|
673
674
|
for key, value in self.run_metadata.items():
|
674
675
|
additional_filter = and_(
|
675
|
-
|
676
|
-
|
676
|
+
RunMetadataResourceSchema.resource_id
|
677
|
+
== ModelVersionSchema.id,
|
678
|
+
RunMetadataResourceSchema.resource_type
|
677
679
|
== MetadataResourceTypes.MODEL_VERSION,
|
678
|
-
|
680
|
+
RunMetadataResourceSchema.run_metadata_id
|
681
|
+
== RunMetadataSchema.id,
|
679
682
|
self.generate_custom_query_conditions_for_column(
|
680
683
|
value=value,
|
681
684
|
table=RunMetadataSchema,
|
@@ -237,6 +237,10 @@ class PipelineRunResponseMetadata(WorkspaceScopedResponseMetadata):
|
|
237
237
|
default=False,
|
238
238
|
description="Whether a template can be created from this run.",
|
239
239
|
)
|
240
|
+
step_substitutions: Dict[str, Dict[str, str]] = Field(
|
241
|
+
title="Substitutions used in the step runs of this pipeline run.",
|
242
|
+
default_factory=dict,
|
243
|
+
)
|
240
244
|
|
241
245
|
|
242
246
|
class PipelineRunResponseResources(WorkspaceScopedResponseResources):
|
@@ -546,6 +550,15 @@ class PipelineRunResponse(
|
|
546
550
|
"""
|
547
551
|
return self.get_metadata().is_templatable
|
548
552
|
|
553
|
+
@property
|
554
|
+
def step_substitutions(self) -> Dict[str, Dict[str, str]]:
|
555
|
+
"""The `step_substitutions` property.
|
556
|
+
|
557
|
+
Returns:
|
558
|
+
the value of the property.
|
559
|
+
"""
|
560
|
+
return self.get_metadata().step_substitutions
|
561
|
+
|
549
562
|
@property
|
550
563
|
def model_version(self) -> Optional[ModelVersionResponse]:
|
551
564
|
"""The `model_version` property.
|
@@ -722,6 +735,7 @@ class PipelineRunFilter(WorkspaceScopedTaggableFilter):
|
|
722
735
|
PipelineDeploymentSchema,
|
723
736
|
PipelineRunSchema,
|
724
737
|
PipelineSchema,
|
738
|
+
RunMetadataResourceSchema,
|
725
739
|
RunMetadataSchema,
|
726
740
|
ScheduleSchema,
|
727
741
|
StackComponentSchema,
|
@@ -897,10 +911,12 @@ class PipelineRunFilter(WorkspaceScopedTaggableFilter):
|
|
897
911
|
|
898
912
|
for key, value in self.run_metadata.items():
|
899
913
|
additional_filter = and_(
|
900
|
-
|
901
|
-
|
914
|
+
RunMetadataResourceSchema.resource_id
|
915
|
+
== PipelineRunSchema.id,
|
916
|
+
RunMetadataResourceSchema.resource_type
|
902
917
|
== MetadataResourceTypes.PIPELINE_RUN,
|
903
|
-
|
918
|
+
RunMetadataResourceSchema.run_metadata_id
|
919
|
+
== RunMetadataSchema.id,
|
904
920
|
self.generate_custom_query_conditions_for_column(
|
905
921
|
value=value,
|
906
922
|
table=RunMetadataSchema,
|
@@ -13,16 +13,16 @@
|
|
13
13
|
# permissions and limitations under the License.
|
14
14
|
"""Models representing run metadata."""
|
15
15
|
|
16
|
-
from typing import Dict, Optional
|
16
|
+
from typing import Dict, List, Optional
|
17
17
|
from uuid import UUID
|
18
18
|
|
19
|
-
from pydantic import Field
|
19
|
+
from pydantic import Field, model_validator
|
20
20
|
|
21
|
-
from zenml.enums import MetadataResourceTypes
|
22
21
|
from zenml.metadata.metadata_types import MetadataType, MetadataTypeEnum
|
23
22
|
from zenml.models.v2.base.scoped import (
|
24
23
|
WorkspaceScopedRequest,
|
25
24
|
)
|
25
|
+
from zenml.models.v2.misc.run_metadata import RunMetadataResource
|
26
26
|
|
27
27
|
# ------------------ Request Model ------------------
|
28
28
|
|
@@ -30,14 +30,12 @@ from zenml.models.v2.base.scoped import (
|
|
30
30
|
class RunMetadataRequest(WorkspaceScopedRequest):
|
31
31
|
"""Request model for run metadata."""
|
32
32
|
|
33
|
-
|
34
|
-
title="The
|
35
|
-
)
|
36
|
-
resource_type: MetadataResourceTypes = Field(
|
37
|
-
title="The type of the resource that this metadata belongs to.",
|
33
|
+
resources: List[RunMetadataResource] = Field(
|
34
|
+
title="The list of resources that this metadata belongs to."
|
38
35
|
)
|
39
36
|
stack_component_id: Optional[UUID] = Field(
|
40
|
-
title="The ID of the stack component that this metadata belongs to."
|
37
|
+
title="The ID of the stack component that this metadata belongs to.",
|
38
|
+
default=None,
|
41
39
|
)
|
42
40
|
values: Dict[str, "MetadataType"] = Field(
|
43
41
|
title="The metadata to be created.",
|
@@ -45,3 +43,26 @@ class RunMetadataRequest(WorkspaceScopedRequest):
|
|
45
43
|
types: Dict[str, "MetadataTypeEnum"] = Field(
|
46
44
|
title="The types of the metadata to be created.",
|
47
45
|
)
|
46
|
+
publisher_step_id: Optional[UUID] = Field(
|
47
|
+
title="The ID of the step execution that published this metadata.",
|
48
|
+
default=None,
|
49
|
+
)
|
50
|
+
|
51
|
+
@model_validator(mode="after")
|
52
|
+
def validate_values_keys(self) -> "RunMetadataRequest":
|
53
|
+
"""Validates if the keys in the metadata are properly defined.
|
54
|
+
|
55
|
+
Returns:
|
56
|
+
self
|
57
|
+
|
58
|
+
Raises:
|
59
|
+
ValueError: if one of the key in the metadata contains `:`
|
60
|
+
"""
|
61
|
+
invalid_keys = [key for key in self.values.keys() if ":" in key]
|
62
|
+
if invalid_keys:
|
63
|
+
raise ValueError(
|
64
|
+
"You can not use colons (`:`) in the key names when you "
|
65
|
+
"are creating metadata for your ZenML objects. Please change "
|
66
|
+
f"the following keys: {invalid_keys}"
|
67
|
+
)
|
68
|
+
return self
|
zenml/models/v2/core/step_run.py
CHANGED
@@ -142,7 +142,7 @@ class StepRunRequest(WorkspaceScopedRequest):
|
|
142
142
|
class StepRunUpdate(BaseModel):
|
143
143
|
"""Update model for step runs."""
|
144
144
|
|
145
|
-
outputs: Dict[str, UUID] = Field(
|
145
|
+
outputs: Dict[str, List[UUID]] = Field(
|
146
146
|
title="The IDs of the output artifact versions of the step run.",
|
147
147
|
default={},
|
148
148
|
)
|
@@ -594,6 +594,7 @@ class StepRunFilter(WorkspaceScopedFilter):
|
|
594
594
|
from zenml.zen_stores.schemas import (
|
595
595
|
ModelSchema,
|
596
596
|
ModelVersionSchema,
|
597
|
+
RunMetadataResourceSchema,
|
597
598
|
RunMetadataSchema,
|
598
599
|
StepRunSchema,
|
599
600
|
)
|
@@ -612,10 +613,11 @@ class StepRunFilter(WorkspaceScopedFilter):
|
|
612
613
|
|
613
614
|
for key, value in self.run_metadata.items():
|
614
615
|
additional_filter = and_(
|
615
|
-
|
616
|
-
|
616
|
+
RunMetadataResourceSchema.resource_id == StepRunSchema.id,
|
617
|
+
RunMetadataResourceSchema.resource_type
|
617
618
|
== MetadataResourceTypes.STEP_RUN,
|
618
|
-
|
619
|
+
RunMetadataResourceSchema.run_metadata_id
|
620
|
+
== RunMetadataSchema.id,
|
619
621
|
self.generate_custom_query_conditions_for_column(
|
620
622
|
value=value,
|
621
623
|
table=RunMetadataSchema,
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# Copyright (c) ZenML GmbH 2024. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at:
|
6
|
+
#
|
7
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
12
|
+
# or implied. See the License for the specific language governing
|
13
|
+
# permissions and limitations under the License.
|
14
|
+
"""Utility classes for modeling run metadata."""
|
15
|
+
|
16
|
+
from datetime import datetime
|
17
|
+
from uuid import UUID
|
18
|
+
|
19
|
+
from pydantic import BaseModel, Field
|
20
|
+
|
21
|
+
from zenml.enums import MetadataResourceTypes
|
22
|
+
from zenml.metadata.metadata_types import MetadataType
|
23
|
+
|
24
|
+
|
25
|
+
class RunMetadataResource(BaseModel):
|
26
|
+
"""Utility class to help identify resources to tag metadata to."""
|
27
|
+
|
28
|
+
id: UUID = Field(title="The ID of the resource.")
|
29
|
+
type: MetadataResourceTypes = Field(title="The type of the resource.")
|
30
|
+
|
31
|
+
|
32
|
+
class RunMetadataEntry(BaseModel):
|
33
|
+
"""Utility class to sort/list run metadata entries."""
|
34
|
+
|
35
|
+
value: MetadataType = Field(title="The value for the run metadata entry")
|
36
|
+
created: datetime = Field(
|
37
|
+
title="The timestamp when this resource was created."
|
38
|
+
)
|
@@ -20,7 +20,7 @@ from zenml.client import Client
|
|
20
20
|
from zenml.config.step_configurations import Step
|
21
21
|
from zenml.enums import ArtifactSaveType, StepRunInputArtifactType
|
22
22
|
from zenml.exceptions import InputResolutionError
|
23
|
-
from zenml.utils import pagination_utils
|
23
|
+
from zenml.utils import pagination_utils, string_utils
|
24
24
|
|
25
25
|
if TYPE_CHECKING:
|
26
26
|
from zenml.models import PipelineRunResponse
|
@@ -53,7 +53,8 @@ def resolve_step_inputs(
|
|
53
53
|
current_run_steps = {
|
54
54
|
run_step.name: run_step
|
55
55
|
for run_step in pagination_utils.depaginate(
|
56
|
-
Client().list_run_steps,
|
56
|
+
Client().list_run_steps,
|
57
|
+
pipeline_run_id=pipeline_run.id,
|
57
58
|
)
|
58
59
|
}
|
59
60
|
|
@@ -66,11 +67,23 @@ def resolve_step_inputs(
|
|
66
67
|
f"No step `{input_.step_name}` found in current run."
|
67
68
|
)
|
68
69
|
|
70
|
+
# Try to get the substitutions from the pipeline run first, as we
|
71
|
+
# already have a hydrated version of that. In the unlikely case
|
72
|
+
# that the pipeline run is outdated, we fetch it from the step
|
73
|
+
# run instead which will costs us one hydration call.
|
74
|
+
substitutions = (
|
75
|
+
pipeline_run.step_substitutions.get(step_run.name)
|
76
|
+
or step_run.config.substitutions
|
77
|
+
)
|
78
|
+
output_name = string_utils.format_name_template(
|
79
|
+
input_.output_name, substitutions=substitutions
|
80
|
+
)
|
81
|
+
|
69
82
|
try:
|
70
|
-
outputs = step_run.outputs[
|
83
|
+
outputs = step_run.outputs[output_name]
|
71
84
|
except KeyError:
|
72
85
|
raise InputResolutionError(
|
73
|
-
f"No step output `{
|
86
|
+
f"No step output `{output_name}` found for step "
|
74
87
|
f"`{input_.step_name}`."
|
75
88
|
)
|
76
89
|
|
@@ -83,12 +96,12 @@ def resolve_step_inputs(
|
|
83
96
|
# This should never happen, there can only be a single regular step
|
84
97
|
# output for a name
|
85
98
|
raise InputResolutionError(
|
86
|
-
f"Too many step outputs for output `{
|
99
|
+
f"Too many step outputs for output `{output_name}` of "
|
87
100
|
f"step `{input_.step_name}`."
|
88
101
|
)
|
89
102
|
elif len(step_outputs) == 0:
|
90
103
|
raise InputResolutionError(
|
91
|
-
f"No step output `{
|
104
|
+
f"No step output `{output_name}` found for step "
|
92
105
|
f"`{input_.step_name}`."
|
93
106
|
)
|
94
107
|
|
@@ -21,6 +21,7 @@ from zenml.enums import ExecutionStatus, MetadataResourceTypes
|
|
21
21
|
from zenml.models import (
|
22
22
|
PipelineRunResponse,
|
23
23
|
PipelineRunUpdate,
|
24
|
+
RunMetadataResource,
|
24
25
|
StepRunResponse,
|
25
26
|
StepRunUpdate,
|
26
27
|
)
|
@@ -32,7 +33,7 @@ if TYPE_CHECKING:
|
|
32
33
|
|
33
34
|
|
34
35
|
def publish_successful_step_run(
|
35
|
-
step_run_id: "UUID", output_artifact_ids: Dict[str, "UUID"]
|
36
|
+
step_run_id: "UUID", output_artifact_ids: Dict[str, List["UUID"]]
|
36
37
|
) -> "StepRunResponse":
|
37
38
|
"""Publishes a successful step run.
|
38
39
|
|
@@ -129,8 +130,11 @@ def publish_pipeline_run_metadata(
|
|
129
130
|
for stack_component_id, metadata in pipeline_run_metadata.items():
|
130
131
|
client.create_run_metadata(
|
131
132
|
metadata=metadata,
|
132
|
-
|
133
|
-
|
133
|
+
resources=[
|
134
|
+
RunMetadataResource(
|
135
|
+
id=pipeline_run_id, type=MetadataResourceTypes.PIPELINE_RUN
|
136
|
+
)
|
137
|
+
],
|
134
138
|
stack_component_id=stack_component_id,
|
135
139
|
)
|
136
140
|
|
@@ -150,7 +154,10 @@ def publish_step_run_metadata(
|
|
150
154
|
for stack_component_id, metadata in step_run_metadata.items():
|
151
155
|
client.create_run_metadata(
|
152
156
|
metadata=metadata,
|
153
|
-
|
154
|
-
|
157
|
+
resources=[
|
158
|
+
RunMetadataResource(
|
159
|
+
id=step_run_id, type=MetadataResourceTypes.STEP_RUN
|
160
|
+
)
|
161
|
+
],
|
155
162
|
stack_component_id=stack_component_id,
|
156
163
|
)
|
@@ -309,8 +309,12 @@ class StepLauncher:
|
|
309
309
|
The created or existing pipeline run,
|
310
310
|
and a boolean indicating whether the run was created or reused.
|
311
311
|
"""
|
312
|
-
|
313
|
-
|
312
|
+
start_time = datetime.utcnow()
|
313
|
+
run_name = string_utils.format_name_template(
|
314
|
+
name_template=self._deployment.run_name_template,
|
315
|
+
substitutions=self._deployment.pipeline_configuration._get_full_substitutions(
|
316
|
+
start_time
|
317
|
+
),
|
314
318
|
)
|
315
319
|
|
316
320
|
logger.debug("Creating pipeline run %s", run_name)
|
@@ -329,7 +333,7 @@ class StepLauncher:
|
|
329
333
|
),
|
330
334
|
status=ExecutionStatus.RUNNING,
|
331
335
|
orchestrator_environment=get_run_environment_dict(),
|
332
|
-
start_time=
|
336
|
+
start_time=start_time,
|
333
337
|
tags=self._deployment.pipeline_configuration.tags,
|
334
338
|
)
|
335
339
|
return client.zen_store.get_or_create_run(pipeline_run)
|
@@ -309,6 +309,9 @@ def create_cached_step_runs(
|
|
309
309
|
for invocation_id in cache_candidates:
|
310
310
|
visited_invocations.add(invocation_id)
|
311
311
|
|
312
|
+
# Make sure the request factory has the most up to date pipeline
|
313
|
+
# run to avoid hydration calls
|
314
|
+
request_factory.pipeline_run = pipeline_run
|
312
315
|
try:
|
313
316
|
step_run_request = request_factory.create_request(
|
314
317
|
invocation_id
|
@@ -354,13 +357,16 @@ def create_cached_step_runs(
|
|
354
357
|
|
355
358
|
|
356
359
|
def get_or_create_model_version_for_pipeline_run(
|
357
|
-
model: "Model",
|
360
|
+
model: "Model",
|
361
|
+
pipeline_run: PipelineRunResponse,
|
362
|
+
substitutions: Dict[str, str],
|
358
363
|
) -> Tuple[ModelVersionResponse, bool]:
|
359
364
|
"""Get or create a model version as part of a pipeline run.
|
360
365
|
|
361
366
|
Args:
|
362
367
|
model: The model to get or create.
|
363
368
|
pipeline_run: The pipeline run for which the model should be created.
|
369
|
+
substitutions: Substitutions to apply to the model version name.
|
364
370
|
|
365
371
|
Returns:
|
366
372
|
The model version and a boolean indicating whether it was newly created
|
@@ -374,12 +380,14 @@ def get_or_create_model_version_for_pipeline_run(
|
|
374
380
|
return model._get_model_version(), False
|
375
381
|
elif model.version:
|
376
382
|
if isinstance(model.version, str):
|
377
|
-
start_time = pipeline_run.start_time or datetime.utcnow()
|
378
383
|
model.version = string_utils.format_name_template(
|
379
384
|
model.version,
|
380
|
-
|
381
|
-
time=start_time.strftime("%H_%M_%S_%f"),
|
385
|
+
substitutions=substitutions,
|
382
386
|
)
|
387
|
+
model.name = string_utils.format_name_template(
|
388
|
+
model.name,
|
389
|
+
substitutions=substitutions,
|
390
|
+
)
|
383
391
|
|
384
392
|
return (
|
385
393
|
model._get_or_create_model_version(),
|
@@ -460,7 +468,9 @@ def prepare_pipeline_run_model_version(
|
|
460
468
|
model_version = pipeline_run.model_version
|
461
469
|
elif config_model := pipeline_run.config.model:
|
462
470
|
model_version, _ = get_or_create_model_version_for_pipeline_run(
|
463
|
-
model=config_model,
|
471
|
+
model=config_model,
|
472
|
+
pipeline_run=pipeline_run,
|
473
|
+
substitutions=pipeline_run.config.substitutions,
|
464
474
|
)
|
465
475
|
pipeline_run = Client().zen_store.update_run(
|
466
476
|
run_id=pipeline_run.id,
|
@@ -492,7 +502,9 @@ def prepare_step_run_model_version(
|
|
492
502
|
model_version = step_run.model_version
|
493
503
|
elif config_model := step_run.config.model:
|
494
504
|
model_version, created = get_or_create_model_version_for_pipeline_run(
|
495
|
-
model=config_model,
|
505
|
+
model=config_model,
|
506
|
+
pipeline_run=pipeline_run,
|
507
|
+
substitutions=step_run.config.substitutions,
|
496
508
|
)
|
497
509
|
step_run = Client().zen_store.update_run_step(
|
498
510
|
step_run_id=step_run.id,
|