zenml-nightly 0.62.0.dev20240729__py3-none-any.whl → 0.64.0.dev20240809__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. README.md +2 -2
  2. RELEASE_NOTES.md +120 -0
  3. zenml/VERSION +1 -1
  4. zenml/__init__.py +0 -4
  5. zenml/actions/pipeline_run/pipeline_run_action.py +19 -17
  6. zenml/analytics/enums.py +4 -6
  7. zenml/cli/__init__.py +28 -76
  8. zenml/cli/base.py +2 -2
  9. zenml/cli/pipeline.py +54 -61
  10. zenml/cli/stack.py +6 -8
  11. zenml/cli/web_login.py +8 -0
  12. zenml/client.py +232 -103
  13. zenml/config/build_configuration.py +43 -17
  14. zenml/config/compiler.py +14 -22
  15. zenml/config/docker_settings.py +80 -57
  16. zenml/config/pipeline_run_configuration.py +3 -0
  17. zenml/config/server_config.py +3 -0
  18. zenml/config/source.py +60 -1
  19. zenml/constants.py +11 -2
  20. zenml/entrypoints/base_entrypoint_configuration.py +53 -8
  21. zenml/enums.py +4 -1
  22. zenml/environment.py +25 -9
  23. zenml/image_builders/base_image_builder.py +1 -1
  24. zenml/image_builders/build_context.py +25 -72
  25. zenml/integrations/aws/orchestrators/sagemaker_orchestrator.py +13 -4
  26. zenml/integrations/azure/__init__.py +4 -0
  27. zenml/integrations/azure/flavors/__init__.py +11 -0
  28. zenml/integrations/azure/flavors/azureml_orchestrator_flavor.py +263 -0
  29. zenml/{_hub → integrations/azure/orchestrators}/__init__.py +7 -2
  30. zenml/integrations/azure/orchestrators/azureml_orchestrator.py +544 -0
  31. zenml/integrations/azure/orchestrators/azureml_orchestrator_entrypoint_config.py +86 -0
  32. zenml/integrations/azure/step_operators/azureml_step_operator.py +3 -0
  33. zenml/integrations/databricks/flavors/databricks_orchestrator_flavor.py +20 -2
  34. zenml/integrations/databricks/orchestrators/databricks_orchestrator.py +19 -13
  35. zenml/integrations/gcp/orchestrators/vertex_orchestrator.py +7 -2
  36. zenml/integrations/gcp/service_connectors/gcp_service_connector.py +123 -6
  37. zenml/integrations/kaniko/image_builders/kaniko_image_builder.py +1 -1
  38. zenml/integrations/mlflow/__init__.py +1 -1
  39. zenml/integrations/mlflow/experiment_trackers/mlflow_experiment_tracker.py +3 -1
  40. zenml/integrations/mlflow/flavors/mlflow_experiment_tracker_flavor.py +3 -0
  41. zenml/logger.py +13 -0
  42. zenml/models/__init__.py +26 -22
  43. zenml/models/v2/base/filter.py +32 -0
  44. zenml/models/v2/core/pipeline.py +73 -89
  45. zenml/models/v2/core/pipeline_build.py +15 -11
  46. zenml/models/v2/core/pipeline_deployment.py +72 -24
  47. zenml/models/v2/core/pipeline_run.py +65 -1
  48. zenml/models/v2/core/run_template.py +393 -0
  49. zenml/models/v2/core/server_settings.py +12 -0
  50. zenml/models/v2/core/user.py +0 -21
  51. zenml/models/v2/misc/server_models.py +7 -1
  52. zenml/models/v2/misc/stack_deployment.py +5 -0
  53. zenml/models/v2/misc/user_auth.py +0 -7
  54. zenml/new/pipelines/build_utils.py +220 -89
  55. zenml/new/pipelines/code_archive.py +157 -0
  56. zenml/new/pipelines/pipeline.py +46 -78
  57. zenml/new/pipelines/run_utils.py +79 -1
  58. zenml/post_execution/pipeline.py +1 -4
  59. zenml/service_connectors/service_connector_utils.py +18 -2
  60. zenml/stack_deployments/aws_stack_deployment.py +32 -8
  61. zenml/stack_deployments/azure_stack_deployment.py +122 -10
  62. zenml/stack_deployments/gcp_stack_deployment.py +36 -7
  63. zenml/stack_deployments/stack_deployment.py +23 -7
  64. zenml/steps/base_step.py +3 -0
  65. zenml/steps/utils.py +0 -4
  66. zenml/utils/archivable.py +149 -0
  67. zenml/utils/code_utils.py +244 -0
  68. zenml/utils/notebook_utils.py +122 -0
  69. zenml/utils/package_utils.py +39 -0
  70. zenml/utils/pipeline_docker_image_builder.py +3 -96
  71. zenml/utils/source_utils.py +109 -1
  72. zenml/zen_server/dashboard/assets/{404-B_YdvmwS.js → 404-CRAA_Lew.js} +1 -1
  73. zenml/zen_server/dashboard/assets/@radix-BXWm7HOa.js +85 -0
  74. zenml/zen_server/dashboard/assets/{@react-router-CO-OsFwI.js → @react-router-l3lMcXA2.js} +1 -1
  75. zenml/zen_server/dashboard/assets/{@reactflow-l_1hUr1S.js → @reactflow-CeVxyqYT.js} +2 -2
  76. zenml/zen_server/dashboard/assets/{@tanstack-DYiOyJUL.js → @tanstack-FmcYZMuX.js} +4 -4
  77. zenml/zen_server/dashboard/assets/AlertDialogDropdownItem-ErO9aOgK.js +1 -0
  78. zenml/zen_server/dashboard/assets/{AwarenessChannel-CFg5iX4Z.js → AwarenessChannel-CLXo5rKM.js} +1 -1
  79. zenml/zen_server/dashboard/assets/{CodeSnippet-Dvkx_82E.js → CodeSnippet-D0VLxT2A.js} +2 -2
  80. zenml/zen_server/dashboard/assets/CollapsibleCard-BaUPiVg0.js +1 -0
  81. zenml/zen_server/dashboard/assets/{Commands-DoN1xrEq.js → Commands-JrcZK-3j.js} +1 -1
  82. zenml/zen_server/dashboard/assets/CopyButton-Dbo52T1K.js +2 -0
  83. zenml/zen_server/dashboard/assets/{CsvVizualization-Ck-nZ43m.js → CsvVizualization-D3kAypDj.js} +3 -3
  84. zenml/zen_server/dashboard/assets/DisplayDate-DizbSeT-.js +1 -0
  85. zenml/zen_server/dashboard/assets/EditSecretDialog-Bd7mFLS4.js +1 -0
  86. zenml/zen_server/dashboard/assets/{EmptyState-BMLnFVlB.js → EmptyState-BHblM39I.js} +1 -1
  87. zenml/zen_server/dashboard/assets/{Error-kLtljEOM.js → Error-C6LeJSER.js} +1 -1
  88. zenml/zen_server/dashboard/assets/{ExecutionStatus-DguLLgTK.js → ExecutionStatus-jH4OrWBq.js} +1 -1
  89. zenml/zen_server/dashboard/assets/{Helpbox-BXUMP21n.js → Helpbox-aAB2XP-z.js} +1 -1
  90. zenml/zen_server/dashboard/assets/{Infobox-DSt0O-dm.js → Infobox-BQ0aty32.js} +1 -1
  91. zenml/zen_server/dashboard/assets/{InlineAvatar-xsrsIGE-.js → InlineAvatar-DpTLgM3Q.js} +1 -1
  92. zenml/zen_server/dashboard/assets/Lock-CNyJvf2r.js +1 -0
  93. zenml/zen_server/dashboard/assets/{MarkdownVisualization-xp3hhULl.js → MarkdownVisualization-Bajxn0HY.js} +1 -1
  94. zenml/zen_server/dashboard/assets/NumberBox-BmKE0qnO.js +1 -0
  95. zenml/zen_server/dashboard/assets/{PasswordChecker-DUveqlva.js → PasswordChecker-yGGoJSB-.js} +1 -1
  96. zenml/zen_server/dashboard/assets/ProviderRadio-BBqkIuTd.js +1 -0
  97. zenml/zen_server/dashboard/assets/RadioItem-xLhXoiFV.js +1 -0
  98. zenml/zen_server/dashboard/assets/SearchField-C9R0mdaX.js +1 -0
  99. zenml/zen_server/dashboard/assets/{SetPassword-BXGTWiwj.js → SetPassword-52sNxNiO.js} +1 -1
  100. zenml/zen_server/dashboard/assets/{SuccessStep-DZC60t0x.js → SuccessStep-DlkItqYG.js} +1 -1
  101. zenml/zen_server/dashboard/assets/Tick-uxv80Q6a.js +1 -0
  102. zenml/zen_server/dashboard/assets/{UpdatePasswordSchemas-DGvwFWO1.js → UpdatePasswordSchemas-oN4G3sKz.js} +1 -1
  103. zenml/zen_server/dashboard/assets/{aws-BgKTfTfx.js → aws-0_3UsPif.js} +1 -1
  104. zenml/zen_server/dashboard/assets/{check-circle-i56092KI.js → check-circle-1_I207rW.js} +1 -1
  105. zenml/zen_server/dashboard/assets/chevron-down-BpaF8JqM.js +1 -0
  106. zenml/zen_server/dashboard/assets/{chevron-right-double-CZBOf6JM.js → chevron-right-double-Dk8e2L99.js} +1 -1
  107. zenml/zen_server/dashboard/assets/{cloud-only-C_yFCAkP.js → cloud-only-BkUuI0lZ.js} +1 -1
  108. zenml/zen_server/dashboard/assets/components-Br2ezRib.js +1 -0
  109. zenml/zen_server/dashboard/assets/{copy-BXNk6BjL.js → copy-f3XGPPxt.js} +1 -1
  110. zenml/zen_server/dashboard/assets/{database-1xWSgZfO.js → database-cXYNX9tt.js} +1 -1
  111. zenml/zen_server/dashboard/assets/{docker-CQMVm_4d.js → docker-8uj__HHK.js} +1 -1
  112. zenml/zen_server/dashboard/assets/dots-horizontal-sKQlWEni.js +1 -0
  113. zenml/zen_server/dashboard/assets/edit-C0MVvPD2.js +1 -0
  114. zenml/zen_server/dashboard/assets/{file-text-CqD_iu6l.js → file-text-B9JibxTs.js} +1 -1
  115. zenml/zen_server/dashboard/assets/{help-bu_DgLKI.js → help-FuHlZwn0.js} +1 -1
  116. zenml/zen_server/dashboard/assets/{index-rK_Wuy2W.js → index-Bd1xgUQG.js} +1 -1
  117. zenml/zen_server/dashboard/assets/index-DaGknux4.css +1 -0
  118. zenml/zen_server/dashboard/assets/{index-BczVOqUf.js → index-DhIZtpxB.js} +5 -5
  119. zenml/zen_server/dashboard/assets/index.esm-DT4uyn2i.js +1 -0
  120. zenml/zen_server/dashboard/assets/layout-D6oiSbfd.js +1 -0
  121. zenml/zen_server/dashboard/assets/{login-mutation-CrHrndTI.js → login-mutation-13A_JSVA.js} +1 -1
  122. zenml/zen_server/dashboard/assets/{logs-D8k8BVFf.js → logs-CgeE2vZP.js} +1 -1
  123. zenml/zen_server/dashboard/assets/{not-found-DYa4pC-C.js → not-found-B0Mmb90p.js} +1 -1
  124. zenml/zen_server/dashboard/assets/package-DdkziX79.js +1 -0
  125. zenml/zen_server/dashboard/assets/page-7-v2OBm-.js +1 -0
  126. zenml/zen_server/dashboard/assets/{page-MFQyIJd3.js → page-B3ozwdD1.js} +1 -1
  127. zenml/zen_server/dashboard/assets/{page-BkuQDIf-.js → page-BGwA9B1M.js} +1 -1
  128. zenml/zen_server/dashboard/assets/{page-1iL8aMqs.js → page-BkjAUyTA.js} +1 -1
  129. zenml/zen_server/dashboard/assets/page-BnacgBiy.js +1 -0
  130. zenml/zen_server/dashboard/assets/page-BxF_KMQ3.js +2 -0
  131. zenml/zen_server/dashboard/assets/page-C4POHC0K.js +1 -0
  132. zenml/zen_server/dashboard/assets/page-C9kudd44.js +9 -0
  133. zenml/zen_server/dashboard/assets/page-CA1j3GpJ.js +1 -0
  134. zenml/zen_server/dashboard/assets/page-CCY6yfmu.js +1 -0
  135. zenml/zen_server/dashboard/assets/page-CgTe7Bme.js +1 -0
  136. zenml/zen_server/dashboard/assets/{page-8a4UMKXZ.js → page-Cgn-6v2Y.js} +1 -1
  137. zenml/zen_server/dashboard/assets/page-CxQmQqDw.js +1 -0
  138. zenml/zen_server/dashboard/assets/page-D2Goey3H.js +1 -0
  139. zenml/zen_server/dashboard/assets/page-DLpOnf7u.js +1 -0
  140. zenml/zen_server/dashboard/assets/{page-BhgCDInH.js → page-DSTQnBk-.js} +1 -1
  141. zenml/zen_server/dashboard/assets/{page-1h_sD1jz.js → page-DTysUGOy.js} +1 -1
  142. zenml/zen_server/dashboard/assets/{page-2grKx_MY.js → page-D_EXUFJb.js} +1 -1
  143. zenml/zen_server/dashboard/assets/page-Db15QzsM.js +1 -0
  144. zenml/zen_server/dashboard/assets/{page-BDns21Iz.js → page-DugsjcQ_.js} +1 -1
  145. zenml/zen_server/dashboard/assets/{page-C6-UGEbH.js → page-OFKSPyN7.js} +1 -1
  146. zenml/zen_server/dashboard/assets/{page-BkeAAYwp.js → page-RnG-qhv9.js} +1 -1
  147. zenml/zen_server/dashboard/assets/{page-CCNRIt_f.js → page-T2BtjwPl.js} +1 -1
  148. zenml/zen_server/dashboard/assets/page-TXe1Eo3Z.js +1 -0
  149. zenml/zen_server/dashboard/assets/{page-BnaevhnB.js → page-YiF_fNbe.js} +1 -1
  150. zenml/zen_server/dashboard/assets/{page-uA5prJGY.js → page-hQaiQXfg.js} +1 -1
  151. zenml/zen_server/dashboard/assets/persist-3-5nOJ6m.js +1 -0
  152. zenml/zen_server/dashboard/assets/{play-circle-CNtZKDnW.js → play-circle-XSkLR12B.js} +1 -1
  153. zenml/zen_server/dashboard/assets/plus-FB9-lEq_.js +1 -0
  154. zenml/zen_server/dashboard/assets/refresh-COb6KYDi.js +1 -0
  155. zenml/zen_server/dashboard/assets/sharedSchema-BoYx_B_L.js +14 -0
  156. zenml/zen_server/dashboard/assets/{stack-detail-query-Cficsl6d.js → stack-detail-query-B-US_-wa.js} +1 -1
  157. zenml/zen_server/dashboard/assets/{terminal-By9cErXc.js → terminal-grtjrIEJ.js} +1 -1
  158. zenml/zen_server/dashboard/assets/trash-Cd5CSFqA.js +1 -0
  159. zenml/zen_server/dashboard/assets/{update-server-settings-mutation-7d8xi1tS.js → update-server-settings-mutation-B8GB_ubU.js} +1 -1
  160. zenml/zen_server/dashboard/assets/{url-D7mAQGUM.js → url-hcMJkz8p.js} +1 -1
  161. zenml/zen_server/dashboard/assets/{zod-BhoGpZ63.js → zod-CnykDKJj.js} +1 -1
  162. zenml/zen_server/dashboard/index.html +7 -7
  163. zenml/zen_server/dashboard_legacy/asset-manifest.json +4 -4
  164. zenml/zen_server/dashboard_legacy/index.html +1 -1
  165. zenml/zen_server/dashboard_legacy/{precache-manifest.12246c7548e71e2c4438e496360de80c.js → precache-manifest.9c473c96a43298343a7ce1256183123b.js} +4 -4
  166. zenml/zen_server/dashboard_legacy/service-worker.js +1 -1
  167. zenml/zen_server/dashboard_legacy/static/js/{main.3b27024b.chunk.js → main.463c90b9.chunk.js} +2 -2
  168. zenml/zen_server/dashboard_legacy/static/js/{main.3b27024b.chunk.js.map → main.463c90b9.chunk.js.map} +1 -1
  169. zenml/zen_server/deploy/helm/Chart.yaml +1 -1
  170. zenml/zen_server/deploy/helm/README.md +2 -2
  171. zenml/zen_server/rbac/models.py +1 -0
  172. zenml/zen_server/rbac/utils.py +4 -0
  173. zenml/zen_server/routers/pipeline_builds_endpoints.py +2 -66
  174. zenml/zen_server/routers/pipeline_deployments_endpoints.py +2 -53
  175. zenml/zen_server/routers/pipelines_endpoints.py +1 -74
  176. zenml/zen_server/routers/run_templates_endpoints.py +212 -0
  177. zenml/zen_server/routers/stack_deployment_endpoints.py +6 -0
  178. zenml/zen_server/routers/users_endpoints.py +0 -7
  179. zenml/zen_server/routers/workspaces_endpoints.py +79 -0
  180. zenml/zen_server/{pipeline_deployment → template_execution}/runner_entrypoint_configuration.py +1 -8
  181. zenml/zen_server/{pipeline_deployment → template_execution}/utils.py +214 -92
  182. zenml/zen_server/utils.py +77 -2
  183. zenml/zen_server/zen_server_api.py +54 -2
  184. zenml/zen_stores/base_zen_store.py +7 -1
  185. zenml/zen_stores/migrations/versions/0.63.0_release.py +23 -0
  186. zenml/zen_stores/migrations/versions/0.64.0_release.py +23 -0
  187. zenml/zen_stores/migrations/versions/026d4577b6a0_add_code_path.py +39 -0
  188. zenml/zen_stores/migrations/versions/3dcc5d20e82f_add_last_user_activity.py +51 -0
  189. zenml/zen_stores/migrations/versions/7d1919bb1ef0_add_run_templates.py +100 -0
  190. zenml/zen_stores/migrations/versions/909550c7c4da_remove_user_hub_token.py +36 -0
  191. zenml/zen_stores/migrations/versions/b59aa68fdb1f_simplify_pipelines.py +139 -0
  192. zenml/zen_stores/rest_zen_store.py +112 -39
  193. zenml/zen_stores/schemas/__init__.py +2 -0
  194. zenml/zen_stores/schemas/pipeline_build_schemas.py +3 -3
  195. zenml/zen_stores/schemas/pipeline_deployment_schemas.py +32 -2
  196. zenml/zen_stores/schemas/pipeline_run_schemas.py +29 -3
  197. zenml/zen_stores/schemas/pipeline_schemas.py +29 -30
  198. zenml/zen_stores/schemas/run_template_schemas.py +264 -0
  199. zenml/zen_stores/schemas/server_settings_schemas.py +2 -0
  200. zenml/zen_stores/schemas/step_run_schemas.py +11 -4
  201. zenml/zen_stores/schemas/user_schemas.py +0 -2
  202. zenml/zen_stores/sql_zen_store.py +389 -151
  203. zenml/zen_stores/template_utils.py +261 -0
  204. zenml/zen_stores/zen_store_interface.py +93 -20
  205. {zenml_nightly-0.62.0.dev20240729.dist-info → zenml_nightly-0.64.0.dev20240809.dist-info}/METADATA +3 -3
  206. {zenml_nightly-0.62.0.dev20240729.dist-info → zenml_nightly-0.64.0.dev20240809.dist-info}/RECORD +211 -184
  207. zenml/_hub/client.py +0 -289
  208. zenml/_hub/constants.py +0 -21
  209. zenml/_hub/utils.py +0 -79
  210. zenml/cli/hub.py +0 -1116
  211. zenml/models/v2/core/pipeline_namespace.py +0 -113
  212. zenml/models/v2/misc/hub_plugin_models.py +0 -79
  213. zenml/new/pipelines/deserialization_utils.py +0 -292
  214. zenml/zen_server/dashboard/assets/@radix-CFOkMR_E.js +0 -85
  215. zenml/zen_server/dashboard/assets/CollapsibleCard-opiuBHHc.js +0 -1
  216. zenml/zen_server/dashboard/assets/CopyButton-Cr7xYEPb.js +0 -2
  217. zenml/zen_server/dashboard/assets/DisplayDate-DYgIjlDF.js +0 -1
  218. zenml/zen_server/dashboard/assets/Pagination-C6X-mifw.js +0 -1
  219. zenml/zen_server/dashboard/assets/index-EpMIKgrI.css +0 -1
  220. zenml/zen_server/dashboard/assets/index.esm-Corw4lXQ.js +0 -1
  221. zenml/zen_server/dashboard/assets/package-B3fWP-Dh.js +0 -1
  222. zenml/zen_server/dashboard/assets/page-5NCOHOsy.js +0 -1
  223. zenml/zen_server/dashboard/assets/page-B6h3iaHJ.js +0 -1
  224. zenml/zen_server/dashboard/assets/page-Bi-wtWiO.js +0 -5
  225. zenml/zen_server/dashboard/assets/page-Bq0YxkLV.js +0 -1
  226. zenml/zen_server/dashboard/assets/page-Bs2F4eoD.js +0 -2
  227. zenml/zen_server/dashboard/assets/page-CHNxpz3n.js +0 -1
  228. zenml/zen_server/dashboard/assets/page-DgorQFqi.js +0 -1
  229. zenml/zen_server/dashboard/assets/page-K8ebxVIs.js +0 -1
  230. zenml/zen_server/dashboard/assets/page-TgCF0P_U.js +0 -1
  231. zenml/zen_server/dashboard/assets/page-ZnCEe-eK.js +0 -9
  232. zenml/zen_server/dashboard/assets/persist-D7HJNBWx.js +0 -1
  233. zenml/zen_server/dashboard/assets/plus-C8WOyCzt.js +0 -1
  234. zenml/zen_server/dashboard/assets/secrets-video-OBJ6irhH.svg +0 -21
  235. zenml/zen_server/dashboard/assets/stacks-video-7gfxpAq4.svg +0 -21
  236. /zenml/zen_server/{pipeline_deployment → template_execution}/__init__.py +0 -0
  237. /zenml/zen_server/{pipeline_deployment → template_execution}/workload_manager_interface.py +0 -0
  238. {zenml_nightly-0.62.0.dev20240729.dist-info → zenml_nightly-0.64.0.dev20240809.dist-info}/LICENSE +0 -0
  239. {zenml_nightly-0.62.0.dev20240729.dist-info → zenml_nightly-0.64.0.dev20240809.dist-info}/WHEEL +0 -0
  240. {zenml_nightly-0.62.0.dev20240729.dist-info → zenml_nightly-0.64.0.dev20240809.dist-info}/entry_points.txt +0 -0
@@ -15,7 +15,6 @@
15
15
 
16
16
  import hashlib
17
17
  import platform
18
- from pathlib import Path
19
18
  from typing import (
20
19
  TYPE_CHECKING,
21
20
  Dict,
@@ -36,12 +35,10 @@ from zenml.models import (
36
35
  PipelineBuildRequest,
37
36
  PipelineBuildResponse,
38
37
  PipelineDeploymentBase,
39
- PipelineDeploymentRequest,
38
+ StackResponse,
40
39
  )
41
40
  from zenml.stack import Stack
42
- from zenml.utils import (
43
- source_utils,
44
- )
41
+ from zenml.utils import source_utils
45
42
  from zenml.utils.pipeline_docker_image_builder import (
46
43
  PipelineDockerImageBuilder,
47
44
  )
@@ -53,64 +50,104 @@ if TYPE_CHECKING:
53
50
  logger = get_logger(__name__)
54
51
 
55
52
 
56
- def _create_deployment(
53
+ def build_required(deployment: "PipelineDeploymentBase") -> bool:
54
+ """Checks whether a build is required for the deployment and active stack.
55
+
56
+ Args:
57
+ deployment: The deployment for which to check.
58
+
59
+ Returns:
60
+ If a build is required.
61
+ """
62
+ stack = Client().active_stack
63
+ return bool(stack.get_docker_builds(deployment=deployment))
64
+
65
+
66
+ def requires_included_code(
57
67
  deployment: "PipelineDeploymentBase",
58
- pipeline_id: Optional[UUID] = None,
59
68
  code_repository: Optional["BaseCodeRepository"] = None,
60
- ) -> UUID:
61
- """Creates a deployment in the ZenStore.
69
+ ) -> bool:
70
+ """Checks whether the deployment requires included code.
62
71
 
63
72
  Args:
64
- deployment: Base of the deployment to create.
65
- pipeline_id: Pipeline ID to use for the deployment.
66
- code_repository: Code repository to use for the deployment.
73
+ deployment: The deployment.
74
+ code_repository: If provided, this code repository can be used to
75
+ download the code inside the container images.
67
76
 
68
77
  Returns:
69
- The ID of the deployment.
78
+ If the deployment requires code included in the container images.
70
79
  """
71
- source_root = source_utils.get_source_root()
80
+ for step in deployment.step_configurations.values():
81
+ docker_settings = step.config.docker_settings
72
82
 
73
- code_reference = None
74
- local_repo_context = (
75
- code_repository.get_local_context(source_root)
76
- if code_repository
77
- else None
78
- )
79
- if local_repo_context and not local_repo_context.is_dirty:
80
- subdirectory = (
81
- Path(source_root).resolve().relative_to(local_repo_context.root)
82
- )
83
+ if docker_settings.allow_download_from_artifact_store:
84
+ return False
83
85
 
84
- code_reference = CodeReferenceRequest(
85
- commit=local_repo_context.current_commit,
86
- subdirectory=subdirectory.as_posix(),
87
- code_repository=local_repo_context.code_repository_id,
88
- )
86
+ if docker_settings.allow_download_from_code_repository:
87
+ if code_repository:
88
+ continue
89
89
 
90
- deployment_request = PipelineDeploymentRequest(
91
- user=Client().active_user.id,
92
- workspace=Client().active_workspace.id,
93
- stack=Client().active_stack.id,
94
- pipeline=pipeline_id,
95
- code_reference=code_reference,
96
- **deployment.model_dump(),
97
- )
98
- return (
99
- Client().zen_store.create_deployment(deployment=deployment_request).id
100
- )
90
+ if docker_settings.allow_including_files_in_images:
91
+ return True
101
92
 
93
+ return False
102
94
 
103
- def build_required(deployment: "PipelineDeploymentBase") -> bool:
104
- """Checks whether a build is required for the deployment and active stack.
95
+
96
+ def requires_download_from_code_repository(
97
+ deployment: "PipelineDeploymentBase",
98
+ ) -> bool:
99
+ """Checks whether the deployment needs to download code from a repository.
105
100
 
106
101
  Args:
107
- deployment: The deployment for which to check.
102
+ deployment: The deployment.
108
103
 
109
104
  Returns:
110
- If a build is required.
105
+ If the deployment needs to download code from a code repository.
111
106
  """
112
- stack = Client().active_stack
113
- return bool(stack.get_docker_builds(deployment=deployment))
107
+ for step in deployment.step_configurations.values():
108
+ docker_settings = step.config.docker_settings
109
+
110
+ if docker_settings.allow_download_from_artifact_store:
111
+ return False
112
+
113
+ if docker_settings.allow_including_files_in_images:
114
+ return False
115
+
116
+ if docker_settings.allow_download_from_code_repository:
117
+ # The other two options are false, which means download from a
118
+ # code repo is required.
119
+ return True
120
+
121
+ return False
122
+
123
+
124
+ def code_download_possible(
125
+ deployment: "PipelineDeploymentBase",
126
+ code_repository: Optional["BaseCodeRepository"] = None,
127
+ ) -> bool:
128
+ """Checks whether code download is possible for the deployment.
129
+
130
+ Args:
131
+ deployment: The deployment.
132
+ code_repository: If provided, this code repository can be used to
133
+ download the code inside the container images.
134
+
135
+ Returns:
136
+ Whether code download is possible for the deployment.
137
+ """
138
+ for step in deployment.step_configurations.values():
139
+ if step.config.docker_settings.allow_download_from_artifact_store:
140
+ continue
141
+
142
+ if (
143
+ step.config.docker_settings.allow_download_from_code_repository
144
+ and code_repository
145
+ ):
146
+ continue
147
+
148
+ return False
149
+
150
+ return True
114
151
 
115
152
 
116
153
  def reuse_or_create_pipeline_build(
@@ -131,8 +168,8 @@ def reuse_or_create_pipeline_build(
131
168
  build: Optional existing build. If given, the build will be fetched
132
169
  (or registered) in the database. If not given, a new build will
133
170
  be created.
134
- code_repository: If provided, this code repository will be used to
135
- download inside the build images.
171
+ code_repository: If provided, this code repository can be used to
172
+ download code inside the container images.
136
173
 
137
174
  Returns:
138
175
  The build response.
@@ -140,8 +177,10 @@ def reuse_or_create_pipeline_build(
140
177
  if not build:
141
178
  if (
142
179
  allow_build_reuse
143
- and code_repository
144
- and not deployment.requires_included_files
180
+ and not deployment.should_prevent_build_reuse
181
+ and not requires_included_code(
182
+ deployment=deployment, code_repository=code_repository
183
+ )
145
184
  and build_required(deployment=deployment)
146
185
  ):
147
186
  existing_build = find_existing_build(
@@ -157,17 +196,13 @@ def reuse_or_create_pipeline_build(
157
196
  return existing_build
158
197
  else:
159
198
  logger.info(
160
- "Unable to find a build to reuse. When using a code "
161
- "repository, a previous build can be reused when the "
162
- "following conditions are met:\n"
199
+ "Unable to find a build to reuse. A previous build can be "
200
+ "reused when the following conditions are met:\n"
163
201
  " * The existing build was created for the same stack, "
164
202
  "ZenML version and Python version\n"
165
203
  " * The stack contains a container registry\n"
166
204
  " * The Docker settings of the pipeline and all its steps "
167
- "are the same as for the existing build\n"
168
- " * The build does not include code. This will only be "
169
- "the case if the existing build was created with a clean "
170
- "code repository."
205
+ "are the same as for the existing build."
171
206
  )
172
207
 
173
208
  return create_pipeline_build(
@@ -199,7 +234,7 @@ def reuse_or_create_pipeline_build(
199
234
 
200
235
  def find_existing_build(
201
236
  deployment: "PipelineDeploymentBase",
202
- code_repository: "BaseCodeRepository",
237
+ code_repository: Optional["BaseCodeRepository"] = None,
203
238
  ) -> Optional["PipelineBuildResponse"]:
204
239
  """Find an existing build for a deployment.
205
240
 
@@ -269,6 +304,7 @@ def create_pipeline_build(
269
304
  settings were specified.
270
305
  """
271
306
  client = Client()
307
+ stack_model = Client().active_stack_model
272
308
  stack = client.active_stack
273
309
  required_builds = stack.get_docker_builds(deployment=deployment)
274
310
 
@@ -328,6 +364,11 @@ def create_pipeline_build(
328
364
  download_files = build_config.should_download_files(
329
365
  code_repository=code_repository,
330
366
  )
367
+ pass_code_repo = (
368
+ build_config.should_download_files_from_code_repository(
369
+ code_repository=code_repository
370
+ )
371
+ )
331
372
 
332
373
  (
333
374
  image_name_or_digest,
@@ -341,7 +382,7 @@ def create_pipeline_build(
341
382
  download_files=download_files,
342
383
  entrypoint=build_config.entrypoint,
343
384
  extra_files=build_config.extra_files,
344
- code_repository=code_repository,
385
+ code_repository=code_repository if pass_code_repo else None,
345
386
  )
346
387
  contains_code = include_files
347
388
 
@@ -362,16 +403,11 @@ def create_pipeline_build(
362
403
  build_checksum = compute_build_checksum(
363
404
  required_builds, stack=stack, code_repository=code_repository
364
405
  )
365
- template_deployment_id = _create_deployment(
366
- deployment=deployment,
367
- pipeline_id=pipeline_id,
368
- code_repository=code_repository,
369
- )
370
-
406
+ stack_checksum = compute_stack_checksum(stack=stack_model)
371
407
  build_request = PipelineBuildRequest(
372
408
  user=client.active_user.id,
373
409
  workspace=client.active_workspace.id,
374
- stack=client.active_stack_model.id,
410
+ stack=stack_model.id,
375
411
  pipeline=pipeline_id,
376
412
  is_local=is_local,
377
413
  contains_code=contains_code,
@@ -379,7 +415,7 @@ def create_pipeline_build(
379
415
  zenml_version=zenml.__version__,
380
416
  python_version=platform.python_version(),
381
417
  checksum=build_checksum,
382
- template_deployment_id=template_deployment_id,
418
+ stack_checksum=stack_checksum,
383
419
  )
384
420
  return client.zen_store.create_build(build_request)
385
421
 
@@ -442,30 +478,30 @@ def verify_local_repository_context(
442
478
  deployment, or None if code download is not possible.
443
479
  """
444
480
  if build_required(deployment=deployment):
445
- if deployment.requires_code_download:
481
+ if requires_download_from_code_repository(deployment=deployment):
446
482
  if not local_repo_context:
447
483
  raise RuntimeError(
448
484
  "The `DockerSettings` of the pipeline or one of its "
449
- "steps specify that code should be included in the "
450
- "Docker image (`source_files='download'`), but there is no "
451
- "code repository active at your current source root "
452
- f"`{source_utils.get_source_root()}`."
485
+ "steps specify that code should be downloaded from a "
486
+ "code repository, but "
487
+ "there is no code repository active at your current source "
488
+ f"root `{source_utils.get_source_root()}`."
453
489
  )
454
490
  elif local_repo_context.is_dirty:
455
491
  raise RuntimeError(
456
492
  "The `DockerSettings` of the pipeline or one of its "
457
- "steps specify that code should be included in the "
458
- "Docker image (`source_files='download'`), but the code "
459
- "repository active at your current source root "
493
+ "steps specify that code should be downloaded from a "
494
+ "code repository, but "
495
+ "the code repository active at your current source root "
460
496
  f"`{source_utils.get_source_root()}` has uncommitted "
461
497
  "changes."
462
498
  )
463
499
  elif local_repo_context.has_local_changes:
464
500
  raise RuntimeError(
465
501
  "The `DockerSettings` of the pipeline or one of its "
466
- "steps specify that code should be included in the "
467
- "Docker image (`source_files='download'`), but the code "
468
- "repository active at your current source root "
502
+ "steps specify that code should be downloaded from a "
503
+ "code repository, but "
504
+ "the code repository active at your current source root "
469
505
  f"`{source_utils.get_source_root()}` has unpushed "
470
506
  "changes."
471
507
  )
@@ -473,13 +509,13 @@ def verify_local_repository_context(
473
509
  if local_repo_context:
474
510
  if local_repo_context.is_dirty:
475
511
  logger.warning(
476
- "Unable to use code repository to download code for this run "
477
- "as there are uncommitted changes."
512
+ "Unable to use code repository to download code for this "
513
+ "run as there are uncommitted changes."
478
514
  )
479
515
  elif local_repo_context.has_local_changes:
480
516
  logger.warning(
481
- "Unable to use code repository to download code for this run "
482
- "as there are unpushed changes."
517
+ "Unable to use code repository to download code for this "
518
+ "run as there are unpushed changes."
483
519
  )
484
520
 
485
521
  code_repository = None
@@ -528,13 +564,41 @@ def verify_custom_build(
528
564
  "might differ from the local code in your client environment."
529
565
  )
530
566
 
531
- if build.requires_code_download and not code_repository:
532
- raise RuntimeError(
533
- "The build you specified does not include code but code download "
534
- "not possible. This might be because you don't have a code "
535
- "repository registered or the code repository contains local "
536
- "changes."
537
- )
567
+ if build.requires_code_download:
568
+ if requires_included_code(
569
+ deployment=deployment, code_repository=code_repository
570
+ ):
571
+ raise RuntimeError(
572
+ "The `DockerSettings` of the pipeline or one of its "
573
+ "steps specify that code should be included in the Docker "
574
+ "image, but the build you "
575
+ "specified requires code download. Either update your "
576
+ "`DockerSettings` or specify a different build and try "
577
+ "again."
578
+ )
579
+
580
+ if (
581
+ requires_download_from_code_repository(deployment=deployment)
582
+ and not code_repository
583
+ ):
584
+ raise RuntimeError(
585
+ "The `DockerSettings` of the pipeline or one of its "
586
+ "steps specify that code should be downloaded from a "
587
+ "code repository but "
588
+ "there is no code repository active at your current source "
589
+ f"root `{source_utils.get_source_root()}`."
590
+ )
591
+
592
+ if not code_download_possible(
593
+ deployment=deployment, code_repository=code_repository
594
+ ):
595
+ raise RuntimeError(
596
+ "The `DockerSettings` of the pipeline or one of its "
597
+ "steps specify that code can not be downloaded from the "
598
+ "artifact store, but the build you specified requires code "
599
+ "download. Either update your `DockerSettings` or specify a "
600
+ "different build and try again."
601
+ )
538
602
 
539
603
  if build.checksum:
540
604
  build_checksum = compute_build_checksum(
@@ -585,3 +649,70 @@ def verify_custom_build(
585
649
  "your local machine or the image tags have been "
586
650
  "overwritten since the original build happened."
587
651
  )
652
+
653
+
654
+ def compute_stack_checksum(stack: StackResponse) -> str:
655
+ """Compute a stack checksum.
656
+
657
+ Args:
658
+ stack: The stack for which to compute the checksum.
659
+
660
+ Returns:
661
+ The checksum.
662
+ """
663
+ hash_ = hashlib.md5() # nosec
664
+
665
+ # This checksum is used to see if the stack has been updated since a build
666
+ # was created for it. We create this checksum not with specific requirements
667
+ # as these might change with new ZenML releases, but they don't actually
668
+ # invalidate those Docker images.
669
+ required_integrations = sorted(
670
+ {
671
+ component.integration
672
+ for components in stack.components.values()
673
+ for component in components
674
+ if component.integration and component.integration != "built-in"
675
+ }
676
+ )
677
+ for integration in required_integrations:
678
+ hash_.update(integration.encode())
679
+
680
+ return hash_.hexdigest()
681
+
682
+
683
+ def should_upload_code(
684
+ deployment: PipelineDeploymentBase,
685
+ build: Optional[PipelineBuildResponse],
686
+ code_reference: Optional[CodeReferenceRequest],
687
+ ) -> bool:
688
+ """Checks whether the current code should be uploaded for the deployment.
689
+
690
+ Args:
691
+ deployment: The deployment.
692
+ build: The build for the deployment.
693
+ code_reference: The code reference for the deployment.
694
+
695
+ Returns:
696
+ Whether the current code should be uploaded for the deployment.
697
+ """
698
+ if not build:
699
+ # No build means we don't need to download code into a Docker container
700
+ # for step execution. In other remote orchestrators that don't use
701
+ # Docker containers but instead use e.g. Wheels to run, the code should
702
+ # already be included.
703
+ return False
704
+
705
+ for step in deployment.step_configurations.values():
706
+ docker_settings = step.config.docker_settings
707
+
708
+ if (
709
+ code_reference
710
+ and docker_settings.allow_download_from_code_repository
711
+ ):
712
+ # No upload needed for this step
713
+ continue
714
+
715
+ if docker_settings.allow_download_from_artifact_store:
716
+ return True
717
+
718
+ return False
@@ -0,0 +1,157 @@
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
+ """Code archive."""
15
+
16
+ import os
17
+ from pathlib import Path
18
+ from typing import IO, TYPE_CHECKING, Dict, Optional
19
+
20
+ from zenml.logger import get_logger
21
+ from zenml.utils import string_utils
22
+ from zenml.utils.archivable import Archivable
23
+
24
+ if TYPE_CHECKING:
25
+ from git.repo.base import Repo
26
+
27
+
28
+ logger = get_logger(__name__)
29
+
30
+
31
+ class CodeArchive(Archivable):
32
+ """Code archive class.
33
+
34
+ This class is used to archive user code before uploading it to the artifact
35
+ store. If the user code is stored in a Git repository, only files not
36
+ excluded by gitignores will be included in the archive.
37
+ """
38
+
39
+ def __init__(self, root: str) -> None:
40
+ """Initialize the object.
41
+
42
+ Args:
43
+ root: Root directory of the archive.
44
+ """
45
+ super().__init__()
46
+ self._root = root
47
+
48
+ @property
49
+ def git_repo(self) -> Optional["Repo"]:
50
+ """Git repository active at the code archive root.
51
+
52
+ Returns:
53
+ The git repository if available.
54
+ """
55
+ try:
56
+ # These imports fail when git is not installed on the machine
57
+ from git.exc import InvalidGitRepositoryError
58
+ from git.repo.base import Repo
59
+ except ImportError:
60
+ return None
61
+
62
+ try:
63
+ git_repo = Repo(path=self._root, search_parent_directories=True)
64
+ except InvalidGitRepositoryError:
65
+ return None
66
+
67
+ return git_repo
68
+
69
+ def _get_all_files(self) -> Dict[str, str]:
70
+ """Get all files inside the archive root.
71
+
72
+ Returns:
73
+ All files inside the archive root.
74
+ """
75
+ all_files = {}
76
+ for root, _, files in os.walk(self._root):
77
+ for file in files:
78
+ file_path = os.path.join(root, file)
79
+ path_in_archive = os.path.relpath(file_path, self._root)
80
+ all_files[path_in_archive] = file_path
81
+
82
+ return all_files
83
+
84
+ def get_files(self) -> Dict[str, str]:
85
+ """Gets all regular files that should be included in the archive.
86
+
87
+ Raises:
88
+ RuntimeError: If the code archive would not include any files.
89
+
90
+ Returns:
91
+ A dict {path_in_archive: path_on_filesystem} for all regular files
92
+ in the archive.
93
+ """
94
+ all_files = {}
95
+
96
+ if repo := self.git_repo:
97
+ try:
98
+ result = repo.git.ls_files(
99
+ "--cached",
100
+ "--others",
101
+ "--modified",
102
+ "--exclude-standard",
103
+ self._root,
104
+ )
105
+ except Exception as e:
106
+ logger.warning(
107
+ "Failed to get non-ignored files from git: %s", str(e)
108
+ )
109
+ all_files = self._get_all_files()
110
+ else:
111
+ for file in result.split():
112
+ file_path = os.path.join(repo.working_dir, file)
113
+ path_in_archive = os.path.relpath(file_path, self._root)
114
+
115
+ if os.path.exists(file_path):
116
+ all_files[path_in_archive] = file_path
117
+ else:
118
+ all_files = self._get_all_files()
119
+
120
+ if not all_files:
121
+ raise RuntimeError(
122
+ "The code archive to be uploaded does not contain any files. "
123
+ "This is probably because all files in your source root "
124
+ f"`{self._root}` are ignored by a .gitignore file."
125
+ )
126
+
127
+ # Explicitly remove .zen directories as we write an updated version
128
+ # to disk everytime ZenML is called. This updates the mtime of the
129
+ # file, which invalidates the code upload caching. The values in
130
+ # the .zen directory are not needed anyway as we set them as
131
+ # environment variables.
132
+ all_files = {
133
+ path_in_archive: file_path
134
+ for path_in_archive, file_path in sorted(all_files.items())
135
+ if ".zen" not in Path(path_in_archive).parts[:-1]
136
+ }
137
+
138
+ return all_files
139
+
140
+ def write_archive(
141
+ self, output_file: IO[bytes], use_gzip: bool = True
142
+ ) -> None:
143
+ """Writes an archive of the build context to the given file.
144
+
145
+ Args:
146
+ output_file: The file to write the archive to.
147
+ use_gzip: Whether to use `gzip` to compress the file.
148
+ """
149
+ super().write_archive(output_file=output_file, use_gzip=use_gzip)
150
+ archive_size = os.path.getsize(output_file.name)
151
+ if archive_size > 20 * 1024 * 1024:
152
+ logger.warning(
153
+ "Code archive size: `%s`. If you believe this is "
154
+ "unreasonably large, make sure to version your code in git and "
155
+ "ignore unnecessary files using a `.gitignore` file.",
156
+ string_utils.get_human_readable_filesize(archive_size),
157
+ )