zenml-nightly 0.83.0.dev20250623__py3-none-any.whl → 0.83.1.dev20250625__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 (158) hide show
  1. zenml/VERSION +1 -1
  2. zenml/cli/login.py +21 -3
  3. zenml/config/__init__.py +13 -2
  4. zenml/constants.py +0 -1
  5. zenml/exceptions.py +16 -0
  6. zenml/integrations/airflow/orchestrators/airflow_orchestrator.py +15 -6
  7. zenml/integrations/aws/orchestrators/sagemaker_orchestrator.py +54 -58
  8. zenml/integrations/azure/orchestrators/azureml_orchestrator.py +28 -19
  9. zenml/integrations/databricks/orchestrators/databricks_orchestrator.py +19 -63
  10. zenml/integrations/gcp/orchestrators/vertex_orchestrator.py +36 -61
  11. zenml/integrations/hyperai/orchestrators/hyperai_orchestrator.py +19 -22
  12. zenml/integrations/kubeflow/orchestrators/kubeflow_orchestrator.py +28 -31
  13. zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator.py +33 -20
  14. zenml/integrations/lightning/orchestrators/lightning_orchestrator.py +25 -100
  15. zenml/integrations/skypilot/orchestrators/skypilot_base_vm_orchestrator.py +19 -8
  16. zenml/integrations/skypilot/utils.py +17 -13
  17. zenml/integrations/tekton/orchestrators/tekton_orchestrator.py +28 -12
  18. zenml/models/v2/core/step_run.py +1 -0
  19. zenml/orchestrators/__init__.py +2 -0
  20. zenml/orchestrators/base_orchestrator.py +137 -66
  21. zenml/orchestrators/input_utils.py +5 -13
  22. zenml/orchestrators/local/local_orchestrator.py +19 -9
  23. zenml/orchestrators/local_docker/local_docker_orchestrator.py +15 -5
  24. zenml/orchestrators/publish_utils.py +24 -0
  25. zenml/orchestrators/step_run_utils.py +1 -2
  26. zenml/pipelines/run_utils.py +12 -7
  27. zenml/step_operators/step_operator_entrypoint_configuration.py +1 -1
  28. zenml/zen_server/dashboard/assets/{404-DmJUgorp.js → 404-B5eko6XL.js} +1 -1
  29. zenml/zen_server/dashboard/assets/{@reactflow-8OCk19Fi.js → @reactflow-B_iCtR7X.js} +1 -1
  30. zenml/zen_server/dashboard/assets/{AlertDialogDropdownItem-CZW4QyWn.js → AlertDialogDropdownItem-DsOmO1FH.js} +1 -1
  31. zenml/zen_server/dashboard/assets/{ButtonGroup-DFWWFGUE.js → ButtonGroup-4sPZDv70.js} +1 -1
  32. zenml/zen_server/dashboard/assets/{CodeSnippet-D2HkkAGr.js → CodeSnippet-Ctplhzdc.js} +1 -1
  33. zenml/zen_server/dashboard/assets/{CollapsibleCard-CnS09ljw.js → CollapsibleCard-CBKenz9f.js} +1 -1
  34. zenml/zen_server/dashboard/assets/{ComponentBadge-CDgdd0Ks.js → ComponentBadge-Cnecw3qz.js} +1 -1
  35. zenml/zen_server/dashboard/assets/{ComponentIcon-CbbOc7lb.js → ComponentIcon-CMiVW-O6.js} +1 -1
  36. zenml/zen_server/dashboard/assets/{DeleteAlertDialog-VIOMDLmx.js → DeleteAlertDialog-DEI0YDzP.js} +1 -1
  37. zenml/zen_server/dashboard/assets/{DialogItem-ClFCqxEp.js → DialogItem-CRCDpYU6.js} +1 -1
  38. zenml/zen_server/dashboard/assets/{Error-CQzjbDcN.js → Error-BG6f_WRd.js} +1 -1
  39. zenml/zen_server/dashboard/assets/{ExecutionStatus-CWreILP0.js → ExecutionStatus-BuhNAE9w.js} +1 -1
  40. zenml/zen_server/dashboard/assets/{Helpbox-CiKxG5_X.js → Helpbox-DtUG2Bf_.js} +1 -1
  41. zenml/zen_server/dashboard/assets/{Infobox-CGxFvqzi.js → Infobox-CSBRrM6r.js} +1 -1
  42. zenml/zen_server/dashboard/assets/{LeftSideMenu-DCsKdIjC.js → LeftSideMenu-DPsCCK3z.js} +1 -1
  43. zenml/zen_server/dashboard/assets/{NestedCollapsible-3M4llYtH.js → NestedCollapsible-CMuDIJlp.js} +1 -1
  44. zenml/zen_server/dashboard/assets/{NumberBox-C0mQktmV.js → NumberBox-DtCv7jh3.js} +1 -1
  45. zenml/zen_server/dashboard/assets/Pagination-CWnEpSpN.js +1 -0
  46. zenml/zen_server/dashboard/assets/{Partials-DSjkttlz.js → Partials-CfHD6OH5.js} +1 -1
  47. zenml/zen_server/dashboard/assets/{ProCta-Dm5cWKpS.js → ProCta-CNyp04C8.js} +1 -1
  48. zenml/zen_server/dashboard/assets/{ProviderIcon-DPwMR6nF.js → ProviderIcon-DHejyg7C.js} +1 -1
  49. zenml/zen_server/dashboard/assets/{ProviderRadio-DEDNRgAb.js → ProviderRadio-tGtie8Gc.js} +1 -1
  50. zenml/zen_server/dashboard/assets/RunsBody-mYwMcWWj.js +1 -0
  51. zenml/zen_server/dashboard/assets/SearchField-BtUi6cYl.js +1 -0
  52. zenml/zen_server/dashboard/assets/{SecretTooltip-CZTRnaCV.js → SecretTooltip-B5u1UsQ9.js} +1 -1
  53. zenml/zen_server/dashboard/assets/{SetPassword-BjNGDC5e.js → SetPassword-BmbgL_ed.js} +1 -1
  54. zenml/zen_server/dashboard/assets/{SheetHeader-CASpN2Lz.js → SheetHeader-DkH7aG9K.js} +1 -1
  55. zenml/zen_server/dashboard/assets/StackComponentList-Bi8BKqCu.js +1 -0
  56. zenml/zen_server/dashboard/assets/StackList-Cvxapo0p.js +1 -0
  57. zenml/zen_server/dashboard/assets/{StackName-ojLC6xdl.js → StackName-CFSZL8ec.js} +1 -1
  58. zenml/zen_server/dashboard/assets/Tabs-D4dv48ry.js +1 -0
  59. zenml/zen_server/dashboard/assets/{Tick-BPrWnNlN.js → Tick-Qquvr4P3.js} +1 -1
  60. zenml/zen_server/dashboard/assets/{UpdatePasswordSchemas-CNfKDo2Q.js → UpdatePasswordSchemas-D_DCETSO.js} +1 -1
  61. zenml/zen_server/dashboard/assets/{UsageReason-Cb-mpV8M.js → UsageReason-DhiUV1bu.js} +1 -1
  62. zenml/zen_server/dashboard/assets/{Wizard-Dg8Pmn5A.js → Wizard-BHvY75u_.js} +1 -1
  63. zenml/zen_server/dashboard/assets/{WizardFooter-BcNDIvlQ.js → WizardFooter-FQm8y-jP.js} +1 -1
  64. zenml/zen_server/dashboard/assets/{all-pipeline-runs-query-DCdax7I5.js → all-pipeline-runs-query-DpKw9WL9.js} +1 -1
  65. zenml/zen_server/dashboard/assets/{bulk-delete-C_kpIB9A.js → bulk-delete-CzYA--cC.js} +1 -1
  66. zenml/zen_server/dashboard/assets/{configuration-form-B2hmKGnF.js → configuration-form-DSoMMiPE.js} +1 -1
  67. zenml/zen_server/dashboard/assets/{constants-1EZZxtay.js → constants-DTfsIqHy.js} +1 -1
  68. zenml/zen_server/dashboard/assets/{create-stack-TKmMtrkQ.js → create-stack-BpZrmKDu.js} +1 -1
  69. zenml/zen_server/dashboard/assets/{delete-run-CCR9md_s.js → delete-run-BkyDsKQc.js} +1 -1
  70. zenml/zen_server/dashboard/assets/elk-worker.min-BdOC9sib.js +6263 -0
  71. zenml/zen_server/dashboard/assets/expand-full-BPiXpch2.js +1 -0
  72. zenml/zen_server/dashboard/assets/{form-DFJkaFDX.js → form-BgtamtJm.js} +1 -1
  73. zenml/zen_server/dashboard/assets/{form-schemas-CrznJVzA.js → form-schemas-dyDkAxXP.js} +1 -1
  74. zenml/zen_server/dashboard/assets/{index-BjUu1mP4.js → index-BBt0LDtR.js} +1 -1
  75. zenml/zen_server/dashboard/assets/index-BfNISy0X.css +1 -0
  76. zenml/zen_server/dashboard/assets/{index-BFqbGSck.js → index-BgEfQ3_G.js} +4 -4
  77. zenml/zen_server/dashboard/assets/{index-U992soPJ.js → index-eoDB_1XX.js} +1 -1
  78. zenml/zen_server/dashboard/assets/{layout-Do9YI4QX.js → layout-o1x87a3q.js} +1 -1
  79. zenml/zen_server/dashboard/assets/{login-mutation-D3tFP6Wm.js → login-mutation-C1hvP_cX.js} +1 -1
  80. zenml/zen_server/dashboard/assets/page-4xUZpMN0.js +31 -0
  81. zenml/zen_server/dashboard/assets/page-4zc4xPv2.js +2 -0
  82. zenml/zen_server/dashboard/assets/page-B0104V6C.js +1 -0
  83. zenml/zen_server/dashboard/assets/page-BNJsjvof.js +1 -0
  84. zenml/zen_server/dashboard/assets/{page-sJjNT9xA.js → page-BPQ66vR-.js} +1 -1
  85. zenml/zen_server/dashboard/assets/{page-CAJ8B0vb.js → page-BQgSZ2nH.js} +1 -1
  86. zenml/zen_server/dashboard/assets/page-BXl2ZX6J.js +1 -0
  87. zenml/zen_server/dashboard/assets/{page-CtiuMP_r.js → page-BxeZrG_t.js} +1 -1
  88. zenml/zen_server/dashboard/assets/{page-Cal6XQ4U.js → page-C2A-2Cj_.js} +1 -1
  89. zenml/zen_server/dashboard/assets/page-C2i-C7jv.js +1 -0
  90. zenml/zen_server/dashboard/assets/{page-DJIGaUQ9.js → page-C3JfJxuR.js} +1 -1
  91. zenml/zen_server/dashboard/assets/{page-ChGcZI_6.js → page-CESEqC2L.js} +1 -1
  92. zenml/zen_server/dashboard/assets/{page-DCcuPZ8P.js → page-CF8cTZ7l.js} +1 -1
  93. zenml/zen_server/dashboard/assets/page-CKjsimVu.js +1 -0
  94. zenml/zen_server/dashboard/assets/{page-DNjKHjnH.js → page-COLzBwff.js} +1 -1
  95. zenml/zen_server/dashboard/assets/page-COifg5fa.js +1 -0
  96. zenml/zen_server/dashboard/assets/{page-CnbIYE80.js → page-CQeJuA8T.js} +1 -1
  97. zenml/zen_server/dashboard/assets/{page-DKK6ulgy.js → page-CcjWEjre.js} +1 -1
  98. zenml/zen_server/dashboard/assets/{page-9RjCitFH.js → page-CefGLeWy.js} +1 -1
  99. zenml/zen_server/dashboard/assets/{page-DUKbOhaD.js → page-CfxpV3j4.js} +1 -1
  100. zenml/zen_server/dashboard/assets/{page-D9Hfx6GV.js → page-ClcUzawe.js} +1 -1
  101. zenml/zen_server/dashboard/assets/page-Ct_LB3zo.js +1 -0
  102. zenml/zen_server/dashboard/assets/page-D-ZWUMYY.js +1 -0
  103. zenml/zen_server/dashboard/assets/{page-CUaMMoPG.js → page-D-tJ_Y0a.js} +1 -1
  104. zenml/zen_server/dashboard/assets/{page-CdZCmszX.js → page-DHrvih9u.js} +1 -1
  105. zenml/zen_server/dashboard/assets/{page-DUK0Nd_1.js → page-DMhaHZDw.js} +1 -1
  106. zenml/zen_server/dashboard/assets/{page-CAUYrfui.js → page-DOCOmmKn.js} +1 -1
  107. zenml/zen_server/dashboard/assets/{page-akLcPcKw.js → page-DcQmxKLp.js} +1 -1
  108. zenml/zen_server/dashboard/assets/page-Dh4GRWw5.js +1 -0
  109. zenml/zen_server/dashboard/assets/{page-DwVPpCFg.js → page-DiHZK-1w.js} +1 -1
  110. zenml/zen_server/dashboard/assets/page-Dn7ZNapg.js +1 -0
  111. zenml/zen_server/dashboard/assets/page-Dy4vSQY7.js +1 -0
  112. zenml/zen_server/dashboard/assets/{page-CN7lkvXr.js → page-QrvWQwZb.js} +1 -1
  113. zenml/zen_server/dashboard/assets/{page-BrT0_zSJ.js → page-RF3Fup0q.js} +1 -1
  114. zenml/zen_server/dashboard/assets/page-WuvCrN47.js +1 -0
  115. zenml/zen_server/dashboard/assets/{page-Be3R2uYn.js → page-_WnHBI1F.js} +1 -1
  116. zenml/zen_server/dashboard/assets/{page-C210HcBA.js → page-ghjVNgVE.js} +1 -1
  117. zenml/zen_server/dashboard/assets/{page-BCrKmYIZ.js → page-iDsDiDXw.js} +1 -1
  118. zenml/zen_server/dashboard/assets/{page-ClvmVesa.js → page-rVhXI5ZO.js} +1 -1
  119. zenml/zen_server/dashboard/assets/{page-DEohTSz6.js → page-uxjMX8Iq.js} +1 -1
  120. zenml/zen_server/dashboard/assets/{persist-Dec_w7aB.js → persist-BsdEtCkd.js} +1 -1
  121. zenml/zen_server/dashboard/assets/{persist-DWMWVP-y.js → persist-CFPbMcJX.js} +1 -1
  122. zenml/zen_server/dashboard/assets/{resource-tyes-list-o2LXiMay.js → resource-tyes-list-79FqS3LY.js} +1 -1
  123. zenml/zen_server/dashboard/assets/{resource-type-tooltip-DwHrJstL.js → resource-type-tooltip-BL9ZTRKi.js} +1 -1
  124. zenml/zen_server/dashboard/assets/{service-connectors-DSEMwJ5A.js → service-connectors-Q8h7-_rG.js} +1 -1
  125. zenml/zen_server/dashboard/assets/{service-jxtvgks0.js → service-k-9Vsb30.js} +1 -1
  126. zenml/zen_server/dashboard/assets/{sharedSchema-BXzg0EZz.js → sharedSchema-C_HkejsG.js} +1 -1
  127. zenml/zen_server/dashboard/assets/{stack-detail-query-Cm0fsgo-.js → stack-detail-query-CNmVZ0Bo.js} +1 -1
  128. zenml/zen_server/dashboard/assets/{update-current-user-mutation-D5MjcQ6F.js → update-current-user-mutation-Ca-Lmwuj.js} +1 -1
  129. zenml/zen_server/dashboard/assets/{update-server-settings-mutation-CmnxdxiK.js → update-server-settings-mutation-Bwe3gUt4.js} +1 -1
  130. zenml/zen_server/dashboard/index.html +4 -4
  131. zenml/zen_stores/migrations/versions/0.83.1_release.py +23 -0
  132. zenml/zen_stores/rest_zen_store.py +147 -128
  133. zenml/zen_stores/sql_zen_store.py +27 -17
  134. {zenml_nightly-0.83.0.dev20250623.dist-info → zenml_nightly-0.83.1.dev20250625.dist-info}/METADATA +5 -9
  135. {zenml_nightly-0.83.0.dev20250623.dist-info → zenml_nightly-0.83.1.dev20250625.dist-info}/RECORD +138 -134
  136. zenml/zen_server/dashboard/assets/RunsBody-BRBn1e2O.js +0 -1
  137. zenml/zen_server/dashboard/assets/SearchField-DY6-UbRT.js +0 -1
  138. zenml/zen_server/dashboard/assets/StackComponentList-Be1pQt9m.js +0 -1
  139. zenml/zen_server/dashboard/assets/StackList-BdiR5DvR.js +0 -1
  140. zenml/zen_server/dashboard/assets/Tabs-DNSKblCM.js +0 -1
  141. zenml/zen_server/dashboard/assets/index-DuhuqTCI.css +0 -1
  142. zenml/zen_server/dashboard/assets/page-B0PsXWiT.js +0 -1
  143. zenml/zen_server/dashboard/assets/page-BcRI3-aR.js +0 -29
  144. zenml/zen_server/dashboard/assets/page-BgknnddT.js +0 -1
  145. zenml/zen_server/dashboard/assets/page-Bs3W2FDi.js +0 -1
  146. zenml/zen_server/dashboard/assets/page-C6KaiZ_W.js +0 -1
  147. zenml/zen_server/dashboard/assets/page-CHxVhF3x.js +0 -1
  148. zenml/zen_server/dashboard/assets/page-CktmtZ8Z.js +0 -1
  149. zenml/zen_server/dashboard/assets/page-CoXzjeEY.js +0 -1
  150. zenml/zen_server/dashboard/assets/page-D9iuB88h.js +0 -1
  151. zenml/zen_server/dashboard/assets/page-DYOucPtA.js +0 -1
  152. zenml/zen_server/dashboard/assets/page-DpqRelAy.js +0 -1
  153. zenml/zen_server/dashboard/assets/page-XURWnYZP.js +0 -1
  154. zenml/zen_server/dashboard/assets/page-abw-2oeW.js +0 -1
  155. zenml/zen_server/dashboard/assets/page-n9ejQ2V3.js +0 -2
  156. {zenml_nightly-0.83.0.dev20250623.dist-info → zenml_nightly-0.83.1.dev20250625.dist-info}/LICENSE +0 -0
  157. {zenml_nightly-0.83.0.dev20250623.dist-info → zenml_nightly-0.83.1.dev20250625.dist-info}/WHEEL +0 -0
  158. {zenml_nightly-0.83.0.dev20250623.dist-info → zenml_nightly-0.83.1.dev20250625.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,23 @@
1
+ """Release [0.83.1].
2
+
3
+ Revision ID: 0.83.1
4
+ Revises: 3d7e39f3ac92
5
+ Create Date: 2025-06-23 07:26:40.361406
6
+
7
+ """
8
+
9
+ # revision identifiers, used by Alembic.
10
+ revision = "0.83.1"
11
+ down_revision = "3d7e39f3ac92"
12
+ branch_labels = None
13
+ depends_on = None
14
+
15
+
16
+ def upgrade() -> None:
17
+ """Upgrade database schema and/or data, creating a new revision."""
18
+ pass
19
+
20
+
21
+ def downgrade() -> None:
22
+ """Downgrade database schema and/or data back to the previous revision."""
23
+ pass
@@ -18,6 +18,7 @@ import re
18
18
  import time
19
19
  from datetime import datetime
20
20
  from pathlib import Path
21
+ from threading import RLock
21
22
  from typing import (
22
23
  Any,
23
24
  ClassVar,
@@ -39,6 +40,7 @@ from pydantic import (
39
40
  BaseModel,
40
41
  ConfigDict,
41
42
  Field,
43
+ PrivateAttr,
42
44
  ValidationError,
43
45
  field_validator,
44
46
  model_validator,
@@ -272,6 +274,7 @@ from zenml.utils.networking_utils import (
272
274
  replace_localhost_with_internal_hostname,
273
275
  )
274
276
  from zenml.utils.pydantic_utils import before_validator_handler
277
+ from zenml.utils.time_utils import utc_now
275
278
  from zenml.zen_server.exceptions import exception_from_response
276
279
  from zenml.zen_stores.base_zen_store import BaseZenStore
277
280
 
@@ -440,6 +443,8 @@ class RestZenStore(BaseZenStore):
440
443
  _api_token: Optional[APIToken] = None
441
444
  _session: Optional[requests.Session] = None
442
445
  _server_info: Optional[ServerModel] = None
446
+ _session_lock: RLock = PrivateAttr(default_factory=RLock)
447
+ _last_authenticated: Optional[datetime] = None
443
448
 
444
449
  # ====================================
445
450
  # ZenML Store interface implementation
@@ -4157,7 +4162,7 @@ class RestZenStore(BaseZenStore):
4157
4162
  elif token.expired:
4158
4163
  raise CredentialsNotValid(
4159
4164
  "Your authentication to the current server has expired. "
4160
- "Please log in again using 'zenml login --url "
4165
+ "Please log in again using 'zenml login "
4161
4166
  f"{self.url}'."
4162
4167
  )
4163
4168
 
@@ -4203,74 +4208,79 @@ class RestZenStore(BaseZenStore):
4203
4208
  Returns:
4204
4209
  A requests session.
4205
4210
  """
4206
- if self._session is None:
4207
- # We only need to initialize the session once over the lifetime
4208
- # of the client. We can swap the token out when it expires.
4209
- if self.config.verify_ssl is False:
4210
- urllib3.disable_warnings(
4211
- urllib3.exceptions.InsecureRequestWarning
4212
- )
4211
+ with self._session_lock:
4212
+ if self._session is None:
4213
+ # We only need to initialize the session once over the lifetime
4214
+ # of the client. We can swap the token out when it expires.
4215
+ if self.config.verify_ssl is False:
4216
+ urllib3.disable_warnings(
4217
+ urllib3.exceptions.InsecureRequestWarning
4218
+ )
4213
4219
 
4214
- self._session = requests.Session()
4215
- # Retries are triggered for all HTTP methods (GET, HEAD, POST, PUT,
4216
- # PATCH, OPTIONS and DELETE) on specific HTTP status codes:
4217
- #
4218
- # 408: Request Timeout.
4219
- # 429: Too Many Requests.
4220
- # 502: Bad Gateway.
4221
- # 503: Service Unavailable.
4222
- # 504: Gateway Timeout
4223
- #
4224
- # This also handles connection level errors, if a connection attempt
4225
- # fails due to transient issues like:
4226
- #
4227
- # DNS resolution errors.
4228
- # Connection timeouts.
4229
- # Network disruptions.
4230
- #
4231
- # Additional errors retried:
4232
- #
4233
- # Read Timeouts: If the server does not send a response within
4234
- # the timeout period.
4235
- # Connection Refused: If the server refuses the connection.
4236
- #
4237
- retries = Retry(
4238
- connect=5,
4239
- read=8,
4240
- redirect=3,
4241
- status=10,
4242
- allowed_methods=[
4243
- "HEAD",
4244
- "GET",
4245
- "POST",
4246
- "PUT",
4247
- "PATCH",
4248
- "DELETE",
4249
- "OPTIONS",
4250
- ],
4251
- status_forcelist=[
4252
- 408, # Request Timeout
4253
- 429, # Too Many Requests
4254
- 502, # Bad Gateway
4255
- 503, # Service Unavailable
4256
- 504, # Gateway Timeout
4257
- ],
4258
- other=3,
4259
- backoff_factor=1,
4260
- )
4261
- self._session.mount("https://", HTTPAdapter(max_retries=retries))
4262
- self._session.mount("http://", HTTPAdapter(max_retries=retries))
4263
- self._session.verify = self.config.verify_ssl
4264
- # Use a custom user agent to identify the ZenML client in the server
4265
- # logs.
4266
- self._session.headers.update(
4267
- {"User-Agent": "zenml/" + zenml.__version__}
4268
- )
4220
+ self._session = requests.Session()
4221
+ # Retries are triggered for all HTTP methods (GET, HEAD, POST, PUT,
4222
+ # PATCH, OPTIONS and DELETE) on specific HTTP status codes:
4223
+ #
4224
+ # 408: Request Timeout.
4225
+ # 429: Too Many Requests.
4226
+ # 502: Bad Gateway.
4227
+ # 503: Service Unavailable.
4228
+ # 504: Gateway Timeout
4229
+ #
4230
+ # This also handles connection level errors, if a connection attempt
4231
+ # fails due to transient issues like:
4232
+ #
4233
+ # DNS resolution errors.
4234
+ # Connection timeouts.
4235
+ # Network disruptions.
4236
+ #
4237
+ # Additional errors retried:
4238
+ #
4239
+ # Read Timeouts: If the server does not send a response within
4240
+ # the timeout period.
4241
+ # Connection Refused: If the server refuses the connection.
4242
+ #
4243
+ retries = Retry(
4244
+ connect=5,
4245
+ read=8,
4246
+ redirect=3,
4247
+ status=10,
4248
+ allowed_methods=[
4249
+ "HEAD",
4250
+ "GET",
4251
+ "POST",
4252
+ "PUT",
4253
+ "PATCH",
4254
+ "DELETE",
4255
+ "OPTIONS",
4256
+ ],
4257
+ status_forcelist=[
4258
+ 408, # Request Timeout
4259
+ 429, # Too Many Requests
4260
+ 502, # Bad Gateway
4261
+ 503, # Service Unavailable
4262
+ 504, # Gateway Timeout
4263
+ ],
4264
+ other=3,
4265
+ backoff_factor=1,
4266
+ )
4267
+ self._session.mount(
4268
+ "https://", HTTPAdapter(max_retries=retries)
4269
+ )
4270
+ self._session.mount(
4271
+ "http://", HTTPAdapter(max_retries=retries)
4272
+ )
4273
+ self._session.verify = self.config.verify_ssl
4274
+ # Use a custom user agent to identify the ZenML client in the server
4275
+ # logs.
4276
+ self._session.headers.update(
4277
+ {"User-Agent": "zenml/" + zenml.__version__}
4278
+ )
4269
4279
 
4270
- # Note that we return an unauthenticated session here. An API token
4271
- # is only fetched and set in the authorization header when and if it is
4272
- # needed.
4273
- return self._session
4280
+ # Note that we return an unauthenticated session here. An API token
4281
+ # is only fetched and set in the authorization header when and if it is
4282
+ # needed.
4283
+ return self._session
4274
4284
 
4275
4285
  def authenticate(self, force: bool = False) -> None:
4276
4286
  """Authenticate or re-authenticate to the ZenML server.
@@ -4325,6 +4335,7 @@ class RestZenStore(BaseZenStore):
4325
4335
  {"Authorization": "Bearer " + new_api_token}
4326
4336
  )
4327
4337
  logger.debug(f"Authenticated to {self.url}")
4338
+ self._last_authenticated = utc_now()
4328
4339
 
4329
4340
  @staticmethod
4330
4341
  def _handle_response(response: requests.Response) -> Json:
@@ -4391,9 +4402,9 @@ class RestZenStore(BaseZenStore):
4391
4402
  CredentialsNotValid: if the request fails due to invalid
4392
4403
  client credentials.
4393
4404
  """
4394
- self.session.headers.update(
4395
- {source_context.name: source_context.get().value}
4396
- )
4405
+ request_headers = {
4406
+ source_context.name: source_context.get().value,
4407
+ }
4397
4408
 
4398
4409
  # If the server replies with a credentials validation (401 Unauthorized)
4399
4410
  # error, we (re-)authenticate and retry the request here in the
@@ -4414,19 +4425,21 @@ class RestZenStore(BaseZenStore):
4414
4425
  while True:
4415
4426
  # Add a request ID to the request headers
4416
4427
  request_id = str(uuid4())[:8]
4417
- self.session.headers.update({"X-Request-ID": request_id})
4428
+ request_headers["X-Request-ID"] = request_id
4418
4429
  # Add an idempotency key to the request headers to ensure that
4419
4430
  # requests are idempotent.
4420
- self.session.headers.update({"Idempotency-Key": str(uuid4())})
4431
+ request_headers["Idempotency-Key"] = str(uuid4())
4421
4432
 
4422
4433
  start_time = time.time()
4423
4434
  logger.debug(f"[{request_id}] {method} {path} started...")
4424
4435
  status_code = "failed"
4436
+ last_authenticated = self._last_authenticated
4425
4437
 
4426
4438
  try:
4427
4439
  response = self.session.request(
4428
4440
  method,
4429
4441
  url,
4442
+ headers=request_headers,
4430
4443
  params=params if params else {},
4431
4444
  verify=self.config.verify_ssl,
4432
4445
  timeout=timeout or self.config.http_timeout,
@@ -4442,62 +4455,68 @@ class RestZenStore(BaseZenStore):
4442
4455
  # authenticated at all.
4443
4456
  credentials_store = get_credentials_store()
4444
4457
 
4445
- if self._api_token is None:
4446
- # The last request was not authenticated with an API
4447
- # token at all. We authenticate here and then try the
4448
- # request again, this time with a valid API token in the
4449
- # header.
4450
- logger.debug(
4451
- f"[{request_id}] The last request was not "
4452
- f"authenticated: {e}\n"
4453
- "Re-authenticating and retrying..."
4454
- )
4455
- self.authenticate()
4456
- elif not credentials_store.can_login(self.url):
4457
- # The request failed either because we're not
4458
- # authenticated or our current credentials are not valid
4459
- # anymore.
4460
- logger.error(
4461
- "The current token is no longer valid, and "
4462
- "it is not possible to generate a new token using the "
4463
- "configured credentials. Please run "
4464
- f"`zenml login {self.url}` to "
4465
- "re-authenticate to the server or authenticate using "
4466
- "an API key. See "
4467
- "https://docs.zenml.io/deploying-zenml/connecting-to-zenml/connect-with-a-service-account "
4468
- "for more information."
4469
- )
4470
- # Clear the current token from the credentials store to
4471
- # force a new authentication flow next time.
4472
- get_credentials_store().clear_token(self.url)
4473
- raise e
4474
- elif not re_authenticated:
4475
- # The last request was authenticated with an API token
4476
- # that was rejected by the server. We attempt a
4477
- # re-authentication here and then retry the request.
4478
- logger.debug(
4479
- f"[{request_id}] The last request was authenticated "
4480
- "with an API token that was rejected by the server: "
4481
- f"{e}\n"
4482
- "Re-authenticating and retrying..."
4483
- )
4484
- re_authenticated = True
4485
- self.authenticate(
4486
- # Ignore the current token and force a re-authentication
4487
- force=True
4488
- )
4489
- else:
4490
- # The last request was made after re-authenticating but
4491
- # still failed. Bailing out.
4492
- logger.debug(
4493
- f"[{request_id}] The last request failed after "
4494
- "re-authenticating: {e}\n"
4495
- "Bailing out..."
4496
- )
4497
- raise CredentialsNotValid(
4498
- "The current credentials are no longer valid. Please "
4499
- "log in again using 'zenml login'."
4500
- ) from e
4458
+ with self._session_lock:
4459
+ if self._last_authenticated != last_authenticated:
4460
+ # Another thread has re-authenticated since the last
4461
+ # request. We simply retry the request.
4462
+ continue
4463
+
4464
+ if self._api_token is None:
4465
+ # The last request was not authenticated with an API
4466
+ # token at all. We authenticate here and then try the
4467
+ # request again, this time with a valid API token in the
4468
+ # header.
4469
+ logger.debug(
4470
+ f"[{request_id}] The last request was not "
4471
+ f"authenticated: {e}\n"
4472
+ "Re-authenticating and retrying..."
4473
+ )
4474
+ self.authenticate()
4475
+ elif not credentials_store.can_login(self.url):
4476
+ # The request failed either because we're not
4477
+ # authenticated or our current credentials are not valid
4478
+ # anymore.
4479
+ logger.error(
4480
+ "The current token is no longer valid, and "
4481
+ "it is not possible to generate a new token using the "
4482
+ "configured credentials. Please run "
4483
+ f"`zenml login {self.url}` to "
4484
+ "re-authenticate to the server or authenticate using "
4485
+ "an API key. See "
4486
+ "https://docs.zenml.io/deploying-zenml/connecting-to-zenml/connect-with-a-service-account "
4487
+ "for more information."
4488
+ )
4489
+ # Clear the current token from the credentials store to
4490
+ # force a new authentication flow next time.
4491
+ get_credentials_store().clear_token(self.url)
4492
+ raise e
4493
+ elif not re_authenticated:
4494
+ # The last request was authenticated with an API token
4495
+ # that was rejected by the server. We attempt a
4496
+ # re-authentication here and then retry the request.
4497
+ logger.debug(
4498
+ f"[{request_id}] The last request was authenticated "
4499
+ "with an API token that was rejected by the server: "
4500
+ f"{e}\n"
4501
+ "Re-authenticating and retrying..."
4502
+ )
4503
+ re_authenticated = True
4504
+ self.authenticate(
4505
+ # Ignore the current token and force a re-authentication
4506
+ force=True
4507
+ )
4508
+ else:
4509
+ # The last request was made after re-authenticating but
4510
+ # still failed. Bailing out.
4511
+ logger.debug(
4512
+ f"[{request_id}] The last request failed after "
4513
+ "re-authenticating: {e}\n"
4514
+ "Bailing out..."
4515
+ )
4516
+ raise CredentialsNotValid(
4517
+ "The current credentials are no longer valid. Please "
4518
+ "log in again using 'zenml login'."
4519
+ ) from e
4501
4520
  finally:
4502
4521
  end_time = time.time()
4503
4522
  duration = (end_time - start_time) * 1000
@@ -8779,19 +8779,18 @@ class SqlZenStore(BaseZenStore):
8779
8779
  session.commit()
8780
8780
  session.refresh(step_schema)
8781
8781
 
8782
- # Save parent step IDs into the database.
8783
- for parent_step_id in step_run.parent_step_ids:
8784
- self._set_run_step_parent_step(
8785
- child_step_run=step_schema,
8786
- parent_id=parent_step_id,
8787
- session=session,
8788
- )
8789
-
8790
8782
  session.commit()
8791
8783
  session.refresh(step_schema)
8792
8784
 
8793
8785
  step_model = step_schema.to_model(include_metadata=True)
8794
8786
 
8787
+ for upstream_step in step_model.spec.upstream_steps:
8788
+ self._set_run_step_parent_step(
8789
+ child_step_run=step_schema,
8790
+ parent_step_name=upstream_step,
8791
+ session=session,
8792
+ )
8793
+
8795
8794
  # Save input artifact IDs into the database.
8796
8795
  for input_name, artifact_version_ids in step_run.inputs.items():
8797
8796
  for artifact_version_id in artifact_version_ids:
@@ -9047,22 +9046,33 @@ class SqlZenStore(BaseZenStore):
9047
9046
  return StepRunInputArtifactType.MANUAL
9048
9047
 
9049
9048
  def _set_run_step_parent_step(
9050
- self, child_step_run: StepRunSchema, parent_id: UUID, session: Session
9049
+ self,
9050
+ child_step_run: StepRunSchema,
9051
+ parent_step_name: str,
9052
+ session: Session,
9051
9053
  ) -> None:
9052
9054
  """Sets the parent step run for a step run.
9053
9055
 
9054
9056
  Args:
9055
9057
  child_step_run: The child step run to set the parent for.
9056
- parent_id: The ID of the parent step run to set a child for.
9058
+ parent_step_name: The name of the parent step run to set a child for.
9057
9059
  session: The database session to use.
9060
+
9061
+ Raises:
9062
+ RuntimeError: If the parent step run is not found.
9058
9063
  """
9059
- parent_step_run = self._get_reference_schema_by_id(
9060
- resource=child_step_run,
9061
- reference_schema=StepRunSchema,
9062
- reference_id=parent_id,
9063
- session=session,
9064
- reference_type="parent step",
9065
- )
9064
+ parent_step_run = session.exec(
9065
+ select(StepRunSchema)
9066
+ .where(StepRunSchema.name == parent_step_name)
9067
+ .where(
9068
+ StepRunSchema.pipeline_run_id == child_step_run.pipeline_run_id
9069
+ )
9070
+ ).first()
9071
+ if parent_step_run is None:
9072
+ raise RuntimeError(
9073
+ f"Parent step run `{parent_step_name}` not found for step run "
9074
+ f"`{child_step_run.name}`."
9075
+ )
9066
9076
 
9067
9077
  # Check if the parent step is already set.
9068
9078
  assignment = session.exec(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: zenml-nightly
3
- Version: 0.83.0.dev20250623
3
+ Version: 0.83.1.dev20250625
4
4
  Summary: ZenML: Write production-ready ML code.
5
5
  License: Apache-2.0
6
6
  Keywords: machine learning,production,pipeline,mlops,devops
@@ -458,17 +458,13 @@ ZenML is being built in public. The [roadmap](https://zenml.io/roadmap) is a reg
458
458
  ZenML is managed by a [core team](https://zenml.io/company) of developers that are responsible for making key decisions and incorporating feedback from the community. The team oversees feedback via various channels,
459
459
  and you can directly influence the roadmap as follows:
460
460
 
461
- - Vote on your most wanted feature on our [Discussion
462
- board](https://zenml.io/discussion).
461
+ - Ask questions and share your thoughts on the [Discussions board](https://zenml.io/discussion).
463
462
  - Start a thread in our [Slack channel](https://zenml.io/slack).
464
463
  - [Create an issue](https://github.com/zenml-io/zenml/issues/new/choose) on our GitHub repo.
465
464
 
466
465
  ## 🙌 Contributing and Community
467
466
 
468
- We would love to develop ZenML together with our community! The best way to get
469
- started is to select any issue from the `[good-first-issue`
470
- label](https://github.com/issues?q=is%3Aopen+is%3Aissue+archived%3Afalse+user%3Azenml-io+label%3A%22good+first+issue%22)
471
- and open up a Pull Request!
467
+ We would love to develop ZenML together with our community! The best way to get started is to select any issue from the [`good-first-issue` label](https://github.com/issues?q=is%3Aopen+is%3Aissue+archived%3Afalse+user%3Azenml-io+label%3A%22good+first+issue%22) and open up a Pull Request!
472
468
 
473
469
  If you
474
470
  would like to contribute, please review our [Contributing
@@ -477,7 +473,7 @@ Guide](CONTRIBUTING.md) for all relevant details.
477
473
  ## 🆘 Getting Help
478
474
 
479
475
  The first point of call should
480
- be [our Slack group](https://zenml.io/slack-invite/).
476
+ be [our Slack group](https://zenml.io/slack/).
481
477
  Ask your questions about bugs or specific use cases, and someone from
482
478
  the [core team](https://zenml.io/company) will respond.
483
479
  Or, if you
@@ -532,7 +528,7 @@ the Apache License Version 2.0.
532
528
  <a href="https://github.com/zenml-io/zenml-projects">Projects Showcase</a>
533
529
  <br />
534
530
  <br />
535
- 🎉 Version 0.83.0 is out. Check out the release notes
531
+ 🎉 Version 0.83.1 is out. Check out the release notes
536
532
  <a href="https://github.com/zenml-io/zenml/releases">here</a>.
537
533
  <br />
538
534
  🖥️ Download our VS Code Extension <a href="https://marketplace.visualstudio.com/items?itemName=ZenML.zenml-vscode">here</a>.