remotivelabs-cli 0.3.0__py3-none-any.whl → 0.3.2__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.

Potentially problematic release.


This version of remotivelabs-cli might be problematic. Click here for more details.

Files changed (45) hide show
  1. cli/broker/__init__.py +36 -0
  2. cli/broker/discovery.py +43 -0
  3. cli/broker/export.py +6 -36
  4. cli/broker/files.py +12 -12
  5. cli/broker/lib/broker.py +13 -18
  6. cli/broker/lib/helper.py +6 -7
  7. cli/broker/license_flows.py +11 -13
  8. cli/broker/playback.py +10 -10
  9. cli/broker/record.py +4 -4
  10. cli/broker/scripting.py +6 -9
  11. cli/broker/signals.py +17 -19
  12. cli/cloud/auth/cmd.py +17 -14
  13. cli/cloud/auth/login.py +16 -26
  14. cli/cloud/auth_tokens.py +9 -13
  15. cli/cloud/brokers.py +5 -9
  16. cli/cloud/configs.py +4 -17
  17. cli/cloud/organisations.py +8 -10
  18. cli/cloud/projects.py +3 -3
  19. cli/cloud/recordings.py +35 -61
  20. cli/cloud/recordings_playback.py +22 -22
  21. cli/cloud/resumable_upload.py +6 -6
  22. cli/cloud/service_account_tokens.py +3 -2
  23. cli/cloud/storage/cmd.py +2 -3
  24. cli/cloud/storage/copy.py +2 -1
  25. cli/connect/connect.py +4 -4
  26. cli/connect/protopie/protopie.py +21 -29
  27. cli/remotive.py +4 -7
  28. cli/settings/core.py +4 -2
  29. cli/settings/migration/migration_tools.py +2 -1
  30. cli/tools/can/can.py +4 -7
  31. cli/topology/__init__.py +3 -0
  32. cli/topology/cmd.py +61 -83
  33. cli/topology/start_trial.py +105 -0
  34. cli/typer/typer_utils.py +3 -6
  35. cli/utils/console.py +61 -0
  36. cli/utils/rest_helper.py +23 -16
  37. cli/utils/versions.py +2 -4
  38. {remotivelabs_cli-0.3.0.dist-info → remotivelabs_cli-0.3.2.dist-info}/METADATA +1 -1
  39. remotivelabs_cli-0.3.2.dist-info/RECORD +74 -0
  40. cli/broker/brokers.py +0 -93
  41. cli/errors.py +0 -44
  42. remotivelabs_cli-0.3.0.dist-info/RECORD +0 -71
  43. {remotivelabs_cli-0.3.0.dist-info → remotivelabs_cli-0.3.2.dist-info}/LICENSE +0 -0
  44. {remotivelabs_cli-0.3.0.dist-info → remotivelabs_cli-0.3.2.dist-info}/WHEEL +0 -0
  45. {remotivelabs_cli-0.3.0.dist-info → remotivelabs_cli-0.3.2.dist-info}/entry_points.txt +0 -0
cli/broker/signals.py CHANGED
@@ -12,10 +12,9 @@ from typing import Any, Dict, Iterable, List, TypedDict, Union
12
12
  import grpc
13
13
  import plotext as plt # type: ignore
14
14
  import typer
15
- from rich import print as rich_rprint
16
15
 
17
- from cli.errors import ErrorPrinter
18
16
  from cli.typer import typer_utils
17
+ from cli.utils.console import print_generic_error, print_generic_message, print_grpc_error, print_hint
19
18
 
20
19
  from .lib.broker import Broker, SubscribableSignal
21
20
 
@@ -23,8 +22,6 @@ app = typer_utils.create_typer(help=help)
23
22
 
24
23
  DEFAULT_GRPC_URL = "http://localhost:50051"
25
24
 
26
- # signal_values:list = list()
27
-
28
25
 
29
26
  class Signals(TypedDict):
30
27
  name: str
@@ -49,18 +46,18 @@ def list_signals(
49
46
  try:
50
47
  broker = Broker(url, api_key)
51
48
  available_signals = broker.list_signal_names(prefix=name_starts_with, suffix=name_ends_with)
52
- print(json.dumps(available_signals))
49
+ print_generic_message(json.dumps(available_signals))
53
50
  except grpc.RpcError as rpc_error:
54
- ErrorPrinter.print_grpc_error(rpc_error)
51
+ print_grpc_error(rpc_error)
55
52
 
56
53
 
57
54
  def read_scripted_code_file(file_path: Path) -> bytes:
58
55
  try:
59
- print(file_path)
56
+ print_generic_message(str(file_path))
60
57
  with open(file_path, "rb") as file:
61
58
  return file.read()
62
59
  except FileNotFoundError:
63
- print("File not found. Please check your file path.")
60
+ print_generic_error("File not found. Please check your file path.")
64
61
  sys.exit(1)
65
62
 
66
63
 
@@ -100,12 +97,12 @@ def subscribe( # noqa: C901, PLR0913, PLR0915
100
97
 
101
98
  if script is None:
102
99
  if len(signal) == 0:
103
- ErrorPrinter.print_generic_error("You must use --signal or use --script when subscribing")
100
+ print_generic_error("You must use --signal or use --script when subscribing")
104
101
  sys.exit(1)
105
102
 
106
103
  if script is not None:
107
104
  if len(signal) > 0:
108
- ErrorPrinter.print_generic_error("You must must not specify --signal when using --script")
105
+ print_generic_error("You must must not specify --signal when using --script")
109
106
  sys.exit(1)
110
107
 
111
108
  plt.title("Signals")
@@ -153,7 +150,8 @@ def subscribe( # noqa: C901, PLR0913, PLR0915
153
150
  plt.show()
154
151
 
155
152
  def on_frame_print(x: Iterable[Any]) -> None:
156
- rich_rprint(json.dumps(list(x)))
153
+ # TODO: use log instead of print for debug information?
154
+ print_generic_message(json.dumps(list(x)))
157
155
 
158
156
  os_signal.signal(os_signal.SIGINT, exit_on_ctrlc)
159
157
 
@@ -172,7 +170,7 @@ def subscribe( # noqa: C901, PLR0913, PLR0915
172
170
  def to_subscribable_signal(sig: str):
173
171
  arr = sig.split(":")
174
172
  if len(arr) != 2:
175
- ErrorPrinter.print_hint(f"--signal must have format namespace:signal ({sig})")
173
+ print_hint(f"--signal must have format namespace:signal ({sig})")
176
174
  sys.exit(1)
177
175
  return SubscribableSignal(namespace=arr[0], name=arr[1])
178
176
 
@@ -180,9 +178,9 @@ def subscribe( # noqa: C901, PLR0913, PLR0915
180
178
 
181
179
  broker = Broker(url, api_key)
182
180
  broker.long_name_subscribe(signals_to_subscribe_to, on_frame_func, on_change_only)
183
- print("Subscribing to signals, press Ctrl+C to exit")
181
+ print_generic_message("Subscribing to signals, press Ctrl+C to exit")
184
182
  except grpc.RpcError as rpc_error:
185
- ErrorPrinter.print_grpc_error(rpc_error)
183
+ print_grpc_error(rpc_error)
186
184
 
187
185
 
188
186
  @app.command(help="List namespaces on broker")
@@ -193,9 +191,9 @@ def namespaces(
193
191
  try:
194
192
  broker = Broker(url, api_key)
195
193
  namespaces_json = broker.list_namespaces()
196
- print(json.dumps(namespaces_json))
194
+ print_generic_message(json.dumps(namespaces_json))
197
195
  except grpc.RpcError as rpc_error:
198
- ErrorPrinter.print_grpc_error(rpc_error)
196
+ print_grpc_error(rpc_error)
199
197
 
200
198
 
201
199
  @app.command()
@@ -214,11 +212,11 @@ def frame_distribution(
214
212
  timestamp: str = datetime.now().strftime("%H:%M:%S")
215
213
  distribution = data["countsByFrameId"]
216
214
  if len(distribution) == 0:
217
- ErrorPrinter.print_hint(f"{timestamp} - No frames available")
215
+ print_hint(f"{timestamp} - No frames available")
218
216
  else:
219
217
  for d in distribution:
220
- ErrorPrinter.print_generic_message(f"{timestamp}: {d}")
218
+ print_generic_message(f"{timestamp}: {d}")
221
219
 
222
220
  broker.listen_on_frame_distribution(namespace, on_data)
223
221
  except grpc.RpcError as rpc_error:
224
- ErrorPrinter.print_grpc_error(rpc_error)
222
+ print_grpc_error(rpc_error)
cli/cloud/auth/cmd.py CHANGED
@@ -1,15 +1,16 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import os
4
+ import sys
4
5
 
5
6
  import typer
6
7
  from rich.console import Console
7
8
  from rich.table import Table
8
9
 
9
10
  from cli.cloud.auth.login import login as do_login
10
- from cli.errors import ErrorPrinter
11
11
  from cli.settings import settings
12
12
  from cli.typer import typer_utils
13
+ from cli.utils.console import print_generic_error, print_generic_message, print_success, print_unformatted
13
14
  from cli.utils.rest_helper import RestHelper as Rest
14
15
 
15
16
  from .. import auth_tokens
@@ -52,24 +53,24 @@ def print_access_token(
52
53
  if not account:
53
54
  active_token = settings.get_active_token() or os.getenv("REMOTIVE_CLOUD_ACCESS_TOKEN", None)
54
55
  if not active_token:
55
- ErrorPrinter.print_generic_error("You have no active account", exit_code=1)
56
- return
56
+ print_generic_error("You have no active account")
57
+ sys.exit(1)
57
58
 
58
- print(active_token)
59
+ print_generic_message(active_token)
59
60
  return
60
61
 
61
62
  accounts = settings.list_accounts()
62
63
  if account not in accounts:
63
- ErrorPrinter.print_generic_error(f"No account for {account} was found", exit_code=1)
64
- return
64
+ print_generic_error(f"No account for {account} was found")
65
+ sys.exit(1)
65
66
 
66
67
  token_file_name = accounts[account].credentials_file
67
68
  token_file = settings.get_token_file(token_file_name)
68
69
  if not token_file:
69
- ErrorPrinter.print_generic_error(f"Token file for {account} could not be found", exit_code=1)
70
- return
70
+ print_generic_error(f"Token file for {account} could not be found")
71
+ sys.exit(1)
71
72
 
72
- print(token_file.token)
73
+ print_generic_message(token_file.token)
73
74
 
74
75
 
75
76
  def print_access_token_file() -> None:
@@ -78,10 +79,10 @@ def print_access_token_file() -> None:
78
79
  """
79
80
  active_token_file = settings.get_active_token_file()
80
81
  if not active_token_file:
81
- ErrorPrinter.print_generic_error("You have no active account", exit_code=1)
82
- return
82
+ print_generic_error("You have no active account")
83
+ sys.exit(1)
83
84
 
84
- print(active_token_file)
85
+ print_generic_message(str(active_token_file))
85
86
 
86
87
 
87
88
  @app.command(name="deactivate")
@@ -90,7 +91,7 @@ def deactivate() -> None:
90
91
  Clears active account
91
92
  """
92
93
  settings.clear_active_account()
93
- print("Account no longer active")
94
+ print_success("Account no longer active")
94
95
 
95
96
 
96
97
  @app.command("activate")
@@ -105,6 +106,8 @@ def activate(token_name: str = typer.Argument(None, help="Name, filename or path
105
106
  def list() -> None:
106
107
  """
107
108
  Lists available credential files on filesystem
109
+
110
+ TODO: Support output format
108
111
  """
109
112
  accounts = settings.list_accounts()
110
113
 
@@ -123,4 +126,4 @@ def list() -> None:
123
126
  str(token_file.created) if token_file else "",
124
127
  str(token_file.expires) if token_file else "",
125
128
  )
126
- console.print(table)
129
+ print_unformatted(table)
cli/cloud/auth/login.py CHANGED
@@ -13,19 +13,16 @@ from typing import Any, Optional, Tuple
13
13
  from urllib.parse import parse_qs, urlparse
14
14
 
15
15
  import typer
16
- from rich.console import Console
17
16
  from typing_extensions import override
18
17
 
19
18
  from cli.cloud.auth_tokens import do_activate, prompt_to_set_org
20
- from cli.errors import ErrorPrinter
21
19
  from cli.settings import settings
22
20
  from cli.settings.token_file import TokenFile
21
+ from cli.utils.console import print_generic_error, print_newline, print_success, print_unformatted, print_url
23
22
  from cli.utils.rest_helper import RestHelper as Rest
24
23
 
25
24
  httpd: HTTPServer
26
25
 
27
- console = Console()
28
-
29
26
 
30
27
  def generate_pkce_pair() -> Tuple[str, str]:
31
28
  """
@@ -79,8 +76,7 @@ class S(BaseHTTPRequestHandler):
79
76
  allow_status_codes=[401, 400],
80
77
  )
81
78
  if res.status_code != 200:
82
- print(res.text)
83
- ErrorPrinter.print_generic_error(
79
+ print_generic_error(
84
80
  "Failed to fetch token. Please try again, if the problem persists please reach out to support@remotivelabs.com"
85
81
  )
86
82
  self.wfile.write(
@@ -95,7 +91,6 @@ class S(BaseHTTPRequestHandler):
95
91
  """Successfully setup CLI, you may close this window now. Return to your terminal to continue""".encode("utf-8")
96
92
  )
97
93
  access_token = res.json()["access_token"]
98
-
99
94
  global short_lived_token # noqa: PLW0603
100
95
  short_lived_token = access_token
101
96
 
@@ -109,7 +104,7 @@ class S(BaseHTTPRequestHandler):
109
104
  Run `remotive cloud auth login` to try again.
110
105
  """.encode("utf-8")
111
106
  )
112
- ErrorPrinter.print_generic_error("You did not grant access to RemotiveCloud, login aborted")
107
+ print_generic_error("You did not grant access to RemotiveCloud, login aborted")
113
108
  elif error_value == "user_not_exists":
114
109
  self.wfile.write(
115
110
  """
@@ -120,22 +115,19 @@ class S(BaseHTTPRequestHandler):
120
115
  Once you are signed up, Run `remotive cloud auth login` again.
121
116
  """.encode("utf-8")
122
117
  )
123
- ErrorPrinter.print_generic_error(
118
+ print_generic_error(
124
119
  "To use RemotiveCLI you must first sign up at https://cloud.remotivelabs.com and approve our agreements"
125
120
  )
126
121
  else:
127
122
  self.wfile.write(f"Unknown error {error_value}, please contact support@remotivelabs.com".encode("utf-8"))
128
- ErrorPrinter.print_generic_error(f"Unexpected error {error_value}, please contact support@remotivelabs.com")
123
+ print_generic_error(f"Unexpected error {error_value}, please contact support@remotivelabs.com")
129
124
  sys.exit(1)
130
125
 
131
126
 
132
127
  def prepare_local_webserver(server_class: type = HTTPServer, handler_class: type = S, port: Optional[int] = None) -> None:
133
128
  if port is None:
134
129
  env_val = os.getenv("REMOTIVE_LOGIN_CALLBACK_PORT" or "")
135
- if env_val and env_val.isdigit():
136
- port = int(env_val)
137
- else:
138
- port = 0
130
+ port = int(env_val) if env_val and env_val.isdigit() else 0
139
131
 
140
132
  server_address = ("", port)
141
133
  global httpd # noqa: PLW0603
@@ -153,7 +145,6 @@ def create_personal_token() -> None:
153
145
  email = token["account"]["email"]
154
146
  existing_file = settings.get_token_file_by_email(email=email)
155
147
  if existing_file is not None:
156
- # ErrorPrinter.print_hint(f"Revoking and deleting existing credentials [remove_me]{existing_file.name}")
157
148
  res = Rest.handle_patch(
158
149
  f"/api/me/keys/{existing_file.name}/revoke",
159
150
  quiet=True,
@@ -170,7 +161,7 @@ def create_personal_token() -> None:
170
161
 
171
162
  settings.add_personal_token(response.text, activate=True)
172
163
 
173
- print("Successfully logged on")
164
+ print_success("Logged in")
174
165
 
175
166
 
176
167
  def _do_prompt_to_use_existing_credentials() -> Optional[TokenFile]:
@@ -232,8 +223,8 @@ def login(headless: bool = False) -> bool: # noqa: C901, PLR0915
232
223
  """
233
224
  This will print a url the will trigger a callback later so the webserver must be up and running.
234
225
  """
235
- print("Copy the following link in a browser to login to cloud, and complete the sign-in prompts:")
236
- print("")
226
+ print_unformatted("Copy the following link in a browser to login to cloud, and complete the sign-in prompts:")
227
+ print_newline()
237
228
 
238
229
  url = (
239
230
  f"{Rest.get_base_frontend_url()}/login"
@@ -243,15 +234,15 @@ def login(headless: bool = False) -> bool: # noqa: C901, PLR0915
243
234
  f"&code_challenge={code_challenge}"
244
235
  f"&redirect_uri=http://localhost:{httpd.server_address[1]}"
245
236
  )
246
- console.print(url, style="bold", soft_wrap=True)
237
+ print_url(url)
247
238
  httpd.serve_forever()
248
239
 
249
240
  def login_headless() -> None:
250
241
  """
251
242
  Full headless, opens a browser and expects a auth code to be entered and exchanged for the token
252
243
  """
253
- print("Copy the following link in a browser to login to cloud, and complete the sign-in prompts:")
254
- print("")
244
+ print_unformatted("Copy the following link in a browser to login to cloud, and complete the sign-in prompts:")
245
+ print_newline()
255
246
 
256
247
  url = (
257
248
  f"{Rest.get_base_frontend_url()}/login"
@@ -260,7 +251,7 @@ def login(headless: bool = False) -> bool: # noqa: C901, PLR0915
260
251
  f"&response_type=code"
261
252
  f"&code_challenge={code_challenge}"
262
253
  )
263
- console.print(url, style="bold", soft_wrap=True)
254
+ print_url(url)
264
255
 
265
256
  code = typer.prompt(
266
257
  "Once finished, enter the verification code provided in your browser",
@@ -273,12 +264,11 @@ def login(headless: bool = False) -> bool: # noqa: C901, PLR0915
273
264
  allow_status_codes=[401],
274
265
  )
275
266
  if res.status_code == 401:
276
- ErrorPrinter.print_generic_error(
267
+ print_generic_error(
277
268
  "Failed to fetch token. Please try again, if the problem persists please reach out to support@remotivelabs.com"
278
269
  )
279
270
  sys.exit(1)
280
271
  access_token = res.json()["access_token"]
281
- # res = Rest.handle_get("/api/whoami", return_response=True, access_token=access_token)
282
272
  global short_lived_token # noqa: PLW0603
283
273
  short_lived_token = access_token
284
274
  create_personal_token()
@@ -299,10 +289,10 @@ def login(headless: bool = False) -> bool: # noqa: C901, PLR0915
299
289
  )
300
290
 
301
291
  if not could_open:
302
- print(
292
+ print_generic_error(
303
293
  "Could not open a browser on this machine, this is likely because you are in an environment where no browser is available"
304
294
  )
305
- print("")
295
+ print_newline()
306
296
  if force_use_webserver_callback():
307
297
  login_with_callback_but_copy_url()
308
298
  create_personal_token()
cli/cloud/auth_tokens.py CHANGED
@@ -3,18 +3,14 @@ from __future__ import annotations
3
3
  from typing import List, Optional
4
4
 
5
5
  import typer
6
- from rich.console import Console
7
6
  from rich.table import Table
8
7
 
9
8
  from cli.cloud.organisations import do_select_default_org
10
- from cli.errors import ErrorPrinter
11
9
  from cli.settings import settings
12
10
  from cli.settings.token_file import TokenFile
11
+ from cli.utils.console import print_generic_error, print_generic_message, print_hint, print_newline, print_success, print_unformatted
13
12
  from cli.utils.rest_helper import RestHelper as Rest
14
13
 
15
- console = Console(stderr=False)
16
- err_console = Console(stderr=True)
17
-
18
14
 
19
15
  def _prompt_choice( # noqa: C901
20
16
  choices: List[TokenFile],
@@ -59,14 +55,14 @@ def _prompt_choice( # noqa: C901
59
55
  str(choice.created),
60
56
  str(choice.expires),
61
57
  )
62
- console.print(table)
58
+ print_unformatted(table)
63
59
 
64
60
  if skip_prompt:
65
61
  return None
66
62
 
67
- typer.echo("")
68
- if info_message is not None:
69
- console.print(info_message)
63
+ print_newline()
64
+ if info_message:
65
+ print_generic_message(info_message)
70
66
 
71
67
  selection = typer.prompt(
72
68
  f"Enter the number(# 1-{len(included_tokens)}) of the account to select (q to quit)",
@@ -101,7 +97,7 @@ def do_activate(token_name: Optional[str]) -> Optional[TokenFile]:
101
97
  if token_name:
102
98
  token_file = settings.get_token_file(token_name)
103
99
  if not token_file:
104
- err_console.print(f":boom: [bold red] Error: [/bold red] Token with filename or name {token_name} could not be found")
100
+ print_generic_error(f"Token with filename or name {token_name} could not be found")
105
101
  return None
106
102
  return settings.activate_token(token_file)
107
103
 
@@ -112,16 +108,16 @@ def do_activate(token_name: Optional[str]) -> Optional[TokenFile]:
112
108
  if token_selected is not None:
113
109
  is_logged_in = Rest.has_access("/api/whoami")
114
110
  if not is_logged_in:
115
- ErrorPrinter.print_generic_error("Could not access RemotiveCloud with selected token")
111
+ print_generic_error("Could not access RemotiveCloud with selected token")
116
112
  else:
117
- console.print("[green]Success![/green] Access to RemotiveCloud granted")
113
+ print_success("Access to RemotiveCloud granted")
118
114
  # Only select default if activate was done with selection and successful
119
115
  # and not SA since SA cannot list available organizations
120
116
  if token_selected.type == "authorized_user":
121
117
  prompt_to_set_org()
122
118
  return token_selected
123
119
 
124
- ErrorPrinter.print_hint("No credentials available, login to activate credentials")
120
+ print_hint("No credentials available, login to activate credentials")
125
121
  return None
126
122
 
127
123
 
cli/cloud/brokers.py CHANGED
@@ -10,6 +10,7 @@ import typer
10
10
  import websocket
11
11
 
12
12
  from cli.typer import typer_utils
13
+ from cli.utils.console import print_generic_message
13
14
  from cli.utils.rest_helper import RestHelper as Rest
14
15
 
15
16
  app = typer_utils.create_typer()
@@ -61,12 +62,6 @@ def start(
61
62
  silent: bool = typer.Option(False, help="Optional specific tag/version"),
62
63
  api_key: str = typer.Option("", help="Start with your own api-key"),
63
64
  ) -> None:
64
- # with Progress(
65
- # SpinnerColumn(),
66
- # TextColumn("[progress.description]{task.description}"),
67
- # transient=True,
68
- # ) as progress:
69
- # progress.add_task(description=f"Starting broker {name}...", total=None)
70
65
  do_start(name, project, api_key, tag, return_response=silent)
71
66
 
72
67
 
@@ -81,7 +76,6 @@ def logs(
81
76
  Exposes broker logs history or real-time tail of the broker.
82
77
 
83
78
  When using --tail option, --history always skipped even if supplied
84
-
85
79
  """
86
80
 
87
81
  def exit_on_ctrlc(_sig: Any, _frame: Any) -> None:
@@ -91,10 +85,12 @@ def logs(
91
85
  os_signal.signal(os_signal.SIGINT, exit_on_ctrlc)
92
86
 
93
87
  def on_message(_wsapp: Any, message: str) -> None:
94
- print(message)
88
+ # TODO: use log instead of print for debug information?
89
+ print_generic_message(message)
95
90
 
96
91
  def on_error(_wsapp: Any, err: str) -> None:
97
- print("EXAMPLE error encountered: ", err)
92
+ # TODO: use log instead of print for debug information?
93
+ print_generic_message(f"Error encountered: {err}")
98
94
 
99
95
  Rest.ensure_auth_token()
100
96
  # This will work with both http -> ws and https -> wss
cli/cloud/configs.py CHANGED
@@ -1,6 +1,5 @@
1
1
  import os.path
2
2
  import shutil
3
- import sys
4
3
  from pathlib import Path
5
4
 
6
5
  import requests
@@ -8,6 +7,7 @@ import typer
8
7
  from rich.progress import Progress, SpinnerColumn, TextColumn
9
8
 
10
9
  from cli.typer import typer_utils
10
+ from cli.utils.console import print_generic_error, print_success
11
11
  from cli.utils.rest_helper import RestHelper as Rest
12
12
 
13
13
  app = typer_utils.create_typer()
@@ -102,21 +102,8 @@ def download(
102
102
  if download_resp.status_code == 200:
103
103
  with open(signal_db_file, "wb") as out_file:
104
104
  shutil.copyfileobj(download_resp.raw, out_file)
105
- print(f"{signal_db_file} downloaded")
105
+ print_success(f"{signal_db_file} downloaded")
106
106
  else:
107
- sys.stderr.write(f"Got unexpected status {download_resp.status_code}\n")
107
+ print_generic_error(f"Got unexpected status {download_resp.status_code}")
108
108
  else:
109
- sys.stderr.write(f"Got unexpected status {get_signed_url_resp.status_code}\n")
110
-
111
-
112
- # @app.command()
113
- # def upload(file: str, project: str = typer.Option(..., help="Project ID", envvar='REMOTIVE_CLOUD_PROJECT')):
114
- # files = {'upload_file': open(file, 'rb')}
115
- # values = {'DB': 'photcat', 'OUT': 'csv', 'SHORT': 'short'}
116
- # rest.headers["content-type"] = "application/octet-stream"
117
- # r = requests.get(f"{rest.base_url}/api/project/{project}/files/recording/upload/{file}", headers=rest.headers)
118
- # print(r.status_code)
119
- # print(r.text)
120
-
121
- # pylint: disable=C0301
122
- # curl -X PUT -H 'Content-Type: application/octet-stream' --upload-file docker-compose.yml 'https://storage.googleapis.com/beamylabs-fileuploads-dev/projects/beamyhack/recording/myrecording?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=recordings-upload-account%40beamycloud-dev.iam.gserviceaccount.com%2F20220729%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20220729T134012Z&X-Goog-Expires=3000&X-Goog-SignedHeaders=content-type%3Bhost&X-Goog-Signature=d1fa7639349d6453aebfce8814d6e5685af03952d07aa4e3cb0d44dba7cf5e572f684c8120dba17cbc7ea6a0ef5450542a3c745c65e04272b34265d0ddcf1b67e6f2b5bfa446264a62d77bd7faabf45ad6bd2aec5225f57004b0a31cfe0480cba063a3807d86346b1da99ecbae3f3e6da8f44f06396dfc1fdc6f89e475abdf969142cef6f369f03aff41000c8abb28aa82185246746fd6c16b6b381baa2d586382a3d3067b6376ddba2b55b2b6f9d942913a1cbfbc61491ba6a615d7d5a0d9a476c357431143e9cea1411dfad9f01b1e1176dc8c056cbf08cccfd401a55d63c19d038f3ab42b712abc48d759047ac07862c4fae937c341e19b568bb60a4e4086'
109
+ print_generic_error(f"Got unexpected status {get_signed_url_resp.status_code}\n")
@@ -5,15 +5,13 @@ from dataclasses import dataclass
5
5
  from typing import List, Optional
6
6
 
7
7
  import typer
8
- from rich.console import Console
9
8
  from rich.table import Table
10
9
 
11
- from cli.errors import ErrorPrinter
12
10
  from cli.settings import settings
13
11
  from cli.typer import typer_utils
12
+ from cli.utils.console import print_generic_error, print_generic_message, print_hint, print_newline, print_unformatted_to_stderr
14
13
  from cli.utils.rest_helper import RestHelper
15
14
 
16
- console = Console(stderr=False)
17
15
  app = typer_utils.create_typer()
18
16
 
19
17
 
@@ -36,9 +34,9 @@ def _prompt_choice(choices: List[Organisation]) -> Optional[Organisation]:
36
34
  choice.uid,
37
35
  ":thumbsup:" if current_default_org is not None and current_default_org == choice.uid else "",
38
36
  )
39
- console.print(table)
37
+ print_unformatted_to_stderr(table)
40
38
 
41
- typer.echo("")
39
+ print_newline()
42
40
  selection = typer.prompt(f"Enter the number(# 1-{len(choices)}) of the organization to select (or q to quit)")
43
41
 
44
42
  if selection == "q":
@@ -49,7 +47,7 @@ def _prompt_choice(choices: List[Organisation]) -> Optional[Organisation]:
49
47
  return choices[index]
50
48
  raise ValueError
51
49
  except ValueError:
52
- typer.echo("Invalid choice, please try again")
50
+ print_generic_error("Invalid choice, please try again")
53
51
  return _prompt_choice(choices)
54
52
 
55
53
 
@@ -75,16 +73,16 @@ def do_select_default_org(organisation_uid: Optional[str] = None, get: bool = Fa
75
73
  active_account = settings.get_active_account()
76
74
  if get:
77
75
  if active_account and active_account.default_organization:
78
- console.print(active_account.default_organization)
76
+ print_unformatted_to_stderr(active_account.default_organization)
79
77
  else:
80
- console.print("No default organization set")
78
+ print_unformatted_to_stderr("No default organization set")
81
79
  elif organisation_uid is not None:
82
80
  settings.set_default_organisation(organisation_uid)
83
81
  else:
84
82
  if active_account:
85
83
  token = settings.get_token_file(active_account.credentials_file)
86
84
  if token and token.type != "authorized_user":
87
- ErrorPrinter.print_hint(
85
+ print_hint(
88
86
  "You must supply the organization name as argument when using a service-account since the "
89
87
  "service-account is not allowed to list"
90
88
  )
@@ -105,4 +103,4 @@ def do_select_default_org(organisation_uid: Optional[str] = None, get: bool = Fa
105
103
  def list_orgs() -> None:
106
104
  r = RestHelper.handle_get("/api/bu", return_response=True)
107
105
  orgs = [{"uid": org["organisation"]["uid"], "displayName": org["organisation"]["displayName"]} for org in r.json()]
108
- print(json.dumps(orgs))
106
+ print_generic_message(json.dumps(orgs))
cli/cloud/projects.py CHANGED
@@ -3,6 +3,7 @@ import json
3
3
  import typer
4
4
 
5
5
  from cli.typer import typer_utils
6
+ from cli.utils.console import print_generic_error, print_generic_message
6
7
  from cli.utils.rest_helper import RestHelper as Rest
7
8
 
8
9
  app = typer_utils.create_typer()
@@ -18,10 +19,9 @@ def list_projects(organization: str = typer.Option(..., help="Organization ID",
18
19
  # extract the project uid parts
19
20
  projects = r.json()["projects"]
20
21
  projects = map(lambda p: p["uid"], projects)
21
- print(json.dumps(list(projects)))
22
+ print_generic_message(json.dumps(list(projects)))
22
23
  else:
23
- print(r.status_code)
24
- print(r.text)
24
+ print_generic_error(f"Got unexpected status {r.status_code}\n")
25
25
 
26
26
 
27
27
  @app.command(name="create")