zenml-nightly 0.83.1.dev20250708__py3-none-any.whl → 0.83.1.dev20250710__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 (43) hide show
  1. zenml/VERSION +1 -1
  2. zenml/cli/login.py +141 -18
  3. zenml/cli/project.py +8 -6
  4. zenml/cli/utils.py +63 -16
  5. zenml/client.py +4 -1
  6. zenml/config/compiler.py +1 -0
  7. zenml/config/retry_config.py +5 -3
  8. zenml/config/step_configurations.py +7 -1
  9. zenml/console.py +4 -1
  10. zenml/constants.py +0 -1
  11. zenml/enums.py +13 -4
  12. zenml/integrations/kubernetes/flavors/kubernetes_orchestrator_flavor.py +58 -4
  13. zenml/integrations/kubernetes/orchestrators/kube_utils.py +172 -0
  14. zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator.py +37 -23
  15. zenml/integrations/kubernetes/orchestrators/kubernetes_orchestrator_entrypoint.py +92 -22
  16. zenml/integrations/kubernetes/orchestrators/manifest_utils.py +59 -0
  17. zenml/logger.py +6 -4
  18. zenml/login/web_login.py +13 -6
  19. zenml/models/v2/core/model_version.py +9 -1
  20. zenml/models/v2/core/pipeline_run.py +1 -0
  21. zenml/models/v2/core/step_run.py +35 -1
  22. zenml/orchestrators/base_orchestrator.py +63 -8
  23. zenml/orchestrators/dag_runner.py +3 -1
  24. zenml/orchestrators/publish_utils.py +4 -1
  25. zenml/orchestrators/step_launcher.py +77 -139
  26. zenml/orchestrators/step_run_utils.py +16 -0
  27. zenml/orchestrators/step_runner.py +1 -4
  28. zenml/pipelines/pipeline_decorator.py +6 -1
  29. zenml/pipelines/pipeline_definition.py +7 -0
  30. zenml/zen_server/auth.py +0 -1
  31. zenml/zen_stores/migrations/versions/360fa84718bf_step_run_versioning.py +64 -0
  32. zenml/zen_stores/migrations/versions/85289fea86ff_adding_source_to_logs.py +1 -1
  33. zenml/zen_stores/schemas/pipeline_deployment_schemas.py +21 -0
  34. zenml/zen_stores/schemas/pipeline_run_schemas.py +31 -2
  35. zenml/zen_stores/schemas/step_run_schemas.py +41 -17
  36. zenml/zen_stores/sql_zen_store.py +152 -32
  37. zenml/zen_stores/template_utils.py +29 -9
  38. zenml_nightly-0.83.1.dev20250710.dist-info/METADATA +499 -0
  39. {zenml_nightly-0.83.1.dev20250708.dist-info → zenml_nightly-0.83.1.dev20250710.dist-info}/RECORD +42 -41
  40. zenml_nightly-0.83.1.dev20250708.dist-info/METADATA +0 -538
  41. {zenml_nightly-0.83.1.dev20250708.dist-info → zenml_nightly-0.83.1.dev20250710.dist-info}/LICENSE +0 -0
  42. {zenml_nightly-0.83.1.dev20250708.dist-info → zenml_nightly-0.83.1.dev20250710.dist-info}/WHEEL +0 -0
  43. {zenml_nightly-0.83.1.dev20250708.dist-info → zenml_nightly-0.83.1.dev20250710.dist-info}/entry_points.txt +0 -0
zenml/VERSION CHANGED
@@ -1 +1 @@
1
- 0.83.1.dev20250708
1
+ 0.83.1.dev20250710
zenml/cli/login.py CHANGED
@@ -22,6 +22,10 @@ from typing import Any, Dict, Optional, Tuple, Union
22
22
  from uuid import UUID
23
23
 
24
24
  import click
25
+ from pydantic import BaseModel
26
+ from rich.panel import Panel
27
+ from rich.prompt import Prompt
28
+ from rich.text import Text
25
29
 
26
30
  from zenml.cli import utils as cli_utils
27
31
  from zenml.cli.cli import cli
@@ -46,6 +50,77 @@ from zenml.utils.server_utils import (
46
50
  logger = get_logger(__name__)
47
51
 
48
52
 
53
+ class LoginMethod(BaseModel):
54
+ """Login method class."""
55
+
56
+ name: str
57
+ description: str
58
+ help: str
59
+
60
+
61
+ possible_login_methods = [
62
+ LoginMethod(
63
+ name="local",
64
+ description="Login to a local server",
65
+ help="(zenml login --local)",
66
+ ),
67
+ LoginMethod(
68
+ name="pro",
69
+ description="Login to ZenML Pro",
70
+ help="(https://cloud.zenml.io)",
71
+ ),
72
+ LoginMethod(
73
+ name="cloud",
74
+ description="Login to a cloud server",
75
+ help="(custom URL)",
76
+ ),
77
+ ]
78
+
79
+
80
+ def _display_login_menu() -> LoginMethod:
81
+ """Display an interactive login menu and return the user's choice.
82
+
83
+ Returns:
84
+ The selected login method enum value.
85
+ """
86
+ title_text = Text("ZenML Login", style="bold cyan")
87
+
88
+ options_text = Text()
89
+ options_text.append("Choose your login method:\n\n", style="dim")
90
+
91
+ for i, login_method in enumerate(possible_login_methods):
92
+ options_text.append(f"{i + 1}. ", style="bold purple")
93
+ options_text.append(
94
+ f"{login_method.description}"
95
+ + " " * (25 - len(login_method.description)),
96
+ style="white",
97
+ )
98
+ options_text.append(f"{login_method.help}", style="dim")
99
+ if i < len(possible_login_methods) - 1:
100
+ options_text.append("\n")
101
+
102
+ panel = Panel(
103
+ options_text,
104
+ title=title_text,
105
+ border_style="white dim",
106
+ padding=(1, 2),
107
+ width=60,
108
+ )
109
+
110
+ console.print(panel)
111
+
112
+ # Get user choice with validation
113
+ while True:
114
+ choice = Prompt.ask(
115
+ "[bold]Enter your choice[/bold]",
116
+ choices=list(
117
+ str(i) for i in range(1, len(possible_login_methods) + 1)
118
+ ),
119
+ default="2",
120
+ )
121
+ return possible_login_methods[int(choice) - 1]
122
+
123
+
49
124
  def start_local_server(
50
125
  docker: bool = False,
51
126
  ip_address: Union[
@@ -424,7 +499,7 @@ def connect_to_pro_server(
424
499
  )
425
500
 
426
501
  cli_utils.declare(
427
- f"Connecting to ZenML Pro server: {server.name} [{str(server.id)}] "
502
+ f"Connecting to ZenML Pro server: '{server.name}' [{str(server.id)}] "
428
503
  )
429
504
 
430
505
  connect_to_server(
@@ -435,7 +510,7 @@ def connect_to_pro_server(
435
510
  # ZenML Pro workspace object.
436
511
  credentials_store.update_server_info(server.url, server)
437
512
 
438
- cli_utils.declare(f"Connected to ZenML Pro server: {server.name}.")
513
+ cli_utils.success(f"Connected to ZenML Pro server: {server.name}.")
439
514
 
440
515
 
441
516
  def is_pro_server(
@@ -523,8 +598,10 @@ def _fail_if_authentication_environment_variables_set() -> None:
523
598
  on the current client state:
524
599
 
525
600
  * if the client is not connected to a non-local ZenML server, the command
526
- will take the user to the ZenML Pro login / signup page to authenticate
527
- and connect to a ZenML Pro server.
601
+ will display an interactive menu with three login options:
602
+ 1. Login to a local server (equivalent to `zenml login --local`)
603
+ 2. Login to ZenML Pro (https://cloud.zenml.io)
604
+ 3. Login to a custom cloud server (you'll be prompted for the URL)
528
605
 
529
606
  * if the client is already connected to a non-local ZenML server, the
530
607
  command triggers a new web login flow with the same server. This allows
@@ -895,20 +972,66 @@ def login(
895
972
  )
896
973
  else:
897
974
  # If no server argument is provided, and the client is not currently
898
- # connected to any non-local server, we default to logging in to ZenML
899
- # Pro.
900
- cli_utils.declare(
901
- "No server argument was provided. Logging to ZenML Pro...\n"
902
- "Hint: You can run 'zenml login --local' to start a local ZenML "
903
- "server and connect to it or 'zenml login <server-url>' to connect "
904
- "to a specific ZenML server. If you wish to login to a ZenML Pro "
905
- "server, you can run 'zenml login --pro'."
906
- )
907
- connect_to_pro_server(
908
- api_key=api_key_value,
909
- pro_api_url=pro_api_url,
910
- verify_ssl=verify_ssl,
911
- )
975
+ # connected to any non-local server, show the interactive login menu.
976
+ login_method = _display_login_menu()
977
+
978
+ if login_method.name == "local":
979
+ # Start a local ZenML server and connect to it
980
+ start_local_server(
981
+ docker=docker,
982
+ ip_address=ip_address,
983
+ port=port,
984
+ blocking=blocking,
985
+ image=image,
986
+ ngrok_token=ngrok_token,
987
+ restart=restart,
988
+ )
989
+ elif login_method.name == "pro":
990
+ # Connect to ZenML Pro
991
+ connect_to_pro_server(
992
+ api_key=api_key_value,
993
+ pro_api_url=pro_api_url,
994
+ verify_ssl=verify_ssl,
995
+ )
996
+ elif login_method.name == "cloud":
997
+ # Get custom server URL from user
998
+ console.print()
999
+ server_url = Prompt.ask(
1000
+ "[bold]Enter the ZenML server URL[/bold]", default="http/https"
1001
+ )
1002
+
1003
+ if not server_url.strip():
1004
+ cli_utils.error("Server URL cannot be empty.")
1005
+ return
1006
+
1007
+ # Validate URL format
1008
+ if not re.match(r"^https?://", server_url):
1009
+ cli_utils.error(
1010
+ "Invalid URL format. Please provide a URL starting with "
1011
+ "http:// or https://"
1012
+ )
1013
+ return
1014
+
1015
+ # Connect to the custom server
1016
+ # First, try to discover if the server is a ZenML Pro server or not
1017
+ server_is_pro, server_pro_api_url = is_pro_server(server_url)
1018
+ if server_is_pro:
1019
+ connect_to_pro_server(
1020
+ pro_server=server_url,
1021
+ api_key=api_key_value,
1022
+ refresh=True, # Force refresh for manually entered URLs
1023
+ # Prefer the pro API URL extracted from the server info if
1024
+ # available
1025
+ pro_api_url=server_pro_api_url or pro_api_url,
1026
+ verify_ssl=verify_ssl,
1027
+ )
1028
+ else:
1029
+ connect_to_server(
1030
+ url=server_url,
1031
+ api_key=api_key_value,
1032
+ verify_ssl=verify_ssl,
1033
+ refresh=True, # Force refresh for manually entered URLs
1034
+ )
912
1035
 
913
1036
 
914
1037
  @cli.command(
zenml/cli/project.py CHANGED
@@ -109,21 +109,23 @@ def register_project(
109
109
  description="",
110
110
  display_name=display_name,
111
111
  )
112
- cli_utils.declare("Project created successfully.")
112
+ cli_utils.success("Project created successfully.")
113
113
  except Exception as e:
114
114
  cli_utils.error(str(e))
115
115
 
116
116
  if set_project:
117
117
  client.set_active_project(project_name)
118
- cli_utils.declare(f"The active project has been set to {project_name}")
118
+ cli_utils.success(
119
+ f"✔ The active project has been set to {project_name}"
120
+ )
119
121
 
120
122
  if set_default:
121
123
  client.update_user(
122
124
  name_id_or_prefix=client.active_user.id,
123
125
  updated_default_project_id=project.id,
124
126
  )
125
- cli_utils.declare(
126
- f"The default project has been set to {project.name}"
127
+ cli_utils.success(
128
+ f"The default project has been set to {project.name}"
127
129
  )
128
130
 
129
131
 
@@ -147,8 +149,8 @@ def set_project(project_name_or_id: str, default: bool = False) -> None:
147
149
  with console.status("Setting project...\n"):
148
150
  try:
149
151
  project = client.set_active_project(project_name_or_id)
150
- cli_utils.declare(
151
- f"The active project has been set to {project_name_or_id}"
152
+ cli_utils.success(
153
+ f"The active project has been set to {project_name_or_id}"
152
154
  )
153
155
  except Exception as e:
154
156
  cli_utils.error(str(e))
zenml/cli/utils.py CHANGED
@@ -22,6 +22,7 @@ import shutil
22
22
  import subprocess
23
23
  import sys
24
24
  from typing import (
25
+ IO,
25
26
  TYPE_CHECKING,
26
27
  AbstractSet,
27
28
  Any,
@@ -162,9 +163,20 @@ def error(text: str) -> NoReturn:
162
163
  text: Input text string.
163
164
 
164
165
  Raises:
165
- ClickException: when called.
166
+ StyledClickException: when called.
166
167
  """
167
- raise click.ClickException(message=click.style(text, fg="red", bold=True))
168
+ error_prefix = click.style("Error: ", fg="red", bold=True)
169
+ error_message = click.style(text, fg="red", bold=False)
170
+
171
+ # Create a custom ClickException that bypasses Click's default "Error: " prefix
172
+ class StyledClickException(click.ClickException):
173
+ def show(self, file: Optional[IO[Any]] = None) -> None:
174
+ if file is None:
175
+ file = click.get_text_stream("stderr")
176
+ # Print our custom styled message directly without Click's prefix
177
+ click.echo(self.message, file=file)
178
+
179
+ raise StyledClickException(message=error_prefix + error_message)
168
180
 
169
181
 
170
182
  def warning(
@@ -186,6 +198,25 @@ def warning(
186
198
  console.print(text, style=style, **kwargs)
187
199
 
188
200
 
201
+ def success(
202
+ text: str,
203
+ bold: Optional[bool] = None,
204
+ italic: Optional[bool] = None,
205
+ **kwargs: Any,
206
+ ) -> None:
207
+ """Echo a success string on the CLI.
208
+
209
+ Args:
210
+ text: Input text string.
211
+ bold: Optional boolean to bold the text.
212
+ italic: Optional boolean to italicize the text.
213
+ **kwargs: Optional kwargs to be passed to console.print().
214
+ """
215
+ base_style = zenml_style_defaults["success"]
216
+ style = Style.chain(base_style, Style(bold=bold, italic=italic))
217
+ console.print(text, style=style, **kwargs)
218
+
219
+
189
220
  def print_markdown(text: str) -> None:
190
221
  """Prints a string as markdown.
191
222
 
@@ -230,7 +261,11 @@ def print_table(
230
261
  column_keys = {key: None for dict_ in obj for key in dict_}
231
262
  column_names = [columns.get(key, key.upper()) for key in column_keys]
232
263
  rich_table = table.Table(
233
- box=box.HEAVY_EDGE, show_lines=True, title=title, caption=caption
264
+ box=box.ROUNDED,
265
+ show_lines=True,
266
+ title=title,
267
+ caption=caption,
268
+ border_style="dim",
234
269
  )
235
270
  for col_name in column_names:
236
271
  if isinstance(col_name, str):
@@ -434,9 +469,10 @@ def print_pydantic_model(
434
469
  columns: Optionally specify subset and order of columns to display.
435
470
  """
436
471
  rich_table = table.Table(
437
- box=box.HEAVY_EDGE,
472
+ box=box.ROUNDED,
438
473
  title=title,
439
474
  show_lines=True,
475
+ border_style="dim",
440
476
  )
441
477
  rich_table.add_column("PROPERTY", overflow="fold")
442
478
  rich_table.add_column("VALUE", overflow="fold")
@@ -552,10 +588,11 @@ def print_stack_configuration(stack: "StackResponse", active: bool) -> None:
552
588
  if active:
553
589
  stack_caption += " (ACTIVE)"
554
590
  rich_table = table.Table(
555
- box=box.HEAVY_EDGE,
591
+ box=box.ROUNDED,
556
592
  title="Stack Configuration",
557
593
  caption=stack_caption,
558
594
  show_lines=True,
595
+ border_style="dim",
559
596
  )
560
597
  rich_table.add_column("COMPONENT_TYPE", overflow="fold")
561
598
  rich_table.add_column("COMPONENT_NAME", overflow="fold")
@@ -573,9 +610,10 @@ def print_stack_configuration(stack: "StackResponse", active: bool) -> None:
573
610
  declare("No labels are set for this stack.")
574
611
  else:
575
612
  rich_table = table.Table(
576
- box=box.HEAVY_EDGE,
613
+ box=box.ROUNDED,
577
614
  title="Labels",
578
615
  show_lines=True,
616
+ border_style="dim",
579
617
  )
580
618
  rich_table.add_column("LABEL")
581
619
  rich_table.add_column("VALUE", overflow="fold")
@@ -649,9 +687,10 @@ def print_stack_component_configuration(
649
687
  if active_status:
650
688
  title_ += " (ACTIVE)"
651
689
  rich_table = table.Table(
652
- box=box.HEAVY_EDGE,
690
+ box=box.ROUNDED,
653
691
  title=title_,
654
692
  show_lines=True,
693
+ border_style="dim",
655
694
  )
656
695
  rich_table.add_column("COMPONENT_PROPERTY")
657
696
  rich_table.add_column("VALUE", overflow="fold")
@@ -672,9 +711,10 @@ def print_stack_component_configuration(
672
711
  declare("No labels are set for this component.")
673
712
  else:
674
713
  rich_table = table.Table(
675
- box=box.HEAVY_EDGE,
714
+ box=box.ROUNDED,
676
715
  title="Labels",
677
716
  show_lines=True,
717
+ border_style="dim",
678
718
  )
679
719
  rich_table.add_column("LABEL")
680
720
  rich_table.add_column("VALUE", overflow="fold")
@@ -688,9 +728,10 @@ def print_stack_component_configuration(
688
728
  declare("No connector is set for this component.")
689
729
  else:
690
730
  rich_table = table.Table(
691
- box=box.HEAVY_EDGE,
731
+ box=box.ROUNDED,
692
732
  title="Service Connector",
693
733
  show_lines=True,
734
+ border_style="dim",
694
735
  )
695
736
  rich_table.add_column("PROPERTY")
696
737
  rich_table.add_column("VALUE", overflow="fold")
@@ -1165,8 +1206,9 @@ def print_list_items(list_items: List[str], column_title: str) -> None:
1165
1206
  column_title: Title of the column
1166
1207
  """
1167
1208
  rich_table = table.Table(
1168
- box=box.HEAVY_EDGE,
1209
+ box=box.ROUNDED,
1169
1210
  show_lines=True,
1211
+ border_style="dim",
1170
1212
  )
1171
1213
  rich_table.add_column(column_title.upper(), overflow="fold")
1172
1214
  list_items.sort()
@@ -1291,9 +1333,10 @@ def pretty_print_model_version_details(
1291
1333
  title_ = f"Properties of model `{model_version.registered_model.name}` version `{model_version.version}`"
1292
1334
 
1293
1335
  rich_table = table.Table(
1294
- box=box.HEAVY_EDGE,
1336
+ box=box.ROUNDED,
1295
1337
  title=title_,
1296
1338
  show_lines=True,
1339
+ border_style="dim",
1297
1340
  )
1298
1341
  rich_table.add_column("MODEL VERSION PROPERTY", overflow="fold")
1299
1342
  rich_table.add_column("VALUE", overflow="fold")
@@ -1343,9 +1386,10 @@ def print_served_model_configuration(
1343
1386
  title_ = f"Properties of Served Model {model_service.uuid}"
1344
1387
 
1345
1388
  rich_table = table.Table(
1346
- box=box.HEAVY_EDGE,
1389
+ box=box.ROUNDED,
1347
1390
  title=title_,
1348
1391
  show_lines=True,
1392
+ border_style="dim",
1349
1393
  )
1350
1394
  rich_table.add_column("MODEL SERVICE PROPERTY", overflow="fold")
1351
1395
  rich_table.add_column("VALUE", overflow="fold")
@@ -1745,9 +1789,10 @@ def print_service_connector_configuration(
1745
1789
  if active_status:
1746
1790
  title_ += " (ACTIVE)"
1747
1791
  rich_table = table.Table(
1748
- box=box.HEAVY_EDGE,
1792
+ box=box.ROUNDED,
1749
1793
  title=title_,
1750
1794
  show_lines=True,
1795
+ border_style="dim",
1751
1796
  )
1752
1797
  rich_table.add_column("PROPERTY")
1753
1798
  rich_table.add_column("VALUE", overflow="fold")
@@ -1819,9 +1864,10 @@ def print_service_connector_configuration(
1819
1864
 
1820
1865
  else:
1821
1866
  rich_table = table.Table(
1822
- box=box.HEAVY_EDGE,
1867
+ box=box.ROUNDED,
1823
1868
  title="Configuration",
1824
1869
  show_lines=True,
1870
+ border_style="dim",
1825
1871
  )
1826
1872
  rich_table.add_column("PROPERTY")
1827
1873
  rich_table.add_column("VALUE", overflow="fold")
@@ -1847,9 +1893,10 @@ def print_service_connector_configuration(
1847
1893
  return
1848
1894
 
1849
1895
  rich_table = table.Table(
1850
- box=box.HEAVY_EDGE,
1896
+ box=box.ROUNDED,
1851
1897
  title="Labels",
1852
1898
  show_lines=True,
1899
+ border_style="dim",
1853
1900
  )
1854
1901
  rich_table.add_column("LABEL")
1855
1902
  rich_table.add_column("VALUE", overflow="fold")
@@ -2609,7 +2656,7 @@ def multi_choice_prompt(
2609
2656
  table = Table(
2610
2657
  title=f"Available {object_type}",
2611
2658
  show_header=True,
2612
- border_style=None,
2659
+ border_style="dim",
2613
2660
  expand=True,
2614
2661
  show_lines=True,
2615
2662
  )
zenml/client.py CHANGED
@@ -4051,6 +4051,7 @@ class Client(metaclass=ClientMetaClass):
4051
4051
  model_version_id: Optional[Union[str, UUID]] = None,
4052
4052
  model: Optional[Union[UUID, str]] = None,
4053
4053
  run_metadata: Optional[List[str]] = None,
4054
+ exclude_retried: Optional[bool] = None,
4054
4055
  hydrate: bool = False,
4055
4056
  ) -> Page[StepRunResponse]:
4056
4057
  """List all pipelines.
@@ -4077,6 +4078,7 @@ class Client(metaclass=ClientMetaClass):
4077
4078
  code_hash: The code hash of the step run to filter by.
4078
4079
  status: The name of the run to filter by.
4079
4080
  run_metadata: Filter by run metadata.
4081
+ exclude_retried: Whether to exclude retried step runs.
4080
4082
  hydrate: Flag deciding whether to hydrate the output model(s)
4081
4083
  by including metadata fields in the response.
4082
4084
 
@@ -4105,6 +4107,7 @@ class Client(metaclass=ClientMetaClass):
4105
4107
  model_version_id=model_version_id,
4106
4108
  model=model,
4107
4109
  run_metadata=run_metadata,
4110
+ exclude_retried=exclude_retried,
4108
4111
  )
4109
4112
  return self.zen_store.list_run_steps(
4110
4113
  step_run_filter_model=step_run_filter_model,
@@ -4352,7 +4355,7 @@ class Client(metaclass=ClientMetaClass):
4352
4355
  version: Optional[Union[str, int]] = None,
4353
4356
  version_number: Optional[int] = None,
4354
4357
  artifact_store_id: Optional[Union[str, UUID]] = None,
4355
- type: Optional[ArtifactType] = None,
4358
+ type: Optional[Union[ArtifactType, str]] = None,
4356
4359
  data_type: Optional[str] = None,
4357
4360
  uri: Optional[str] = None,
4358
4361
  materializer: Optional[str] = None,
zenml/config/compiler.py CHANGED
@@ -206,6 +206,7 @@ class Compiler:
206
206
  tags=config.tags,
207
207
  extra=config.extra,
208
208
  model=config.model,
209
+ retry=config.retry,
209
210
  parameters=config.parameters,
210
211
  )
211
212
 
@@ -13,6 +13,8 @@
13
13
  # permissions and limitations under the License.
14
14
  """Retry configuration for a step."""
15
15
 
16
+ from pydantic import NonNegativeInt, PositiveInt
17
+
16
18
  from zenml.config.strict_base_model import StrictBaseModel
17
19
 
18
20
 
@@ -22,6 +24,6 @@ class StepRetryConfig(StrictBaseModel):
22
24
  Delay is an integer (specified in seconds).
23
25
  """
24
26
 
25
- max_retries: int = 1
26
- delay: int = 0 # in seconds
27
- backoff: int = 0
27
+ max_retries: PositiveInt = 1
28
+ delay: NonNegativeInt = 0 # in seconds
29
+ backoff: NonNegativeInt = 0
@@ -289,6 +289,7 @@ class StepConfiguration(PartialStepConfiguration):
289
289
  "extra",
290
290
  "failure_hook_source",
291
291
  "success_hook_source",
292
+ "retry",
292
293
  "substitutions",
293
294
  },
294
295
  exclude_none=True,
@@ -300,12 +301,17 @@ class StepConfiguration(PartialStepConfiguration):
300
301
  "extra",
301
302
  "failure_hook_source",
302
303
  "success_hook_source",
304
+ "retry",
303
305
  "substitutions",
304
306
  },
305
307
  exclude_none=True,
306
308
  )
307
309
 
308
- updated_config = self.model_copy(update=pipeline_values, deep=True)
310
+ updated_config_dict = {
311
+ **self.model_dump(),
312
+ **pipeline_values,
313
+ }
314
+ updated_config = self.model_validate(updated_config_dict)
309
315
  return update_model(updated_config, original_values)
310
316
  else:
311
317
  return self.model_copy(deep=True)
zenml/console.py CHANGED
@@ -18,11 +18,14 @@ from rich.style import Style
18
18
  from rich.theme import Theme
19
19
 
20
20
  zenml_style_defaults = {
21
- "info": Style(color="cyan", dim=True),
21
+ "info": Style(color="white", dim=True),
22
22
  "warning": Style(color="yellow"),
23
23
  "danger": Style(color="red", bold=True),
24
24
  "title": Style(color="cyan", bold=True, underline=True),
25
25
  "error": Style(color="red"),
26
+ "success": Style(color="green"),
27
+ "repr.str": Style(color="white", dim=False),
28
+ "repr.uuid": Style(color="magenta", dim=False),
26
29
  }
27
30
 
28
31
  zenml_custom_theme = Theme(zenml_style_defaults)
zenml/constants.py CHANGED
@@ -171,7 +171,6 @@ ENV_ZENML_ENABLE_IMPLICIT_AUTH_METHODS = "ZENML_ENABLE_IMPLICIT_AUTH_METHODS"
171
171
  ENV_ZENML_DISABLE_PIPELINE_LOGS_STORAGE = "ZENML_DISABLE_PIPELINE_LOGS_STORAGE"
172
172
  ENV_ZENML_DISABLE_STEP_LOGS_STORAGE = "ZENML_DISABLE_STEP_LOGS_STORAGE"
173
173
  ENV_ZENML_DISABLE_STEP_NAMES_IN_LOGS = "ZENML_DISABLE_STEP_NAMES_IN_LOGS"
174
- ENV_ZENML_IGNORE_FAILURE_HOOK = "ZENML_IGNORE_FAILURE_HOOK"
175
174
  ENV_ZENML_CUSTOM_SOURCE_ROOT = "ZENML_CUSTOM_SOURCE_ROOT"
176
175
  ENV_ZENML_PIPELINE_RUN_API_TOKEN_EXPIRATION = (
177
176
  "ZENML_PIPELINE_API_TOKEN_EXPIRATION"
zenml/enums.py CHANGED
@@ -78,6 +78,8 @@ class ExecutionStatus(StrEnum):
78
78
  COMPLETED = "completed"
79
79
  RUNNING = "running"
80
80
  CACHED = "cached"
81
+ RETRYING = "retrying"
82
+ RETRIED = "retried"
81
83
  STOPPED = "stopped"
82
84
  STOPPING = "stopping"
83
85
 
@@ -92,9 +94,19 @@ class ExecutionStatus(StrEnum):
92
94
  ExecutionStatus.FAILED,
93
95
  ExecutionStatus.COMPLETED,
94
96
  ExecutionStatus.CACHED,
97
+ ExecutionStatus.RETRIED,
95
98
  ExecutionStatus.STOPPED,
96
99
  }
97
100
 
101
+ @property
102
+ def is_successful(self) -> bool:
103
+ """Whether the execution status refers to a successful execution.
104
+
105
+ Returns:
106
+ Whether the execution status refers to a successful execution.
107
+ """
108
+ return self in {ExecutionStatus.COMPLETED, ExecutionStatus.CACHED}
109
+
98
110
 
99
111
  class LoggingLevels(Enum):
100
112
  """Enum for logging levels."""
@@ -411,9 +423,6 @@ class OnboardingStep(StrEnum):
411
423
  DEVICE_VERIFIED = "device_verified"
412
424
  PROJECT_CREATED = "project_created"
413
425
  PIPELINE_RUN = "pipeline_run"
414
- SECOND_PIPELINE_RUN = "second_pipeline_run"
415
- THIRD_PIPELINE_RUN = "third_pipeline_run"
416
- STARTER_SETUP_COMPLETED = "starter_setup_completed"
417
426
  STACK_WITH_REMOTE_ORCHESTRATOR_CREATED = (
418
427
  "stack_with_remote_orchestrator_created"
419
428
  )
@@ -426,7 +435,7 @@ class OnboardingStep(StrEnum):
426
435
  PIPELINE_RUN_WITH_REMOTE_ARTIFACT_STORE = (
427
436
  "pipeline_run_with_remote_artifact_store"
428
437
  )
429
- PRODUCTION_SETUP_COMPLETED = "production_setup_completed"
438
+ OSS_ONBOARDING_COMPLETED = "oss_onboarding_completed"
430
439
  PRO_ONBOARDING_COMPLETED = "pro_onboarding_completed"
431
440
 
432
441