zenml-nightly 0.70.0.dev20241125__py3-none-any.whl → 0.70.0.dev20241201__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/artifact_stores/base_artifact_store.py +2 -2
- zenml/artifacts/artifact_config.py +7 -1
- zenml/artifacts/utils.py +56 -31
- zenml/cli/__init__.py +18 -0
- zenml/cli/base.py +4 -4
- zenml/cli/login.py +26 -0
- zenml/cli/pipeline.py +80 -0
- zenml/cli/server.py +1 -1
- zenml/cli/service_connectors.py +3 -3
- 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/image_builders/local_image_builder.py +13 -3
- zenml/integrations/__init__.py +1 -0
- zenml/integrations/aws/orchestrators/sagemaker_orchestrator.py +14 -6
- zenml/integrations/constants.py +1 -0
- zenml/integrations/feast/__init__.py +1 -1
- zenml/integrations/feast/feature_stores/feast_feature_store.py +13 -9
- zenml/integrations/kubernetes/orchestrators/kube_utils.py +46 -2
- zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator.py +13 -2
- zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator_entrypoint.py +3 -1
- zenml/integrations/kubernetes/orchestrators/manifest_utils.py +3 -2
- zenml/integrations/kubernetes/step_operators/kubernetes_step_operator.py +3 -1
- zenml/integrations/modal/__init__.py +46 -0
- zenml/integrations/modal/flavors/__init__.py +26 -0
- zenml/integrations/modal/flavors/modal_step_operator_flavor.py +125 -0
- zenml/integrations/modal/step_operators/__init__.py +22 -0
- zenml/integrations/modal/step_operators/modal_step_operator.py +242 -0
- zenml/io/filesystem.py +2 -2
- zenml/io/local_filesystem.py +3 -3
- zenml/materializers/built_in_materializer.py +18 -1
- zenml/materializers/structured_string_materializer.py +8 -3
- zenml/model/model.py +11 -85
- 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 +26 -9
- zenml/orchestrators/step_runner.py +40 -3
- zenml/orchestrators/utils.py +24 -23
- zenml/pipelines/pipeline_decorator.py +4 -0
- zenml/pipelines/pipeline_definition.py +26 -8
- zenml/pipelines/run_utils.py +9 -5
- zenml/steps/base_step.py +11 -1
- zenml/steps/entrypoint_function_utils.py +7 -3
- 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/cloud_utils.py +3 -1
- zenml/zen_server/rbac/endpoint_utils.py +6 -4
- zenml/zen_server/rbac/models.py +3 -2
- zenml/zen_server/rbac/utils.py +4 -7
- zenml/zen_server/routers/users_endpoints.py +35 -37
- zenml/zen_server/routers/workspaces_endpoints.py +44 -55
- 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/migrations/versions/ec6307720f92_simplify_model_version_links.py +7 -6
- 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 +130 -34
- {zenml_nightly-0.70.0.dev20241125.dist-info → zenml_nightly-0.70.0.dev20241201.dist-info}/METADATA +1 -1
- {zenml_nightly-0.70.0.dev20241125.dist-info → zenml_nightly-0.70.0.dev20241201.dist-info}/RECORD +90 -83
- zenml/utils/cloud_utils.py +0 -40
- {zenml_nightly-0.70.0.dev20241125.dist-info → zenml_nightly-0.70.0.dev20241201.dist-info}/LICENSE +0 -0
- {zenml_nightly-0.70.0.dev20241125.dist-info → zenml_nightly-0.70.0.dev20241201.dist-info}/WHEEL +0 -0
- {zenml_nightly-0.70.0.dev20241125.dist-info → zenml_nightly-0.70.0.dev20241201.dist-info}/entry_points.txt +0 -0
@@ -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,
|
@@ -518,10 +530,15 @@ def log_model_version_dashboard_url(
|
|
518
530
|
Args:
|
519
531
|
model_version: The model version for which to log the dashboard URL.
|
520
532
|
"""
|
521
|
-
from zenml.utils.
|
533
|
+
from zenml.utils.dashboard_utils import get_model_version_url
|
522
534
|
|
523
|
-
if
|
524
|
-
logger.info(
|
535
|
+
if model_version_url := get_model_version_url(model_version.id):
|
536
|
+
logger.info(
|
537
|
+
"Dashboard URL for Model Version `%s (%s)`:\n%s",
|
538
|
+
model_version.model.name,
|
539
|
+
model_version.name,
|
540
|
+
model_version_url,
|
541
|
+
)
|
525
542
|
else:
|
526
543
|
logger.info(
|
527
544
|
"Models can be viewed in the dashboard using ZenML Pro. Sign up "
|
@@ -56,7 +56,7 @@ from zenml.steps.utils import (
|
|
56
56
|
parse_return_type_annotations,
|
57
57
|
resolve_type_annotation,
|
58
58
|
)
|
59
|
-
from zenml.utils import materializer_utils, source_utils
|
59
|
+
from zenml.utils import materializer_utils, source_utils, string_utils
|
60
60
|
from zenml.utils.typing_utils import get_origin, is_union
|
61
61
|
|
62
62
|
if TYPE_CHECKING:
|
@@ -152,6 +152,15 @@ class StepRunner:
|
|
152
152
|
func=step_instance.entrypoint
|
153
153
|
)
|
154
154
|
|
155
|
+
self._evaluate_artifact_names_in_collections(
|
156
|
+
step_run,
|
157
|
+
output_annotations,
|
158
|
+
[
|
159
|
+
output_artifact_uris,
|
160
|
+
output_materializers,
|
161
|
+
],
|
162
|
+
)
|
163
|
+
|
155
164
|
self._stack.prepare_step_run(info=step_run_info)
|
156
165
|
|
157
166
|
# Initialize the step context singleton
|
@@ -257,7 +266,9 @@ class StepRunner:
|
|
257
266
|
|
258
267
|
# Update the status and output artifacts of the step run.
|
259
268
|
output_artifact_ids = {
|
260
|
-
output_name:
|
269
|
+
output_name: [
|
270
|
+
artifact.id,
|
271
|
+
]
|
261
272
|
for output_name, artifact in output_artifacts.items()
|
262
273
|
}
|
263
274
|
publish_successful_step_run(
|
@@ -265,6 +276,32 @@ class StepRunner:
|
|
265
276
|
output_artifact_ids=output_artifact_ids,
|
266
277
|
)
|
267
278
|
|
279
|
+
def _evaluate_artifact_names_in_collections(
|
280
|
+
self,
|
281
|
+
step_run: "StepRunResponse",
|
282
|
+
output_annotations: Dict[str, OutputSignature],
|
283
|
+
collections: List[Dict[str, Any]],
|
284
|
+
) -> None:
|
285
|
+
"""Evaluates the artifact names in the collections.
|
286
|
+
|
287
|
+
Args:
|
288
|
+
step_run: The step run.
|
289
|
+
output_annotations: The output annotations of the step function
|
290
|
+
(also evaluated).
|
291
|
+
collections: The collections to evaluate.
|
292
|
+
"""
|
293
|
+
collections.append(output_annotations)
|
294
|
+
for k, v in list(output_annotations.items()):
|
295
|
+
name = k
|
296
|
+
if v.artifact_config and v.artifact_config.name:
|
297
|
+
name = string_utils.format_name_template(
|
298
|
+
v.artifact_config.name,
|
299
|
+
substitutions=step_run.config.substitutions,
|
300
|
+
)
|
301
|
+
|
302
|
+
for d in collections:
|
303
|
+
d[name] = d.pop(k)
|
304
|
+
|
268
305
|
def _load_step(self) -> "BaseStep":
|
269
306
|
"""Load the step instance.
|
270
307
|
|
@@ -400,7 +437,7 @@ class StepRunner:
|
|
400
437
|
**artifact.get_hydrated_version().model_dump()
|
401
438
|
)
|
402
439
|
|
403
|
-
if data_type
|
440
|
+
if data_type in (None, Any) or is_union(get_origin(data_type)):
|
404
441
|
# Entrypoint function does not define a specific type for the input,
|
405
442
|
# we use the datatype of the stored artifact
|
406
443
|
data_type = source_utils.load(artifact.data_type)
|
zenml/orchestrators/utils.py
CHANGED
@@ -32,7 +32,6 @@ from zenml.constants import (
|
|
32
32
|
from zenml.enums import AuthScheme, StackComponentType, StoreType
|
33
33
|
from zenml.logger import get_logger
|
34
34
|
from zenml.stack import StackComponent
|
35
|
-
from zenml.utils.string_utils import format_name_template
|
36
35
|
|
37
36
|
logger = get_logger(__name__)
|
38
37
|
|
@@ -40,7 +39,9 @@ if TYPE_CHECKING:
|
|
40
39
|
from zenml.artifact_stores.base_artifact_store import BaseArtifactStore
|
41
40
|
|
42
41
|
|
43
|
-
def get_orchestrator_run_name(
|
42
|
+
def get_orchestrator_run_name(
|
43
|
+
pipeline_name: str, max_length: Optional[int] = None
|
44
|
+
) -> str:
|
44
45
|
"""Gets an orchestrator run name.
|
45
46
|
|
46
47
|
This run name is not the same as the ZenML run name but can instead be
|
@@ -48,11 +49,31 @@ def get_orchestrator_run_name(pipeline_name: str) -> str:
|
|
48
49
|
|
49
50
|
Args:
|
50
51
|
pipeline_name: Name of the pipeline that will run.
|
52
|
+
max_length: Maximum length of the generated name.
|
53
|
+
|
54
|
+
Raises:
|
55
|
+
ValueError: If the max length is below 8 characters.
|
51
56
|
|
52
57
|
Returns:
|
53
58
|
The orchestrator run name.
|
54
59
|
"""
|
55
|
-
|
60
|
+
suffix_length = 32
|
61
|
+
pipeline_name = f"{pipeline_name}_"
|
62
|
+
|
63
|
+
if max_length:
|
64
|
+
if max_length < 8:
|
65
|
+
raise ValueError(
|
66
|
+
"Maximum length for orchestrator run name must be 8 or above."
|
67
|
+
)
|
68
|
+
|
69
|
+
# Make sure we always have a certain suffix to guarantee no overlap
|
70
|
+
# with other runs
|
71
|
+
suffix_length = min(32, max(8, max_length - len(pipeline_name)))
|
72
|
+
pipeline_name = pipeline_name[: (max_length - suffix_length)]
|
73
|
+
|
74
|
+
suffix = "".join(random.choices("0123456789abcdef", k=suffix_length))
|
75
|
+
|
76
|
+
return f"{pipeline_name}{suffix}"
|
56
77
|
|
57
78
|
|
58
79
|
def is_setting_enabled(
|
@@ -174,26 +195,6 @@ def get_config_environment_vars(
|
|
174
195
|
return environment_vars
|
175
196
|
|
176
197
|
|
177
|
-
def get_run_name(run_name_template: str) -> str:
|
178
|
-
"""Fill out the run name template to get a complete run name.
|
179
|
-
|
180
|
-
Args:
|
181
|
-
run_name_template: The run name template to fill out.
|
182
|
-
|
183
|
-
Raises:
|
184
|
-
ValueError: If the run name is empty.
|
185
|
-
|
186
|
-
Returns:
|
187
|
-
The run name derived from the template.
|
188
|
-
"""
|
189
|
-
run_name = format_name_template(run_name_template)
|
190
|
-
|
191
|
-
if run_name == "":
|
192
|
-
raise ValueError("Empty run names are not allowed.")
|
193
|
-
|
194
|
-
return run_name
|
195
|
-
|
196
|
-
|
197
198
|
class register_artifact_store_filesystem:
|
198
199
|
"""Context manager for the artifact_store/filesystem_registry dependency.
|
199
200
|
|
@@ -55,6 +55,7 @@ def pipeline(
|
|
55
55
|
on_failure: Optional["HookSpecification"] = None,
|
56
56
|
on_success: Optional["HookSpecification"] = None,
|
57
57
|
model: Optional["Model"] = None,
|
58
|
+
substitutions: Optional[Dict[str, str]] = None,
|
58
59
|
) -> Callable[["F"], "Pipeline"]: ...
|
59
60
|
|
60
61
|
|
@@ -71,6 +72,7 @@ def pipeline(
|
|
71
72
|
on_failure: Optional["HookSpecification"] = None,
|
72
73
|
on_success: Optional["HookSpecification"] = None,
|
73
74
|
model: Optional["Model"] = None,
|
75
|
+
substitutions: Optional[Dict[str, str]] = None,
|
74
76
|
) -> Union["Pipeline", Callable[["F"], "Pipeline"]]:
|
75
77
|
"""Decorator to create a pipeline.
|
76
78
|
|
@@ -91,6 +93,7 @@ def pipeline(
|
|
91
93
|
function with no arguments, or a source path to such a function
|
92
94
|
(e.g. `module.my_function`).
|
93
95
|
model: configuration of the model in the Model Control Plane.
|
96
|
+
substitutions: Extra placeholders to use in the name templates.
|
94
97
|
|
95
98
|
Returns:
|
96
99
|
A pipeline instance.
|
@@ -111,6 +114,7 @@ def pipeline(
|
|
111
114
|
on_success=on_success,
|
112
115
|
model=model,
|
113
116
|
entrypoint=func,
|
117
|
+
substitutions=substitutions,
|
114
118
|
)
|
115
119
|
|
116
120
|
p.__doc__ = func.__doc__
|