nextmv 1.0.0__py3-none-any.whl → 1.0.0.dev0__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 (140) hide show
  1. nextmv/__about__.py +1 -1
  2. nextmv/__entrypoint__.py +2 -1
  3. nextmv/__init__.py +4 -0
  4. nextmv/cli/CONTRIBUTING.md +40 -112
  5. nextmv/cli/cloud/__init__.py +0 -4
  6. nextmv/cli/cloud/acceptance/create.py +22 -20
  7. nextmv/cli/cloud/acceptance/delete.py +12 -8
  8. nextmv/cli/cloud/acceptance/get.py +10 -9
  9. nextmv/cli/cloud/acceptance/list.py +3 -3
  10. nextmv/cli/cloud/acceptance/update.py +6 -6
  11. nextmv/cli/cloud/account/__init__.py +3 -3
  12. nextmv/cli/cloud/account/create.py +11 -11
  13. nextmv/cli/cloud/account/delete.py +8 -7
  14. nextmv/cli/cloud/account/get.py +3 -3
  15. nextmv/cli/cloud/account/update.py +5 -5
  16. nextmv/cli/cloud/app/create.py +26 -25
  17. nextmv/cli/cloud/app/delete.py +7 -6
  18. nextmv/cli/cloud/app/exists.py +2 -2
  19. nextmv/cli/cloud/app/get.py +2 -2
  20. nextmv/cli/cloud/app/list.py +3 -3
  21. nextmv/cli/cloud/app/push.py +54 -349
  22. nextmv/cli/cloud/app/update.py +12 -12
  23. nextmv/cli/cloud/batch/create.py +28 -26
  24. nextmv/cli/cloud/batch/delete.py +10 -6
  25. nextmv/cli/cloud/batch/get.py +9 -9
  26. nextmv/cli/cloud/batch/list.py +3 -3
  27. nextmv/cli/cloud/batch/metadata.py +4 -4
  28. nextmv/cli/cloud/batch/update.py +6 -6
  29. nextmv/cli/cloud/data/__init__.py +1 -1
  30. nextmv/cli/cloud/data/upload.py +15 -15
  31. nextmv/cli/cloud/ensemble/__init__.py +0 -2
  32. nextmv/cli/cloud/ensemble/create.py +22 -21
  33. nextmv/cli/cloud/ensemble/delete.py +10 -6
  34. nextmv/cli/cloud/ensemble/get.py +4 -4
  35. nextmv/cli/cloud/ensemble/update.py +9 -9
  36. nextmv/cli/cloud/input_set/__init__.py +0 -2
  37. nextmv/cli/cloud/input_set/create.py +22 -22
  38. nextmv/cli/cloud/input_set/get.py +3 -3
  39. nextmv/cli/cloud/input_set/list.py +3 -3
  40. nextmv/cli/cloud/input_set/update.py +24 -24
  41. nextmv/cli/cloud/instance/create.py +15 -14
  42. nextmv/cli/cloud/instance/delete.py +7 -6
  43. nextmv/cli/cloud/instance/exists.py +2 -2
  44. nextmv/cli/cloud/instance/get.py +2 -2
  45. nextmv/cli/cloud/instance/list.py +3 -3
  46. nextmv/cli/cloud/instance/update.py +14 -14
  47. nextmv/cli/cloud/managed_input/create.py +16 -14
  48. nextmv/cli/cloud/managed_input/delete.py +8 -7
  49. nextmv/cli/cloud/managed_input/get.py +3 -3
  50. nextmv/cli/cloud/managed_input/list.py +3 -3
  51. nextmv/cli/cloud/managed_input/update.py +9 -9
  52. nextmv/cli/cloud/run/cancel.py +2 -2
  53. nextmv/cli/cloud/run/create.py +40 -34
  54. nextmv/cli/cloud/run/get.py +8 -8
  55. nextmv/cli/cloud/run/input.py +4 -4
  56. nextmv/cli/cloud/run/list.py +6 -6
  57. nextmv/cli/cloud/run/logs.py +10 -9
  58. nextmv/cli/cloud/run/metadata.py +4 -4
  59. nextmv/cli/cloud/run/track.py +33 -32
  60. nextmv/cli/cloud/scenario/create.py +21 -21
  61. nextmv/cli/cloud/scenario/delete.py +10 -6
  62. nextmv/cli/cloud/scenario/get.py +9 -9
  63. nextmv/cli/cloud/scenario/list.py +3 -3
  64. nextmv/cli/cloud/scenario/metadata.py +4 -4
  65. nextmv/cli/cloud/scenario/update.py +6 -6
  66. nextmv/cli/cloud/secrets/create.py +17 -17
  67. nextmv/cli/cloud/secrets/delete.py +10 -6
  68. nextmv/cli/cloud/secrets/get.py +4 -4
  69. nextmv/cli/cloud/secrets/list.py +3 -3
  70. nextmv/cli/cloud/secrets/update.py +20 -17
  71. nextmv/cli/cloud/upload/create.py +2 -2
  72. nextmv/cli/cloud/version/create.py +10 -9
  73. nextmv/cli/cloud/version/delete.py +7 -6
  74. nextmv/cli/cloud/version/exists.py +2 -2
  75. nextmv/cli/cloud/version/get.py +2 -2
  76. nextmv/cli/cloud/version/list.py +3 -3
  77. nextmv/cli/cloud/version/update.py +8 -8
  78. nextmv/cli/community/__init__.py +1 -1
  79. nextmv/cli/community/clone.py +204 -20
  80. nextmv/cli/community/list.py +125 -60
  81. nextmv/cli/configuration/config.py +10 -43
  82. nextmv/cli/configuration/create.py +7 -7
  83. nextmv/cli/configuration/delete.py +8 -8
  84. nextmv/cli/configuration/list.py +3 -3
  85. nextmv/cli/main.py +36 -26
  86. nextmv/cli/message.py +54 -71
  87. nextmv/cli/options.py +0 -28
  88. nextmv/cli/version.py +1 -1
  89. nextmv/cloud/__init__.py +38 -14
  90. nextmv/cloud/acceptance_test.py +65 -1
  91. nextmv/cloud/account.py +6 -1
  92. nextmv/cloud/application/__init__.py +75 -18
  93. nextmv/cloud/application/_acceptance.py +8 -13
  94. nextmv/cloud/application/_batch_scenario.py +19 -4
  95. nextmv/cloud/application/_input_set.py +6 -42
  96. nextmv/cloud/application/_instance.py +3 -3
  97. nextmv/cloud/application/_managed_input.py +2 -2
  98. nextmv/cloud/application/_version.py +3 -4
  99. nextmv/cloud/batch_experiment.py +1 -3
  100. nextmv/cloud/integration.py +4 -7
  101. nextmv/deprecated.py +3 -5
  102. nextmv/input.py +52 -0
  103. nextmv/local/runner.py +1 -1
  104. nextmv/model.py +11 -50
  105. nextmv/options.py +256 -11
  106. nextmv/output.py +62 -0
  107. nextmv/run.py +10 -1
  108. nextmv/status.py +51 -1
  109. {nextmv-1.0.0.dist-info → nextmv-1.0.0.dev0.dist-info}/METADATA +4 -5
  110. nextmv-1.0.0.dev0.dist-info/RECORD +158 -0
  111. nextmv/cli/cloud/ensemble/list.py +0 -63
  112. nextmv/cli/cloud/input_set/delete.py +0 -64
  113. nextmv/cli/cloud/shadow/__init__.py +0 -33
  114. nextmv/cli/cloud/shadow/create.py +0 -184
  115. nextmv/cli/cloud/shadow/delete.py +0 -64
  116. nextmv/cli/cloud/shadow/get.py +0 -61
  117. nextmv/cli/cloud/shadow/list.py +0 -63
  118. nextmv/cli/cloud/shadow/metadata.py +0 -66
  119. nextmv/cli/cloud/shadow/start.py +0 -43
  120. nextmv/cli/cloud/shadow/stop.py +0 -53
  121. nextmv/cli/cloud/shadow/update.py +0 -96
  122. nextmv/cli/cloud/switchback/__init__.py +0 -33
  123. nextmv/cli/cloud/switchback/create.py +0 -151
  124. nextmv/cli/cloud/switchback/delete.py +0 -64
  125. nextmv/cli/cloud/switchback/get.py +0 -62
  126. nextmv/cli/cloud/switchback/list.py +0 -63
  127. nextmv/cli/cloud/switchback/metadata.py +0 -68
  128. nextmv/cli/cloud/switchback/start.py +0 -43
  129. nextmv/cli/cloud/switchback/stop.py +0 -53
  130. nextmv/cli/cloud/switchback/update.py +0 -96
  131. nextmv/cli/confirm.py +0 -34
  132. nextmv/cloud/application/_shadow.py +0 -320
  133. nextmv/cloud/application/_switchback.py +0 -332
  134. nextmv/cloud/community.py +0 -446
  135. nextmv/cloud/shadow.py +0 -254
  136. nextmv/cloud/switchback.py +0 -228
  137. nextmv-1.0.0.dist-info/RECORD +0 -185
  138. nextmv-1.0.0.dist-info/entry_points.txt +0 -2
  139. {nextmv-1.0.0.dist-info → nextmv-1.0.0.dev0.dist-info}/WHEEL +0 -0
  140. {nextmv-1.0.0.dist-info → nextmv-1.0.0.dev0.dist-info}/licenses/LICENSE +0 -0
@@ -14,7 +14,7 @@ from nextmv.cli.configuration.config import (
14
14
  obscure_api_key,
15
15
  save_config,
16
16
  )
17
- from nextmv.cli.message import error, message, success
17
+ from nextmv.cli.message import error, info, success
18
18
 
19
19
  # Set up subcommand application.
20
20
  app = typer.Typer()
@@ -58,14 +58,14 @@ def create(
58
58
  [bold][underline]Examples[/underline][/bold]
59
59
 
60
60
  - Default configuration.
61
- $ [dim]nextmv configuration create --api-key NEXTMV_API_KEY[/dim]
61
+ $ [green]nextmv configuration create --api-key NEXTMV_API_KEY[/green]
62
62
 
63
63
  - Configure a profile named [magenta]hare[/magenta].
64
- $ [dim]nextmv configuration create --api-key NEXTMV_API_KEY --profile hare[/dim]
64
+ $ [green]nextmv configuration create --api-key NEXTMV_API_KEY --profile hare[/green]
65
65
  """
66
66
 
67
67
  if profile is not None and profile.strip().lower() == "default":
68
- error("[magenta]default[/magenta] is a reserved profile name.")
68
+ error("[code]default[/code] is a reserved profile name.")
69
69
 
70
70
  endpoint = str(endpoint)
71
71
  if endpoint.startswith("https://"):
@@ -88,7 +88,7 @@ def create(
88
88
  save_config(config)
89
89
 
90
90
  success("Configuration saved successfully.")
91
- message(f"\t[bold]Profile[/bold]: [magenta]{profile or 'Default'}[/magenta]")
92
- message(f"\t[bold]API Key[/bold]: [magenta]{obscure_api_key(api_key)}[/magenta]")
91
+ info(f"\t[bold]Profile[/bold]: {profile or 'Default'}")
92
+ info(f"\t[bold]API Key[/bold]: {obscure_api_key(api_key)}")
93
93
  if endpoint != DEFAULT_ENDPOINT:
94
- message(f"\t[bold]Endpoint[/bold]: [magenta]{endpoint}[/magenta]")
94
+ info(f"\t[bold]Endpoint[/bold]: {endpoint}")
@@ -5,9 +5,9 @@ This module defines the configuration delete command for the Nextmv CLI.
5
5
  from typing import Annotated
6
6
 
7
7
  import typer
8
+ from rich.prompt import Confirm
8
9
 
9
10
  from nextmv.cli.configuration.config import load_config, save_config
10
- from nextmv.cli.confirm import get_confirmation
11
11
  from nextmv.cli.message import error, info, success
12
12
 
13
13
  # Set up subcommand application.
@@ -36,29 +36,29 @@ def delete(
36
36
  ] = False,
37
37
  ) -> None:
38
38
  """
39
- Delete a profile from the configuration.
40
-
41
- Use the --yes flag to skip the confirmation prompt.
39
+ Delete a profile from the configuration. Use the [code]--yes[/code]
40
+ flag to skip the confirmation prompt.
42
41
 
43
42
  [bold][underline]Examples[/underline][/bold]
44
43
 
45
44
  - Delete a profile named [magenta]hare[/magenta].
46
- $ [dim]nextmv configuration delete --profile hare[/dim]
45
+ $ [green]nextmv configuration delete --profile hare[/green]
47
46
 
48
47
  - Delete a profile named [magenta]hare[/magenta] without confirmation prompt.
49
- $ [dim]nextmv configuration delete --profile hare --yes[/dim]
48
+ $ [green]nextmv configuration delete --profile hare --yes[/green]
50
49
  """
51
50
  config = load_config()
52
51
  if profile not in config:
53
52
  error(f"Profile [magenta]{profile}[/magenta] does not exist.")
54
53
 
55
54
  if not yes:
56
- confirm = get_confirmation(
55
+ confirm = Confirm.ask(
57
56
  f"Are you sure you want to delete profile [magenta]{profile}[/magenta]? This action cannot be undone.",
57
+ default=False,
58
58
  )
59
59
 
60
60
  if not confirm:
61
- info(f"Profile [magenta]{profile}[/magenta] will not be deleted.")
61
+ info(msg=f"Profile [magenta]{profile}[/magenta] will not be deleted.", emoji=":bulb:")
62
62
  return
63
63
 
64
64
  del config[profile]
@@ -6,7 +6,7 @@ import typer
6
6
  from rich.console import Console
7
7
  from rich.table import Table
8
8
 
9
- from nextmv.cli.configuration.config import API_KEY_KEY, ENDPOINT_KEY, load_config, non_profile_keys, obscure_api_key
9
+ from nextmv.cli.configuration.config import API_KEY_KEY, ENDPOINT_KEY, load_config, obscure_api_key
10
10
  from nextmv.cli.message import error
11
11
 
12
12
  # Set up subcommand application.
@@ -22,7 +22,7 @@ def list() -> None:
22
22
  [bold][underline]Examples[/underline][/bold]
23
23
 
24
24
  - Show current configuration and all profiles.
25
- $ [dim]nextmv configuration list[/dim]
25
+ $ [green]nextmv configuration list[/green]
26
26
  """
27
27
 
28
28
  config = load_config()
@@ -38,7 +38,7 @@ def list() -> None:
38
38
 
39
39
  for k, v in config.items():
40
40
  # Skip default configuration.
41
- if k in non_profile_keys():
41
+ if k in {API_KEY_KEY, ENDPOINT_KEY}:
42
42
  continue
43
43
 
44
44
  profile = {
nextmv/cli/main.py CHANGED
@@ -13,25 +13,22 @@ about the features used here. An example of Rich markup can be found in the
13
13
  epilog of the Typer application defined below.
14
14
  """
15
15
 
16
+ import os
16
17
  import sys
17
18
  from typing import Annotated
18
19
 
19
20
  import rich
20
21
  import typer
21
- from typer import rich_utils
22
+ from rich.prompt import Confirm
22
23
 
23
24
  from nextmv.cli.cloud import app as cloud_app
24
25
  from nextmv.cli.community import app as community_app
25
26
  from nextmv.cli.configuration import app as configuration_app
26
27
  from nextmv.cli.configuration.config import CONFIG_DIR, GO_CLI_PATH, load_config
27
- from nextmv.cli.confirm import get_confirmation
28
28
  from nextmv.cli.message import error, info, success, warning
29
29
  from nextmv.cli.version import app as version_app
30
30
  from nextmv.cli.version import version_callback
31
31
 
32
- # Disable dim text for the extended help of commands.
33
- rich_utils.STYLE_HELPTEXT = ""
34
-
35
32
  # Main CLI application.
36
33
  app = typer.Typer(
37
34
  help="The Nextmv Command Line Interface (CLI).",
@@ -69,15 +66,6 @@ def callback(
69
66
  environment.
70
67
  """
71
68
 
72
- # Skip checks for help commands.
73
- if "--help" in sys.argv or "-h" in sys.argv:
74
- return
75
-
76
- # Skip checks for certain commands.
77
- ignored_commands = {"configuration", "version"}
78
- if ctx.invoked_subcommand in ignored_commands:
79
- return
80
-
81
69
  handle_go_cli()
82
70
  handle_config_existence(ctx)
83
71
 
@@ -92,20 +80,19 @@ def handle_go_cli() -> None:
92
80
 
93
81
  exists = go_cli_exists()
94
82
  if exists:
95
- delete = get_confirmation(
83
+ delete = Confirm.ask(
96
84
  "Do you want to delete the [italic red]deprecated[/italic red] Nextmv CLI "
97
- f"at [magenta]{GO_CLI_PATH}[/magenta] now?"
85
+ f"at [magenta]{GO_CLI_PATH}[/magenta] now?",
86
+ default=False,
98
87
  )
99
88
  if delete:
100
89
  remove_go_cli()
101
- return
102
-
103
- info(
104
- "You can delete the [italic red]deprecated[/italic red] Nextmv CLI later by removing "
105
- f"[magenta]{GO_CLI_PATH}[/magenta]. "
106
- "Make sure you also clean up your [code]PATH[/code], "
107
- f"by removing references to [magenta]{CONFIG_DIR}[/magenta] from it."
108
- )
90
+ else:
91
+ info(
92
+ msg="You can delete the [italic red]deprecated[/italic red] Nextmv CLI later by removing "
93
+ f"[magenta]{GO_CLI_PATH}[/magenta]. Make sure you also clean up your [code]PATH[/code].",
94
+ emoji=":bulb:",
95
+ )
109
96
 
110
97
 
111
98
  def handle_config_existence(ctx: typer.Context) -> None:
@@ -118,6 +105,10 @@ def handle_config_existence(ctx: typer.Context) -> None:
118
105
  The Typer context object.
119
106
  """
120
107
 
108
+ ignored_commands = {"configuration", "version"}
109
+ if ctx.invoked_subcommand in ignored_commands:
110
+ return
111
+
121
112
  config = load_config()
122
113
  if config == {}:
123
114
  error("No configuration found. Please run [code]nextmv configuration create[/code].")
@@ -139,9 +130,11 @@ def go_cli_exists() -> bool:
139
130
  if exists:
140
131
  warning(
141
132
  "A [italic red]deprecated[/italic red] Nextmv CLI is installed at "
142
- f"[magenta]{GO_CLI_PATH}[/magenta]. You should delete it to avoid conflicts."
133
+ f"[magenta]{GO_CLI_PATH}[/magenta]. You must delete it to avoid conflicts."
143
134
  )
144
135
 
136
+ check_config_in_path()
137
+
145
138
  return exists
146
139
 
147
140
 
@@ -152,7 +145,24 @@ def remove_go_cli() -> None:
152
145
 
153
146
  if GO_CLI_PATH.exists():
154
147
  GO_CLI_PATH.unlink()
155
- success(f"Deleted [italic red]deprecated[/italic red] [magenta]{GO_CLI_PATH}[/magenta].")
148
+ success(f"Deleted deprecated [magenta]{GO_CLI_PATH}[/magenta].")
149
+
150
+ check_config_in_path()
151
+
152
+
153
+ def check_config_in_path() -> None:
154
+ """
155
+ Check if the configuration directory is in the PATH and notify the user.
156
+ """
157
+
158
+ path_dirs = os.environ.get("PATH", "").split(os.pathsep)
159
+ config_dir_str = str(CONFIG_DIR)
160
+
161
+ if config_dir_str in path_dirs:
162
+ warning(
163
+ f"[magenta]{CONFIG_DIR}[/magenta] was found in your [code]PATH[/code]. "
164
+ f"You should remove any entries related to [magenta]{CONFIG_DIR}[/magenta] from your [code]PATH[/code]."
165
+ )
156
166
 
157
167
 
158
168
  def main() -> None:
nextmv/cli/message.py CHANGED
@@ -11,107 +11,106 @@ import rich
11
11
  import typer
12
12
 
13
13
 
14
- def message(msg: str, emoji: str | None = None) -> None:
14
+ def error(msg: str) -> None:
15
15
  """
16
- Pretty-print a message. Your message should end with a period. The use of
17
- emojis is encouraged to give context to the message. An emoji should be a
18
- string as specified in:
19
- https://rich.readthedocs.io/en/latest/markup.html#emoji.
16
+ Pretty-print an error message and exit with code 1. Your message should end
17
+ with a period.
20
18
 
21
19
  Parameters
22
20
  ----------
23
21
  msg : str
24
- The message to display.
25
- emoji : str | None
26
- An optional emoji to prefix the message. If None, no emoji is used. The
27
- emoji should be a string as specified in:
28
- https://rich.readthedocs.io/en/latest/markup.html#emoji. For example:
29
- `:hourglass_flowing_sand:`.
22
+ The error message to display.
23
+
24
+ Raises
25
+ ------
26
+ typer.Exit
27
+ Exits the program with code 1.
30
28
  """
31
29
 
32
- msg = _format(msg)
33
- if emoji:
34
- rich.print(f"{emoji} {msg}", file=sys.stderr)
35
- return
30
+ msg = msg.rstrip("\n")
31
+ if not msg.endswith("."):
32
+ msg += "."
36
33
 
37
- rich.print(msg, file=sys.stderr)
34
+ rich.print(f"[red]Error:[/red] {msg}", file=sys.stderr)
35
+
36
+ raise typer.Exit(code=1)
38
37
 
39
38
 
40
- def info(msg: str) -> None:
39
+ def success(msg: str) -> None:
41
40
  """
42
- Pretty-print an informational message. Your message should end with a
43
- period.
41
+ Pretty-print a success message. Your message should end with a period.
44
42
 
45
43
  Parameters
46
44
  ----------
47
45
  msg : str
48
- The informational message to display.
46
+ The success message to display.
49
47
  """
50
48
 
51
- message(msg, emoji=":bulb:")
49
+ msg = msg.rstrip("\n")
50
+ if not msg.endswith("."):
51
+ msg += "."
52
52
 
53
+ rich.print(f":white_check_mark: {msg}", file=sys.stderr)
53
54
 
54
- def in_progress(msg: str) -> None:
55
+
56
+ def warning(msg: str) -> None:
55
57
  """
56
- Pretty-print an in-progress message with an hourglass emoji. Your message
57
- should end with a period.
58
+ Pretty-print a warning message. Your message should end with a period.
58
59
 
59
60
  Parameters
60
61
  ----------
61
62
  msg : str
62
- The in-progress message to display.
63
+ The warning message to display.
63
64
  """
64
65
 
65
- message(msg, emoji=":hourglass_flowing_sand:")
66
+ msg = msg.rstrip("\n")
67
+ if not msg.endswith("."):
68
+ msg += "."
66
69
 
70
+ rich.print(f":construction: {msg}", file=sys.stderr)
67
71
 
68
- def success(msg: str) -> None:
72
+
73
+ def info(msg: str, emoji: str | None = None) -> None:
69
74
  """
70
- Pretty-print a success message. Your message should end with a period.
75
+ Pretty-print an informational message. Your message should end with a
76
+ period. The use of emojis is encouraged to give context to the message. An
77
+ emoji should be a string as specified in:
78
+ https://rich.readthedocs.io/en/latest/markup.html#emoji.
71
79
 
72
80
  Parameters
73
81
  ----------
74
82
  msg : str
75
- The success message to display.
83
+ The informational message to display.
84
+ emoji : str | None
85
+ An optional emoji to prefix the message. If None, no emoji is used. The
86
+ emoji should be a string as specified in:
87
+ https://rich.readthedocs.io/en/latest/markup.html#emoji. For example:
88
+ `:hourglass_flowing_sand:`.
76
89
  """
77
90
 
78
- message(msg, emoji=":white_check_mark:")
79
-
80
-
81
- def warning(msg: str) -> None:
82
- """
83
- Pretty-print a warning message. Your message should end with a period.
91
+ msg = msg.rstrip("\n")
92
+ if not msg.endswith("."):
93
+ msg += "."
84
94
 
85
- Parameters
86
- ----------
87
- msg : str
88
- The warning message to display.
89
- """
95
+ if emoji:
96
+ rich.print(f"{emoji} {msg}", file=sys.stderr)
97
+ return
90
98
 
91
- msg = _format(msg)
92
- rich.print(f":construction: [yellow] Warning:[/yellow] {msg}", file=sys.stderr)
99
+ rich.print(msg, file=sys.stderr)
93
100
 
94
101
 
95
- def error(msg: str) -> None:
102
+ def in_progress(msg: str) -> None:
96
103
  """
97
- Pretty-print an error message and exit with code 1. Your message should end
98
- with a period.
104
+ Pretty-print an in-progress message with an hourglass emoji. Your message
105
+ should end with a period.
99
106
 
100
107
  Parameters
101
108
  ----------
102
109
  msg : str
103
- The error message to display.
104
-
105
- Raises
106
- ------
107
- typer.Exit
108
- Exits the program with code 1.
110
+ The in-progress message to display.
109
111
  """
110
112
 
111
- msg = _format(msg)
112
- rich.print(f":x: [red]Error:[/red] {msg}", file=sys.stderr)
113
-
114
- raise typer.Exit(code=1)
113
+ info(msg, emoji=":hourglass_flowing_sand:")
115
114
 
116
115
 
117
116
  def print_json(data: dict[str, Any] | list[dict[str, Any]]) -> None:
@@ -152,19 +151,3 @@ def enum_values(enum_class: Enum) -> str:
152
151
  return " and ".join(values)
153
152
 
154
153
  return ", ".join(values[:-1]) + ", and " + values[-1]
155
-
156
-
157
- def _format(msg: str) -> str:
158
- """
159
- Format a message to ensure it ends with a period.
160
-
161
- Parameters
162
- ----------
163
- msg : str
164
- The message to format.
165
- """
166
- msg = msg.rstrip("\n")
167
- if not msg.endswith("."):
168
- msg += "."
169
-
170
- return msg
nextmv/cli/options.py CHANGED
@@ -190,31 +190,3 @@ SecretsCollectionIDOption = Annotated[
190
190
  metavar="SECRETS_COLLECTION_ID",
191
191
  ),
192
192
  ]
193
-
194
- # shadow_test_id option - can be used in any command that requires a shadow test ID.
195
- # Define it as follows in commands or callbacks, as necessary:
196
- # shadow_test_id: ShadowTestIDOption
197
- ShadowTestIDOption = Annotated[
198
- str,
199
- typer.Option(
200
- "--shadow-test-id",
201
- "-s",
202
- help="The Nextmv Cloud shadow test ID to use for this action.",
203
- envvar="NEXTMV_SHADOW_TEST_ID",
204
- metavar="SHADOW_TEST_ID",
205
- ),
206
- ]
207
-
208
- # switchback_test_id option - can be used in any command that requires a switchback test ID.
209
- # Define it as follows in commands or callbacks, as necessary:
210
- # switchback_test_id: SwitchbackTestIDOption
211
- SwitchbackTestIDOption = Annotated[
212
- str,
213
- typer.Option(
214
- "--switchback-test-id",
215
- "-s",
216
- help="The Nextmv Cloud switchback test ID to use for this action.",
217
- envvar="NEXTMV_SWITCHBACK_TEST_ID",
218
- metavar="SWITCHBACK_TEST_ID",
219
- ),
220
- ]
nextmv/cli/version.py CHANGED
@@ -18,7 +18,7 @@ def version() -> None:
18
18
  [bold][underline]Examples[/underline][/bold]
19
19
 
20
20
  - Show the version.
21
- $ [dim]nextmv version[/dim]
21
+ $ [green]nextmv version[/green]
22
22
  """
23
23
 
24
24
  version_callback(True)
nextmv/cloud/__init__.py CHANGED
@@ -1,5 +1,42 @@
1
1
  """Functionality for interacting with the Nextmv Cloud."""
2
2
 
3
+ # These imports are kept for backwards compatibility but the preferred import path is
4
+ # from nextmv directly. These imports will be removed in a future release.
5
+ from nextmv.manifest import MANIFEST_FILE_NAME as MANIFEST_FILE_NAME
6
+ from nextmv.manifest import Manifest as Manifest
7
+ from nextmv.manifest import ManifestBuild as ManifestBuild
8
+ from nextmv.manifest import ManifestContent as ManifestContent
9
+ from nextmv.manifest import ManifestContentMultiFile as ManifestContentMultiFile
10
+ from nextmv.manifest import ManifestContentMultiFileInput as ManifestContentMultiFileInput
11
+ from nextmv.manifest import ManifestContentMultiFileOutput as ManifestContentMultiFileOutput
12
+ from nextmv.manifest import ManifestOption as ManifestOption
13
+ from nextmv.manifest import ManifestPython as ManifestPython
14
+ from nextmv.manifest import ManifestPythonModel as ManifestPythonModel
15
+ from nextmv.manifest import ManifestRuntime as ManifestRuntime
16
+ from nextmv.manifest import ManifestType as ManifestType
17
+ from nextmv.polling import PollingOptions as PollingOptions
18
+ from nextmv.polling import poll as poll
19
+ from nextmv.run import ErrorLog as ErrorLog
20
+ from nextmv.run import ExternalRunResult as ExternalRunResult
21
+ from nextmv.run import Format as Format
22
+ from nextmv.run import FormatInput as FormatInput
23
+ from nextmv.run import FormatOutput as FormatOutput
24
+ from nextmv.run import Metadata as Metadata
25
+ from nextmv.run import RunConfiguration as RunConfiguration
26
+ from nextmv.run import RunInformation as RunInformation
27
+ from nextmv.run import RunLog as RunLog
28
+ from nextmv.run import RunQueuing as RunQueuing
29
+ from nextmv.run import RunResult as RunResult
30
+ from nextmv.run import RunType as RunType
31
+ from nextmv.run import RunTypeConfiguration as RunTypeConfiguration
32
+ from nextmv.run import TrackedRun as TrackedRun
33
+ from nextmv.run import TrackedRunStatus as TrackedRunStatus
34
+ from nextmv.run import run_duration as run_duration
35
+ from nextmv.safe import safe_id as safe_id
36
+ from nextmv.safe import safe_name_and_id as safe_name_and_id
37
+ from nextmv.status import Status as Status
38
+ from nextmv.status import StatusV2 as StatusV2
39
+
3
40
  from .acceptance_test import AcceptanceTest as AcceptanceTest
4
41
  from .acceptance_test import AcceptanceTestResults as AcceptanceTestResults
5
42
  from .acceptance_test import Comparison as Comparison
@@ -15,6 +52,7 @@ from .acceptance_test import MetricToleranceType as MetricToleranceType
15
52
  from .acceptance_test import MetricType as MetricType
16
53
  from .acceptance_test import ResultStatistics as ResultStatistics
17
54
  from .acceptance_test import StatisticType as StatisticType
55
+ from .acceptance_test import ToleranceType as ToleranceType
18
56
  from .account import Account as Account
19
57
  from .account import AccountMember as AccountMember
20
58
  from .account import Queue as Queue
@@ -30,9 +68,6 @@ from .batch_experiment import BatchExperimentRun as BatchExperimentRun
30
68
  from .batch_experiment import ExperimentStatus as ExperimentStatus
31
69
  from .client import Client as Client
32
70
  from .client import get_size as get_size
33
- from .community import CommunityApp as CommunityApp
34
- from .community import clone_community_app as clone_community_app
35
- from .community import list_community_apps as list_community_apps
36
71
  from .ensemble import EnsembleDefinition as EnsembleDefinition
37
72
  from .ensemble import EvaluationRule as EvaluationRule
38
73
  from .ensemble import RuleObjective as RuleObjective
@@ -55,17 +90,6 @@ from .secrets import Secret as Secret
55
90
  from .secrets import SecretsCollection as SecretsCollection
56
91
  from .secrets import SecretsCollectionSummary as SecretsCollectionSummary
57
92
  from .secrets import SecretType as SecretType
58
- from .shadow import ShadowTest as ShadowTest
59
- from .shadow import ShadowTestMetadata as ShadowTestMetadata
60
- from .shadow import StartEvents as StartEvents
61
- from .shadow import StopIntent as StopIntent
62
- from .shadow import TerminationEvents as TerminationEvents
63
- from .shadow import TestComparison as TestComparison
64
- from .switchback import SwitchbackPlan as SwitchbackPlan
65
- from .switchback import SwitchbackPlanUnit as SwitchbackPlanUnit
66
- from .switchback import SwitchbackTest as SwitchbackTest
67
- from .switchback import SwitchbackTestMetadata as SwitchbackTestMetadata
68
- from .switchback import TestComparisonSingle as TestComparisonSingle
69
93
  from .url import DownloadURL as DownloadURL
70
94
  from .url import UploadURL as UploadURL
71
95
  from .version import Version as Version
@@ -13,7 +13,7 @@ StatisticType : Enum
13
13
  Type of statistical process for collapsing multiple values of a metric.
14
14
  Comparison : Enum
15
15
  Comparison operators to use for comparing two metrics.
16
- MetricToleranceType : Enum
16
+ ToleranceType : Enum
17
17
  Type of tolerance used for a metric.
18
18
  ExperimentStatus : Enum
19
19
  Status of an acceptance test experiment.
@@ -46,6 +46,7 @@ from enum import Enum
46
46
 
47
47
  from nextmv.base_model import BaseModel
48
48
  from nextmv.cloud.batch_experiment import ExperimentStatus
49
+ from nextmv.deprecated import deprecated
49
50
 
50
51
 
51
52
  class MetricType(str, Enum):
@@ -211,6 +212,69 @@ class Comparison(str, Enum):
211
212
  """Not equal to metric type."""
212
213
 
213
214
 
215
+ class ToleranceType(str, Enum):
216
+ """
217
+ !!! warning
218
+ `ToleranceType` is deprecated, use `MetricToleranceType` instead.
219
+
220
+ Type of tolerance used for a metric.
221
+
222
+ You can import the `ToleranceType` class directly from `cloud`:
223
+
224
+ ```python
225
+ from nextmv.cloud import ToleranceType
226
+ ```
227
+
228
+ This enumeration defines the different types of tolerances that can be used
229
+ when comparing metrics in acceptance tests.
230
+
231
+ Attributes
232
+ ----------
233
+ undefined : str
234
+ Undefined tolerance type (empty string).
235
+ absolute : str
236
+ Absolute tolerance type, using a fixed value.
237
+ relative : str
238
+ Relative tolerance type, using a percentage.
239
+
240
+ Examples
241
+ --------
242
+ >>> from nextmv.cloud import ToleranceType
243
+ >>> tol_type = ToleranceType.absolute
244
+ >>> tol_type
245
+ <ToleranceType.absolute: 'absolute'>
246
+ """
247
+
248
+ undefined = ""
249
+ """ToleranceType is deprecated, please use MetricToleranceType instead.
250
+ Undefined tolerance type."""
251
+ absolute = "absolute"
252
+ """ToleranceType is deprecated, please use MetricToleranceType instead.
253
+ Absolute tolerance type."""
254
+ relative = "relative"
255
+ """ToleranceType is deprecated, please use MetricToleranceType instead.
256
+ Relative tolerance type."""
257
+
258
+
259
+ # Override __getattribute__ to emit deprecation warnings when enum values are accessed
260
+ _original_getattribute = ToleranceType.__class__.__getattribute__
261
+
262
+
263
+ def _deprecated_getattribute(cls, name: str):
264
+ # Only emit deprecation warning if this is specifically the ToleranceType class
265
+ if cls is ToleranceType and name in ("undefined", "absolute", "relative"):
266
+ deprecated(
267
+ f"ToleranceType.{name}",
268
+ "ToleranceType is deprecated and will be removed in a future version. "
269
+ "Please use MetricToleranceType instead",
270
+ )
271
+
272
+ return _original_getattribute(cls, name)
273
+
274
+
275
+ ToleranceType.__class__.__getattribute__ = _deprecated_getattribute
276
+
277
+
214
278
  class MetricToleranceType(str, Enum):
215
279
  """
216
280
  Type of tolerance used for a metric.
nextmv/cloud/account.py CHANGED
@@ -21,7 +21,7 @@ from pydantic import AliasChoices, Field
21
21
 
22
22
  from nextmv.base_model import BaseModel
23
23
  from nextmv.cloud.client import Client
24
- from nextmv.status import StatusV2
24
+ from nextmv.status import Status, StatusV2
25
25
 
26
26
 
27
27
  class QueuedRun(BaseModel):
@@ -57,6 +57,8 @@ class QueuedRun(BaseModel):
57
57
  ID of the application version used for the run.
58
58
  execution_class : str
59
59
  Execution class used for the run.
60
+ status : Status
61
+ Deprecated: use status_v2.
60
62
  status_v2 : StatusV2
61
63
  Status of the run.
62
64
 
@@ -72,6 +74,7 @@ class QueuedRun(BaseModel):
72
74
  ... "application_instance_id": "appins-123456",
73
75
  ... "application_version_id": "appver-123456",
74
76
  ... "execution_class": "standard",
77
+ ... "status": "RUNNING",
75
78
  ... "status_v2": "RUNNING"
76
79
  ... })
77
80
  >>> print(queued_run.name)
@@ -96,6 +99,8 @@ class QueuedRun(BaseModel):
96
99
  """ID of the application version used for the run."""
97
100
  execution_class: str
98
101
  """Execution class used for the run."""
102
+ status: Status
103
+ """Deprecated: use status_v2."""
99
104
  status_v2: StatusV2
100
105
  """Status of the run."""
101
106