zenml-nightly 0.80.1.dev20250407__py3-none-any.whl → 0.80.1.dev20250409__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 (183) hide show
  1. zenml/VERSION +1 -1
  2. zenml/cli/base.py +1 -1
  3. zenml/cli/integration.py +36 -0
  4. zenml/client.py +6 -0
  5. zenml/config/step_configurations.py +3 -2
  6. zenml/constants.py +1 -1
  7. zenml/entrypoints/step_entrypoint_configuration.py +2 -0
  8. zenml/integrations/airflow/orchestrators/airflow_orchestrator.py +7 -2
  9. zenml/integrations/aws/orchestrators/sagemaker_orchestrator.py +2 -0
  10. zenml/integrations/azure/orchestrators/azureml_orchestrator.py +2 -0
  11. zenml/integrations/databricks/orchestrators/databricks_orchestrator.py +3 -1
  12. zenml/integrations/gcp/orchestrators/vertex_orchestrator.py +2 -0
  13. zenml/integrations/hyperai/orchestrators/hyperai_orchestrator.py +3 -1
  14. zenml/integrations/kubeflow/orchestrators/kubeflow_orchestrator.py +3 -1
  15. zenml/integrations/kubernetes/flavors/kubernetes_orchestrator_flavor.py +12 -0
  16. zenml/integrations/kubernetes/orchestrators/kube_utils.py +3 -0
  17. zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator.py +4 -1
  18. zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator_entrypoint.py +164 -19
  19. zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator_entrypoint_configuration.py +8 -1
  20. zenml/integrations/lightning/orchestrators/lightning_orchestrator.py +3 -1
  21. zenml/integrations/mlflow/__init__.py +0 -27
  22. zenml/integrations/mlflow/services/mlflow_deployment.py +25 -7
  23. zenml/integrations/pandas/materializers/pandas_materializer.py +41 -2
  24. zenml/integrations/seldon/services/seldon_deployment.py +1 -1
  25. zenml/integrations/skypilot/orchestrators/skypilot_base_vm_orchestrator.py +3 -1
  26. zenml/integrations/tekton/orchestrators/tekton_orchestrator.py +3 -1
  27. zenml/integrations/vllm/services/vllm_deployment.py +1 -1
  28. zenml/model/model.py +3 -1
  29. zenml/models/__init__.py +5 -0
  30. zenml/models/v2/core/run_template.py +32 -1
  31. zenml/orchestrators/base_orchestrator.py +3 -0
  32. zenml/orchestrators/dag_runner.py +48 -15
  33. zenml/orchestrators/local/local_orchestrator.py +3 -1
  34. zenml/orchestrators/local_docker/local_docker_orchestrator.py +3 -1
  35. zenml/steps/base_step.py +11 -8
  36. zenml/utils/secret_utils.py +2 -2
  37. zenml/zen_server/dashboard/assets/{404-2I8egBQu.js → 404-CYPi9d8E.js} +1 -1
  38. zenml/zen_server/dashboard/assets/@radix-C7hRs6Kx.js +95 -0
  39. zenml/zen_server/dashboard/assets/{@react-router-BUo5vhN4.js → @react-router-BGgzhn5D.js} +5 -5
  40. zenml/zen_server/dashboard/assets/@reactflow-CQi1Z1Wq.js +17 -0
  41. zenml/zen_server/dashboard/assets/@tanstack-CSxjHCME.js +22 -0
  42. zenml/zen_server/dashboard/assets/{AlertDialogDropdownItem-D7KZcPFw.js → AlertDialogDropdownItem-Dn8bgaXG.js} +1 -1
  43. zenml/zen_server/dashboard/assets/{CodeSnippet-DUkCnBpQ.js → CodeSnippet-CSINAl3I.js} +1 -1
  44. zenml/zen_server/dashboard/assets/{CollapsibleCard-B5-5Plnd.js → CollapsibleCard-CQOb53t9.js} +1 -1
  45. zenml/zen_server/dashboard/assets/{Commands-CbOMmarC.js → Commands-CPleXvse.js} +1 -1
  46. zenml/zen_server/dashboard/assets/{ComponentBadge-FrujKBC6.js → ComponentBadge-CIFj0W7T.js} +1 -1
  47. zenml/zen_server/dashboard/assets/{ComponentIcon-Dx5fBrDX.js → ComponentIcon-D3JHFhJU.js} +1 -1
  48. zenml/zen_server/dashboard/assets/{CsvVizualization-B8E3p9we.js → CsvVizualization-Cklc1Vb5.js} +6 -6
  49. zenml/zen_server/dashboard/assets/{DeleteAlertDialog-BgTZbbAt.js → DeleteAlertDialog-Bzq-uSd7.js} +1 -1
  50. zenml/zen_server/dashboard/assets/{DialogItem-CNWLiJcc.js → DialogItem-zjMgCmCl.js} +1 -1
  51. zenml/zen_server/dashboard/assets/{DisplayDate-C5Aw-Yca.js → DisplayDate-CYVBBSgr.js} +1 -1
  52. zenml/zen_server/dashboard/assets/{EmptyState-DpbfQBDE.js → EmptyState-M1jafpg6.js} +1 -1
  53. zenml/zen_server/dashboard/assets/{Error-BkUP4Luv.js → Error-kdeNHm_o.js} +1 -1
  54. zenml/zen_server/dashboard/assets/{ExecutionStatus-CD8Vj7sp.js → ExecutionStatus-UE6Rbmtk.js} +1 -1
  55. zenml/zen_server/dashboard/assets/{Helpbox-DIx6mDOH.js → Helpbox-CeM-FPQl.js} +1 -1
  56. zenml/zen_server/dashboard/assets/{Infobox-BHEdNmME.js → Infobox-CD0fDbYF.js} +1 -1
  57. zenml/zen_server/dashboard/assets/{InlineAvatar-Bin9UPKJ.js → InlineAvatar-CrHWwlf4.js} +1 -1
  58. zenml/zen_server/dashboard/assets/{Lock-tO9Z41I9.js → Lock-DW-0_M0o.js} +1 -1
  59. zenml/zen_server/dashboard/assets/{MarkdownVisualization-C3JLiPCY.js → MarkdownVisualization-URCyUPcZ.js} +2 -2
  60. zenml/zen_server/dashboard/assets/{NestedCollapsible-Da-k0Mff.js → NestedCollapsible-DfTTGG8u.js} +1 -1
  61. zenml/zen_server/dashboard/assets/{NumberBox-BvBJYxCu.js → NumberBox-D2A7ENHb.js} +1 -1
  62. zenml/zen_server/dashboard/assets/Partials-DggkUpWp.js +1 -0
  63. zenml/zen_server/dashboard/assets/{PasswordChecker-B4Uw6BJZ.js → PasswordChecker-lYTOtNom.js} +1 -1
  64. zenml/zen_server/dashboard/assets/ProBadge-BCdprj69.js +1 -0
  65. zenml/zen_server/dashboard/assets/{ProCta-7_FtpX3I.js → ProCta-szzPO0Y7.js} +1 -1
  66. zenml/zen_server/dashboard/assets/{ProviderIcon-CxeziA5a.js → ProviderIcon-MdqWDO6-.js} +1 -1
  67. zenml/zen_server/dashboard/assets/{ProviderRadio-DPmZHff_.js → ProviderRadio-B4CB4vzP.js} +1 -1
  68. zenml/zen_server/dashboard/assets/{RunSelector-BVKB4Z8F.js → RunSelector-Bhb83FyB.js} +1 -1
  69. zenml/zen_server/dashboard/assets/{RunsBody-Cj4sIqQB.js → RunsBody-Csn2VEOE.js} +1 -1
  70. zenml/zen_server/dashboard/assets/{SearchField-DjAOZic5.js → SearchField-Cce00eQL.js} +1 -1
  71. zenml/zen_server/dashboard/assets/{SecretTooltip-mMAAP4dM.js → SecretTooltip-DaDLBVj-.js} +1 -1
  72. zenml/zen_server/dashboard/assets/{SetPassword-B0o5kSJU.js → SetPassword-tX6fom1Y.js} +1 -1
  73. zenml/zen_server/dashboard/assets/{StackList-5UB8LoEq.js → StackList-CQt1xGRh.js} +1 -1
  74. zenml/zen_server/dashboard/assets/{Tabs-AuhCyzle.js → Tabs-CCQyIqRb.js} +1 -1
  75. zenml/zen_server/dashboard/assets/{Tick-CHW0jc8Y.js → Tick-D63_jhf1.js} +1 -1
  76. zenml/zen_server/dashboard/assets/{UpdatePasswordSchemas-Bauivjf-.js → UpdatePasswordSchemas-CbbvoGYV.js} +1 -1
  77. zenml/zen_server/dashboard/assets/{UsageReason-Dr5ca5M4.js → UsageReason-C2cNrUeS.js} +1 -1
  78. zenml/zen_server/dashboard/assets/{Wizard-XEp9rGmf.js → Wizard-BVkN2a2x.js} +1 -1
  79. zenml/zen_server/dashboard/assets/WizardFooter-Bk7gIKiS.js +1 -0
  80. zenml/zen_server/dashboard/assets/{all-pipeline-runs-query-COvsm3bC.js → all-pipeline-runs-query-BLclwQSi.js} +1 -1
  81. zenml/zen_server/dashboard/assets/{arrow-left-B2hyhFky.js → arrow-left-CwgF2MEM.js} +1 -1
  82. zenml/zen_server/dashboard/assets/{check-DZ0KAh3W.js → check-DK77doTf.js} +1 -1
  83. zenml/zen_server/dashboard/assets/{check-circle-DyCCYTA0.js → check-circle-mvyzYvIW.js} +1 -1
  84. zenml/zen_server/dashboard/assets/{chevron-down-A3PXOshS.js → chevron-down-A-rmltmI.js} +1 -1
  85. zenml/zen_server/dashboard/assets/{chevron-right-double-zKz7rAaU.js → chevron-right-double-uNWbJT-C.js} +1 -1
  86. zenml/zen_server/dashboard/assets/{clock-k5T5tYrt.js → clock-CPA5cYxq.js} +1 -1
  87. zenml/zen_server/dashboard/assets/{code-browser-DvB0W2Ix.js → code-browser-j2EpcxIA.js} +1 -1
  88. zenml/zen_server/dashboard/assets/{configuration-form-BJUCr0wl.js → configuration-form-CjrAp0GS.js} +1 -1
  89. zenml/zen_server/dashboard/assets/{create-stack-B2c98UlP.js → create-stack-Bd2JdQer.js} +1 -1
  90. zenml/zen_server/dashboard/assets/delete-run-Cwpxu1-d.js +1 -0
  91. zenml/zen_server/dashboard/assets/{docker-B3Sqzd8J.js → docker-BuDBFEDL.js} +1 -1
  92. zenml/zen_server/dashboard/assets/{file-text-CgxVzNph.js → file-text-BdxZdjP_.js} +1 -1
  93. zenml/zen_server/dashboard/assets/{flavor-select-D8CranSY.js → flavor-select-c0w-6o9w.js} +1 -1
  94. zenml/zen_server/dashboard/assets/{form-schemas-Bm-dTV3L.js → form-schemas-B5Ax1SZf.js} +1 -1
  95. zenml/zen_server/dashboard/assets/{gcp-0u4le6mC.js → gcp-CHNvgEss.js} +1 -1
  96. zenml/zen_server/dashboard/assets/{help-CfT0tY2I.js → help-DyMolRxD.js} +1 -1
  97. zenml/zen_server/dashboard/assets/index-BW-KaQ2p.js +1 -0
  98. zenml/zen_server/dashboard/assets/{index-DPjvk73v.js → index-Be2jLIYM.js} +8 -8
  99. zenml/zen_server/dashboard/assets/{index-D-n6tspq.js → index-CjdtNrfJ.js} +1 -1
  100. zenml/zen_server/dashboard/assets/{index-BVVKxTWC.js → index-DR30v9MZ.js} +1 -1
  101. zenml/zen_server/dashboard/assets/{index-CzhJC6pc.js → index-d_40qKeY.js} +1 -1
  102. zenml/zen_server/dashboard/assets/index.esm-D7jFlf5N.js +1 -0
  103. zenml/zen_server/dashboard/assets/{key-icon-CjwWwoOU.js → key-icon-DO4DPJHZ.js} +1 -1
  104. zenml/zen_server/dashboard/assets/{kubernetes-eA-Y6gE7.js → kubernetes-D6OUjwSK.js} +1 -1
  105. zenml/zen_server/dashboard/assets/{layout-3_rgDUxf.js → layout-h3cbx8WZ.js} +1 -1
  106. zenml/zen_server/dashboard/assets/{link-external-BYm_zH_8.js → link-external-DUhCSKNm.js} +1 -1
  107. zenml/zen_server/dashboard/assets/{login-mutation-D6uiKsKk.js → login-mutation-DOajKct8.js} +1 -1
  108. zenml/zen_server/dashboard/assets/{logs-D6_diV2k.js → logs-B5n0U7tB.js} +1 -1
  109. zenml/zen_server/dashboard/assets/{not-found-DFrksY0r.js → not-found-DolTp0dr.js} +1 -1
  110. zenml/zen_server/dashboard/assets/{package-BOms6B-A.js → package-D1Mhqeh8.js} +1 -1
  111. zenml/zen_server/dashboard/assets/{page-DBNBYSwq.js → page-48DMcIQw.js} +2 -2
  112. zenml/zen_server/dashboard/assets/{page-DOzFoJuo.js → page-B32kCGPe.js} +1 -1
  113. zenml/zen_server/dashboard/assets/page-BAjhc2bs.js +1 -0
  114. zenml/zen_server/dashboard/assets/{page-D5GZlpKq.js → page-BBNrvxC1.js} +1 -1
  115. zenml/zen_server/dashboard/assets/{page-DF9q7ySu.js → page-BEAx6ZvH.js} +1 -1
  116. zenml/zen_server/dashboard/assets/{page-DDvwWgKP.js → page-BRfeowe0.js} +1 -1
  117. zenml/zen_server/dashboard/assets/{page-BJ15SGwt.js → page-BbRtQC2E.js} +1 -1
  118. zenml/zen_server/dashboard/assets/{page-D2F0Rvak.js → page-BgUR_5z3.js} +1 -1
  119. zenml/zen_server/dashboard/assets/{page-D0Zt2-7X.js → page-BiAjLLww.js} +1 -1
  120. zenml/zen_server/dashboard/assets/{page-B80TE04v.js → page-BkPPfNfG.js} +1 -1
  121. zenml/zen_server/dashboard/assets/{page-DkJfgcDi.js → page-BmTf1Lf1.js} +2 -2
  122. zenml/zen_server/dashboard/assets/{page-CAKBSE9f.js → page-BuZC8z6N.js} +1 -1
  123. zenml/zen_server/dashboard/assets/{page-BwAFqFCf.js → page-C4zMMcaH.js} +1 -1
  124. zenml/zen_server/dashboard/assets/{page-BnUwQBeg.js → page-CKVbEdX2.js} +1 -1
  125. zenml/zen_server/dashboard/assets/{page-BXh1mF-D.js → page-CPRymOIS.js} +1 -1
  126. zenml/zen_server/dashboard/assets/{page-BMZaECzB.js → page-CaTJVICi.js} +1 -1
  127. zenml/zen_server/dashboard/assets/{page-NIWnUdVg.js → page-CmzmFF4S.js} +1 -1
  128. zenml/zen_server/dashboard/assets/{page-BIseZTJt.js → page-CwAbTnvK.js} +2 -2
  129. zenml/zen_server/dashboard/assets/{page-BeFiRx31.js → page-D-MjLTXS.js} +1 -1
  130. zenml/zen_server/dashboard/assets/{page-B1Un9vAU.js → page-D3m9-YWJ.js} +1 -1
  131. zenml/zen_server/dashboard/assets/{page-DhNnHHmX.js → page-DCpZju6a.js} +1 -1
  132. zenml/zen_server/dashboard/assets/page-DEUeF3mO.js +1 -0
  133. zenml/zen_server/dashboard/assets/{page-B150LbzG.js → page-DWOAh8Pp.js} +1 -1
  134. zenml/zen_server/dashboard/assets/{page-EhqRFAZc.js → page-DezabeEO.js} +1 -1
  135. zenml/zen_server/dashboard/assets/{page-BTvnIFGR.js → page-DivlNKt9.js} +1 -1
  136. zenml/zen_server/dashboard/assets/{page-BqQ6y8Hb.js → page-DmOcZO8U.js} +1 -1
  137. zenml/zen_server/dashboard/assets/page-DnY59jOg.js +1 -0
  138. zenml/zen_server/dashboard/assets/{page-DaHH2ZEF.js → page-Dv3qtvm8.js} +1 -1
  139. zenml/zen_server/dashboard/assets/page-P81CcE2L.js +1 -0
  140. zenml/zen_server/dashboard/assets/{page-Dd-0y3SU.js → page-a1c6o4vv.js} +1 -1
  141. zenml/zen_server/dashboard/assets/{page-BJrZsPSh.js → page-bS5tHLDW.js} +1 -1
  142. zenml/zen_server/dashboard/assets/{page-C11vPVkH.js → page-gRfUvR0E.js} +1 -1
  143. zenml/zen_server/dashboard/assets/{page-BZUxCBoD.js → page-hNHJPQtK.js} +1 -1
  144. zenml/zen_server/dashboard/assets/{page-kYlFrH53.js → page-ir7Scz2Y.js} +1 -1
  145. zenml/zen_server/dashboard/assets/{page-ygCPGHAV.js → page-mtwS5oci.js} +1 -1
  146. zenml/zen_server/dashboard/assets/{persist-DHGuHP2H.js → persist-BUqILw7G.js} +1 -1
  147. zenml/zen_server/dashboard/assets/{persist-C5RlwSq6.js → persist-BbdfLc0W.js} +1 -1
  148. zenml/zen_server/dashboard/assets/{plus-CoKtHiA9.js → plus-COjQg3AG.js} +1 -1
  149. zenml/zen_server/dashboard/assets/{react-error-boundary.esm-BkGIR1Du.js → react-error-boundary.esm-fyoUBS25.js} +1 -1
  150. zenml/zen_server/dashboard/assets/{refresh-CupyU1Vs.js → refresh-CM5T3QeU.js} +1 -1
  151. zenml/zen_server/dashboard/assets/{rocket-k68ONPDS.js → rocket-Cf-B-XOR.js} +1 -1
  152. zenml/zen_server/dashboard/assets/{service-Do7yitqe.js → service-CV2zjc-p.js} +1 -1
  153. zenml/zen_server/dashboard/assets/{sharedSchema-i_9Y4WcA.js → sharedSchema-DpGc9kQg.js} +1 -1
  154. zenml/zen_server/dashboard/assets/stack-detail-query-BpzLZjvw.js +1 -0
  155. zenml/zen_server/dashboard/assets/{terminal-square-URAPn9DB.js → terminal-square-DMtel8mb.js} +1 -1
  156. zenml/zen_server/dashboard/assets/{tick-circle-AaVBszPn.js → tick-circle-m94Aa6Zt.js} +1 -1
  157. zenml/zen_server/dashboard/assets/{trash-B_JgTgqd.js → trash-BWSZ7NRK.js} +1 -1
  158. zenml/zen_server/dashboard/assets/update-server-settings-mutation-Dv6qHtK9.js +1 -0
  159. zenml/zen_server/dashboard/assets/{zod-CRNUMWWg.js → zod-C0xYeTvL.js} +1 -1
  160. zenml/zen_server/dashboard/index.html +6 -6
  161. zenml/zen_server/template_execution/utils.py +53 -33
  162. zenml/zen_stores/migrations/versions/6611d4bcc95b_add_hidden_option_for_templates.py +47 -0
  163. zenml/zen_stores/schemas/run_template_schemas.py +7 -0
  164. {zenml_nightly-0.80.1.dev20250407.dist-info → zenml_nightly-0.80.1.dev20250409.dist-info}/METADATA +2 -2
  165. {zenml_nightly-0.80.1.dev20250407.dist-info → zenml_nightly-0.80.1.dev20250409.dist-info}/RECORD +168 -167
  166. zenml/zen_server/dashboard/assets/@radix-AvWw-1nd.js +0 -95
  167. zenml/zen_server/dashboard/assets/@reactflow-BHoFKFSZ.js +0 -17
  168. zenml/zen_server/dashboard/assets/@tanstack-CcI3lvwB.js +0 -22
  169. zenml/zen_server/dashboard/assets/Partials-TNaYjHsV.js +0 -1
  170. zenml/zen_server/dashboard/assets/ProBadge-BfPp-B97.js +0 -1
  171. zenml/zen_server/dashboard/assets/WizardFooter-BtL1Gi1k.js +0 -1
  172. zenml/zen_server/dashboard/assets/delete-run-Do3XyF4W.js +0 -1
  173. zenml/zen_server/dashboard/assets/index-eIIP-0dQ.js +0 -1
  174. zenml/zen_server/dashboard/assets/index.esm-cf-8NBxV.js +0 -1
  175. zenml/zen_server/dashboard/assets/page-B-uHUFcm.js +0 -1
  176. zenml/zen_server/dashboard/assets/page-B0Llmzo_.js +0 -1
  177. zenml/zen_server/dashboard/assets/page-BzlVs5tC.js +0 -1
  178. zenml/zen_server/dashboard/assets/page-CPe9nQSo.js +0 -1
  179. zenml/zen_server/dashboard/assets/stack-detail-query-omCumL7U.js +0 -1
  180. zenml/zen_server/dashboard/assets/update-server-settings-mutation-B4eE33z-.js +0 -1
  181. {zenml_nightly-0.80.1.dev20250407.dist-info → zenml_nightly-0.80.1.dev20250409.dist-info}/LICENSE +0 -0
  182. {zenml_nightly-0.80.1.dev20250407.dist-info → zenml_nightly-0.80.1.dev20250409.dist-info}/WHEEL +0 -0
  183. {zenml_nightly-0.80.1.dev20250407.dist-info → zenml_nightly-0.80.1.dev20250409.dist-info}/entry_points.txt +0 -0
zenml/VERSION CHANGED
@@ -1 +1 @@
1
- 0.80.1.dev20250407
1
+ 0.80.1.dev20250409
zenml/cli/base.py CHANGED
@@ -87,7 +87,7 @@ ZENML_PROJECT_TEMPLATES = dict(
87
87
  ),
88
88
  nlp=ZenMLProjectTemplateLocation(
89
89
  github_url="zenml-io/template-nlp",
90
- github_tag="2025.01.08", # Make sure it is aligned with .github/workflows/update-templates-to-examples.yml
90
+ github_tag="2025.04.07", # Make sure it is aligned with .github/workflows/update-templates-to-examples.yml
91
91
  ),
92
92
  llm_finetuning=ZenMLProjectTemplateLocation(
93
93
  github_url="zenml-io/template-llm-finetuning",
zenml/cli/integration.py CHANGED
@@ -13,6 +13,8 @@
13
13
  # permissions and limitations under the License.
14
14
  """Functionality to install or uninstall ZenML integrations via the CLI."""
15
15
 
16
+ import os
17
+ import subprocess
16
18
  import sys
17
19
  from typing import Optional, Tuple
18
20
 
@@ -131,12 +133,20 @@ def get_requirements(integration_name: Optional[str] = None) -> None:
131
133
  "environment. This can not be specified when also providing explicit "
132
134
  "integrations.",
133
135
  )
136
+ @click.option(
137
+ "--poetry",
138
+ "poetry",
139
+ is_flag=True,
140
+ default=False,
141
+ help="Add the exported requirements to your current Poetry project.",
142
+ )
134
143
  def export_requirements(
135
144
  integrations: Tuple[str],
136
145
  ignore_integration: Tuple[str],
137
146
  output_file: Optional[str] = None,
138
147
  overwrite: bool = False,
139
148
  installed_only: bool = False,
149
+ poetry: bool = False,
140
150
  ) -> None:
141
151
  """Exports integration requirements so they can be installed using pip.
142
152
 
@@ -150,6 +160,7 @@ def export_requirements(
150
160
  installed_only: Only export requirements for integrations installed in
151
161
  your current environment. This can not be specified when also
152
162
  providing explicit integrations.
163
+ poetry: Add the exported requirements to your current Poetry project.
153
164
  """
154
165
  from zenml.integrations.registry import integration_registry
155
166
 
@@ -160,6 +171,12 @@ def export_requirements(
160
171
  "environment, not both."
161
172
  )
162
173
 
174
+ if poetry and output_file:
175
+ error(
176
+ "You can either specify an output file or add the requirements to "
177
+ "the Poetry project, not both."
178
+ )
179
+
163
180
  all_integrations = set(integration_registry.integrations.keys())
164
181
 
165
182
  if integrations:
@@ -204,6 +221,25 @@ def export_requirements(
204
221
  with open(output_file, "w") as f:
205
222
  f.write("\n".join(requirements))
206
223
  declare(f"Requirements exported to {output_file}.")
224
+ if poetry:
225
+ res = os.popen("poetry env list").read()
226
+ envs = [
227
+ env
228
+ for env in res.split("\n")
229
+ if env.lower().find("(activated)") > 0
230
+ ]
231
+ if len(envs) == 0:
232
+ error(
233
+ "No activated Poetry environment found. Please activate one "
234
+ "and try again."
235
+ )
236
+ else:
237
+ # Use subprocess.run with shell=False to avoid command injection
238
+ args = ["poetry", "add"] + requirements
239
+ subprocess.run(args, check=True)
240
+ declare(
241
+ f"Requirements added to `{envs[0]}` environment in Poetry."
242
+ )
207
243
  else:
208
244
  click.echo(" ".join(requirements), nl=False)
209
245
 
zenml/client.py CHANGED
@@ -3574,6 +3574,7 @@ class Client(metaclass=ClientMetaClass):
3574
3574
  updated: Optional[Union[datetime, str]] = None,
3575
3575
  id: Optional[Union[UUID, str]] = None,
3576
3576
  name: Optional[str] = None,
3577
+ hidden: Optional[bool] = False,
3577
3578
  tag: Optional[str] = None,
3578
3579
  project: Optional[Union[str, UUID]] = None,
3579
3580
  pipeline_id: Optional[Union[str, UUID]] = None,
@@ -3596,6 +3597,7 @@ class Client(metaclass=ClientMetaClass):
3596
3597
  updated: Filter by the last updated date.
3597
3598
  id: Filter by run template ID.
3598
3599
  name: Filter by run template name.
3600
+ hidden: Filter by run template hidden status.
3599
3601
  tag: Filter by run template tags.
3600
3602
  project: Filter by project name/ID.
3601
3603
  pipeline_id: Filter by pipeline ID.
@@ -3620,6 +3622,7 @@ class Client(metaclass=ClientMetaClass):
3620
3622
  updated=updated,
3621
3623
  id=id,
3622
3624
  name=name,
3625
+ hidden=hidden,
3623
3626
  tag=tag,
3624
3627
  project=project,
3625
3628
  pipeline_id=pipeline_id,
@@ -3640,6 +3643,7 @@ class Client(metaclass=ClientMetaClass):
3640
3643
  name_id_or_prefix: Union[str, UUID],
3641
3644
  name: Optional[str] = None,
3642
3645
  description: Optional[str] = None,
3646
+ hidden: Optional[bool] = None,
3643
3647
  add_tags: Optional[List[str]] = None,
3644
3648
  remove_tags: Optional[List[str]] = None,
3645
3649
  project: Optional[Union[str, UUID]] = None,
@@ -3650,6 +3654,7 @@ class Client(metaclass=ClientMetaClass):
3650
3654
  name_id_or_prefix: Name/ID/ID prefix of the template to update.
3651
3655
  name: The new name of the run template.
3652
3656
  description: The new description of the run template.
3657
+ hidden: The new hidden status of the run template.
3653
3658
  add_tags: Tags to add to the run template.
3654
3659
  remove_tags: Tags to remove from the run template.
3655
3660
  project: The project name/ID to filter by.
@@ -3675,6 +3680,7 @@ class Client(metaclass=ClientMetaClass):
3675
3680
  template_update=RunTemplateUpdate(
3676
3681
  name=name,
3677
3682
  description=description,
3683
+ hidden=hidden,
3678
3684
  add_tags=add_tags,
3679
3685
  remove_tags=remove_tags,
3680
3686
  ),
@@ -118,8 +118,9 @@ class ArtifactConfiguration(PartialArtifactConfiguration):
118
118
  @field_validator("materializer_source", mode="before")
119
119
  @classmethod
120
120
  def _convert_source(
121
- cls, value: Union[Source, Dict[str, Any], str, Tuple[Source, ...]]
122
- ) -> Tuple[Source, ...]:
121
+ cls,
122
+ value: Union[None, Source, Dict[str, Any], str, Tuple[Source, ...]],
123
+ ) -> Optional[Tuple[Source, ...]]:
123
124
  """Converts old source strings to tuples of source objects.
124
125
 
125
126
  Args:
zenml/constants.py CHANGED
@@ -196,7 +196,7 @@ ENV_ZENML_RUN_SINGLE_STEPS_WITHOUT_STACK = (
196
196
  )
197
197
  ENV_ZENML_PREVENT_CLIENT_SIDE_CACHING = "ZENML_PREVENT_CLIENT_SIDE_CACHING"
198
198
  ENV_ZENML_DISABLE_CREDENTIALS_DISK_CACHING = "DISABLE_CREDENTIALS_DISK_CACHING"
199
-
199
+ ENV_ZENML_RUNNER_IMAGE_DISABLE_UV = "ZENML_RUNNER_IMAGE_DISABLE_UV"
200
200
  # Logging variables
201
201
  IS_DEBUG_ENV: bool = handle_bool_env_var(ENV_ZENML_DEBUG, default=False)
202
202
 
@@ -75,6 +75,8 @@ class StepEntrypointConfiguration(BaseEntrypointConfiguration):
75
75
  self,
76
76
  deployment: "PipelineDeployment",
77
77
  stack: "Stack",
78
+ environment: Dict[str, str],
79
+ placeholder_run: Optional["PipelineRunResponse"] = None,
78
80
  ) -> Any:
79
81
  ...
80
82
 
@@ -51,7 +51,11 @@ if TYPE_CHECKING:
51
51
  DagConfiguration,
52
52
  TaskConfiguration,
53
53
  )
54
- from zenml.models import PipelineDeploymentResponse, ScheduleResponse
54
+ from zenml.models import (
55
+ PipelineDeploymentResponse,
56
+ PipelineRunResponse,
57
+ ScheduleResponse,
58
+ )
55
59
  from zenml.stack import Stack
56
60
 
57
61
  logger = get_logger(__name__)
@@ -192,6 +196,7 @@ class AirflowOrchestrator(ContainerizedOrchestrator):
192
196
  deployment: "PipelineDeploymentResponse",
193
197
  stack: "Stack",
194
198
  environment: Dict[str, str],
199
+ placeholder_run: Optional["PipelineRunResponse"] = None,
195
200
  ) -> Any:
196
201
  """Creates and writes an Airflow DAG zip file.
197
202
 
@@ -200,7 +205,7 @@ class AirflowOrchestrator(ContainerizedOrchestrator):
200
205
  stack: The stack the pipeline will run on.
201
206
  environment: Environment variables to set in the orchestration
202
207
  environment.
203
-
208
+ placeholder_run: An optional placeholder run for the deployment.
204
209
  """
205
210
  pipeline_settings = cast(
206
211
  AirflowOrchestratorSettings, self.get_settings(deployment)
@@ -267,6 +267,7 @@ class SagemakerOrchestrator(ContainerizedOrchestrator):
267
267
  deployment: "PipelineDeploymentResponse",
268
268
  stack: "Stack",
269
269
  environment: Dict[str, str],
270
+ placeholder_run: Optional["PipelineRunResponse"] = None,
270
271
  ) -> Iterator[Dict[str, MetadataType]]:
271
272
  """Prepares or runs a pipeline on Sagemaker.
272
273
 
@@ -275,6 +276,7 @@ class SagemakerOrchestrator(ContainerizedOrchestrator):
275
276
  stack: The stack to run on.
276
277
  environment: Environment variables to set in the orchestration
277
278
  environment.
279
+ placeholder_run: An optional placeholder run for the deployment.
278
280
 
279
281
  Raises:
280
282
  RuntimeError: If there is an error creating or scheduling the
@@ -203,6 +203,7 @@ class AzureMLOrchestrator(ContainerizedOrchestrator):
203
203
  deployment: "PipelineDeploymentResponse",
204
204
  stack: "Stack",
205
205
  environment: Dict[str, str],
206
+ placeholder_run: Optional["PipelineRunResponse"] = None,
206
207
  ) -> Iterator[Dict[str, MetadataType]]:
207
208
  """Prepares or runs a pipeline on AzureML.
208
209
 
@@ -211,6 +212,7 @@ class AzureMLOrchestrator(ContainerizedOrchestrator):
211
212
  stack: The stack to run on.
212
213
  environment: Environment variables to set in the orchestration
213
214
  environment.
215
+ placeholder_run: An optional placeholder run for the deployment.
214
216
 
215
217
  Raises:
216
218
  RuntimeError: If the creation of the schedule fails.
@@ -58,7 +58,7 @@ from zenml.utils.pipeline_docker_image_builder import (
58
58
  )
59
59
 
60
60
  if TYPE_CHECKING:
61
- from zenml.models import PipelineDeploymentResponse
61
+ from zenml.models import PipelineDeploymentResponse, PipelineRunResponse
62
62
  from zenml.stack import Stack
63
63
 
64
64
 
@@ -201,6 +201,7 @@ class DatabricksOrchestrator(WheeledOrchestrator):
201
201
  deployment: "PipelineDeploymentResponse",
202
202
  stack: "Stack",
203
203
  environment: Dict[str, str],
204
+ placeholder_run: Optional["PipelineRunResponse"] = None,
204
205
  ) -> Any:
205
206
  """Creates a wheel and uploads the pipeline to Databricks.
206
207
 
@@ -225,6 +226,7 @@ class DatabricksOrchestrator(WheeledOrchestrator):
225
226
  stack: The stack the pipeline will run on.
226
227
  environment: Environment variables to set in the orchestration
227
228
  environment.
229
+ placeholder_run: An optional placeholder run for the deployment.
228
230
 
229
231
  Raises:
230
232
  ValueError: If the schedule is not set or if the cron expression
@@ -357,6 +357,7 @@ class VertexOrchestrator(ContainerizedOrchestrator, GoogleCredentialsMixin):
357
357
  deployment: "PipelineDeploymentResponse",
358
358
  stack: "Stack",
359
359
  environment: Dict[str, str],
360
+ placeholder_run: Optional["PipelineRunResponse"] = None,
360
361
  ) -> Iterator[Dict[str, MetadataType]]:
361
362
  """Creates a KFP JSON pipeline.
362
363
 
@@ -390,6 +391,7 @@ class VertexOrchestrator(ContainerizedOrchestrator, GoogleCredentialsMixin):
390
391
  stack: The stack the pipeline will run on.
391
392
  environment: Environment variables to set in the orchestration
392
393
  environment.
394
+ placeholder_run: An optional placeholder run for the deployment.
393
395
 
394
396
  Raises:
395
397
  ValueError: If the attribute `pipeline_root` is not set, and it
@@ -36,7 +36,7 @@ from zenml.orchestrators import (
36
36
  from zenml.stack import Stack, StackValidator
37
37
 
38
38
  if TYPE_CHECKING:
39
- from zenml.models import PipelineDeploymentResponse
39
+ from zenml.models import PipelineDeploymentResponse, PipelineRunResponse
40
40
 
41
41
  logger = get_logger(__name__)
42
42
 
@@ -164,6 +164,7 @@ class HyperAIOrchestrator(ContainerizedOrchestrator):
164
164
  deployment: "PipelineDeploymentResponse",
165
165
  stack: "Stack",
166
166
  environment: Dict[str, str],
167
+ placeholder_run: Optional["PipelineRunResponse"] = None,
167
168
  ) -> Any:
168
169
  """Sequentially runs all pipeline steps in Docker containers.
169
170
 
@@ -182,6 +183,7 @@ class HyperAIOrchestrator(ContainerizedOrchestrator):
182
183
  stack: The stack the pipeline will run on.
183
184
  environment: Environment variables to set in the orchestration
184
185
  environment.
186
+ placeholder_run: An optional placeholder run for the deployment.
185
187
 
186
188
  Raises:
187
189
  RuntimeError: If a step fails.
@@ -75,7 +75,7 @@ from zenml.stack import StackValidator
75
75
  from zenml.utils import io_utils, settings_utils, yaml_utils
76
76
 
77
77
  if TYPE_CHECKING:
78
- from zenml.models import PipelineDeploymentResponse
78
+ from zenml.models import PipelineDeploymentResponse, PipelineRunResponse
79
79
  from zenml.stack import Stack
80
80
 
81
81
 
@@ -471,6 +471,7 @@ class KubeflowOrchestrator(ContainerizedOrchestrator):
471
471
  deployment: "PipelineDeploymentResponse",
472
472
  stack: "Stack",
473
473
  environment: Dict[str, str],
474
+ placeholder_run: Optional["PipelineRunResponse"] = None,
474
475
  ) -> Any:
475
476
  """Creates a kfp yaml file.
476
477
 
@@ -501,6 +502,7 @@ class KubeflowOrchestrator(ContainerizedOrchestrator):
501
502
  stack: The stack the pipeline will run on.
502
503
  environment: Environment variables to set in the orchestration
503
504
  environment.
505
+ placeholder_run: An optional placeholder run for the deployment.
504
506
 
505
507
  Raises:
506
508
  RuntimeError: If trying to run a pipeline in a notebook
@@ -47,6 +47,14 @@ class KubernetesOrchestratorSettings(BaseSettings):
47
47
  pod_settings: Pod settings to apply to pods executing the steps.
48
48
  orchestrator_pod_settings: Pod settings to apply to the pod which is
49
49
  launching the actual steps.
50
+ pod_startup_timeout: The maximum time to wait for a pending step pod to
51
+ start (in seconds).
52
+ pod_failure_max_retries: The maximum number of times to retry a step
53
+ pod if the step Kubernetes pod fails to start
54
+ pod_failure_retry_delay: The delay in seconds between pod
55
+ failure retries and pod startup retries (in seconds)
56
+ pod_failure_backoff: The backoff factor for pod failure retries and
57
+ pod startup retries.
50
58
  """
51
59
 
52
60
  synchronous: bool = True
@@ -56,6 +64,10 @@ class KubernetesOrchestratorSettings(BaseSettings):
56
64
  privileged: bool = False
57
65
  pod_settings: Optional[KubernetesPodSettings] = None
58
66
  orchestrator_pod_settings: Optional[KubernetesPodSettings] = None
67
+ pod_startup_timeout: int = 60 * 10 # Default 10 minutes
68
+ pod_failure_max_retries: int = 3
69
+ pod_failure_retry_delay: int = 10
70
+ pod_failure_backoff: float = 1.0
59
71
 
60
72
 
61
73
  class KubernetesOrchestratorConfig(
@@ -264,6 +264,9 @@ def wait_pod(
264
264
 
265
265
  resp = get_pod(core_api, pod_name, namespace)
266
266
 
267
+ if resp is None:
268
+ raise RuntimeError(f"Pod `{namespace}:{pod_name}` not found.")
269
+
267
270
  # Stream logs to `zenml.logger.info()`.
268
271
  # TODO: can we do this without parsing all logs every time?
269
272
  if stream_logs and pod_is_not_pending(resp):
@@ -67,7 +67,7 @@ from zenml.orchestrators.utils import get_orchestrator_run_name
67
67
  from zenml.stack import StackValidator
68
68
 
69
69
  if TYPE_CHECKING:
70
- from zenml.models import PipelineDeploymentResponse
70
+ from zenml.models import PipelineDeploymentResponse, PipelineRunResponse
71
71
  from zenml.stack import Stack
72
72
 
73
73
  logger = get_logger(__name__)
@@ -393,6 +393,7 @@ class KubernetesOrchestrator(ContainerizedOrchestrator):
393
393
  deployment: "PipelineDeploymentResponse",
394
394
  stack: "Stack",
395
395
  environment: Dict[str, str],
396
+ placeholder_run: Optional["PipelineRunResponse"] = None,
396
397
  ) -> Any:
397
398
  """Runs the pipeline in Kubernetes.
398
399
 
@@ -401,6 +402,7 @@ class KubernetesOrchestrator(ContainerizedOrchestrator):
401
402
  stack: The stack the pipeline will run on.
402
403
  environment: Environment variables to set in the orchestration
403
404
  environment.
405
+ placeholder_run: An optional placeholder run for the deployment.
404
406
 
405
407
  Raises:
406
408
  RuntimeError: If the Kubernetes orchestrator is not configured.
@@ -450,6 +452,7 @@ class KubernetesOrchestrator(ContainerizedOrchestrator):
450
452
  run_name=orchestrator_run_name,
451
453
  deployment_id=deployment.id,
452
454
  kubernetes_namespace=self.config.kubernetes_namespace,
455
+ run_id=placeholder_run.id if placeholder_run else None,
453
456
  )
454
457
 
455
458
  settings = cast(
@@ -15,6 +15,9 @@
15
15
 
16
16
  import argparse
17
17
  import socket
18
+ import time
19
+ from typing import Any, Dict
20
+ from uuid import UUID
18
21
 
19
22
  from kubernetes import client as k8s_client
20
23
 
@@ -22,6 +25,8 @@ from zenml.client import Client
22
25
  from zenml.entrypoints.step_entrypoint_configuration import (
23
26
  StepEntrypointConfiguration,
24
27
  )
28
+ from zenml.enums import ExecutionStatus
29
+ from zenml.exceptions import AuthorizationException
25
30
  from zenml.integrations.kubernetes.flavors.kubernetes_orchestrator_flavor import (
26
31
  KubernetesOrchestratorSettings,
27
32
  )
@@ -35,7 +40,8 @@ from zenml.integrations.kubernetes.orchestrators.manifest_utils import (
35
40
  build_pod_manifest,
36
41
  )
37
42
  from zenml.logger import get_logger
38
- from zenml.orchestrators.dag_runner import ThreadedDagRunner
43
+ from zenml.orchestrators import publish_utils
44
+ from zenml.orchestrators.dag_runner import NodeStatus, ThreadedDagRunner
39
45
  from zenml.orchestrators.utils import get_config_environment_vars
40
46
 
41
47
  logger = get_logger(__name__)
@@ -51,6 +57,7 @@ def parse_args() -> argparse.Namespace:
51
57
  parser.add_argument("--run_name", type=str, required=True)
52
58
  parser.add_argument("--deployment_id", type=str, required=True)
53
59
  parser.add_argument("--kubernetes_namespace", type=str, required=True)
60
+ parser.add_argument("--run_id", type=str, required=False)
54
61
  return parser.parse_args()
55
62
 
56
63
 
@@ -64,7 +71,9 @@ def main() -> None:
64
71
 
65
72
  orchestrator_run_id = socket.gethostname()
66
73
 
67
- deployment_config = Client().get_deployment(args.deployment_id)
74
+ client = Client()
75
+
76
+ deployment_config = client.get_deployment(args.deployment_id)
68
77
 
69
78
  pipeline_dag = {
70
79
  step_name: step.spec.upstream_steps
@@ -72,7 +81,7 @@ def main() -> None:
72
81
  }
73
82
  step_command = StepEntrypointConfiguration.get_entrypoint_command()
74
83
 
75
- active_stack = Client().active_stack
84
+ active_stack = client.active_stack
76
85
  mount_local_stores = active_stack.orchestrator.config.is_local
77
86
 
78
87
  # Get a Kubernetes client from the active Kubernetes orchestrator, but
@@ -91,6 +100,11 @@ def main() -> None:
91
100
 
92
101
  Args:
93
102
  step_name: Name of the step.
103
+
104
+ Raises:
105
+ Exception: If the pod fails to start.
106
+ TimeoutError: If the pod is still in a pending state after the
107
+ maximum wait time has elapsed.
94
108
  """
95
109
  # Define Kubernetes pod name.
96
110
  pod_name = f"{orchestrator_run_id}-{step_name}"
@@ -162,24 +176,154 @@ def main() -> None:
162
176
  mount_local_stores=mount_local_stores,
163
177
  )
164
178
 
165
- # Create and run pod.
166
- core_api.create_namespaced_pod(
167
- namespace=args.kubernetes_namespace,
168
- body=pod_manifest,
169
- )
179
+ retries = 0
180
+ max_retries = settings.pod_failure_max_retries
181
+ delay: float = settings.pod_failure_retry_delay
182
+ backoff = settings.pod_failure_backoff
183
+
184
+ while retries < max_retries:
185
+ try:
186
+ # Create and run pod.
187
+ core_api.create_namespaced_pod(
188
+ namespace=args.kubernetes_namespace,
189
+ body=pod_manifest,
190
+ )
191
+ break
192
+ except Exception as e:
193
+ retries += 1
194
+ if retries < max_retries:
195
+ logger.debug(
196
+ f"Pod for step `{step_name}` failed to start: {e}"
197
+ )
198
+ logger.error(
199
+ f"Failed to create pod for step `{step_name}`. "
200
+ f"Retrying in {delay} seconds..."
201
+ )
202
+ time.sleep(delay)
203
+ delay *= backoff
204
+ else:
205
+ logger.error(
206
+ f"Failed to create pod for step `{step_name}` after "
207
+ f"{max_retries} retries. Exiting."
208
+ )
209
+ raise
210
+
211
+ # Wait for pod to start
212
+ max_wait = settings.pod_startup_timeout
213
+ total_wait: float = 0
214
+ delay = settings.pod_failure_retry_delay
215
+ while True:
216
+ pod = kube_utils.get_pod(
217
+ core_api, pod_name, args.kubernetes_namespace
218
+ )
219
+ if not pod or kube_utils.pod_is_not_pending(pod):
220
+ break
221
+ if total_wait >= max_wait:
222
+ # Have to delete the pending pod so it doesn't start running
223
+ # later on.
224
+ try:
225
+ core_api.delete_namespaced_pod(
226
+ name=pod_name,
227
+ namespace=args.kubernetes_namespace,
228
+ )
229
+ except Exception:
230
+ pass
231
+ raise TimeoutError(
232
+ f"Pod for step `{step_name}` is still in a pending state "
233
+ f"after {total_wait} seconds. Exiting."
234
+ )
235
+
236
+ if total_wait + delay > max_wait:
237
+ delay = max_wait - total_wait
238
+ total_wait += delay
239
+ time.sleep(delay)
240
+ delay *= backoff
170
241
 
171
242
  # Wait for pod to finish.
172
- logger.info(f"Waiting for pod of step `{step_name}` to start...")
173
- kube_utils.wait_pod(
174
- kube_client_fn=lambda: orchestrator.get_kube_client(
175
- incluster=True
176
- ),
177
- pod_name=pod_name,
178
- namespace=args.kubernetes_namespace,
179
- exit_condition_lambda=kube_utils.pod_is_done,
180
- stream_logs=True,
181
- )
182
- logger.info(f"Pod of step `{step_name}` completed.")
243
+ logger.info(f"Waiting for pod of step `{step_name}` to finish...")
244
+ try:
245
+ kube_utils.wait_pod(
246
+ kube_client_fn=lambda: orchestrator.get_kube_client(
247
+ incluster=True
248
+ ),
249
+ pod_name=pod_name,
250
+ namespace=args.kubernetes_namespace,
251
+ exit_condition_lambda=kube_utils.pod_is_done,
252
+ stream_logs=True,
253
+ )
254
+
255
+ logger.info(f"Pod for step `{step_name}` completed.")
256
+ except Exception:
257
+ logger.error(f"Pod for step `{step_name}` failed.")
258
+
259
+ raise
260
+
261
+ def finalize_run(node_states: Dict[str, NodeStatus]) -> None:
262
+ """Finalize the run.
263
+
264
+ Args:
265
+ node_states: The states of the nodes.
266
+ """
267
+ try:
268
+ # Some steps may have failed because the pods could not be created.
269
+ # We need to check for this and mark the step run as failed if so.
270
+
271
+ # Fetch the pipeline run using any means possible.
272
+ list_args: Dict[str, Any] = {}
273
+ if args.run_id:
274
+ # For a run triggered outside of a schedule, we can use the
275
+ # placeholder run ID to find the pipeline run.
276
+ list_args = dict(id=UUID(args.run_id))
277
+ else:
278
+ # For a run triggered by a schedule, we can only use the
279
+ # orchestrator run ID to find the pipeline run.
280
+ list_args = dict(orchestrator_run_id=orchestrator_run_id)
281
+
282
+ pipeline_runs = client.list_pipeline_runs(
283
+ hydrate=True,
284
+ project=deployment_config.project.id,
285
+ deployment_id=deployment_config.id,
286
+ **list_args,
287
+ )
288
+ if not len(pipeline_runs):
289
+ # No pipeline run found, so we can't mark any step runs as failed.
290
+ return
291
+
292
+ pipeline_run = pipeline_runs[0]
293
+ pipeline_failed = False
294
+
295
+ for step_name, node_state in node_states.items():
296
+ if node_state != NodeStatus.FAILED:
297
+ continue
298
+
299
+ pipeline_failed = True
300
+
301
+ # If steps failed for any reason, we need to mark the step run as
302
+ # failed, if it exists and it wasn't already in a final state.
303
+
304
+ step_run = pipeline_run.steps.get(step_name)
305
+
306
+ # Try to update the step run status, if it exists and is in
307
+ # a transient state.
308
+ if step_run and step_run.status in {
309
+ ExecutionStatus.INITIALIZING,
310
+ ExecutionStatus.RUNNING,
311
+ }:
312
+ publish_utils.publish_failed_step_run(step_run.id)
313
+
314
+ # If any steps failed and the pipeline run is still in a transient
315
+ # state, we need to mark it as failed.
316
+ if pipeline_failed and pipeline_run.status in {
317
+ ExecutionStatus.INITIALIZING,
318
+ ExecutionStatus.RUNNING,
319
+ }:
320
+ publish_utils.publish_failed_pipeline_run(pipeline_run.id)
321
+ except AuthorizationException:
322
+ # If a step of the pipeline failed or all of them completed
323
+ # successfully, the pipeline run will be finished and the API token
324
+ # will be invalidated. We catch this exception and do nothing here,
325
+ # as the pipeline run status will already have been published.
326
+ pass
183
327
 
184
328
  parallel_node_startup_waiting_period = (
185
329
  orchestrator.config.parallel_step_startup_waiting_period or 0.0
@@ -188,6 +332,7 @@ def main() -> None:
188
332
  ThreadedDagRunner(
189
333
  dag=pipeline_dag,
190
334
  run_fn=run_step_on_kubernetes,
335
+ finalize_fn=finalize_run,
191
336
  parallel_node_startup_waiting_period=parallel_node_startup_waiting_period,
192
337
  ).run()
193
338
  logger.info("Orchestration pod completed.")