zenml-nightly 0.58.2.dev20240623__py3-none-any.whl → 0.61.0.dev20240712__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 (249) hide show
  1. README.md +30 -9
  2. RELEASE_NOTES.md +240 -0
  3. zenml/VERSION +1 -1
  4. zenml/actions/base_action.py +177 -174
  5. zenml/actions/pipeline_run/pipeline_run_action.py +28 -23
  6. zenml/analytics/enums.py +3 -0
  7. zenml/artifact_stores/base_artifact_store.py +7 -1
  8. zenml/artifacts/utils.py +13 -10
  9. zenml/cli/__init__.py +28 -0
  10. zenml/cli/artifact.py +1 -2
  11. zenml/cli/integration.py +9 -8
  12. zenml/cli/server.py +6 -0
  13. zenml/cli/service_connectors.py +1 -0
  14. zenml/cli/stack.py +946 -39
  15. zenml/cli/stack_components.py +7 -0
  16. zenml/cli/text_utils.py +35 -1
  17. zenml/cli/utils.py +127 -10
  18. zenml/client.py +257 -72
  19. zenml/config/compiler.py +10 -9
  20. zenml/config/docker_settings.py +33 -14
  21. zenml/constants.py +11 -2
  22. zenml/container_registries/base_container_registry.py +1 -0
  23. zenml/enums.py +7 -0
  24. zenml/event_hub/base_event_hub.py +5 -5
  25. zenml/event_hub/event_hub.py +20 -14
  26. zenml/event_sources/base_event.py +0 -11
  27. zenml/event_sources/base_event_source.py +7 -0
  28. zenml/event_sources/webhooks/base_webhook_event_source.py +1 -4
  29. zenml/exceptions.py +4 -0
  30. zenml/hooks/hook_validators.py +2 -3
  31. zenml/integrations/aws/__init__.py +1 -0
  32. zenml/integrations/azure/__init__.py +1 -0
  33. zenml/integrations/bitbucket/plugins/event_sources/bitbucket_webhook_event_source.py +3 -3
  34. zenml/integrations/deepchecks/__init__.py +1 -0
  35. zenml/integrations/discord/__init__.py +1 -0
  36. zenml/integrations/evidently/__init__.py +1 -0
  37. zenml/integrations/facets/__init__.py +1 -0
  38. zenml/integrations/feast/__init__.py +1 -0
  39. zenml/integrations/gcp/__init__.py +3 -1
  40. zenml/integrations/gcp/google_credentials_mixin.py +1 -1
  41. zenml/integrations/gcp/service_connectors/gcp_service_connector.py +320 -64
  42. zenml/integrations/huggingface/__init__.py +1 -0
  43. zenml/integrations/integration.py +24 -0
  44. zenml/integrations/kubeflow/__init__.py +3 -0
  45. zenml/integrations/kubeflow/flavors/kubeflow_orchestrator_flavor.py +1 -1
  46. zenml/integrations/kubeflow/orchestrators/kubeflow_orchestrator.py +0 -1
  47. zenml/integrations/kubernetes/__init__.py +3 -1
  48. zenml/integrations/kubernetes/orchestrators/kube_utils.py +4 -1
  49. zenml/integrations/label_studio/annotators/label_studio_annotator.py +1 -0
  50. zenml/integrations/langchain/__init__.py +1 -0
  51. zenml/integrations/mlflow/__init__.py +4 -2
  52. zenml/integrations/neural_prophet/__init__.py +1 -0
  53. zenml/integrations/polars/__init__.py +1 -0
  54. zenml/integrations/prodigy/__init__.py +1 -0
  55. zenml/integrations/pycaret/__init__.py +6 -0
  56. zenml/integrations/registry.py +37 -0
  57. zenml/integrations/s3/artifact_stores/s3_artifact_store.py +93 -9
  58. zenml/integrations/seldon/__init__.py +1 -0
  59. zenml/integrations/seldon/model_deployers/seldon_model_deployer.py +1 -0
  60. zenml/integrations/skypilot/flavors/skypilot_orchestrator_base_vm_config.py +2 -2
  61. zenml/integrations/skypilot/orchestrators/skypilot_base_vm_orchestrator.py +1 -1
  62. zenml/integrations/skypilot/orchestrators/skypilot_orchestrator_entrypoint.py +2 -2
  63. zenml/integrations/skypilot_aws/__init__.py +2 -1
  64. zenml/integrations/skypilot_azure/__init__.py +1 -1
  65. zenml/integrations/skypilot_gcp/__init__.py +1 -1
  66. zenml/integrations/skypilot_lambda/__init__.py +1 -1
  67. zenml/integrations/skypilot_lambda/flavors/skypilot_orchestrator_lambda_vm_flavor.py +1 -1
  68. zenml/integrations/slack/__init__.py +1 -0
  69. zenml/integrations/tekton/__init__.py +1 -0
  70. zenml/integrations/tensorboard/__init__.py +0 -1
  71. zenml/integrations/tensorflow/__init__.py +18 -6
  72. zenml/integrations/wandb/__init__.py +1 -0
  73. zenml/logging/step_logging.py +54 -51
  74. zenml/models/__init__.py +28 -0
  75. zenml/models/v2/core/action.py +276 -0
  76. zenml/models/v2/core/component.py +18 -0
  77. zenml/models/v2/core/model.py +1 -2
  78. zenml/models/v2/core/service_connector.py +17 -0
  79. zenml/models/v2/core/stack.py +31 -0
  80. zenml/models/v2/core/trigger.py +182 -141
  81. zenml/models/v2/misc/full_stack.py +97 -0
  82. zenml/models/v2/misc/stack_deployment.py +86 -0
  83. zenml/new/pipelines/pipeline.py +14 -4
  84. zenml/new/pipelines/pipeline_decorator.py +1 -2
  85. zenml/new/pipelines/run_utils.py +1 -12
  86. zenml/new/steps/step_decorator.py +2 -3
  87. zenml/orchestrators/input_utils.py +3 -6
  88. zenml/pipelines/base_pipeline.py +0 -2
  89. zenml/pipelines/pipeline_decorator.py +1 -2
  90. zenml/stack/stack.py +3 -6
  91. zenml/stack/stack_component.py +4 -0
  92. zenml/stack_deployments/__init__.py +14 -0
  93. zenml/stack_deployments/aws_stack_deployment.py +254 -0
  94. zenml/stack_deployments/gcp_stack_deployment.py +260 -0
  95. zenml/stack_deployments/stack_deployment.py +208 -0
  96. zenml/stack_deployments/utils.py +44 -0
  97. zenml/steps/base_step.py +1 -2
  98. zenml/steps/step_decorator.py +1 -2
  99. zenml/types.py +10 -1
  100. zenml/utils/function_utils.py +1 -1
  101. zenml/utils/pagination_utils.py +7 -5
  102. zenml/utils/pipeline_docker_image_builder.py +117 -73
  103. zenml/utils/pydantic_utils.py +6 -5
  104. zenml/zen_server/cloud_utils.py +18 -3
  105. zenml/zen_server/dashboard/assets/{404-CDPQCl4D.js → 404-DpJaNHKF.js} +1 -1
  106. zenml/zen_server/dashboard/assets/@radix-CFOkMR_E.js +85 -0
  107. zenml/zen_server/dashboard/assets/{@react-router-DYovave8.js → @react-router-CO-OsFwI.js} +2 -2
  108. zenml/zen_server/dashboard/assets/{@reactflow-CHBapDaj.js → @reactflow-DJfzkHO1.js} +2 -2
  109. zenml/zen_server/dashboard/assets/@tanstack-DYiOyJUL.js +22 -0
  110. zenml/zen_server/dashboard/assets/AwarenessChannel-BYDLT2xC.js +1 -0
  111. zenml/zen_server/dashboard/assets/{CodeSnippet-BidtnWOi.js → CodeSnippet-BkOuRmyq.js} +2 -2
  112. zenml/zen_server/dashboard/assets/Commands-ZvWR1BRs.js +1 -0
  113. zenml/zen_server/dashboard/assets/CopyButton-DVwLkafa.js +2 -0
  114. zenml/zen_server/dashboard/assets/{CsvVizualization-BOuez-fG.js → CsvVizualization-C2IiqX4I.js} +7 -7
  115. zenml/zen_server/dashboard/assets/DisplayDate-DYgIjlDF.js +1 -0
  116. zenml/zen_server/dashboard/assets/EmptyState-BMLnFVlB.js +1 -0
  117. zenml/zen_server/dashboard/assets/Error-CqX0VqW_.js +1 -0
  118. zenml/zen_server/dashboard/assets/ExecutionStatus-BoLUXR9t.js +1 -0
  119. zenml/zen_server/dashboard/assets/Helpbox-LFydyVwh.js +1 -0
  120. zenml/zen_server/dashboard/assets/Infobox-DnENC0sh.js +1 -0
  121. zenml/zen_server/dashboard/assets/InlineAvatar-CbJtYr0t.js +1 -0
  122. zenml/zen_server/dashboard/assets/{MarkdownVisualization-DsB2QZiK.js → MarkdownVisualization-xp3hhULl.js} +2 -2
  123. zenml/zen_server/dashboard/assets/Pagination-DEbVUupy.js +1 -0
  124. zenml/zen_server/dashboard/assets/PasswordChecker-DUveqlva.js +1 -0
  125. zenml/zen_server/dashboard/assets/SetPassword-BYBdbQDo.js +1 -0
  126. zenml/zen_server/dashboard/assets/SuccessStep-Nx743hll.js +1 -0
  127. zenml/zen_server/dashboard/assets/{UpdatePasswordSchemas-DnM-c11H.js → UpdatePasswordSchemas-DF9gSzE0.js} +1 -1
  128. zenml/zen_server/dashboard/assets/{aws-t0gKCj_R.js → aws-BgKTfTfx.js} +1 -1
  129. zenml/zen_server/dashboard/assets/{check-circle-BVvhm5dy.js → check-circle-i56092KI.js} +1 -1
  130. zenml/zen_server/dashboard/assets/{chevron-down-zcvCWmyP.js → chevron-down-D_ZlKMqH.js} +1 -1
  131. zenml/zen_server/dashboard/assets/{chevron-right-double-CJ50E9Gr.js → chevron-right-double-BiEMg7rd.js} +1 -1
  132. zenml/zen_server/dashboard/assets/cloud-only-DVbIeckv.js +1 -0
  133. zenml/zen_server/dashboard/assets/{copy-BRhQz3j-.js → copy-BXNk6BjL.js} +1 -1
  134. zenml/zen_server/dashboard/assets/{database-CRRnyFWh.js → database-1xWSgZfO.js} +1 -1
  135. zenml/zen_server/dashboard/assets/{docker-BAonhm6G.js → docker-CQMVm_4d.js} +1 -1
  136. zenml/zen_server/dashboard/assets/{file-text-CbVERUON.js → file-text-CqD_iu6l.js} +1 -1
  137. zenml/zen_server/dashboard/assets/{help-B8rqCvqn.js → help-bu_DgLKI.js} +1 -1
  138. zenml/zen_server/dashboard/assets/index-C_CrU4vI.js +1 -0
  139. zenml/zen_server/dashboard/assets/index-DK1ynKjA.js +55 -0
  140. zenml/zen_server/dashboard/assets/index-inApY3KQ.css +1 -0
  141. zenml/zen_server/dashboard/assets/index-rK_Wuy2W.js +1 -0
  142. zenml/zen_server/dashboard/assets/index.esm-Corw4lXQ.js +1 -0
  143. zenml/zen_server/dashboard/assets/{login-mutation-wzzl23C6.js → login-mutation-BUnVASxp.js} +1 -1
  144. zenml/zen_server/dashboard/assets/not-found-B4VnX8gK.js +1 -0
  145. zenml/zen_server/dashboard/assets/package-CsUhPmou.js +1 -0
  146. zenml/zen_server/dashboard/assets/{page-BmkSiYeQ.js → page-3efNCDeb.js} +2 -2
  147. zenml/zen_server/dashboard/assets/page-7zTHbhhI.js +1 -0
  148. zenml/zen_server/dashboard/assets/page-BEs6jK71.js +1 -0
  149. zenml/zen_server/dashboard/assets/page-BpSqIf4B.js +1 -0
  150. zenml/zen_server/dashboard/assets/{page-AQKopn_4.js → page-Bx6o0ARS.js} +1 -1
  151. zenml/zen_server/dashboard/assets/page-C43QGHTt.js +9 -0
  152. zenml/zen_server/dashboard/assets/page-CR0OG7ss.js +1 -0
  153. zenml/zen_server/dashboard/assets/page-CRTJ0UuR.js +1 -0
  154. zenml/zen_server/dashboard/assets/page-CUZIGO-3.js +1 -0
  155. zenml/zen_server/dashboard/assets/page-CaopxiU1.js +1 -0
  156. zenml/zen_server/dashboard/assets/{page-CuT1SUik.js → page-Cx67M0QT.js} +1 -1
  157. zenml/zen_server/dashboard/assets/page-D7Z399xy.js +1 -0
  158. zenml/zen_server/dashboard/assets/page-D93kd7Xj.js +1 -0
  159. zenml/zen_server/dashboard/assets/{page-BzVZGExK.js → page-DKlIdAe5.js} +1 -1
  160. zenml/zen_server/dashboard/assets/{page-Bi5AI0S7.js → page-DMOYZppS.js} +1 -1
  161. zenml/zen_server/dashboard/assets/page-DMsSn3dv.js +2 -0
  162. zenml/zen_server/dashboard/assets/{page-BW6Ket3a.js → page-Dc_7KMQE.js} +1 -1
  163. zenml/zen_server/dashboard/assets/page-DvCvroOM.js +1 -0
  164. zenml/zen_server/dashboard/assets/page-Hus2pr9T.js +1 -0
  165. zenml/zen_server/dashboard/assets/page-JyfeDUfu.js +1 -0
  166. zenml/zen_server/dashboard/assets/{page-yN4rZ-ZS.js → page-Sxn82W-5.js} +1 -1
  167. zenml/zen_server/dashboard/assets/page-TKXERe16.js +1 -0
  168. zenml/zen_server/dashboard/assets/page-Xu8JEjSU.js +1 -0
  169. zenml/zen_server/dashboard/assets/{play-circle-DK5QMJyp.js → play-circle-CNtZKDnW.js} +1 -1
  170. zenml/zen_server/dashboard/assets/plus-DOeLmm7C.js +1 -0
  171. zenml/zen_server/dashboard/assets/{terminal-B2ovgWuz.js → terminal-By9cErXc.js} +1 -1
  172. zenml/zen_server/dashboard/assets/{update-server-settings-mutation-0Wgz8pUE.js → update-server-settings-mutation-CR8e3Sir.js} +1 -1
  173. zenml/zen_server/dashboard/assets/{url-6_xv0WJS.js → url-DuQMeqYA.js} +1 -1
  174. zenml/zen_server/dashboard/assets/{zod-DrZvVLjd.js → zod-BhoGpZ63.js} +1 -1
  175. zenml/zen_server/dashboard/index.html +7 -7
  176. zenml/zen_server/dashboard_legacy/asset-manifest.json +4 -4
  177. zenml/zen_server/dashboard_legacy/index.html +1 -1
  178. zenml/zen_server/dashboard_legacy/{precache-manifest.f4abc5b7cfa7d90c1caf5521918e29a8.js → precache-manifest.c8c57fb0d2132b1d3c2119e776b7dfb3.js} +4 -4
  179. zenml/zen_server/dashboard_legacy/service-worker.js +1 -1
  180. zenml/zen_server/dashboard_legacy/static/js/{main.ac2f17d0.chunk.js → main.382439a7.chunk.js} +2 -2
  181. zenml/zen_server/dashboard_legacy/static/js/{main.ac2f17d0.chunk.js.map → main.382439a7.chunk.js.map} +1 -1
  182. zenml/zen_server/deploy/helm/Chart.yaml +1 -1
  183. zenml/zen_server/deploy/helm/README.md +2 -2
  184. zenml/zen_server/feature_gate/zenml_cloud_feature_gate.py +11 -5
  185. zenml/zen_server/pipeline_deployment/utils.py +57 -44
  186. zenml/zen_server/rbac/models.py +1 -0
  187. zenml/zen_server/rbac/utils.py +22 -1
  188. zenml/zen_server/rbac/zenml_cloud_rbac.py +11 -5
  189. zenml/zen_server/routers/actions_endpoints.py +324 -0
  190. zenml/zen_server/routers/stack_deployment_endpoints.py +158 -0
  191. zenml/zen_server/routers/triggers_endpoints.py +30 -158
  192. zenml/zen_server/routers/workspaces_endpoints.py +64 -0
  193. zenml/zen_server/zen_server_api.py +4 -0
  194. zenml/zen_stores/migrations/utils.py +1 -1
  195. zenml/zen_stores/migrations/versions/0.60.0_release.py +23 -0
  196. zenml/zen_stores/migrations/versions/0.61.0_release.py +23 -0
  197. zenml/zen_stores/migrations/versions/0d707865f404_adding_labels_to_stacks.py +30 -0
  198. zenml/zen_stores/migrations/versions/25155145c545_separate_actions_and_triggers.py +228 -0
  199. zenml/zen_stores/rest_zen_store.py +248 -8
  200. zenml/zen_stores/schemas/__init__.py +2 -0
  201. zenml/zen_stores/schemas/action_schemas.py +192 -0
  202. zenml/zen_stores/schemas/stack_schemas.py +10 -0
  203. zenml/zen_stores/schemas/step_run_schemas.py +27 -11
  204. zenml/zen_stores/schemas/trigger_schemas.py +43 -50
  205. zenml/zen_stores/schemas/user_schemas.py +10 -2
  206. zenml/zen_stores/schemas/workspace_schemas.py +5 -0
  207. zenml/zen_stores/sql_zen_store.py +540 -36
  208. zenml/zen_stores/zen_store_interface.py +165 -0
  209. {zenml_nightly-0.58.2.dev20240623.dist-info → zenml_nightly-0.61.0.dev20240712.dist-info}/METADATA +33 -11
  210. {zenml_nightly-0.58.2.dev20240623.dist-info → zenml_nightly-0.61.0.dev20240712.dist-info}/RECORD +213 -193
  211. zenml/zen_server/dashboard/assets/@radix-C9DBgJhe.js +0 -77
  212. zenml/zen_server/dashboard/assets/@tanstack-CEbkxrhX.js +0 -30
  213. zenml/zen_server/dashboard/assets/AwarenessChannel-nXGpmj_f.js +0 -1
  214. zenml/zen_server/dashboard/assets/Cards-nwsvQLVS.js +0 -1
  215. zenml/zen_server/dashboard/assets/Commands-DuIWKg_Q.js +0 -1
  216. zenml/zen_server/dashboard/assets/CopyButton-B_YSm-Ds.js +0 -2
  217. zenml/zen_server/dashboard/assets/DisplayDate-BdguISQF.js +0 -1
  218. zenml/zen_server/dashboard/assets/EmptyState-BkooiGtL.js +0 -1
  219. zenml/zen_server/dashboard/assets/Error-B6M0dPph.js +0 -1
  220. zenml/zen_server/dashboard/assets/Helpbox-BQoqCm04.js +0 -1
  221. zenml/zen_server/dashboard/assets/Infobox-Ce9mefqU.js +0 -1
  222. zenml/zen_server/dashboard/assets/InlineAvatar-DGf3dVhV.js +0 -1
  223. zenml/zen_server/dashboard/assets/PageHeader-DGaemzjc.js +0 -1
  224. zenml/zen_server/dashboard/assets/Pagination-DVYfBCCc.js +0 -1
  225. zenml/zen_server/dashboard/assets/PasswordChecker-DSLBp7Vl.js +0 -1
  226. zenml/zen_server/dashboard/assets/SetPassword-B5s7DJug.js +0 -1
  227. zenml/zen_server/dashboard/assets/SuccessStep-ZzczaM7g.js +0 -1
  228. zenml/zen_server/dashboard/assets/cloud-only-Ba_ShBR5.js +0 -1
  229. zenml/zen_server/dashboard/assets/index-CWJ3xbIf.css +0 -1
  230. zenml/zen_server/dashboard/assets/index-QORVVTMN.js +0 -55
  231. zenml/zen_server/dashboard/assets/index.esm-F7nqy9zY.js +0 -1
  232. zenml/zen_server/dashboard/assets/not-found-Dh2la7kh.js +0 -1
  233. zenml/zen_server/dashboard/assets/page-B-5jAKoO.js +0 -1
  234. zenml/zen_server/dashboard/assets/page-B-vWk8a6.js +0 -1
  235. zenml/zen_server/dashboard/assets/page-B0BrqfS8.js +0 -1
  236. zenml/zen_server/dashboard/assets/page-BQxVFlUl.js +0 -1
  237. zenml/zen_server/dashboard/assets/page-ByrHy6Ss.js +0 -1
  238. zenml/zen_server/dashboard/assets/page-CPtY4Kv_.js +0 -1
  239. zenml/zen_server/dashboard/assets/page-CmmukLsl.js +0 -1
  240. zenml/zen_server/dashboard/assets/page-D2D-7qyr.js +0 -9
  241. zenml/zen_server/dashboard/assets/page-DAQQyLxT.js +0 -1
  242. zenml/zen_server/dashboard/assets/page-DHkUMl_E.js +0 -1
  243. zenml/zen_server/dashboard/assets/page-DZCbwOEs.js +0 -2
  244. zenml/zen_server/dashboard/assets/page-DdaIt20-.js +0 -1
  245. zenml/zen_server/dashboard/assets/page-LqLs24Ot.js +0 -1
  246. zenml/zen_server/dashboard/assets/page-lebv0c7C.js +0 -1
  247. {zenml_nightly-0.58.2.dev20240623.dist-info → zenml_nightly-0.61.0.dev20240712.dist-info}/LICENSE +0 -0
  248. {zenml_nightly-0.58.2.dev20240623.dist-info → zenml_nightly-0.61.0.dev20240712.dist-info}/WHEEL +0 -0
  249. {zenml_nightly-0.58.2.dev20240623.dist-info → zenml_nightly-0.61.0.dev20240712.dist-info}/entry_points.txt +0 -0
@@ -111,12 +111,14 @@ from zenml.enums import (
111
111
  SecretsStoreType,
112
112
  SorterOps,
113
113
  StackComponentType,
114
+ StackDeploymentProvider,
114
115
  StepRunInputArtifactType,
115
116
  StepRunOutputArtifactType,
116
117
  StoreType,
117
118
  TaggableResourceTypes,
118
119
  )
119
120
  from zenml.exceptions import (
121
+ ActionExistsError,
120
122
  AuthorizationException,
121
123
  BackupSecretsStoreNotConfiguredError,
122
124
  EntityExistsError,
@@ -130,6 +132,10 @@ from zenml.exceptions import (
130
132
  from zenml.io import fileio
131
133
  from zenml.logger import get_console_handler, get_logger, get_logging_level
132
134
  from zenml.models import (
135
+ ActionFilter,
136
+ ActionRequest,
137
+ ActionResponse,
138
+ ActionUpdate,
133
139
  APIKeyFilter,
134
140
  APIKeyInternalResponse,
135
141
  APIKeyInternalUpdate,
@@ -159,6 +165,7 @@ from zenml.models import (
159
165
  ComponentRequest,
160
166
  ComponentResponse,
161
167
  ComponentUpdate,
168
+ DeployedStack,
162
169
  EventSourceFilter,
163
170
  EventSourceRequest,
164
171
  EventSourceResponse,
@@ -167,6 +174,7 @@ from zenml.models import (
167
174
  FlavorRequest,
168
175
  FlavorResponse,
169
176
  FlavorUpdate,
177
+ FullStackRequest,
170
178
  LogsResponse,
171
179
  ModelFilter,
172
180
  ModelRequest,
@@ -237,6 +245,8 @@ from zenml.models import (
237
245
  ServiceRequest,
238
246
  ServiceResponse,
239
247
  ServiceUpdate,
248
+ StackDeploymentConfig,
249
+ StackDeploymentInfo,
240
250
  StackFilter,
241
251
  StackRequest,
242
252
  StackResponse,
@@ -289,6 +299,7 @@ from zenml.zen_stores.migrations.alembic import (
289
299
  )
290
300
  from zenml.zen_stores.migrations.utils import MigrationUtils
291
301
  from zenml.zen_stores.schemas import (
302
+ ActionSchema,
292
303
  APIKeySchema,
293
304
  ArtifactSchema,
294
305
  ArtifactVersionSchema,
@@ -1542,12 +1553,18 @@ class SqlZenStore(BaseZenStore):
1542
1553
  revisions_afterwards = self.alembic.current_revisions()
1543
1554
 
1544
1555
  if current_revisions != revisions_afterwards:
1545
- if current_revisions and version.parse(
1546
- current_revisions[0]
1547
- ) < version.parse("0.57.1"):
1548
- # We want to send the missing user enriched events for users
1549
- # which were created pre 0.57.1 and only on one upgrade
1550
- self._should_send_user_enriched_events = True
1556
+ try:
1557
+ if current_revisions and version.parse(
1558
+ current_revisions[0]
1559
+ ) < version.parse("0.57.1"):
1560
+ # We want to send the missing user enriched events for users
1561
+ # which were created pre 0.57.1 and only on one upgrade
1562
+ self._should_send_user_enriched_events = True
1563
+ except version.InvalidVersion:
1564
+ # This can happen if the database is not currently
1565
+ # stamped with an official ZenML version (e.g. in
1566
+ # development environments).
1567
+ pass
1551
1568
 
1552
1569
  self._sync_flavors()
1553
1570
 
@@ -1739,6 +1756,205 @@ class SqlZenStore(BaseZenStore):
1739
1756
 
1740
1757
  self.activate_server(request)
1741
1758
 
1759
+ # -------------------- Actions --------------------
1760
+
1761
+ def _fail_if_action_with_name_exists(
1762
+ self, action_name: str, workspace_id: UUID, session: Session
1763
+ ) -> None:
1764
+ """Raise an exception if an action with same name exists.
1765
+
1766
+ Args:
1767
+ action_name: The name of the action.
1768
+ workspace_id: Workspace ID of the action.
1769
+ session: DB Session.
1770
+
1771
+ Raises:
1772
+ ActionExistsError: If an action with the given name already exists.
1773
+ """
1774
+ existing_domain_action = session.exec(
1775
+ select(ActionSchema)
1776
+ .where(ActionSchema.name == action_name)
1777
+ .where(ActionSchema.workspace_id == workspace_id)
1778
+ ).first()
1779
+ if existing_domain_action is not None:
1780
+ workspace = self._get_workspace_schema(
1781
+ workspace_name_or_id=workspace_id, session=session
1782
+ )
1783
+ raise ActionExistsError(
1784
+ f"Unable to register action with name "
1785
+ f"'{action_name}': Found an existing action with "
1786
+ f"the same name in the active workspace, '{workspace.name}'."
1787
+ )
1788
+
1789
+ def create_action(self, action: ActionRequest) -> ActionResponse:
1790
+ """Create an action.
1791
+
1792
+ Args:
1793
+ action: The action to create.
1794
+
1795
+ Returns:
1796
+ The created action.
1797
+ """
1798
+ with Session(self.engine) as session:
1799
+ self._fail_if_action_with_name_exists(
1800
+ action_name=action.name,
1801
+ workspace_id=action.workspace,
1802
+ session=session,
1803
+ )
1804
+
1805
+ # Verify that the given service account exists
1806
+ self._get_account_schema(
1807
+ account_name_or_id=action.service_account_id,
1808
+ session=session,
1809
+ service_account=True,
1810
+ )
1811
+
1812
+ new_action = ActionSchema.from_request(action)
1813
+ session.add(new_action)
1814
+ session.commit()
1815
+ session.refresh(new_action)
1816
+
1817
+ return new_action.to_model(
1818
+ include_metadata=True, include_resources=True
1819
+ )
1820
+
1821
+ def _get_action(
1822
+ self,
1823
+ action_id: UUID,
1824
+ session: Session,
1825
+ ) -> ActionSchema:
1826
+ """Get an action by ID.
1827
+
1828
+ Args:
1829
+ action_id: The ID of the action to get.
1830
+ session: The DB session.
1831
+
1832
+ Returns:
1833
+ The action schema.
1834
+ """
1835
+ return self._get_schema_by_name_or_id(
1836
+ object_name_or_id=action_id,
1837
+ schema_class=ActionSchema,
1838
+ schema_name="action",
1839
+ session=session,
1840
+ )
1841
+
1842
+ def get_action(
1843
+ self,
1844
+ action_id: UUID,
1845
+ hydrate: bool = True,
1846
+ ) -> ActionResponse:
1847
+ """Get an action by ID.
1848
+
1849
+ Args:
1850
+ action_id: The ID of the action to get.
1851
+ hydrate: Flag deciding whether to hydrate the output model(s)
1852
+ by including metadata fields in the response.
1853
+
1854
+ Returns:
1855
+ The action.
1856
+ """
1857
+ with Session(self.engine) as session:
1858
+ action = self._get_action(action_id=action_id, session=session)
1859
+
1860
+ return action.to_model(
1861
+ include_metadata=hydrate, include_resources=hydrate
1862
+ )
1863
+
1864
+ def list_actions(
1865
+ self,
1866
+ action_filter_model: ActionFilter,
1867
+ hydrate: bool = False,
1868
+ ) -> Page[ActionResponse]:
1869
+ """List all actions matching the given filter criteria.
1870
+
1871
+ Args:
1872
+ action_filter_model: All filter parameters including pagination
1873
+ params.
1874
+ hydrate: Flag deciding whether to hydrate the output model(s)
1875
+ by including metadata fields in the response.
1876
+
1877
+ Returns:
1878
+ A page of actions matching the filter criteria.
1879
+ """
1880
+ with Session(self.engine) as session:
1881
+ query = select(ActionSchema)
1882
+ return self.filter_and_paginate(
1883
+ session=session,
1884
+ query=query,
1885
+ table=ActionSchema,
1886
+ filter_model=action_filter_model,
1887
+ hydrate=hydrate,
1888
+ )
1889
+
1890
+ def update_action(
1891
+ self,
1892
+ action_id: UUID,
1893
+ action_update: ActionUpdate,
1894
+ ) -> ActionResponse:
1895
+ """Update an existing action.
1896
+
1897
+ Args:
1898
+ action_id: The ID of the action to update.
1899
+ action_update: The update to be applied to the action.
1900
+
1901
+ Returns:
1902
+ The updated action.
1903
+ """
1904
+ with Session(self.engine) as session:
1905
+ action = self._get_action(session=session, action_id=action_id)
1906
+
1907
+ if action_update.service_account_id:
1908
+ # Verify that the given service account exists
1909
+ self._get_account_schema(
1910
+ account_name_or_id=action_update.service_account_id,
1911
+ session=session,
1912
+ service_account=True,
1913
+ )
1914
+
1915
+ # In case of a renaming update, make sure no action already exists
1916
+ # with that name
1917
+ if action_update.name:
1918
+ if action.name != action_update.name:
1919
+ self._fail_if_action_with_name_exists(
1920
+ action_name=action_update.name,
1921
+ workspace_id=action.workspace.id,
1922
+ session=session,
1923
+ )
1924
+
1925
+ action.update(action_update=action_update)
1926
+ session.add(action)
1927
+ session.commit()
1928
+
1929
+ session.refresh(action)
1930
+
1931
+ return action.to_model(
1932
+ include_metadata=True, include_resources=True
1933
+ )
1934
+
1935
+ def delete_action(self, action_id: UUID) -> None:
1936
+ """Delete an action.
1937
+
1938
+ Args:
1939
+ action_id: The ID of the action to delete.
1940
+
1941
+ Raises:
1942
+ IllegalOperationError: If the action can't be deleted
1943
+ because it's used by triggers.
1944
+ """
1945
+ with Session(self.engine) as session:
1946
+ action = self._get_action(action_id=action_id, session=session)
1947
+
1948
+ # Prevent deletion of action if it is used by a trigger
1949
+ if action.triggers:
1950
+ raise IllegalOperationError(
1951
+ f"Unable to delete action with ID `{action_id}` "
1952
+ f"as it is used by {len(action.triggers)} triggers."
1953
+ )
1954
+
1955
+ session.delete(action)
1956
+ session.commit()
1957
+
1742
1958
  # ------------------------- API Keys -------------------------
1743
1959
 
1744
1960
  def _get_api_key(
@@ -4183,11 +4399,9 @@ class SqlZenStore(BaseZenStore):
4183
4399
  event_source: The event_source to create.
4184
4400
  session: The Session
4185
4401
 
4186
- Returns:
4187
- None
4188
-
4189
4402
  Raises:
4190
- EventSourceExistsError: In case the event source already exists
4403
+ EventSourceExistsError: If an event source with the given name
4404
+ already exists.
4191
4405
  """
4192
4406
  existing_domain_event_source = session.exec(
4193
4407
  select(EventSourceSchema)
@@ -4203,7 +4417,6 @@ class SqlZenStore(BaseZenStore):
4203
4417
  f"'{event_source.name}': Found an existing event source with "
4204
4418
  f"the same name in the active workspace, '{workspace.name}'."
4205
4419
  )
4206
- return None
4207
4420
 
4208
4421
  def create_event_source(
4209
4422
  self, event_source: EventSourceRequest
@@ -4269,7 +4482,7 @@ class SqlZenStore(BaseZenStore):
4269
4482
  with Session(self.engine) as session:
4270
4483
  return self._get_event_source(
4271
4484
  event_source_id=event_source_id, session=session
4272
- ).to_model(include_metadata=hydrate, include_resources=True)
4485
+ ).to_model(include_metadata=hydrate, include_resources=hydrate)
4273
4486
 
4274
4487
  def list_event_sources(
4275
4488
  self,
@@ -4333,6 +4546,8 @@ class SqlZenStore(BaseZenStore):
4333
4546
 
4334
4547
  Raises:
4335
4548
  KeyError: if the event_source doesn't exist.
4549
+ IllegalOperationError: If the event source can't be deleted
4550
+ because it's used by triggers.
4336
4551
  """
4337
4552
  with Session(self.engine) as session:
4338
4553
  event_source = self._get_event_source(
@@ -4343,12 +4558,17 @@ class SqlZenStore(BaseZenStore):
4343
4558
  f"Unable to delete event_source with ID `{event_source_id}`: "
4344
4559
  f"No event_source with this ID found."
4345
4560
  )
4561
+
4562
+ # Prevent deletion of event source if it is used by a trigger
4563
+ if event_source.triggers:
4564
+ raise IllegalOperationError(
4565
+ f"Unable to delete event_source with ID `{event_source_id}`"
4566
+ f" as it is used by {len(event_source.triggers)} triggers."
4567
+ )
4568
+
4346
4569
  session.delete(event_source)
4347
4570
  session.commit()
4348
4571
 
4349
- # TODO: catch and throw proper error if it can't be deleted due to
4350
- # not-null constraints on triggers
4351
-
4352
4572
  # ----------------------------- Pipeline runs -----------------------------
4353
4573
 
4354
4574
  def create_run(
@@ -6702,6 +6922,9 @@ class SqlZenStore(BaseZenStore):
6702
6922
  name=stack.name,
6703
6923
  description=stack.description,
6704
6924
  components=defined_components,
6925
+ labels=base64.b64encode(
6926
+ json.dumps(stack.labels).encode("utf-8")
6927
+ ),
6705
6928
  )
6706
6929
 
6707
6930
  session.add(new_stack_schema)
@@ -6710,6 +6933,223 @@ class SqlZenStore(BaseZenStore):
6710
6933
 
6711
6934
  return new_stack_schema.to_model(include_metadata=True)
6712
6935
 
6936
+ def create_full_stack(self, full_stack: FullStackRequest) -> StackResponse:
6937
+ """Register a full stack.
6938
+
6939
+ Args:
6940
+ full_stack: The full stack configuration.
6941
+
6942
+ Returns:
6943
+ The registered stack.
6944
+
6945
+ Raises:
6946
+ ValueError: If the full stack creation fails, due to the corrupted
6947
+ input.
6948
+ RuntimeError: If the full stack creation fails, due to unforeseen
6949
+ errors.
6950
+ """
6951
+ # For clean-up purposes, each created entity is tracked here
6952
+ service_connectors_created_ids: List[UUID] = []
6953
+ components_created_ids: List[UUID] = []
6954
+
6955
+ try:
6956
+ # Validate the name of the new stack
6957
+ validate_name(full_stack)
6958
+
6959
+ if full_stack.labels is None:
6960
+ full_stack.labels = {}
6961
+
6962
+ full_stack.labels.update({"zenml:full_stack": True})
6963
+
6964
+ # Service Connectors
6965
+ service_connectors: List[ServiceConnectorResponse] = []
6966
+
6967
+ for connector_id_or_info in full_stack.service_connectors:
6968
+ # Fetch an existing service connector
6969
+ if isinstance(connector_id_or_info, UUID):
6970
+ service_connectors.append(
6971
+ self.get_service_connector(connector_id_or_info)
6972
+ )
6973
+ # Create a new service connector
6974
+ else:
6975
+ connector_name = full_stack.name
6976
+ while True:
6977
+ try:
6978
+ service_connector_request = ServiceConnectorRequest(
6979
+ name=connector_name,
6980
+ connector_type=connector_id_or_info.type,
6981
+ auth_method=connector_id_or_info.auth_method,
6982
+ configuration=connector_id_or_info.configuration,
6983
+ user=full_stack.user,
6984
+ workspace=full_stack.workspace,
6985
+ labels={
6986
+ k: str(v)
6987
+ for k, v in full_stack.labels.items()
6988
+ },
6989
+ )
6990
+ service_connector_response = (
6991
+ self.create_service_connector(
6992
+ service_connector=service_connector_request
6993
+ )
6994
+ )
6995
+ service_connectors.append(
6996
+ service_connector_response
6997
+ )
6998
+ service_connectors_created_ids.append(
6999
+ service_connector_response.id
7000
+ )
7001
+ break
7002
+ except EntityExistsError:
7003
+ connector_name = (
7004
+ f"{full_stack.name}-{random_str(4)}".lower()
7005
+ )
7006
+ continue
7007
+
7008
+ # Stack Components
7009
+ components_mapping: Dict[StackComponentType, List[UUID]] = {}
7010
+ for (
7011
+ component_type,
7012
+ component_info,
7013
+ ) in full_stack.components.items():
7014
+ # Fetch an existing component
7015
+ if isinstance(component_info, UUID):
7016
+ component = self.get_stack_component(
7017
+ component_id=component_info
7018
+ )
7019
+ # Create a new component
7020
+ else:
7021
+ flavor_list = self.list_flavors(
7022
+ flavor_filter_model=FlavorFilter(
7023
+ name=component_info.flavor,
7024
+ type=component_type,
7025
+ )
7026
+ )
7027
+ if not len(flavor_list):
7028
+ raise ValueError(
7029
+ f"Flavor '{component_info.flavor}' not found "
7030
+ f"for component type '{component_type}'."
7031
+ )
7032
+
7033
+ flavor_model = flavor_list[0]
7034
+
7035
+ component_name = full_stack.name
7036
+ while True:
7037
+ try:
7038
+ component_request = ComponentRequest(
7039
+ name=component_name,
7040
+ type=component_type,
7041
+ flavor=component_info.flavor,
7042
+ configuration=component_info.configuration,
7043
+ user=full_stack.user,
7044
+ workspace=full_stack.workspace,
7045
+ labels=full_stack.labels,
7046
+ )
7047
+ component = self.create_stack_component(
7048
+ component=component_request
7049
+ )
7050
+ components_created_ids.append(component.id)
7051
+ break
7052
+ except EntityExistsError:
7053
+ component_name = (
7054
+ f"{full_stack.name}-{random_str(4)}".lower()
7055
+ )
7056
+ continue
7057
+
7058
+ if component_info.service_connector_index is not None:
7059
+ service_connector = service_connectors[
7060
+ component_info.service_connector_index
7061
+ ]
7062
+
7063
+ requirements = flavor_model.connector_requirements
7064
+
7065
+ if not requirements:
7066
+ raise ValueError(
7067
+ f"The '{flavor_model.name}' implementation "
7068
+ "does not support using a service connector to "
7069
+ "connect to resources."
7070
+ )
7071
+
7072
+ if component_info.service_connector_resource_id:
7073
+ resource_id = (
7074
+ component_info.service_connector_resource_id
7075
+ )
7076
+ else:
7077
+ resource_id = None
7078
+ resource_type = requirements.resource_type
7079
+ if requirements.resource_id_attr is not None:
7080
+ resource_id = component_info.configuration.get(
7081
+ requirements.resource_id_attr
7082
+ )
7083
+
7084
+ satisfied, msg = requirements.is_satisfied_by(
7085
+ connector=service_connector,
7086
+ component=component,
7087
+ )
7088
+
7089
+ if not satisfied:
7090
+ raise ValueError(
7091
+ "Please pick a connector that is "
7092
+ "compatible with the component flavor and "
7093
+ "try again.."
7094
+ )
7095
+
7096
+ if not resource_id:
7097
+ if service_connector.resource_id:
7098
+ resource_id = service_connector.resource_id
7099
+ elif service_connector.supports_instances:
7100
+ raise ValueError(
7101
+ f"Multiple {resource_type} resources "
7102
+ "are available for the selected "
7103
+ "connector. Please use a `resource_id` "
7104
+ "to configure a "
7105
+ f"{resource_type} resource."
7106
+ )
7107
+
7108
+ component_update = ComponentUpdate(
7109
+ connector=service_connector.id,
7110
+ connector_resource_id=resource_id,
7111
+ )
7112
+ self.update_stack_component(
7113
+ component_id=component.id,
7114
+ component_update=component_update,
7115
+ )
7116
+
7117
+ components_mapping[component_type] = [
7118
+ component.id,
7119
+ ]
7120
+
7121
+ # Stack
7122
+ stack_name = full_stack.name
7123
+ while True:
7124
+ try:
7125
+ stack_request = StackRequest(
7126
+ user=full_stack.user,
7127
+ workspace=full_stack.workspace,
7128
+ name=stack_name,
7129
+ description=full_stack.description,
7130
+ components=components_mapping,
7131
+ labels=full_stack.labels,
7132
+ )
7133
+ stack_response = self.create_stack(stack_request)
7134
+
7135
+ break
7136
+ except EntityExistsError:
7137
+ stack_name = f"{full_stack.name}-{random_str(4)}".lower()
7138
+
7139
+ return stack_response
7140
+
7141
+ except Exception as e:
7142
+ for component_id in components_created_ids:
7143
+ self.delete_stack_component(component_id=component_id)
7144
+ for service_connector_id in service_connectors_created_ids:
7145
+ self.delete_service_connector(
7146
+ service_connector_id=service_connector_id
7147
+ )
7148
+ raise RuntimeError(
7149
+ f"Full Stack creation has failed {e}. Cleaning up the "
7150
+ f"created entities."
7151
+ ) from e
7152
+
6713
7153
  def get_stack(self, stack_id: UUID, hydrate: bool = True) -> StackResponse:
6714
7154
  """Get a stack by its unique ID.
6715
7155
 
@@ -6986,6 +7426,69 @@ class SqlZenStore(BaseZenStore):
6986
7426
  workspace_id=workspace.id,
6987
7427
  )
6988
7428
 
7429
+ # ---------------- Stack deployments-----------------
7430
+
7431
+ def get_stack_deployment_info(
7432
+ self,
7433
+ provider: StackDeploymentProvider,
7434
+ ) -> StackDeploymentInfo:
7435
+ """Get information about a stack deployment provider.
7436
+
7437
+ Args:
7438
+ provider: The stack deployment provider.
7439
+
7440
+ Raises:
7441
+ NotImplementedError: Stack deployments are not supported by the
7442
+ local ZenML deployment.
7443
+ """
7444
+ raise NotImplementedError(
7445
+ "Stack deployments are not supported by local ZenML deployments."
7446
+ )
7447
+
7448
+ def get_stack_deployment_config(
7449
+ self,
7450
+ provider: StackDeploymentProvider,
7451
+ stack_name: str,
7452
+ location: Optional[str] = None,
7453
+ ) -> StackDeploymentConfig:
7454
+ """Return the cloud provider console URL and configuration needed to deploy the ZenML stack.
7455
+
7456
+ Args:
7457
+ provider: The stack deployment provider.
7458
+ stack_name: The name of the stack.
7459
+ location: The location where the stack should be deployed.
7460
+
7461
+ Raises:
7462
+ NotImplementedError: Stack deployments are not supported by the
7463
+ local ZenML deployment.
7464
+ """
7465
+ raise NotImplementedError(
7466
+ "Stack deployments are not supported by local ZenML deployments."
7467
+ )
7468
+
7469
+ def get_stack_deployment_stack(
7470
+ self,
7471
+ provider: StackDeploymentProvider,
7472
+ stack_name: str,
7473
+ location: Optional[str] = None,
7474
+ date_start: Optional[datetime] = None,
7475
+ ) -> Optional[DeployedStack]:
7476
+ """Return a matching ZenML stack that was deployed and registered.
7477
+
7478
+ Args:
7479
+ provider: The stack deployment provider.
7480
+ stack_name: The name of the stack.
7481
+ location: The location where the stack should be deployed.
7482
+ date_start: The date when the deployment started.
7483
+
7484
+ Raises:
7485
+ NotImplementedError: Stack deployments are not supported by the
7486
+ local ZenML deployment.
7487
+ """
7488
+ raise NotImplementedError(
7489
+ "Stack deployments are not supported by local ZenML deployments."
7490
+ )
7491
+
6989
7492
  # ----------------------------- Step runs -----------------------------
6990
7493
 
6991
7494
  def create_run_step(self, step_run: StepRunRequest) -> StepRunResponse:
@@ -7478,19 +7981,19 @@ class SqlZenStore(BaseZenStore):
7478
7981
  The newly created trigger.
7479
7982
  """
7480
7983
  with Session(self.engine) as session:
7481
- # Verify that the given event_source exists
7482
- self._get_event_source(
7483
- event_source_id=trigger.event_source_id, session=session
7484
- )
7984
+ # Verify that the given action exists
7985
+ self._get_action(action_id=trigger.action_id, session=session)
7485
7986
 
7486
- # Verify that the given service account exists
7487
- self._get_account_schema(
7488
- account_name_or_id=trigger.service_account_id,
7489
- session=session,
7490
- service_account=True,
7491
- )
7987
+ if trigger.event_source_id:
7988
+ # Verify that the given event_source exists
7989
+ self._get_event_source(
7990
+ event_source_id=trigger.event_source_id, session=session
7991
+ )
7992
+
7993
+ # Verify that the action exists
7994
+ self._get_action(action_id=trigger.action_id, session=session)
7492
7995
 
7493
- # Verify that the trigger won't validate Unique
7996
+ # Verify that the trigger name is unique
7494
7997
  self._fail_if_trigger_with_name_exists(
7495
7998
  trigger_name=trigger.name,
7496
7999
  workspace_id=trigger.workspace,
@@ -7520,7 +8023,7 @@ class SqlZenStore(BaseZenStore):
7520
8023
  The trigger with the given ID.
7521
8024
 
7522
8025
  Raises:
7523
- KeyError: if the trigger doesn't exist.
8026
+ KeyError: If the trigger doesn't exist.
7524
8027
  """
7525
8028
  with Session(self.engine) as session:
7526
8029
  trigger = session.exec(
@@ -7573,7 +8076,8 @@ class SqlZenStore(BaseZenStore):
7573
8076
  The updated trigger.
7574
8077
 
7575
8078
  Raises:
7576
- KeyError: if the trigger doesn't exist.
8079
+ KeyError: If the trigger doesn't exist.
8080
+ ValueError: If both a schedule and an event source are provided.
7577
8081
  """
7578
8082
  with Session(self.engine) as session:
7579
8083
  # Check if trigger with the domain key (name, workspace, owner)
@@ -7583,16 +8087,16 @@ class SqlZenStore(BaseZenStore):
7583
8087
  ).first()
7584
8088
  if existing_trigger is None:
7585
8089
  raise KeyError(
7586
- f"Unable to update trigger with id '{trigger_id}': Found no"
7587
- f"existing trigger with this id."
8090
+ f"Unable to update trigger with id '{trigger_id}': No "
8091
+ f"existing trigger with this id exists."
7588
8092
  )
7589
8093
 
7590
- if trigger_update.service_account_id:
7591
- # Verify that the given service account exists
7592
- self._get_account_schema(
7593
- account_name_or_id=trigger_update.service_account_id,
7594
- session=session,
7595
- service_account=True,
8094
+ # Verify that either a schedule or an event source is provided, not
8095
+ # both
8096
+ if existing_trigger.event_source and trigger_update.schedule:
8097
+ raise ValueError(
8098
+ "Unable to update trigger: A trigger cannot have both a "
8099
+ "schedule and an event source."
7596
8100
  )
7597
8101
 
7598
8102
  # In case of a renaming update, make sure no trigger already exists