zenml-nightly 0.84.0.dev20250728__py3-none-any.whl → 0.84.0.dev20250730__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.
- zenml/VERSION +1 -1
- zenml/client.py +6 -1
- zenml/code_repositories/git/local_git_repository_context.py +3 -4
- zenml/constants.py +28 -0
- zenml/integrations/azure/service_connectors/azure_service_connector.py +20 -9
- zenml/integrations/gcp/__init__.py +4 -1
- zenml/integrations/kubernetes/flavors/kubernetes_orchestrator_flavor.py +20 -1
- zenml/integrations/kubernetes/orchestrators/kube_utils.py +80 -3
- zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator_entrypoint.py +18 -14
- zenml/logging/__init__.py +0 -11
- zenml/logging/step_logging.py +255 -149
- zenml/models/__init__.py +6 -0
- zenml/models/v2/core/service_account.py +87 -1
- zenml/models/v2/core/step_run.py +13 -0
- zenml/models/v2/core/user.py +20 -6
- zenml/models/v2/misc/exception_info.py +30 -0
- zenml/models/v2/misc/external_user.py +4 -1
- zenml/orchestrators/publish_utils.py +10 -0
- zenml/orchestrators/step_launcher.py +11 -6
- zenml/orchestrators/step_runner.py +26 -1
- zenml/utils/exception_utils.py +90 -0
- zenml/zen_server/auth.py +138 -27
- zenml/zen_server/dashboard/assets/{404-B5cfnwZ1.js → 404-CMbwR10f.js} +1 -1
- zenml/zen_server/dashboard/assets/{@radix-C_LirfyT.js → @radix-B1sy0Lhr.js} +1 -1
- zenml/zen_server/dashboard/assets/{@react-router-BSsrkPOd.js → @react-router-CHjLNlgw.js} +1 -1
- zenml/zen_server/dashboard/assets/{@reactflow-D9hglKLF.js → @reactflow-gbyyU3kq.js} +2 -2
- zenml/zen_server/dashboard/assets/{@tanstack-C0SeHZng.js → @tanstack-Dwlisomv.js} +1 -1
- zenml/zen_server/dashboard/assets/AlertDialogDropdownItem-BpLj419i.js +1 -0
- zenml/zen_server/dashboard/assets/ButtonGroup-DVhzbQxV.js +1 -0
- zenml/zen_server/dashboard/assets/{CodeSnippet-D8iBqOVv.js → CodeSnippet-B7Wd4R8u.js} +1 -1
- zenml/zen_server/dashboard/assets/{CollapsibleCard-D0-pQi1n.js → CollapsibleCard-DSZzbjx5.js} +1 -1
- zenml/zen_server/dashboard/assets/{ComponentBadge-mw2Ja_ON.js → ComponentBadge-MVT08kBV.js} +1 -1
- zenml/zen_server/dashboard/assets/{ComponentIcon-BXgpt-jw.js → ComponentIcon-C9AY8usJ.js} +1 -1
- zenml/zen_server/dashboard/assets/DeleteAlertDialog-CzhTVQaC.js +1 -0
- zenml/zen_server/dashboard/assets/{DialogItem-DeME0oSt.js → DialogItem-DD_7v3UY.js} +1 -1
- zenml/zen_server/dashboard/assets/{DisplayDate-v3KW7oez.js → DisplayDate-57lUNS79.js} +1 -1
- zenml/zen_server/dashboard/assets/{EmptyState-DG0m-CGv.js → EmptyState-BMA34iVR.js} +1 -1
- zenml/zen_server/dashboard/assets/{Error-DcVLcrLs.js → Error-Cakgjexo.js} +1 -1
- zenml/zen_server/dashboard/assets/{ExecutionStatus-C4tlFnlh.js → ExecutionStatus-CQbWovhV.js} +1 -1
- zenml/zen_server/dashboard/assets/{Helpbox-C-RGHz3S.js → Helpbox-7FZpmsHB.js} +1 -1
- zenml/zen_server/dashboard/assets/{Infobox-DFCWPbMb.js → Infobox-DnduZjNU.js} +1 -1
- zenml/zen_server/dashboard/assets/{LeftSideMenu-Czev0KCA.js → LeftSideMenu-D5UEs4vB.js} +1 -1
- zenml/zen_server/dashboard/assets/{Lock-CRP5J_su.js → Lock-u8WOoTTd.js} +1 -1
- zenml/zen_server/dashboard/assets/NestedCollapsible-0yviIfaA.js +1 -0
- zenml/zen_server/dashboard/assets/{NumberBox-CoQjQYDJ.js → NumberBox-C2Pju4PR.js} +1 -1
- zenml/zen_server/dashboard/assets/{Pagination-CcDD5yHh.js → Pagination-C1sE5Nzn.js} +1 -1
- zenml/zen_server/dashboard/assets/{Partials-DlMzfKgs.js → Partials-DosysQMU.js} +1 -1
- zenml/zen_server/dashboard/assets/{PasswordChecker-BZwoeQIm.js → PasswordChecker-DOPLfvg7.js} +1 -1
- zenml/zen_server/dashboard/assets/{ProCta-CU2ycJDo.js → ProCta-CUkpV3PJ.js} +1 -1
- zenml/zen_server/dashboard/assets/{ProviderIcon-BMAn9Jld.js → ProviderIcon-aQjTuTRX.js} +1 -1
- zenml/zen_server/dashboard/assets/{ProviderRadio-D_q9tE3G.js → ProviderRadio-C6pLVNxC.js} +1 -1
- zenml/zen_server/dashboard/assets/RunsBody-CZAiSxYK.js +1 -0
- zenml/zen_server/dashboard/assets/{SearchField-D_0-uAPj.js → SearchField-Byv1PtST.js} +1 -1
- zenml/zen_server/dashboard/assets/{SecretTooltip-BcWMKb9f.js → SecretTooltip-CErfhVgF.js} +1 -1
- zenml/zen_server/dashboard/assets/{SetPassword-CaKVSqAL.js → SetPassword-C4OH-cn1.js} +1 -1
- zenml/zen_server/dashboard/assets/{SheetHeader-7vwlsY_i.js → SheetHeader-Bb3v9rha.js} +1 -1
- zenml/zen_server/dashboard/assets/StackComponentList-D85oab98.js +1 -0
- zenml/zen_server/dashboard/assets/StackList-DSAjbVb5.js +1 -0
- zenml/zen_server/dashboard/assets/Tabs-2uwqXsdL.js +1 -0
- zenml/zen_server/dashboard/assets/Tick-BQ7_xDBl.js +1 -0
- zenml/zen_server/dashboard/assets/{UpdatePasswordSchemas-Da5RndbV.js → UpdatePasswordSchemas-DNkYgzN6.js} +1 -1
- zenml/zen_server/dashboard/assets/{Wizard-8aJzxUjb.js → Wizard-2FIi8JNY.js} +1 -1
- zenml/zen_server/dashboard/assets/WizardFooter-DQEnlDmZ.js +1 -0
- zenml/zen_server/dashboard/assets/{all-pipeline-runs-query-gorNNEaT.js → all-pipeline-runs-query-CdvWtiAY.js} +1 -1
- zenml/zen_server/dashboard/assets/{arrow-left-hcj2H8HY.js → arrow-left-BFB2mgJo.js} +1 -1
- zenml/zen_server/dashboard/assets/{bar-chart-square-check-9siI9icm.js → bar-chart-square-check-_m-oYysN.js} +1 -1
- zenml/zen_server/dashboard/assets/{bulk-delete-B5RTlnD_.js → bulk-delete-wdObjfps.js} +2 -2
- zenml/zen_server/dashboard/assets/{check-D1bHMJkL.js → check-C9Nye5lR.js} +1 -1
- zenml/zen_server/dashboard/assets/{check-circle-mnEgPhPF.js → check-circle-CG6XAdk-.js} +1 -1
- zenml/zen_server/dashboard/assets/{chevron-down-Z3nUe-0U.js → chevron-down-Bl7WwQAL.js} +1 -1
- zenml/zen_server/dashboard/assets/{chevron-right-double-CbRQKN4Q.js → chevron-right-double-CbMG1dOM.js} +1 -1
- zenml/zen_server/dashboard/assets/{clock-BMjHXT3f.js → clock-BnPvxp3D.js} +1 -1
- zenml/zen_server/dashboard/assets/{code-browser-DftoiCIg.js → code-browser-CzWvJ4S6.js} +1 -1
- zenml/zen_server/dashboard/assets/configuration-form-BbcNBQTO.js +1 -0
- zenml/zen_server/dashboard/assets/constants-DfvsDtcH.js +1 -0
- zenml/zen_server/dashboard/assets/{create-stack-BruqH_6X.js → create-stack-D4Sf7QpF.js} +1 -1
- zenml/zen_server/dashboard/assets/{credit-card-CH1BHrXY.js → credit-card-DfBA6dBb.js} +1 -1
- zenml/zen_server/dashboard/assets/{dataflow-2-qHjWt7zp.js → dataflow-2-BLkaTH0Q.js} +1 -1
- zenml/zen_server/dashboard/assets/{delete-run-ibBtciMR.js → delete-run-XSre8ru-.js} +1 -1
- zenml/zen_server/dashboard/assets/{expand-full-CD4fFvM-.js → expand-full-C8p_0jQv.js} +1 -1
- zenml/zen_server/dashboard/assets/{eye-CLNgIh_K.js → eye-BXcQevds.js} +1 -1
- zenml/zen_server/dashboard/assets/{file-text-CltVhgwZ.js → file-text-TdPXNd7s.js} +1 -1
- zenml/zen_server/dashboard/assets/form-C1jJgRy1.js +1 -0
- zenml/zen_server/dashboard/assets/{form-schemas-B9XgTS1V.js → form-schemas-BjWDRvGd.js} +1 -1
- zenml/zen_server/dashboard/assets/{help-B0CvBhCm.js → help-CRPfbPTO.js} +1 -1
- zenml/zen_server/dashboard/assets/{icon-hDriJUXY.js → icon--Tp6obFZ.js} +1 -1
- zenml/zen_server/dashboard/assets/{index-mA8kL088.js → index-B4ZeIaPd.js} +1 -1
- zenml/zen_server/dashboard/assets/{index-dCcVgFNl.js → index-BYHxFvoG.js} +1 -1
- zenml/zen_server/dashboard/assets/{index-BQWlHo1Y.js → index-BYzR7YrM.js} +1 -1
- zenml/zen_server/dashboard/assets/{index-BacoJBEQ.js → index-CO6UN3UX.js} +11 -11
- zenml/zen_server/dashboard/assets/{index-B7CRNU8l.js → index-d_QrPL-8.js} +1 -1
- zenml/zen_server/dashboard/assets/{index-BRhKF2z-.js → index-g7wOyc86.js} +1 -1
- zenml/zen_server/dashboard/assets/index-n_sn2ITN.css +1 -0
- zenml/zen_server/dashboard/assets/{index.es-DcVFDpJU.js → index.es-CZMSrR6z.js} +1 -1
- zenml/zen_server/dashboard/assets/{index.esm-COnaHLSh.js → index.esm-SBF9nn_P.js} +1 -1
- zenml/zen_server/dashboard/assets/{info-CyMih3vQ.js → info-CI2szPUG.js} +1 -1
- zenml/zen_server/dashboard/assets/{key-icon-HOx2gazv.js → key-icon-BiV171aI.js} +1 -1
- zenml/zen_server/dashboard/assets/layout-Cyc-V16c.js +1 -0
- zenml/zen_server/dashboard/assets/{layout-C5dgIReC.js → layout-GIiNvS10.js} +1 -1
- zenml/zen_server/dashboard/assets/{login-mutation-CidpsqyH.js → login-mutation-CDgTlQBD.js} +1 -1
- zenml/zen_server/dashboard/assets/{logs-DoLoTEfj.js → logs-lNLbZqHL.js} +1 -1
- zenml/zen_server/dashboard/assets/{mail-C160gvB0.js → mail-DBJRSzyu.js} +1 -1
- zenml/zen_server/dashboard/assets/{message-chat-square-DLz6XmPS.js → message-chat-square-C3CRCQvD.js} +1 -1
- zenml/zen_server/dashboard/assets/{package-BhYXGPxF.js → package-pR4bbXJp.js} +1 -1
- zenml/zen_server/dashboard/assets/page-1DXG7hp8.js +1 -0
- zenml/zen_server/dashboard/assets/{page-BCRXJXC9.js → page-43SWdz4k.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-YdWnx9MX.js → page-AOVMuHDc.js} +1 -1
- zenml/zen_server/dashboard/assets/page-B4QBxV0B.js +22 -0
- zenml/zen_server/dashboard/assets/{page-CvllZMBF.js → page-B8ict_cR.js} +1 -1
- zenml/zen_server/dashboard/assets/page-BDre_qCO.js +1 -0
- zenml/zen_server/dashboard/assets/page-BbsvGfyi.js +18 -0
- zenml/zen_server/dashboard/assets/page-Bi4I23Hs.js +1 -0
- zenml/zen_server/dashboard/assets/page-BnAMyQZb.js +1 -0
- zenml/zen_server/dashboard/assets/{page-D6cvOG8w.js → page-BnZEAhNn.js} +1 -1
- zenml/zen_server/dashboard/assets/page-Bncp08FW.js +1 -0
- zenml/zen_server/dashboard/assets/{page-BTDi81N3.js → page-C4Jnp1qP.js} +1 -1
- zenml/zen_server/dashboard/assets/page-C7Z2sDHE.js +1 -0
- zenml/zen_server/dashboard/assets/page-C8t9qLdV.js +1 -0
- zenml/zen_server/dashboard/assets/{page-BByayrO-.js → page-C9IsnFid.js} +2 -2
- zenml/zen_server/dashboard/assets/page-CEHZzQ1Q.js +1 -0
- zenml/zen_server/dashboard/assets/page-CGtll3Jk.js +1 -0
- zenml/zen_server/dashboard/assets/{page-q41JNDWO.js → page-CKPkbOoE.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-DF4FVxxW.js → page-CMvcoaSZ.js} +2 -2
- zenml/zen_server/dashboard/assets/page-CVwTAlzd.js +1 -0
- zenml/zen_server/dashboard/assets/{page-DSZfclXt.js → page-ClqRvz_V.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-7CJ4Wq3O.js → page-CzDjN1wE.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-BK59rZvf.js → page-D654xHWd.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-DcXrWWWh.js → page-DLrYW-Dn.js} +1 -1
- zenml/zen_server/dashboard/assets/page-DOnAInjC.js +1 -0
- zenml/zen_server/dashboard/assets/{page-Cc8owYXQ.js → page-DQncGJeH.js} +1 -1
- zenml/zen_server/dashboard/assets/page-DQzNmXk3.js +1 -0
- zenml/zen_server/dashboard/assets/{page-FQxi1Otg.js → page-DSn1Jcvs.js} +1 -1
- zenml/zen_server/dashboard/assets/page-DZ5hcS1o.js +1 -0
- zenml/zen_server/dashboard/assets/page-DerIbaqa.js +1 -0
- zenml/zen_server/dashboard/assets/{page-8U20Tu_8.js → page-DgOEl3Bc.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-DgldL5UB.js → page-DgSu4pTE.js} +2 -2
- zenml/zen_server/dashboard/assets/page-DgblJuXC.js +1 -0
- zenml/zen_server/dashboard/assets/{page-CY0LPcAJ.js → page-Dpw-xP4q.js} +1 -1
- zenml/zen_server/dashboard/assets/page-DsFXol8x.js +1 -0
- zenml/zen_server/dashboard/assets/page-Du6bFZTS.js +1 -0
- zenml/zen_server/dashboard/assets/{page-CeGBDh1Q.js → page-DznxxpKA.js} +1 -1
- zenml/zen_server/dashboard/assets/page-E9Mx9_rn.js +1 -0
- zenml/zen_server/dashboard/assets/page-HrebZOAM.js +1 -0
- zenml/zen_server/dashboard/assets/{page-BX67x4iL.js → page-O5xnz_nW.js} +1 -1
- zenml/zen_server/dashboard/assets/{page-DDWW21kl.js → page-hX7NkNdA.js} +1 -1
- zenml/zen_server/dashboard/assets/{persist-BKKcL1Kp.js → persist-B3Hb8HDW.js} +1 -1
- zenml/zen_server/dashboard/assets/{persist-DxiyfAax.js → persist-Dkbp9MFP.js} +1 -1
- zenml/zen_server/dashboard/assets/{pipeline-BJ8liDnl.js → pipeline-CDJSAXrb.js} +1 -1
- zenml/zen_server/dashboard/assets/{plus-cI8zD2xh.js → plus-DOrkJCmy.js} +1 -1
- zenml/zen_server/dashboard/assets/primary-role-CjkpP9fL.js +1 -0
- zenml/zen_server/dashboard/assets/{react-error-boundary.esm-DoXxY4pT.js → react-error-boundary.esm-DgOYA0wh.js} +1 -1
- zenml/zen_server/dashboard/assets/{refresh-3EF2R7ja.js → refresh-C8BXS3Fb.js} +1 -1
- zenml/zen_server/dashboard/assets/{resource-tyes-list-B5rkZcbc.js → resource-tyes-list-CugyWUAE.js} +1 -1
- zenml/zen_server/dashboard/assets/{resource-type-tooltip-E97WGqfk.js → resource-type-tooltip-V-zdiLKz.js} +1 -1
- zenml/zen_server/dashboard/assets/{service-B9aVzfAF.js → service-FjqYTmBw.js} +2 -2
- zenml/zen_server/dashboard/assets/{service-connectors-DL2-k_E2.js → service-connectors-nF4-OXB9.js} +1 -1
- zenml/zen_server/dashboard/assets/{sharedSchema-DyUO09BR.js → sharedSchema-Br1JPr8d.js} +1 -1
- zenml/zen_server/dashboard/assets/{slash-circle-D2Lb2FyR.js → slash-circle-B0xMh8q6.js} +1 -1
- zenml/zen_server/dashboard/assets/{stack-detail-query-Bc4QKlWg.js → stack-detail-query-DnyMCdVE.js} +1 -1
- zenml/zen_server/dashboard/assets/{terminal-BObrvDlO.js → terminal-C2tAF2XG.js} +1 -1
- zenml/zen_server/dashboard/assets/{terminal-square-BObrvDlO.js → terminal-square-C2tAF2XG.js} +1 -1
- zenml/zen_server/dashboard/assets/{transform-DFpKTKgF.js → transform-S7omcvTm.js} +1 -1
- zenml/zen_server/dashboard/assets/{trash-HKxXWbSG.js → trash-D9LA4VFD.js} +1 -1
- zenml/zen_server/dashboard/assets/{update-current-user-mutation-DSyUyHVj.js → update-current-user-mutation-B3Dpv3u6.js} +1 -1
- zenml/zen_server/dashboard/assets/{update-server-settings-mutation-CdM-Sdds.js → update-server-settings-mutation-s7tlHN8s.js} +1 -1
- zenml/zen_server/dashboard/assets/{zod-DgEcN9jD.js → zod-D48zuELD.js} +1 -1
- zenml/zen_server/dashboard/index.html +7 -7
- zenml/zen_server/rbac/zenml_cloud_rbac.py +8 -4
- zenml/zen_server/routers/service_accounts_endpoints.py +71 -12
- zenml/zen_stores/base_zen_store.py +0 -19
- zenml/zen_stores/migrations/versions/8d4b9ba22c1f_add_user_avatar.py +39 -0
- zenml/zen_stores/migrations/versions/d4591f95ac07_step_exception_info.py +43 -0
- zenml/zen_stores/schemas/step_run_schemas.py +19 -0
- zenml/zen_stores/schemas/user_schemas.py +16 -5
- zenml/zen_stores/sql_zen_store.py +5 -1
- {zenml_nightly-0.84.0.dev20250728.dist-info → zenml_nightly-0.84.0.dev20250730.dist-info}/METADATA +1 -1
- {zenml_nightly-0.84.0.dev20250728.dist-info → zenml_nightly-0.84.0.dev20250730.dist-info}/RECORD +180 -176
- zenml/zen_server/dashboard/assets/AlertDialogDropdownItem-druRNuO2.js +0 -1
- zenml/zen_server/dashboard/assets/ButtonGroup-SF2DlzHV.js +0 -1
- zenml/zen_server/dashboard/assets/DeleteAlertDialog-BbyFVnVI.js +0 -1
- zenml/zen_server/dashboard/assets/NestedCollapsible-CN9scBUn.js +0 -1
- zenml/zen_server/dashboard/assets/RunsBody-BToytB8e.js +0 -1
- zenml/zen_server/dashboard/assets/StackComponentList-s7eSfm8o.js +0 -1
- zenml/zen_server/dashboard/assets/StackList-Dt0FrIkM.js +0 -1
- zenml/zen_server/dashboard/assets/Tabs-B27AHUfo.js +0 -1
- zenml/zen_server/dashboard/assets/Tick-DDeDgTuT.js +0 -1
- zenml/zen_server/dashboard/assets/WizardFooter-Bt7_UE14.js +0 -1
- zenml/zen_server/dashboard/assets/configuration-form-Yz8m0QIG.js +0 -1
- zenml/zen_server/dashboard/assets/constants-DeV48DuZ.js +0 -1
- zenml/zen_server/dashboard/assets/form-6aSt3tIl.js +0 -1
- zenml/zen_server/dashboard/assets/index-eggipFZS.css +0 -1
- zenml/zen_server/dashboard/assets/layout-CFLL6-CM.js +0 -1
- zenml/zen_server/dashboard/assets/page-6huxSHEu.js +0 -1
- zenml/zen_server/dashboard/assets/page-BMpXak4U.js +0 -1
- zenml/zen_server/dashboard/assets/page-Bjmcdg64.js +0 -1
- zenml/zen_server/dashboard/assets/page-BsAn8p4m.js +0 -1
- zenml/zen_server/dashboard/assets/page-BwjPRuaY.js +0 -1
- zenml/zen_server/dashboard/assets/page-CDtSVkNc.js +0 -1
- zenml/zen_server/dashboard/assets/page-CEDU0L2T.js +0 -1
- zenml/zen_server/dashboard/assets/page-COJK90rG.js +0 -1
- zenml/zen_server/dashboard/assets/page-C_XMn4GU.js +0 -1
- zenml/zen_server/dashboard/assets/page-Cb3KGsPK.js +0 -22
- zenml/zen_server/dashboard/assets/page-CiGOVsj3.js +0 -1
- zenml/zen_server/dashboard/assets/page-CmLSFMkW.js +0 -1
- zenml/zen_server/dashboard/assets/page-CnfCptXq.js +0 -1
- zenml/zen_server/dashboard/assets/page-CxzglV3-.js +0 -1
- zenml/zen_server/dashboard/assets/page-DVLez4R1.js +0 -1
- zenml/zen_server/dashboard/assets/page-Dg7-H_9i.js +0 -1
- zenml/zen_server/dashboard/assets/page-Dw7XuiSo.js +0 -18
- zenml/zen_server/dashboard/assets/page-XrmOHHg7.js +0 -1
- zenml/zen_server/dashboard/assets/page-oRm7D4TC.js +0 -1
- zenml/zen_server/dashboard/assets/page-x2GXC8sI.js +0 -1
- zenml/zen_server/dashboard/assets/page-z2FXP4GY.js +0 -1
- zenml/zen_server/dashboard/assets/primary-role-CPGHymjN.js +0 -1
- {zenml_nightly-0.84.0.dev20250728.dist-info → zenml_nightly-0.84.0.dev20250730.dist-info}/LICENSE +0 -0
- {zenml_nightly-0.84.0.dev20250728.dist-info → zenml_nightly-0.84.0.dev20250730.dist-info}/WHEEL +0 -0
- {zenml_nightly-0.84.0.dev20250728.dist-info → zenml_nightly-0.84.0.dev20250730.dist-info}/entry_points.txt +0 -0
@@ -14,6 +14,7 @@
|
|
14
14
|
"""Models representing service accounts."""
|
15
15
|
|
16
16
|
from typing import TYPE_CHECKING, ClassVar, List, Optional, Type, Union
|
17
|
+
from uuid import UUID
|
17
18
|
|
18
19
|
from pydantic import ConfigDict, Field
|
19
20
|
|
@@ -43,8 +44,13 @@ class ServiceAccountRequest(BaseRequest):
|
|
43
44
|
]
|
44
45
|
|
45
46
|
name: str = Field(
|
46
|
-
title="The unique
|
47
|
+
title="The unique username for the service account.",
|
48
|
+
max_length=STR_FIELD_MAX_LENGTH,
|
49
|
+
)
|
50
|
+
full_name: str = Field(
|
51
|
+
default="",
|
47
52
|
max_length=STR_FIELD_MAX_LENGTH,
|
53
|
+
title="The display name of the service account.",
|
48
54
|
)
|
49
55
|
description: Optional[str] = Field(
|
50
56
|
default=None,
|
@@ -52,9 +58,23 @@ class ServiceAccountRequest(BaseRequest):
|
|
52
58
|
max_length=TEXT_FIELD_MAX_LENGTH,
|
53
59
|
)
|
54
60
|
active: bool = Field(title="Whether the service account is active or not.")
|
61
|
+
avatar_url: Optional[str] = Field(
|
62
|
+
default=None,
|
63
|
+
title="The avatar URL for the account.",
|
64
|
+
)
|
65
|
+
|
55
66
|
model_config = ConfigDict(validate_assignment=True, extra="ignore")
|
56
67
|
|
57
68
|
|
69
|
+
class ServiceAccountInternalRequest(ServiceAccountRequest):
|
70
|
+
"""Internal request model for service accounts."""
|
71
|
+
|
72
|
+
external_user_id: Optional[UUID] = Field(
|
73
|
+
default=None,
|
74
|
+
title="The external user ID associated with the account.",
|
75
|
+
)
|
76
|
+
|
77
|
+
|
58
78
|
# ------------------ Update Model ------------------
|
59
79
|
|
60
80
|
|
@@ -68,6 +88,11 @@ class ServiceAccountUpdate(BaseUpdate):
|
|
68
88
|
max_length=STR_FIELD_MAX_LENGTH,
|
69
89
|
default=None,
|
70
90
|
)
|
91
|
+
full_name: Optional[str] = Field(
|
92
|
+
title="The display name of the service account.",
|
93
|
+
max_length=STR_FIELD_MAX_LENGTH,
|
94
|
+
default=None,
|
95
|
+
)
|
71
96
|
description: Optional[str] = Field(
|
72
97
|
title="A description of the service account.",
|
73
98
|
max_length=TEXT_FIELD_MAX_LENGTH,
|
@@ -78,16 +103,38 @@ class ServiceAccountUpdate(BaseUpdate):
|
|
78
103
|
default=None,
|
79
104
|
)
|
80
105
|
|
106
|
+
avatar_url: Optional[str] = Field(
|
107
|
+
default=None,
|
108
|
+
title="The avatar URL for the account.",
|
109
|
+
)
|
110
|
+
|
81
111
|
model_config = ConfigDict(validate_assignment=True)
|
82
112
|
|
83
113
|
|
114
|
+
class ServiceAccountInternalUpdate(ServiceAccountUpdate):
|
115
|
+
"""Internal update model for service accounts."""
|
116
|
+
|
117
|
+
external_user_id: Optional[UUID] = Field(
|
118
|
+
default=None,
|
119
|
+
title="The external user ID associated with the account.",
|
120
|
+
)
|
121
|
+
|
122
|
+
|
84
123
|
# ------------------ Response Model ------------------
|
85
124
|
|
86
125
|
|
87
126
|
class ServiceAccountResponseBody(BaseDatedResponseBody):
|
88
127
|
"""Response body for service accounts."""
|
89
128
|
|
129
|
+
full_name: str = Field(
|
130
|
+
default="",
|
131
|
+
title="The display name of the service account.",
|
132
|
+
)
|
90
133
|
active: bool = Field(default=False, title="Whether the account is active.")
|
134
|
+
avatar_url: Optional[str] = Field(
|
135
|
+
default=None,
|
136
|
+
title="The avatar URL for the account.",
|
137
|
+
)
|
91
138
|
|
92
139
|
|
93
140
|
class ServiceAccountResponseMetadata(BaseResponseMetadata):
|
@@ -99,6 +146,11 @@ class ServiceAccountResponseMetadata(BaseResponseMetadata):
|
|
99
146
|
max_length=TEXT_FIELD_MAX_LENGTH,
|
100
147
|
)
|
101
148
|
|
149
|
+
external_user_id: Optional[UUID] = Field(
|
150
|
+
default=None,
|
151
|
+
title="The external user ID associated with the account.",
|
152
|
+
)
|
153
|
+
|
102
154
|
|
103
155
|
class ServiceAccountResponseResources(BaseResponseResources):
|
104
156
|
"""Class for all resource models associated with the service account entity."""
|
@@ -160,6 +212,8 @@ class ServiceAccountResponse(
|
|
160
212
|
created=self.created,
|
161
213
|
updated=self.updated,
|
162
214
|
is_admin=False,
|
215
|
+
avatar_url=self.avatar_url,
|
216
|
+
full_name=self.full_name,
|
163
217
|
),
|
164
218
|
metadata=UserResponseMetadata(
|
165
219
|
description=self.description,
|
@@ -167,6 +221,15 @@ class ServiceAccountResponse(
|
|
167
221
|
)
|
168
222
|
|
169
223
|
# Body and metadata properties
|
224
|
+
@property
|
225
|
+
def full_name(self) -> str:
|
226
|
+
"""The `full_name` property.
|
227
|
+
|
228
|
+
Returns:
|
229
|
+
the value of the property.
|
230
|
+
"""
|
231
|
+
return self.get_body().full_name
|
232
|
+
|
170
233
|
@property
|
171
234
|
def active(self) -> bool:
|
172
235
|
"""The `active` property.
|
@@ -185,6 +248,24 @@ class ServiceAccountResponse(
|
|
185
248
|
"""
|
186
249
|
return self.get_metadata().description
|
187
250
|
|
251
|
+
@property
|
252
|
+
def external_user_id(self) -> Optional[UUID]:
|
253
|
+
"""The `external_user_id` property.
|
254
|
+
|
255
|
+
Returns:
|
256
|
+
the value of the property.
|
257
|
+
"""
|
258
|
+
return self.get_metadata().external_user_id
|
259
|
+
|
260
|
+
@property
|
261
|
+
def avatar_url(self) -> Optional[str]:
|
262
|
+
"""The `avatar_url` property.
|
263
|
+
|
264
|
+
Returns:
|
265
|
+
the value of the property.
|
266
|
+
"""
|
267
|
+
return self.get_body().avatar_url
|
268
|
+
|
188
269
|
|
189
270
|
# ------------------ Filter Model ------------------
|
190
271
|
class ServiceAccountFilter(BaseFilter):
|
@@ -203,6 +284,11 @@ class ServiceAccountFilter(BaseFilter):
|
|
203
284
|
description="Whether the user is active",
|
204
285
|
union_mode="left_to_right",
|
205
286
|
)
|
287
|
+
external_user_id: Optional[Union[UUID, str]] = Field(
|
288
|
+
default=None,
|
289
|
+
title="The external user ID associated with the account.",
|
290
|
+
union_mode="left_to_right",
|
291
|
+
)
|
206
292
|
|
207
293
|
def apply_filter(
|
208
294
|
self,
|
zenml/models/v2/core/step_run.py
CHANGED
@@ -48,6 +48,7 @@ from zenml.models.v2.base.scoped import (
|
|
48
48
|
)
|
49
49
|
from zenml.models.v2.core.artifact_version import ArtifactVersionResponse
|
50
50
|
from zenml.models.v2.core.model_version import ModelVersionResponse
|
51
|
+
from zenml.models.v2.misc.exception_info import ExceptionInfo
|
51
52
|
|
52
53
|
if TYPE_CHECKING:
|
53
54
|
from sqlalchemy.sql.elements import ColumnElement
|
@@ -143,6 +144,10 @@ class StepRunRequest(ProjectScopedRequest):
|
|
143
144
|
title="Logs associated with this step run.",
|
144
145
|
default=None,
|
145
146
|
)
|
147
|
+
exception_info: Optional[ExceptionInfo] = Field(
|
148
|
+
default=None,
|
149
|
+
title="The exception information of the step run.",
|
150
|
+
)
|
146
151
|
|
147
152
|
model_config = ConfigDict(protected_namespaces=())
|
148
153
|
|
@@ -169,6 +174,10 @@ class StepRunUpdate(BaseUpdate):
|
|
169
174
|
title="The end time of the step run.",
|
170
175
|
default=None,
|
171
176
|
)
|
177
|
+
exception_info: Optional[ExceptionInfo] = Field(
|
178
|
+
default=None,
|
179
|
+
title="The exception information of the step run.",
|
180
|
+
)
|
172
181
|
model_config = ConfigDict(protected_namespaces=())
|
173
182
|
|
174
183
|
|
@@ -237,6 +246,10 @@ class StepRunResponseMetadata(ProjectScopedResponseMetadata):
|
|
237
246
|
default=None,
|
238
247
|
max_length=TEXT_FIELD_MAX_LENGTH,
|
239
248
|
)
|
249
|
+
exception_info: Optional[ExceptionInfo] = Field(
|
250
|
+
default=None,
|
251
|
+
title="The exception information of the step run.",
|
252
|
+
)
|
240
253
|
|
241
254
|
# References
|
242
255
|
logs: Optional["LogsResponse"] = Field(
|
zenml/models/v2/core/user.py
CHANGED
@@ -81,6 +81,10 @@ class UserBase(BaseModel):
|
|
81
81
|
default=None,
|
82
82
|
title="The metadata associated with the user.",
|
83
83
|
)
|
84
|
+
avatar_url: Optional[str] = Field(
|
85
|
+
default=None,
|
86
|
+
title="The avatar URL for the account.",
|
87
|
+
)
|
84
88
|
|
85
89
|
@classmethod
|
86
90
|
def _get_crypt_context(cls) -> "CryptContext":
|
@@ -156,8 +160,7 @@ class UserRequest(UserBase, BaseRequest):
|
|
156
160
|
)
|
157
161
|
full_name: str = Field(
|
158
162
|
default="",
|
159
|
-
title="The
|
160
|
-
"accounts.",
|
163
|
+
title="The display name for the account.",
|
161
164
|
max_length=STR_FIELD_MAX_LENGTH,
|
162
165
|
)
|
163
166
|
is_admin: bool = Field(
|
@@ -186,8 +189,7 @@ class UserUpdate(UserBase, BaseUpdate):
|
|
186
189
|
)
|
187
190
|
full_name: Optional[str] = Field(
|
188
191
|
default=None,
|
189
|
-
title="The
|
190
|
-
"accounts.",
|
192
|
+
title="The display name for the account.",
|
191
193
|
max_length=STR_FIELD_MAX_LENGTH,
|
192
194
|
)
|
193
195
|
is_admin: Optional[bool] = Field(
|
@@ -266,8 +268,7 @@ class UserResponseBody(BaseDatedResponseBody):
|
|
266
268
|
)
|
267
269
|
full_name: str = Field(
|
268
270
|
default="",
|
269
|
-
title="The
|
270
|
-
"accounts.",
|
271
|
+
title="The display name for the account.",
|
271
272
|
max_length=STR_FIELD_MAX_LENGTH,
|
272
273
|
)
|
273
274
|
email_opted_in: Optional[bool] = Field(
|
@@ -287,6 +288,10 @@ class UserResponseBody(BaseDatedResponseBody):
|
|
287
288
|
default=None,
|
288
289
|
title="The default project ID for the user.",
|
289
290
|
)
|
291
|
+
avatar_url: Optional[str] = Field(
|
292
|
+
default=None,
|
293
|
+
title="The avatar URL for the account.",
|
294
|
+
)
|
290
295
|
|
291
296
|
|
292
297
|
class UserResponseMetadata(BaseResponseMetadata):
|
@@ -439,6 +444,15 @@ class UserResponse(
|
|
439
444
|
"""
|
440
445
|
return self.get_body().default_project_id
|
441
446
|
|
447
|
+
@property
|
448
|
+
def avatar_url(self) -> Optional[str]:
|
449
|
+
"""The `avatar_url` property.
|
450
|
+
|
451
|
+
Returns:
|
452
|
+
the value of the property.
|
453
|
+
"""
|
454
|
+
return self.get_body().avatar_url
|
455
|
+
|
442
456
|
# Helper methods
|
443
457
|
@classmethod
|
444
458
|
def _get_crypt_context(cls) -> "CryptContext":
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# Copyright (c) ZenML GmbH 2025. 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
|
+
"""Exception information models."""
|
15
|
+
|
16
|
+
from typing import Optional
|
17
|
+
|
18
|
+
from pydantic import BaseModel, Field
|
19
|
+
|
20
|
+
|
21
|
+
class ExceptionInfo(BaseModel):
|
22
|
+
"""Exception information."""
|
23
|
+
|
24
|
+
traceback: str = Field(
|
25
|
+
title="The traceback of the exception.",
|
26
|
+
)
|
27
|
+
step_code_line: Optional[int] = Field(
|
28
|
+
default=None,
|
29
|
+
title="The line number of the step code that raised the exception.",
|
30
|
+
)
|
@@ -23,8 +23,11 @@ class ExternalUserModel(BaseModel):
|
|
23
23
|
"""External user model."""
|
24
24
|
|
25
25
|
id: UUID
|
26
|
-
|
26
|
+
username: str
|
27
|
+
email: Optional[str] = None
|
27
28
|
name: Optional[str] = None
|
28
29
|
is_admin: bool = False
|
30
|
+
is_service_account: bool = False
|
31
|
+
avatar_url: Optional[str] = None
|
29
32
|
|
30
33
|
model_config = ConfigDict(extra="ignore")
|
@@ -13,12 +13,14 @@
|
|
13
13
|
# permissions and limitations under the License.
|
14
14
|
"""Utilities to publish pipeline and step runs."""
|
15
15
|
|
16
|
+
from contextvars import ContextVar
|
16
17
|
from datetime import datetime
|
17
18
|
from typing import TYPE_CHECKING, Dict, List, Optional
|
18
19
|
|
19
20
|
from zenml.client import Client
|
20
21
|
from zenml.enums import ExecutionStatus, MetadataResourceTypes
|
21
22
|
from zenml.models import (
|
23
|
+
ExceptionInfo,
|
22
24
|
PipelineRunResponse,
|
23
25
|
PipelineRunUpdate,
|
24
26
|
RunMetadataResource,
|
@@ -32,6 +34,10 @@ if TYPE_CHECKING:
|
|
32
34
|
|
33
35
|
from zenml.metadata.metadata_types import MetadataType
|
34
36
|
|
37
|
+
step_exception_info: ContextVar[Optional[ExceptionInfo]] = ContextVar(
|
38
|
+
"step_exception_info", default=None
|
39
|
+
)
|
40
|
+
|
35
41
|
|
36
42
|
def publish_successful_step_run(
|
37
43
|
step_run_id: "UUID", output_artifact_ids: Dict[str, List["UUID"]]
|
@@ -59,6 +65,7 @@ def publish_step_run_status_update(
|
|
59
65
|
step_run_id: "UUID",
|
60
66
|
status: "ExecutionStatus",
|
61
67
|
end_time: Optional[datetime] = None,
|
68
|
+
exception_info: Optional[ExceptionInfo] = None,
|
62
69
|
) -> "StepRunResponse":
|
63
70
|
"""Publishes a step run update.
|
64
71
|
|
@@ -66,6 +73,7 @@ def publish_step_run_status_update(
|
|
66
73
|
step_run_id: ID of the step run.
|
67
74
|
status: New status of the step run.
|
68
75
|
end_time: New end time of the step run.
|
76
|
+
exception_info: Exception information of the step run.
|
69
77
|
|
70
78
|
Returns:
|
71
79
|
The updated step run.
|
@@ -83,6 +91,7 @@ def publish_step_run_status_update(
|
|
83
91
|
step_run_update=StepRunUpdate(
|
84
92
|
status=status,
|
85
93
|
end_time=end_time,
|
94
|
+
exception_info=exception_info,
|
86
95
|
),
|
87
96
|
)
|
88
97
|
|
@@ -102,6 +111,7 @@ def publish_failed_step_run(step_run_id: "UUID") -> "StepRunResponse":
|
|
102
111
|
step_run_id=step_run_id,
|
103
112
|
status=ExecutionStatus.FAILED,
|
104
113
|
end_time=utc_now(),
|
114
|
+
exception_info=step_exception_info.get(),
|
105
115
|
)
|
106
116
|
|
107
117
|
|
@@ -16,7 +16,6 @@
|
|
16
16
|
import signal
|
17
17
|
import time
|
18
18
|
from contextlib import nullcontext
|
19
|
-
from functools import partial
|
20
19
|
from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Tuple
|
21
20
|
|
22
21
|
from zenml.client import Client
|
@@ -24,6 +23,7 @@ from zenml.config.step_configurations import Step
|
|
24
23
|
from zenml.config.step_run_info import StepRunInfo
|
25
24
|
from zenml.constants import (
|
26
25
|
ENV_ZENML_DISABLE_STEP_LOGS_STORAGE,
|
26
|
+
ENV_ZENML_STEP_OPERATOR,
|
27
27
|
handle_bool_env_var,
|
28
28
|
)
|
29
29
|
from zenml.enums import ExecutionStatus
|
@@ -43,7 +43,7 @@ from zenml.orchestrators import output_utils, publish_utils, step_run_utils
|
|
43
43
|
from zenml.orchestrators import utils as orchestrator_utils
|
44
44
|
from zenml.orchestrators.step_runner import StepRunner
|
45
45
|
from zenml.stack import Stack
|
46
|
-
from zenml.utils import string_utils
|
46
|
+
from zenml.utils import exception_utils, string_utils
|
47
47
|
from zenml.utils.time_utils import utc_now
|
48
48
|
|
49
49
|
if TYPE_CHECKING:
|
@@ -211,7 +211,9 @@ class StepLauncher:
|
|
211
211
|
|
212
212
|
Raises:
|
213
213
|
RunStoppedException: If the pipeline run is stopped by the user.
|
214
|
+
BaseException: If the step preparation or execution fails.
|
214
215
|
"""
|
216
|
+
publish_utils.step_exception_info.set(None)
|
215
217
|
pipeline_run, run_was_created = self._create_or_reuse_run()
|
216
218
|
|
217
219
|
# Enable or disable step logs storage
|
@@ -269,10 +271,13 @@ class StepLauncher:
|
|
269
271
|
|
270
272
|
try:
|
271
273
|
request_factory.populate_request(request=step_run_request)
|
272
|
-
except:
|
274
|
+
except BaseException as e:
|
273
275
|
logger.exception(f"Failed preparing step `{self._step_name}`.")
|
274
276
|
step_run_request.status = ExecutionStatus.FAILED
|
275
277
|
step_run_request.end_time = utc_now()
|
278
|
+
step_run_request.exception_info = (
|
279
|
+
exception_utils.collect_exception_information(e)
|
280
|
+
)
|
276
281
|
raise
|
277
282
|
finally:
|
278
283
|
step_run = Client().zen_store.create_run_step(step_run_request)
|
@@ -293,9 +298,8 @@ class StepLauncher:
|
|
293
298
|
logs_context,
|
294
299
|
step_logging.PipelineLogsStorageContext,
|
295
300
|
):
|
296
|
-
force_write_logs =
|
297
|
-
logs_context.storage.
|
298
|
-
force=True,
|
301
|
+
force_write_logs = (
|
302
|
+
logs_context.storage.send_merge_event
|
299
303
|
)
|
300
304
|
else:
|
301
305
|
|
@@ -453,6 +457,7 @@ class StepLauncher:
|
|
453
457
|
environment = orchestrator_utils.get_config_environment_vars(
|
454
458
|
pipeline_run_id=step_run_info.run_id,
|
455
459
|
)
|
460
|
+
environment[ENV_ZENML_STEP_OPERATOR] = "True"
|
456
461
|
logger.info(
|
457
462
|
"Using step operator `%s` to run step `%s`.",
|
458
463
|
step_operator.name,
|
@@ -16,6 +16,7 @@
|
|
16
16
|
|
17
17
|
import copy
|
18
18
|
import inspect
|
19
|
+
import os
|
19
20
|
from contextlib import nullcontext
|
20
21
|
from typing import (
|
21
22
|
TYPE_CHECKING,
|
@@ -34,6 +35,7 @@ from zenml.config.step_configurations import StepConfiguration
|
|
34
35
|
from zenml.config.step_run_info import StepRunInfo
|
35
36
|
from zenml.constants import (
|
36
37
|
ENV_ZENML_DISABLE_STEP_LOGS_STORAGE,
|
38
|
+
ENV_ZENML_STEP_OPERATOR,
|
37
39
|
handle_bool_env_var,
|
38
40
|
)
|
39
41
|
from zenml.enums import ArtifactSaveType
|
@@ -41,10 +43,14 @@ from zenml.exceptions import StepInterfaceError
|
|
41
43
|
from zenml.logger import get_logger
|
42
44
|
from zenml.logging.step_logging import PipelineLogsStorageContext, redirected
|
43
45
|
from zenml.materializers.base_materializer import BaseMaterializer
|
44
|
-
from zenml.models.v2.core.step_run import
|
46
|
+
from zenml.models.v2.core.step_run import (
|
47
|
+
StepRunInputResponse,
|
48
|
+
StepRunUpdate,
|
49
|
+
)
|
45
50
|
from zenml.orchestrators.publish_utils import (
|
46
51
|
publish_step_run_metadata,
|
47
52
|
publish_successful_step_run,
|
53
|
+
step_exception_info,
|
48
54
|
)
|
49
55
|
from zenml.orchestrators.utils import (
|
50
56
|
is_setting_enabled,
|
@@ -56,6 +62,7 @@ from zenml.steps.utils import (
|
|
56
62
|
resolve_type_annotation,
|
57
63
|
)
|
58
64
|
from zenml.utils import (
|
65
|
+
exception_utils,
|
59
66
|
materializer_utils,
|
60
67
|
source_utils,
|
61
68
|
string_utils,
|
@@ -193,6 +200,24 @@ class StepRunner:
|
|
193
200
|
)
|
194
201
|
except BaseException as step_exception: # noqa: E722
|
195
202
|
step_failed = True
|
203
|
+
|
204
|
+
exception_info = exception_utils.collect_exception_information(
|
205
|
+
step_exception, step_instance
|
206
|
+
)
|
207
|
+
|
208
|
+
if ENV_ZENML_STEP_OPERATOR in os.environ:
|
209
|
+
# We're running in a step operator environment, so we can't
|
210
|
+
# depend on the step launcher to publish the exception info
|
211
|
+
Client().zen_store.update_run_step(
|
212
|
+
step_run_id=step_run_info.step_run_id,
|
213
|
+
step_run_update=StepRunUpdate(
|
214
|
+
exception_info=exception_info,
|
215
|
+
),
|
216
|
+
)
|
217
|
+
else:
|
218
|
+
# This will be published by the step launcher
|
219
|
+
step_exception_info.set(exception_info)
|
220
|
+
|
196
221
|
if not step_run.is_retriable:
|
197
222
|
if (
|
198
223
|
failure_hook_source
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# Copyright (c) ZenML GmbH 2025. 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
|
+
"""Exception utilities."""
|
15
|
+
|
16
|
+
import inspect
|
17
|
+
import os
|
18
|
+
import re
|
19
|
+
import traceback
|
20
|
+
from typing import TYPE_CHECKING, Optional
|
21
|
+
|
22
|
+
from zenml.constants import MEDIUMTEXT_MAX_LENGTH
|
23
|
+
from zenml.logger import get_logger
|
24
|
+
from zenml.models import (
|
25
|
+
ExceptionInfo,
|
26
|
+
)
|
27
|
+
|
28
|
+
if TYPE_CHECKING:
|
29
|
+
from zenml.steps import BaseStep
|
30
|
+
|
31
|
+
logger = get_logger(__name__)
|
32
|
+
|
33
|
+
|
34
|
+
def collect_exception_information(
|
35
|
+
exception: BaseException, step_instance: Optional["BaseStep"] = None
|
36
|
+
) -> ExceptionInfo:
|
37
|
+
"""Collects the exception information.
|
38
|
+
|
39
|
+
Args:
|
40
|
+
exception: The exception to collect information from.
|
41
|
+
step_instance: The step instance that is currently running.
|
42
|
+
|
43
|
+
Returns:
|
44
|
+
The exception information.
|
45
|
+
"""
|
46
|
+
tb = traceback.format_tb(exception.__traceback__)
|
47
|
+
line_number = None
|
48
|
+
start_index = None
|
49
|
+
|
50
|
+
if step_instance and (
|
51
|
+
source_file := inspect.getsourcefile(step_instance.entrypoint)
|
52
|
+
):
|
53
|
+
try:
|
54
|
+
source_file = os.path.abspath(source_file)
|
55
|
+
|
56
|
+
lines, start_line = inspect.getsourcelines(
|
57
|
+
step_instance.entrypoint
|
58
|
+
)
|
59
|
+
end_line = start_line + len(lines)
|
60
|
+
|
61
|
+
line_pattern = re.compile(f'File "{source_file}", line (\d+),')
|
62
|
+
|
63
|
+
for index, line in enumerate(tb):
|
64
|
+
match = line_pattern.search(line)
|
65
|
+
if match:
|
66
|
+
potential_line_number = int(match.group(1))
|
67
|
+
if (
|
68
|
+
potential_line_number >= start_line
|
69
|
+
and potential_line_number <= end_line
|
70
|
+
):
|
71
|
+
line_number = potential_line_number - start_line
|
72
|
+
start_index = index
|
73
|
+
break
|
74
|
+
except Exception as e:
|
75
|
+
logger.debug("Failed to detect step code line: %s", e)
|
76
|
+
|
77
|
+
if start_index is not None:
|
78
|
+
# If the code failed while executing user code, we remove the initial
|
79
|
+
# part of the traceback that is happening in the ZenML code.
|
80
|
+
tb = tb[start_index:]
|
81
|
+
|
82
|
+
tb_bytes = "\n".join(tb).encode()
|
83
|
+
tb_bytes = tb_bytes[:MEDIUMTEXT_MAX_LENGTH]
|
84
|
+
|
85
|
+
return ExceptionInfo(
|
86
|
+
# Ignore errors when decoding in case we cut off in the middle of an
|
87
|
+
# encoded character.
|
88
|
+
traceback=tb_bytes.decode(errors="ignore"),
|
89
|
+
step_code_line=line_number,
|
90
|
+
)
|