zenml-nightly 0.70.0.dev20241125__py3-none-any.whl → 0.71.0.dev20241220__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.
- README.md +4 -4
- RELEASE_NOTES.md +112 -0
- zenml/VERSION +1 -1
- zenml/artifact_stores/base_artifact_store.py +2 -2
- zenml/artifacts/artifact_config.py +15 -6
- zenml/artifacts/utils.py +59 -32
- zenml/cli/__init__.py +22 -4
- zenml/cli/base.py +5 -5
- zenml/cli/login.py +26 -0
- zenml/cli/pipeline.py +111 -62
- zenml/cli/server.py +20 -20
- 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 +62 -20
- zenml/config/compiler.py +12 -3
- zenml/config/pipeline_configurations.py +20 -0
- zenml/config/pipeline_run_configuration.py +1 -0
- zenml/config/secret_reference_mixin.py +1 -1
- zenml/config/server_config.py +4 -0
- zenml/config/step_configurations.py +21 -0
- zenml/constants.py +10 -0
- zenml/enums.py +1 -0
- zenml/image_builders/base_image_builder.py +5 -2
- zenml/image_builders/build_context.py +7 -16
- zenml/image_builders/local_image_builder.py +13 -3
- zenml/integrations/__init__.py +1 -0
- zenml/integrations/aws/__init__.py +3 -0
- zenml/integrations/aws/flavors/__init__.py +6 -0
- zenml/integrations/aws/flavors/aws_image_builder_flavor.py +146 -0
- zenml/integrations/aws/image_builders/__init__.py +20 -0
- zenml/integrations/aws/image_builders/aws_image_builder.py +307 -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/gcp/orchestrators/vertex_orchestrator.py +1 -1
- zenml/integrations/kaniko/image_builders/kaniko_image_builder.py +2 -1
- zenml/integrations/kubernetes/flavors/kubernetes_orchestrator_flavor.py +11 -0
- 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 -2
- zenml/integrations/lightning/flavors/lightning_orchestrator_flavor.py +11 -0
- 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/integrations/neptune/experiment_trackers/neptune_experiment_tracker.py +7 -5
- zenml/integrations/neptune/experiment_trackers/run_state.py +69 -53
- zenml/integrations/registry.py +2 -2
- zenml/integrations/skypilot/flavors/skypilot_orchestrator_base_vm_config.py +12 -0
- zenml/integrations/wandb/flavors/wandb_experiment_tracker_flavor.py +13 -5
- 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 +23 -101
- zenml/model/utils.py +21 -17
- zenml/models/__init__.py +6 -0
- zenml/models/v2/base/filter.py +26 -30
- zenml/models/v2/base/scoped.py +258 -5
- zenml/models/v2/core/artifact_version.py +21 -29
- zenml/models/v2/core/code_repository.py +1 -12
- zenml/models/v2/core/component.py +5 -68
- zenml/models/v2/core/flavor.py +1 -11
- zenml/models/v2/core/model.py +1 -57
- zenml/models/v2/core/model_version.py +11 -36
- zenml/models/v2/core/model_version_artifact.py +11 -3
- zenml/models/v2/core/model_version_pipeline_run.py +14 -3
- zenml/models/v2/core/pipeline.py +47 -55
- zenml/models/v2/core/pipeline_build.py +67 -12
- zenml/models/v2/core/pipeline_deployment.py +0 -10
- zenml/models/v2/core/pipeline_run.py +110 -32
- zenml/models/v2/core/run_metadata.py +30 -9
- zenml/models/v2/core/run_template.py +21 -29
- zenml/models/v2/core/schedule.py +0 -10
- zenml/models/v2/core/secret.py +0 -14
- zenml/models/v2/core/service.py +9 -16
- zenml/models/v2/core/service_connector.py +0 -11
- zenml/models/v2/core/stack.py +21 -30
- zenml/models/v2/core/step_run.py +24 -18
- zenml/models/v2/core/trigger.py +19 -3
- zenml/models/v2/misc/run_metadata.py +38 -0
- zenml/orchestrators/base_orchestrator.py +13 -1
- zenml/orchestrators/input_utils.py +19 -6
- zenml/orchestrators/output_utils.py +5 -1
- zenml/orchestrators/publish_utils.py +12 -5
- zenml/orchestrators/step_launcher.py +16 -16
- zenml/orchestrators/step_run_utils.py +18 -197
- zenml/orchestrators/step_runner.py +40 -3
- zenml/orchestrators/utils.py +79 -50
- zenml/pipelines/build_utils.py +12 -0
- zenml/pipelines/pipeline_decorator.py +4 -0
- zenml/pipelines/pipeline_definition.py +26 -8
- zenml/pipelines/run_utils.py +9 -5
- zenml/service_connectors/service_connector_utils.py +3 -9
- zenml/stack/stack_component.py +1 -1
- zenml/stack_deployments/aws_stack_deployment.py +22 -0
- 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/archivable.py +65 -36
- zenml/utils/code_utils.py +8 -4
- zenml/utils/docker_utils.py +9 -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/auth.py +9 -10
- zenml/zen_server/cloud_utils.py +3 -1
- zenml/zen_server/dashboard/assets/{404-NVXKFp-x.js → 404-Cqu3EDCm.js} +1 -1
- zenml/zen_server/dashboard/assets/{@reactflow-CK0KJUen.js → @reactflow-D2Y7BWwz.js} +1 -1
- zenml/zen_server/dashboard/assets/{AlertDialogDropdownItem-DezXKmDf.js → AlertDialogDropdownItem-BHd71pVS.js} +1 -1
- zenml/zen_server/dashboard/assets/{CodeSnippet-JzR8CEtw.js → CodeSnippet-DIonwetW.js} +1 -1
- zenml/zen_server/dashboard/assets/{CollapsibleCard-DQW_ktMO.js → CollapsibleCard-CDnC97pB.js} +1 -1
- zenml/zen_server/dashboard/assets/{Commands-DL2kwkRd.js → Commands-BVEXKAOj.js} +1 -1
- zenml/zen_server/dashboard/assets/{ComponentBadge-D_g62Wv8.js → ComponentBadge-CrRvovox.js} +1 -1
- zenml/zen_server/dashboard/assets/{CopyButton-LNcWaa14.js → CopyButton-B6wGAhQv.js} +1 -1
- zenml/zen_server/dashboard/assets/{CsvVizualization-DknpE5ej.js → CsvVizualization-CjcT7LMm.js} +5 -5
- zenml/zen_server/dashboard/assets/DeleteAlertDialog-D2ELtM2W.js +1 -0
- zenml/zen_server/dashboard/assets/{DialogItem-Bxf8FuAT.js → DialogItem-DXIMhBgU.js} +1 -1
- zenml/zen_server/dashboard/assets/{Error-DYflYyps.js → Error-B8uUfTpL.js} +1 -1
- zenml/zen_server/dashboard/assets/{ExecutionStatus-C7zyIQKZ.js → ExecutionStatus-ibAdY-dG.js} +1 -1
- zenml/zen_server/dashboard/assets/{Helpbox-oYSGpLqd.js → Helpbox-BfAfhKHw.js} +1 -1
- zenml/zen_server/dashboard/assets/{Infobox-Cx4xGoXR.js → Infobox-M_SMOu96.js} +1 -1
- zenml/zen_server/dashboard/assets/{InlineAvatar-DiGOWNKF.js → InlineAvatar-DBA0a0-a.js} +1 -1
- zenml/zen_server/dashboard/assets/{NestedCollapsible-DYbgyKxK.js → NestedCollapsible-DpgmEFKw.js} +1 -1
- zenml/zen_server/dashboard/assets/{Partials-03iZf8-N.js → Partials-D_ldD9if.js} +1 -1
- zenml/zen_server/dashboard/assets/{ProBadge-D_EB8HNo.js → ProBadge-DQbfFotM.js} +1 -1
- zenml/zen_server/dashboard/assets/{ProCta-DqNS4v3x.js → ProCta-Bcpb4rcY.js} +1 -1
- zenml/zen_server/dashboard/assets/{ProviderIcon-Bki2aw8w.js → ProviderIcon-BZpgPigN.js} +1 -1
- zenml/zen_server/dashboard/assets/{ProviderRadio-8f43sPD4.js → ProviderRadio-DWPnMuQ1.js} +1 -1
- zenml/zen_server/dashboard/assets/RunSelector-DgRGaAc6.js +1 -0
- zenml/zen_server/dashboard/assets/{RunsBody-07YEO7qI.js → RunsBody-KecfSkjY.js} +1 -1
- zenml/zen_server/dashboard/assets/{SearchField-lp1KgU4e.js → SearchField-n-ILHnaP.js} +1 -1
- zenml/zen_server/dashboard/assets/{SecretTooltip-CgnbyeOx.js → SecretTooltip-B8MrX5yu.js} +1 -1
- zenml/zen_server/dashboard/assets/{SetPassword-CpP418A2.js → SetPassword-B_IVq_wg.js} +1 -1
- zenml/zen_server/dashboard/assets/StackList-TWPBYnkF.js +1 -0
- zenml/zen_server/dashboard/assets/{Tabs-BktHkCJJ.js → Tabs-Rg857zmd.js} +1 -1
- zenml/zen_server/dashboard/assets/{Tick-BlMoIlJT.js → Tick-COg4A-xo.js} +1 -1
- zenml/zen_server/dashboard/assets/{UpdatePasswordSchemas-Sc0A0pP-.js → UpdatePasswordSchemas-C6Aj3hm6.js} +1 -1
- zenml/zen_server/dashboard/assets/{UsageReason-YYduL4fj.js → UsageReason-BTLbx7w4.js} +1 -1
- zenml/zen_server/dashboard/assets/{WizardFooter-dgmizSJC.js → WizardFooter-BCAj69Vj.js} +1 -1
- zenml/zen_server/dashboard/assets/{all-pipeline-runs-query-D-c2G6lV.js → all-pipeline-runs-query-DMXkDrV2.js} +1 -1
- zenml/zen_server/dashboard/assets/code-snippets-CqONne41.js +13 -0
- zenml/zen_server/dashboard/assets/{create-stack-DM_JPgef.js → create-stack-HfdbhLs4.js} +1 -1
- zenml/zen_server/dashboard/assets/dates-3pMLCNrD.js +1 -0
- zenml/zen_server/dashboard/assets/delete-run-DZ4hIXff.js +1 -0
- zenml/zen_server/dashboard/assets/{form-schemas-K6FYKjwa.js → form-schemas-B0AVEd9b.js} +1 -1
- zenml/zen_server/dashboard/assets/{index-BAkC7FXi.js → index-DPqSWjug.js} +1 -1
- zenml/zen_server/dashboard/assets/{index-CEV4Cvaf.js → index-DScjfBRb.js} +1 -1
- zenml/zen_server/dashboard/assets/index-DXvT1_Um.css +1 -0
- zenml/zen_server/dashboard/assets/{index-CCOPpudF.js → index-FO-p0GU7.js} +5 -5
- zenml/zen_server/dashboard/assets/{index-B1mVPYxf.js → index-I3bKUGUj.js} +1 -1
- zenml/zen_server/dashboard/assets/key-icon-aH-QIa5R.js +1 -0
- zenml/zen_server/dashboard/assets/login-command-CkqxPtV3.js +1 -0
- zenml/zen_server/dashboard/assets/{login-mutation-hf-lK87O.js → login-mutation-BQeo4wTY.js} +1 -1
- zenml/zen_server/dashboard/assets/{not-found-BGirLjU-.js → not-found-gAJ5aDdR.js} +1 -1
- zenml/zen_server/dashboard/assets/page-9Y9-gig0.js +1 -0
- zenml/zen_server/dashboard/assets/{page-DjRJCGb3.js → page-AUwiQ14W.js} +1 -1
- zenml/zen_server/dashboard/assets/page-B6XU7yYT.js +2 -0
- zenml/zen_server/dashboard/assets/{page-C00YAkaB.js → page-BKZYc2Zv.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-CdMWnQak.js → page-BU9FG4sR.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-D7S3aCbF.js → page-B_Apk3xg.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-Djikxq_S.js → page-BdowiCbr.js} +1 -1
- zenml/zen_server/dashboard/assets/page-Bg8OjTRe.js +1 -0
- zenml/zen_server/dashboard/assets/page-BxL4qD4_.js +1 -0
- zenml/zen_server/dashboard/assets/{page-DakHVWXF.js → page-CWxT5K5J.js} +1 -1
- zenml/zen_server/dashboard/assets/page-CXuQufSe.js +1 -0
- zenml/zen_server/dashboard/assets/{page-DLC-bNBP.js → page-CcQr8CPP.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-CD-DcWoy.js → page-Ce4Hrjnr.js} +1 -1
- zenml/zen_server/dashboard/assets/page-CiYxgZP_.js +1 -0
- zenml/zen_server/dashboard/assets/page-Cldq1mpe.js +1 -0
- zenml/zen_server/dashboard/assets/{page-BDigxVpo.js → page-D4wdonLm.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-D6uU2ax4.js → page-D8ObrbH8.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-DXSTpqRD.js → page-DFuAUGt4.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-CbpvrsDL.js → page-DGazBpuP.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-COXXJj1k.js → page-DO1UcqPX.js} +1 -1
- zenml/zen_server/dashboard/assets/page-DRYXdL5o.js +1 -0
- zenml/zen_server/dashboard/assets/{page-Df-Fw0aq.js → page-DYEquBC2.js} +1 -1
- zenml/zen_server/dashboard/assets/page-Dk32IeZm.js +1 -0
- zenml/zen_server/dashboard/assets/{page-yYC9OI-E.js → page-I3nKFGie.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-6m6yHHlE.js → page-M0w-n6vn.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-Vcxara9U.js → page-R5dx3xGF.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-BR68V0V1.js → page-bT5pOvcB.js} +1 -1
- zenml/zen_server/dashboard/assets/page-hUqK889I.js +6 -0
- zenml/zen_server/dashboard/assets/{page-CjGdWY13.js → page-h_Stveon.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-D01JhjQB.js → page-r8XK5vR7.js} +1 -1
- zenml/zen_server/dashboard/assets/page-u_-ZXBKb.js +1 -0
- zenml/zen_server/dashboard/assets/page-zaMqB_ao.js +1 -0
- zenml/zen_server/dashboard/assets/{persist-GjC8PZoC.js → persist-AppN1B0J.js} +1 -1
- zenml/zen_server/dashboard/assets/{persist-Coz7ZWvz.js → persist-DAUi_3za.js} +1 -1
- zenml/zen_server/dashboard/assets/service-BqqeXLEe.js +2 -0
- zenml/zen_server/dashboard/assets/{sharedSchema-CQb14VSr.js → sharedSchema-uXN9FLLk.js} +1 -1
- zenml/zen_server/dashboard/assets/{stack-detail-query-OPEW-cDJ.js → stack-detail-query-XfZBiBP2.js} +1 -1
- zenml/zen_server/dashboard/assets/{update-server-settings-mutation-LwuQfHYn.js → update-server-settings-mutation-BWmgVJwA.js} +1 -1
- zenml/zen_server/dashboard/assets/{url-CkvKAnwF.js → url-BLwMbzES.js} +1 -1
- zenml/zen_server/dashboard/index.html +4 -4
- zenml/zen_server/deploy/helm/Chart.yaml +1 -1
- zenml/zen_server/deploy/helm/README.md +2 -2
- zenml/zen_server/rbac/endpoint_utils.py +6 -4
- zenml/zen_server/rbac/models.py +3 -2
- zenml/zen_server/rbac/rbac_sql_zen_store.py +173 -0
- zenml/zen_server/rbac/utils.py +4 -7
- zenml/zen_server/routers/auth_endpoints.py +22 -11
- zenml/zen_server/routers/steps_endpoints.py +7 -1
- 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 +4 -1
- zenml/zen_server/utils.py +4 -3
- zenml/zen_stores/base_zen_store.py +10 -2
- zenml/zen_stores/migrations/versions/0.71.0_release.py +23 -0
- zenml/zen_stores/migrations/versions/26351d482b9e_add_step_run_unique_constraint.py +37 -0
- zenml/zen_stores/migrations/versions/a1237ba94fd8_add_model_version_producer_run_unique_.py +68 -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/rest_zen_store.py +76 -43
- 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 +55 -17
- zenml/zen_stores/schemas/pipeline_deployment_schemas.py +7 -7
- zenml/zen_stores/schemas/pipeline_run_schemas.py +52 -18
- zenml/zen_stores/schemas/pipeline_schemas.py +5 -0
- zenml/zen_stores/schemas/run_metadata_schemas.py +66 -31
- zenml/zen_stores/schemas/step_run_schemas.py +40 -13
- zenml/zen_stores/schemas/utils.py +47 -3
- zenml/zen_stores/sql_zen_store.py +462 -134
- {zenml_nightly-0.70.0.dev20241125.dist-info → zenml_nightly-0.71.0.dev20241220.dist-info}/METADATA +5 -5
- {zenml_nightly-0.70.0.dev20241125.dist-info → zenml_nightly-0.71.0.dev20241220.dist-info}/RECORD +239 -217
- zenml/utils/cloud_utils.py +0 -40
- zenml/zen_server/dashboard/assets/RunSelector-DkPiIiNr.js +0 -1
- zenml/zen_server/dashboard/assets/StackList-WvuKQusZ.js +0 -1
- zenml/zen_server/dashboard/assets/delete-run-CJdh1P_h.js +0 -1
- zenml/zen_server/dashboard/assets/index-DlGvJQPn.css +0 -1
- zenml/zen_server/dashboard/assets/page-0JE_-Ec1.js +0 -1
- zenml/zen_server/dashboard/assets/page-BRLpxOt0.js +0 -1
- zenml/zen_server/dashboard/assets/page-BU7huvKw.js +0 -6
- zenml/zen_server/dashboard/assets/page-BvqLv2Ky.js +0 -1
- zenml/zen_server/dashboard/assets/page-CwxrFarU.js +0 -1
- zenml/zen_server/dashboard/assets/page-DfbXf_8s.js +0 -1
- zenml/zen_server/dashboard/assets/page-Dnovpa0i.js +0 -3
- zenml/zen_server/dashboard/assets/page-Dot3LPmL.js +0 -1
- zenml/zen_server/dashboard/assets/page-Xynx4btY.js +0 -14
- zenml/zen_server/dashboard/assets/page-YpKAqVSa.js +0 -1
- {zenml_nightly-0.70.0.dev20241125.dist-info → zenml_nightly-0.71.0.dev20241220.dist-info}/LICENSE +0 -0
- {zenml_nightly-0.70.0.dev20241125.dist-info → zenml_nightly-0.71.0.dev20241220.dist-info}/WHEEL +0 -0
- {zenml_nightly-0.70.0.dev20241125.dist-info → zenml_nightly-0.71.0.dev20241220.dist-info}/entry_points.txt +0 -0
@@ -26,6 +26,7 @@ from datetime import datetime, timezone
|
|
26
26
|
from functools import lru_cache
|
27
27
|
from pathlib import Path
|
28
28
|
from typing import (
|
29
|
+
TYPE_CHECKING,
|
29
30
|
Any,
|
30
31
|
Callable,
|
31
32
|
ClassVar,
|
@@ -54,7 +55,7 @@ from pydantic import (
|
|
54
55
|
field_validator,
|
55
56
|
model_validator,
|
56
57
|
)
|
57
|
-
from sqlalchemy import
|
58
|
+
from sqlalchemy import func
|
58
59
|
from sqlalchemy.engine import URL, Engine, make_url
|
59
60
|
from sqlalchemy.exc import (
|
60
61
|
ArgumentError,
|
@@ -70,6 +71,7 @@ from sqlmodel import (
|
|
70
71
|
col,
|
71
72
|
create_engine,
|
72
73
|
delete,
|
74
|
+
desc,
|
73
75
|
or_,
|
74
76
|
select,
|
75
77
|
)
|
@@ -99,7 +101,6 @@ from zenml.constants import (
|
|
99
101
|
ENV_ZENML_SERVER,
|
100
102
|
FINISHED_ONBOARDING_SURVEY_KEY,
|
101
103
|
MAX_RETRIES_FOR_VERSIONED_ENTITY_CREATION,
|
102
|
-
SORT_PIPELINES_BY_LATEST_RUN_KEY,
|
103
104
|
SQL_STORE_BACKUP_DIRECTORY_NAME,
|
104
105
|
TEXT_FIELD_MAX_LENGTH,
|
105
106
|
handle_bool_env_var,
|
@@ -116,7 +117,6 @@ from zenml.enums import (
|
|
116
117
|
OnboardingStep,
|
117
118
|
SecretScope,
|
118
119
|
SecretsStoreType,
|
119
|
-
SorterOps,
|
120
120
|
StackComponentType,
|
121
121
|
StackDeploymentProvider,
|
122
122
|
StepRunInputArtifactType,
|
@@ -219,6 +219,7 @@ from zenml.models import (
|
|
219
219
|
PipelineRunUpdate,
|
220
220
|
PipelineUpdate,
|
221
221
|
RunMetadataRequest,
|
222
|
+
RunMetadataResource,
|
222
223
|
RunTemplateFilter,
|
223
224
|
RunTemplateRequest,
|
224
225
|
RunTemplateResponse,
|
@@ -296,7 +297,11 @@ from zenml.utils.networking_utils import (
|
|
296
297
|
replace_localhost_with_internal_hostname,
|
297
298
|
)
|
298
299
|
from zenml.utils.pydantic_utils import before_validator_handler
|
299
|
-
from zenml.utils.string_utils import
|
300
|
+
from zenml.utils.string_utils import (
|
301
|
+
format_name_template,
|
302
|
+
random_str,
|
303
|
+
validate_name,
|
304
|
+
)
|
300
305
|
from zenml.zen_stores import template_utils
|
301
306
|
from zenml.zen_stores.base_zen_store import (
|
302
307
|
BaseZenStore,
|
@@ -325,6 +330,7 @@ from zenml.zen_stores.schemas import (
|
|
325
330
|
PipelineDeploymentSchema,
|
326
331
|
PipelineRunSchema,
|
327
332
|
PipelineSchema,
|
333
|
+
RunMetadataResourceSchema,
|
328
334
|
RunMetadataSchema,
|
329
335
|
RunTemplateSchema,
|
330
336
|
ScheduleSchema,
|
@@ -354,6 +360,9 @@ from zenml.zen_stores.secrets_stores.sql_secrets_store import (
|
|
354
360
|
SqlSecretsStoreConfiguration,
|
355
361
|
)
|
356
362
|
|
363
|
+
if TYPE_CHECKING:
|
364
|
+
from zenml.metadata.metadata_types import MetadataType, MetadataTypeEnum
|
365
|
+
|
357
366
|
AnyNamedSchema = TypeVar("AnyNamedSchema", bound=NamedSchema)
|
358
367
|
AnySchema = TypeVar("AnySchema", bound=BaseSchema)
|
359
368
|
|
@@ -2726,7 +2735,9 @@ class SqlZenStore(BaseZenStore):
|
|
2726
2735
|
# -------------------- Artifact Versions --------------------
|
2727
2736
|
|
2728
2737
|
def _get_or_create_artifact_for_name(
|
2729
|
-
self,
|
2738
|
+
self,
|
2739
|
+
name: str,
|
2740
|
+
has_custom_name: bool,
|
2730
2741
|
) -> ArtifactSchema:
|
2731
2742
|
"""Get or create an artifact with a specific name.
|
2732
2743
|
|
@@ -2747,7 +2758,8 @@ class SqlZenStore(BaseZenStore):
|
|
2747
2758
|
try:
|
2748
2759
|
with session.begin_nested():
|
2749
2760
|
artifact_request = ArtifactRequest(
|
2750
|
-
name=name,
|
2761
|
+
name=name,
|
2762
|
+
has_custom_name=has_custom_name,
|
2751
2763
|
)
|
2752
2764
|
artifact = ArtifactSchema.from_request(
|
2753
2765
|
artifact_request
|
@@ -2915,17 +2927,41 @@ class SqlZenStore(BaseZenStore):
|
|
2915
2927
|
|
2916
2928
|
# Save metadata of the artifact
|
2917
2929
|
if artifact_version.metadata:
|
2930
|
+
values: Dict[str, "MetadataType"] = {}
|
2931
|
+
types: Dict[str, "MetadataTypeEnum"] = {}
|
2918
2932
|
for key, value in artifact_version.metadata.items():
|
2919
|
-
|
2920
|
-
|
2921
|
-
|
2922
|
-
|
2923
|
-
|
2924
|
-
|
2925
|
-
|
2926
|
-
|
2933
|
+
# Skip metadata that is too large to be stored in the DB.
|
2934
|
+
if len(json.dumps(value)) > TEXT_FIELD_MAX_LENGTH:
|
2935
|
+
logger.warning(
|
2936
|
+
f"Metadata value for key '{key}' is too large to be "
|
2937
|
+
"stored in the database. Skipping."
|
2938
|
+
)
|
2939
|
+
continue
|
2940
|
+
# Skip metadata that is not of a supported type.
|
2941
|
+
try:
|
2942
|
+
metadata_type = get_metadata_type(value)
|
2943
|
+
except ValueError as e:
|
2944
|
+
logger.warning(
|
2945
|
+
f"Metadata value for key '{key}' is not of a "
|
2946
|
+
f"supported type. Skipping. Full error: {e}"
|
2947
|
+
)
|
2948
|
+
continue
|
2949
|
+
values[key] = value
|
2950
|
+
types[key] = metadata_type
|
2951
|
+
self.create_run_metadata(
|
2952
|
+
RunMetadataRequest(
|
2953
|
+
workspace=artifact_version.workspace,
|
2954
|
+
user=artifact_version.user,
|
2955
|
+
resources=[
|
2956
|
+
RunMetadataResource(
|
2957
|
+
id=artifact_version_id,
|
2958
|
+
type=MetadataResourceTypes.ARTIFACT_VERSION,
|
2959
|
+
)
|
2960
|
+
],
|
2961
|
+
values=values,
|
2962
|
+
types=types,
|
2927
2963
|
)
|
2928
|
-
|
2964
|
+
)
|
2929
2965
|
|
2930
2966
|
session.commit()
|
2931
2967
|
artifact_version_schema = session.exec(
|
@@ -4325,69 +4361,14 @@ class SqlZenStore(BaseZenStore):
|
|
4325
4361
|
Returns:
|
4326
4362
|
A list of all pipelines matching the filter criteria.
|
4327
4363
|
"""
|
4328
|
-
query: Union[Select[Any], SelectOfScalar[Any]] = select(PipelineSchema)
|
4329
|
-
_custom_conversion: Optional[Callable[[Any], PipelineResponse]] = None
|
4330
|
-
|
4331
|
-
column, operand = pipeline_filter_model.sorting_params
|
4332
|
-
if column == SORT_PIPELINES_BY_LATEST_RUN_KEY:
|
4333
|
-
with Session(self.engine) as session:
|
4334
|
-
max_date_subquery = (
|
4335
|
-
# If no run exists for the pipeline yet, we use the pipeline
|
4336
|
-
# creation date as a fallback, otherwise newly created
|
4337
|
-
# pipeline would always be at the top/bottom
|
4338
|
-
select(
|
4339
|
-
PipelineSchema.id,
|
4340
|
-
case(
|
4341
|
-
(
|
4342
|
-
func.max(PipelineRunSchema.created).is_(None),
|
4343
|
-
PipelineSchema.created,
|
4344
|
-
),
|
4345
|
-
else_=func.max(PipelineRunSchema.created),
|
4346
|
-
).label("run_or_created"),
|
4347
|
-
)
|
4348
|
-
.outerjoin(
|
4349
|
-
PipelineRunSchema,
|
4350
|
-
PipelineSchema.id == PipelineRunSchema.pipeline_id, # type: ignore[arg-type]
|
4351
|
-
)
|
4352
|
-
.group_by(col(PipelineSchema.id))
|
4353
|
-
.subquery()
|
4354
|
-
)
|
4355
|
-
|
4356
|
-
if operand == SorterOps.DESCENDING:
|
4357
|
-
sort_clause = desc
|
4358
|
-
else:
|
4359
|
-
sort_clause = asc
|
4360
|
-
|
4361
|
-
query = (
|
4362
|
-
# We need to include the subquery in the select here to
|
4363
|
-
# make this query work with the distinct statement. This
|
4364
|
-
# result will be removed in the custom conversion function
|
4365
|
-
# applied later
|
4366
|
-
select(PipelineSchema, max_date_subquery.c.run_or_created)
|
4367
|
-
.where(PipelineSchema.id == max_date_subquery.c.id)
|
4368
|
-
.order_by(sort_clause(max_date_subquery.c.run_or_created))
|
4369
|
-
# We always add the `id` column as a tiebreaker to ensure a
|
4370
|
-
# stable, repeatable order of items, otherwise subsequent
|
4371
|
-
# pages might contain the same items.
|
4372
|
-
.order_by(col(PipelineSchema.id))
|
4373
|
-
)
|
4374
|
-
|
4375
|
-
def _custom_conversion(row: Any) -> PipelineResponse:
|
4376
|
-
return cast(
|
4377
|
-
PipelineResponse,
|
4378
|
-
row[0].to_model(
|
4379
|
-
include_metadata=hydrate, include_resources=True
|
4380
|
-
),
|
4381
|
-
)
|
4382
|
-
|
4383
4364
|
with Session(self.engine) as session:
|
4365
|
+
query = select(PipelineSchema)
|
4384
4366
|
return self.filter_and_paginate(
|
4385
4367
|
session=session,
|
4386
4368
|
query=query,
|
4387
4369
|
table=PipelineSchema,
|
4388
4370
|
filter_model=pipeline_filter_model,
|
4389
4371
|
hydrate=hydrate,
|
4390
|
-
custom_schema_to_model_conversion=_custom_conversion,
|
4391
4372
|
)
|
4392
4373
|
|
4393
4374
|
def count_pipelines(self, filter_model: Optional[PipelineFilter]) -> int:
|
@@ -5178,6 +5159,20 @@ class SqlZenStore(BaseZenStore):
|
|
5178
5159
|
"already exists."
|
5179
5160
|
)
|
5180
5161
|
|
5162
|
+
if model_version_id := self._get_or_create_model_version_for_run(
|
5163
|
+
new_run
|
5164
|
+
):
|
5165
|
+
new_run.model_version_id = model_version_id
|
5166
|
+
session.add(new_run)
|
5167
|
+
session.commit()
|
5168
|
+
|
5169
|
+
self.create_model_version_pipeline_run_link(
|
5170
|
+
ModelVersionPipelineRunRequest(
|
5171
|
+
model_version=model_version_id, pipeline_run=new_run.id
|
5172
|
+
)
|
5173
|
+
)
|
5174
|
+
session.refresh(new_run)
|
5175
|
+
|
5181
5176
|
return new_run.to_model(
|
5182
5177
|
include_metadata=True, include_resources=True
|
5183
5178
|
)
|
@@ -5329,6 +5324,19 @@ class SqlZenStore(BaseZenStore):
|
|
5329
5324
|
"orchestrator run ID."
|
5330
5325
|
)
|
5331
5326
|
|
5327
|
+
try:
|
5328
|
+
# We first try the most likely case that the run was already
|
5329
|
+
# created by a previous step in the same pipeline run.
|
5330
|
+
return (
|
5331
|
+
self._get_run_by_orchestrator_run_id(
|
5332
|
+
orchestrator_run_id=pipeline_run.orchestrator_run_id,
|
5333
|
+
deployment_id=pipeline_run.deployment,
|
5334
|
+
),
|
5335
|
+
False,
|
5336
|
+
)
|
5337
|
+
except KeyError:
|
5338
|
+
pass
|
5339
|
+
|
5332
5340
|
try:
|
5333
5341
|
return (
|
5334
5342
|
self._replace_placeholder_run(
|
@@ -5516,20 +5524,29 @@ class SqlZenStore(BaseZenStore):
|
|
5516
5524
|
The created run metadata.
|
5517
5525
|
"""
|
5518
5526
|
with Session(self.engine) as session:
|
5519
|
-
|
5520
|
-
|
5521
|
-
|
5522
|
-
|
5523
|
-
|
5524
|
-
|
5525
|
-
|
5526
|
-
|
5527
|
-
|
5528
|
-
|
5529
|
-
|
5530
|
-
|
5531
|
-
|
5532
|
-
|
5527
|
+
if run_metadata.resources:
|
5528
|
+
for key, value in run_metadata.values.items():
|
5529
|
+
type_ = run_metadata.types[key]
|
5530
|
+
run_metadata_schema = RunMetadataSchema(
|
5531
|
+
workspace_id=run_metadata.workspace,
|
5532
|
+
user_id=run_metadata.user,
|
5533
|
+
stack_component_id=run_metadata.stack_component_id,
|
5534
|
+
key=key,
|
5535
|
+
value=json.dumps(value),
|
5536
|
+
type=type_,
|
5537
|
+
publisher_step_id=run_metadata.publisher_step_id,
|
5538
|
+
)
|
5539
|
+
session.add(run_metadata_schema)
|
5540
|
+
session.commit()
|
5541
|
+
|
5542
|
+
for resource in run_metadata.resources:
|
5543
|
+
rm_resource_link = RunMetadataResourceSchema(
|
5544
|
+
resource_id=resource.id,
|
5545
|
+
resource_type=resource.type.value,
|
5546
|
+
run_metadata_id=run_metadata_schema.id,
|
5547
|
+
)
|
5548
|
+
session.add(rm_resource_link)
|
5549
|
+
session.commit()
|
5533
5550
|
return None
|
5534
5551
|
|
5535
5552
|
# ----------------------------- Schedules -----------------------------
|
@@ -8112,25 +8129,17 @@ class SqlZenStore(BaseZenStore):
|
|
8112
8129
|
f"with ID '{step_run.pipeline_run_id}' found."
|
8113
8130
|
)
|
8114
8131
|
|
8115
|
-
|
8116
|
-
|
8117
|
-
|
8118
|
-
.
|
8119
|
-
|
8120
|
-
StepRunSchema.pipeline_run_id == step_run.pipeline_run_id
|
8121
|
-
)
|
8122
|
-
).first()
|
8123
|
-
if existing_step_run is not None:
|
8132
|
+
step_schema = StepRunSchema.from_request(step_run)
|
8133
|
+
session.add(step_schema)
|
8134
|
+
try:
|
8135
|
+
session.commit()
|
8136
|
+
except IntegrityError:
|
8124
8137
|
raise EntityExistsError(
|
8125
8138
|
f"Unable to create step `{step_run.name}`: A step with "
|
8126
8139
|
f"this name already exists in the pipeline run with ID "
|
8127
8140
|
f"'{step_run.pipeline_run_id}'."
|
8128
8141
|
)
|
8129
8142
|
|
8130
|
-
# Create the step
|
8131
|
-
step_schema = StepRunSchema.from_request(step_run)
|
8132
|
-
session.add(step_schema)
|
8133
|
-
|
8134
8143
|
# Add logs entry for the step if exists
|
8135
8144
|
if step_run.logs is not None:
|
8136
8145
|
log_entry = LogsSchema(
|
@@ -8140,6 +8149,46 @@ class SqlZenStore(BaseZenStore):
|
|
8140
8149
|
)
|
8141
8150
|
session.add(log_entry)
|
8142
8151
|
|
8152
|
+
# If cached, attach metadata of the original step
|
8153
|
+
if (
|
8154
|
+
step_run.status == ExecutionStatus.CACHED
|
8155
|
+
and step_run.original_step_run_id is not None
|
8156
|
+
):
|
8157
|
+
original_metadata_links = session.exec(
|
8158
|
+
select(RunMetadataResourceSchema)
|
8159
|
+
.where(
|
8160
|
+
RunMetadataResourceSchema.run_metadata_id
|
8161
|
+
== RunMetadataSchema.id
|
8162
|
+
)
|
8163
|
+
.where(
|
8164
|
+
RunMetadataResourceSchema.resource_id
|
8165
|
+
== step_run.original_step_run_id
|
8166
|
+
)
|
8167
|
+
.where(
|
8168
|
+
RunMetadataResourceSchema.resource_type
|
8169
|
+
== MetadataResourceTypes.STEP_RUN
|
8170
|
+
)
|
8171
|
+
.where(
|
8172
|
+
RunMetadataSchema.publisher_step_id
|
8173
|
+
== step_run.original_step_run_id
|
8174
|
+
)
|
8175
|
+
).all()
|
8176
|
+
|
8177
|
+
# Create new links in a batch
|
8178
|
+
new_links = [
|
8179
|
+
RunMetadataResourceSchema(
|
8180
|
+
resource_id=step_schema.id,
|
8181
|
+
resource_type=link.resource_type,
|
8182
|
+
run_metadata_id=link.run_metadata_id,
|
8183
|
+
)
|
8184
|
+
for link in original_metadata_links
|
8185
|
+
]
|
8186
|
+
# Add all new links in a single operation
|
8187
|
+
session.add_all(new_links)
|
8188
|
+
# Commit the changes
|
8189
|
+
session.commit()
|
8190
|
+
session.refresh(step_schema)
|
8191
|
+
|
8143
8192
|
# Save parent step IDs into the database.
|
8144
8193
|
for parent_step_id in step_run.parent_step_ids:
|
8145
8194
|
self._set_run_step_parent_step(
|
@@ -8169,12 +8218,12 @@ class SqlZenStore(BaseZenStore):
|
|
8169
8218
|
)
|
8170
8219
|
|
8171
8220
|
# Save output artifact IDs into the database.
|
8172
|
-
for
|
8221
|
+
for name, artifact_version_ids in step_run.outputs.items():
|
8173
8222
|
for artifact_version_id in artifact_version_ids:
|
8174
8223
|
self._set_run_step_output_artifact(
|
8175
8224
|
step_run_id=step_schema.id,
|
8176
8225
|
artifact_version_id=artifact_version_id,
|
8177
|
-
name=
|
8226
|
+
name=name,
|
8178
8227
|
session=session,
|
8179
8228
|
)
|
8180
8229
|
|
@@ -8186,6 +8235,21 @@ class SqlZenStore(BaseZenStore):
|
|
8186
8235
|
session.commit()
|
8187
8236
|
session.refresh(step_schema)
|
8188
8237
|
|
8238
|
+
if model_version_id := self._get_or_create_model_version_for_run(
|
8239
|
+
step_schema
|
8240
|
+
):
|
8241
|
+
step_schema.model_version_id = model_version_id
|
8242
|
+
session.add(step_schema)
|
8243
|
+
session.commit()
|
8244
|
+
|
8245
|
+
self.create_model_version_pipeline_run_link(
|
8246
|
+
ModelVersionPipelineRunRequest(
|
8247
|
+
model_version=model_version_id,
|
8248
|
+
pipeline_run=step_schema.pipeline_run_id,
|
8249
|
+
)
|
8250
|
+
)
|
8251
|
+
session.refresh(step_schema)
|
8252
|
+
|
8189
8253
|
return step_schema.to_model(
|
8190
8254
|
include_metadata=True, include_resources=True
|
8191
8255
|
)
|
@@ -8278,13 +8342,14 @@ class SqlZenStore(BaseZenStore):
|
|
8278
8342
|
session.add(existing_step_run)
|
8279
8343
|
|
8280
8344
|
# Update the artifacts.
|
8281
|
-
for name,
|
8282
|
-
|
8283
|
-
|
8284
|
-
|
8285
|
-
|
8286
|
-
|
8287
|
-
|
8345
|
+
for name, artifact_version_ids in step_run_update.outputs.items():
|
8346
|
+
for artifact_version_id in artifact_version_ids:
|
8347
|
+
self._set_run_step_output_artifact(
|
8348
|
+
step_run_id=step_run_id,
|
8349
|
+
artifact_version_id=artifact_version_id,
|
8350
|
+
name=name,
|
8351
|
+
session=session,
|
8352
|
+
)
|
8288
8353
|
|
8289
8354
|
# Update loaded artifacts.
|
8290
8355
|
for (
|
@@ -8537,7 +8602,11 @@ class SqlZenStore(BaseZenStore):
|
|
8537
8602
|
|
8538
8603
|
# Deployment always exists for pipeline runs of newer versions
|
8539
8604
|
assert pipeline_run.deployment
|
8540
|
-
num_steps = len(
|
8605
|
+
num_steps = len(
|
8606
|
+
pipeline_run.deployment.to_model(
|
8607
|
+
include_metadata=True
|
8608
|
+
).step_configurations
|
8609
|
+
)
|
8541
8610
|
new_status = get_pipeline_run_status(
|
8542
8611
|
step_statuses=[
|
8543
8612
|
ExecutionStatus(step_run.status) for step_run in step_runs
|
@@ -10183,6 +10252,22 @@ class SqlZenStore(BaseZenStore):
|
|
10183
10252
|
|
10184
10253
|
# ----------------------------- Model Versions -----------------------------
|
10185
10254
|
|
10255
|
+
def _get_or_create_model(
|
10256
|
+
self, model_request: ModelRequest
|
10257
|
+
) -> Tuple[bool, ModelResponse]:
|
10258
|
+
"""Get or create a model.
|
10259
|
+
|
10260
|
+
Args:
|
10261
|
+
model_request: The model request.
|
10262
|
+
|
10263
|
+
Returns:
|
10264
|
+
A boolean whether the model was created or not, and the model.
|
10265
|
+
"""
|
10266
|
+
try:
|
10267
|
+
return True, self.create_model(model_request)
|
10268
|
+
except EntityExistsError:
|
10269
|
+
return False, self.get_model(model_request.name)
|
10270
|
+
|
10186
10271
|
def _get_next_numeric_version_for_model(
|
10187
10272
|
self, session: Session, model_id: UUID
|
10188
10273
|
) -> int:
|
@@ -10207,55 +10292,276 @@ class SqlZenStore(BaseZenStore):
|
|
10207
10292
|
else:
|
10208
10293
|
return int(current_max_version) + 1
|
10209
10294
|
|
10210
|
-
def _model_version_exists(
|
10295
|
+
def _model_version_exists(
|
10296
|
+
self,
|
10297
|
+
model_id: UUID,
|
10298
|
+
version: Optional[str] = None,
|
10299
|
+
producer_run_id: Optional[UUID] = None,
|
10300
|
+
) -> bool:
|
10211
10301
|
"""Check if a model version with a certain version exists.
|
10212
10302
|
|
10213
10303
|
Args:
|
10214
10304
|
model_id: The model ID of the version.
|
10215
10305
|
version: The version name.
|
10306
|
+
producer_run_id: The producer run ID. If given, checks if a numeric
|
10307
|
+
version for the producer run exists.
|
10308
|
+
|
10309
|
+
Returns:
|
10310
|
+
If a model version for the given arguments exists.
|
10311
|
+
"""
|
10312
|
+
query = select(ModelVersionSchema.id).where(
|
10313
|
+
ModelVersionSchema.model_id == model_id
|
10314
|
+
)
|
10315
|
+
|
10316
|
+
if version:
|
10317
|
+
query = query.where(ModelVersionSchema.name == version)
|
10318
|
+
|
10319
|
+
if producer_run_id:
|
10320
|
+
query = query.where(
|
10321
|
+
ModelVersionSchema.producer_run_id_if_numeric
|
10322
|
+
== producer_run_id,
|
10323
|
+
)
|
10324
|
+
|
10325
|
+
with Session(self.engine) as session:
|
10326
|
+
return session.exec(query).first() is not None
|
10327
|
+
|
10328
|
+
def _get_model_version(
|
10329
|
+
self,
|
10330
|
+
model_id: UUID,
|
10331
|
+
version_name: Optional[str] = None,
|
10332
|
+
producer_run_id: Optional[UUID] = None,
|
10333
|
+
) -> ModelVersionResponse:
|
10334
|
+
"""Get a model version.
|
10335
|
+
|
10336
|
+
Args:
|
10337
|
+
model_id: The ID of the model.
|
10338
|
+
version_name: The name of the model version.
|
10339
|
+
producer_run_id: The ID of the producer pipeline run. If this is
|
10340
|
+
set, only numeric versions created as part of the pipeline run
|
10341
|
+
will be returned.
|
10342
|
+
|
10343
|
+
Raises:
|
10344
|
+
ValueError: If no version name or producer run ID was provided.
|
10345
|
+
KeyError: If no model version was found.
|
10216
10346
|
|
10217
10347
|
Returns:
|
10218
|
-
|
10348
|
+
The model version.
|
10219
10349
|
"""
|
10350
|
+
query = select(ModelVersionSchema).where(
|
10351
|
+
ModelVersionSchema.model_id == model_id
|
10352
|
+
)
|
10353
|
+
|
10354
|
+
if version_name:
|
10355
|
+
if version_name.isnumeric():
|
10356
|
+
query = query.where(
|
10357
|
+
ModelVersionSchema.number == int(version_name)
|
10358
|
+
)
|
10359
|
+
error_text = (
|
10360
|
+
f"No version with number {version_name} found "
|
10361
|
+
f"for model {model_id}."
|
10362
|
+
)
|
10363
|
+
elif version_name in ModelStages.values():
|
10364
|
+
if version_name == ModelStages.LATEST:
|
10365
|
+
query = query.order_by(
|
10366
|
+
desc(col(ModelVersionSchema.number))
|
10367
|
+
).limit(1)
|
10368
|
+
else:
|
10369
|
+
query = query.where(
|
10370
|
+
ModelVersionSchema.stage == version_name
|
10371
|
+
)
|
10372
|
+
error_text = (
|
10373
|
+
f"No {version_name} stage version found for "
|
10374
|
+
f"model {model_id}."
|
10375
|
+
)
|
10376
|
+
else:
|
10377
|
+
query = query.where(ModelVersionSchema.name == version_name)
|
10378
|
+
error_text = (
|
10379
|
+
f"No {version_name} version found for model {model_id}."
|
10380
|
+
)
|
10381
|
+
|
10382
|
+
elif producer_run_id:
|
10383
|
+
query = query.where(
|
10384
|
+
ModelVersionSchema.producer_run_id_if_numeric
|
10385
|
+
== producer_run_id,
|
10386
|
+
)
|
10387
|
+
error_text = (
|
10388
|
+
f"No numeric model version found for model {model_id} "
|
10389
|
+
f"and producer run {producer_run_id}."
|
10390
|
+
)
|
10391
|
+
else:
|
10392
|
+
raise ValueError(
|
10393
|
+
"Version name or producer run id need to be specified."
|
10394
|
+
)
|
10395
|
+
|
10220
10396
|
with Session(self.engine) as session:
|
10221
|
-
|
10222
|
-
|
10223
|
-
|
10224
|
-
|
10225
|
-
|
10226
|
-
|
10227
|
-
|
10397
|
+
schema = session.exec(query).one_or_none()
|
10398
|
+
|
10399
|
+
if not schema:
|
10400
|
+
raise KeyError(error_text)
|
10401
|
+
|
10402
|
+
return schema.to_model(
|
10403
|
+
include_metadata=True, include_resources=True
|
10228
10404
|
)
|
10229
10405
|
|
10230
|
-
|
10231
|
-
|
10232
|
-
|
10406
|
+
def _get_or_create_model_version(
|
10407
|
+
self,
|
10408
|
+
model_version_request: ModelVersionRequest,
|
10409
|
+
producer_run_id: Optional[UUID] = None,
|
10410
|
+
) -> Tuple[bool, ModelVersionResponse]:
|
10411
|
+
"""Get or create a model version.
|
10412
|
+
|
10413
|
+
Args:
|
10414
|
+
model_version_request: The model version request.
|
10415
|
+
producer_run_id: ID of the producer pipeline run.
|
10416
|
+
|
10417
|
+
Raises:
|
10418
|
+
EntityCreationError: If the model version creation failed.
|
10419
|
+
|
10420
|
+
Returns:
|
10421
|
+
A boolean whether the model version was created or not, and the
|
10422
|
+
model version.
|
10423
|
+
"""
|
10424
|
+
try:
|
10425
|
+
model_version = self._create_model_version(
|
10426
|
+
model_version=model_version_request,
|
10427
|
+
producer_run_id=producer_run_id,
|
10428
|
+
)
|
10429
|
+
track(event=AnalyticsEvent.CREATED_MODEL_VERSION)
|
10430
|
+
return True, model_version
|
10431
|
+
except EntityCreationError:
|
10432
|
+
# Need to explicitly re-raise this here as otherwise the catching
|
10433
|
+
# of the RuntimeError would include this
|
10434
|
+
raise
|
10435
|
+
except RuntimeError:
|
10436
|
+
return False, self._get_model_version(
|
10437
|
+
model_id=model_version_request.model,
|
10438
|
+
producer_run_id=producer_run_id,
|
10439
|
+
)
|
10440
|
+
except EntityExistsError:
|
10441
|
+
return False, self._get_model_version(
|
10442
|
+
model_id=model_version_request.model,
|
10443
|
+
version_name=model_version_request.name,
|
10444
|
+
)
|
10445
|
+
|
10446
|
+
def _get_or_create_model_version_for_run(
|
10447
|
+
self, pipeline_or_step_run: Union[PipelineRunSchema, StepRunSchema]
|
10448
|
+
) -> Optional[UUID]:
|
10449
|
+
"""Get or create a model version for a pipeline or step run.
|
10450
|
+
|
10451
|
+
Args:
|
10452
|
+
pipeline_or_step_run: The pipeline or step run for which to create
|
10453
|
+
the model version.
|
10454
|
+
|
10455
|
+
Returns:
|
10456
|
+
The model version.
|
10457
|
+
"""
|
10458
|
+
if isinstance(pipeline_or_step_run, PipelineRunSchema):
|
10459
|
+
producer_run_id = pipeline_or_step_run.id
|
10460
|
+
pipeline_run = pipeline_or_step_run.to_model(include_metadata=True)
|
10461
|
+
configured_model = pipeline_run.config.model
|
10462
|
+
substitutions = pipeline_run.config.substitutions
|
10463
|
+
else:
|
10464
|
+
producer_run_id = pipeline_or_step_run.pipeline_run_id
|
10465
|
+
step_run = pipeline_or_step_run.to_model(include_metadata=True)
|
10466
|
+
configured_model = step_run.config.model
|
10467
|
+
substitutions = step_run.config.substitutions
|
10468
|
+
|
10469
|
+
if not configured_model:
|
10470
|
+
return None
|
10471
|
+
|
10472
|
+
model_request = ModelRequest(
|
10473
|
+
name=format_name_template(
|
10474
|
+
configured_model.name, substitutions=substitutions
|
10475
|
+
),
|
10476
|
+
license=configured_model.license,
|
10477
|
+
description=configured_model.description,
|
10478
|
+
audience=configured_model.audience,
|
10479
|
+
use_cases=configured_model.use_cases,
|
10480
|
+
limitations=configured_model.limitations,
|
10481
|
+
trade_offs=configured_model.trade_offs,
|
10482
|
+
ethics=configured_model.ethics,
|
10483
|
+
save_models_to_registry=configured_model.save_models_to_registry,
|
10484
|
+
user=pipeline_or_step_run.user_id,
|
10485
|
+
workspace=pipeline_or_step_run.workspace_id,
|
10486
|
+
)
|
10487
|
+
|
10488
|
+
_, model_response = self._get_or_create_model(
|
10489
|
+
model_request=model_request
|
10490
|
+
)
|
10491
|
+
|
10492
|
+
version_name = None
|
10493
|
+
if configured_model.version is not None:
|
10494
|
+
version_name = format_name_template(
|
10495
|
+
str(configured_model.version), substitutions=substitutions
|
10496
|
+
)
|
10497
|
+
|
10498
|
+
# If the model version was specified to be a numeric version or
|
10499
|
+
# stage we don't try to create it (which will fail because it is not
|
10500
|
+
# allowed) but try to fetch it immediately
|
10501
|
+
if (
|
10502
|
+
version_name.isnumeric()
|
10503
|
+
or version_name in ModelStages.values()
|
10504
|
+
):
|
10505
|
+
return self._get_model_version(
|
10506
|
+
model_id=model_response.id, version_name=version_name
|
10507
|
+
).id
|
10508
|
+
|
10509
|
+
model_version_request = ModelVersionRequest(
|
10510
|
+
model=model_response.id,
|
10511
|
+
name=version_name,
|
10512
|
+
description=configured_model.description,
|
10513
|
+
tags=configured_model.tags,
|
10514
|
+
user=pipeline_or_step_run.user_id,
|
10515
|
+
workspace=pipeline_or_step_run.workspace_id,
|
10516
|
+
)
|
10517
|
+
|
10518
|
+
_, model_version_response = self._get_or_create_model_version(
|
10519
|
+
model_version_request=model_version_request,
|
10520
|
+
producer_run_id=producer_run_id,
|
10521
|
+
)
|
10522
|
+
return model_version_response.id
|
10523
|
+
|
10524
|
+
def _create_model_version(
|
10525
|
+
self,
|
10526
|
+
model_version: ModelVersionRequest,
|
10527
|
+
producer_run_id: Optional[UUID] = None,
|
10233
10528
|
) -> ModelVersionResponse:
|
10234
10529
|
"""Creates a new model version.
|
10235
10530
|
|
10236
10531
|
Args:
|
10237
10532
|
model_version: the Model Version to be created.
|
10533
|
+
producer_run_id: ID of the pipeline run that produced this model
|
10534
|
+
version.
|
10238
10535
|
|
10239
10536
|
Returns:
|
10240
10537
|
The newly created model version.
|
10241
10538
|
|
10242
10539
|
Raises:
|
10243
|
-
ValueError: If
|
10540
|
+
ValueError: If the requested version name is invalid.
|
10244
10541
|
EntityExistsError: If a model version with the given name already
|
10245
10542
|
exists.
|
10246
10543
|
EntityCreationError: If the model version creation failed.
|
10544
|
+
RuntimeError: If an auto-incremented model version already exists
|
10545
|
+
for the producer run.
|
10247
10546
|
"""
|
10248
|
-
|
10249
|
-
|
10250
|
-
|
10251
|
-
)
|
10547
|
+
has_custom_name = False
|
10548
|
+
if model_version.name:
|
10549
|
+
has_custom_name = True
|
10550
|
+
validate_name(model_version)
|
10252
10551
|
|
10253
|
-
|
10552
|
+
if model_version.name.isnumeric():
|
10553
|
+
raise ValueError(
|
10554
|
+
"Can't create model version with custom numeric model "
|
10555
|
+
"version name."
|
10556
|
+
)
|
10254
10557
|
|
10255
|
-
|
10256
|
-
|
10257
|
-
|
10558
|
+
if str(model_version.name).lower() in ModelStages.values():
|
10559
|
+
raise ValueError(
|
10560
|
+
"Can't create model version with a name that is used as a "
|
10561
|
+
f"model version stage ({ModelStages.values()})."
|
10562
|
+
)
|
10258
10563
|
|
10564
|
+
model = self.get_model(model_version.model)
|
10259
10565
|
model_version_id = None
|
10260
10566
|
|
10261
10567
|
remaining_tries = MAX_RETRIES_FOR_VERSIONED_ENTITY_CREATION
|
@@ -10263,17 +10569,19 @@ class SqlZenStore(BaseZenStore):
|
|
10263
10569
|
remaining_tries -= 1
|
10264
10570
|
try:
|
10265
10571
|
with Session(self.engine) as session:
|
10266
|
-
|
10572
|
+
model_version_number = (
|
10267
10573
|
self._get_next_numeric_version_for_model(
|
10268
10574
|
session=session,
|
10269
10575
|
model_id=model.id,
|
10270
10576
|
)
|
10271
10577
|
)
|
10272
10578
|
if not has_custom_name:
|
10273
|
-
model_version.name = str(
|
10579
|
+
model_version.name = str(model_version_number)
|
10274
10580
|
|
10275
10581
|
model_version_schema = ModelVersionSchema.from_request(
|
10276
|
-
model_version
|
10582
|
+
model_version,
|
10583
|
+
model_version_number=model_version_number,
|
10584
|
+
producer_run_id=producer_run_id,
|
10277
10585
|
)
|
10278
10586
|
session.add(model_version_schema)
|
10279
10587
|
session.commit()
|
@@ -10294,6 +10602,13 @@ class SqlZenStore(BaseZenStore):
|
|
10294
10602
|
f"{model_version.name}): A model with the "
|
10295
10603
|
"same name and version already exists."
|
10296
10604
|
)
|
10605
|
+
elif producer_run_id and self._model_version_exists(
|
10606
|
+
model_id=model.id, producer_run_id=producer_run_id
|
10607
|
+
):
|
10608
|
+
raise RuntimeError(
|
10609
|
+
"Auto-incremented model version already exists for "
|
10610
|
+
f"producer run {producer_run_id}."
|
10611
|
+
)
|
10297
10612
|
elif remaining_tries == 0:
|
10298
10613
|
raise EntityCreationError(
|
10299
10614
|
f"Failed to create version for model "
|
@@ -10312,10 +10627,9 @@ class SqlZenStore(BaseZenStore):
|
|
10312
10627
|
)
|
10313
10628
|
logger.debug(
|
10314
10629
|
"Failed to create model version %s "
|
10315
|
-
"
|
10630
|
+
"due to an integrity error. "
|
10316
10631
|
"Retrying in %f seconds.",
|
10317
10632
|
model.name,
|
10318
|
-
model_version.number,
|
10319
10633
|
sleep_duration,
|
10320
10634
|
)
|
10321
10635
|
time.sleep(sleep_duration)
|
@@ -10330,6 +10644,20 @@ class SqlZenStore(BaseZenStore):
|
|
10330
10644
|
|
10331
10645
|
return self.get_model_version(model_version_id)
|
10332
10646
|
|
10647
|
+
@track_decorator(AnalyticsEvent.CREATED_MODEL_VERSION)
|
10648
|
+
def create_model_version(
|
10649
|
+
self, model_version: ModelVersionRequest
|
10650
|
+
) -> ModelVersionResponse:
|
10651
|
+
"""Creates a new model version.
|
10652
|
+
|
10653
|
+
Args:
|
10654
|
+
model_version: the Model Version to be created.
|
10655
|
+
|
10656
|
+
Returns:
|
10657
|
+
The newly created model version.
|
10658
|
+
"""
|
10659
|
+
return self._create_model_version(model_version=model_version)
|
10660
|
+
|
10333
10661
|
def get_model_version(
|
10334
10662
|
self, model_version_id: UUID, hydrate: bool = True
|
10335
10663
|
) -> ModelVersionResponse:
|