zenml-nightly 0.70.0.dev20241125__py3-none-any.whl → 0.71.0.dev20241220__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (254) hide show
  1. README.md +4 -4
  2. RELEASE_NOTES.md +112 -0
  3. zenml/VERSION +1 -1
  4. zenml/artifact_stores/base_artifact_store.py +2 -2
  5. zenml/artifacts/artifact_config.py +15 -6
  6. zenml/artifacts/utils.py +59 -32
  7. zenml/cli/__init__.py +22 -4
  8. zenml/cli/base.py +5 -5
  9. zenml/cli/login.py +26 -0
  10. zenml/cli/pipeline.py +111 -62
  11. zenml/cli/server.py +20 -20
  12. zenml/cli/service_connectors.py +3 -3
  13. zenml/cli/stack.py +0 -3
  14. zenml/cli/stack_components.py +0 -1
  15. zenml/cli/utils.py +0 -5
  16. zenml/client.py +62 -20
  17. zenml/config/compiler.py +12 -3
  18. zenml/config/pipeline_configurations.py +20 -0
  19. zenml/config/pipeline_run_configuration.py +1 -0
  20. zenml/config/secret_reference_mixin.py +1 -1
  21. zenml/config/server_config.py +4 -0
  22. zenml/config/step_configurations.py +21 -0
  23. zenml/constants.py +10 -0
  24. zenml/enums.py +1 -0
  25. zenml/image_builders/base_image_builder.py +5 -2
  26. zenml/image_builders/build_context.py +7 -16
  27. zenml/image_builders/local_image_builder.py +13 -3
  28. zenml/integrations/__init__.py +1 -0
  29. zenml/integrations/aws/__init__.py +3 -0
  30. zenml/integrations/aws/flavors/__init__.py +6 -0
  31. zenml/integrations/aws/flavors/aws_image_builder_flavor.py +146 -0
  32. zenml/integrations/aws/image_builders/__init__.py +20 -0
  33. zenml/integrations/aws/image_builders/aws_image_builder.py +307 -0
  34. zenml/integrations/aws/orchestrators/sagemaker_orchestrator.py +14 -6
  35. zenml/integrations/constants.py +1 -0
  36. zenml/integrations/feast/__init__.py +1 -1
  37. zenml/integrations/feast/feature_stores/feast_feature_store.py +13 -9
  38. zenml/integrations/gcp/orchestrators/vertex_orchestrator.py +1 -1
  39. zenml/integrations/kaniko/image_builders/kaniko_image_builder.py +2 -1
  40. zenml/integrations/kubernetes/flavors/kubernetes_orchestrator_flavor.py +11 -0
  41. zenml/integrations/kubernetes/orchestrators/kube_utils.py +46 -2
  42. zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator.py +13 -2
  43. zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator_entrypoint.py +3 -1
  44. zenml/integrations/kubernetes/orchestrators/manifest_utils.py +3 -2
  45. zenml/integrations/kubernetes/step_operators/kubernetes_step_operator.py +3 -2
  46. zenml/integrations/lightning/flavors/lightning_orchestrator_flavor.py +11 -0
  47. zenml/integrations/modal/__init__.py +46 -0
  48. zenml/integrations/modal/flavors/__init__.py +26 -0
  49. zenml/integrations/modal/flavors/modal_step_operator_flavor.py +125 -0
  50. zenml/integrations/modal/step_operators/__init__.py +22 -0
  51. zenml/integrations/modal/step_operators/modal_step_operator.py +242 -0
  52. zenml/integrations/neptune/experiment_trackers/neptune_experiment_tracker.py +7 -5
  53. zenml/integrations/neptune/experiment_trackers/run_state.py +69 -53
  54. zenml/integrations/registry.py +2 -2
  55. zenml/integrations/skypilot/flavors/skypilot_orchestrator_base_vm_config.py +12 -0
  56. zenml/integrations/wandb/flavors/wandb_experiment_tracker_flavor.py +13 -5
  57. zenml/io/filesystem.py +2 -2
  58. zenml/io/local_filesystem.py +3 -3
  59. zenml/materializers/built_in_materializer.py +18 -1
  60. zenml/materializers/structured_string_materializer.py +8 -3
  61. zenml/model/model.py +23 -101
  62. zenml/model/utils.py +21 -17
  63. zenml/models/__init__.py +6 -0
  64. zenml/models/v2/base/filter.py +26 -30
  65. zenml/models/v2/base/scoped.py +258 -5
  66. zenml/models/v2/core/artifact_version.py +21 -29
  67. zenml/models/v2/core/code_repository.py +1 -12
  68. zenml/models/v2/core/component.py +5 -68
  69. zenml/models/v2/core/flavor.py +1 -11
  70. zenml/models/v2/core/model.py +1 -57
  71. zenml/models/v2/core/model_version.py +11 -36
  72. zenml/models/v2/core/model_version_artifact.py +11 -3
  73. zenml/models/v2/core/model_version_pipeline_run.py +14 -3
  74. zenml/models/v2/core/pipeline.py +47 -55
  75. zenml/models/v2/core/pipeline_build.py +67 -12
  76. zenml/models/v2/core/pipeline_deployment.py +0 -10
  77. zenml/models/v2/core/pipeline_run.py +110 -32
  78. zenml/models/v2/core/run_metadata.py +30 -9
  79. zenml/models/v2/core/run_template.py +21 -29
  80. zenml/models/v2/core/schedule.py +0 -10
  81. zenml/models/v2/core/secret.py +0 -14
  82. zenml/models/v2/core/service.py +9 -16
  83. zenml/models/v2/core/service_connector.py +0 -11
  84. zenml/models/v2/core/stack.py +21 -30
  85. zenml/models/v2/core/step_run.py +24 -18
  86. zenml/models/v2/core/trigger.py +19 -3
  87. zenml/models/v2/misc/run_metadata.py +38 -0
  88. zenml/orchestrators/base_orchestrator.py +13 -1
  89. zenml/orchestrators/input_utils.py +19 -6
  90. zenml/orchestrators/output_utils.py +5 -1
  91. zenml/orchestrators/publish_utils.py +12 -5
  92. zenml/orchestrators/step_launcher.py +16 -16
  93. zenml/orchestrators/step_run_utils.py +18 -197
  94. zenml/orchestrators/step_runner.py +40 -3
  95. zenml/orchestrators/utils.py +79 -50
  96. zenml/pipelines/build_utils.py +12 -0
  97. zenml/pipelines/pipeline_decorator.py +4 -0
  98. zenml/pipelines/pipeline_definition.py +26 -8
  99. zenml/pipelines/run_utils.py +9 -5
  100. zenml/service_connectors/service_connector_utils.py +3 -9
  101. zenml/stack/stack_component.py +1 -1
  102. zenml/stack_deployments/aws_stack_deployment.py +22 -0
  103. zenml/steps/base_step.py +11 -1
  104. zenml/steps/entrypoint_function_utils.py +7 -3
  105. zenml/steps/step_decorator.py +4 -0
  106. zenml/steps/utils.py +23 -7
  107. zenml/types.py +4 -0
  108. zenml/utils/archivable.py +65 -36
  109. zenml/utils/code_utils.py +8 -4
  110. zenml/utils/docker_utils.py +9 -0
  111. zenml/utils/metadata_utils.py +186 -153
  112. zenml/utils/string_utils.py +41 -16
  113. zenml/utils/visualization_utils.py +4 -1
  114. zenml/zen_server/auth.py +9 -10
  115. zenml/zen_server/cloud_utils.py +3 -1
  116. zenml/zen_server/dashboard/assets/{404-NVXKFp-x.js → 404-Cqu3EDCm.js} +1 -1
  117. zenml/zen_server/dashboard/assets/{@reactflow-CK0KJUen.js → @reactflow-D2Y7BWwz.js} +1 -1
  118. zenml/zen_server/dashboard/assets/{AlertDialogDropdownItem-DezXKmDf.js → AlertDialogDropdownItem-BHd71pVS.js} +1 -1
  119. zenml/zen_server/dashboard/assets/{CodeSnippet-JzR8CEtw.js → CodeSnippet-DIonwetW.js} +1 -1
  120. zenml/zen_server/dashboard/assets/{CollapsibleCard-DQW_ktMO.js → CollapsibleCard-CDnC97pB.js} +1 -1
  121. zenml/zen_server/dashboard/assets/{Commands-DL2kwkRd.js → Commands-BVEXKAOj.js} +1 -1
  122. zenml/zen_server/dashboard/assets/{ComponentBadge-D_g62Wv8.js → ComponentBadge-CrRvovox.js} +1 -1
  123. zenml/zen_server/dashboard/assets/{CopyButton-LNcWaa14.js → CopyButton-B6wGAhQv.js} +1 -1
  124. zenml/zen_server/dashboard/assets/{CsvVizualization-DknpE5ej.js → CsvVizualization-CjcT7LMm.js} +5 -5
  125. zenml/zen_server/dashboard/assets/DeleteAlertDialog-D2ELtM2W.js +1 -0
  126. zenml/zen_server/dashboard/assets/{DialogItem-Bxf8FuAT.js → DialogItem-DXIMhBgU.js} +1 -1
  127. zenml/zen_server/dashboard/assets/{Error-DYflYyps.js → Error-B8uUfTpL.js} +1 -1
  128. zenml/zen_server/dashboard/assets/{ExecutionStatus-C7zyIQKZ.js → ExecutionStatus-ibAdY-dG.js} +1 -1
  129. zenml/zen_server/dashboard/assets/{Helpbox-oYSGpLqd.js → Helpbox-BfAfhKHw.js} +1 -1
  130. zenml/zen_server/dashboard/assets/{Infobox-Cx4xGoXR.js → Infobox-M_SMOu96.js} +1 -1
  131. zenml/zen_server/dashboard/assets/{InlineAvatar-DiGOWNKF.js → InlineAvatar-DBA0a0-a.js} +1 -1
  132. zenml/zen_server/dashboard/assets/{NestedCollapsible-DYbgyKxK.js → NestedCollapsible-DpgmEFKw.js} +1 -1
  133. zenml/zen_server/dashboard/assets/{Partials-03iZf8-N.js → Partials-D_ldD9if.js} +1 -1
  134. zenml/zen_server/dashboard/assets/{ProBadge-D_EB8HNo.js → ProBadge-DQbfFotM.js} +1 -1
  135. zenml/zen_server/dashboard/assets/{ProCta-DqNS4v3x.js → ProCta-Bcpb4rcY.js} +1 -1
  136. zenml/zen_server/dashboard/assets/{ProviderIcon-Bki2aw8w.js → ProviderIcon-BZpgPigN.js} +1 -1
  137. zenml/zen_server/dashboard/assets/{ProviderRadio-8f43sPD4.js → ProviderRadio-DWPnMuQ1.js} +1 -1
  138. zenml/zen_server/dashboard/assets/RunSelector-DgRGaAc6.js +1 -0
  139. zenml/zen_server/dashboard/assets/{RunsBody-07YEO7qI.js → RunsBody-KecfSkjY.js} +1 -1
  140. zenml/zen_server/dashboard/assets/{SearchField-lp1KgU4e.js → SearchField-n-ILHnaP.js} +1 -1
  141. zenml/zen_server/dashboard/assets/{SecretTooltip-CgnbyeOx.js → SecretTooltip-B8MrX5yu.js} +1 -1
  142. zenml/zen_server/dashboard/assets/{SetPassword-CpP418A2.js → SetPassword-B_IVq_wg.js} +1 -1
  143. zenml/zen_server/dashboard/assets/StackList-TWPBYnkF.js +1 -0
  144. zenml/zen_server/dashboard/assets/{Tabs-BktHkCJJ.js → Tabs-Rg857zmd.js} +1 -1
  145. zenml/zen_server/dashboard/assets/{Tick-BlMoIlJT.js → Tick-COg4A-xo.js} +1 -1
  146. zenml/zen_server/dashboard/assets/{UpdatePasswordSchemas-Sc0A0pP-.js → UpdatePasswordSchemas-C6Aj3hm6.js} +1 -1
  147. zenml/zen_server/dashboard/assets/{UsageReason-YYduL4fj.js → UsageReason-BTLbx7w4.js} +1 -1
  148. zenml/zen_server/dashboard/assets/{WizardFooter-dgmizSJC.js → WizardFooter-BCAj69Vj.js} +1 -1
  149. zenml/zen_server/dashboard/assets/{all-pipeline-runs-query-D-c2G6lV.js → all-pipeline-runs-query-DMXkDrV2.js} +1 -1
  150. zenml/zen_server/dashboard/assets/code-snippets-CqONne41.js +13 -0
  151. zenml/zen_server/dashboard/assets/{create-stack-DM_JPgef.js → create-stack-HfdbhLs4.js} +1 -1
  152. zenml/zen_server/dashboard/assets/dates-3pMLCNrD.js +1 -0
  153. zenml/zen_server/dashboard/assets/delete-run-DZ4hIXff.js +1 -0
  154. zenml/zen_server/dashboard/assets/{form-schemas-K6FYKjwa.js → form-schemas-B0AVEd9b.js} +1 -1
  155. zenml/zen_server/dashboard/assets/{index-BAkC7FXi.js → index-DPqSWjug.js} +1 -1
  156. zenml/zen_server/dashboard/assets/{index-CEV4Cvaf.js → index-DScjfBRb.js} +1 -1
  157. zenml/zen_server/dashboard/assets/index-DXvT1_Um.css +1 -0
  158. zenml/zen_server/dashboard/assets/{index-CCOPpudF.js → index-FO-p0GU7.js} +5 -5
  159. zenml/zen_server/dashboard/assets/{index-B1mVPYxf.js → index-I3bKUGUj.js} +1 -1
  160. zenml/zen_server/dashboard/assets/key-icon-aH-QIa5R.js +1 -0
  161. zenml/zen_server/dashboard/assets/login-command-CkqxPtV3.js +1 -0
  162. zenml/zen_server/dashboard/assets/{login-mutation-hf-lK87O.js → login-mutation-BQeo4wTY.js} +1 -1
  163. zenml/zen_server/dashboard/assets/{not-found-BGirLjU-.js → not-found-gAJ5aDdR.js} +1 -1
  164. zenml/zen_server/dashboard/assets/page-9Y9-gig0.js +1 -0
  165. zenml/zen_server/dashboard/assets/{page-DjRJCGb3.js → page-AUwiQ14W.js} +1 -1
  166. zenml/zen_server/dashboard/assets/page-B6XU7yYT.js +2 -0
  167. zenml/zen_server/dashboard/assets/{page-C00YAkaB.js → page-BKZYc2Zv.js} +1 -1
  168. zenml/zen_server/dashboard/assets/{page-CdMWnQak.js → page-BU9FG4sR.js} +1 -1
  169. zenml/zen_server/dashboard/assets/{page-D7S3aCbF.js → page-B_Apk3xg.js} +1 -1
  170. zenml/zen_server/dashboard/assets/{page-Djikxq_S.js → page-BdowiCbr.js} +1 -1
  171. zenml/zen_server/dashboard/assets/page-Bg8OjTRe.js +1 -0
  172. zenml/zen_server/dashboard/assets/page-BxL4qD4_.js +1 -0
  173. zenml/zen_server/dashboard/assets/{page-DakHVWXF.js → page-CWxT5K5J.js} +1 -1
  174. zenml/zen_server/dashboard/assets/page-CXuQufSe.js +1 -0
  175. zenml/zen_server/dashboard/assets/{page-DLC-bNBP.js → page-CcQr8CPP.js} +1 -1
  176. zenml/zen_server/dashboard/assets/{page-CD-DcWoy.js → page-Ce4Hrjnr.js} +1 -1
  177. zenml/zen_server/dashboard/assets/page-CiYxgZP_.js +1 -0
  178. zenml/zen_server/dashboard/assets/page-Cldq1mpe.js +1 -0
  179. zenml/zen_server/dashboard/assets/{page-BDigxVpo.js → page-D4wdonLm.js} +1 -1
  180. zenml/zen_server/dashboard/assets/{page-D6uU2ax4.js → page-D8ObrbH8.js} +1 -1
  181. zenml/zen_server/dashboard/assets/{page-DXSTpqRD.js → page-DFuAUGt4.js} +1 -1
  182. zenml/zen_server/dashboard/assets/{page-CbpvrsDL.js → page-DGazBpuP.js} +1 -1
  183. zenml/zen_server/dashboard/assets/{page-COXXJj1k.js → page-DO1UcqPX.js} +1 -1
  184. zenml/zen_server/dashboard/assets/page-DRYXdL5o.js +1 -0
  185. zenml/zen_server/dashboard/assets/{page-Df-Fw0aq.js → page-DYEquBC2.js} +1 -1
  186. zenml/zen_server/dashboard/assets/page-Dk32IeZm.js +1 -0
  187. zenml/zen_server/dashboard/assets/{page-yYC9OI-E.js → page-I3nKFGie.js} +1 -1
  188. zenml/zen_server/dashboard/assets/{page-6m6yHHlE.js → page-M0w-n6vn.js} +1 -1
  189. zenml/zen_server/dashboard/assets/{page-Vcxara9U.js → page-R5dx3xGF.js} +1 -1
  190. zenml/zen_server/dashboard/assets/{page-BR68V0V1.js → page-bT5pOvcB.js} +1 -1
  191. zenml/zen_server/dashboard/assets/page-hUqK889I.js +6 -0
  192. zenml/zen_server/dashboard/assets/{page-CjGdWY13.js → page-h_Stveon.js} +1 -1
  193. zenml/zen_server/dashboard/assets/{page-D01JhjQB.js → page-r8XK5vR7.js} +1 -1
  194. zenml/zen_server/dashboard/assets/page-u_-ZXBKb.js +1 -0
  195. zenml/zen_server/dashboard/assets/page-zaMqB_ao.js +1 -0
  196. zenml/zen_server/dashboard/assets/{persist-GjC8PZoC.js → persist-AppN1B0J.js} +1 -1
  197. zenml/zen_server/dashboard/assets/{persist-Coz7ZWvz.js → persist-DAUi_3za.js} +1 -1
  198. zenml/zen_server/dashboard/assets/service-BqqeXLEe.js +2 -0
  199. zenml/zen_server/dashboard/assets/{sharedSchema-CQb14VSr.js → sharedSchema-uXN9FLLk.js} +1 -1
  200. zenml/zen_server/dashboard/assets/{stack-detail-query-OPEW-cDJ.js → stack-detail-query-XfZBiBP2.js} +1 -1
  201. zenml/zen_server/dashboard/assets/{update-server-settings-mutation-LwuQfHYn.js → update-server-settings-mutation-BWmgVJwA.js} +1 -1
  202. zenml/zen_server/dashboard/assets/{url-CkvKAnwF.js → url-BLwMbzES.js} +1 -1
  203. zenml/zen_server/dashboard/index.html +4 -4
  204. zenml/zen_server/deploy/helm/Chart.yaml +1 -1
  205. zenml/zen_server/deploy/helm/README.md +2 -2
  206. zenml/zen_server/rbac/endpoint_utils.py +6 -4
  207. zenml/zen_server/rbac/models.py +3 -2
  208. zenml/zen_server/rbac/rbac_sql_zen_store.py +173 -0
  209. zenml/zen_server/rbac/utils.py +4 -7
  210. zenml/zen_server/routers/auth_endpoints.py +22 -11
  211. zenml/zen_server/routers/steps_endpoints.py +7 -1
  212. zenml/zen_server/routers/users_endpoints.py +35 -37
  213. zenml/zen_server/routers/workspaces_endpoints.py +44 -55
  214. zenml/zen_server/template_execution/utils.py +4 -1
  215. zenml/zen_server/utils.py +4 -3
  216. zenml/zen_stores/base_zen_store.py +10 -2
  217. zenml/zen_stores/migrations/versions/0.71.0_release.py +23 -0
  218. zenml/zen_stores/migrations/versions/26351d482b9e_add_step_run_unique_constraint.py +37 -0
  219. zenml/zen_stores/migrations/versions/a1237ba94fd8_add_model_version_producer_run_unique_.py +68 -0
  220. zenml/zen_stores/migrations/versions/b73bc71f1106_remove_component_spec_path.py +36 -0
  221. zenml/zen_stores/migrations/versions/cc269488e5a9_separate_run_metadata.py +135 -0
  222. zenml/zen_stores/migrations/versions/ec6307720f92_simplify_model_version_links.py +7 -6
  223. zenml/zen_stores/rest_zen_store.py +76 -43
  224. zenml/zen_stores/schemas/__init__.py +5 -1
  225. zenml/zen_stores/schemas/artifact_schemas.py +12 -11
  226. zenml/zen_stores/schemas/component_schemas.py +0 -3
  227. zenml/zen_stores/schemas/model_schemas.py +55 -17
  228. zenml/zen_stores/schemas/pipeline_deployment_schemas.py +7 -7
  229. zenml/zen_stores/schemas/pipeline_run_schemas.py +52 -18
  230. zenml/zen_stores/schemas/pipeline_schemas.py +5 -0
  231. zenml/zen_stores/schemas/run_metadata_schemas.py +66 -31
  232. zenml/zen_stores/schemas/step_run_schemas.py +40 -13
  233. zenml/zen_stores/schemas/utils.py +47 -3
  234. zenml/zen_stores/sql_zen_store.py +462 -134
  235. {zenml_nightly-0.70.0.dev20241125.dist-info → zenml_nightly-0.71.0.dev20241220.dist-info}/METADATA +5 -5
  236. {zenml_nightly-0.70.0.dev20241125.dist-info → zenml_nightly-0.71.0.dev20241220.dist-info}/RECORD +239 -217
  237. zenml/utils/cloud_utils.py +0 -40
  238. zenml/zen_server/dashboard/assets/RunSelector-DkPiIiNr.js +0 -1
  239. zenml/zen_server/dashboard/assets/StackList-WvuKQusZ.js +0 -1
  240. zenml/zen_server/dashboard/assets/delete-run-CJdh1P_h.js +0 -1
  241. zenml/zen_server/dashboard/assets/index-DlGvJQPn.css +0 -1
  242. zenml/zen_server/dashboard/assets/page-0JE_-Ec1.js +0 -1
  243. zenml/zen_server/dashboard/assets/page-BRLpxOt0.js +0 -1
  244. zenml/zen_server/dashboard/assets/page-BU7huvKw.js +0 -6
  245. zenml/zen_server/dashboard/assets/page-BvqLv2Ky.js +0 -1
  246. zenml/zen_server/dashboard/assets/page-CwxrFarU.js +0 -1
  247. zenml/zen_server/dashboard/assets/page-DfbXf_8s.js +0 -1
  248. zenml/zen_server/dashboard/assets/page-Dnovpa0i.js +0 -3
  249. zenml/zen_server/dashboard/assets/page-Dot3LPmL.js +0 -1
  250. zenml/zen_server/dashboard/assets/page-Xynx4btY.js +0 -14
  251. zenml/zen_server/dashboard/assets/page-YpKAqVSa.js +0 -1
  252. {zenml_nightly-0.70.0.dev20241125.dist-info → zenml_nightly-0.71.0.dev20241220.dist-info}/LICENSE +0 -0
  253. {zenml_nightly-0.70.0.dev20241125.dist-info → zenml_nightly-0.71.0.dev20241220.dist-info}/WHEEL +0 -0
  254. {zenml_nightly-0.70.0.dev20241125.dist-info → zenml_nightly-0.71.0.dev20241220.dist-info}/entry_points.txt +0 -0
@@ -14,7 +14,7 @@
14
14
  """Utilities for creating step runs."""
15
15
 
16
16
  from datetime import datetime
17
- from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple
17
+ from typing import Dict, List, Optional, Set, Tuple
18
18
 
19
19
  from zenml.client import Client
20
20
  from zenml.config.step_configurations import Step
@@ -24,21 +24,13 @@ from zenml.logger import get_logger
24
24
  from zenml.model.utils import link_artifact_version_to_model_version
25
25
  from zenml.models import (
26
26
  ArtifactVersionResponse,
27
- ModelVersionPipelineRunRequest,
28
27
  ModelVersionResponse,
29
28
  PipelineDeploymentResponse,
30
29
  PipelineRunResponse,
31
- PipelineRunUpdate,
32
30
  StepRunRequest,
33
- StepRunResponse,
34
- StepRunUpdate,
35
31
  )
36
32
  from zenml.orchestrators import cache_utils, input_utils, utils
37
33
  from zenml.stack import Stack
38
- from zenml.utils import pagination_utils, string_utils
39
-
40
- if TYPE_CHECKING:
41
- from zenml.model.model import Model
42
34
 
43
35
  logger = get_logger(__name__)
44
36
 
@@ -293,10 +285,6 @@ def create_cached_step_runs(
293
285
  deployment=deployment, pipeline_run=pipeline_run, stack=stack
294
286
  )
295
287
 
296
- pipeline_model_version, pipeline_run = prepare_pipeline_run_model_version(
297
- pipeline_run=pipeline_run
298
- )
299
-
300
288
  while (
301
289
  cache_candidates := find_cacheable_invocation_candidates(
302
290
  deployment=deployment,
@@ -309,6 +297,11 @@ def create_cached_step_runs(
309
297
  for invocation_id in cache_candidates:
310
298
  visited_invocations.add(invocation_id)
311
299
 
300
+ # Make sure the request factory has the most up to date pipeline
301
+ # run to avoid hydration calls
302
+ request_factory.pipeline_run = Client().get_pipeline_run(
303
+ pipeline_run.id
304
+ )
312
305
  try:
313
306
  step_run_request = request_factory.create_request(
314
307
  invocation_id
@@ -333,15 +326,10 @@ def create_cached_step_runs(
333
326
 
334
327
  step_run = Client().zen_store.create_run_step(step_run_request)
335
328
 
336
- # Refresh the pipeline run here to make sure we have the latest
337
- # state
338
- pipeline_run = Client().get_pipeline_run(pipeline_run.id)
339
-
340
- step_model_version, step_run = prepare_step_run_model_version(
341
- step_run=step_run, pipeline_run=pipeline_run
342
- )
343
-
344
- if model_version := step_model_version or pipeline_model_version:
329
+ if (
330
+ model_version := step_run.model_version
331
+ or pipeline_run.model_version
332
+ ):
345
333
  link_output_artifacts_to_model_version(
346
334
  artifacts=step_run.outputs,
347
335
  model_version=model_version,
@@ -353,160 +341,6 @@ def create_cached_step_runs(
353
341
  return cached_invocations
354
342
 
355
343
 
356
- def get_or_create_model_version_for_pipeline_run(
357
- model: "Model", pipeline_run: PipelineRunResponse
358
- ) -> Tuple[ModelVersionResponse, bool]:
359
- """Get or create a model version as part of a pipeline run.
360
-
361
- Args:
362
- model: The model to get or create.
363
- pipeline_run: The pipeline run for which the model should be created.
364
-
365
- Returns:
366
- The model version and a boolean indicating whether it was newly created
367
- or not.
368
- """
369
- # Copy the model before modifying it so we don't accidently modify
370
- # configurations in which the model object is potentially referenced
371
- model = model.model_copy()
372
-
373
- if model.model_version_id:
374
- return model._get_model_version(), False
375
- elif model.version:
376
- if isinstance(model.version, str):
377
- start_time = pipeline_run.start_time or datetime.utcnow()
378
- model.version = string_utils.format_name_template(
379
- model.version,
380
- date=start_time.strftime("%Y_%m_%d"),
381
- time=start_time.strftime("%H_%M_%S_%f"),
382
- )
383
-
384
- return (
385
- model._get_or_create_model_version(),
386
- model._created_model_version,
387
- )
388
-
389
- # The model version should be created as part of this run
390
- # -> We first check if it was already created as part of this run, and if
391
- # not we do create it. If this is running in two parallel steps, we might
392
- # run into issues that this will create two versions. Ideally, all model
393
- # versions required for a pipeline run and its steps could be created
394
- # server-side at run creation time before the first step starts.
395
- if model_version := get_model_version_created_by_pipeline_run(
396
- model_name=model.name, pipeline_run=pipeline_run
397
- ):
398
- return model_version, False
399
- else:
400
- return model._get_or_create_model_version(), True
401
-
402
-
403
- def get_model_version_created_by_pipeline_run(
404
- model_name: str, pipeline_run: PipelineRunResponse
405
- ) -> Optional[ModelVersionResponse]:
406
- """Get a model version that was created by a specific pipeline run.
407
-
408
- This function does not refresh the pipeline run, so it will only try to
409
- fetch the model version from existing steps if they're already part of the
410
- response.
411
-
412
- Args:
413
- model_name: The model name for which to get the version.
414
- pipeline_run: The pipeline run for which to get the version.
415
-
416
- Returns:
417
- A model version with the given name created by the run, or None if such
418
- a model version does not exist.
419
- """
420
- if pipeline_run.config.model and pipeline_run.model_version:
421
- if (
422
- pipeline_run.config.model.name == model_name
423
- and pipeline_run.config.model.version is None
424
- ):
425
- return pipeline_run.model_version
426
-
427
- # We fetch a list of hydrated step runs here in order to avoid hydration
428
- # calls for each step separately.
429
- candidate_step_runs = pagination_utils.depaginate(
430
- Client().list_run_steps,
431
- pipeline_run_id=pipeline_run.id,
432
- model=model_name,
433
- hydrate=True,
434
- )
435
- for step_run in candidate_step_runs:
436
- if step_run.config.model and step_run.model_version:
437
- if (
438
- step_run.config.model.name == model_name
439
- and step_run.config.model.version is None
440
- ):
441
- return step_run.model_version
442
-
443
- return None
444
-
445
-
446
- def prepare_pipeline_run_model_version(
447
- pipeline_run: PipelineRunResponse,
448
- ) -> Tuple[Optional[ModelVersionResponse], PipelineRunResponse]:
449
- """Prepare the model version for a pipeline run.
450
-
451
- Args:
452
- pipeline_run: The pipeline run for which to prepare the model version.
453
-
454
- Returns:
455
- The prepared model version and the updated pipeline run.
456
- """
457
- model_version = None
458
-
459
- if pipeline_run.model_version:
460
- model_version = pipeline_run.model_version
461
- elif config_model := pipeline_run.config.model:
462
- model_version, _ = get_or_create_model_version_for_pipeline_run(
463
- model=config_model, pipeline_run=pipeline_run
464
- )
465
- pipeline_run = Client().zen_store.update_run(
466
- run_id=pipeline_run.id,
467
- run_update=PipelineRunUpdate(model_version_id=model_version.id),
468
- )
469
- link_pipeline_run_to_model_version(
470
- pipeline_run=pipeline_run, model_version=model_version
471
- )
472
- log_model_version_dashboard_url(model_version)
473
-
474
- return model_version, pipeline_run
475
-
476
-
477
- def prepare_step_run_model_version(
478
- step_run: StepRunResponse, pipeline_run: PipelineRunResponse
479
- ) -> Tuple[Optional[ModelVersionResponse], StepRunResponse]:
480
- """Prepare the model version for a step run.
481
-
482
- Args:
483
- step_run: The step run for which to prepare the model version.
484
- pipeline_run: The pipeline run of the step.
485
-
486
- Returns:
487
- The prepared model version and the updated step run.
488
- """
489
- model_version = None
490
-
491
- if step_run.model_version:
492
- model_version = step_run.model_version
493
- elif config_model := step_run.config.model:
494
- model_version, created = get_or_create_model_version_for_pipeline_run(
495
- model=config_model, pipeline_run=pipeline_run
496
- )
497
- step_run = Client().zen_store.update_run_step(
498
- step_run_id=step_run.id,
499
- step_run_update=StepRunUpdate(model_version_id=model_version.id),
500
- )
501
- link_pipeline_run_to_model_version(
502
- pipeline_run=pipeline_run, model_version=model_version
503
- )
504
- if created:
505
- log_model_version_dashboard_url(model_version)
506
-
507
- return model_version, step_run
508
-
509
-
510
344
  def log_model_version_dashboard_url(
511
345
  model_version: ModelVersionResponse,
512
346
  ) -> None:
@@ -518,10 +352,15 @@ def log_model_version_dashboard_url(
518
352
  Args:
519
353
  model_version: The model version for which to log the dashboard URL.
520
354
  """
521
- from zenml.utils.cloud_utils import try_get_model_version_url
355
+ from zenml.utils.dashboard_utils import get_model_version_url
522
356
 
523
- if model_version_url_logs := try_get_model_version_url(model_version):
524
- logger.info(model_version_url_logs)
357
+ if model_version_url := get_model_version_url(model_version.id):
358
+ logger.info(
359
+ "Dashboard URL for Model Version `%s (%s)`:\n%s",
360
+ model_version.model.name,
361
+ model_version.name,
362
+ model_version_url,
363
+ )
525
364
  else:
526
365
  logger.info(
527
366
  "Models can be viewed in the dashboard using ZenML Pro. Sign up "
@@ -529,24 +368,6 @@ def log_model_version_dashboard_url(
529
368
  )
530
369
 
531
370
 
532
- def link_pipeline_run_to_model_version(
533
- pipeline_run: PipelineRunResponse, model_version: ModelVersionResponse
534
- ) -> None:
535
- """Link a pipeline run to a model version.
536
-
537
- Args:
538
- pipeline_run: The pipeline run to link.
539
- model_version: The model version to link.
540
- """
541
- client = Client()
542
- client.zen_store.create_model_version_pipeline_run_link(
543
- ModelVersionPipelineRunRequest(
544
- pipeline_run=pipeline_run.id,
545
- model_version=model_version.id,
546
- )
547
- )
548
-
549
-
550
371
  def link_output_artifacts_to_model_version(
551
372
  artifacts: Dict[str, List[ArtifactVersionResponse]],
552
373
  model_version: ModelVersionResponse,
@@ -56,7 +56,7 @@ from zenml.steps.utils import (
56
56
  parse_return_type_annotations,
57
57
  resolve_type_annotation,
58
58
  )
59
- from zenml.utils import materializer_utils, source_utils
59
+ from zenml.utils import materializer_utils, source_utils, string_utils
60
60
  from zenml.utils.typing_utils import get_origin, is_union
61
61
 
62
62
  if TYPE_CHECKING:
@@ -152,6 +152,15 @@ class StepRunner:
152
152
  func=step_instance.entrypoint
153
153
  )
154
154
 
155
+ self._evaluate_artifact_names_in_collections(
156
+ step_run,
157
+ output_annotations,
158
+ [
159
+ output_artifact_uris,
160
+ output_materializers,
161
+ ],
162
+ )
163
+
155
164
  self._stack.prepare_step_run(info=step_run_info)
156
165
 
157
166
  # Initialize the step context singleton
@@ -257,7 +266,9 @@ class StepRunner:
257
266
 
258
267
  # Update the status and output artifacts of the step run.
259
268
  output_artifact_ids = {
260
- output_name: artifact.id
269
+ output_name: [
270
+ artifact.id,
271
+ ]
261
272
  for output_name, artifact in output_artifacts.items()
262
273
  }
263
274
  publish_successful_step_run(
@@ -265,6 +276,32 @@ class StepRunner:
265
276
  output_artifact_ids=output_artifact_ids,
266
277
  )
267
278
 
279
+ def _evaluate_artifact_names_in_collections(
280
+ self,
281
+ step_run: "StepRunResponse",
282
+ output_annotations: Dict[str, OutputSignature],
283
+ collections: List[Dict[str, Any]],
284
+ ) -> None:
285
+ """Evaluates the artifact names in the collections.
286
+
287
+ Args:
288
+ step_run: The step run.
289
+ output_annotations: The output annotations of the step function
290
+ (also evaluated).
291
+ collections: The collections to evaluate.
292
+ """
293
+ collections.append(output_annotations)
294
+ for k, v in list(output_annotations.items()):
295
+ name = k
296
+ if v.artifact_config and v.artifact_config.name:
297
+ name = string_utils.format_name_template(
298
+ v.artifact_config.name,
299
+ substitutions=step_run.config.substitutions,
300
+ )
301
+
302
+ for d in collections:
303
+ d[name] = d.pop(k)
304
+
268
305
  def _load_step(self) -> "BaseStep":
269
306
  """Load the step instance.
270
307
 
@@ -400,7 +437,7 @@ class StepRunner:
400
437
  **artifact.get_hydrated_version().model_dump()
401
438
  )
402
439
 
403
- if data_type is Any or is_union(get_origin(data_type)):
440
+ if data_type in (None, Any) or is_union(get_origin(data_type)):
404
441
  # Entrypoint function does not define a specific type for the input,
405
442
  # we use the datatype of the stored artifact
406
443
  data_type = source_utils.load(artifact.data_type)
@@ -26,13 +26,14 @@ from zenml.constants import (
26
26
  ENV_ZENML_ACTIVE_STACK_ID,
27
27
  ENV_ZENML_ACTIVE_WORKSPACE_ID,
28
28
  ENV_ZENML_DISABLE_CREDENTIALS_DISK_CACHING,
29
+ ENV_ZENML_PIPELINE_RUN_API_TOKEN_EXPIRATION,
29
30
  ENV_ZENML_SERVER,
30
31
  ENV_ZENML_STORE_PREFIX,
32
+ ZENML_PIPELINE_RUN_API_TOKEN_EXPIRATION,
31
33
  )
32
- from zenml.enums import AuthScheme, StackComponentType, StoreType
34
+ from zenml.enums import APITokenType, AuthScheme, StackComponentType, StoreType
33
35
  from zenml.logger import get_logger
34
36
  from zenml.stack import StackComponent
35
- from zenml.utils.string_utils import format_name_template
36
37
 
37
38
  logger = get_logger(__name__)
38
39
 
@@ -40,7 +41,9 @@ if TYPE_CHECKING:
40
41
  from zenml.artifact_stores.base_artifact_store import BaseArtifactStore
41
42
 
42
43
 
43
- def get_orchestrator_run_name(pipeline_name: str) -> str:
44
+ def get_orchestrator_run_name(
45
+ pipeline_name: str, max_length: Optional[int] = None
46
+ ) -> str:
44
47
  """Gets an orchestrator run name.
45
48
 
46
49
  This run name is not the same as the ZenML run name but can instead be
@@ -48,11 +51,31 @@ def get_orchestrator_run_name(pipeline_name: str) -> str:
48
51
 
49
52
  Args:
50
53
  pipeline_name: Name of the pipeline that will run.
54
+ max_length: Maximum length of the generated name.
55
+
56
+ Raises:
57
+ ValueError: If the max length is below 8 characters.
51
58
 
52
59
  Returns:
53
60
  The orchestrator run name.
54
61
  """
55
- return f"{pipeline_name}_{random.Random().getrandbits(128):032x}"
62
+ suffix_length = 32
63
+ pipeline_name = f"{pipeline_name}_"
64
+
65
+ if max_length:
66
+ if max_length < 8:
67
+ raise ValueError(
68
+ "Maximum length for orchestrator run name must be 8 or above."
69
+ )
70
+
71
+ # Make sure we always have a certain suffix to guarantee no overlap
72
+ # with other runs
73
+ suffix_length = min(32, max(8, max_length - len(pipeline_name)))
74
+ pipeline_name = pipeline_name[: (max_length - suffix_length)]
75
+
76
+ suffix = "".join(random.choices("0123456789abcdef", k=suffix_length))
77
+
78
+ return f"{pipeline_name}{suffix}"
56
79
 
57
80
 
58
81
  def is_setting_enabled(
@@ -116,37 +139,63 @@ def get_config_environment_vars(
116
139
  url = global_config.store_configuration.url
117
140
  api_token = credentials_store.get_token(url, allow_expired=False)
118
141
  if schedule_id or pipeline_run_id or step_run_id:
119
- # When connected to an authenticated ZenML server, if a schedule ID,
120
- # pipeline run ID or step run ID is supplied, we need to fetch a new
121
- # workload API token scoped to the schedule, pipeline run or step
122
- # run.
123
142
  assert isinstance(global_config.zen_store, RestZenStore)
124
143
 
125
- # If only a schedule is given, the pipeline run credentials will
126
- # be valid for the entire duration of the schedule.
127
- api_key = credentials_store.get_api_key(url)
128
- if not api_key and not pipeline_run_id and not step_run_id:
144
+ # The user has the option to manually set an expiration for the API
145
+ # token generated for a pipeline run. In this case, we generate a new
146
+ # generic API token that will be valid for the indicated duration.
147
+ if (
148
+ pipeline_run_id
149
+ and ZENML_PIPELINE_RUN_API_TOKEN_EXPIRATION != 0
150
+ ):
129
151
  logger.warning(
130
- "An API token without an expiration time will be generated "
131
- "and used to run this pipeline on a schedule. This is very "
132
- "insecure because the API token will be valid for the "
133
- "entire lifetime of the schedule and can be used to access "
134
- "your user account if accidentally leaked. When deploying "
135
- "a pipeline on a schedule, it is strongly advised to use a "
136
- "service account API key to authenticate to the ZenML "
137
- "server instead of your regular user account. For more "
138
- "information, see "
139
- "https://docs.zenml.io/how-to/connecting-to-zenml/connect-with-a-service-account"
152
+ f"An unscoped API token will be generated for this pipeline "
153
+ f"run that will expire after "
154
+ f"{ZENML_PIPELINE_RUN_API_TOKEN_EXPIRATION} "
155
+ f"seconds instead of being scoped to the pipeline run "
156
+ f"and not having an expiration time. This is more insecure "
157
+ f"because the API token will remain valid even after the "
158
+ f"pipeline run completes its execution. This option has "
159
+ "been explicitly enabled by setting the "
160
+ f"{ENV_ZENML_PIPELINE_RUN_API_TOKEN_EXPIRATION} environment "
161
+ f"variable"
162
+ )
163
+ new_api_token = global_config.zen_store.get_api_token(
164
+ token_type=APITokenType.GENERIC,
165
+ expires_in=ZENML_PIPELINE_RUN_API_TOKEN_EXPIRATION,
140
166
  )
141
167
 
142
- # The schedule, pipeline run or step run credentials are scoped to
143
- # the schedule, pipeline run or step run and will only be valid for
144
- # the duration of the schedule/pipeline run/step run.
145
- new_api_token = global_config.zen_store.get_api_token(
146
- schedule_id=schedule_id,
147
- pipeline_run_id=pipeline_run_id,
148
- step_run_id=step_run_id,
149
- )
168
+ else:
169
+ # If a schedule ID, pipeline run ID or step run ID is supplied,
170
+ # we need to fetch a new workload API token scoped to the
171
+ # schedule, pipeline run or step run.
172
+
173
+ # If only a schedule is given, the pipeline run credentials will
174
+ # be valid for the entire duration of the schedule.
175
+ api_key = credentials_store.get_api_key(url)
176
+ if not api_key and not pipeline_run_id and not step_run_id:
177
+ logger.warning(
178
+ "An API token without an expiration time will be generated "
179
+ "and used to run this pipeline on a schedule. This is very "
180
+ "insecure because the API token will be valid for the "
181
+ "entire lifetime of the schedule and can be used to access "
182
+ "your user account if accidentally leaked. When deploying "
183
+ "a pipeline on a schedule, it is strongly advised to use a "
184
+ "service account API key to authenticate to the ZenML "
185
+ "server instead of your regular user account. For more "
186
+ "information, see "
187
+ "https://docs.zenml.io/how-to/connecting-to-zenml/connect-with-a-service-account"
188
+ )
189
+
190
+ # The schedule, pipeline run or step run credentials are scoped to
191
+ # the schedule, pipeline run or step run and will only be valid for
192
+ # the duration of the schedule/pipeline run/step run.
193
+ new_api_token = global_config.zen_store.get_api_token(
194
+ token_type=APITokenType.WORKLOAD,
195
+ schedule_id=schedule_id,
196
+ pipeline_run_id=pipeline_run_id,
197
+ step_run_id=step_run_id,
198
+ )
150
199
 
151
200
  environment_vars[ENV_ZENML_STORE_PREFIX + "API_TOKEN"] = (
152
201
  new_api_token
@@ -174,26 +223,6 @@ def get_config_environment_vars(
174
223
  return environment_vars
175
224
 
176
225
 
177
- def get_run_name(run_name_template: str) -> str:
178
- """Fill out the run name template to get a complete run name.
179
-
180
- Args:
181
- run_name_template: The run name template to fill out.
182
-
183
- Raises:
184
- ValueError: If the run name is empty.
185
-
186
- Returns:
187
- The run name derived from the template.
188
- """
189
- run_name = format_name_template(run_name_template)
190
-
191
- if run_name == "":
192
- raise ValueError("Empty run names are not allowed.")
193
-
194
- return run_name
195
-
196
-
197
226
  class register_artifact_store_filesystem:
198
227
  """Context manager for the artifact_store/filesystem_registry dependency.
199
228
 
@@ -249,6 +249,11 @@ def find_existing_build(
249
249
  client = Client()
250
250
  stack = client.active_stack
251
251
 
252
+ if not stack.container_registry:
253
+ # There can be no non-local builds that we can reuse if there is no
254
+ # container registry in the stack.
255
+ return None
256
+
252
257
  python_version_prefix = ".".join(platform.python_version_tuple()[:2])
253
258
  required_builds = stack.get_docker_builds(deployment=deployment)
254
259
 
@@ -263,6 +268,13 @@ def find_existing_build(
263
268
  sort_by="desc:created",
264
269
  size=1,
265
270
  stack_id=stack.id,
271
+ # Until we implement stack versioning, users can still update their
272
+ # stack to update/remove the container registry. In that case, we might
273
+ # try to pull an image from a container registry that we don't have
274
+ # access to. This is why we add an additional check for the container
275
+ # registry ID here. (This is still not perfect as users can update the
276
+ # container registry URI or config, but the best we can do)
277
+ container_registry_id=stack.container_registry.id,
266
278
  # The build is local and it's not clear whether the images
267
279
  # exist on the current machine or if they've been overwritten.
268
280
  # TODO: Should we support this by storing the unique Docker ID for
@@ -55,6 +55,7 @@ def pipeline(
55
55
  on_failure: Optional["HookSpecification"] = None,
56
56
  on_success: Optional["HookSpecification"] = None,
57
57
  model: Optional["Model"] = None,
58
+ substitutions: Optional[Dict[str, str]] = None,
58
59
  ) -> Callable[["F"], "Pipeline"]: ...
59
60
 
60
61
 
@@ -71,6 +72,7 @@ def pipeline(
71
72
  on_failure: Optional["HookSpecification"] = None,
72
73
  on_success: Optional["HookSpecification"] = None,
73
74
  model: Optional["Model"] = None,
75
+ substitutions: Optional[Dict[str, str]] = None,
74
76
  ) -> Union["Pipeline", Callable[["F"], "Pipeline"]]:
75
77
  """Decorator to create a pipeline.
76
78
 
@@ -91,6 +93,7 @@ def pipeline(
91
93
  function with no arguments, or a source path to such a function
92
94
  (e.g. `module.my_function`).
93
95
  model: configuration of the model in the Model Control Plane.
96
+ substitutions: Extra placeholders to use in the name templates.
94
97
 
95
98
  Returns:
96
99
  A pipeline instance.
@@ -111,6 +114,7 @@ def pipeline(
111
114
  on_success=on_success,
112
115
  model=model,
113
116
  entrypoint=func,
117
+ substitutions=substitutions,
114
118
  )
115
119
 
116
120
  p.__doc__ = func.__doc__