zenml-nightly 0.62.0.dev20240729__py3-none-any.whl → 0.64.0.dev20240809__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 +2 -2
- RELEASE_NOTES.md +120 -0
- zenml/VERSION +1 -1
- zenml/__init__.py +0 -4
- zenml/actions/pipeline_run/pipeline_run_action.py +19 -17
- zenml/analytics/enums.py +4 -6
- zenml/cli/__init__.py +28 -76
- zenml/cli/base.py +2 -2
- zenml/cli/pipeline.py +54 -61
- zenml/cli/stack.py +6 -8
- zenml/cli/web_login.py +8 -0
- zenml/client.py +232 -103
- zenml/config/build_configuration.py +43 -17
- zenml/config/compiler.py +14 -22
- zenml/config/docker_settings.py +80 -57
- zenml/config/pipeline_run_configuration.py +3 -0
- zenml/config/server_config.py +3 -0
- zenml/config/source.py +60 -1
- zenml/constants.py +11 -2
- zenml/entrypoints/base_entrypoint_configuration.py +53 -8
- zenml/enums.py +4 -1
- zenml/environment.py +25 -9
- zenml/image_builders/base_image_builder.py +1 -1
- zenml/image_builders/build_context.py +25 -72
- zenml/integrations/aws/orchestrators/sagemaker_orchestrator.py +13 -4
- zenml/integrations/azure/__init__.py +4 -0
- zenml/integrations/azure/flavors/__init__.py +11 -0
- zenml/integrations/azure/flavors/azureml_orchestrator_flavor.py +263 -0
- zenml/{_hub → integrations/azure/orchestrators}/__init__.py +7 -2
- zenml/integrations/azure/orchestrators/azureml_orchestrator.py +544 -0
- zenml/integrations/azure/orchestrators/azureml_orchestrator_entrypoint_config.py +86 -0
- zenml/integrations/azure/step_operators/azureml_step_operator.py +3 -0
- zenml/integrations/databricks/flavors/databricks_orchestrator_flavor.py +20 -2
- zenml/integrations/databricks/orchestrators/databricks_orchestrator.py +19 -13
- zenml/integrations/gcp/orchestrators/vertex_orchestrator.py +7 -2
- zenml/integrations/gcp/service_connectors/gcp_service_connector.py +123 -6
- zenml/integrations/kaniko/image_builders/kaniko_image_builder.py +1 -1
- zenml/integrations/mlflow/__init__.py +1 -1
- zenml/integrations/mlflow/experiment_trackers/mlflow_experiment_tracker.py +3 -1
- zenml/integrations/mlflow/flavors/mlflow_experiment_tracker_flavor.py +3 -0
- zenml/logger.py +13 -0
- zenml/models/__init__.py +26 -22
- zenml/models/v2/base/filter.py +32 -0
- zenml/models/v2/core/pipeline.py +73 -89
- zenml/models/v2/core/pipeline_build.py +15 -11
- zenml/models/v2/core/pipeline_deployment.py +72 -24
- zenml/models/v2/core/pipeline_run.py +65 -1
- zenml/models/v2/core/run_template.py +393 -0
- zenml/models/v2/core/server_settings.py +12 -0
- zenml/models/v2/core/user.py +0 -21
- zenml/models/v2/misc/server_models.py +7 -1
- zenml/models/v2/misc/stack_deployment.py +5 -0
- zenml/models/v2/misc/user_auth.py +0 -7
- zenml/new/pipelines/build_utils.py +220 -89
- zenml/new/pipelines/code_archive.py +157 -0
- zenml/new/pipelines/pipeline.py +46 -78
- zenml/new/pipelines/run_utils.py +79 -1
- zenml/post_execution/pipeline.py +1 -4
- zenml/service_connectors/service_connector_utils.py +18 -2
- zenml/stack_deployments/aws_stack_deployment.py +32 -8
- zenml/stack_deployments/azure_stack_deployment.py +122 -10
- zenml/stack_deployments/gcp_stack_deployment.py +36 -7
- zenml/stack_deployments/stack_deployment.py +23 -7
- zenml/steps/base_step.py +3 -0
- zenml/steps/utils.py +0 -4
- zenml/utils/archivable.py +149 -0
- zenml/utils/code_utils.py +244 -0
- zenml/utils/notebook_utils.py +122 -0
- zenml/utils/package_utils.py +39 -0
- zenml/utils/pipeline_docker_image_builder.py +3 -96
- zenml/utils/source_utils.py +109 -1
- zenml/zen_server/dashboard/assets/{404-B_YdvmwS.js → 404-CRAA_Lew.js} +1 -1
- zenml/zen_server/dashboard/assets/@radix-BXWm7HOa.js +85 -0
- zenml/zen_server/dashboard/assets/{@react-router-CO-OsFwI.js → @react-router-l3lMcXA2.js} +1 -1
- zenml/zen_server/dashboard/assets/{@reactflow-l_1hUr1S.js → @reactflow-CeVxyqYT.js} +2 -2
- zenml/zen_server/dashboard/assets/{@tanstack-DYiOyJUL.js → @tanstack-FmcYZMuX.js} +4 -4
- zenml/zen_server/dashboard/assets/AlertDialogDropdownItem-ErO9aOgK.js +1 -0
- zenml/zen_server/dashboard/assets/{AwarenessChannel-CFg5iX4Z.js → AwarenessChannel-CLXo5rKM.js} +1 -1
- zenml/zen_server/dashboard/assets/{CodeSnippet-Dvkx_82E.js → CodeSnippet-D0VLxT2A.js} +2 -2
- zenml/zen_server/dashboard/assets/CollapsibleCard-BaUPiVg0.js +1 -0
- zenml/zen_server/dashboard/assets/{Commands-DoN1xrEq.js → Commands-JrcZK-3j.js} +1 -1
- zenml/zen_server/dashboard/assets/CopyButton-Dbo52T1K.js +2 -0
- zenml/zen_server/dashboard/assets/{CsvVizualization-Ck-nZ43m.js → CsvVizualization-D3kAypDj.js} +3 -3
- zenml/zen_server/dashboard/assets/DisplayDate-DizbSeT-.js +1 -0
- zenml/zen_server/dashboard/assets/EditSecretDialog-Bd7mFLS4.js +1 -0
- zenml/zen_server/dashboard/assets/{EmptyState-BMLnFVlB.js → EmptyState-BHblM39I.js} +1 -1
- zenml/zen_server/dashboard/assets/{Error-kLtljEOM.js → Error-C6LeJSER.js} +1 -1
- zenml/zen_server/dashboard/assets/{ExecutionStatus-DguLLgTK.js → ExecutionStatus-jH4OrWBq.js} +1 -1
- zenml/zen_server/dashboard/assets/{Helpbox-BXUMP21n.js → Helpbox-aAB2XP-z.js} +1 -1
- zenml/zen_server/dashboard/assets/{Infobox-DSt0O-dm.js → Infobox-BQ0aty32.js} +1 -1
- zenml/zen_server/dashboard/assets/{InlineAvatar-xsrsIGE-.js → InlineAvatar-DpTLgM3Q.js} +1 -1
- zenml/zen_server/dashboard/assets/Lock-CNyJvf2r.js +1 -0
- zenml/zen_server/dashboard/assets/{MarkdownVisualization-xp3hhULl.js → MarkdownVisualization-Bajxn0HY.js} +1 -1
- zenml/zen_server/dashboard/assets/NumberBox-BmKE0qnO.js +1 -0
- zenml/zen_server/dashboard/assets/{PasswordChecker-DUveqlva.js → PasswordChecker-yGGoJSB-.js} +1 -1
- zenml/zen_server/dashboard/assets/ProviderRadio-BBqkIuTd.js +1 -0
- zenml/zen_server/dashboard/assets/RadioItem-xLhXoiFV.js +1 -0
- zenml/zen_server/dashboard/assets/SearchField-C9R0mdaX.js +1 -0
- zenml/zen_server/dashboard/assets/{SetPassword-BXGTWiwj.js → SetPassword-52sNxNiO.js} +1 -1
- zenml/zen_server/dashboard/assets/{SuccessStep-DZC60t0x.js → SuccessStep-DlkItqYG.js} +1 -1
- zenml/zen_server/dashboard/assets/Tick-uxv80Q6a.js +1 -0
- zenml/zen_server/dashboard/assets/{UpdatePasswordSchemas-DGvwFWO1.js → UpdatePasswordSchemas-oN4G3sKz.js} +1 -1
- zenml/zen_server/dashboard/assets/{aws-BgKTfTfx.js → aws-0_3UsPif.js} +1 -1
- zenml/zen_server/dashboard/assets/{check-circle-i56092KI.js → check-circle-1_I207rW.js} +1 -1
- zenml/zen_server/dashboard/assets/chevron-down-BpaF8JqM.js +1 -0
- zenml/zen_server/dashboard/assets/{chevron-right-double-CZBOf6JM.js → chevron-right-double-Dk8e2L99.js} +1 -1
- zenml/zen_server/dashboard/assets/{cloud-only-C_yFCAkP.js → cloud-only-BkUuI0lZ.js} +1 -1
- zenml/zen_server/dashboard/assets/components-Br2ezRib.js +1 -0
- zenml/zen_server/dashboard/assets/{copy-BXNk6BjL.js → copy-f3XGPPxt.js} +1 -1
- zenml/zen_server/dashboard/assets/{database-1xWSgZfO.js → database-cXYNX9tt.js} +1 -1
- zenml/zen_server/dashboard/assets/{docker-CQMVm_4d.js → docker-8uj__HHK.js} +1 -1
- zenml/zen_server/dashboard/assets/dots-horizontal-sKQlWEni.js +1 -0
- zenml/zen_server/dashboard/assets/edit-C0MVvPD2.js +1 -0
- zenml/zen_server/dashboard/assets/{file-text-CqD_iu6l.js → file-text-B9JibxTs.js} +1 -1
- zenml/zen_server/dashboard/assets/{help-bu_DgLKI.js → help-FuHlZwn0.js} +1 -1
- zenml/zen_server/dashboard/assets/{index-rK_Wuy2W.js → index-Bd1xgUQG.js} +1 -1
- zenml/zen_server/dashboard/assets/index-DaGknux4.css +1 -0
- zenml/zen_server/dashboard/assets/{index-BczVOqUf.js → index-DhIZtpxB.js} +5 -5
- zenml/zen_server/dashboard/assets/index.esm-DT4uyn2i.js +1 -0
- zenml/zen_server/dashboard/assets/layout-D6oiSbfd.js +1 -0
- zenml/zen_server/dashboard/assets/{login-mutation-CrHrndTI.js → login-mutation-13A_JSVA.js} +1 -1
- zenml/zen_server/dashboard/assets/{logs-D8k8BVFf.js → logs-CgeE2vZP.js} +1 -1
- zenml/zen_server/dashboard/assets/{not-found-DYa4pC-C.js → not-found-B0Mmb90p.js} +1 -1
- zenml/zen_server/dashboard/assets/package-DdkziX79.js +1 -0
- zenml/zen_server/dashboard/assets/page-7-v2OBm-.js +1 -0
- zenml/zen_server/dashboard/assets/{page-MFQyIJd3.js → page-B3ozwdD1.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-BkuQDIf-.js → page-BGwA9B1M.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-1iL8aMqs.js → page-BkjAUyTA.js} +1 -1
- zenml/zen_server/dashboard/assets/page-BnacgBiy.js +1 -0
- zenml/zen_server/dashboard/assets/page-BxF_KMQ3.js +2 -0
- zenml/zen_server/dashboard/assets/page-C4POHC0K.js +1 -0
- zenml/zen_server/dashboard/assets/page-C9kudd44.js +9 -0
- zenml/zen_server/dashboard/assets/page-CA1j3GpJ.js +1 -0
- zenml/zen_server/dashboard/assets/page-CCY6yfmu.js +1 -0
- zenml/zen_server/dashboard/assets/page-CgTe7Bme.js +1 -0
- zenml/zen_server/dashboard/assets/{page-8a4UMKXZ.js → page-Cgn-6v2Y.js} +1 -1
- zenml/zen_server/dashboard/assets/page-CxQmQqDw.js +1 -0
- zenml/zen_server/dashboard/assets/page-D2Goey3H.js +1 -0
- zenml/zen_server/dashboard/assets/page-DLpOnf7u.js +1 -0
- zenml/zen_server/dashboard/assets/{page-BhgCDInH.js → page-DSTQnBk-.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-1h_sD1jz.js → page-DTysUGOy.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-2grKx_MY.js → page-D_EXUFJb.js} +1 -1
- zenml/zen_server/dashboard/assets/page-Db15QzsM.js +1 -0
- zenml/zen_server/dashboard/assets/{page-BDns21Iz.js → page-DugsjcQ_.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-C6-UGEbH.js → page-OFKSPyN7.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-BkeAAYwp.js → page-RnG-qhv9.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-CCNRIt_f.js → page-T2BtjwPl.js} +1 -1
- zenml/zen_server/dashboard/assets/page-TXe1Eo3Z.js +1 -0
- zenml/zen_server/dashboard/assets/{page-BnaevhnB.js → page-YiF_fNbe.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-uA5prJGY.js → page-hQaiQXfg.js} +1 -1
- zenml/zen_server/dashboard/assets/persist-3-5nOJ6m.js +1 -0
- zenml/zen_server/dashboard/assets/{play-circle-CNtZKDnW.js → play-circle-XSkLR12B.js} +1 -1
- zenml/zen_server/dashboard/assets/plus-FB9-lEq_.js +1 -0
- zenml/zen_server/dashboard/assets/refresh-COb6KYDi.js +1 -0
- zenml/zen_server/dashboard/assets/sharedSchema-BoYx_B_L.js +14 -0
- zenml/zen_server/dashboard/assets/{stack-detail-query-Cficsl6d.js → stack-detail-query-B-US_-wa.js} +1 -1
- zenml/zen_server/dashboard/assets/{terminal-By9cErXc.js → terminal-grtjrIEJ.js} +1 -1
- zenml/zen_server/dashboard/assets/trash-Cd5CSFqA.js +1 -0
- zenml/zen_server/dashboard/assets/{update-server-settings-mutation-7d8xi1tS.js → update-server-settings-mutation-B8GB_ubU.js} +1 -1
- zenml/zen_server/dashboard/assets/{url-D7mAQGUM.js → url-hcMJkz8p.js} +1 -1
- zenml/zen_server/dashboard/assets/{zod-BhoGpZ63.js → zod-CnykDKJj.js} +1 -1
- zenml/zen_server/dashboard/index.html +7 -7
- zenml/zen_server/dashboard_legacy/asset-manifest.json +4 -4
- zenml/zen_server/dashboard_legacy/index.html +1 -1
- zenml/zen_server/dashboard_legacy/{precache-manifest.12246c7548e71e2c4438e496360de80c.js → precache-manifest.9c473c96a43298343a7ce1256183123b.js} +4 -4
- zenml/zen_server/dashboard_legacy/service-worker.js +1 -1
- zenml/zen_server/dashboard_legacy/static/js/{main.3b27024b.chunk.js → main.463c90b9.chunk.js} +2 -2
- zenml/zen_server/dashboard_legacy/static/js/{main.3b27024b.chunk.js.map → main.463c90b9.chunk.js.map} +1 -1
- zenml/zen_server/deploy/helm/Chart.yaml +1 -1
- zenml/zen_server/deploy/helm/README.md +2 -2
- zenml/zen_server/rbac/models.py +1 -0
- zenml/zen_server/rbac/utils.py +4 -0
- zenml/zen_server/routers/pipeline_builds_endpoints.py +2 -66
- zenml/zen_server/routers/pipeline_deployments_endpoints.py +2 -53
- zenml/zen_server/routers/pipelines_endpoints.py +1 -74
- zenml/zen_server/routers/run_templates_endpoints.py +212 -0
- zenml/zen_server/routers/stack_deployment_endpoints.py +6 -0
- zenml/zen_server/routers/users_endpoints.py +0 -7
- zenml/zen_server/routers/workspaces_endpoints.py +79 -0
- zenml/zen_server/{pipeline_deployment → template_execution}/runner_entrypoint_configuration.py +1 -8
- zenml/zen_server/{pipeline_deployment → template_execution}/utils.py +214 -92
- zenml/zen_server/utils.py +77 -2
- zenml/zen_server/zen_server_api.py +54 -2
- zenml/zen_stores/base_zen_store.py +7 -1
- zenml/zen_stores/migrations/versions/0.63.0_release.py +23 -0
- zenml/zen_stores/migrations/versions/0.64.0_release.py +23 -0
- zenml/zen_stores/migrations/versions/026d4577b6a0_add_code_path.py +39 -0
- zenml/zen_stores/migrations/versions/3dcc5d20e82f_add_last_user_activity.py +51 -0
- zenml/zen_stores/migrations/versions/7d1919bb1ef0_add_run_templates.py +100 -0
- zenml/zen_stores/migrations/versions/909550c7c4da_remove_user_hub_token.py +36 -0
- zenml/zen_stores/migrations/versions/b59aa68fdb1f_simplify_pipelines.py +139 -0
- zenml/zen_stores/rest_zen_store.py +112 -39
- zenml/zen_stores/schemas/__init__.py +2 -0
- zenml/zen_stores/schemas/pipeline_build_schemas.py +3 -3
- zenml/zen_stores/schemas/pipeline_deployment_schemas.py +32 -2
- zenml/zen_stores/schemas/pipeline_run_schemas.py +29 -3
- zenml/zen_stores/schemas/pipeline_schemas.py +29 -30
- zenml/zen_stores/schemas/run_template_schemas.py +264 -0
- zenml/zen_stores/schemas/server_settings_schemas.py +2 -0
- zenml/zen_stores/schemas/step_run_schemas.py +11 -4
- zenml/zen_stores/schemas/user_schemas.py +0 -2
- zenml/zen_stores/sql_zen_store.py +389 -151
- zenml/zen_stores/template_utils.py +261 -0
- zenml/zen_stores/zen_store_interface.py +93 -20
- {zenml_nightly-0.62.0.dev20240729.dist-info → zenml_nightly-0.64.0.dev20240809.dist-info}/METADATA +3 -3
- {zenml_nightly-0.62.0.dev20240729.dist-info → zenml_nightly-0.64.0.dev20240809.dist-info}/RECORD +211 -184
- zenml/_hub/client.py +0 -289
- zenml/_hub/constants.py +0 -21
- zenml/_hub/utils.py +0 -79
- zenml/cli/hub.py +0 -1116
- zenml/models/v2/core/pipeline_namespace.py +0 -113
- zenml/models/v2/misc/hub_plugin_models.py +0 -79
- zenml/new/pipelines/deserialization_utils.py +0 -292
- zenml/zen_server/dashboard/assets/@radix-CFOkMR_E.js +0 -85
- zenml/zen_server/dashboard/assets/CollapsibleCard-opiuBHHc.js +0 -1
- zenml/zen_server/dashboard/assets/CopyButton-Cr7xYEPb.js +0 -2
- zenml/zen_server/dashboard/assets/DisplayDate-DYgIjlDF.js +0 -1
- zenml/zen_server/dashboard/assets/Pagination-C6X-mifw.js +0 -1
- zenml/zen_server/dashboard/assets/index-EpMIKgrI.css +0 -1
- zenml/zen_server/dashboard/assets/index.esm-Corw4lXQ.js +0 -1
- zenml/zen_server/dashboard/assets/package-B3fWP-Dh.js +0 -1
- zenml/zen_server/dashboard/assets/page-5NCOHOsy.js +0 -1
- zenml/zen_server/dashboard/assets/page-B6h3iaHJ.js +0 -1
- zenml/zen_server/dashboard/assets/page-Bi-wtWiO.js +0 -5
- zenml/zen_server/dashboard/assets/page-Bq0YxkLV.js +0 -1
- zenml/zen_server/dashboard/assets/page-Bs2F4eoD.js +0 -2
- zenml/zen_server/dashboard/assets/page-CHNxpz3n.js +0 -1
- zenml/zen_server/dashboard/assets/page-DgorQFqi.js +0 -1
- zenml/zen_server/dashboard/assets/page-K8ebxVIs.js +0 -1
- zenml/zen_server/dashboard/assets/page-TgCF0P_U.js +0 -1
- zenml/zen_server/dashboard/assets/page-ZnCEe-eK.js +0 -9
- zenml/zen_server/dashboard/assets/persist-D7HJNBWx.js +0 -1
- zenml/zen_server/dashboard/assets/plus-C8WOyCzt.js +0 -1
- zenml/zen_server/dashboard/assets/secrets-video-OBJ6irhH.svg +0 -21
- zenml/zen_server/dashboard/assets/stacks-video-7gfxpAq4.svg +0 -21
- /zenml/zen_server/{pipeline_deployment → template_execution}/__init__.py +0 -0
- /zenml/zen_server/{pipeline_deployment → template_execution}/workload_manager_interface.py +0 -0
- {zenml_nightly-0.62.0.dev20240729.dist-info → zenml_nightly-0.64.0.dev20240809.dist-info}/LICENSE +0 -0
- {zenml_nightly-0.62.0.dev20240729.dist-info → zenml_nightly-0.64.0.dev20240809.dist-info}/WHEEL +0 -0
- {zenml_nightly-0.62.0.dev20240729.dist-info → zenml_nightly-0.64.0.dev20240809.dist-info}/entry_points.txt +0 -0
@@ -80,6 +80,7 @@ from zenml.constants import (
|
|
80
80
|
PIPELINE_DEPLOYMENTS,
|
81
81
|
PIPELINES,
|
82
82
|
RUN_METADATA,
|
83
|
+
RUN_TEMPLATES,
|
83
84
|
RUNS,
|
84
85
|
SCHEDULES,
|
85
86
|
SECRETS,
|
@@ -192,6 +193,10 @@ from zenml.models import (
|
|
192
193
|
RunMetadataFilter,
|
193
194
|
RunMetadataRequest,
|
194
195
|
RunMetadataResponse,
|
196
|
+
RunTemplateFilter,
|
197
|
+
RunTemplateRequest,
|
198
|
+
RunTemplateResponse,
|
199
|
+
RunTemplateUpdate,
|
195
200
|
ScheduleFilter,
|
196
201
|
ScheduleRequest,
|
197
202
|
ScheduleResponse,
|
@@ -1524,35 +1529,6 @@ class RestZenStore(BaseZenStore):
|
|
1524
1529
|
route=PIPELINE_BUILDS,
|
1525
1530
|
)
|
1526
1531
|
|
1527
|
-
def run_build(
|
1528
|
-
self,
|
1529
|
-
build_id: UUID,
|
1530
|
-
run_configuration: Optional[PipelineRunConfiguration] = None,
|
1531
|
-
) -> PipelineRunResponse:
|
1532
|
-
"""Run a pipeline from a build.
|
1533
|
-
|
1534
|
-
Args:
|
1535
|
-
build_id: The ID of the build to run.
|
1536
|
-
run_configuration: Configuration for the run.
|
1537
|
-
|
1538
|
-
Raises:
|
1539
|
-
RuntimeError: If the server does not support running a build.
|
1540
|
-
|
1541
|
-
Returns:
|
1542
|
-
Model of the pipeline run.
|
1543
|
-
"""
|
1544
|
-
run_configuration = run_configuration or PipelineRunConfiguration()
|
1545
|
-
try:
|
1546
|
-
response_body = self.post(
|
1547
|
-
f"{PIPELINE_BUILDS}/{build_id}/runs", body=run_configuration
|
1548
|
-
)
|
1549
|
-
except MethodNotAllowedError as e:
|
1550
|
-
raise RuntimeError(
|
1551
|
-
"Running a build is not supported for this server."
|
1552
|
-
) from e
|
1553
|
-
|
1554
|
-
return PipelineRunResponse.model_validate(response_body)
|
1555
|
-
|
1556
1532
|
# -------------------------- Pipeline Deployments --------------------------
|
1557
1533
|
|
1558
1534
|
def create_deployment(
|
@@ -1627,19 +1603,114 @@ class RestZenStore(BaseZenStore):
|
|
1627
1603
|
route=PIPELINE_DEPLOYMENTS,
|
1628
1604
|
)
|
1629
1605
|
|
1630
|
-
|
1606
|
+
# -------------------- Run templates --------------------
|
1607
|
+
|
1608
|
+
def create_run_template(
|
1631
1609
|
self,
|
1632
|
-
|
1610
|
+
template: RunTemplateRequest,
|
1611
|
+
) -> RunTemplateResponse:
|
1612
|
+
"""Create a new run template.
|
1613
|
+
|
1614
|
+
Args:
|
1615
|
+
template: The template to create.
|
1616
|
+
|
1617
|
+
Returns:
|
1618
|
+
The newly created template.
|
1619
|
+
"""
|
1620
|
+
return self._create_workspace_scoped_resource(
|
1621
|
+
resource=template,
|
1622
|
+
route=RUN_TEMPLATES,
|
1623
|
+
response_model=RunTemplateResponse,
|
1624
|
+
)
|
1625
|
+
|
1626
|
+
def get_run_template(
|
1627
|
+
self, template_id: UUID, hydrate: bool = True
|
1628
|
+
) -> RunTemplateResponse:
|
1629
|
+
"""Get a run template with a given ID.
|
1630
|
+
|
1631
|
+
Args:
|
1632
|
+
template_id: ID of the template.
|
1633
|
+
hydrate: Flag deciding whether to hydrate the output model(s)
|
1634
|
+
by including metadata fields in the response.
|
1635
|
+
|
1636
|
+
Returns:
|
1637
|
+
The template.
|
1638
|
+
"""
|
1639
|
+
return self._get_resource(
|
1640
|
+
resource_id=template_id,
|
1641
|
+
route=RUN_TEMPLATES,
|
1642
|
+
response_model=RunTemplateResponse,
|
1643
|
+
params={"hydrate": hydrate},
|
1644
|
+
)
|
1645
|
+
|
1646
|
+
def list_run_templates(
|
1647
|
+
self,
|
1648
|
+
template_filter_model: RunTemplateFilter,
|
1649
|
+
hydrate: bool = False,
|
1650
|
+
) -> Page[RunTemplateResponse]:
|
1651
|
+
"""List all run templates matching the given filter criteria.
|
1652
|
+
|
1653
|
+
Args:
|
1654
|
+
template_filter_model: All filter parameters including pagination
|
1655
|
+
params.
|
1656
|
+
hydrate: Flag deciding whether to hydrate the output model(s)
|
1657
|
+
by including metadata fields in the response.
|
1658
|
+
|
1659
|
+
Returns:
|
1660
|
+
A list of all templates matching the filter criteria.
|
1661
|
+
"""
|
1662
|
+
return self._list_paginated_resources(
|
1663
|
+
route=RUN_TEMPLATES,
|
1664
|
+
response_model=RunTemplateResponse,
|
1665
|
+
filter_model=template_filter_model,
|
1666
|
+
params={"hydrate": hydrate},
|
1667
|
+
)
|
1668
|
+
|
1669
|
+
def update_run_template(
|
1670
|
+
self,
|
1671
|
+
template_id: UUID,
|
1672
|
+
template_update: RunTemplateUpdate,
|
1673
|
+
) -> RunTemplateResponse:
|
1674
|
+
"""Updates a run template.
|
1675
|
+
|
1676
|
+
Args:
|
1677
|
+
template_id: The ID of the template to update.
|
1678
|
+
template_update: The update to apply.
|
1679
|
+
|
1680
|
+
Returns:
|
1681
|
+
The updated template.
|
1682
|
+
"""
|
1683
|
+
return self._update_resource(
|
1684
|
+
resource_id=template_id,
|
1685
|
+
resource_update=template_update,
|
1686
|
+
route=RUN_TEMPLATES,
|
1687
|
+
response_model=RunTemplateResponse,
|
1688
|
+
)
|
1689
|
+
|
1690
|
+
def delete_run_template(self, template_id: UUID) -> None:
|
1691
|
+
"""Delete a run template.
|
1692
|
+
|
1693
|
+
Args:
|
1694
|
+
template_id: The ID of the template to delete.
|
1695
|
+
"""
|
1696
|
+
self._delete_resource(
|
1697
|
+
resource_id=template_id,
|
1698
|
+
route=RUN_TEMPLATES,
|
1699
|
+
)
|
1700
|
+
|
1701
|
+
def run_template(
|
1702
|
+
self,
|
1703
|
+
template_id: UUID,
|
1633
1704
|
run_configuration: Optional[PipelineRunConfiguration] = None,
|
1634
1705
|
) -> PipelineRunResponse:
|
1635
|
-
"""Run a
|
1706
|
+
"""Run a template.
|
1636
1707
|
|
1637
1708
|
Args:
|
1638
|
-
|
1709
|
+
template_id: The ID of the template to run.
|
1639
1710
|
run_configuration: Configuration for the run.
|
1640
1711
|
|
1641
1712
|
Raises:
|
1642
|
-
RuntimeError: If the server does not support running a
|
1713
|
+
RuntimeError: If the server does not support running a template.
|
1643
1714
|
|
1644
1715
|
Returns:
|
1645
1716
|
Model of the pipeline run.
|
@@ -1648,12 +1719,12 @@ class RestZenStore(BaseZenStore):
|
|
1648
1719
|
|
1649
1720
|
try:
|
1650
1721
|
response_body = self.post(
|
1651
|
-
f"{
|
1722
|
+
f"{RUN_TEMPLATES}/{template_id}/runs",
|
1652
1723
|
body=run_configuration,
|
1653
1724
|
)
|
1654
1725
|
except MethodNotAllowedError as e:
|
1655
1726
|
raise RuntimeError(
|
1656
|
-
"Running a
|
1727
|
+
"Running a template is not supported for this server."
|
1657
1728
|
) from e
|
1658
1729
|
|
1659
1730
|
return PipelineRunResponse.model_validate(response_body)
|
@@ -4224,7 +4295,7 @@ class RestZenStore(BaseZenStore):
|
|
4224
4295
|
return self._request(
|
4225
4296
|
"POST",
|
4226
4297
|
self.url + API + VERSION_1 + path,
|
4227
|
-
|
4298
|
+
json=body.model_dump(mode="json"),
|
4228
4299
|
params=params,
|
4229
4300
|
timeout=timeout,
|
4230
4301
|
**kwargs,
|
@@ -4251,11 +4322,13 @@ class RestZenStore(BaseZenStore):
|
|
4251
4322
|
The response body.
|
4252
4323
|
"""
|
4253
4324
|
logger.debug(f"Sending PUT request to {path}...")
|
4254
|
-
|
4325
|
+
json = (
|
4326
|
+
body.model_dump(mode="json", exclude_unset=True) if body else None
|
4327
|
+
)
|
4255
4328
|
return self._request(
|
4256
4329
|
"PUT",
|
4257
4330
|
self.url + API + VERSION_1 + path,
|
4258
|
-
|
4331
|
+
json=json,
|
4259
4332
|
params=params,
|
4260
4333
|
timeout=timeout,
|
4261
4334
|
**kwargs,
|
@@ -69,6 +69,7 @@ from zenml.zen_stores.schemas.model_schemas import (
|
|
69
69
|
ModelVersionArtifactSchema,
|
70
70
|
ModelVersionPipelineRunSchema,
|
71
71
|
)
|
72
|
+
from zenml.zen_stores.schemas.run_template_schemas import RunTemplateSchema
|
72
73
|
from zenml.zen_stores.schemas.server_settings_schemas import ServerSettingsSchema
|
73
74
|
|
74
75
|
__all__ = [
|
@@ -102,6 +103,7 @@ __all__ = [
|
|
102
103
|
"StepRunOutputArtifactSchema",
|
103
104
|
"StepRunParentsSchema",
|
104
105
|
"StepRunSchema",
|
106
|
+
"RunTemplateSchema",
|
105
107
|
"TagSchema",
|
106
108
|
"TagResourceSchema",
|
107
109
|
"TriggerSchema",
|
@@ -84,7 +84,6 @@ class PipelineBuildSchema(BaseSchema, table=True):
|
|
84
84
|
back_populates="builds"
|
85
85
|
)
|
86
86
|
|
87
|
-
template_deployment_id: Optional[UUID] = None
|
88
87
|
images: str = Field(
|
89
88
|
sa_column=Column(
|
90
89
|
String(length=MEDIUMTEXT_MAX_LENGTH).with_variant(
|
@@ -100,6 +99,7 @@ class PipelineBuildSchema(BaseSchema, table=True):
|
|
100
99
|
zenml_version: Optional[str]
|
101
100
|
python_version: Optional[str]
|
102
101
|
checksum: Optional[str]
|
102
|
+
stack_checksum: Optional[str]
|
103
103
|
|
104
104
|
@classmethod
|
105
105
|
def from_request(
|
@@ -124,7 +124,7 @@ class PipelineBuildSchema(BaseSchema, table=True):
|
|
124
124
|
zenml_version=request.zenml_version,
|
125
125
|
python_version=request.python_version,
|
126
126
|
checksum=request.checksum,
|
127
|
-
|
127
|
+
stack_checksum=request.stack_checksum,
|
128
128
|
)
|
129
129
|
|
130
130
|
def to_model(
|
@@ -159,9 +159,9 @@ class PipelineBuildSchema(BaseSchema, table=True):
|
|
159
159
|
zenml_version=self.zenml_version,
|
160
160
|
python_version=self.python_version,
|
161
161
|
checksum=self.checksum,
|
162
|
+
stack_checksum=self.stack_checksum,
|
162
163
|
is_local=self.is_local,
|
163
164
|
contains_code=self.contains_code,
|
164
|
-
template_deployment_id=self.template_deployment_id,
|
165
165
|
)
|
166
166
|
return PipelineBuildResponse(
|
167
167
|
id=self.id,
|
@@ -22,6 +22,7 @@ from sqlalchemy.dialects.mysql import MEDIUMTEXT
|
|
22
22
|
from sqlmodel import Field, Relationship
|
23
23
|
|
24
24
|
from zenml.config.pipeline_configurations import PipelineConfiguration
|
25
|
+
from zenml.config.pipeline_spec import PipelineSpec
|
25
26
|
from zenml.config.step_configurations import Step
|
26
27
|
from zenml.constants import MEDIUMTEXT_MAX_LENGTH
|
27
28
|
from zenml.models import (
|
@@ -74,6 +75,16 @@ class PipelineDeploymentSchema(BaseSchema, table=True):
|
|
74
75
|
run_name_template: str = Field(nullable=False)
|
75
76
|
client_version: str = Field(nullable=True)
|
76
77
|
server_version: str = Field(nullable=True)
|
78
|
+
pipeline_version_hash: Optional[str] = Field(nullable=True, default=None)
|
79
|
+
pipeline_spec: Optional[str] = Field(
|
80
|
+
sa_column=Column(
|
81
|
+
String(length=MEDIUMTEXT_MAX_LENGTH).with_variant(
|
82
|
+
MEDIUMTEXT, "mysql"
|
83
|
+
),
|
84
|
+
nullable=True,
|
85
|
+
)
|
86
|
+
)
|
87
|
+
code_path: Optional[str] = Field(nullable=True)
|
77
88
|
|
78
89
|
# Foreign keys
|
79
90
|
user_id: Optional[UUID] = build_foreign_key_field(
|
@@ -132,12 +143,15 @@ class PipelineDeploymentSchema(BaseSchema, table=True):
|
|
132
143
|
ondelete="SET NULL",
|
133
144
|
nullable=True,
|
134
145
|
)
|
146
|
+
# This is not a foreign key to remove a cycle which messes with our DB
|
147
|
+
# backup process
|
148
|
+
template_id: Optional[UUID] = None
|
135
149
|
|
136
150
|
# SQLModel Relationships
|
137
151
|
user: Optional["UserSchema"] = Relationship()
|
138
152
|
workspace: "WorkspaceSchema" = Relationship()
|
139
|
-
stack: "StackSchema" = Relationship()
|
140
|
-
pipeline: "PipelineSchema" = Relationship()
|
153
|
+
stack: Optional["StackSchema"] = Relationship()
|
154
|
+
pipeline: Optional["PipelineSchema"] = Relationship()
|
141
155
|
schedule: Optional["ScheduleSchema"] = Relationship()
|
142
156
|
build: Optional["PipelineBuildSchema"] = Relationship(
|
143
157
|
sa_relationship_kwargs={
|
@@ -176,6 +190,7 @@ class PipelineDeploymentSchema(BaseSchema, table=True):
|
|
176
190
|
build_id=request.build,
|
177
191
|
user_id=request.user,
|
178
192
|
schedule_id=request.schedule,
|
193
|
+
template_id=request.template,
|
179
194
|
code_reference_id=code_reference_id,
|
180
195
|
run_name_template=request.run_name_template,
|
181
196
|
pipeline_configuration=request.pipeline_configuration.model_dump_json(),
|
@@ -187,6 +202,13 @@ class PipelineDeploymentSchema(BaseSchema, table=True):
|
|
187
202
|
client_environment=json.dumps(request.client_environment),
|
188
203
|
client_version=request.client_version,
|
189
204
|
server_version=request.server_version,
|
205
|
+
pipeline_version_hash=request.pipeline_version_hash,
|
206
|
+
pipeline_spec=json.dumps(
|
207
|
+
request.pipeline_spec.model_dump(mode="json"), sort_keys=True
|
208
|
+
)
|
209
|
+
if request.pipeline_spec
|
210
|
+
else None,
|
211
|
+
code_path=request.code_path,
|
190
212
|
)
|
191
213
|
|
192
214
|
def to_model(
|
@@ -235,6 +257,14 @@ class PipelineDeploymentSchema(BaseSchema, table=True):
|
|
235
257
|
code_reference=self.code_reference.to_model()
|
236
258
|
if self.code_reference
|
237
259
|
else None,
|
260
|
+
pipeline_version_hash=self.pipeline_version_hash,
|
261
|
+
pipeline_spec=PipelineSpec.model_validate_json(
|
262
|
+
self.pipeline_spec
|
263
|
+
)
|
264
|
+
if self.pipeline_spec
|
265
|
+
else None,
|
266
|
+
code_path=self.code_path,
|
267
|
+
template_id=self.template_id,
|
238
268
|
)
|
239
269
|
return PipelineDeploymentResponse(
|
240
270
|
id=self.id,
|
@@ -22,7 +22,11 @@ from sqlalchemy import UniqueConstraint
|
|
22
22
|
from sqlmodel import TEXT, Column, Field, Relationship
|
23
23
|
|
24
24
|
from zenml.config.pipeline_configurations import PipelineConfiguration
|
25
|
-
from zenml.enums import
|
25
|
+
from zenml.enums import (
|
26
|
+
ExecutionStatus,
|
27
|
+
MetadataResourceTypes,
|
28
|
+
TaggableResourceTypes,
|
29
|
+
)
|
26
30
|
from zenml.models import (
|
27
31
|
PipelineRunRequest,
|
28
32
|
PipelineRunResponse,
|
@@ -52,6 +56,7 @@ if TYPE_CHECKING:
|
|
52
56
|
from zenml.zen_stores.schemas.run_metadata_schemas import RunMetadataSchema
|
53
57
|
from zenml.zen_stores.schemas.service_schemas import ServiceSchema
|
54
58
|
from zenml.zen_stores.schemas.step_run_schemas import StepRunSchema
|
59
|
+
from zenml.zen_stores.schemas.tag_schemas import TagResourceSchema
|
55
60
|
|
56
61
|
|
57
62
|
class PipelineRunSchema(NamedSchema, table=True):
|
@@ -187,6 +192,13 @@ class PipelineRunSchema(NamedSchema, table=True):
|
|
187
192
|
services: List["ServiceSchema"] = Relationship(
|
188
193
|
back_populates="pipeline_run",
|
189
194
|
)
|
195
|
+
tags: List["TagResourceSchema"] = Relationship(
|
196
|
+
sa_relationship_kwargs=dict(
|
197
|
+
primaryjoin=f"and_(TagResourceSchema.resource_type=='{TaggableResourceTypes.PIPELINE_RUN.value}', foreign(TagResourceSchema.resource_id)==PipelineRunSchema.id)",
|
198
|
+
cascade="delete",
|
199
|
+
overlaps="tags",
|
200
|
+
),
|
201
|
+
)
|
190
202
|
|
191
203
|
@classmethod
|
192
204
|
def from_request(
|
@@ -310,15 +322,29 @@ class PipelineRunSchema(NamedSchema, table=True):
|
|
310
322
|
client_environment=client_environment,
|
311
323
|
orchestrator_environment=orchestrator_environment,
|
312
324
|
orchestrator_run_id=self.orchestrator_run_id,
|
325
|
+
code_path=self.deployment.code_path
|
326
|
+
if self.deployment
|
327
|
+
else None,
|
328
|
+
template_id=self.deployment.template_id
|
329
|
+
if self.deployment
|
330
|
+
else None,
|
313
331
|
)
|
314
332
|
|
315
333
|
resources = None
|
316
334
|
if include_resources:
|
317
335
|
model_version = None
|
318
336
|
if config.model and config.model.model_version_id:
|
319
|
-
|
337
|
+
try:
|
338
|
+
model_version = config.model._get_model_version(
|
339
|
+
hydrate=False
|
340
|
+
)
|
341
|
+
except KeyError:
|
342
|
+
# Unable to find the model version, it was probably deleted
|
343
|
+
pass
|
344
|
+
|
320
345
|
resources = PipelineRunResponseResources(
|
321
|
-
model_version=model_version
|
346
|
+
model_version=model_version,
|
347
|
+
tags=[t.tag.to_model() for t in self.tags],
|
322
348
|
)
|
323
349
|
|
324
350
|
return PipelineRunResponse(
|
@@ -13,22 +13,20 @@
|
|
13
13
|
# permissions and limitations under the License.
|
14
14
|
"""SQL Model Implementations for Pipelines and Pipeline Runs."""
|
15
15
|
|
16
|
-
import json
|
17
16
|
from datetime import datetime
|
18
17
|
from typing import TYPE_CHECKING, Any, List, Optional
|
19
18
|
from uuid import UUID
|
20
19
|
|
21
|
-
from sqlalchemy import TEXT, Column
|
22
|
-
from sqlalchemy.dialects.mysql import MEDIUMTEXT
|
20
|
+
from sqlalchemy import TEXT, Column
|
23
21
|
from sqlmodel import Field, Relationship
|
24
22
|
|
25
|
-
from zenml.
|
26
|
-
from zenml.constants import MEDIUMTEXT_MAX_LENGTH
|
23
|
+
from zenml.enums import TaggableResourceTypes
|
27
24
|
from zenml.models import (
|
28
25
|
PipelineRequest,
|
29
26
|
PipelineResponse,
|
30
27
|
PipelineResponseBody,
|
31
28
|
PipelineResponseMetadata,
|
29
|
+
PipelineResponseResources,
|
32
30
|
PipelineUpdate,
|
33
31
|
)
|
34
32
|
from zenml.zen_stores.schemas.base_schemas import NamedSchema
|
@@ -45,6 +43,7 @@ if TYPE_CHECKING:
|
|
45
43
|
)
|
46
44
|
from zenml.zen_stores.schemas.pipeline_run_schemas import PipelineRunSchema
|
47
45
|
from zenml.zen_stores.schemas.schedule_schema import ScheduleSchema
|
46
|
+
from zenml.zen_stores.schemas.tag_schemas import TagResourceSchema
|
48
47
|
|
49
48
|
|
50
49
|
class PipelineSchema(NamedSchema, table=True):
|
@@ -53,17 +52,7 @@ class PipelineSchema(NamedSchema, table=True):
|
|
53
52
|
__tablename__ = "pipeline"
|
54
53
|
|
55
54
|
# Fields
|
56
|
-
|
57
|
-
version_hash: str
|
58
|
-
docstring: Optional[str] = Field(sa_column=Column(TEXT, nullable=True))
|
59
|
-
spec: str = Field(
|
60
|
-
sa_column=Column(
|
61
|
-
String(length=MEDIUMTEXT_MAX_LENGTH).with_variant(
|
62
|
-
MEDIUMTEXT, "mysql"
|
63
|
-
),
|
64
|
-
nullable=False,
|
65
|
-
)
|
66
|
-
)
|
55
|
+
description: Optional[str] = Field(sa_column=Column(TEXT, nullable=True))
|
67
56
|
|
68
57
|
# Foreign keys
|
69
58
|
workspace_id: UUID = build_foreign_key_field(
|
@@ -90,13 +79,23 @@ class PipelineSchema(NamedSchema, table=True):
|
|
90
79
|
schedules: List["ScheduleSchema"] = Relationship(
|
91
80
|
back_populates="pipeline",
|
92
81
|
)
|
93
|
-
runs: List["PipelineRunSchema"] = Relationship(
|
82
|
+
runs: List["PipelineRunSchema"] = Relationship(
|
83
|
+
back_populates="pipeline",
|
84
|
+
sa_relationship_kwargs={"order_by": "PipelineRunSchema.created"},
|
85
|
+
)
|
94
86
|
builds: List["PipelineBuildSchema"] = Relationship(
|
95
87
|
back_populates="pipeline"
|
96
88
|
)
|
97
89
|
deployments: List["PipelineDeploymentSchema"] = Relationship(
|
98
90
|
back_populates="pipeline",
|
99
91
|
)
|
92
|
+
tags: List["TagResourceSchema"] = Relationship(
|
93
|
+
sa_relationship_kwargs=dict(
|
94
|
+
primaryjoin=f"and_(TagResourceSchema.resource_type=='{TaggableResourceTypes.PIPELINE.value}', foreign(TagResourceSchema.resource_id)==PipelineSchema.id)",
|
95
|
+
cascade="delete",
|
96
|
+
overlaps="tags",
|
97
|
+
),
|
98
|
+
)
|
100
99
|
|
101
100
|
@classmethod
|
102
101
|
def from_request(
|
@@ -113,21 +112,15 @@ class PipelineSchema(NamedSchema, table=True):
|
|
113
112
|
"""
|
114
113
|
return cls(
|
115
114
|
name=pipeline_request.name,
|
116
|
-
|
117
|
-
version_hash=pipeline_request.version_hash,
|
115
|
+
description=pipeline_request.description,
|
118
116
|
workspace_id=pipeline_request.workspace,
|
119
117
|
user_id=pipeline_request.user,
|
120
|
-
docstring=pipeline_request.docstring,
|
121
|
-
spec=json.dumps(
|
122
|
-
pipeline_request.spec.model_dump(mode="json"), sort_keys=True
|
123
|
-
),
|
124
118
|
)
|
125
119
|
|
126
120
|
def to_model(
|
127
121
|
self,
|
128
122
|
include_metadata: bool = False,
|
129
123
|
include_resources: bool = False,
|
130
|
-
last_x_runs: int = 3,
|
131
124
|
**kwargs: Any,
|
132
125
|
) -> "PipelineResponse":
|
133
126
|
"""Convert a `PipelineSchema` to a `PipelineResponse`.
|
@@ -136,25 +129,29 @@ class PipelineSchema(NamedSchema, table=True):
|
|
136
129
|
include_metadata: Whether the metadata will be filled.
|
137
130
|
include_resources: Whether the resources will be filled.
|
138
131
|
**kwargs: Keyword arguments to allow schema specific logic
|
139
|
-
last_x_runs: How many runs to use for the execution status
|
140
132
|
|
141
133
|
Returns:
|
142
134
|
The created PipelineResponse.
|
143
135
|
"""
|
144
136
|
body = PipelineResponseBody(
|
145
137
|
user=self.user.to_model() if self.user else None,
|
146
|
-
|
138
|
+
latest_run_id=self.runs[-1].id if self.runs else None,
|
139
|
+
latest_run_status=self.runs[-1].status if self.runs else None,
|
147
140
|
created=self.created,
|
148
141
|
updated=self.updated,
|
149
|
-
version=self.version,
|
150
142
|
)
|
143
|
+
|
151
144
|
metadata = None
|
152
145
|
if include_metadata:
|
153
146
|
metadata = PipelineResponseMetadata(
|
154
147
|
workspace=self.workspace.to_model(),
|
155
|
-
|
156
|
-
|
157
|
-
|
148
|
+
description=self.description,
|
149
|
+
)
|
150
|
+
|
151
|
+
resources = None
|
152
|
+
if include_resources:
|
153
|
+
resources = PipelineResponseResources(
|
154
|
+
tags=[t.tag.to_model() for t in self.tags],
|
158
155
|
)
|
159
156
|
|
160
157
|
return PipelineResponse(
|
@@ -162,6 +159,7 @@ class PipelineSchema(NamedSchema, table=True):
|
|
162
159
|
name=self.name,
|
163
160
|
body=body,
|
164
161
|
metadata=metadata,
|
162
|
+
resources=resources,
|
165
163
|
)
|
166
164
|
|
167
165
|
def update(self, pipeline_update: "PipelineUpdate") -> "PipelineSchema":
|
@@ -173,5 +171,6 @@ class PipelineSchema(NamedSchema, table=True):
|
|
173
171
|
Returns:
|
174
172
|
The updated `PipelineSchema`.
|
175
173
|
"""
|
174
|
+
self.description = pipeline_update.description
|
176
175
|
self.updated = datetime.utcnow()
|
177
176
|
return self
|