zenml-nightly 0.66.0.dev20240924__py3-none-any.whl → 0.66.0.dev20240926__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.
Files changed (122) hide show
  1. zenml/VERSION +1 -1
  2. zenml/cli/__init__.py +7 -0
  3. zenml/cli/pipeline.py +21 -0
  4. zenml/constants.py +3 -0
  5. zenml/integrations/__init__.py +1 -0
  6. zenml/integrations/aws/orchestrators/sagemaker_orchestrator.py +288 -71
  7. zenml/integrations/azure/orchestrators/azureml_orchestrator.py +157 -4
  8. zenml/integrations/constants.py +1 -0
  9. zenml/integrations/deepchecks/__init__.py +1 -1
  10. zenml/integrations/deepchecks/data_validators/deepchecks_data_validator.py +55 -14
  11. zenml/integrations/deepchecks/validation_checks.py +62 -5
  12. zenml/integrations/gcp/orchestrators/vertex_orchestrator.py +207 -18
  13. zenml/integrations/lightning/__init__.py +1 -1
  14. zenml/integrations/lightning/flavors/lightning_orchestrator_flavor.py +9 -0
  15. zenml/integrations/lightning/orchestrators/lightning_orchestrator.py +18 -17
  16. zenml/integrations/lightning/orchestrators/lightning_orchestrator_entrypoint.py +2 -6
  17. zenml/integrations/mlflow/steps/mlflow_registry.py +2 -0
  18. zenml/integrations/skypilot/orchestrators/skypilot_base_vm_orchestrator.py +38 -26
  19. zenml/integrations/skypilot_kubernetes/__init__.py +52 -0
  20. zenml/integrations/skypilot_kubernetes/flavors/__init__.py +26 -0
  21. zenml/integrations/skypilot_kubernetes/flavors/skypilot_orchestrator_kubernetes_vm_flavor.py +125 -0
  22. zenml/integrations/skypilot_kubernetes/orchestrators/__init__.py +25 -0
  23. zenml/integrations/skypilot_kubernetes/orchestrators/skypilot_kubernetes_vm_orchestrator.py +74 -0
  24. zenml/models/v2/core/pipeline_run.py +62 -1
  25. zenml/new/pipelines/run_utils.py +4 -1
  26. zenml/orchestrators/base_orchestrator.py +41 -12
  27. zenml/stack/stack.py +11 -2
  28. zenml/zen_server/cloud_utils.py +33 -8
  29. zenml/zen_server/dashboard/assets/{404-iO8vpun1.js → 404-CMnKjD-L.js} +1 -1
  30. zenml/zen_server/dashboard/assets/{@reactflow-B6kq9fJZ.js → @reactflow-CEC2f0cl.js} +1 -1
  31. zenml/zen_server/dashboard/assets/AlertDialogDropdownItem-BqM1UpCD.js +1 -0
  32. zenml/zen_server/dashboard/assets/{CodeSnippet-DNWdQmbo.js → CodeSnippet-DRy_0J4D.js} +2 -2
  33. zenml/zen_server/dashboard/assets/{CollapsibleCard-B2OVjWYE.js → CollapsibleCard-lE-75Zob.js} +1 -1
  34. zenml/zen_server/dashboard/assets/{Commands-DsoaVElZ.js → Commands-CVx2RAoT.js} +1 -1
  35. zenml/zen_server/dashboard/assets/{CopyButton-BqE_-PHO.js → CopyButton-C_yRGWuP.js} +1 -1
  36. zenml/zen_server/dashboard/assets/{CsvVizualization-Dyasr2jU.js → CsvVizualization-Dd0P02Iz.js} +1 -1
  37. zenml/zen_server/dashboard/assets/{DialogItem-Cz1VLRwa.js → DialogItem-BCrc2wIk.js} +1 -1
  38. zenml/zen_server/dashboard/assets/{Error-DorJD_va.js → Error-BuMJbG-M.js} +1 -1
  39. zenml/zen_server/dashboard/assets/{ExecutionStatus-CIfQTutR.js → ExecutionStatus-fIulMG4w.js} +1 -1
  40. zenml/zen_server/dashboard/assets/{Helpbox-CmfvtNeq.js → Helpbox-CJAp4kbv.js} +1 -1
  41. zenml/zen_server/dashboard/assets/Infobox-CC70zvGO.js +1 -0
  42. zenml/zen_server/dashboard/assets/{InlineAvatar-Ds2ZFHPc.js → InlineAvatar-C3QXdFW1.js} +1 -1
  43. zenml/zen_server/dashboard/assets/{Partials-DX-8iEa1.js → Partials-Cb8lrNsi.js} +1 -1
  44. zenml/zen_server/dashboard/assets/{ProviderIcon-BOQJgapd.js → ProviderIcon-C9BuYVSN.js} +1 -1
  45. zenml/zen_server/dashboard/assets/{ProviderRadio-BsYBw9YA.js → ProviderRadio-GYc9PJtG.js} +1 -1
  46. zenml/zen_server/dashboard/assets/{SearchField-W3GXpLlI.js → SearchField-BeF1yR7M.js} +1 -1
  47. zenml/zen_server/dashboard/assets/SecretTooltip-DgVWrPxX.js +1 -0
  48. zenml/zen_server/dashboard/assets/{SetPassword-B-0a8UCj.js → SetPassword-nAhHddXW.js} +1 -1
  49. zenml/zen_server/dashboard/assets/{Tick-i1DYsVcX.js → Tick-C5ZVvNRQ.js} +1 -1
  50. zenml/zen_server/dashboard/assets/{UpdatePasswordSchemas-C6Zb7ASL.js → UpdatePasswordSchemas-7KFsDbKb.js} +1 -1
  51. zenml/zen_server/dashboard/assets/UsageReason-DL5NL_ZD.js +1 -0
  52. zenml/zen_server/dashboard/assets/{WizardFooter-BHbO7zOa.js → WizardFooter-CgvFSppz.js} +1 -1
  53. zenml/zen_server/dashboard/assets/{all-pipeline-runs-query-BBEe6I9-.js → all-pipeline-runs-query-DAPSF_74.js} +1 -1
  54. zenml/zen_server/dashboard/assets/{cloud-only-BuP4Kt_7.js → cloud-only-CxoNxh86.js} +1 -1
  55. zenml/zen_server/dashboard/assets/{create-stack-B2x2d4r1.js → create-stack-BfgeXFuV.js} +1 -1
  56. zenml/zen_server/dashboard/assets/delete-run-OkGmZQ5G.js +1 -0
  57. zenml/zen_server/dashboard/assets/{form-schemas-Bap0f854.js → form-schemas-C09PrQUJ.js} +1 -1
  58. zenml/zen_server/dashboard/assets/{index-DFi8BroH.js → index-CLT4K7oC.js} +1 -1
  59. zenml/zen_server/dashboard/assets/{index-B9wVwe7u.js → index-D0bJjaey.js} +3 -3
  60. zenml/zen_server/dashboard/assets/index-PcI3Xw77.css +1 -0
  61. zenml/zen_server/dashboard/assets/{login-mutation-DwxUz8VA.js → login-mutation-CB45FHbP.js} +1 -1
  62. zenml/zen_server/dashboard/assets/{not-found-D5i9DunU.js → not-found-NtCUfXiV.js} +1 -1
  63. zenml/zen_server/dashboard/assets/page-AvcQe_oR.js +1 -0
  64. zenml/zen_server/dashboard/assets/page-B6DccgPa.js +1 -0
  65. zenml/zen_server/dashboard/assets/{page-xQG6GmFJ.js → page-B7DTiwhv.js} +1 -1
  66. zenml/zen_server/dashboard/assets/{page-CIbehp7V.js → page-B7LduaiG.js} +1 -1
  67. zenml/zen_server/dashboard/assets/{page-CEJWu1YO.js → page-B8WlhDq6.js} +1 -1
  68. zenml/zen_server/dashboard/assets/{page-BitfWsiW.js → page-BIhP9udn.js} +1 -1
  69. zenml/zen_server/dashboard/assets/{page-DE03uZZR.js → page-BLS9bXB8.js} +1 -1
  70. zenml/zen_server/dashboard/assets/{page-DFCK65G9.js → page-BYXn4SXu.js} +1 -1
  71. zenml/zen_server/dashboard/assets/{page-bimkItOg.js → page-Bfvwt3AB.js} +1 -1
  72. zenml/zen_server/dashboard/assets/{page-D5F3DJjm.js → page-BipKr1Pt.js} +1 -1
  73. zenml/zen_server/dashboard/assets/page-BwG4f5qc.js +1 -0
  74. zenml/zen_server/dashboard/assets/page-C1c_unjg.js +9 -0
  75. zenml/zen_server/dashboard/assets/{page-DQdwZZ9x.js → page-C25tiRdj.js} +1 -1
  76. zenml/zen_server/dashboard/assets/page-CIATsAA7.js +1 -0
  77. zenml/zen_server/dashboard/assets/{page-iwoJnwPv.js → page-CKUVhcYr.js} +1 -1
  78. zenml/zen_server/dashboard/assets/{page-BiF8hLbO.js → page-CXLwze-m.js} +1 -1
  79. zenml/zen_server/dashboard/assets/page-D7TD0k_A.js +1 -0
  80. zenml/zen_server/dashboard/assets/{page-CDOQLrPC.js → page-DIlOQjGU.js} +1 -1
  81. zenml/zen_server/dashboard/assets/{page-DGMa3ZQL.js → page-DJ31Huvj.js} +1 -1
  82. zenml/zen_server/dashboard/assets/{page-J0s8Sq3N.js → page-DOqsdVzG.js} +1 -1
  83. zenml/zen_server/dashboard/assets/{page-DQGCHKrQ.js → page-DUapawuM.js} +1 -1
  84. zenml/zen_server/dashboard/assets/{page-WCQ659by.js → page-Dd3jZyrf.js} +1 -1
  85. zenml/zen_server/dashboard/assets/{page-CrSdkteO.js → page-DyZzYHWA.js} +2 -2
  86. zenml/zen_server/dashboard/assets/page-L_xNBh_5.js +3 -0
  87. zenml/zen_server/dashboard/assets/{page-oS4hqS8M.js → page-VsrKiIdF.js} +1 -1
  88. zenml/zen_server/dashboard/assets/{page-DgM-N9RL.js → page-ioO58ULo.js} +1 -1
  89. zenml/zen_server/dashboard/assets/page-kalpiPZz.js +6 -0
  90. zenml/zen_server/dashboard/assets/{persist-xsYgVtR1.js → persist-ChKZVcn3.js} +1 -1
  91. zenml/zen_server/dashboard/assets/{persist-mEZN_fgH.js → persist-DodaLO0k.js} +1 -1
  92. zenml/zen_server/dashboard/assets/{sharedSchema-BfZcy7aP.js → sharedSchema-BvRWAv-c.js} +1 -1
  93. zenml/zen_server/dashboard/assets/{stack-detail-query-CU4egfhp.js → stack-detail-query-C9XwNP1E.js} +1 -1
  94. zenml/zen_server/dashboard/assets/tick-circle-m-hJG8i9.js +1 -0
  95. zenml/zen_server/dashboard/assets/{update-server-settings-mutation-DNqmQXDM.js → update-server-settings-mutation-DJDefwqW.js} +1 -1
  96. zenml/zen_server/dashboard/assets/{url-DwbuKk1b.js → url-DdWrpIhi.js} +1 -1
  97. zenml/zen_server/dashboard/index.html +4 -4
  98. zenml/zen_server/dashboard_legacy/asset-manifest.json +4 -4
  99. zenml/zen_server/dashboard_legacy/index.html +1 -1
  100. zenml/zen_server/dashboard_legacy/{precache-manifest.290b95d5b43efa3368b3dc63d20c4782.js → precache-manifest.4f9db97de1b48fd5944e8a766c1300fe.js} +4 -4
  101. zenml/zen_server/dashboard_legacy/service-worker.js +1 -1
  102. zenml/zen_server/dashboard_legacy/static/js/{main.840d1bf0.chunk.js → main.0fdd4aad.chunk.js} +2 -2
  103. zenml/zen_server/dashboard_legacy/static/js/{main.840d1bf0.chunk.js.map → main.0fdd4aad.chunk.js.map} +1 -1
  104. zenml/zen_server/routers/runs_endpoints.py +89 -3
  105. {zenml_nightly-0.66.0.dev20240924.dist-info → zenml_nightly-0.66.0.dev20240926.dist-info}/METADATA +8 -1
  106. {zenml_nightly-0.66.0.dev20240924.dist-info → zenml_nightly-0.66.0.dev20240926.dist-info}/RECORD +109 -102
  107. zenml/zen_server/dashboard/assets/AlertDialogDropdownItem-BXeSvmMY.js +0 -1
  108. zenml/zen_server/dashboard/assets/EditSecretDialog-Du423_3U.js +0 -1
  109. zenml/zen_server/dashboard/assets/Infobox-BL9NOS37.js +0 -1
  110. zenml/zen_server/dashboard/assets/UsageReason-CCnzmwS8.js +0 -1
  111. zenml/zen_server/dashboard/assets/index-6DYjZgDn.css +0 -1
  112. zenml/zen_server/dashboard/assets/page-BFuJICXM.js +0 -9
  113. zenml/zen_server/dashboard/assets/page-CLiRGfWo.js +0 -1
  114. zenml/zen_server/dashboard/assets/page-CV44mQn9.js +0 -1
  115. zenml/zen_server/dashboard/assets/page-DI-qTWrm.js +0 -1
  116. zenml/zen_server/dashboard/assets/page-Dt8VgzbE.js +0 -1
  117. zenml/zen_server/dashboard/assets/page-oSqx9dkH.js +0 -1
  118. zenml/zen_server/dashboard/assets/page-p3GqEAUW.js +0 -1
  119. zenml/zen_server/dashboard/assets/page-qvcUVPE-.js +0 -1
  120. {zenml_nightly-0.66.0.dev20240924.dist-info → zenml_nightly-0.66.0.dev20240926.dist-info}/LICENSE +0 -0
  121. {zenml_nightly-0.66.0.dev20240924.dist-info → zenml_nightly-0.66.0.dev20240926.dist-info}/WHEEL +0 -0
  122. {zenml_nightly-0.66.0.dev20240924.dist-info → zenml_nightly-0.66.0.dev20240926.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,125 @@
1
+ # Copyright (c) ZenML GmbH 2023. 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
+ """Skypilot orchestrator Kubernetes flavor."""
15
+
16
+ from typing import TYPE_CHECKING, Optional, Type
17
+
18
+ from zenml.constants import KUBERNETES_CLUSTER_RESOURCE_TYPE
19
+ from zenml.integrations.skypilot.flavors.skypilot_orchestrator_base_vm_config import (
20
+ SkypilotBaseOrchestratorConfig,
21
+ SkypilotBaseOrchestratorSettings,
22
+ )
23
+ from zenml.integrations.skypilot_kubernetes import (
24
+ SKYPILOT_KUBERNETES_ORCHESTRATOR_FLAVOR,
25
+ )
26
+ from zenml.logger import get_logger
27
+ from zenml.models import ServiceConnectorRequirements
28
+ from zenml.orchestrators import BaseOrchestratorConfig, BaseOrchestratorFlavor
29
+
30
+ if TYPE_CHECKING:
31
+ from zenml.integrations.skypilot_kubernetes.orchestrators import (
32
+ SkypilotKubernetesOrchestrator,
33
+ )
34
+
35
+
36
+ logger = get_logger(__name__)
37
+
38
+
39
+ class SkypilotKubernetesOrchestratorSettings(SkypilotBaseOrchestratorSettings):
40
+ """Skypilot orchestrator settings."""
41
+
42
+
43
+ class SkypilotKubernetesOrchestratorConfig(
44
+ SkypilotBaseOrchestratorConfig, SkypilotKubernetesOrchestratorSettings
45
+ ):
46
+ """Skypilot orchestrator config."""
47
+
48
+
49
+ class SkypilotKubernetesOrchestratorFlavor(BaseOrchestratorFlavor):
50
+ """Flavor for the Skypilot Kubernetes orchestrator."""
51
+
52
+ @property
53
+ def name(self) -> str:
54
+ """Name of the orchestrator flavor.
55
+
56
+ Returns:
57
+ Name of the orchestrator flavor.
58
+ """
59
+ return SKYPILOT_KUBERNETES_ORCHESTRATOR_FLAVOR
60
+
61
+ @property
62
+ def service_connector_requirements(
63
+ self,
64
+ ) -> Optional[ServiceConnectorRequirements]:
65
+ """Service connector resource requirements for service connectors.
66
+
67
+ Specifies resource requirements that are used to filter the available
68
+ service connector types that are compatible with this flavor.
69
+
70
+ Returns:
71
+ Requirements for compatible service connectors, if a service
72
+ connector is required for this flavor.
73
+ """
74
+ return ServiceConnectorRequirements(
75
+ resource_type=KUBERNETES_CLUSTER_RESOURCE_TYPE,
76
+ )
77
+
78
+ @property
79
+ def docs_url(self) -> Optional[str]:
80
+ """A url to point at docs explaining this flavor.
81
+
82
+ Returns:
83
+ A flavor docs url.
84
+ """
85
+ return self.generate_default_docs_url()
86
+
87
+ @property
88
+ def sdk_docs_url(self) -> Optional[str]:
89
+ """A url to point at SDK docs explaining this flavor.
90
+
91
+ Returns:
92
+ A flavor SDK docs url.
93
+ """
94
+ return self.generate_default_sdk_docs_url()
95
+
96
+ @property
97
+ def logo_url(self) -> str:
98
+ """A url to represent the flavor in the dashboard.
99
+
100
+ Returns:
101
+ The flavor logo.
102
+ """
103
+ return "https://public-flavor-logos.s3.eu-central-1.amazonaws.com/orchestrator/kubernetes-skypilot.png"
104
+
105
+ @property
106
+ def config_class(self) -> Type[BaseOrchestratorConfig]:
107
+ """Config class for the base orchestrator flavor.
108
+
109
+ Returns:
110
+ The config class.
111
+ """
112
+ return SkypilotKubernetesOrchestratorConfig
113
+
114
+ @property
115
+ def implementation_class(self) -> Type["SkypilotKubernetesOrchestrator"]:
116
+ """Implementation class for this flavor.
117
+
118
+ Returns:
119
+ Implementation class for this flavor.
120
+ """
121
+ from zenml.integrations.skypilot_kubernetes.orchestrators import (
122
+ SkypilotKubernetesOrchestrator,
123
+ )
124
+
125
+ return SkypilotKubernetesOrchestrator
@@ -0,0 +1,25 @@
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
+ """Initialization of the Skypilot Kubernetes ZenML orchestrator."""
15
+
16
+ from zenml.integrations.skypilot.orchestrators.skypilot_base_vm_orchestrator import ( # noqa
17
+ SkypilotBaseOrchestrator,
18
+ )
19
+ from zenml.integrations.skypilot_kubernetes.orchestrators.skypilot_kubernetes_vm_orchestrator import ( # noqa
20
+ SkypilotKubernetesOrchestrator,
21
+ )
22
+ __all__ = [
23
+ "SkypilotBaseOrchestrator",
24
+ "SkypilotKubernetesOrchestrator",
25
+ ]
@@ -0,0 +1,74 @@
1
+ # Copyright (c) ZenML GmbH 2023. 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
+ """Implementation of the a Skypilot based Kubernetes VM orchestrator."""
15
+
16
+ from typing import TYPE_CHECKING, Optional, Type, cast
17
+
18
+ import sky
19
+
20
+ from zenml.integrations.skypilot.orchestrators.skypilot_base_vm_orchestrator import (
21
+ SkypilotBaseOrchestrator,
22
+ )
23
+ from zenml.integrations.skypilot_kubernetes.flavors.skypilot_orchestrator_kubernetes_vm_flavor import (
24
+ SkypilotKubernetesOrchestratorConfig,
25
+ SkypilotKubernetesOrchestratorSettings,
26
+ )
27
+ from zenml.logger import get_logger
28
+
29
+ if TYPE_CHECKING:
30
+ from zenml.config.base_settings import BaseSettings
31
+
32
+ logger = get_logger(__name__)
33
+
34
+
35
+ class SkypilotKubernetesOrchestrator(SkypilotBaseOrchestrator):
36
+ """Orchestrator responsible for running pipelines remotely in a VM on Kubernetes.
37
+
38
+ This orchestrator does not support running on a schedule.
39
+ """
40
+
41
+ @property
42
+ def cloud(self) -> sky.clouds.Cloud:
43
+ """The type of sky cloud to use.
44
+
45
+ Returns:
46
+ A `sky.clouds.Cloud` instance.
47
+ """
48
+ return sky.clouds.Kubernetes()
49
+
50
+ @property
51
+ def config(self) -> SkypilotKubernetesOrchestratorConfig:
52
+ """Returns the `SkypilotKubernetesOrchestratorConfig` config.
53
+
54
+ Returns:
55
+ The configuration.
56
+ """
57
+ return cast(SkypilotKubernetesOrchestratorConfig, self._config)
58
+
59
+ @property
60
+ def settings_class(self) -> Optional[Type["BaseSettings"]]:
61
+ """Settings class for the Skypilot orchestrator.
62
+
63
+ Returns:
64
+ The settings class.
65
+ """
66
+ return SkypilotKubernetesOrchestratorSettings
67
+
68
+ def prepare_environment_variable(self, set: bool = True) -> None:
69
+ """Set up Environment variables that are required for the orchestrator.
70
+
71
+ Args:
72
+ set: Whether to set the environment variables or not.
73
+ """
74
+ pass
@@ -21,6 +21,7 @@ from typing import (
21
21
  List,
22
22
  Optional,
23
23
  Union,
24
+ cast,
24
25
  )
25
26
  from uuid import UUID
26
27
 
@@ -136,7 +137,8 @@ class PipelineRunUpdate(BaseModel):
136
137
  "configured by this pipeline run explicitly.",
137
138
  default=None,
138
139
  )
139
- # TODO: we should maybe have a different update model here, the upper three attributes should only be for internal use
140
+ # TODO: we should maybe have a different update model here, the upper
141
+ # three attributes should only be for internal use
140
142
  add_tags: Optional[List[str]] = Field(
141
143
  default=None, title="New tags to add to the pipeline run."
142
144
  )
@@ -235,6 +237,7 @@ class PipelineRunResponseMetadata(WorkspaceScopedResponseMetadata):
235
237
  description="Template used for the pipeline run.",
236
238
  )
237
239
  is_templatable: bool = Field(
240
+ default=False,
238
241
  description="Whether a template can be created from this run.",
239
242
  )
240
243
 
@@ -307,6 +310,64 @@ class PipelineRunResponse(
307
310
 
308
311
  return get_artifacts_versions_of_pipeline_run(self, only_produced=True)
309
312
 
313
+ def refresh_run_status(self) -> "PipelineRunResponse":
314
+ """Method to refresh the status of a run if it is initializing/running.
315
+
316
+ Returns:
317
+ The updated pipeline.
318
+
319
+ Raises:
320
+ ValueError: If the stack of the run response is None.
321
+ """
322
+ if self.status in [
323
+ ExecutionStatus.INITIALIZING,
324
+ ExecutionStatus.RUNNING,
325
+ ]:
326
+ # Check if the stack still accessible
327
+ if self.stack is None:
328
+ raise ValueError(
329
+ "The stack that this pipeline run response was executed on"
330
+ "has been deleted."
331
+ )
332
+
333
+ # Create the orchestrator instance
334
+ from zenml.enums import StackComponentType
335
+ from zenml.orchestrators.base_orchestrator import BaseOrchestrator
336
+ from zenml.stack.stack_component import StackComponent
337
+
338
+ # Check if the stack still accessible
339
+ orchestrator_list = self.stack.components.get(
340
+ StackComponentType.ORCHESTRATOR, []
341
+ )
342
+ if len(orchestrator_list) == 0:
343
+ raise ValueError(
344
+ "The orchestrator that this pipeline run response was "
345
+ "executed with has been deleted."
346
+ )
347
+
348
+ orchestrator = cast(
349
+ BaseOrchestrator,
350
+ StackComponent.from_model(
351
+ component_model=orchestrator_list[0]
352
+ ),
353
+ )
354
+
355
+ # Fetch the status
356
+ status = orchestrator.fetch_status(run=self)
357
+
358
+ # If it is different from the current status, update it
359
+ if status != self.status:
360
+ from zenml.client import Client
361
+ from zenml.models import PipelineRunUpdate
362
+
363
+ client = Client()
364
+ return client.zen_store.update_run(
365
+ run_id=self.id,
366
+ run_update=PipelineRunUpdate(status=status),
367
+ )
368
+
369
+ return self
370
+
310
371
  # Body and metadata properties
311
372
  @property
312
373
  def status(self) -> ExecutionStatus:
@@ -138,7 +138,10 @@ def deploy_pipeline(
138
138
  previous_value = constants.SHOULD_PREVENT_PIPELINE_EXECUTION
139
139
  constants.SHOULD_PREVENT_PIPELINE_EXECUTION = True
140
140
  try:
141
- stack.deploy_pipeline(deployment=deployment)
141
+ stack.deploy_pipeline(
142
+ deployment=deployment,
143
+ placeholder_run=placeholder_run,
144
+ )
142
145
  except Exception as e:
143
146
  if (
144
147
  placeholder_run
@@ -14,12 +14,14 @@
14
14
  """Base orchestrator class."""
15
15
 
16
16
  from abc import ABC, abstractmethod
17
- from typing import TYPE_CHECKING, Any, Dict, Optional, Type, cast
17
+ from typing import TYPE_CHECKING, Any, Dict, Iterator, Optional, Type, cast
18
18
 
19
19
  from pydantic import model_validator
20
20
 
21
- from zenml.enums import StackComponentType
21
+ from zenml.enums import ExecutionStatus, StackComponentType
22
22
  from zenml.logger import get_logger
23
+ from zenml.metadata.metadata_types import MetadataType
24
+ from zenml.orchestrators.publish_utils import publish_pipeline_run_metadata
23
25
  from zenml.orchestrators.step_launcher import StepLauncher
24
26
  from zenml.orchestrators.utils import get_config_environment_vars
25
27
  from zenml.stack import Flavor, Stack, StackComponent, StackComponentConfig
@@ -27,7 +29,7 @@ from zenml.utils.pydantic_utils import before_validator_handler
27
29
 
28
30
  if TYPE_CHECKING:
29
31
  from zenml.config.step_configurations import Step
30
- from zenml.models import PipelineDeploymentResponse
32
+ from zenml.models import PipelineDeploymentResponse, PipelineRunResponse
31
33
 
32
34
  logger = get_logger(__name__)
33
35
 
@@ -124,7 +126,7 @@ class BaseOrchestrator(StackComponent, ABC):
124
126
  deployment: "PipelineDeploymentResponse",
125
127
  stack: "Stack",
126
128
  environment: Dict[str, str],
127
- ) -> Any:
129
+ ) -> Optional[Iterator[Dict[str, MetadataType]]]:
128
130
  """The method needs to be implemented by the respective orchestrator.
129
131
 
130
132
  Depending on the type of orchestrator you'll have to perform slightly
@@ -169,29 +171,41 @@ class BaseOrchestrator(StackComponent, ABC):
169
171
  self,
170
172
  deployment: "PipelineDeploymentResponse",
171
173
  stack: "Stack",
174
+ placeholder_run: Optional["PipelineRunResponse"] = None,
172
175
  ) -> Any:
173
176
  """Runs a pipeline on a stack.
174
177
 
175
178
  Args:
176
179
  deployment: The pipeline deployment.
177
180
  stack: The stack on which to run the pipeline.
178
-
179
- Returns:
180
- Orchestrator-specific return value.
181
+ placeholder_run: An optional placeholder run for the deployment.
182
+ This will be deleted in case the pipeline deployment failed.
181
183
  """
182
184
  self._prepare_run(deployment=deployment)
183
185
 
184
186
  environment = get_config_environment_vars(deployment=deployment)
185
187
 
186
188
  try:
187
- result = self.prepare_or_run_pipeline(
188
- deployment=deployment, stack=stack, environment=environment
189
- )
189
+ if metadata_iterator := self.prepare_or_run_pipeline(
190
+ deployment=deployment,
191
+ stack=stack,
192
+ environment=environment,
193
+ ):
194
+ for metadata_dict in metadata_iterator:
195
+ try:
196
+ if placeholder_run:
197
+ publish_pipeline_run_metadata(
198
+ pipeline_run_id=placeholder_run.id,
199
+ pipeline_run_metadata={self.id: metadata_dict},
200
+ )
201
+ except Exception as e:
202
+ logger.debug(
203
+ "Something went went wrong trying to publish the"
204
+ f"run metadata: {e}"
205
+ )
190
206
  finally:
191
207
  self._cleanup_run()
192
208
 
193
- return result
194
-
195
209
  def run_step(self, step: "Step") -> None:
196
210
  """Runs the given step.
197
211
 
@@ -239,6 +253,21 @@ class BaseOrchestrator(StackComponent, ABC):
239
253
  """Cleans up the active run."""
240
254
  self._active_deployment = None
241
255
 
256
+ def fetch_status(self, run: "PipelineRunResponse") -> ExecutionStatus:
257
+ """Refreshes the status of a specific pipeline run.
258
+
259
+ Args:
260
+ run: A pipeline run response to fetch its status.
261
+
262
+ Raises:
263
+ NotImplementedError: If any orchestrator inheriting from the base
264
+ class does not implement this logic.
265
+ """
266
+ raise NotImplementedError(
267
+ "The fetch status functionality is not implemented for the "
268
+ f"'{self.__class__.__name__}' orchestrator."
269
+ )
270
+
242
271
 
243
272
  class BaseOrchestratorFlavor(Flavor):
244
273
  """Base orchestrator flavor class."""
zenml/stack/stack.py CHANGED
@@ -62,7 +62,11 @@ if TYPE_CHECKING:
62
62
  from zenml.image_builders import BaseImageBuilder
63
63
  from zenml.model_deployers import BaseModelDeployer
64
64
  from zenml.model_registries import BaseModelRegistry
65
- from zenml.models import PipelineDeploymentBase, PipelineDeploymentResponse
65
+ from zenml.models import (
66
+ PipelineDeploymentBase,
67
+ PipelineDeploymentResponse,
68
+ PipelineRunResponse,
69
+ )
66
70
  from zenml.orchestrators import BaseOrchestrator
67
71
  from zenml.stack import StackComponent
68
72
  from zenml.step_operators import BaseStepOperator
@@ -826,16 +830,21 @@ class Stack:
826
830
  def deploy_pipeline(
827
831
  self,
828
832
  deployment: "PipelineDeploymentResponse",
833
+ placeholder_run: Optional["PipelineRunResponse"] = None,
829
834
  ) -> Any:
830
835
  """Deploys a pipeline on this stack.
831
836
 
832
837
  Args:
833
838
  deployment: The pipeline deployment.
839
+ placeholder_run: An optional placeholder run for the deployment.
840
+ This will be deleted in case the pipeline deployment failed.
834
841
 
835
842
  Returns:
836
843
  The return value of the call to `orchestrator.run_pipeline(...)`.
837
844
  """
838
- return self.orchestrator.run(deployment=deployment, stack=self)
845
+ return self.orchestrator.run(
846
+ deployment=deployment, stack=self, placeholder_run=placeholder_run
847
+ )
839
848
 
840
849
  def _get_active_components_for_step(
841
850
  self, step_config: "StepConfiguration"
@@ -1,6 +1,7 @@
1
1
  """Utils concerning anything concerning the cloud control plane backend."""
2
2
 
3
3
  import os
4
+ from datetime import datetime, timedelta, timezone
4
5
  from typing import Any, Dict, Optional
5
6
 
6
7
  import requests
@@ -19,11 +20,9 @@ class ZenMLCloudConfiguration(BaseModel):
19
20
  """ZenML Pro RBAC configuration."""
20
21
 
21
22
  api_url: str
22
-
23
23
  oauth2_client_id: str
24
24
  oauth2_client_secret: str
25
25
  oauth2_audience: str
26
- auth0_domain: str
27
26
 
28
27
  @field_validator("api_url")
29
28
  @classmethod
@@ -68,6 +67,8 @@ class ZenMLCloudConnection:
68
67
  """Initialize the RBAC component."""
69
68
  self._config = ZenMLCloudConfiguration.from_environment()
70
69
  self._session: Optional[requests.Session] = None
70
+ self._token: Optional[str] = None
71
+ self._token_expires_at: Optional[datetime] = None
71
72
 
72
73
  def get(
73
74
  self, endpoint: str, params: Optional[Dict[str, Any]]
@@ -91,7 +92,8 @@ class ZenMLCloudConnection:
91
92
 
92
93
  response = self.session.get(url=url, params=params, timeout=7)
93
94
  if response.status_code == 401:
94
- # Refresh the auth token and try again
95
+ # If we get an Unauthorized error from the API serer, we refresh the
96
+ # auth token and try again
95
97
  self._clear_session()
96
98
  response = self.session.get(url=url, params=params, timeout=7)
97
99
 
@@ -186,6 +188,8 @@ class ZenMLCloudConnection:
186
188
  def _clear_session(self) -> None:
187
189
  """Clear the authentication session."""
188
190
  self._session = None
191
+ self._token = None
192
+ self._token_expires_at = None
189
193
 
190
194
  def _fetch_auth_token(self) -> str:
191
195
  """Fetch an auth token for the Cloud API from auth0.
@@ -196,8 +200,16 @@ class ZenMLCloudConnection:
196
200
  Returns:
197
201
  Auth token.
198
202
  """
203
+ if (
204
+ self._token is not None
205
+ and self._token_expires_at is not None
206
+ and datetime.now(timezone.utc) + timedelta(minutes=5)
207
+ < self._token_expires_at
208
+ ):
209
+ return self._token
210
+
199
211
  # Get an auth token from auth0
200
- auth0_url = f"https://{self._config.auth0_domain}/oauth/token"
212
+ login_url = f"{self._config.api_url}/auth/login"
201
213
  headers = {"content-type": "application/x-www-form-urlencoded"}
202
214
  payload = {
203
215
  "client_id": self._config.oauth2_client_id,
@@ -207,18 +219,31 @@ class ZenMLCloudConnection:
207
219
  }
208
220
  try:
209
221
  response = requests.post(
210
- auth0_url, headers=headers, data=payload, timeout=7
222
+ login_url, headers=headers, data=payload, timeout=7
211
223
  )
212
224
  response.raise_for_status()
213
225
  except Exception as e:
214
226
  raise RuntimeError(f"Error fetching auth token from auth0: {e}")
215
227
 
216
- access_token = response.json().get("access_token", "")
228
+ json_response = response.json()
229
+ access_token = json_response.get("access_token", "")
230
+ expires_in = json_response.get("expires_in", 0)
217
231
 
218
- if not access_token or not isinstance(access_token, str):
232
+ if (
233
+ not access_token
234
+ or not isinstance(access_token, str)
235
+ or not expires_in
236
+ or not isinstance(expires_in, int)
237
+ ):
219
238
  raise RuntimeError("Could not fetch auth token from auth0.")
220
239
 
221
- return str(access_token)
240
+ self._token = access_token
241
+ self._token_expires_at = datetime.now(timezone.utc) + timedelta(
242
+ seconds=expires_in
243
+ )
244
+
245
+ assert self._token is not None
246
+ return self._token
222
247
 
223
248
 
224
249
  def cloud_connection() -> ZenMLCloudConnection:
@@ -1 +1 @@
1
- import{j as e}from"./@radix-DnFH_oo1.js";import{f as s,r as t}from"./index-B9wVwe7u.js";import{E as r}from"./EmptyState-Cs3DEmso.js";import{H as a}from"./help-CwN931fX.js";import{L as o}from"./@react-router-APVeuk-U.js";import"./@tanstack-QbMbTrh5.js";import"./@reactflow-B6kq9fJZ.js";function d(){return e.jsx("div",{className:"flex min-h-screen w-full flex-col",children:e.jsx(r,{icon:e.jsx(a,{className:"h-[120px] w-[120px] fill-neutral-300"}),children:e.jsxs("div",{className:"text-center",children:[e.jsx("h1",{className:"mb-2 text-display-xs font-semibold",children:"We can't find the page you are looking for"}),e.jsx("p",{className:"text-lg text-theme-text-secondary",children:"You can try typing a different URL or we can bring you back to your Homepage."}),e.jsx("div",{className:"mt-5 flex justify-center",children:e.jsx(s,{size:"md",asChild:!0,children:e.jsx(o,{className:"w-min self-center whitespace-nowrap",to:t.home,children:e.jsx("span",{className:"px-0.5",children:"Go to Home"})})})})]})})})}export{d as default};
1
+ import{j as e}from"./@radix-DnFH_oo1.js";import{f as s,r as t}from"./index-D0bJjaey.js";import{E as r}from"./EmptyState-Cs3DEmso.js";import{H as a}from"./help-CwN931fX.js";import{L as o}from"./@react-router-APVeuk-U.js";import"./@tanstack-QbMbTrh5.js";import"./@reactflow-CEC2f0cl.js";function d(){return e.jsx("div",{className:"flex min-h-screen w-full flex-col",children:e.jsx(r,{icon:e.jsx(a,{className:"h-[120px] w-[120px] fill-neutral-300"}),children:e.jsxs("div",{className:"text-center",children:[e.jsx("h1",{className:"mb-2 text-display-xs font-semibold",children:"We can't find the page you are looking for"}),e.jsx("p",{className:"text-lg text-theme-text-secondary",children:"You can try typing a different URL or we can bring you back to your Homepage."}),e.jsx("div",{className:"mt-5 flex justify-center",children:e.jsx(s,{size:"md",asChild:!0,children:e.jsx(o,{className:"w-min self-center whitespace-nowrap",to:t.home,children:e.jsx("span",{className:"px-0.5",children:"Go to Home"})})})})]})})})}export{d as default};