zenml-nightly 0.71.0.dev20250109__py3-none-any.whl → 0.71.0.dev20250112__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 (134) hide show
  1. zenml/VERSION +1 -1
  2. zenml/cli/base.py +1 -1
  3. zenml/cli/formatter.py +1 -1
  4. zenml/cli/integration.py +1 -1
  5. zenml/cli/model_registry.py +1 -2
  6. zenml/cli/secret.py +1 -2
  7. zenml/cli/service_connectors.py +1 -1
  8. zenml/cli/stack.py +2 -3
  9. zenml/cli/stack_components.py +4 -6
  10. zenml/cli/text_utils.py +1 -1
  11. zenml/cli/utils.py +4 -5
  12. zenml/client.py +1 -4
  13. zenml/constants.py +1 -0
  14. zenml/entrypoints/step_entrypoint_configuration.py +15 -0
  15. zenml/integrations/azure/__init__.py +1 -1
  16. zenml/integrations/azure/azureml_utils.py +1 -1
  17. zenml/integrations/azure/orchestrators/azureml_orchestrator_entrypoint_config.py +0 -5
  18. zenml/integrations/bitbucket/plugins/event_sources/bitbucket_webhook_event_source.py +3 -3
  19. zenml/integrations/databricks/orchestrators/databricks_orchestrator.py +1 -3
  20. zenml/integrations/evidently/metrics.py +2 -2
  21. zenml/integrations/evidently/tests.py +2 -2
  22. zenml/integrations/gcp/service_connectors/gcp_service_connector.py +3 -3
  23. zenml/integrations/github/plugins/event_sources/github_webhook_event_source.py +3 -3
  24. zenml/integrations/s3/utils.py +1 -2
  25. zenml/logger.py +1 -1
  26. zenml/models/v2/base/scoped.py +32 -28
  27. zenml/models/v2/core/artifact.py +86 -2
  28. zenml/models/v2/core/model.py +81 -2
  29. zenml/models/v2/core/pipeline.py +15 -12
  30. zenml/models/v2/core/pipeline_run.py +2 -0
  31. zenml/services/container/container_service.py +1 -1
  32. zenml/stack/stack_component.py +1 -1
  33. zenml/utils/deprecation_utils.py +6 -6
  34. zenml/utils/filesync_model.py +3 -3
  35. zenml/utils/function_utils.py +1 -1
  36. zenml/utils/pipeline_docker_image_builder.py +1 -1
  37. zenml/zen_server/auth.py +2 -5
  38. zenml/zen_server/dashboard/assets/{404-Cqu3EDCm.js → 404-Dfq64Boz.js} +1 -1
  39. zenml/zen_server/dashboard/assets/{@reactflow-D2Y7BWwz.js → @reactflow-BUNIMFeC.js} +1 -1
  40. zenml/zen_server/dashboard/assets/{AlertDialogDropdownItem-BHd71pVS.js → AlertDialogDropdownItem-B73Vs10T.js} +1 -1
  41. zenml/zen_server/dashboard/assets/{CodeSnippet-DIonwetW.js → CodeSnippet-DIJRT2NT.js} +1 -1
  42. zenml/zen_server/dashboard/assets/{CollapsibleCard-CDnC97pB.js → CollapsibleCard-BzUHGZOU.js} +1 -1
  43. zenml/zen_server/dashboard/assets/{Commands-BVEXKAOj.js → Commands-BEGyld4c.js} +1 -1
  44. zenml/zen_server/dashboard/assets/{ComponentBadge-CrRvovox.js → ComponentBadge-xyKiek1s.js} +1 -1
  45. zenml/zen_server/dashboard/assets/{CopyButton-B6wGAhQv.js → CopyButton-DhW-mapu.js} +1 -1
  46. zenml/zen_server/dashboard/assets/{CsvVizualization-CjcT7LMm.js → CsvVizualization-D8oazBiE.js} +1 -1
  47. zenml/zen_server/dashboard/assets/{DeleteAlertDialog-D2ELtM2W.js → DeleteAlertDialog-WkSIIgfy.js} +1 -1
  48. zenml/zen_server/dashboard/assets/{DialogItem-DXIMhBgU.js → DialogItem-Bgroeg29.js} +1 -1
  49. zenml/zen_server/dashboard/assets/{Error-B8uUfTpL.js → Error-CY5tlu17.js} +1 -1
  50. zenml/zen_server/dashboard/assets/{ExecutionStatus-ibAdY-dG.js → ExecutionStatus-G8mjIaeA.js} +1 -1
  51. zenml/zen_server/dashboard/assets/{Helpbox-BfAfhKHw.js → Helpbox-Bb1ed--O.js} +1 -1
  52. zenml/zen_server/dashboard/assets/{Infobox-M_SMOu96.js → Infobox-Da6-76M2.js} +1 -1
  53. zenml/zen_server/dashboard/assets/{InlineAvatar-DBA0a0-a.js → InlineAvatar-DqnZaBNq.js} +1 -1
  54. zenml/zen_server/dashboard/assets/{NestedCollapsible-DpgmEFKw.js → NestedCollapsible-aK5ojKoF.js} +1 -1
  55. zenml/zen_server/dashboard/assets/{Partials-D_ldD9if.js → Partials-CqZp5NMX.js} +1 -1
  56. zenml/zen_server/dashboard/assets/{ProBadge-DQbfFotM.js → ProBadge-B4tRUYve.js} +1 -1
  57. zenml/zen_server/dashboard/assets/{ProCta-Bcpb4rcY.js → ProCta-CZuP29Qz.js} +1 -1
  58. zenml/zen_server/dashboard/assets/{ProviderIcon-BZpgPigN.js → ProviderIcon-Bd7GUQ1_.js} +1 -1
  59. zenml/zen_server/dashboard/assets/{ProviderRadio-DWPnMuQ1.js → ProviderRadio-mstdqzsS.js} +1 -1
  60. zenml/zen_server/dashboard/assets/{RunSelector-DgRGaAc6.js → RunSelector-CsruSB4i.js} +1 -1
  61. zenml/zen_server/dashboard/assets/{RunsBody-KecfSkjY.js → RunsBody-DxxtWVYz.js} +1 -1
  62. zenml/zen_server/dashboard/assets/{SearchField-n-ILHnaP.js → SearchField-D6tPxyqw.js} +1 -1
  63. zenml/zen_server/dashboard/assets/{SecretTooltip-B8MrX5yu.js → SecretTooltip-CLzJIYW_.js} +1 -1
  64. zenml/zen_server/dashboard/assets/{SetPassword-B_IVq_wg.js → SetPassword-Yn50ooBC.js} +1 -1
  65. zenml/zen_server/dashboard/assets/{StackList-TWPBYnkF.js → StackList-U537qoYd.js} +1 -1
  66. zenml/zen_server/dashboard/assets/{Tabs-Rg857zmd.js → Tabs-CNv-eTYM.js} +1 -1
  67. zenml/zen_server/dashboard/assets/{Tick-COg4A-xo.js → Tick-jEIevzVf.js} +1 -1
  68. zenml/zen_server/dashboard/assets/{UpdatePasswordSchemas-C6Aj3hm6.js → UpdatePasswordSchemas-C16GW-kX.js} +1 -1
  69. zenml/zen_server/dashboard/assets/{UsageReason-BTLbx7w4.js → UsageReason-Bf2tzhv1.js} +1 -1
  70. zenml/zen_server/dashboard/assets/{WizardFooter-BCAj69Vj.js → WizardFooter-D6i-AP1K.js} +1 -1
  71. zenml/zen_server/dashboard/assets/{all-pipeline-runs-query-DMXkDrV2.js → all-pipeline-runs-query-DUti43aF.js} +1 -1
  72. zenml/zen_server/dashboard/assets/{create-stack-HfdbhLs4.js → create-stack-Ch2WPs9U.js} +1 -1
  73. zenml/zen_server/dashboard/assets/{delete-run-DZ4hIXff.js → delete-run-Byf9hTjA.js} +1 -1
  74. zenml/zen_server/dashboard/assets/{form-schemas-B0AVEd9b.js → form-schemas-BZqKBPBF.js} +1 -1
  75. zenml/zen_server/dashboard/assets/{index-FO-p0GU7.js → index-CE0aQlv8.js} +3 -3
  76. zenml/zen_server/dashboard/assets/{index-DScjfBRb.js → index-CtdYkjUi.js} +1 -1
  77. zenml/zen_server/dashboard/assets/{index-DPqSWjug.js → index-CyBKZcpO.js} +1 -1
  78. zenml/zen_server/dashboard/assets/{index-I3bKUGUj.js → index-v6gQjDEo.js} +1 -1
  79. zenml/zen_server/dashboard/assets/{login-mutation-BQeo4wTY.js → login-mutation-DNDVp_2H.js} +1 -1
  80. zenml/zen_server/dashboard/assets/{not-found-gAJ5aDdR.js → not-found-Bmup4ctE.js} +1 -1
  81. zenml/zen_server/dashboard/assets/{page-I3nKFGie.js → page--XLMzHrn.js} +1 -1
  82. zenml/zen_server/dashboard/assets/{page-DO1UcqPX.js → page-ANYGfEUL.js} +1 -1
  83. zenml/zen_server/dashboard/assets/{page-AUwiQ14W.js → page-B5Sr8pib.js} +1 -1
  84. zenml/zen_server/dashboard/assets/{page-CcQr8CPP.js → page-BC27C_OI.js} +1 -1
  85. zenml/zen_server/dashboard/assets/{page-zaMqB_ao.js → page-BNxYrN0q.js} +1 -1
  86. zenml/zen_server/dashboard/assets/{page-CiYxgZP_.js → page-BYJfqgLN.js} +1 -1
  87. zenml/zen_server/dashboard/assets/{page-h_Stveon.js → page-B_0XkV48.js} +1 -1
  88. zenml/zen_server/dashboard/assets/{page-R5dx3xGF.js → page-BrmJp1Wt.js} +1 -1
  89. zenml/zen_server/dashboard/assets/page-C2nU3Gxn.js +1 -0
  90. zenml/zen_server/dashboard/assets/{page-Dk32IeZm.js → page-C70wZtV2.js} +1 -1
  91. zenml/zen_server/dashboard/assets/{page-CWxT5K5J.js → page-CHRn1fQm.js} +1 -1
  92. zenml/zen_server/dashboard/assets/{page-M0w-n6vn.js → page-CWr96ZKN.js} +1 -1
  93. zenml/zen_server/dashboard/assets/{page-Ce4Hrjnr.js → page-CXAbSyp9.js} +1 -1
  94. zenml/zen_server/dashboard/assets/{page-D8ObrbH8.js → page-CaeI9ptC.js} +1 -1
  95. zenml/zen_server/dashboard/assets/{page-B_Apk3xg.js → page-Cc8ZEuj4.js} +1 -1
  96. zenml/zen_server/dashboard/assets/{page-BxL4qD4_.js → page-CltCNL0T.js} +1 -1
  97. zenml/zen_server/dashboard/assets/{page-D4wdonLm.js → page-CmlYj7Nl.js} +1 -1
  98. zenml/zen_server/dashboard/assets/{page-DFuAUGt4.js → page-D6Ev5P8V.js} +1 -1
  99. zenml/zen_server/dashboard/assets/{page-u_-ZXBKb.js → page-D9Oh05fl.js} +1 -1
  100. zenml/zen_server/dashboard/assets/{page-DRYXdL5o.js → page-DGlm1RVc.js} +1 -1
  101. zenml/zen_server/dashboard/assets/{page-r8XK5vR7.js → page-DN4BVIOL.js} +1 -1
  102. zenml/zen_server/dashboard/assets/{page-DYEquBC2.js → page-Dif8CWyZ.js} +1 -1
  103. zenml/zen_server/dashboard/assets/{page-BdowiCbr.js → page-DlIi5ThM.js} +1 -1
  104. zenml/zen_server/dashboard/assets/{page-9Y9-gig0.js → page-DoW7YxTu.js} +1 -1
  105. zenml/zen_server/dashboard/assets/{page-BKZYc2Zv.js → page-Dth9X1Ih.js} +1 -1
  106. zenml/zen_server/dashboard/assets/{page-bT5pOvcB.js → page-DweqqCkF.js} +1 -1
  107. zenml/zen_server/dashboard/assets/{page-CXuQufSe.js → page-DyOJ_pq3.js} +1 -1
  108. zenml/zen_server/dashboard/assets/{page-DGazBpuP.js → page-Hn8q9iJZ.js} +1 -1
  109. zenml/zen_server/dashboard/assets/{page-hUqK889I.js → page-IhckKFnD.js} +1 -1
  110. zenml/zen_server/dashboard/assets/{page-BU9FG4sR.js → page-LyZ_l8vR.js} +1 -1
  111. zenml/zen_server/dashboard/assets/{page-Cldq1mpe.js → page-PamGpk0j.js} +1 -1
  112. zenml/zen_server/dashboard/assets/page-PxOWfKgF.js +2 -0
  113. zenml/zen_server/dashboard/assets/{persist-DAUi_3za.js → persist-DeXRG61d.js} +1 -1
  114. zenml/zen_server/dashboard/assets/{persist-AppN1B0J.js → persist-vP0-Xl4f.js} +1 -1
  115. zenml/zen_server/dashboard/assets/{service-BqqeXLEe.js → service-DH_oUqQj.js} +1 -1
  116. zenml/zen_server/dashboard/assets/{sharedSchema-uXN9FLLk.js → sharedSchema-Bw1_Wa7l.js} +1 -1
  117. zenml/zen_server/dashboard/assets/{stack-detail-query-XfZBiBP2.js → stack-detail-query-B_0R_fd6.js} +1 -1
  118. zenml/zen_server/dashboard/assets/{update-server-settings-mutation-BWmgVJwA.js → update-server-settings-mutation-D9qYhfaN.js} +1 -1
  119. zenml/zen_server/dashboard/assets/{url-BLwMbzES.js → url-Dh93fvh0.js} +1 -1
  120. zenml/zen_server/dashboard/index.html +3 -3
  121. zenml/zen_server/deploy/deployer.py +1 -1
  122. zenml/zen_server/rbac/rbac_sql_zen_store.py +3 -1
  123. zenml/zen_server/routers/webhook_endpoints.py +1 -2
  124. zenml/zen_stores/migrations/utils.py +1 -2
  125. zenml/zen_stores/migrations/versions/5330ba58bf20_rename_tables_and_foreign_keys.py +7 -9
  126. zenml/zen_stores/rest_zen_store.py +1 -1
  127. zenml/zen_stores/sql_zen_store.py +9 -3
  128. {zenml_nightly-0.71.0.dev20250109.dist-info → zenml_nightly-0.71.0.dev20250112.dist-info}/METADATA +2 -2
  129. {zenml_nightly-0.71.0.dev20250109.dist-info → zenml_nightly-0.71.0.dev20250112.dist-info}/RECORD +132 -132
  130. zenml/zen_server/dashboard/assets/page-B6XU7yYT.js +0 -2
  131. zenml/zen_server/dashboard/assets/page-Bg8OjTRe.js +0 -1
  132. {zenml_nightly-0.71.0.dev20250109.dist-info → zenml_nightly-0.71.0.dev20250112.dist-info}/LICENSE +0 -0
  133. {zenml_nightly-0.71.0.dev20250109.dist-info → zenml_nightly-0.71.0.dev20250112.dist-info}/WHEEL +0 -0
  134. {zenml_nightly-0.71.0.dev20250109.dist-info → zenml_nightly-0.71.0.dev20250112.dist-info}/entry_points.txt +0 -0
zenml/VERSION CHANGED
@@ -1 +1 @@
1
- 0.71.0.dev20250109
1
+ 0.71.0.dev20250112
zenml/cli/base.py CHANGED
@@ -87,7 +87,7 @@ ZENML_PROJECT_TEMPLATES = dict(
87
87
  ),
88
88
  nlp=ZenMLProjectTemplateLocation(
89
89
  github_url="zenml-io/template-nlp",
90
- github_tag="2024.11.28", # Make sure it is aligned with .github/workflows/update-templates-to-examples.yml
90
+ github_tag="2025.01.08", # Make sure it is aligned with .github/workflows/update-templates-to-examples.yml
91
91
  ),
92
92
  llm_finetuning=ZenMLProjectTemplateLocation(
93
93
  github_url="zenml-io/template-llm-finetuning",
zenml/cli/formatter.py CHANGED
@@ -173,7 +173,7 @@ class ZenFormatter(formatting.HelpFormatter):
173
173
 
174
174
  for line in lines[1:]:
175
175
  self.write(
176
- f"{'':>{second_col + self.current_indent * 4 }}{line}\n"
176
+ f"{'':>{second_col + self.current_indent * 4}}{line}\n"
177
177
  )
178
178
  else:
179
179
  self.write("\n")
zenml/cli/integration.py CHANGED
@@ -83,7 +83,7 @@ def get_requirements(integration_name: Optional[str] = None) -> None:
83
83
  else:
84
84
  if requirements:
85
85
  title(
86
- f'Requirements for {integration_name or "all integrations"}:\n'
86
+ f"Requirements for {integration_name or 'all integrations'}:\n"
87
87
  )
88
88
  declare(f"{requirements}")
89
89
  warning(
@@ -183,8 +183,7 @@ def register_model_registry_subcommands() -> None: # noqa: C901
183
183
  return
184
184
  if not yes:
185
185
  confirmation = cli_utils.confirmation(
186
- f"Found Model with name {name}. Do you want to "
187
- f"delete them?"
186
+ f"Found Model with name {name}. Do you want to delete them?"
188
187
  )
189
188
  if not confirmation:
190
189
  cli_utils.declare("Model deletion canceled.")
zenml/cli/secret.py CHANGED
@@ -347,8 +347,7 @@ def update_secret(
347
347
  )
348
348
 
349
349
  declare(
350
- "You will now have a chance to update each secret pair "
351
- "one by one."
350
+ "You will now have a chance to update each secret pair one by one."
352
351
  )
353
352
  secret_args_add_update = {}
354
353
  for k, _ in secret.secret_values.items():
@@ -1483,7 +1483,7 @@ def update_service_connector(
1483
1483
  resource_type = None
1484
1484
  title = (
1485
1485
  "The connector is configured to access any of the supported "
1486
- f'resource types ({", ".join(available_resource_types)}). '
1486
+ f"resource types ({', '.join(available_resource_types)}). "
1487
1487
  "Would you like to restrict it to a single resource type?"
1488
1488
  )
1489
1489
  else:
zenml/cli/stack.py CHANGED
@@ -1073,8 +1073,7 @@ def set_active_stack_command(stack_name_or_id: str) -> None:
1073
1073
  cli_utils.error(str(err))
1074
1074
 
1075
1075
  cli_utils.declare(
1076
- f"Active {scope} stack set to: "
1077
- f"'{client.active_stack_model.name}'"
1076
+ f"Active {scope} stack set to: '{client.active_stack_model.name}'"
1078
1077
  )
1079
1078
 
1080
1079
 
@@ -1763,7 +1762,7 @@ def _get_service_connector_info(
1763
1762
  required = ""
1764
1763
  for each_req in schema["required"]:
1765
1764
  field = schema["properties"][each_req]
1766
- required += f"[bold]{each_req}[/bold] [italic]({field.get('title','no description')})[/italic]\n"
1765
+ required += f"[bold]{each_req}[/bold] [italic]({field.get('title', 'no description')})[/italic]\n"
1767
1766
  choices.append([value.name, required])
1768
1767
 
1769
1768
  selected_auth_idx = cli_utils.multi_choice_prompt(
@@ -266,7 +266,7 @@ def generate_stack_component_register_command(
266
266
  client.get_service_connector(connector)
267
267
  except KeyError as err:
268
268
  cli_utils.error(
269
- f"Could not find a connector '{connector}': " f"{str(err)}"
269
+ f"Could not find a connector '{connector}': {str(err)}"
270
270
  )
271
271
 
272
272
  with console.status(f"Registering {display_name} '{name}'...\n"):
@@ -971,8 +971,7 @@ def prompt_select_resource(
971
971
  # Prompt the user to select a connector by its name or ID
972
972
  while True:
973
973
  connector_id = click.prompt(
974
- "Please enter the name or ID of the connector you want "
975
- "to use",
974
+ "Please enter the name or ID of the connector you want to use",
976
975
  type=click.Choice(
977
976
  [
978
977
  str(connector.id)
@@ -1344,8 +1343,7 @@ def connect_stack_component_with_service_connector(
1344
1343
 
1345
1344
  if not connector and not interactive:
1346
1345
  cli_utils.error(
1347
- "Please provide either a connector ID or set the interactive "
1348
- "flag."
1346
+ "Please provide either a connector ID or set the interactive flag."
1349
1347
  )
1350
1348
 
1351
1349
  if connector and interactive:
@@ -1446,7 +1444,7 @@ def connect_stack_component_with_service_connector(
1446
1444
  connector_model = client.get_service_connector(connector)
1447
1445
  except KeyError as err:
1448
1446
  cli_utils.error(
1449
- f"Could not find a connector '{connector}': " f"{str(err)}"
1447
+ f"Could not find a connector '{connector}': {str(err)}"
1450
1448
  )
1451
1449
 
1452
1450
  connector_id = connector_model.id
zenml/cli/text_utils.py CHANGED
@@ -77,7 +77,7 @@ def zenml_go_notebook_tutorial_message(ipynb_files: List[str]) -> Markdown:
77
77
 
78
78
  The ZenML tutorial repository was cloned to your current working directory.
79
79
  Within the repository you can get started on one of these notebooks:
80
- {''.join(ipynb_files)}
80
+ {"".join(ipynb_files)}
81
81
  Next we will start a Jupyter notebook server. Feel free to try your hand at our
82
82
  tutorial notebooks. If your browser does not open automatically click one of the
83
83
  links below.\n
zenml/cli/utils.py CHANGED
@@ -1812,8 +1812,7 @@ def print_service_connector_configuration(
1812
1812
  )
1813
1813
  else:
1814
1814
  declare(
1815
- f"Service connector '{connector.name}' of type "
1816
- f"'{connector.type}'."
1815
+ f"Service connector '{connector.name}' of type '{connector.type}'."
1817
1816
  )
1818
1817
 
1819
1818
  title_ = f"'{connector.name}' {connector.type} Service Connector Details"
@@ -1993,7 +1992,7 @@ def print_service_connector_resource_type(
1993
1992
  message = f"{title}\n" if title else ""
1994
1993
  emoji = replace_emojis(resource_type.emoji) if resource_type.emoji else ""
1995
1994
  supported_auth_methods = [
1996
- f'{Emoji("lock")} {a}' for a in resource_type.auth_methods
1995
+ f"{Emoji('lock')} {a}" for a in resource_type.auth_methods
1997
1996
  ]
1998
1997
  message += (
1999
1998
  f"{heading} {emoji} {resource_type.name} "
@@ -2117,7 +2116,7 @@ def print_service_connector_type(
2117
2116
  """
2118
2117
  message = f"{title}\n" if title else ""
2119
2118
  supported_auth_methods = [
2120
- f'{Emoji("lock")} {a.auth_method}' for a in connector_type.auth_methods
2119
+ f"{Emoji('lock')} {a.auth_method}" for a in connector_type.auth_methods
2121
2120
  ]
2122
2121
  supported_resource_types = [
2123
2122
  f"{replace_emojis(r.emoji)} {r.resource_type}"
@@ -2724,7 +2723,7 @@ def multi_choice_prompt(
2724
2723
  *([f"Create a new {object_type}"] * len(headers)),
2725
2724
  )
2726
2725
  for i, one_choice in enumerate(choices):
2727
- table.add_row(f"[{i+i_shift}]", *[str(x) for x in one_choice])
2726
+ table.add_row(f"[{i + i_shift}]", *[str(x) for x in one_choice])
2728
2727
  Console().print(table)
2729
2728
 
2730
2729
  selected = Prompt.ask(
zenml/client.py CHANGED
@@ -4669,10 +4669,7 @@ class Client(metaclass=ClientMetaClass):
4669
4669
  hydrate=hydrate,
4670
4670
  )
4671
4671
 
4672
- msg = (
4673
- f"No secret found with name, ID or prefix "
4674
- f"'{name_id_or_prefix}'"
4675
- )
4672
+ msg = f"No secret found with name, ID or prefix '{name_id_or_prefix}'"
4676
4673
  if scope is not None:
4677
4674
  msg += f" in scope '{scope}'"
4678
4675
 
zenml/constants.py CHANGED
@@ -429,6 +429,7 @@ PAGE_SIZE_MAXIMUM: int = handle_int_env_var(
429
429
  )
430
430
  FILTERING_DATETIME_FORMAT: str = "%Y-%m-%d %H:%M:%S"
431
431
  SORT_PIPELINES_BY_LATEST_RUN_KEY = "latest_run"
432
+ SORT_BY_LATEST_VERSION_KEY = "latest_version"
432
433
 
433
434
  # Metadata constants
434
435
  METADATA_ORCHESTRATOR_URL = "orchestrator_url"
@@ -13,6 +13,8 @@
13
13
  # permissions and limitations under the License.
14
14
  """Base class for entrypoint configurations that run a single step."""
15
15
 
16
+ import os
17
+ import sys
16
18
  from typing import TYPE_CHECKING, Any, List, Set
17
19
 
18
20
  from zenml.client import Client
@@ -153,10 +155,23 @@ class StepEntrypointConfiguration(BaseEntrypointConfiguration):
153
155
 
154
156
  step_name = self.entrypoint_args[STEP_NAME_OPTION]
155
157
 
158
+ # Change the working directory to make sure we're in the correct
159
+ # directory where the files in the Docker image should be included.
160
+ # This is necessary as some services overwrite the working directory
161
+ # configured in the Docker image itself.
162
+ os.makedirs("/app", exist_ok=True)
163
+ os.chdir("/app")
164
+
156
165
  self.download_code_if_necessary(
157
166
  deployment=deployment, step_name=step_name
158
167
  )
159
168
 
169
+ # If the working directory is not in the sys.path, we include it to make
170
+ # sure user code gets correctly imported.
171
+ cwd = os.getcwd()
172
+ if cwd not in sys.path:
173
+ sys.path.insert(0, cwd)
174
+
160
175
  pipeline_name = deployment.pipeline_configuration.name
161
176
 
162
177
  step = deployment.step_configurations[step_name]
@@ -48,7 +48,7 @@ class AzureIntegration(Integration):
48
48
  "azure-mgmt-containerservice>=20.0.0",
49
49
  "azure-storage-blob==12.17.0", # temporary fix for https://github.com/Azure/azure-sdk-for-python/issues/32056
50
50
  "kubernetes",
51
- "azure-ai-ml==1.18.0",
51
+ "azure-ai-ml==1.23.1",
52
52
  # In azureml/core/_metrics.py:212 of azureml-core 1.56.0, they use
53
53
  # an attribute that was removed in Numpy 2.0. However, AzureML itself
54
54
  # does not have a limitation on numpy.
@@ -159,7 +159,7 @@ def create_or_get_compute(
159
159
  # If the compute target does not exist create it
160
160
  except ResourceNotFoundError:
161
161
  logger.info(
162
- "Can not find the compute target with name: " f"'{compute_name}':"
162
+ f"Can not find the compute target with name: '{compute_name}':"
163
163
  )
164
164
 
165
165
  if settings.mode == AzureMLComputeTypes.COMPUTE_INSTANCE:
@@ -67,11 +67,6 @@ class AzureMLEntrypointConfiguration(StepEntrypointConfiguration):
67
67
  # Set the environmental variables first
68
68
  self._set_env_variables()
69
69
 
70
- # Azure automatically changes the working directory, we have to set it
71
- # back to /app before running the step.
72
- os.makedirs("/app", exist_ok=True)
73
- os.chdir("/app")
74
-
75
70
  # Run the step
76
71
  super().run()
77
72
 
@@ -327,9 +327,9 @@ class BitbucketWebhookEventSourceHandler(BaseWebhookEventSourceHandler):
327
327
  config: Event source configuration instantiated from the response.
328
328
  """
329
329
  assert isinstance(config, BitbucketWebhookEventSourceConfiguration)
330
- assert (
331
- event_source.user is not None
332
- ), "User is not set for event source"
330
+ assert event_source.user is not None, (
331
+ "User is not set for event source"
332
+ )
333
333
 
334
334
  secret_key_value = random_str(12)
335
335
  webhook_secret = SecretRequest(
@@ -495,9 +495,7 @@ class DatabricksOrchestrator(WheeledOrchestrator):
495
495
  Returns:
496
496
  A dictionary of metadata.
497
497
  """
498
- run_url = (
499
- f"{self.config.host}/jobs/" f"{self.get_orchestrator_run_id()}"
500
- )
498
+ run_url = f"{self.config.host}/jobs/{self.get_orchestrator_run_id()}"
501
499
  return {
502
500
  METADATA_ORCHESTRATOR_URL: Uri(run_url),
503
501
  }
@@ -211,7 +211,7 @@ class EvidentlyMetricConfig(BaseModel):
211
211
  else:
212
212
  raise ValueError(f"Invalid Evidently Metric class: {metric}")
213
213
 
214
- class_path = f"{metric_class.__module__}." f"{metric_class.__name__}"
214
+ class_path = f"{metric_class.__module__}.{metric_class.__name__}"
215
215
 
216
216
  config = cls(
217
217
  class_path=class_path,
@@ -291,7 +291,7 @@ class EvidentlyMetricConfig(BaseModel):
291
291
  f"Invalid Evidently Metric or MetricPreset class: {metric}"
292
292
  )
293
293
 
294
- class_path = f"{metric_class.__module__}." f"{metric_class.__name__}"
294
+ class_path = f"{metric_class.__module__}.{metric_class.__name__}"
295
295
 
296
296
  config = cls(class_path=class_path, parameters=parameters)
297
297
 
@@ -205,7 +205,7 @@ class EvidentlyTestConfig(BaseModel):
205
205
  else:
206
206
  raise ValueError(f"Invalid Evidently Test class: {test}")
207
207
 
208
- class_path = f"{test_class.__module__}." f"{test_class.__name__}"
208
+ class_path = f"{test_class.__module__}.{test_class.__name__}"
209
209
 
210
210
  config = cls(
211
211
  class_path=class_path,
@@ -284,7 +284,7 @@ class EvidentlyTestConfig(BaseModel):
284
284
  f"Invalid Evidently Test or TestPreset class: {test}"
285
285
  )
286
286
 
287
- class_path = f"{test_class.__module__}." f"{test_class.__name__}"
287
+ class_path = f"{test_class.__module__}.{test_class.__name__}"
288
288
  config = cls(class_path=class_path, parameters=parameters)
289
289
 
290
290
  # Try to instantiate the configuration to check if the parameters are
@@ -169,7 +169,7 @@ class GCPUserAccountCredentials(AuthenticationConfig):
169
169
  if missing_fields:
170
170
  raise ValueError(
171
171
  f"GCP user account credentials JSON is missing required "
172
- f'fields: {", ".join(list(missing_fields))}'
172
+ f"fields: {', '.join(list(missing_fields))}"
173
173
  )
174
174
 
175
175
  if user_account_info["type"] != "authorized_user":
@@ -276,7 +276,7 @@ class GCPServiceAccountCredentials(AuthenticationConfig):
276
276
  if missing_fields:
277
277
  raise ValueError(
278
278
  f"GCP service account credentials JSON is missing required "
279
- f'fields: {", ".join(list(missing_fields))}'
279
+ f"fields: {', '.join(list(missing_fields))}"
280
280
  )
281
281
 
282
282
  if service_account_info["type"] != "service_account":
@@ -376,7 +376,7 @@ class GCPExternalAccountCredentials(AuthenticationConfig):
376
376
  if missing_fields:
377
377
  raise ValueError(
378
378
  f"GCP external account credentials JSON is missing required "
379
- f'fields: {", ".join(list(missing_fields))}'
379
+ f"fields: {', '.join(list(missing_fields))}"
380
380
  )
381
381
 
382
382
  if external_account_info["type"] != "external_account":
@@ -353,9 +353,9 @@ class GithubWebhookEventSourceHandler(BaseWebhookEventSourceHandler):
353
353
  config: Event source configuration instantiated from the response.
354
354
  """
355
355
  assert isinstance(config, GithubWebhookEventSourceConfiguration)
356
- assert (
357
- event_source.user is not None
358
- ), "User is not set for event source"
356
+ assert event_source.user is not None, (
357
+ "User is not set for event source"
358
+ )
359
359
 
360
360
  secret_key_value = random_str(12)
361
361
  webhook_secret = SecretRequest(
@@ -31,8 +31,7 @@ def split_s3_path(s3_path: str) -> Tuple[str, str]:
31
31
  """
32
32
  if not s3_path.startswith("s3://"):
33
33
  raise ValueError(
34
- f"Invalid S3 URI given: {s3_path}. "
35
- "It should start with `s3://`."
34
+ f"Invalid S3 URI given: {s3_path}. It should start with `s3://`."
36
35
  )
37
36
  path_parts = s3_path.replace("s3://", "").split("/")
38
37
  bucket = path_parts.pop(0)
zenml/logger.py CHANGED
@@ -136,7 +136,7 @@ def set_root_verbosity() -> None:
136
136
 
137
137
  logging.root.setLevel(level=level.value)
138
138
  get_logger(__name__).debug(
139
- f"Logging set to level: " f"{logging.getLevelName(level.value)}"
139
+ f"Logging set to level: {logging.getLevelName(level.value)}"
140
140
  )
141
141
  else:
142
142
  logging.disable(sys.maxsize)
@@ -245,6 +245,8 @@ class UserScopedFilter(BaseFilter):
245
245
  UserSchema, getattr(table, "user_id") == UserSchema.id
246
246
  )
247
247
 
248
+ query = query.add_columns(UserSchema.name)
249
+
248
250
  if operand == SorterOps.ASCENDING:
249
251
  query = query.order_by(asc(column))
250
252
  else:
@@ -449,6 +451,8 @@ class WorkspaceScopedFilter(UserScopedFilter):
449
451
  getattr(table, "workspace_id") == WorkspaceSchema.id,
450
452
  )
451
453
 
454
+ query = query.add_columns(WorkspaceSchema.name)
455
+
452
456
  if operand == SorterOps.ASCENDING:
453
457
  query = query.order_by(asc(column))
454
458
  else:
@@ -470,10 +474,9 @@ class WorkspaceScopedTaggableFilter(WorkspaceScopedFilter):
470
474
  *WorkspaceScopedFilter.FILTER_EXCLUDE_FIELDS,
471
475
  "tag",
472
476
  ]
473
-
474
477
  CUSTOM_SORTING_OPTIONS: ClassVar[List[str]] = [
475
478
  *WorkspaceScopedFilter.CUSTOM_SORTING_OPTIONS,
476
- "tag",
479
+ "tags",
477
480
  ]
478
481
 
479
482
  def apply_filter(
@@ -540,8 +543,8 @@ class WorkspaceScopedTaggableFilter(WorkspaceScopedFilter):
540
543
  """
541
544
  sort_by, operand = self.sorting_params
542
545
 
543
- if sort_by == "tag":
544
- from sqlmodel import and_, asc, desc, func
546
+ if sort_by == "tags":
547
+ from sqlmodel import asc, desc, func, select
545
548
 
546
549
  from zenml.enums import SorterOps, TaggableResourceTypes
547
550
  from zenml.zen_stores.schemas import (
@@ -566,35 +569,36 @@ class WorkspaceScopedTaggableFilter(WorkspaceScopedFilter):
566
569
  RunTemplateSchema: TaggableResourceTypes.RUN_TEMPLATE,
567
570
  }
568
571
 
569
- query = (
570
- query.outerjoin(
571
- TagResourceSchema,
572
- and_(
573
- table.id == TagResourceSchema.resource_id,
574
- TagResourceSchema.resource_type
575
- == resource_type_mapping[table],
576
- ),
572
+ sorted_tags = (
573
+ select(TagResourceSchema.resource_id, TagSchema.name)
574
+ .join(TagSchema, TagResourceSchema.tag_id == TagSchema.id) # type: ignore[arg-type]
575
+ .filter(
576
+ TagResourceSchema.resource_type # type: ignore[arg-type]
577
+ == resource_type_mapping[table]
578
+ )
579
+ .order_by(
580
+ asc(TagResourceSchema.resource_id), asc(TagSchema.name)
577
581
  )
578
- .outerjoin(TagSchema, TagResourceSchema.tag_id == TagSchema.id)
579
- .group_by(table.id)
582
+ ).alias("sorted_tags")
583
+
584
+ tags_subquery = (
585
+ select(
586
+ sorted_tags.c.resource_id,
587
+ func.group_concat(sorted_tags.c.name, ", ").label(
588
+ "tags_list"
589
+ ),
590
+ ).group_by(sorted_tags.c.resource_id)
591
+ ).alias("tags_subquery")
592
+
593
+ query = query.add_columns(tags_subquery.c.tags_list).outerjoin(
594
+ tags_subquery, table.id == tags_subquery.c.resource_id
580
595
  )
581
596
 
597
+ # Apply ordering based on the tags list
582
598
  if operand == SorterOps.ASCENDING:
583
- query = query.order_by(
584
- asc(
585
- func.group_concat(TagSchema.name, ",").label(
586
- "tags_list"
587
- )
588
- )
589
- )
599
+ query = query.order_by(asc("tags_list"))
590
600
  else:
591
- query = query.order_by(
592
- desc(
593
- func.group_concat(TagSchema.name, ",").label(
594
- "tags_list"
595
- )
596
- )
597
- )
601
+ query = query.order_by(desc("tags_list"))
598
602
 
599
603
  return query
600
604
 
@@ -13,12 +13,21 @@
13
13
  # permissions and limitations under the License.
14
14
  """Models representing artifacts."""
15
15
 
16
- from typing import TYPE_CHECKING, Dict, List, Optional
16
+ from typing import (
17
+ TYPE_CHECKING,
18
+ Any,
19
+ ClassVar,
20
+ Dict,
21
+ List,
22
+ Optional,
23
+ Type,
24
+ TypeVar,
25
+ )
17
26
  from uuid import UUID
18
27
 
19
28
  from pydantic import BaseModel, Field
20
29
 
21
- from zenml.constants import STR_FIELD_MAX_LENGTH
30
+ from zenml.constants import SORT_BY_LATEST_VERSION_KEY, STR_FIELD_MAX_LENGTH
22
31
  from zenml.models.v2.base.base import (
23
32
  BaseDatedResponseBody,
24
33
  BaseIdentifiedResponse,
@@ -31,6 +40,11 @@ from zenml.models.v2.core.tag import TagResponse
31
40
 
32
41
  if TYPE_CHECKING:
33
42
  from zenml.models.v2.core.artifact_version import ArtifactVersionResponse
43
+ from zenml.zen_stores.schemas import BaseSchema
44
+
45
+ AnySchema = TypeVar("AnySchema", bound=BaseSchema)
46
+
47
+ AnyQuery = TypeVar("AnyQuery", bound=Any)
34
48
 
35
49
  # ------------------ Request Model ------------------
36
50
 
@@ -174,3 +188,73 @@ class ArtifactFilter(WorkspaceScopedTaggableFilter):
174
188
 
175
189
  name: Optional[str] = None
176
190
  has_custom_name: Optional[bool] = None
191
+
192
+ CUSTOM_SORTING_OPTIONS: ClassVar[List[str]] = [
193
+ *WorkspaceScopedTaggableFilter.CUSTOM_SORTING_OPTIONS,
194
+ SORT_BY_LATEST_VERSION_KEY,
195
+ ]
196
+
197
+ def apply_sorting(
198
+ self,
199
+ query: AnyQuery,
200
+ table: Type["AnySchema"],
201
+ ) -> AnyQuery:
202
+ """Apply sorting to the query for Artifacts.
203
+
204
+ Args:
205
+ query: The query to which to apply the sorting.
206
+ table: The query table.
207
+
208
+ Returns:
209
+ The query with sorting applied.
210
+ """
211
+ from sqlmodel import asc, case, col, desc, func, select
212
+
213
+ from zenml.enums import SorterOps
214
+ from zenml.zen_stores.schemas import (
215
+ ArtifactSchema,
216
+ ArtifactVersionSchema,
217
+ )
218
+
219
+ sort_by, operand = self.sorting_params
220
+
221
+ if sort_by == SORT_BY_LATEST_VERSION_KEY:
222
+ # Subquery to find the latest version per artifact
223
+ latest_version_subquery = (
224
+ select(
225
+ ArtifactSchema.id,
226
+ case(
227
+ (
228
+ func.max(ArtifactVersionSchema.created).is_(None),
229
+ ArtifactSchema.created,
230
+ ),
231
+ else_=func.max(ArtifactVersionSchema.created),
232
+ ).label("latest_version_created"),
233
+ )
234
+ .outerjoin(
235
+ ArtifactVersionSchema,
236
+ ArtifactSchema.id == ArtifactVersionSchema.artifact_id, # type: ignore[arg-type]
237
+ )
238
+ .group_by(col(ArtifactSchema.id))
239
+ .subquery()
240
+ )
241
+
242
+ query = query.add_columns(
243
+ latest_version_subquery.c.latest_version_created,
244
+ ).where(ArtifactSchema.id == latest_version_subquery.c.id)
245
+
246
+ # Apply sorting based on the operand
247
+ if operand == SorterOps.ASCENDING:
248
+ query = query.order_by(
249
+ asc(latest_version_subquery.c.latest_version_created),
250
+ asc(ArtifactSchema.id),
251
+ )
252
+ else:
253
+ query = query.order_by(
254
+ desc(latest_version_subquery.c.latest_version_created),
255
+ desc(ArtifactSchema.id),
256
+ )
257
+ return query
258
+
259
+ # For other sorting cases, delegate to the parent class
260
+ return super().apply_sorting(query=query, table=table)