zenml-nightly 0.68.1.dev20241103__py3-none-any.whl → 0.70.0.dev20241115__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 (264) hide show
  1. README.md +1 -1
  2. RELEASE_NOTES.md +77 -0
  3. zenml/VERSION +1 -1
  4. zenml/__init__.py +2 -0
  5. zenml/artifacts/external_artifact.py +2 -1
  6. zenml/artifacts/{load_directory_materializer.py → preexisting_data_materializer.py} +8 -9
  7. zenml/artifacts/utils.py +139 -80
  8. zenml/cli/base.py +4 -4
  9. zenml/cli/model.py +1 -6
  10. zenml/cli/stack.py +1 -0
  11. zenml/client.py +29 -74
  12. zenml/config/server_config.py +17 -1
  13. zenml/constants.py +2 -7
  14. zenml/data_validators/base_data_validator.py +2 -2
  15. zenml/enums.py +20 -4
  16. zenml/exceptions.py +4 -0
  17. zenml/integrations/__init__.py +3 -1
  18. zenml/integrations/aws/orchestrators/sagemaker_orchestrator.py +20 -18
  19. zenml/integrations/azure/orchestrators/azureml_orchestrator.py +1 -1
  20. zenml/integrations/bentoml/materializers/bentoml_bento_materializer.py +19 -31
  21. zenml/integrations/constants.py +1 -0
  22. zenml/integrations/deepchecks/data_validators/deepchecks_data_validator.py +1 -1
  23. zenml/integrations/evidently/__init__.py +1 -1
  24. zenml/integrations/gcp/orchestrators/vertex_orchestrator.py +1 -1
  25. zenml/integrations/huggingface/materializers/huggingface_datasets_materializer.py +8 -12
  26. zenml/integrations/huggingface/materializers/huggingface_pt_model_materializer.py +17 -18
  27. zenml/integrations/huggingface/materializers/huggingface_t5_materializer.py +2 -5
  28. zenml/integrations/huggingface/materializers/huggingface_tf_model_materializer.py +17 -18
  29. zenml/integrations/huggingface/materializers/huggingface_tokenizer_materializer.py +2 -3
  30. zenml/integrations/langchain/__init__.py +2 -1
  31. zenml/integrations/langchain/materializers/openai_embedding_materializer.py +28 -2
  32. zenml/integrations/lightgbm/materializers/lightgbm_booster_materializer.py +8 -15
  33. zenml/integrations/lightgbm/materializers/lightgbm_dataset_materializer.py +11 -16
  34. zenml/integrations/lightning/orchestrators/lightning_orchestrator.py +29 -9
  35. zenml/integrations/openai/__init__.py +1 -1
  36. zenml/integrations/openai/hooks/open_ai_failure_hook.py +39 -14
  37. zenml/integrations/pillow/materializers/pillow_image_materializer.py +17 -20
  38. zenml/integrations/polars/materializers/dataframe_materializer.py +26 -39
  39. zenml/integrations/pycaret/materializers/model_materializer.py +7 -22
  40. zenml/integrations/tensorboard/visualizers/tensorboard_visualizer.py +60 -54
  41. zenml/integrations/tensorflow/materializers/keras_materializer.py +11 -22
  42. zenml/integrations/tensorflow/materializers/tf_dataset_materializer.py +8 -15
  43. zenml/integrations/vllm/__init__.py +50 -0
  44. zenml/integrations/vllm/flavors/__init__.py +21 -0
  45. zenml/integrations/vllm/flavors/vllm_model_deployer_flavor.py +91 -0
  46. zenml/integrations/vllm/model_deployers/__init__.py +19 -0
  47. zenml/integrations/vllm/model_deployers/vllm_model_deployer.py +263 -0
  48. zenml/integrations/vllm/services/__init__.py +19 -0
  49. zenml/integrations/vllm/services/vllm_deployment.py +206 -0
  50. zenml/integrations/whylogs/materializers/whylogs_materializer.py +11 -18
  51. zenml/integrations/xgboost/materializers/xgboost_booster_materializer.py +11 -22
  52. zenml/integrations/xgboost/materializers/xgboost_dmatrix_materializer.py +10 -19
  53. zenml/materializers/base_materializer.py +68 -1
  54. zenml/metadata/lazy_load.py +20 -7
  55. zenml/model/model.py +17 -64
  56. zenml/model/utils.py +5 -0
  57. zenml/models/__init__.py +0 -12
  58. zenml/models/v2/base/filter.py +121 -8
  59. zenml/models/v2/core/artifact_version.py +42 -7
  60. zenml/models/v2/core/model_version.py +26 -5
  61. zenml/models/v2/core/pipeline_run.py +25 -6
  62. zenml/models/v2/core/run_metadata.py +2 -217
  63. zenml/models/v2/core/step_run.py +62 -24
  64. zenml/orchestrators/base_orchestrator.py +12 -1
  65. zenml/orchestrators/input_utils.py +44 -19
  66. zenml/orchestrators/step_launcher.py +4 -3
  67. zenml/orchestrators/step_run_utils.py +19 -15
  68. zenml/orchestrators/step_runner.py +25 -14
  69. zenml/orchestrators/utils.py +45 -26
  70. zenml/stack/flavor.py +9 -5
  71. zenml/stack_deployments/aws_stack_deployment.py +23 -6
  72. zenml/stack_deployments/azure_stack_deployment.py +28 -5
  73. zenml/stack_deployments/gcp_stack_deployment.py +25 -8
  74. zenml/stack_deployments/stack_deployment.py +3 -5
  75. zenml/steps/base_step.py +1 -1
  76. zenml/steps/entrypoint_function_utils.py +3 -5
  77. zenml/steps/step_context.py +5 -2
  78. zenml/steps/utils.py +13 -2
  79. zenml/utils/callback_registry.py +71 -0
  80. zenml/utils/metadata_utils.py +335 -0
  81. zenml/zen_server/auth.py +221 -3
  82. zenml/zen_server/cache.py +208 -0
  83. zenml/zen_server/dashboard/assets/{404-DT4QRUqN.js → 404-NVXKFp-x.js} +1 -1
  84. zenml/zen_server/dashboard/assets/{@radix-DP6vWzyx.js → @radix-DeK6qiuw.js} +1 -1
  85. zenml/zen_server/dashboard/assets/{@react-router-BMhZulnd.js → @react-router-B3Z5rLr2.js} +1 -1
  86. zenml/zen_server/dashboard/assets/{@reactflow-8U9qNlMR.js → @reactflow-CK0KJUen.js} +2 -2
  87. zenml/zen_server/dashboard/assets/{@tanstack-BUCbhJyH.js → @tanstack-DT5WLu9C.js} +1 -1
  88. zenml/zen_server/dashboard/assets/AlertDialogDropdownItem-DezXKmDf.js +1 -0
  89. zenml/zen_server/dashboard/assets/{CodeSnippet-CqybNv0k.js → CodeSnippet-JzR8CEtw.js} +2 -2
  90. zenml/zen_server/dashboard/assets/{CollapsibleCard-0r_8G2Lj.js → CollapsibleCard-DQW_ktMO.js} +1 -1
  91. zenml/zen_server/dashboard/assets/{Commands-BDjgBQKi.js → Commands-DL2kwkRd.js} +1 -1
  92. zenml/zen_server/dashboard/assets/ComponentBadge-D_g62Wv8.js +1 -0
  93. zenml/zen_server/dashboard/assets/{CopyButton-C745BrKi.js → CopyButton-LNcWaa14.js} +1 -1
  94. zenml/zen_server/dashboard/assets/{CsvVizualization-PpAq0CeZ.js → CsvVizualization-DknpE5ej.js} +5 -5
  95. zenml/zen_server/dashboard/assets/{DialogItem-DcVCZEew.js → DialogItem-Bxf8FuAT.js} +1 -1
  96. zenml/zen_server/dashboard/assets/{DisplayDate-BeXgUG_C.js → DisplayDate-CDMUcQHS.js} +1 -1
  97. zenml/zen_server/dashboard/assets/{EmptyState-DeK7H4pr.js → EmptyState-BzdlCwp3.js} +1 -1
  98. zenml/zen_server/dashboard/assets/{Error-BMlzibXj.js → Error-DYflYyps.js} +1 -1
  99. zenml/zen_server/dashboard/assets/ExecutionStatus-C7zyIQKZ.js +1 -0
  100. zenml/zen_server/dashboard/assets/{Helpbox-BLf40fLV.js → Helpbox-oYSGpLqd.js} +1 -1
  101. zenml/zen_server/dashboard/assets/{Infobox-BwisKifi.js → Infobox-Cx4xGoXR.js} +1 -1
  102. zenml/zen_server/dashboard/assets/{InlineAvatar-jEgodSgX.js → InlineAvatar-DiGOWNKF.js} +1 -1
  103. zenml/zen_server/dashboard/assets/{Lock-3lLt1ih0.js → Lock-CYYy18Mm.js} +1 -1
  104. zenml/zen_server/dashboard/assets/{MarkdownVisualization-8O9kTr-2.js → MarkdownVisualization-ylXaAxev.js} +1 -1
  105. zenml/zen_server/dashboard/assets/NestedCollapsible-DYbgyKxK.js +1 -0
  106. zenml/zen_server/dashboard/assets/{NumberBox-T9eELfLZ.js → NumberBox-Dtp3J6g5.js} +1 -1
  107. zenml/zen_server/dashboard/assets/Partials-03iZf8-N.js +1 -0
  108. zenml/zen_server/dashboard/assets/{PasswordChecker-CW0kqY0W.js → PasswordChecker-B0nadgh6.js} +1 -1
  109. zenml/zen_server/dashboard/assets/ProBadge-D_EB8HNo.js +1 -0
  110. zenml/zen_server/dashboard/assets/ProCta-DqNS4v3x.js +1 -0
  111. zenml/zen_server/dashboard/assets/ProviderIcon-Bki2aw8w.js +1 -0
  112. zenml/zen_server/dashboard/assets/{ProviderRadio-BROY1700.js → ProviderRadio-8f43sPD4.js} +1 -1
  113. zenml/zen_server/dashboard/assets/RunSelector-DkPiIiNr.js +1 -0
  114. zenml/zen_server/dashboard/assets/RunsBody-07YEO7qI.js +1 -0
  115. zenml/zen_server/dashboard/assets/SearchField-lp1KgU4e.js +1 -0
  116. zenml/zen_server/dashboard/assets/{SecretTooltip-C_qByGWB.js → SecretTooltip-CgnbyeOx.js} +1 -1
  117. zenml/zen_server/dashboard/assets/{SetPassword-7pRB00El.js → SetPassword-CpP418A2.js} +1 -1
  118. zenml/zen_server/dashboard/assets/StackList-WvuKQusZ.js +1 -0
  119. zenml/zen_server/dashboard/assets/Tabs-BktHkCJJ.js +1 -0
  120. zenml/zen_server/dashboard/assets/Tick-BlMoIlJT.js +1 -0
  121. zenml/zen_server/dashboard/assets/{UpdatePasswordSchemas-DckMEkFf.js → UpdatePasswordSchemas-Sc0A0pP-.js} +1 -1
  122. zenml/zen_server/dashboard/assets/{UsageReason-DVceN14P.js → UsageReason-YYduL4fj.js} +1 -1
  123. zenml/zen_server/dashboard/assets/{WizardFooter-CW0Cvd70.js → WizardFooter-dgmizSJC.js} +1 -1
  124. zenml/zen_server/dashboard/assets/all-pipeline-runs-query-D-c2G6lV.js +1 -0
  125. zenml/zen_server/dashboard/assets/check-DloQpStc.js +1 -0
  126. zenml/zen_server/dashboard/assets/{check-circle-Dwxliy1Z.js → check-circle-jNbX5-sR.js} +1 -1
  127. zenml/zen_server/dashboard/assets/{chevron-down-8wLBS5pQ.js → chevron-down-6JyMkfjR.js} +1 -1
  128. zenml/zen_server/dashboard/assets/{chevron-right-double-DoD8iXWM.js → chevron-right-double-D7ojK9Co.js} +1 -1
  129. zenml/zen_server/dashboard/assets/{code-browser-CZUQs3Wa.js → code-browser-CUFUIHfp.js} +1 -1
  130. zenml/zen_server/dashboard/assets/{copy-CaSMXwiU.js → copy-C8XQA2Ug.js} +1 -1
  131. zenml/zen_server/dashboard/assets/create-stack-DM_JPgef.js +1 -0
  132. zenml/zen_server/dashboard/assets/delete-run-CJdh1P_h.js +1 -0
  133. zenml/zen_server/dashboard/assets/{docker-BFNgg-z3.js → docker-BdA9vrnW.js} +1 -1
  134. zenml/zen_server/dashboard/assets/{dots-horizontal-DK5Duzx4.js → dots-horizontal-otGBOSDJ.js} +1 -1
  135. zenml/zen_server/dashboard/assets/{form-schemas-1AyOCx90.js → form-schemas-K6FYKjwa.js} +1 -1
  136. zenml/zen_server/dashboard/assets/{gcp-7M2Yf3ZK.js → gcp-CFtm4BA7.js} +1 -1
  137. zenml/zen_server/dashboard/assets/{help-Dam461dC.js → help-Cc9bBIJH.js} +1 -1
  138. zenml/zen_server/dashboard/assets/index-B1mVPYxf.js +1 -0
  139. zenml/zen_server/dashboard/assets/index-BAkC7FXi.js +1 -0
  140. zenml/zen_server/dashboard/assets/{index-QQb7wQEC.js → index-CCOPpudF.js} +8 -8
  141. zenml/zen_server/dashboard/assets/index-CEV4Cvaf.js +1 -0
  142. zenml/zen_server/dashboard/assets/index-DlGvJQPn.css +1 -0
  143. zenml/zen_server/dashboard/assets/{index-BVJ8n2-j.js → index-Uu49AX48.js} +1 -1
  144. zenml/zen_server/dashboard/assets/{index.esm-cuVep_NJ.js → index.esm-Dy6Z9Ung.js} +1 -1
  145. zenml/zen_server/dashboard/assets/{kubernetes--g7r02Zu.js → kubernetes-B2wmAJ1d.js} +1 -1
  146. zenml/zen_server/dashboard/assets/{layout-DCSYN7-C.js → layout-BtHBmE4w.js} +1 -1
  147. zenml/zen_server/dashboard/assets/{link-external-CBEk6kEG.js → link-external-b9AXw_sW.js} +1 -1
  148. zenml/zen_server/dashboard/assets/{login-mutation-DTcAFP1l.js → login-mutation-hf-lK87O.js} +1 -1
  149. zenml/zen_server/dashboard/assets/{logs-D5bdJGur.js → logs-WMSM52RF.js} +1 -1
  150. zenml/zen_server/dashboard/assets/{not-found-Cc-JkRH2.js → not-found-BGirLjU-.js} +1 -1
  151. zenml/zen_server/dashboard/assets/{package-Cs35Szwh.js → package-C6uypY4h.js} +1 -1
  152. zenml/zen_server/dashboard/assets/page-0JE_-Ec1.js +1 -0
  153. zenml/zen_server/dashboard/assets/{page-DH_Z7iW1.js → page-6m6yHHlE.js} +1 -1
  154. zenml/zen_server/dashboard/assets/page-BDigxVpo.js +1 -0
  155. zenml/zen_server/dashboard/assets/page-BR68V0V1.js +1 -0
  156. zenml/zen_server/dashboard/assets/page-BRLpxOt0.js +1 -0
  157. zenml/zen_server/dashboard/assets/{page-BQQKaabe.js → page-BU7huvKw.js} +3 -3
  158. zenml/zen_server/dashboard/assets/page-BvqLv2Ky.js +1 -0
  159. zenml/zen_server/dashboard/assets/page-C00YAkaB.js +1 -0
  160. zenml/zen_server/dashboard/assets/{page-N4qoPHKb.js → page-CD-DcWoy.js} +1 -1
  161. zenml/zen_server/dashboard/assets/page-COXXJj1k.js +1 -0
  162. zenml/zen_server/dashboard/assets/page-CbpvrsDL.js +1 -0
  163. zenml/zen_server/dashboard/assets/page-CdMWnQak.js +1 -0
  164. zenml/zen_server/dashboard/assets/{page-ClUVkl-O.js → page-CjGdWY13.js} +1 -1
  165. zenml/zen_server/dashboard/assets/page-CwxrFarU.js +1 -0
  166. zenml/zen_server/dashboard/assets/{page-DLixvR-7.js → page-D01JhjQB.js} +1 -1
  167. zenml/zen_server/dashboard/assets/page-D6uU2ax4.js +1 -0
  168. zenml/zen_server/dashboard/assets/page-D7S3aCbF.js +1 -0
  169. zenml/zen_server/dashboard/assets/{page-9yplj5JT.js → page-DLC-bNBP.js} +1 -1
  170. zenml/zen_server/dashboard/assets/page-DXSTpqRD.js +1 -0
  171. zenml/zen_server/dashboard/assets/{page-DzpVUZ8f.js → page-DakHVWXF.js} +1 -1
  172. zenml/zen_server/dashboard/assets/{page-DIOXwhiD.js → page-Df-Fw0aq.js} +1 -1
  173. zenml/zen_server/dashboard/assets/{page-B-y2XKIc.js → page-DfbXf_8s.js} +1 -1
  174. zenml/zen_server/dashboard/assets/page-DjRJCGb3.js +1 -0
  175. zenml/zen_server/dashboard/assets/{page-C0N5q3l7.js → page-Djikxq_S.js} +1 -1
  176. zenml/zen_server/dashboard/assets/page-Dnovpa0i.js +3 -0
  177. zenml/zen_server/dashboard/assets/page-Dot3LPmL.js +1 -0
  178. zenml/zen_server/dashboard/assets/page-Vcxara9U.js +1 -0
  179. zenml/zen_server/dashboard/assets/page-Xynx4btY.js +14 -0
  180. zenml/zen_server/dashboard/assets/page-YpKAqVSa.js +1 -0
  181. zenml/zen_server/dashboard/assets/page-yYC9OI-E.js +1 -0
  182. zenml/zen_server/dashboard/assets/{persist-DNb5cdrU.js → persist-Coz7ZWvz.js} +1 -1
  183. zenml/zen_server/dashboard/assets/{persist-CP0JmYZ4.js → persist-GjC8PZoC.js} +1 -1
  184. zenml/zen_server/dashboard/assets/{plus-C9IxgN2M.js → plus-tf1V2hTJ.js} +1 -1
  185. zenml/zen_server/dashboard/assets/{refresh-BVu22P_C.js → refresh-BjOeWlEq.js} +1 -1
  186. zenml/zen_server/dashboard/assets/{rocket-CONEmRmB.js → rocket-DjT2cDvG.js} +1 -1
  187. zenml/zen_server/dashboard/assets/sharedSchema-CQb14VSr.js +14 -0
  188. zenml/zen_server/dashboard/assets/stack-detail-query-OPEW-cDJ.js +1 -0
  189. zenml/zen_server/dashboard/assets/{tick-circle-CM1ZScbQ.js → tick-circle-BEX_Tp4v.js} +1 -1
  190. zenml/zen_server/dashboard/assets/{trash-DkJHMOg7.js → trash-arLUMWMS.js} +1 -1
  191. zenml/zen_server/dashboard/assets/{update-server-settings-mutation-DsU8cNVl.js → update-server-settings-mutation-LwuQfHYn.js} +1 -1
  192. zenml/zen_server/dashboard/assets/upgrade-form-CwRHBuXB.webp +0 -0
  193. zenml/zen_server/dashboard/assets/url-CkvKAnwF.js +1 -0
  194. zenml/zen_server/dashboard/assets/{zod-D89GC_vc.js → zod-BwEbpOxH.js} +1 -1
  195. zenml/zen_server/dashboard/index.html +7 -7
  196. zenml/zen_server/deploy/helm/Chart.yaml +1 -1
  197. zenml/zen_server/deploy/helm/README.md +2 -2
  198. zenml/zen_server/exceptions.py +2 -0
  199. zenml/zen_server/jwt.py +30 -13
  200. zenml/zen_server/rbac/endpoint_utils.py +43 -1
  201. zenml/zen_server/rbac/utils.py +0 -2
  202. zenml/zen_server/routers/artifact_version_endpoints.py +27 -1
  203. zenml/zen_server/routers/auth_endpoints.py +134 -102
  204. zenml/zen_server/routers/logs_endpoints.py +66 -0
  205. zenml/zen_server/routers/workspaces_endpoints.py +3 -4
  206. zenml/zen_server/template_execution/utils.py +14 -16
  207. zenml/zen_server/utils.py +27 -0
  208. zenml/zen_server/zen_server_api.py +6 -3
  209. zenml/zen_stores/migrations/versions/0.70.0_release.py +23 -0
  210. zenml/zen_stores/migrations/versions/1cb6477f72d6_move_artifact_save_type.py +99 -0
  211. zenml/zen_stores/migrations/versions/904464ea4041_add_pipeline_model_run_unique_constraints.py +192 -0
  212. zenml/zen_stores/migrations/versions/b557b2871693_update_step_run_input_types.py +33 -0
  213. zenml/zen_stores/rest_zen_store.py +68 -64
  214. zenml/zen_stores/schemas/artifact_schemas.py +8 -1
  215. zenml/zen_stores/schemas/model_schemas.py +27 -3
  216. zenml/zen_stores/schemas/pipeline_run_schemas.py +6 -1
  217. zenml/zen_stores/schemas/pipeline_schemas.py +8 -2
  218. zenml/zen_stores/schemas/run_metadata_schemas.py +1 -48
  219. zenml/zen_stores/schemas/step_run_schemas.py +18 -10
  220. zenml/zen_stores/sql_zen_store.py +283 -219
  221. zenml/zen_stores/zen_store_interface.py +15 -42
  222. {zenml_nightly-0.68.1.dev20241103.dist-info → zenml_nightly-0.70.0.dev20241115.dist-info}/METADATA +2 -2
  223. {zenml_nightly-0.68.1.dev20241103.dist-info → zenml_nightly-0.70.0.dev20241115.dist-info}/RECORD +226 -203
  224. zenml/zen_server/dashboard/assets/AlertDialogDropdownItem-C6N2rGrB.js +0 -1
  225. zenml/zen_server/dashboard/assets/ComponentBadge-DUiEYJHu.js +0 -1
  226. zenml/zen_server/dashboard/assets/ComponentFallbackDialog-BFoH5K4V.js +0 -1
  227. zenml/zen_server/dashboard/assets/ComponentIcon-CAIoUis2.js +0 -1
  228. zenml/zen_server/dashboard/assets/Partials-YPBB3V4q.js +0 -1
  229. zenml/zen_server/dashboard/assets/ProviderIcon-Bb3Xha5A.js +0 -1
  230. zenml/zen_server/dashboard/assets/RunSelector-DCiL3M1c.js +0 -1
  231. zenml/zen_server/dashboard/assets/SearchField-DfUiGFVd.js +0 -1
  232. zenml/zen_server/dashboard/assets/Tick-CykQFPj2.js +0 -1
  233. zenml/zen_server/dashboard/assets/cloud-only-B-s_HMDm.js +0 -1
  234. zenml/zen_server/dashboard/assets/codespaces-BitYDX9d.gif +0 -0
  235. zenml/zen_server/dashboard/assets/create-stack-CEmaPZ4c.js +0 -1
  236. zenml/zen_server/dashboard/assets/delete-run-D-LKbGyz.js +0 -1
  237. zenml/zen_server/dashboard/assets/index-Bpmj40BI.js +0 -1
  238. zenml/zen_server/dashboard/assets/index-CbU4Ln_E.css +0 -1
  239. zenml/zen_server/dashboard/assets/index-DKPhqP2B.js +0 -1
  240. zenml/zen_server/dashboard/assets/page-BBpOxVcY.js +0 -1
  241. zenml/zen_server/dashboard/assets/page-BRInM1Lg.js +0 -1
  242. zenml/zen_server/dashboard/assets/page-BjjlMk7s.js +0 -1
  243. zenml/zen_server/dashboard/assets/page-Bvd7YH2A.js +0 -1
  244. zenml/zen_server/dashboard/assets/page-CT3Nep8W.js +0 -1
  245. zenml/zen_server/dashboard/assets/page-C_f47pBf.js +0 -1
  246. zenml/zen_server/dashboard/assets/page-Cmv8C_yM.js +0 -3
  247. zenml/zen_server/dashboard/assets/page-CyN2bdWG.js +0 -1
  248. zenml/zen_server/dashboard/assets/page-CzzXH4fs.js +0 -1
  249. zenml/zen_server/dashboard/assets/page-DTlGjgnG.js +0 -1
  250. zenml/zen_server/dashboard/assets/page-Dbpl86h0.js +0 -1
  251. zenml/zen_server/dashboard/assets/page-Ddgy6kDS.js +0 -1
  252. zenml/zen_server/dashboard/assets/page-DtCAfBLy.js +0 -9
  253. zenml/zen_server/dashboard/assets/page-Dx16z7nA.js +0 -1
  254. zenml/zen_server/dashboard/assets/page-McUyYbo1.js +0 -1
  255. zenml/zen_server/dashboard/assets/page-T1P3RyAR.js +0 -1
  256. zenml/zen_server/dashboard/assets/page-bKaULTGG.js +0 -1
  257. zenml/zen_server/dashboard/assets/page-sbXUJy9t.js +0 -1
  258. zenml/zen_server/dashboard/assets/sharedSchema-TMLu-nYQ.js +0 -14
  259. zenml/zen_server/dashboard/assets/stack-detail-query-xmYxSsUY.js +0 -1
  260. zenml/zen_server/dashboard/assets/url-D5le3J4q.js +0 -1
  261. zenml/zen_server/routers/run_metadata_endpoints.py +0 -96
  262. {zenml_nightly-0.68.1.dev20241103.dist-info → zenml_nightly-0.70.0.dev20241115.dist-info}/LICENSE +0 -0
  263. {zenml_nightly-0.68.1.dev20241103.dist-info → zenml_nightly-0.70.0.dev20241115.dist-info}/WHEEL +0 -0
  264. {zenml_nightly-0.68.1.dev20241103.dist-info → zenml_nightly-0.70.0.dev20241115.dist-info}/entry_points.txt +0 -0
zenml/zen_server/auth.py CHANGED
@@ -14,13 +14,13 @@
14
14
  """Authentication module for ZenML server."""
15
15
 
16
16
  from contextvars import ContextVar
17
- from datetime import datetime
17
+ from datetime import datetime, timedelta
18
18
  from typing import Callable, Optional, Union
19
19
  from urllib.parse import urlencode
20
20
  from uuid import UUID
21
21
 
22
22
  import requests
23
- from fastapi import Depends
23
+ from fastapi import Depends, Response
24
24
  from fastapi.security import (
25
25
  HTTPBasic,
26
26
  HTTPBasicCredentials,
@@ -37,7 +37,7 @@ from zenml.constants import (
37
37
  LOGIN,
38
38
  VERSION_1,
39
39
  )
40
- from zenml.enums import AuthScheme, OAuthDeviceStatus
40
+ from zenml.enums import AuthScheme, ExecutionStatus, OAuthDeviceStatus
41
41
  from zenml.exceptions import (
42
42
  AuthorizationException,
43
43
  CredentialsNotValid,
@@ -51,11 +51,13 @@ from zenml.models import (
51
51
  ExternalUserModel,
52
52
  OAuthDeviceInternalResponse,
53
53
  OAuthDeviceInternalUpdate,
54
+ OAuthTokenResponse,
54
55
  UserAuthModel,
55
56
  UserRequest,
56
57
  UserResponse,
57
58
  UserUpdate,
58
59
  )
60
+ from zenml.zen_server.cache import cache_result
59
61
  from zenml.zen_server.exceptions import http_exception_from_error
60
62
  from zenml.zen_server.jwt import JWTToken
61
63
  from zenml.zen_server.utils import server_config, zen_store
@@ -329,6 +331,148 @@ def authenticate_credentials(
329
331
  ),
330
332
  )
331
333
 
334
+ if decoded_token.schedule_id:
335
+ # If the token contains a schedule ID, we need to check if the
336
+ # schedule still exists in the database. We use a cached version
337
+ # of the schedule active status to avoid unnecessary database
338
+ # queries.
339
+
340
+ @cache_result(expiry=30)
341
+ def get_schedule_active(schedule_id: UUID) -> Optional[bool]:
342
+ """Get the active status of a schedule.
343
+
344
+ Args:
345
+ schedule_id: The schedule ID.
346
+
347
+ Returns:
348
+ The schedule active status or None if the schedule does not
349
+ exist.
350
+ """
351
+ try:
352
+ schedule = zen_store().get_schedule(
353
+ schedule_id, hydrate=False
354
+ )
355
+ except KeyError:
356
+ return False
357
+
358
+ return schedule.active
359
+
360
+ schedule_active = get_schedule_active(decoded_token.schedule_id)
361
+ if schedule_active is None:
362
+ error = (
363
+ f"Authentication error: error retrieving token schedule "
364
+ f"{decoded_token.schedule_id}"
365
+ )
366
+ logger.error(error)
367
+ raise CredentialsNotValid(error)
368
+
369
+ if not schedule_active:
370
+ error = (
371
+ f"Authentication error: schedule {decoded_token.schedule_id} "
372
+ "is not active"
373
+ )
374
+ logger.error(error)
375
+ raise CredentialsNotValid(error)
376
+
377
+ if decoded_token.pipeline_run_id:
378
+ # If the token contains a pipeline run ID, we need to check if the
379
+ # pipeline run exists in the database and the pipeline run has
380
+ # not concluded. We use a cached version of the pipeline run status
381
+ # to avoid unnecessary database queries.
382
+
383
+ @cache_result(expiry=30)
384
+ def get_pipeline_run_status(
385
+ pipeline_run_id: UUID,
386
+ ) -> Optional[ExecutionStatus]:
387
+ """Get the status of a pipeline run.
388
+
389
+ Args:
390
+ pipeline_run_id: The pipeline run ID.
391
+
392
+ Returns:
393
+ The pipeline run status or None if the pipeline run does not
394
+ exist.
395
+ """
396
+ try:
397
+ pipeline_run = zen_store().get_run(
398
+ pipeline_run_id, hydrate=False
399
+ )
400
+ except KeyError:
401
+ return None
402
+
403
+ return pipeline_run.status
404
+
405
+ pipeline_run_status = get_pipeline_run_status(
406
+ decoded_token.pipeline_run_id
407
+ )
408
+ if pipeline_run_status is None:
409
+ error = (
410
+ f"Authentication error: error retrieving token pipeline run "
411
+ f"{decoded_token.pipeline_run_id}"
412
+ )
413
+ logger.error(error)
414
+ raise CredentialsNotValid(error)
415
+
416
+ if pipeline_run_status in [
417
+ ExecutionStatus.FAILED,
418
+ ExecutionStatus.COMPLETED,
419
+ ]:
420
+ error = (
421
+ f"The execution of pipeline run "
422
+ f"{decoded_token.pipeline_run_id} has already concluded and "
423
+ "API tokens scoped to it are no longer valid."
424
+ )
425
+ logger.error(error)
426
+ raise CredentialsNotValid(error)
427
+
428
+ if decoded_token.step_run_id:
429
+ # If the token contains a step run ID, we need to check if the
430
+ # step run exists in the database and the step run has not concluded.
431
+ # We use a cached version of the step run status to avoid unnecessary
432
+ # database queries.
433
+
434
+ @cache_result(expiry=30)
435
+ def get_step_run_status(
436
+ step_run_id: UUID,
437
+ ) -> Optional[ExecutionStatus]:
438
+ """Get the status of a step run.
439
+
440
+ Args:
441
+ step_run_id: The step run ID.
442
+
443
+ Returns:
444
+ The step run status or None if the step run does not exist.
445
+ """
446
+ try:
447
+ step_run = zen_store().get_run_step(
448
+ step_run_id, hydrate=False
449
+ )
450
+ except KeyError:
451
+ return None
452
+
453
+ return step_run.status
454
+
455
+ step_run_status = get_step_run_status(decoded_token.step_run_id)
456
+ if step_run_status is None:
457
+ error = (
458
+ f"Authentication error: error retrieving token step run "
459
+ f"{decoded_token.step_run_id}"
460
+ )
461
+ logger.error(error)
462
+ raise CredentialsNotValid(error)
463
+
464
+ if step_run_status in [
465
+ ExecutionStatus.FAILED,
466
+ ExecutionStatus.COMPLETED,
467
+ ]:
468
+ error = (
469
+ f"The execution of step run "
470
+ f"{decoded_token.step_run_id} has already concluded and "
471
+ "API tokens scoped to it are no longer valid."
472
+ )
473
+ logger.error(error)
474
+ raise CredentialsNotValid(error)
475
+
332
476
  auth_context = AuthContext(
333
477
  user=user_model,
334
478
  access_token=decoded_token,
@@ -660,6 +804,80 @@ def authenticate_api_key(
660
804
  return AuthContext(user=user_model, api_key=internal_api_key)
661
805
 
662
806
 
807
+ def generate_access_token(
808
+ user_id: UUID,
809
+ response: Optional[Response] = None,
810
+ device: Optional[OAuthDeviceInternalResponse] = None,
811
+ api_key: Optional[APIKeyInternalResponse] = None,
812
+ expires_in: Optional[int] = None,
813
+ schedule_id: Optional[UUID] = None,
814
+ pipeline_run_id: Optional[UUID] = None,
815
+ step_run_id: Optional[UUID] = None,
816
+ ) -> OAuthTokenResponse:
817
+ """Generates an access token for the given user.
818
+
819
+ Args:
820
+ user_id: The ID of the user.
821
+ response: The FastAPI response object.
822
+ device: The device used for authentication.
823
+ api_key: The service account API key used for authentication.
824
+ expires_in: The number of seconds until the token expires.
825
+ schedule_id: The ID of the schedule to scope the token to.
826
+ pipeline_run_id: The ID of the pipeline run to scope the token to.
827
+ step_run_id: The ID of the step run to scope the token to.
828
+
829
+ Returns:
830
+ An authentication response with an access token.
831
+ """
832
+ config = server_config()
833
+
834
+ # If the expiration time is not supplied, the JWT tokens are set to expire
835
+ # according to the values configured in the server config. Device tokens are
836
+ # handled separately from regular user tokens.
837
+ expires: Optional[datetime] = None
838
+ if expires_in:
839
+ expires = datetime.utcnow() + timedelta(seconds=expires_in)
840
+ elif device:
841
+ # If a device was used for authentication, the token will expire
842
+ # at the same time as the device.
843
+ expires = device.expires
844
+ if expires:
845
+ expires_in = max(
846
+ int(expires.timestamp() - datetime.utcnow().timestamp()), 0
847
+ )
848
+ elif config.jwt_token_expire_minutes:
849
+ expires = datetime.utcnow() + timedelta(
850
+ minutes=config.jwt_token_expire_minutes
851
+ )
852
+ expires_in = config.jwt_token_expire_minutes * 60
853
+
854
+ access_token = JWTToken(
855
+ user_id=user_id,
856
+ device_id=device.id if device else None,
857
+ api_key_id=api_key.id if api_key else None,
858
+ schedule_id=schedule_id,
859
+ pipeline_run_id=pipeline_run_id,
860
+ step_run_id=step_run_id,
861
+ ).encode(expires=expires)
862
+
863
+ if not device and response:
864
+ # Also set the access token as an HTTP only cookie in the response
865
+ response.set_cookie(
866
+ key=config.get_auth_cookie_name(),
867
+ value=access_token,
868
+ httponly=True,
869
+ samesite="lax",
870
+ max_age=config.jwt_token_expire_minutes * 60
871
+ if config.jwt_token_expire_minutes
872
+ else None,
873
+ domain=config.auth_cookie_domain,
874
+ )
875
+
876
+ return OAuthTokenResponse(
877
+ access_token=access_token, expires_in=expires_in, token_type="bearer"
878
+ )
879
+
880
+
663
881
  def http_authentication(
664
882
  credentials: HTTPBasicCredentials = Depends(HTTPBasic()),
665
883
  ) -> AuthContext:
@@ -0,0 +1,208 @@
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
+ """Memory cache module for the ZenML server."""
15
+
16
+ import time
17
+ from collections import OrderedDict
18
+ from threading import Lock
19
+ from typing import Any, Callable, Optional
20
+ from typing import OrderedDict as OrderedDictType
21
+ from uuid import UUID
22
+
23
+ from zenml.logger import get_logger
24
+ from zenml.utils.singleton import SingletonMetaClass
25
+
26
+ logger = get_logger(__name__)
27
+
28
+
29
+ class MemoryCacheEntry:
30
+ """Simple class to hold cache entry data."""
31
+
32
+ def __init__(self, value: Any, expiry: int) -> None:
33
+ """Initialize a cache entry with value and expiry time.
34
+
35
+ Args:
36
+ value: The value to store in the cache.
37
+ expiry: The expiry time in seconds.
38
+ """
39
+ self.value: Any = value
40
+ self.expiry: int = expiry
41
+ self.timestamp: float = time.time()
42
+
43
+ @property
44
+ def expired(self) -> bool:
45
+ """Check if the cache entry has expired.
46
+
47
+ Returns:
48
+ True if the cache entry has expired; otherwise, False.
49
+ """
50
+ return time.time() - self.timestamp >= self.expiry
51
+
52
+
53
+ class MemoryCache(metaclass=SingletonMetaClass):
54
+ """Simple in-memory cache with expiry and capacity management.
55
+
56
+ This cache is thread-safe and can be used in both synchronous and
57
+ asynchronous contexts. It uses a simple LRU (Least Recently Used) eviction
58
+ strategy to manage the cache size.
59
+
60
+ Each cache entry has a key, value, timestamp, and expiry. The cache
61
+ automatically removes expired entries and evicts the oldest entry when
62
+ the cache reaches its maximum capacity.
63
+
64
+
65
+ Usage Example:
66
+
67
+ cache = MemoryCache()
68
+ uuid_key = UUID("12345678123456781234567812345678")
69
+
70
+ if not cache.get(uuid_key):
71
+ # Get the value from the database or other source
72
+ value = get_value_from_database()
73
+ cache.set(uuid_key, value, expiry=60)
74
+
75
+ Usage Example with decorator:
76
+
77
+ @cache_result(expiry=60)
78
+ def get_cached_value(key: UUID) -> Any:
79
+ return get_value_from_database(key)
80
+
81
+ uuid_key = UUID("12345678123456781234567812345678")
82
+
83
+ value = get_cached_value(uuid_key)
84
+ """
85
+
86
+ def __init__(self, max_capacity: int, default_expiry: int) -> None:
87
+ """Initialize the cache with a maximum capacity and default expiry time.
88
+
89
+ Args:
90
+ max_capacity: The maximum number of entries the cache can hold.
91
+ default_expiry: The default expiry time in seconds.
92
+ """
93
+ self.cache: OrderedDictType[UUID, MemoryCacheEntry] = OrderedDict()
94
+ self.max_capacity = max_capacity
95
+ self.default_expiry = default_expiry
96
+ self._lock = Lock()
97
+
98
+ def set(self, key: UUID, value: Any, expiry: Optional[int] = None) -> None:
99
+ """Insert value into cache with optional custom expiry time in seconds.
100
+
101
+ Args:
102
+ key: The key to insert the value with.
103
+ value: The value to insert into the cache.
104
+ expiry: The expiry time in seconds. If None, uses the default expiry.
105
+ """
106
+ with self._lock:
107
+ self.cache[key] = MemoryCacheEntry(
108
+ value=value, expiry=expiry or self.default_expiry
109
+ )
110
+ self._cleanup()
111
+
112
+ def get(self, key: UUID) -> Optional[Any]:
113
+ """Retrieve value if it's still valid; otherwise, return None.
114
+
115
+ Args:
116
+ key: The key to retrieve the value for.
117
+
118
+ Returns:
119
+ The value if it's still valid; otherwise, None.
120
+ """
121
+ with self._lock:
122
+ return self._get_internal(key)
123
+
124
+ def _get_internal(self, key: UUID) -> Optional[Any]:
125
+ """Helper to retrieve a value without lock (internal use only).
126
+
127
+ Args:
128
+ key: The key to retrieve the value for.
129
+
130
+ Returns:
131
+ The value if it's still valid; otherwise, None.
132
+ """
133
+ entry = self.cache.get(key)
134
+ if entry and not entry.expired:
135
+ return entry.value
136
+ elif entry:
137
+ del self.cache[key] # Invalidate expired entry
138
+ return None
139
+
140
+ def _cleanup(self) -> None:
141
+ """Remove expired or excess entries."""
142
+ # Remove expired entries
143
+ keys_to_remove = [k for k, v in self.cache.items() if v.expired]
144
+ for k in keys_to_remove:
145
+ del self.cache[k]
146
+
147
+ # Ensure we don't exceed max capacity
148
+ while len(self.cache) > self.max_capacity:
149
+ self.cache.popitem(last=False)
150
+
151
+
152
+ F = Callable[[UUID], Any]
153
+
154
+
155
+ def cache_result(
156
+ expiry: Optional[int] = None,
157
+ ) -> Callable[[F], F]:
158
+ """A decorator to cache the result of a function based on a UUID key argument.
159
+
160
+ Args:
161
+ expiry: Custom time in seconds for the cache entry to expire. If None,
162
+ uses the default expiry time.
163
+
164
+ Returns:
165
+ A decorator that wraps a function, caching its results based on a UUID
166
+ key.
167
+ """
168
+
169
+ def decorator(func: F) -> F:
170
+ """The actual decorator that wraps the function with caching logic.
171
+
172
+ Args:
173
+ func: The function to wrap.
174
+
175
+ Returns:
176
+ The wrapped function with caching logic.
177
+ """
178
+
179
+ def wrapper(key: UUID) -> Any:
180
+ """The wrapped function with caching logic.
181
+
182
+ Args:
183
+ key: The key to use for caching.
184
+
185
+ Returns:
186
+ The result of the original function, either from cache or
187
+ freshly computed.
188
+ """
189
+ from zenml.zen_server.utils import memcache
190
+
191
+ cache = memcache()
192
+
193
+ # Attempt to retrieve the result from cache
194
+ cached_value = cache.get(key)
195
+ if cached_value is not None:
196
+ logger.debug(
197
+ f"Memory cache hit for key: {key} and func: {func.__name__}"
198
+ )
199
+ return cached_value
200
+
201
+ # Call the original function and cache its result
202
+ result = func(key)
203
+ cache.set(key, result, expiry)
204
+ return result
205
+
206
+ return wrapper
207
+
208
+ return decorator
@@ -1 +1 @@
1
- import{j as e}from"./@radix-DP6vWzyx.js";import{f as s,r as t}from"./index-QQb7wQEC.js";import{E as r}from"./EmptyState-DeK7H4pr.js";import{S as a}from"./help-Dam461dC.js";import{L as o}from"./@react-router-BMhZulnd.js";import"./@tanstack-BUCbhJyH.js";import"./@reactflow-8U9qNlMR.js";function d(){return e.jsx("div",{className:"flex min-h-screen w-full flex-col",children:e.jsx(r,{icon:e.jsx(a,{className:"h-[120px] w-[120px] fill-neutral-300"}),children:e.jsxs("div",{className:"text-center",children:[e.jsx("h1",{className:"mb-2 text-display-xs font-semibold",children:"We can't find the page you are looking for"}),e.jsx("p",{className:"text-lg text-theme-text-secondary",children:"You can try typing a different URL or we can bring you back to your Homepage."}),e.jsx("div",{className:"mt-5 flex justify-center",children:e.jsx(s,{size:"md",asChild:!0,children:e.jsx(o,{className:"w-min self-center whitespace-nowrap",to:t.home,children:e.jsx("span",{className:"px-0.5",children:"Go to Home"})})})})]})})})}export{d as default};
1
+ import{j as e}from"./@radix-DeK6qiuw.js";import{f as s,r as t}from"./index-CCOPpudF.js";import{E as r}from"./EmptyState-BzdlCwp3.js";import{S as a}from"./help-Cc9bBIJH.js";import{L as o}from"./@react-router-B3Z5rLr2.js";import"./@tanstack-DT5WLu9C.js";import"./@reactflow-CK0KJUen.js";function d(){return e.jsx("div",{className:"flex min-h-screen w-full flex-col",children:e.jsx(r,{icon:e.jsx(a,{className:"h-[120px] w-[120px] fill-neutral-300"}),children:e.jsxs("div",{className:"text-center",children:[e.jsx("h1",{className:"mb-2 text-display-xs font-semibold",children:"We can't find the page you are looking for"}),e.jsx("p",{className:"text-lg text-theme-text-secondary",children:"You can try typing a different URL or we can bring you back to your Homepage."}),e.jsx("div",{className:"mt-5 flex justify-center",children:e.jsx(s,{size:"md",asChild:!0,children:e.jsx(o,{className:"w-min self-center whitespace-nowrap",to:t.home,children:e.jsx("span",{className:"px-0.5",children:"Go to Home"})})})})]})})})}export{d as default};