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
@@ -31,6 +31,9 @@ class KubeflowIntegration(Integration):
31
31
 
32
32
  NAME = KUBEFLOW
33
33
  REQUIREMENTS = ["kfp>=2.6.0", "kfp-kubernetes>=1.1.0"] # Only 1.x version that supports pyyaml 6
34
+ REQUIREMENTS_IGNORED_ON_UNINSTALL = [
35
+ "kfp", # it is used by GCP as well
36
+ ]
34
37
 
35
38
  @classmethod
36
39
  def flavors(cls) -> List[Type[Flavor]]:
@@ -149,7 +149,7 @@ class KubeflowOrchestratorConfig(
149
149
 
150
150
  kubeflow_hostname: Optional[str] = None
151
151
  kubeflow_namespace: str = "kubeflow"
152
- kubernetes_context: Optional[str] # TODO: Potential setting
152
+ kubernetes_context: Optional[str] = None # TODO: Potential setting
153
153
 
154
154
  @model_validator(mode="before")
155
155
  @classmethod
@@ -433,7 +433,6 @@ class KubeflowOrchestrator(ContainerizedOrchestrator):
433
433
  The dynamic container component.
434
434
  """
435
435
 
436
- @dsl.container_component # type: ignore[misc]
437
436
  def dynamic_container_component() -> dsl.ContainerSpec:
438
437
  """Dynamic container component.
439
438
 
@@ -31,7 +31,9 @@ class KubernetesIntegration(Integration):
31
31
 
32
32
  NAME = KUBERNETES
33
33
  REQUIREMENTS = ["kubernetes>=21.7,<26"]
34
-
34
+ REQUIREMENTS_IGNORED_ON_UNINSTALL = [
35
+ "kfp", # it is used by many others
36
+ ]
35
37
  @classmethod
36
38
  def flavors(cls) -> List[Type[Flavor]]:
37
39
  """Declare the stack component flavors for the Kubernetes integration.
@@ -225,8 +225,11 @@ def wait_pod(
225
225
  response = core_api.read_namespaced_pod_log(
226
226
  name=pod_name,
227
227
  namespace=namespace,
228
+ _preload_content=False,
228
229
  )
229
- logs = response.splitlines()
230
+ raw_data = response.data
231
+ decoded_log = raw_data.decode("utf-8", errors="replace")
232
+ logs = decoded_log.splitlines()
230
233
  if len(logs) > logged_lines:
231
234
  for line in logs[logged_lines:]:
232
235
  logger.info(line)
@@ -527,6 +527,7 @@ class LabelStudioAnnotator(BaseAnnotator, AuthenticationMixin):
527
527
  aws_access_key_id,
528
528
  aws_secret_access_key,
529
529
  aws_session_token,
530
+ _,
530
531
  ) = artifact_store.get_credentials()
531
532
 
532
533
  if aws_access_key_id and aws_secret_access_key:
@@ -30,6 +30,7 @@ class LangchainIntegration(Integration):
30
30
  "pyyaml>=6.0.1",
31
31
  "tenacity!=8.4.0", # https://github.com/jd/tenacity/issues/471
32
32
  ]
33
+ REQUIREMENTS_IGNORED_ON_UNINSTALL = ["pyyaml","tenacity"]
33
34
 
34
35
  @classmethod
35
36
  def activate(cls) -> None:
@@ -33,7 +33,7 @@ class MlflowIntegration(Integration):
33
33
  NAME = MLFLOW
34
34
 
35
35
  REQUIREMENTS = [
36
- "mlflow>=2.1.1,<=2.12.2",
36
+ "mlflow>=2.1.1,<=2.14.1",
37
37
  "mlserver>=1.3.3",
38
38
  "mlserver-mlflow>=1.3.3",
39
39
  # TODO: remove this requirement once rapidjson is fixed
@@ -45,9 +45,11 @@ class MlflowIntegration(Integration):
45
45
  # This downgrades pydantic to v1 even though mlflow does not have
46
46
  # any issues with v2. This is why we have to pin it here so a downgrade
47
47
  # will not happen.
48
- "pydantic>=2.7.0,<2.8.0"
48
+ "pydantic>=2.7.0,<2.8.0",
49
49
  ]
50
50
 
51
+ REQUIREMENTS_IGNORED_ON_UNINSTALL = ["python-rapidjson", "pydantic"]
52
+
51
53
  @classmethod
52
54
  def activate(cls) -> None:
53
55
  """Activate the MLflow integration."""
@@ -26,6 +26,7 @@ class NeuralProphetIntegration(Integration):
26
26
  "holidays>=0.4.1,<0.25.0",
27
27
  "tenacity!=8.4.0", # https://github.com/jd/tenacity/issues/471
28
28
  ]
29
+ REQUIREMENTS_IGNORED_ON_UNINSTALL = ["tenacity"]
29
30
 
30
31
  @classmethod
31
32
  def activate(cls) -> None:
@@ -25,6 +25,7 @@ class PolarsIntegration(Integration):
25
25
  "polars>=0.19.5",
26
26
  "pyarrow>=12.0.0"
27
27
  ]
28
+ REQUIREMENTS_IGNORED_ON_UNINSTALL = ["pyarrow"]
28
29
 
29
30
  @classmethod
30
31
  def activate(cls) -> None:
@@ -29,6 +29,7 @@ class ProdigyIntegration(Integration):
29
29
  "prodigy",
30
30
  "urllib3<2",
31
31
  ]
32
+ REQUIREMENTS_IGNORED_ON_UNINSTALL = ["urllib3"]
32
33
 
33
34
  @classmethod
34
35
  def flavors(cls) -> List[Type[Flavor]]:
@@ -28,6 +28,12 @@ class PyCaretIntegration(Integration):
28
28
  "catboost",
29
29
  "lightgbm",
30
30
  ]
31
+ REQUIREMENTS_IGNORED_ON_UNINSTALL = [
32
+ "scikit-learn",
33
+ "xgboost",
34
+ "catboost",
35
+ "lightgbm",
36
+ ]
31
37
 
32
38
  @classmethod
33
39
  def activate(cls) -> None:
@@ -124,6 +124,43 @@ class IntegrationRegistry(object):
124
124
  )
125
125
  ]
126
126
 
127
+ def select_uninstall_requirements(
128
+ self,
129
+ integration_name: Optional[str] = None,
130
+ target_os: Optional[str] = None,
131
+ ) -> List[str]:
132
+ """Select the uninstall requirements for a given integration or all integrations.
133
+
134
+ Args:
135
+ integration_name: Name of the integration to check.
136
+ target_os: Target OS for the requirements.
137
+
138
+ Returns:
139
+ List of requirements for the integration uninstall.
140
+
141
+ Raises:
142
+ KeyError: If the integration is not found.
143
+ """
144
+ if integration_name:
145
+ if integration_name in self.list_integration_names:
146
+ return self._integrations[
147
+ integration_name
148
+ ].get_uninstall_requirements(target_os=target_os)
149
+ else:
150
+ raise KeyError(
151
+ f"Version {integration_name} does not exist. "
152
+ f"Currently the following integrations are implemented. "
153
+ f"{self.list_integration_names}"
154
+ )
155
+ else:
156
+ return [
157
+ requirement
158
+ for name in self.list_integration_names
159
+ for requirement in self._integrations[
160
+ name
161
+ ].get_uninstall_requirements(target_os=target_os)
162
+ ]
163
+
127
164
  def is_installed(self, integration_name: Optional[str] = None) -> bool:
128
165
  """Checks if all requirements for an integration are installed.
129
166
 
@@ -26,6 +26,7 @@ from typing import (
26
26
  )
27
27
 
28
28
  import s3fs
29
+ from fsspec.asyn import FSTimeoutError, sync, sync_wrapper
29
30
 
30
31
  from zenml.artifact_stores import BaseArtifactStore
31
32
  from zenml.integrations.s3.flavors.s3_artifact_store_flavor import (
@@ -38,10 +39,77 @@ from zenml.stack.authentication_mixin import AuthenticationMixin
38
39
  PathType = Union[bytes, str]
39
40
 
40
41
 
42
+ class ZenMLS3Filesystem(s3fs.S3FileSystem): # type: ignore[misc]
43
+ """Modified s3fs.S3FileSystem to disable caching.
44
+
45
+ The original s3fs.S3FileSystem caches all class instances based on the
46
+ constructor input arguments and it never releases them. This is problematic
47
+ in the context of the ZenML server, because the server is a long-running
48
+ process that instantiates many S3 filesystems with different credentials,
49
+ especially when the credentials are generated by service connectors.
50
+
51
+ The caching behavior of s3fs causes the server to slowly consume more and
52
+ more memory over time until it crashes. This class disables the caching
53
+ behavior of s3fs by setting the `cachable` attribute to `False`.
54
+
55
+ In addition to disabling instance caching, this class also provides a
56
+ correct cleanup implementation by overriding the `close_session` method
57
+ the S3 aiobotocore client. The original one provided by s3fs was causing
58
+ memory leaks by creating a new event loop in the destructor instead of
59
+ using the existing one.
60
+
61
+ A `close` method is also provided to allow for synchronous on-demand cleanup
62
+ of the S3 client.
63
+ """
64
+
65
+ cachable = False
66
+
67
+ async def _close(self) -> None:
68
+ """Close the S3 client."""
69
+ if self._s3creator is not None: # type: ignore[has-type]
70
+ await self._s3creator.__aexit__(None, None, None) # type: ignore[has-type]
71
+ self._s3creator = None
72
+ self._s3 = None
73
+
74
+ close = sync_wrapper(_close)
75
+
76
+ @staticmethod
77
+ def close_session(loop: Any, s3: Any) -> None:
78
+ """Close the S3 client session.
79
+
80
+ Args:
81
+ loop: The event loop to use for closing the session.
82
+ s3: The S3 client to close.
83
+ """
84
+ # IMPORTANT: This method is a copy of the original close_session method
85
+ # from s3fs.S3FileSystem. The only difference is that it uses the
86
+ # provided event loop instead of creating a new one.
87
+ if loop is not None and loop.is_running():
88
+ try:
89
+ # NOTE: this is the line in the original method that causes
90
+ # the memory leak
91
+ # loop = asyncio.get_event_loop()
92
+ loop.create_task(s3.__aexit__(None, None, None))
93
+ return
94
+ except RuntimeError:
95
+ pass
96
+ try:
97
+ sync(loop, s3.__aexit__, None, None, None, timeout=0.1)
98
+ return
99
+ except FSTimeoutError:
100
+ pass
101
+ try:
102
+ # close the actual socket
103
+ s3._client._endpoint.http_session._connector._close()
104
+ except AttributeError:
105
+ # but during shutdown, it may have gone
106
+ pass
107
+
108
+
41
109
  class S3ArtifactStore(BaseArtifactStore, AuthenticationMixin):
42
110
  """Artifact Store for S3 based artifacts."""
43
111
 
44
- _filesystem: Optional[s3fs.S3FileSystem] = None
112
+ _filesystem: Optional[ZenMLS3Filesystem] = None
45
113
 
46
114
  @property
47
115
  def config(self) -> S3ArtifactStoreConfig:
@@ -54,7 +122,7 @@ class S3ArtifactStore(BaseArtifactStore, AuthenticationMixin):
54
122
 
55
123
  def get_credentials(
56
124
  self,
57
- ) -> Tuple[Optional[str], Optional[str], Optional[str]]:
125
+ ) -> Tuple[Optional[str], Optional[str], Optional[str], Optional[str]]:
58
126
  """Gets authentication credentials.
59
127
 
60
128
  If an authentication secret is configured, the secret values are
@@ -62,8 +130,8 @@ class S3ArtifactStore(BaseArtifactStore, AuthenticationMixin):
62
130
  attributes.
63
131
 
64
132
  Returns:
65
- Tuple (key, secret, token) of credentials used to authenticate with
66
- the S3 filesystem.
133
+ Tuple (key, secret, token, region) of credentials used to
134
+ authenticate with the S3 filesystem.
67
135
 
68
136
  Raises:
69
137
  RuntimeError: If the AWS connector behaves unexpectedly.
@@ -83,6 +151,7 @@ class S3ArtifactStore(BaseArtifactStore, AuthenticationMixin):
83
151
  credentials.access_key,
84
152
  credentials.secret_key,
85
153
  credentials.token,
154
+ client.meta.region_name,
86
155
  )
87
156
 
88
157
  secret = self.get_typed_authentication_secret(
@@ -93,12 +162,13 @@ class S3ArtifactStore(BaseArtifactStore, AuthenticationMixin):
93
162
  secret.aws_access_key_id,
94
163
  secret.aws_secret_access_key,
95
164
  secret.aws_session_token,
165
+ None,
96
166
  )
97
167
  else:
98
- return self.config.key, self.config.secret, self.config.token
168
+ return self.config.key, self.config.secret, self.config.token, None
99
169
 
100
170
  @property
101
- def filesystem(self) -> s3fs.S3FileSystem:
171
+ def filesystem(self) -> ZenMLS3Filesystem:
102
172
  """The s3 filesystem to access this artifact store.
103
173
 
104
174
  Returns:
@@ -108,18 +178,32 @@ class S3ArtifactStore(BaseArtifactStore, AuthenticationMixin):
108
178
  if self._filesystem and not self.connector_has_expired():
109
179
  return self._filesystem
110
180
 
111
- key, secret, token = self.get_credentials()
181
+ key, secret, token, region = self.get_credentials()
182
+
183
+ # Use the region from the connector if available, otherwise some
184
+ # remote workloads (e.g. Sagemaker) might not work correctly because
185
+ # they look for the bucket in the wrong region
186
+ client_kwargs = {}
187
+ if region:
188
+ client_kwargs["region_name"] = region
189
+ if self.config.client_kwargs:
190
+ client_kwargs.update(self.config.client_kwargs)
112
191
 
113
- self._filesystem = s3fs.S3FileSystem(
192
+ self._filesystem = ZenMLS3Filesystem(
114
193
  key=key,
115
194
  secret=secret,
116
195
  token=token,
117
- client_kwargs=self.config.client_kwargs,
196
+ client_kwargs=client_kwargs,
118
197
  config_kwargs=self.config.config_kwargs,
119
198
  s3_additional_kwargs=self.config.s3_additional_kwargs,
120
199
  )
121
200
  return self._filesystem
122
201
 
202
+ def cleanup(self) -> None:
203
+ """Close the filesystem."""
204
+ if self._filesystem:
205
+ self._filesystem.close()
206
+
123
207
  def open(self, path: PathType, mode: str = "r") -> Any:
124
208
  """Open a file at the given path.
125
209
 
@@ -33,6 +33,7 @@ class SeldonIntegration(Integration):
33
33
  REQUIREMENTS = [
34
34
  "kubernetes==18.20.0",
35
35
  ]
36
+ REQUIREMENTS_IGNORED_ON_UNINSTALL = ["kubernetes"]
36
37
 
37
38
  @classmethod
38
39
  def activate(cls) -> None:
@@ -290,6 +290,7 @@ class SeldonModelDeployer(BaseModelDeployer):
290
290
  assert isinstance(artifact_store, S3ArtifactStore)
291
291
 
292
292
  (
293
+ region_name,
293
294
  aws_access_key_id,
294
295
  aws_secret_access_key,
295
296
  aws_session_token,
@@ -43,7 +43,7 @@ class SkypilotBaseOrchestratorSettings(BaseSettings):
43
43
  `{'tpu_vm': True, 'runtime_version': 'tpu-vm-base'}` for TPUs.
44
44
  use_spot: whether to use spot instances. If None, defaults to
45
45
  False.
46
- spot_recovery: the spot recovery strategy to use for the managed
46
+ job_recovery: the spot recovery strategy to use for the managed
47
47
  spot to recover the cluster from preemption. Refer to
48
48
  `recovery_strategy module <https://github.com/skypilot-org/skypilot/blob/master/sky/spot/recovery_strategy.py>`__ # pylint: disable=line-too-long
49
49
  for more details.
@@ -103,7 +103,7 @@ class SkypilotBaseOrchestratorSettings(BaseSettings):
103
103
  )
104
104
  accelerator_args: Optional[Dict[str, str]] = None
105
105
  use_spot: Optional[bool] = None
106
- spot_recovery: Optional[str] = None
106
+ job_recovery: Optional[str] = None
107
107
  region: Optional[str] = None
108
108
  zone: Optional[str] = None
109
109
  image_id: Union[Dict[str, str], str, None] = Field(
@@ -303,7 +303,7 @@ class SkypilotBaseOrchestrator(ContainerizedOrchestrator):
303
303
  accelerators=settings.accelerators,
304
304
  accelerator_args=settings.accelerator_args,
305
305
  use_spot=settings.use_spot,
306
- spot_recovery=settings.spot_recovery,
306
+ job_recovery=settings.job_recovery,
307
307
  region=settings.region,
308
308
  zone=settings.zone,
309
309
  image_id=settings.image_id,
@@ -136,7 +136,7 @@ def main() -> None:
136
136
  settings.disk_size, # Assuming disk_size is part of the settings
137
137
  settings.disk_tier, # Assuming disk_tier is part of the settings
138
138
  settings.use_spot,
139
- settings.spot_recovery,
139
+ settings.job_recovery,
140
140
  settings.region,
141
141
  settings.zone,
142
142
  accelerators_hashable,
@@ -213,7 +213,7 @@ def main() -> None:
213
213
  accelerators=settings.accelerators,
214
214
  accelerator_args=settings.accelerator_args,
215
215
  use_spot=settings.use_spot,
216
- spot_recovery=settings.spot_recovery,
216
+ job_recovery=settings.job_recovery,
217
217
  region=settings.region,
218
218
  zone=settings.zone,
219
219
  image_id=settings.image_id,
@@ -31,7 +31,8 @@ class SkypilotAWSIntegration(Integration):
31
31
  """Definition of Skypilot AWS Integration for ZenML."""
32
32
 
33
33
  NAME = SKYPILOT_AWS
34
- REQUIREMENTS = ["skypilot[aws]<=0.5.0"]
34
+ # all 0.6.x versions of skypilot[aws] are compatible
35
+ REQUIREMENTS = ["skypilot[aws]~=0.6.0"]
35
36
  APT_PACKAGES = ["openssh-client", "rsync"]
36
37
 
37
38
  @classmethod
@@ -33,7 +33,7 @@ class SkypilotAzureIntegration(Integration):
33
33
  """Definition of Skypilot (Azure) Integration for ZenML."""
34
34
 
35
35
  NAME = SKYPILOT_AZURE
36
- REQUIREMENTS = ["skypilot[azure]<=0.5.0"]
36
+ REQUIREMENTS = ["skypilot[azure]~=0.6.0"]
37
37
  APT_PACKAGES = ["openssh-client", "rsync"]
38
38
 
39
39
  @classmethod
@@ -31,7 +31,7 @@ class SkypilotGCPIntegration(Integration):
31
31
  """Definition of Skypilot (GCP) Integration for ZenML."""
32
32
 
33
33
  NAME = SKYPILOT_GCP
34
- REQUIREMENTS = ["skypilot[gcp]<=0.5.0"]
34
+ REQUIREMENTS = ["skypilot[gcp]~=0.6.0"]
35
35
  APT_PACKAGES = ["openssh-client", "rsync"]
36
36
 
37
37
  @classmethod
@@ -31,7 +31,7 @@ class SkypilotLambdaIntegration(Integration):
31
31
  """Definition of Skypilot Lambda Integration for ZenML."""
32
32
 
33
33
  NAME = SKYPILOT_LAMBDA
34
- REQUIREMENTS = ["skypilot[lambda]<=0.5.0"]
34
+ REQUIREMENTS = ["skypilot[lambda]<=0.6.0"]
35
35
 
36
36
  @classmethod
37
37
  def flavors(cls) -> List[Type[Flavor]]:
@@ -40,7 +40,7 @@ class SkypilotLambdaOrchestratorSettings(SkypilotBaseOrchestratorSettings):
40
40
 
41
41
  _UNSUPPORTED_FEATURES = {
42
42
  "use_spot": "Spot instances not supported for Lambda orchestrator.",
43
- "spot_recovery": "Spot recovery not supported for Lambda orchestrator.",
43
+ "job_recovery": "Job recovery not supported for Lambda orchestrator.",
44
44
  "image_id": "Custom image IDs not supported for Lambda orchestrator.",
45
45
  # Add other unsupported features as needed
46
46
  }
@@ -31,6 +31,7 @@ class SlackIntegration(Integration):
31
31
 
32
32
  NAME = SLACK
33
33
  REQUIREMENTS = ["slack-sdk>=3.16.1", "aiohttp>=3.8.1"]
34
+ REQUIREMENTS_IGNORED_ON_UNINSTALL = ["aiohttp"]
34
35
 
35
36
  @classmethod
36
37
  def flavors(cls) -> List[Type[Flavor]]:
@@ -32,6 +32,7 @@ class TektonIntegration(Integration):
32
32
 
33
33
  NAME = TEKTON
34
34
  REQUIREMENTS = ["kfp>=2.6.0", "kfp-kubernetes>=1.1.0"]
35
+ REQUIREMENTS_IGNORED_ON_UNINSTALL = ["kfp"]
35
36
 
36
37
  @classmethod
37
38
  def flavors(cls) -> List[Type[Flavor]]:
@@ -13,7 +13,6 @@
13
13
  # permissions and limitations under the License.
14
14
  """Initialization for TensorBoard integration."""
15
15
 
16
- import sys
17
16
  from typing import List, Optional
18
17
  from zenml.integrations.constants import TENSORBOARD
19
18
  from zenml.integrations.integration import Integration
@@ -18,6 +18,9 @@ import sys
18
18
  from typing import List, Optional
19
19
  from zenml.integrations.constants import TENSORFLOW
20
20
  from zenml.integrations.integration import Integration
21
+ from zenml.logger import get_logger
22
+
23
+ logger = get_logger(__name__)
21
24
 
22
25
 
23
26
  class TensorflowIntegration(Integration):
@@ -25,20 +28,27 @@ class TensorflowIntegration(Integration):
25
28
 
26
29
  NAME = TENSORFLOW
27
30
  REQUIREMENTS = []
31
+ REQUIREMENTS_IGNORED_ON_UNINSTALL = ["typing-extensions"]
28
32
 
29
33
  @classmethod
30
34
  def activate(cls) -> None:
31
35
  """Activates the integration."""
32
36
  # need to import this explicitly to load the Tensorflow file IO support
33
37
  # for S3 and other file systems
34
- if (
35
- not platform.system() == "Darwin"
36
- or not platform.machine() == "arm64"
37
- ):
38
+ if not platform.system() == "Darwin" or not platform.machine() == "arm64":
38
39
  import tensorflow_io # type: ignore
39
40
 
40
41
  from zenml.integrations.tensorflow import materializers # noqa
41
42
 
43
+ if sys.version_info.minor == 8:
44
+ logger.warning(
45
+ "Python 3.8 with TensorFlow is not fully "
46
+ "compatible with Pydantic 2 requirements. "
47
+ "Consider upgrading to a higher Python "
48
+ "version if you would like to use the "
49
+ "Tensorflow integration."
50
+ )
51
+
42
52
  @classmethod
43
53
  def get_requirements(cls, target_os: Optional[str] = None) -> List[str]:
44
54
  """Defines platform specific requirements for the integration.
@@ -52,13 +62,15 @@ class TensorflowIntegration(Integration):
52
62
  target_os = target_os or platform.system()
53
63
  if target_os == "Darwin" and platform.machine() == "arm64":
54
64
  requirements = [
55
- f"tensorflow-macos>=2.12,<=2.15",
65
+ "tensorflow-macos>=2.12,<=2.15",
56
66
  ]
57
67
  else:
58
68
  requirements = [
59
- f"tensorflow>=2.12,<=2.15",
69
+ "tensorflow>=2.12,<=2.15",
60
70
  "tensorflow_io>=0.24.0",
61
71
  ]
72
+ if sys.version_info.minor == 8:
73
+ requirements.append("typing-extensions>=4.6.1")
62
74
  return requirements
63
75
 
64
76
 
@@ -31,6 +31,7 @@ class WandbIntegration(Integration):
31
31
 
32
32
  NAME = WANDB
33
33
  REQUIREMENTS = ["wandb>=0.12.12", "Pillow>=9.1.0"]
34
+ REQUIREMENTS_IGNORED_ON_UNINSTALL = ["Pillow"]
34
35
 
35
36
  @classmethod
36
37
  def flavors(cls) -> List[Type[Flavor]]: