zenml-nightly 0.68.1.dev20241111__py3-none-any.whl → 0.70.0.dev20241114__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 (202) 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/utils.py +5 -1
  6. zenml/cli/base.py +1 -1
  7. zenml/client.py +9 -2
  8. zenml/config/server_config.py +17 -1
  9. zenml/constants.py +1 -7
  10. zenml/enums.py +8 -0
  11. zenml/exceptions.py +4 -0
  12. zenml/integrations/aws/orchestrators/sagemaker_orchestrator.py +1 -14
  13. zenml/integrations/lightning/orchestrators/lightning_orchestrator.py +29 -9
  14. zenml/model/model.py +16 -62
  15. zenml/model/utils.py +5 -0
  16. zenml/models/v2/base/filter.py +121 -8
  17. zenml/models/v2/core/artifact_version.py +23 -0
  18. zenml/models/v2/core/model_version.py +23 -0
  19. zenml/models/v2/core/pipeline_run.py +22 -1
  20. zenml/models/v2/core/step_run.py +22 -0
  21. zenml/orchestrators/base_orchestrator.py +12 -1
  22. zenml/orchestrators/step_launcher.py +2 -1
  23. zenml/orchestrators/utils.py +45 -26
  24. zenml/stack_deployments/aws_stack_deployment.py +23 -6
  25. zenml/stack_deployments/azure_stack_deployment.py +28 -5
  26. zenml/stack_deployments/gcp_stack_deployment.py +25 -8
  27. zenml/stack_deployments/stack_deployment.py +3 -5
  28. zenml/steps/utils.py +5 -0
  29. zenml/utils/metadata_utils.py +335 -0
  30. zenml/zen_server/auth.py +221 -3
  31. zenml/zen_server/cache.py +208 -0
  32. zenml/zen_server/dashboard/assets/{404-DT4QRUqN.js → 404-NVXKFp-x.js} +1 -1
  33. zenml/zen_server/dashboard/assets/{@radix-DP6vWzyx.js → @radix-DeK6qiuw.js} +1 -1
  34. zenml/zen_server/dashboard/assets/{@react-router-BMhZulnd.js → @react-router-B3Z5rLr2.js} +1 -1
  35. zenml/zen_server/dashboard/assets/{@reactflow-8U9qNlMR.js → @reactflow-CK0KJUen.js} +2 -2
  36. zenml/zen_server/dashboard/assets/{@tanstack-BUCbhJyH.js → @tanstack-DT5WLu9C.js} +1 -1
  37. zenml/zen_server/dashboard/assets/AlertDialogDropdownItem-DezXKmDf.js +1 -0
  38. zenml/zen_server/dashboard/assets/{CodeSnippet-CqybNv0k.js → CodeSnippet-JzR8CEtw.js} +2 -2
  39. zenml/zen_server/dashboard/assets/{CollapsibleCard-0r_8G2Lj.js → CollapsibleCard-DQW_ktMO.js} +1 -1
  40. zenml/zen_server/dashboard/assets/{Commands-BDjgBQKi.js → Commands-DL2kwkRd.js} +1 -1
  41. zenml/zen_server/dashboard/assets/ComponentBadge-D_g62Wv8.js +1 -0
  42. zenml/zen_server/dashboard/assets/{CopyButton-C745BrKi.js → CopyButton-LNcWaa14.js} +1 -1
  43. zenml/zen_server/dashboard/assets/{CsvVizualization-PpAq0CeZ.js → CsvVizualization-DknpE5ej.js} +5 -5
  44. zenml/zen_server/dashboard/assets/{DialogItem-DcVCZEew.js → DialogItem-Bxf8FuAT.js} +1 -1
  45. zenml/zen_server/dashboard/assets/{DisplayDate-BeXgUG_C.js → DisplayDate-CDMUcQHS.js} +1 -1
  46. zenml/zen_server/dashboard/assets/{EmptyState-DeK7H4pr.js → EmptyState-BzdlCwp3.js} +1 -1
  47. zenml/zen_server/dashboard/assets/{Error-BMlzibXj.js → Error-DYflYyps.js} +1 -1
  48. zenml/zen_server/dashboard/assets/ExecutionStatus-C7zyIQKZ.js +1 -0
  49. zenml/zen_server/dashboard/assets/{Helpbox-BLf40fLV.js → Helpbox-oYSGpLqd.js} +1 -1
  50. zenml/zen_server/dashboard/assets/{Infobox-BwisKifi.js → Infobox-Cx4xGoXR.js} +1 -1
  51. zenml/zen_server/dashboard/assets/{InlineAvatar-jEgodSgX.js → InlineAvatar-DiGOWNKF.js} +1 -1
  52. zenml/zen_server/dashboard/assets/{Lock-3lLt1ih0.js → Lock-CYYy18Mm.js} +1 -1
  53. zenml/zen_server/dashboard/assets/{MarkdownVisualization-8O9kTr-2.js → MarkdownVisualization-ylXaAxev.js} +1 -1
  54. zenml/zen_server/dashboard/assets/NestedCollapsible-DYbgyKxK.js +1 -0
  55. zenml/zen_server/dashboard/assets/{NumberBox-T9eELfLZ.js → NumberBox-Dtp3J6g5.js} +1 -1
  56. zenml/zen_server/dashboard/assets/Partials-03iZf8-N.js +1 -0
  57. zenml/zen_server/dashboard/assets/{PasswordChecker-CW0kqY0W.js → PasswordChecker-B0nadgh6.js} +1 -1
  58. zenml/zen_server/dashboard/assets/ProBadge-D_EB8HNo.js +1 -0
  59. zenml/zen_server/dashboard/assets/ProCta-DqNS4v3x.js +1 -0
  60. zenml/zen_server/dashboard/assets/ProviderIcon-Bki2aw8w.js +1 -0
  61. zenml/zen_server/dashboard/assets/{ProviderRadio-BROY1700.js → ProviderRadio-8f43sPD4.js} +1 -1
  62. zenml/zen_server/dashboard/assets/RunSelector-DkPiIiNr.js +1 -0
  63. zenml/zen_server/dashboard/assets/RunsBody-07YEO7qI.js +1 -0
  64. zenml/zen_server/dashboard/assets/SearchField-lp1KgU4e.js +1 -0
  65. zenml/zen_server/dashboard/assets/{SecretTooltip-C_qByGWB.js → SecretTooltip-CgnbyeOx.js} +1 -1
  66. zenml/zen_server/dashboard/assets/{SetPassword-7pRB00El.js → SetPassword-CpP418A2.js} +1 -1
  67. zenml/zen_server/dashboard/assets/StackList-WvuKQusZ.js +1 -0
  68. zenml/zen_server/dashboard/assets/Tabs-BktHkCJJ.js +1 -0
  69. zenml/zen_server/dashboard/assets/Tick-BlMoIlJT.js +1 -0
  70. zenml/zen_server/dashboard/assets/{UpdatePasswordSchemas-DckMEkFf.js → UpdatePasswordSchemas-Sc0A0pP-.js} +1 -1
  71. zenml/zen_server/dashboard/assets/{UsageReason-DVceN14P.js → UsageReason-YYduL4fj.js} +1 -1
  72. zenml/zen_server/dashboard/assets/{WizardFooter-CW0Cvd70.js → WizardFooter-dgmizSJC.js} +1 -1
  73. zenml/zen_server/dashboard/assets/all-pipeline-runs-query-D-c2G6lV.js +1 -0
  74. zenml/zen_server/dashboard/assets/check-DloQpStc.js +1 -0
  75. zenml/zen_server/dashboard/assets/{check-circle-Dwxliy1Z.js → check-circle-jNbX5-sR.js} +1 -1
  76. zenml/zen_server/dashboard/assets/{chevron-down-8wLBS5pQ.js → chevron-down-6JyMkfjR.js} +1 -1
  77. zenml/zen_server/dashboard/assets/{chevron-right-double-DoD8iXWM.js → chevron-right-double-D7ojK9Co.js} +1 -1
  78. zenml/zen_server/dashboard/assets/{code-browser-CZUQs3Wa.js → code-browser-CUFUIHfp.js} +1 -1
  79. zenml/zen_server/dashboard/assets/{copy-CaSMXwiU.js → copy-C8XQA2Ug.js} +1 -1
  80. zenml/zen_server/dashboard/assets/create-stack-DM_JPgef.js +1 -0
  81. zenml/zen_server/dashboard/assets/delete-run-CJdh1P_h.js +1 -0
  82. zenml/zen_server/dashboard/assets/{docker-BFNgg-z3.js → docker-BdA9vrnW.js} +1 -1
  83. zenml/zen_server/dashboard/assets/{dots-horizontal-DK5Duzx4.js → dots-horizontal-otGBOSDJ.js} +1 -1
  84. zenml/zen_server/dashboard/assets/{form-schemas-1AyOCx90.js → form-schemas-K6FYKjwa.js} +1 -1
  85. zenml/zen_server/dashboard/assets/{gcp-7M2Yf3ZK.js → gcp-CFtm4BA7.js} +1 -1
  86. zenml/zen_server/dashboard/assets/{help-Dam461dC.js → help-Cc9bBIJH.js} +1 -1
  87. zenml/zen_server/dashboard/assets/index-B1mVPYxf.js +1 -0
  88. zenml/zen_server/dashboard/assets/index-BAkC7FXi.js +1 -0
  89. zenml/zen_server/dashboard/assets/{index-QQb7wQEC.js → index-CCOPpudF.js} +8 -8
  90. zenml/zen_server/dashboard/assets/index-CEV4Cvaf.js +1 -0
  91. zenml/zen_server/dashboard/assets/index-DlGvJQPn.css +1 -0
  92. zenml/zen_server/dashboard/assets/{index-BVJ8n2-j.js → index-Uu49AX48.js} +1 -1
  93. zenml/zen_server/dashboard/assets/{index.esm-cuVep_NJ.js → index.esm-Dy6Z9Ung.js} +1 -1
  94. zenml/zen_server/dashboard/assets/{kubernetes--g7r02Zu.js → kubernetes-B2wmAJ1d.js} +1 -1
  95. zenml/zen_server/dashboard/assets/{layout-DCSYN7-C.js → layout-BtHBmE4w.js} +1 -1
  96. zenml/zen_server/dashboard/assets/{link-external-CBEk6kEG.js → link-external-b9AXw_sW.js} +1 -1
  97. zenml/zen_server/dashboard/assets/{login-mutation-DTcAFP1l.js → login-mutation-hf-lK87O.js} +1 -1
  98. zenml/zen_server/dashboard/assets/{logs-D5bdJGur.js → logs-WMSM52RF.js} +1 -1
  99. zenml/zen_server/dashboard/assets/{not-found-Cc-JkRH2.js → not-found-BGirLjU-.js} +1 -1
  100. zenml/zen_server/dashboard/assets/{package-Cs35Szwh.js → package-C6uypY4h.js} +1 -1
  101. zenml/zen_server/dashboard/assets/page-0JE_-Ec1.js +1 -0
  102. zenml/zen_server/dashboard/assets/{page-DH_Z7iW1.js → page-6m6yHHlE.js} +1 -1
  103. zenml/zen_server/dashboard/assets/page-BDigxVpo.js +1 -0
  104. zenml/zen_server/dashboard/assets/page-BR68V0V1.js +1 -0
  105. zenml/zen_server/dashboard/assets/page-BRLpxOt0.js +1 -0
  106. zenml/zen_server/dashboard/assets/{page-BQQKaabe.js → page-BU7huvKw.js} +3 -3
  107. zenml/zen_server/dashboard/assets/page-BvqLv2Ky.js +1 -0
  108. zenml/zen_server/dashboard/assets/page-C00YAkaB.js +1 -0
  109. zenml/zen_server/dashboard/assets/{page-N4qoPHKb.js → page-CD-DcWoy.js} +1 -1
  110. zenml/zen_server/dashboard/assets/page-COXXJj1k.js +1 -0
  111. zenml/zen_server/dashboard/assets/page-CbpvrsDL.js +1 -0
  112. zenml/zen_server/dashboard/assets/page-CdMWnQak.js +1 -0
  113. zenml/zen_server/dashboard/assets/{page-ClUVkl-O.js → page-CjGdWY13.js} +1 -1
  114. zenml/zen_server/dashboard/assets/page-CwxrFarU.js +1 -0
  115. zenml/zen_server/dashboard/assets/{page-DLixvR-7.js → page-D01JhjQB.js} +1 -1
  116. zenml/zen_server/dashboard/assets/page-D6uU2ax4.js +1 -0
  117. zenml/zen_server/dashboard/assets/page-D7S3aCbF.js +1 -0
  118. zenml/zen_server/dashboard/assets/{page-9yplj5JT.js → page-DLC-bNBP.js} +1 -1
  119. zenml/zen_server/dashboard/assets/page-DXSTpqRD.js +1 -0
  120. zenml/zen_server/dashboard/assets/{page-DzpVUZ8f.js → page-DakHVWXF.js} +1 -1
  121. zenml/zen_server/dashboard/assets/{page-DIOXwhiD.js → page-Df-Fw0aq.js} +1 -1
  122. zenml/zen_server/dashboard/assets/{page-B-y2XKIc.js → page-DfbXf_8s.js} +1 -1
  123. zenml/zen_server/dashboard/assets/page-DjRJCGb3.js +1 -0
  124. zenml/zen_server/dashboard/assets/{page-C0N5q3l7.js → page-Djikxq_S.js} +1 -1
  125. zenml/zen_server/dashboard/assets/page-Dnovpa0i.js +3 -0
  126. zenml/zen_server/dashboard/assets/page-Dot3LPmL.js +1 -0
  127. zenml/zen_server/dashboard/assets/page-Vcxara9U.js +1 -0
  128. zenml/zen_server/dashboard/assets/page-Xynx4btY.js +14 -0
  129. zenml/zen_server/dashboard/assets/page-YpKAqVSa.js +1 -0
  130. zenml/zen_server/dashboard/assets/page-yYC9OI-E.js +1 -0
  131. zenml/zen_server/dashboard/assets/{persist-DNb5cdrU.js → persist-Coz7ZWvz.js} +1 -1
  132. zenml/zen_server/dashboard/assets/{persist-CP0JmYZ4.js → persist-GjC8PZoC.js} +1 -1
  133. zenml/zen_server/dashboard/assets/{plus-C9IxgN2M.js → plus-tf1V2hTJ.js} +1 -1
  134. zenml/zen_server/dashboard/assets/{refresh-BVu22P_C.js → refresh-BjOeWlEq.js} +1 -1
  135. zenml/zen_server/dashboard/assets/{rocket-CONEmRmB.js → rocket-DjT2cDvG.js} +1 -1
  136. zenml/zen_server/dashboard/assets/sharedSchema-CQb14VSr.js +14 -0
  137. zenml/zen_server/dashboard/assets/stack-detail-query-OPEW-cDJ.js +1 -0
  138. zenml/zen_server/dashboard/assets/{tick-circle-CM1ZScbQ.js → tick-circle-BEX_Tp4v.js} +1 -1
  139. zenml/zen_server/dashboard/assets/{trash-DkJHMOg7.js → trash-arLUMWMS.js} +1 -1
  140. zenml/zen_server/dashboard/assets/{update-server-settings-mutation-DsU8cNVl.js → update-server-settings-mutation-LwuQfHYn.js} +1 -1
  141. zenml/zen_server/dashboard/assets/upgrade-form-CwRHBuXB.webp +0 -0
  142. zenml/zen_server/dashboard/assets/url-CkvKAnwF.js +1 -0
  143. zenml/zen_server/dashboard/assets/{zod-D89GC_vc.js → zod-BwEbpOxH.js} +1 -1
  144. zenml/zen_server/dashboard/index.html +7 -7
  145. zenml/zen_server/deploy/helm/Chart.yaml +1 -1
  146. zenml/zen_server/deploy/helm/README.md +2 -2
  147. zenml/zen_server/exceptions.py +2 -0
  148. zenml/zen_server/jwt.py +30 -13
  149. zenml/zen_server/routers/auth_endpoints.py +134 -102
  150. zenml/zen_server/routers/logs_endpoints.py +66 -0
  151. zenml/zen_server/template_execution/utils.py +14 -16
  152. zenml/zen_server/utils.py +27 -0
  153. zenml/zen_server/zen_server_api.py +6 -1
  154. zenml/zen_stores/migrations/versions/0.70.0_release.py +23 -0
  155. zenml/zen_stores/migrations/versions/904464ea4041_add_pipeline_model_run_unique_constraints.py +192 -0
  156. zenml/zen_stores/rest_zen_store.py +13 -10
  157. zenml/zen_stores/schemas/model_schemas.py +25 -1
  158. zenml/zen_stores/schemas/pipeline_run_schemas.py +5 -0
  159. zenml/zen_stores/schemas/pipeline_schemas.py +8 -2
  160. zenml/zen_stores/sql_zen_store.py +215 -121
  161. {zenml_nightly-0.68.1.dev20241111.dist-info → zenml_nightly-0.70.0.dev20241114.dist-info}/METADATA +2 -2
  162. {zenml_nightly-0.68.1.dev20241111.dist-info → zenml_nightly-0.70.0.dev20241114.dist-info}/RECORD +165 -151
  163. zenml/zen_server/dashboard/assets/AlertDialogDropdownItem-C6N2rGrB.js +0 -1
  164. zenml/zen_server/dashboard/assets/ComponentBadge-DUiEYJHu.js +0 -1
  165. zenml/zen_server/dashboard/assets/ComponentFallbackDialog-BFoH5K4V.js +0 -1
  166. zenml/zen_server/dashboard/assets/ComponentIcon-CAIoUis2.js +0 -1
  167. zenml/zen_server/dashboard/assets/Partials-YPBB3V4q.js +0 -1
  168. zenml/zen_server/dashboard/assets/ProviderIcon-Bb3Xha5A.js +0 -1
  169. zenml/zen_server/dashboard/assets/RunSelector-DCiL3M1c.js +0 -1
  170. zenml/zen_server/dashboard/assets/SearchField-DfUiGFVd.js +0 -1
  171. zenml/zen_server/dashboard/assets/Tick-CykQFPj2.js +0 -1
  172. zenml/zen_server/dashboard/assets/cloud-only-B-s_HMDm.js +0 -1
  173. zenml/zen_server/dashboard/assets/codespaces-BitYDX9d.gif +0 -0
  174. zenml/zen_server/dashboard/assets/create-stack-CEmaPZ4c.js +0 -1
  175. zenml/zen_server/dashboard/assets/delete-run-D-LKbGyz.js +0 -1
  176. zenml/zen_server/dashboard/assets/index-Bpmj40BI.js +0 -1
  177. zenml/zen_server/dashboard/assets/index-CbU4Ln_E.css +0 -1
  178. zenml/zen_server/dashboard/assets/index-DKPhqP2B.js +0 -1
  179. zenml/zen_server/dashboard/assets/page-BBpOxVcY.js +0 -1
  180. zenml/zen_server/dashboard/assets/page-BRInM1Lg.js +0 -1
  181. zenml/zen_server/dashboard/assets/page-BjjlMk7s.js +0 -1
  182. zenml/zen_server/dashboard/assets/page-Bvd7YH2A.js +0 -1
  183. zenml/zen_server/dashboard/assets/page-CT3Nep8W.js +0 -1
  184. zenml/zen_server/dashboard/assets/page-C_f47pBf.js +0 -1
  185. zenml/zen_server/dashboard/assets/page-Cmv8C_yM.js +0 -3
  186. zenml/zen_server/dashboard/assets/page-CyN2bdWG.js +0 -1
  187. zenml/zen_server/dashboard/assets/page-CzzXH4fs.js +0 -1
  188. zenml/zen_server/dashboard/assets/page-DTlGjgnG.js +0 -1
  189. zenml/zen_server/dashboard/assets/page-Dbpl86h0.js +0 -1
  190. zenml/zen_server/dashboard/assets/page-Ddgy6kDS.js +0 -1
  191. zenml/zen_server/dashboard/assets/page-DtCAfBLy.js +0 -9
  192. zenml/zen_server/dashboard/assets/page-Dx16z7nA.js +0 -1
  193. zenml/zen_server/dashboard/assets/page-McUyYbo1.js +0 -1
  194. zenml/zen_server/dashboard/assets/page-T1P3RyAR.js +0 -1
  195. zenml/zen_server/dashboard/assets/page-bKaULTGG.js +0 -1
  196. zenml/zen_server/dashboard/assets/page-sbXUJy9t.js +0 -1
  197. zenml/zen_server/dashboard/assets/sharedSchema-TMLu-nYQ.js +0 -14
  198. zenml/zen_server/dashboard/assets/stack-detail-query-xmYxSsUY.js +0 -1
  199. zenml/zen_server/dashboard/assets/url-D5le3J4q.js +0 -1
  200. {zenml_nightly-0.68.1.dev20241111.dist-info → zenml_nightly-0.70.0.dev20241114.dist-info}/LICENSE +0 -0
  201. {zenml_nightly-0.68.1.dev20241111.dist-info → zenml_nightly-0.70.0.dev20241114.dist-info}/WHEEL +0 -0
  202. {zenml_nightly-0.68.1.dev20241111.dist-info → zenml_nightly-0.70.0.dev20241114.dist-info}/entry_points.txt +0 -0
@@ -13,6 +13,7 @@
13
13
  # permissions and limitations under the License.
14
14
  """Base filter model definitions."""
15
15
 
16
+ import json
16
17
  from abc import ABC, abstractmethod
17
18
  from datetime import datetime
18
19
  from typing import (
@@ -36,7 +37,7 @@ from pydantic import (
36
37
  field_validator,
37
38
  model_validator,
38
39
  )
39
- from sqlalchemy import asc, desc
40
+ from sqlalchemy import Float, and_, asc, cast, desc
40
41
  from sqlmodel import SQLModel
41
42
 
42
43
  from zenml.constants import (
@@ -63,6 +64,11 @@ logger = get_logger(__name__)
63
64
 
64
65
  AnyQuery = TypeVar("AnyQuery", bound=Any)
65
66
 
67
+ ONEOF_ERROR = (
68
+ "When you are using the 'oneof:' filtering make sure that the "
69
+ "provided value is a json formatted list."
70
+ )
71
+
66
72
 
67
73
  class Filter(BaseModel, ABC):
68
74
  """Filter for all fields.
@@ -171,8 +177,28 @@ class StrFilter(Filter):
171
177
  GenericFilterOps.STARTSWITH,
172
178
  GenericFilterOps.CONTAINS,
173
179
  GenericFilterOps.ENDSWITH,
180
+ GenericFilterOps.ONEOF,
181
+ GenericFilterOps.GT,
182
+ GenericFilterOps.GTE,
183
+ GenericFilterOps.LT,
184
+ GenericFilterOps.LTE,
174
185
  ]
175
186
 
187
+ @model_validator(mode="after")
188
+ def check_value_if_operation_oneof(self) -> "StrFilter":
189
+ """Validator to check if value is a list if oneof operation is used.
190
+
191
+ Raises:
192
+ ValueError: If the value is not a list
193
+
194
+ Returns:
195
+ self
196
+ """
197
+ if self.operation == GenericFilterOps.ONEOF:
198
+ if not isinstance(self.value, list):
199
+ raise ValueError(ONEOF_ERROR)
200
+ return self
201
+
176
202
  def generate_query_conditions_from_column(self, column: Any) -> Any:
177
203
  """Generate query conditions for a string column.
178
204
 
@@ -181,6 +207,9 @@ class StrFilter(Filter):
181
207
 
182
208
  Returns:
183
209
  A list of query conditions.
210
+
211
+ Raises:
212
+ ValueError: the comparison of the column to a numeric value fails.
184
213
  """
185
214
  if self.operation == GenericFilterOps.CONTAINS:
186
215
  return column.like(f"%{self.value}%")
@@ -190,6 +219,40 @@ class StrFilter(Filter):
190
219
  return column.endswith(f"{self.value}")
191
220
  if self.operation == GenericFilterOps.NOT_EQUALS:
192
221
  return column != self.value
222
+ if self.operation == GenericFilterOps.ONEOF:
223
+ return column.in_(self.value)
224
+ if self.operation in {
225
+ GenericFilterOps.GT,
226
+ GenericFilterOps.LT,
227
+ GenericFilterOps.GTE,
228
+ GenericFilterOps.LTE,
229
+ }:
230
+ try:
231
+ numeric_column = cast(column, Float)
232
+
233
+ assert self.value is not None
234
+
235
+ if self.operation == GenericFilterOps.GT:
236
+ return and_(
237
+ numeric_column, numeric_column > float(self.value)
238
+ )
239
+ if self.operation == GenericFilterOps.LT:
240
+ return and_(
241
+ numeric_column, numeric_column < float(self.value)
242
+ )
243
+ if self.operation == GenericFilterOps.GTE:
244
+ return and_(
245
+ numeric_column, numeric_column >= float(self.value)
246
+ )
247
+ if self.operation == GenericFilterOps.LTE:
248
+ return and_(
249
+ numeric_column, numeric_column <= float(self.value)
250
+ )
251
+ except Exception as e:
252
+ raise ValueError(
253
+ f"Failed to compare the column '{column}' to the "
254
+ f"value '{self.value}' (must be numeric): {e}"
255
+ )
193
256
 
194
257
  return column == self.value
195
258
 
@@ -211,6 +274,9 @@ class UUIDFilter(StrFilter):
211
274
  if isinstance(value, str):
212
275
  return value.replace("-", "")
213
276
 
277
+ if isinstance(value, list):
278
+ return [str(v).replace("-", "") for v in value]
279
+
214
280
  return value
215
281
 
216
282
  def generate_query_conditions_from_column(self, column: Any) -> Any:
@@ -588,6 +654,10 @@ class BaseFilter(BaseModel):
588
654
 
589
655
  Returns:
590
656
  A tuple of the filter value and the operator.
657
+
658
+ Raises:
659
+ ValueError: when we try to use the `oneof` operator with the wrong
660
+ value.
591
661
  """
592
662
  operator = GenericFilterOps.EQUALS # Default operator
593
663
  if isinstance(value, str):
@@ -598,6 +668,15 @@ class BaseFilter(BaseModel):
598
668
  ):
599
669
  value = split_value[1]
600
670
  operator = GenericFilterOps(split_value[0])
671
+
672
+ if operator == operator.ONEOF:
673
+ try:
674
+ value = json.loads(value)
675
+ if not isinstance(value, list):
676
+ raise ValueError
677
+ except ValueError:
678
+ raise ValueError(ONEOF_ERROR)
679
+
601
680
  return value, operator
602
681
 
603
682
  def generate_name_or_id_query_conditions(
@@ -648,8 +727,8 @@ class BaseFilter(BaseModel):
648
727
 
649
728
  return or_(*conditions)
650
729
 
730
+ @staticmethod
651
731
  def generate_custom_query_conditions_for_column(
652
- self,
653
732
  value: Any,
654
733
  table: Type[SQLModel],
655
734
  column: str,
@@ -833,16 +912,17 @@ class FilterGenerator:
833
912
 
834
913
  # Create str filters
835
914
  if self.is_str_field(column):
836
- return StrFilter(
837
- operation=GenericFilterOps(operator),
915
+ return self._define_str_filter(
916
+ operator=GenericFilterOps(operator),
838
917
  column=column,
839
918
  value=value,
840
919
  )
841
920
 
842
921
  # Handle unsupported datatypes
843
922
  logger.warning(
844
- f"The Datatype {self._model_class.model_fields[column].annotation} might "
845
- "not be supported for filtering. Defaulting to a string filter."
923
+ f"The Datatype {self._model_class.model_fields[column].annotation} "
924
+ "might not be supported for filtering. Defaulting to a string "
925
+ "filter."
846
926
  )
847
927
  return StrFilter(
848
928
  operation=GenericFilterOps(operator),
@@ -1032,8 +1112,9 @@ class FilterGenerator:
1032
1112
  "Invalid value passed as UUID query parameter."
1033
1113
  ) from e
1034
1114
 
1035
- # Cast the value to string for further comparisons.
1036
- value = str(value)
1115
+ # For equality checks, ensure that the value is a valid UUID.
1116
+ if operator == GenericFilterOps.ONEOF and not isinstance(value, list):
1117
+ raise ValueError(ONEOF_ERROR)
1037
1118
 
1038
1119
  # Generate the filter.
1039
1120
  uuid_filter = UUIDFilter(
@@ -1043,6 +1124,38 @@ class FilterGenerator:
1043
1124
  )
1044
1125
  return uuid_filter
1045
1126
 
1127
+ @staticmethod
1128
+ def _define_str_filter(
1129
+ column: str, value: Any, operator: GenericFilterOps
1130
+ ) -> StrFilter:
1131
+ """Define a str filter for a given column.
1132
+
1133
+ Args:
1134
+ column: The column to filter on.
1135
+ value: The UUID value by which to filter.
1136
+ operator: The operator to use for filtering.
1137
+
1138
+ Returns:
1139
+ A Filter object.
1140
+
1141
+ Raises:
1142
+ ValueError: If the value is not a proper value.
1143
+ """
1144
+ # For equality checks, ensure that the value is a valid UUID.
1145
+ if operator == GenericFilterOps.ONEOF and not isinstance(value, list):
1146
+ raise ValueError(
1147
+ "If you are using `oneof:` as a filtering op, the value needs "
1148
+ "to be a json formatted list string."
1149
+ )
1150
+
1151
+ # Generate the filter.
1152
+ str_filter = StrFilter(
1153
+ operation=GenericFilterOps(operator),
1154
+ column=column,
1155
+ value=value,
1156
+ )
1157
+ return str_filter
1158
+
1046
1159
  @staticmethod
1047
1160
  def _define_bool_filter(
1048
1161
  column: str, value: Any, operator: GenericFilterOps
@@ -474,6 +474,7 @@ class ArtifactVersionFilter(WorkspaceScopedTaggableFilter):
474
474
  "user",
475
475
  "model",
476
476
  "pipeline_run",
477
+ "run_metadata",
477
478
  ]
478
479
  artifact_id: Optional[Union[UUID, str]] = Field(
479
480
  default=None,
@@ -545,6 +546,10 @@ class ArtifactVersionFilter(WorkspaceScopedTaggableFilter):
545
546
  description="Name/ID of a pipeline run that is associated with this "
546
547
  "artifact version.",
547
548
  )
549
+ run_metadata: Optional[Dict[str, str]] = Field(
550
+ default=None,
551
+ description="The run_metadata to filter the artifact versions by.",
552
+ )
548
553
 
549
554
  model_config = ConfigDict(protected_namespaces=())
550
555
 
@@ -564,6 +569,7 @@ class ArtifactVersionFilter(WorkspaceScopedTaggableFilter):
564
569
  ModelSchema,
565
570
  ModelVersionArtifactSchema,
566
571
  PipelineRunSchema,
572
+ RunMetadataSchema,
567
573
  StepRunInputArtifactSchema,
568
574
  StepRunOutputArtifactSchema,
569
575
  StepRunSchema,
@@ -645,6 +651,23 @@ class ArtifactVersionFilter(WorkspaceScopedTaggableFilter):
645
651
  )
646
652
  custom_filters.append(pipeline_run_filter)
647
653
 
654
+ if self.run_metadata is not None:
655
+ from zenml.enums import MetadataResourceTypes
656
+
657
+ for key, value in self.run_metadata.items():
658
+ additional_filter = and_(
659
+ RunMetadataSchema.resource_id == ArtifactVersionSchema.id,
660
+ RunMetadataSchema.resource_type
661
+ == MetadataResourceTypes.ARTIFACT_VERSION,
662
+ RunMetadataSchema.key == key,
663
+ self.generate_custom_query_conditions_for_column(
664
+ value=value,
665
+ table=RunMetadataSchema,
666
+ column="value",
667
+ ),
668
+ )
669
+ custom_filters.append(additional_filter)
670
+
648
671
  return custom_filters
649
672
 
650
673
 
@@ -590,6 +590,7 @@ class ModelVersionFilter(WorkspaceScopedTaggableFilter):
590
590
  FILTER_EXCLUDE_FIELDS: ClassVar[List[str]] = [
591
591
  *WorkspaceScopedTaggableFilter.FILTER_EXCLUDE_FIELDS,
592
592
  "user",
593
+ "run_metadata",
593
594
  ]
594
595
 
595
596
  name: Optional[str] = Field(
@@ -619,6 +620,10 @@ class ModelVersionFilter(WorkspaceScopedTaggableFilter):
619
620
  default=None,
620
621
  description="Name/ID of the user that created the model version.",
621
622
  )
623
+ run_metadata: Optional[Dict[str, str]] = Field(
624
+ default=None,
625
+ description="The run_metadata to filter the model versions by.",
626
+ )
622
627
 
623
628
  _model_id: UUID = PrivateAttr(None)
624
629
 
@@ -651,6 +656,7 @@ class ModelVersionFilter(WorkspaceScopedTaggableFilter):
651
656
 
652
657
  from zenml.zen_stores.schemas import (
653
658
  ModelVersionSchema,
659
+ RunMetadataSchema,
654
660
  UserSchema,
655
661
  )
656
662
 
@@ -665,6 +671,23 @@ class ModelVersionFilter(WorkspaceScopedTaggableFilter):
665
671
  )
666
672
  custom_filters.append(user_filter)
667
673
 
674
+ if self.run_metadata is not None:
675
+ from zenml.enums import MetadataResourceTypes
676
+
677
+ for key, value in self.run_metadata.items():
678
+ additional_filter = and_(
679
+ RunMetadataSchema.resource_id == ModelVersionSchema.id,
680
+ RunMetadataSchema.resource_type
681
+ == MetadataResourceTypes.MODEL_VERSION,
682
+ RunMetadataSchema.key == key,
683
+ self.generate_custom_query_conditions_for_column(
684
+ value=value,
685
+ table=RunMetadataSchema,
686
+ column="value",
687
+ ),
688
+ )
689
+ custom_filters.append(additional_filter)
690
+
668
691
  return custom_filters
669
692
 
670
693
  def apply_filter(
@@ -587,6 +587,7 @@ class PipelineRunFilter(WorkspaceScopedTaggableFilter):
587
587
  "stack_component",
588
588
  "pipeline_name",
589
589
  "templatable",
590
+ "run_metadata",
590
591
  ]
591
592
  name: Optional[str] = Field(
592
593
  default=None,
@@ -665,6 +666,10 @@ class PipelineRunFilter(WorkspaceScopedTaggableFilter):
665
666
  default=None,
666
667
  description="Name/ID of the user that created the run.",
667
668
  )
669
+ run_metadata: Optional[Dict[str, str]] = Field(
670
+ default=None,
671
+ description="The run_metadata to filter the pipeline runs by.",
672
+ )
668
673
  # TODO: Remove once frontend is ready for it. This is replaced by the more
669
674
  # generic `pipeline` filter below.
670
675
  pipeline_name: Optional[str] = Field(
@@ -694,7 +699,6 @@ class PipelineRunFilter(WorkspaceScopedTaggableFilter):
694
699
  templatable: Optional[bool] = Field(
695
700
  default=None, description="Whether the run is templatable."
696
701
  )
697
-
698
702
  model_config = ConfigDict(protected_namespaces=())
699
703
 
700
704
  def get_custom_filters(
@@ -718,6 +722,7 @@ class PipelineRunFilter(WorkspaceScopedTaggableFilter):
718
722
  PipelineDeploymentSchema,
719
723
  PipelineRunSchema,
720
724
  PipelineSchema,
725
+ RunMetadataSchema,
721
726
  ScheduleSchema,
722
727
  StackComponentSchema,
723
728
  StackCompositionSchema,
@@ -887,5 +892,21 @@ class PipelineRunFilter(WorkspaceScopedTaggableFilter):
887
892
  )
888
893
 
889
894
  custom_filters.append(templatable_filter)
895
+ if self.run_metadata is not None:
896
+ from zenml.enums import MetadataResourceTypes
897
+
898
+ for key, value in self.run_metadata.items():
899
+ additional_filter = and_(
900
+ RunMetadataSchema.resource_id == PipelineRunSchema.id,
901
+ RunMetadataSchema.resource_type
902
+ == MetadataResourceTypes.PIPELINE_RUN,
903
+ RunMetadataSchema.key == key,
904
+ self.generate_custom_query_conditions_for_column(
905
+ value=value,
906
+ table=RunMetadataSchema,
907
+ column="value",
908
+ ),
909
+ )
910
+ custom_filters.append(additional_filter)
890
911
 
891
912
  return custom_filters
@@ -509,6 +509,7 @@ class StepRunFilter(WorkspaceScopedFilter):
509
509
  FILTER_EXCLUDE_FIELDS: ClassVar[List[str]] = [
510
510
  *WorkspaceScopedFilter.FILTER_EXCLUDE_FIELDS,
511
511
  "model",
512
+ "run_metadata",
512
513
  ]
513
514
 
514
515
  name: Optional[str] = Field(
@@ -571,6 +572,10 @@ class StepRunFilter(WorkspaceScopedFilter):
571
572
  default=None,
572
573
  description="Name/ID of the model associated with the step run.",
573
574
  )
575
+ run_metadata: Optional[Dict[str, str]] = Field(
576
+ default=None,
577
+ description="The run_metadata to filter the step runs by.",
578
+ )
574
579
 
575
580
  model_config = ConfigDict(protected_namespaces=())
576
581
 
@@ -589,6 +594,7 @@ class StepRunFilter(WorkspaceScopedFilter):
589
594
  from zenml.zen_stores.schemas import (
590
595
  ModelSchema,
591
596
  ModelVersionSchema,
597
+ RunMetadataSchema,
592
598
  StepRunSchema,
593
599
  )
594
600
 
@@ -601,5 +607,21 @@ class StepRunFilter(WorkspaceScopedFilter):
601
607
  ),
602
608
  )
603
609
  custom_filters.append(model_filter)
610
+ if self.run_metadata is not None:
611
+ from zenml.enums import MetadataResourceTypes
612
+
613
+ for key, value in self.run_metadata.items():
614
+ additional_filter = and_(
615
+ RunMetadataSchema.resource_id == StepRunSchema.id,
616
+ RunMetadataSchema.resource_type
617
+ == MetadataResourceTypes.STEP_RUN,
618
+ RunMetadataSchema.key == key,
619
+ self.generate_custom_query_conditions_for_column(
620
+ value=value,
621
+ table=RunMetadataSchema,
622
+ column="value",
623
+ ),
624
+ )
625
+ custom_filters.append(additional_filter)
604
626
 
605
627
  return custom_filters
@@ -15,6 +15,7 @@
15
15
 
16
16
  from abc import ABC, abstractmethod
17
17
  from typing import TYPE_CHECKING, Any, Dict, Iterator, Optional, Type, cast
18
+ from uuid import UUID
18
19
 
19
20
  from pydantic import model_validator
20
21
 
@@ -186,7 +187,17 @@ class BaseOrchestrator(StackComponent, ABC):
186
187
  """
187
188
  self._prepare_run(deployment=deployment)
188
189
 
189
- environment = get_config_environment_vars(deployment=deployment)
190
+ pipeline_run_id: Optional[UUID] = None
191
+ schedule_id: Optional[UUID] = None
192
+ if deployment.schedule:
193
+ schedule_id = deployment.schedule.id
194
+ if placeholder_run:
195
+ pipeline_run_id = placeholder_run.id
196
+
197
+ environment = get_config_environment_vars(
198
+ schedule_id=schedule_id,
199
+ pipeline_run_id=pipeline_run_id,
200
+ )
190
201
 
191
202
  prevent_client_side_caching = handle_bool_env_var(
192
203
  ENV_ZENML_PREVENT_CLIENT_SIDE_CACHING, default=False
@@ -422,7 +422,8 @@ class StepLauncher:
422
422
  )
423
423
  )
424
424
  environment = orchestrator_utils.get_config_environment_vars(
425
- deployment=self._deployment
425
+ pipeline_run_id=step_run_info.run_id,
426
+ step_run_id=step_run_info.step_run_id,
426
427
  )
427
428
  if last_retry:
428
429
  environment[ENV_ZENML_IGNORE_FAILURE_HOOK] = str(False)
@@ -28,16 +28,16 @@ from zenml.constants import (
28
28
  ENV_ZENML_DISABLE_CREDENTIALS_DISK_CACHING,
29
29
  ENV_ZENML_SERVER,
30
30
  ENV_ZENML_STORE_PREFIX,
31
- PIPELINE_API_TOKEN_EXPIRES_MINUTES,
32
31
  )
33
32
  from zenml.enums import AuthScheme, StackComponentType, StoreType
34
33
  from zenml.logger import get_logger
35
34
  from zenml.stack import StackComponent
36
35
  from zenml.utils.string_utils import format_name_template
37
36
 
37
+ logger = get_logger(__name__)
38
+
38
39
  if TYPE_CHECKING:
39
40
  from zenml.artifact_stores.base_artifact_store import BaseArtifactStore
40
- from zenml.models import PipelineDeploymentResponse
41
41
 
42
42
 
43
43
  def get_orchestrator_run_name(pipeline_name: str) -> str:
@@ -80,16 +80,23 @@ def is_setting_enabled(
80
80
 
81
81
 
82
82
  def get_config_environment_vars(
83
- deployment: Optional["PipelineDeploymentResponse"] = None,
83
+ schedule_id: Optional[UUID] = None,
84
+ pipeline_run_id: Optional[UUID] = None,
85
+ step_run_id: Optional[UUID] = None,
84
86
  ) -> Dict[str, str]:
85
87
  """Gets environment variables to set for mirroring the active config.
86
88
 
87
- If a pipeline deployment is given, the environment variables will be set to
88
- include a newly generated API token valid for the duration of the pipeline
89
- run instead of the API token from the global config.
89
+ If a schedule ID, pipeline run ID or step run ID is given, and the current
90
+ client is not authenticated to a server with an API key, the environment
91
+ variables will be updated to include a newly generated workload API token
92
+ that will be valid for the duration of the schedule, pipeline run, or step
93
+ run instead of the current API token used to authenticate the client.
90
94
 
91
95
  Args:
92
- deployment: Optional deployment to use for the environment variables.
96
+ schedule_id: Optional schedule ID to use to generate a new API token.
97
+ pipeline_run_id: Optional pipeline run ID to use to generate a new API
98
+ token.
99
+ step_run_id: Optional step run ID to use to generate a new API token.
93
100
 
94
101
  Returns:
95
102
  Environment variable dict.
@@ -107,34 +114,46 @@ def get_config_environment_vars(
107
114
  ):
108
115
  credentials_store = get_credentials_store()
109
116
  url = global_config.store_configuration.url
110
- api_key = credentials_store.get_api_key(url)
111
117
  api_token = credentials_store.get_token(url, allow_expired=False)
112
- if api_key:
113
- environment_vars[ENV_ZENML_STORE_PREFIX + "API_KEY"] = api_key
114
- elif deployment:
115
- # When connected to an authenticated ZenML server, if a pipeline
116
- # deployment is supplied, we need to fetch an API token that will be
117
- # valid for the duration of the pipeline run.
118
+ if schedule_id or pipeline_run_id or step_run_id:
119
+ # When connected to an authenticated ZenML server, if a schedule ID,
120
+ # pipeline run ID or step run ID is supplied, we need to fetch a new
121
+ # workload API token scoped to the schedule, pipeline run or step
122
+ # run.
118
123
  assert isinstance(global_config.zen_store, RestZenStore)
119
- pipeline_id: Optional[UUID] = None
120
- if deployment.pipeline:
121
- pipeline_id = deployment.pipeline.id
122
- schedule_id: Optional[UUID] = None
123
- expires_minutes: Optional[int] = PIPELINE_API_TOKEN_EXPIRES_MINUTES
124
- if deployment.schedule:
125
- schedule_id = deployment.schedule.id
126
- # If a schedule is given, this is a long running pipeline that
127
- # should not have an API token that expires.
128
- expires_minutes = None
124
+
125
+ # If only a schedule is given, the pipeline run credentials will
126
+ # be valid for the entire duration of the schedule.
127
+ api_key = credentials_store.get_api_key(url)
128
+ if not api_key and not pipeline_run_id and not step_run_id:
129
+ logger.warning(
130
+ "An API token without an expiration time will be generated "
131
+ "and used to run this pipeline on a schedule. This is very "
132
+ "insecure because the API token will be valid for the "
133
+ "entire lifetime of the schedule and can be used to access "
134
+ "your user account if accidentally leaked. When deploying "
135
+ "a pipeline on a schedule, it is strongly advised to use a "
136
+ "service account API key to authenticate to the ZenML "
137
+ "server instead of your regular user account. For more "
138
+ "information, see "
139
+ "https://docs.zenml.io/how-to/connecting-to-zenml/connect-with-a-service-account"
140
+ )
141
+
142
+ # The schedule, pipeline run or step run credentials are scoped to
143
+ # the schedule, pipeline run or step run and will only be valid for
144
+ # the duration of the schedule/pipeline run/step run.
129
145
  new_api_token = global_config.zen_store.get_api_token(
130
- pipeline_id=pipeline_id,
131
146
  schedule_id=schedule_id,
132
- expires_minutes=expires_minutes,
147
+ pipeline_run_id=pipeline_run_id,
148
+ step_run_id=step_run_id,
133
149
  )
150
+
134
151
  environment_vars[ENV_ZENML_STORE_PREFIX + "API_TOKEN"] = (
135
152
  new_api_token
136
153
  )
137
154
  elif api_token:
155
+ # For all other cases, the pipeline run environment is configured
156
+ # with the current access token.
138
157
  environment_vars[ENV_ZENML_STORE_PREFIX + "API_TOKEN"] = (
139
158
  api_token.access_token
140
159
  )
@@ -71,7 +71,8 @@ of any potential costs:
71
71
 
72
72
  - An S3 bucket registered as a [ZenML artifact store](https://docs.zenml.io/stack-components/artifact-stores/s3).
73
73
  - An ECR repository registered as a [ZenML container registry](https://docs.zenml.io/stack-components/container-registries/aws).
74
- - Sagemaker registered as a [ZenML orchestrator](https://docs.zenml.io/stack-components/orchestrators/sagemaker).
74
+ - Sagemaker registered as a [ZenML orchestrator](https://docs.zenml.io/stack-components/orchestrators/sagemaker)
75
+ as well as a [ZenML step operator](https://docs.zenml.io/stack-components/step-operators/sagemaker).
75
76
  - An IAM user and IAM role with the minimum necessary permissions to access the
76
77
  above resources.
77
78
  - An AWS access key used to give access to ZenML to connect to the above
@@ -257,13 +258,29 @@ console.
257
258
 
258
259
  config: Optional[str] = None
259
260
  if self.deployment_type == STACK_DEPLOYMENT_TERRAFORM:
260
- config = f"""module "zenml_stack" {{
261
- source = "zenml-io/zenml-stack/aws"
261
+ config = f"""terraform {{
262
+ required_providers {{
263
+ aws = {{
264
+ source = "hashicorp/aws"
265
+ }}
266
+ zenml = {{
267
+ source = "zenml-io/zenml"
268
+ }}
269
+ }}
270
+ }}
262
271
 
272
+ provider "aws" {{
263
273
  region = "{self.location or "eu-central-1"}"
264
- zenml_server_url = "{self.zenml_server_url}"
265
- zenml_api_key = ""
266
- zenml_api_token = "{self.zenml_server_api_token}"
274
+ }}
275
+
276
+ provider "zenml" {{
277
+ server_url = "{self.zenml_server_url}"
278
+ api_token = "{self.zenml_server_api_token}"
279
+ }}
280
+
281
+ module "zenml_stack" {{
282
+ source = "zenml-io/zenml-stack/aws"
283
+
267
284
  zenml_stack_name = "{self.stack_name}"
268
285
  zenml_stack_deployment = "{self.deployment_type}"
269
286
  }}
@@ -259,14 +259,37 @@ ZenML's access to your Azure subscription.
259
259
  The configuration or script to deploy the ZenML stack to the
260
260
  specified cloud provider.
261
261
  """
262
- config = f"""module "zenml_stack" {{
262
+ config = f"""terraform {{
263
+ required_providers {{
264
+ azurerm = {{
265
+ source = "hashicorp/azurerm"
266
+ }}
267
+ azuread = {{
268
+ source = "hashicorp/azuread"
269
+ }}
270
+ zenml = {{
271
+ source = "zenml-io/zenml"
272
+ }}
273
+ }}
274
+ }}
275
+
276
+ provider "azurerm" {{
277
+ features {{
278
+ resource_group {{
279
+ prevent_deletion_if_contains_resources = false
280
+ }}
281
+ }}
282
+ }}
283
+
284
+ provider "zenml" {{
285
+ server_url = "{self.zenml_server_url}"
286
+ api_token = "{self.zenml_server_api_token}"
287
+ }}
288
+
289
+ module "zenml_stack" {{
263
290
  source = "zenml-io/zenml-stack/azure"
264
291
 
265
292
  location = "{self.location or "eastus"}"
266
- orchestrator = "azureml"
267
- zenml_server_url = "{self.zenml_server_url}"
268
- zenml_api_key = ""
269
- zenml_api_token = "{self.zenml_server_api_token}"
270
293
  zenml_stack_name = "{self.stack_name}"
271
294
  zenml_stack_deployment = "{self.deployment_type}"
272
295
  }}