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/cloud/recordings.py CHANGED
@@ -17,10 +17,17 @@ from rich.progress import Progress, SpinnerColumn, TaskID, TextColumn, track
17
17
  from typing_extensions import Annotated
18
18
 
19
19
  from cli.cloud.uri import URI
20
- from cli.errors import ErrorPrinter
21
20
  from cli.typer import typer_utils
21
+ from cli.utils.console import (
22
+ print_generic_error,
23
+ print_generic_message,
24
+ print_grpc_error,
25
+ print_hint,
26
+ print_success,
27
+ print_unformatted,
28
+ print_unformatted_to_stderr,
29
+ )
22
30
  from cli.utils.rest_helper import RestHelper as Rest
23
- from cli.utils.rest_helper import err_console
24
31
 
25
32
  from ..broker.lib.broker import Broker
26
33
  from .recordings_playback import app as playback_app
@@ -30,7 +37,8 @@ app.add_typer(playback_app, name="playback")
30
37
 
31
38
 
32
39
  def uid(p: Any) -> Any:
33
- print(p)
40
+ # TODO: use log instead of print for debug information?
41
+ print_generic_message(p)
34
42
  return p["uid"]
35
43
 
36
44
 
@@ -38,19 +46,6 @@ def uid(p: Any) -> Any:
38
46
  # ruff: noqa: C901
39
47
 
40
48
 
41
- # to be used in options
42
- # autocompletion=project_names)
43
- def project_names() -> Any:
44
- r = requests.get(f"{Rest.get_base_url()}/api/bu/{Rest.get_org()}/project", headers=Rest.get_headers(), timeout=60)
45
- # sys.stderr.write(r.text)
46
- if r.status_code == 200:
47
- projects = r.json()
48
- names = map(lambda p: p["uid"], projects)
49
- return list(names)
50
- sys.stderr.write(f"Could not list projects due to {r.status_code}\n")
51
- raise typer.Exit(0)
52
-
53
-
54
49
  @app.command("list")
55
50
  def list_recordings(
56
51
  is_processing: bool = typer.Option(default=False, help="Use this option to see only those that are beeing processed or are invalid"),
@@ -59,13 +54,12 @@ def list_recordings(
59
54
  """
60
55
  List all recording sessions in a project. You can choose to see all valid recordings (default) or use
61
56
  --is-processing and you will get those that are currently beeing processed or that failed to be validated.
62
-
63
57
  """
64
58
 
65
59
  if is_processing:
66
60
  res = Rest.handle_get(f"/api/project/{project}/files/recording/processing", return_response=True)
67
61
  json_res: List[Dict[str, Any]] = res.json()
68
- print(json.dumps(list(filter(lambda r: r["status"] == "RUNNING" or r["status"] == "FAILED", json_res))))
62
+ print_generic_message(json.dumps(list(filter(lambda r: r["status"] == "RUNNING" or r["status"] == "FAILED", json_res))))
69
63
  else:
70
64
  Rest.handle_get(f"/api/project/{project}/files/recording")
71
65
 
@@ -78,14 +72,6 @@ def describe(
78
72
  Rest.handle_get(f"/api/project/{project}/files/recording/{recording_session}")
79
73
 
80
74
 
81
- # @app.command(help="Shows details about a specific recording in project")
82
- # def copy(recording_session: str = typer.Argument(..., help="Recording session id"),
83
- # target_project: str = typer.Option(..., help="Which project to copy the recording to"),
84
- # project: str = typer.Option(..., help="Project ID", envvar='REMOTIVE_CLOUD_PROJECT')):
85
- # Rest.handle_post(url=f"/api/project/{project}/files/recording/{recording_session}/copy",
86
- # body=json.dumps({'projectUid': target_project}))
87
-
88
-
89
75
  @app.command(name="import")
90
76
  def import_as_recording(
91
77
  uri: Annotated[URI, typer.Argument(help="Remote storage path", parser=URI, show_default=False)],
@@ -103,9 +89,7 @@ def import_as_recording(
103
89
  body=json.dumps({"path": uri.path}),
104
90
  )
105
91
 
106
- ErrorPrinter.print_hint(
107
- f"Import started, you can track progress with 'remotive cloud recordings list --is-processing --project {project}'"
108
- )
92
+ print_hint(f"Import started, you can track progress with 'remotive cloud recordings list --is-processing --project {project}'")
109
93
 
110
94
 
111
95
  def do_start(name: str, project: str, api_key: str, return_response: bool = False) -> requests.Response:
@@ -142,10 +126,10 @@ def mount( # noqa: C901
142
126
  elif r.status_code == 404:
143
127
  r = do_start("personal", project, "", return_response=True)
144
128
  if r.status_code != 200:
145
- print(r.text)
129
+ print_generic_error(r.text)
146
130
  sys.exit(0)
147
131
  else:
148
- sys.stderr.write(f"Got http status code {r.status_code}")
132
+ print_generic_error(f"Got http status code {r.status_code}")
149
133
  raise typer.Exit(0)
150
134
  else:
151
135
  r = Rest.handle_get(url=f"/api/project/{project}/brokers/{broker}", return_response=True, allow_status_codes=[404])
@@ -154,10 +138,10 @@ def mount( # noqa: C901
154
138
  if ensure_broker_started:
155
139
  r = do_start(broker, project, "", return_response=True)
156
140
  if r.status_code != 200:
157
- print(r.text)
141
+ print_generic_error(r.text)
158
142
  sys.exit(1)
159
143
  else:
160
- ErrorPrinter.print_generic_error(f"Broker {broker} not running")
144
+ print_generic_error(f"Broker {broker} not running")
161
145
  sys.exit(1)
162
146
  elif r.status_code != 200:
163
147
  sys.stderr.write(f"Got http status code {r.status_code}")
@@ -175,8 +159,8 @@ def mount( # noqa: C901
175
159
  return_response=True,
176
160
  progress_label="Preparing recording on broker...",
177
161
  )
178
- err_console.print("Successfully mounted recording on broker")
179
- print(json.dumps(broker_info))
162
+ print_unformatted_to_stderr("Successfully mounted recording on broker")
163
+ print_unformatted(json.dumps(broker_info))
180
164
 
181
165
 
182
166
  @app.command(help="Downloads the specified recording file to disk")
@@ -198,9 +182,9 @@ def download_recording_file(
198
182
  if get_signed_url_resp.status_code == 200:
199
183
  # Next download the actual file
200
184
  Rest.download_file(Path(recording_file_name), get_signed_url_resp.json()["downloadUrl"])
201
- print(f"Downloaded {recording_file_name}")
185
+ print_success(f"Downloaded {recording_file_name}")
202
186
  else:
203
- print(get_signed_url_resp)
187
+ print_generic_error(get_signed_url_resp.text)
204
188
 
205
189
 
206
190
  @app.command(name="delete")
@@ -267,10 +251,8 @@ def upload( # noqa: C901, PLR0912, PLR0915
267
251
  if match:
268
252
  upload_id = match.group(1)
269
253
  else:
270
- ErrorPrinter.print_generic_error(
271
- "Something went wrong, please try again. Please contact RemotiveLabs support if this problem remains"
272
- )
273
- ErrorPrinter.print_hint("Please make sure to use the latest version of RemotiveCLI")
254
+ print_generic_error("Something went wrong, please try again. Please contact RemotiveLabs support if this problem remains")
255
+ print_hint("Please make sure to use the latest version of RemotiveCLI")
274
256
  sys.exit(1)
275
257
 
276
258
  upload_response = Rest.upload_file_with_signed_url(
@@ -296,7 +278,6 @@ def upload( # noqa: C901, PLR0912, PLR0915
296
278
  return "Finishing up..."
297
279
  return "Processing..."
298
280
 
299
- # print(response)
300
281
  if 200 <= upload_response.status_code < 300:
301
282
  # We need to print the error message outside the with Progress so the indicator is closed
302
283
  error_message: Union[str, None] = None
@@ -319,17 +300,17 @@ def upload( # noqa: C901, PLR0912, PLR0915
319
300
  if tracking_state["status"] == "FAILED":
320
301
  error_message = f"Processing of uploaded file failed: {tracking_state['errors'][0]['message']}"
321
302
  else:
322
- print("File successfully uploaded")
303
+ print_success("File successfully uploaded")
323
304
  break
324
305
  else:
325
306
  error_message = "Something went wrong, please try again. Please contact RemotiveLabs support if this problem remains"
326
307
  break
327
308
  if error_message is not None:
328
- ErrorPrinter.print_generic_error(error_message)
309
+ print_generic_error(error_message)
329
310
  sys.exit(1)
330
311
 
331
312
  else:
332
- err_console.print(f":boom: [bold red]Got status code[/bold red]: {upload_response.status_code} {upload_response.text}")
313
+ print_generic_error(f"Got status code: {upload_response.status_code} {upload_response.text}")
333
314
 
334
315
 
335
316
  # TODO - Change to use Path for directory
@@ -412,8 +393,7 @@ def upload_broker_configuration(
412
393
  if response is None:
413
394
  return
414
395
  if response.status_code != 200:
415
- print("Failed to prepare configuration upload")
416
- print(f"{response.text} - {response.status_code}")
396
+ print_generic_error(f"Failed to prepare configuration upload: {response.text} - {response.status_code}")
417
397
  raise typer.Exit(1)
418
398
 
419
399
  #
@@ -430,12 +410,10 @@ def upload_broker_configuration(
430
410
  headers = {"Content-Type": "application/x-www-form-urlencoded"}
431
411
  r = requests.put(url, open(path, "rb"), headers=headers, timeout=60)
432
412
  if r.status_code != 200:
433
- print("Failed to upload broker configuration")
434
- print(r.status_code)
435
- print(r.text)
413
+ print_generic_error(f"Failed to upload broker configuration: {r.text} - {r.status_code}")
436
414
  raise typer.Exit(1)
437
415
 
438
- print(f"Successfully uploaded broker configuration {broker_config_dir_name}")
416
+ print_success(f"Uploaded broker configuration {broker_config_dir_name}")
439
417
 
440
418
 
441
419
  @app.command(help="Downloads the specified broker configuration directory as zip file")
@@ -454,7 +432,7 @@ def download_broker_configuration(
454
432
  if filename is not None:
455
433
  with open(filename, "wb") as f:
456
434
  f.write(r.content)
457
- print(f"Downloaded file {filename}")
435
+ print_success(f"Downloaded file {filename}")
458
436
 
459
437
 
460
438
  @app.command(help="Delete the specified broker configuration")
@@ -546,8 +524,8 @@ def _do_change_playback_mode( # noqa: PLR0912
546
524
  broker_arg = ""
547
525
  if broker_name is not None:
548
526
  broker_arg = f" --broker {broker_name} --ensure-broker-started"
549
- ErrorPrinter.print_generic_error("You need to mount the recording before you play")
550
- ErrorPrinter.print_hint(f"remotive cloud recordings mount {recording_session}{broker_arg} --project {project}")
527
+ print_generic_error("You need to mount the recording before you play")
528
+ print_hint(f"remotive cloud recordings mount {recording_session}{broker_arg} --project {project}")
551
529
  sys.exit(1)
552
530
 
553
531
  broker_info = json.loads(response.text)
@@ -561,18 +539,14 @@ def _do_change_playback_mode( # noqa: PLR0912
561
539
  with open(tmp, "r", encoding="utf8") as f:
562
540
  json_context = json.loads(f.read())
563
541
  if json_context["recordingSessionId"] != recording_session:
564
- ErrorPrinter.print_generic_error(
542
+ print_generic_error(
565
543
  f"The recording id mounted is '{json_context['recordingSessionId']}' "
566
544
  f"which not the same as you are trying to {mode}, use cmd below to mount this recording"
567
545
  )
568
- ErrorPrinter.print_hint(f"remotive cloud recordings mount {recording_session} --project {project}")
546
+ print_hint(f"remotive cloud recordings mount {recording_session} --project {project}")
569
547
  sys.exit(1)
570
548
  except grpc.RpcError as rpc_error:
571
- # if rpc_error.code() == grpc.StatusCode.NOT_FOUND:
572
- # ErrorPrinter.print_generic_error(f"You must use mount to prepare a recording before you can use {mode}")
573
- # ErrorPrinter.print_hint(f"remotive cloud recordings mount {recording_session} --project {project}")
574
- # else:
575
- ErrorPrinter.print_grpc_error(rpc_error)
549
+ print_grpc_error(rpc_error)
576
550
  sys.exit(1)
577
551
  if mode == "pause":
578
552
  broker.pause_play(files, True)
@@ -9,12 +9,10 @@ from pathlib import Path
9
9
  from typing import Any, List, Union
10
10
 
11
11
  import grpc
12
- import rich
13
12
  import typer
14
- from rich import print as rich_print
15
13
  from rich.progress import Progress, SpinnerColumn, TextColumn
16
14
 
17
- from cli.errors import ErrorPrinter
15
+ from cli.utils.console import print_generic_error, print_generic_message, print_grpc_error, print_hint, print_unformatted
18
16
  from cli.utils.rest_helper import RestHelper as Rest
19
17
 
20
18
  from ..broker.lib.broker import Broker, SubscribableSignal
@@ -127,11 +125,11 @@ def subscribe( # noqa: PLR0913
127
125
  """
128
126
  if script is None:
129
127
  if len(signal) == 0:
130
- ErrorPrinter.print_generic_error("You must use include at least one signal and one namespace or use script when subscribing")
128
+ print_generic_error("You must use include at least one signal and one namespace or use script when subscribing")
131
129
  sys.exit(1)
132
130
  if script is not None:
133
131
  if len(signal) > 0:
134
- ErrorPrinter.print_generic_error("You must must not specify --signal when using --script")
132
+ print_generic_error("You must must not specify --signal when using --script")
135
133
  sys.exit(1)
136
134
 
137
135
  broker_client = _get_broker_info(project, recording_session, broker, "subscribe")
@@ -139,24 +137,26 @@ def subscribe( # noqa: PLR0913
139
137
  try:
140
138
  if script is not None:
141
139
  script_src = read_scripted_code_file(script)
142
- broker_client.subscribe_on_script(script_src, lambda sig: rich_print(json.dumps(list(sig))), on_change_only)
140
+ broker_client.subscribe_on_script(script_src, lambda sig: print_generic_message(json.dumps(list(sig))), on_change_only)
143
141
  else:
144
142
 
145
143
  def to_subscribable_signal(sig: str):
146
144
  arr = sig.split(":")
147
145
  if len(arr) != 2:
148
- ErrorPrinter.print_hint(f"--signal must have format namespace:signal ({sig})")
146
+ print_hint(f"--signal must have format namespace:signal ({sig})")
149
147
  sys.exit(1)
150
148
  return SubscribableSignal(namespace=arr[0], name=arr[1])
151
149
 
152
150
  signals_to_subscribe_to = list(map(to_subscribable_signal, signal))
153
- broker_client.long_name_subscribe(signals_to_subscribe_to, lambda sig: rich_print(json.dumps(list(sig))), on_change_only)
154
- print("Subscribing to signals, press Ctrl+C to exit")
151
+ broker_client.long_name_subscribe(
152
+ signals_to_subscribe_to, lambda sig: print_generic_message(json.dumps(list(sig))), on_change_only
153
+ )
154
+ print_generic_message("Subscribing to signals, press Ctrl+C to exit")
155
155
  except grpc.RpcError as rpc_error:
156
- ErrorPrinter.print_grpc_error(rpc_error)
156
+ print_grpc_error(rpc_error)
157
157
 
158
158
  except Exception as e:
159
- ErrorPrinter.print_generic_error(str(e))
159
+ print_generic_error(str(e))
160
160
  sys.exit(1)
161
161
 
162
162
 
@@ -184,8 +184,8 @@ def _do_change_playback_mode( # noqa: C901, PLR0913, PLR0912
184
184
  broker_arg = ""
185
185
  if brokerstr is not None:
186
186
  broker_arg = f" --broker {brokerstr} --ensure-broker-started"
187
- ErrorPrinter.print_generic_error("You need to mount the recording before you play")
188
- ErrorPrinter.print_hint(f"remotive cloud recordings mount {recording_session}{broker_arg} --project {project}")
187
+ print_generic_error("You need to mount the recording before you play")
188
+ print_hint(f"remotive cloud recordings mount {recording_session}{broker_arg} --project {project}")
189
189
  sys.exit(1)
190
190
 
191
191
  broker_info = json.loads(response.text)
@@ -216,7 +216,7 @@ def _track_progress(broker: Broker, repeat: bool, files: List[Any]) -> None:
216
216
  p = Progress(SpinnerColumn(), TextColumn("[progress.description]{task.description}"), transient=True)
217
217
  t = p.add_task("label", total=1)
218
218
  if repeat:
219
- rich.print(":point_right: Keep this command running in terminal to keep the recording play with repeat")
219
+ print_unformatted(":point_right: Keep this command running in terminal to keep the recording play with repeat")
220
220
  with p:
221
221
 
222
222
  def print_progress(offset: int, total: int, current_mode: str) -> None:
@@ -238,18 +238,18 @@ def _verify_recording_on_broker(broker: Broker, recording_session: str, mode: st
238
238
  with open(tmp, "r", encoding="utf8") as f:
239
239
  json_context = json.loads(f.read())
240
240
  if json_context["recordingSessionId"] != recording_session:
241
- ErrorPrinter.print_generic_error(
241
+ print_generic_error(
242
242
  f"The recording id mounted is '{json_context['recordingSessionId']}' "
243
243
  f"which not the same as you are trying to {mode}, use cmd below to mount this recording"
244
244
  )
245
- ErrorPrinter.print_hint(f"remotive cloud recordings mount {recording_session} --project {project}")
245
+ print_hint(f"remotive cloud recordings mount {recording_session} --project {project}")
246
246
  sys.exit(1)
247
247
  except grpc.RpcError as rpc_error:
248
248
  if rpc_error.code() == grpc.StatusCode.NOT_FOUND:
249
- ErrorPrinter.print_generic_error(f"You must use mount to prepare a recording before you can use {mode}")
250
- ErrorPrinter.print_hint(f"remotive cloud recordings mount {recording_session} --project {project}")
249
+ print_generic_error(f"You must use mount to prepare a recording before you can use {mode}")
250
+ print_hint(f"remotive cloud recordings mount {recording_session} --project {project}")
251
251
  else:
252
- ErrorPrinter.print_grpc_error(rpc_error)
252
+ print_grpc_error(rpc_error)
253
253
  sys.exit(1)
254
254
 
255
255
 
@@ -260,14 +260,14 @@ def _get_broker_info(project: str, recording_session: str, broker: Union[str, No
260
260
  broker_name = broker if broker is not None else "personal"
261
261
  response = Rest.handle_get(f"/api/project/{project}/brokers/{broker_name}", return_response=True, allow_status_codes=[404])
262
262
  if response is None:
263
- ErrorPrinter.print_generic_error(f"No response from: /api/project/{project}/brokers/{broker_name}")
263
+ print_generic_error(f"No response from: /api/project/{project}/brokers/{broker_name}")
264
264
  sys.exit(1)
265
265
  if response.status_code == 404:
266
266
  broker_arg = ""
267
267
  if broker is not None:
268
268
  broker_arg = f"--broker {broker} --ensure-broker-started"
269
- ErrorPrinter.print_generic_error("You need to mount the recording before you play")
270
- ErrorPrinter.print_hint(f"remotive cloud recordings mount {recording_session} {broker_arg} --project {project}")
269
+ print_generic_error("You need to mount the recording before you play")
270
+ print_hint(f"remotive cloud recordings mount {recording_session} {broker_arg} --project {project}")
271
271
  sys.exit(1)
272
272
  broker_info = json.loads(response.text)
273
273
  broker_client = Broker(broker_info["url"], None)
@@ -8,7 +8,7 @@ from typing import Dict
8
8
  import requests
9
9
  from rich.progress import wrap_file
10
10
 
11
- from ..errors import ErrorPrinter
11
+ from cli.utils.console import print_generic_error, print_success
12
12
 
13
13
 
14
14
  def __get_uploaded_bytes(upload_url: str) -> int:
@@ -40,7 +40,7 @@ def with_resumable_upload_signed_url(signed_url: str, source_file_name: str, con
40
40
  headers = {"x-goog-resumable": "start", "content-type": content_type}
41
41
  response = requests.post(signed_url, headers=headers, timeout=60)
42
42
  if response.status_code not in (200, 201, 308):
43
- ErrorPrinter.print_generic_error(f"Failed to upload file: {response.status_code} - {response.text}")
43
+ print_generic_error(f"Failed to upload file: {response.status_code} - {response.text}")
44
44
  sys.exit(1)
45
45
 
46
46
  upload_url = response.headers["Location"]
@@ -61,10 +61,10 @@ def with_resumable_upload_signed_url(signed_url: str, source_file_name: str, con
61
61
  headers = {"Content-Range": f"bytes {chunk_start}-{chunk_end}/{file_size}"}
62
62
  response = requests.put(upload_url, headers=headers, data=chunk, timeout=60)
63
63
  if response.status_code not in (200, 201, 308):
64
- ErrorPrinter.print_generic_error(f"Failed to upload file: {response.status_code} - {response.text}")
64
+ print_generic_error(f"Failed to upload file: {response.status_code} - {response.text}")
65
65
  sys.exit(1)
66
66
 
67
- print(f"File {source_file_name} uploaded successfully.")
67
+ print_success(f"File {source_file_name} uploaded successfully.")
68
68
 
69
69
 
70
70
  def upload_signed_url(signed_url: str, source_file_name: Path, headers: Dict[str, str]) -> None:
@@ -81,7 +81,7 @@ def upload_signed_url(signed_url: str, source_file_name: Path, headers: Dict[str
81
81
  with wrap_file(file, os.stat(source_file_name).st_size, description=f"Uploading {source_file_name}...") as f:
82
82
  response = requests.put(signed_url, headers=headers, timeout=60, data=f)
83
83
  if response.status_code not in (200, 201, 308):
84
- ErrorPrinter.print_generic_error(f"Failed to upload file: {response.status_code} - {response.text}")
84
+ print_generic_error(f"Failed to upload file: {response.status_code} - {response.text}")
85
85
  sys.exit(1)
86
86
 
87
- print(f"File {source_file_name} uploaded successfully.")
87
+ print_success(f"File {source_file_name} uploaded successfully.")
@@ -4,6 +4,7 @@ import typer
4
4
 
5
5
  from cli.settings import settings
6
6
  from cli.typer import typer_utils
7
+ from cli.utils.console import print_generic_message, print_success
7
8
  from cli.utils.rest_helper import RestHelper as Rest
8
9
 
9
10
  app = typer_utils.create_typer()
@@ -23,8 +24,8 @@ def create(
23
24
  )
24
25
 
25
26
  sat = settings.add_service_account_token(response.text)
26
- print(f"Service account access token added: {sat.name}")
27
- print("\033[93m This file contains secrets and must be kept safe")
27
+ print_success(f"Service account access token added: {sat.name}")
28
+ print_generic_message("This file contains secrets and must be kept safe")
28
29
 
29
30
 
30
31
  @app.command(name="list", help="List service account access tokens")
cli/cloud/storage/cmd.py CHANGED
@@ -7,15 +7,14 @@ from cli.cloud.storage.copy import copy
7
7
  from cli.cloud.storage.uri_or_path import UriOrPath
8
8
  from cli.cloud.storage.uri_or_path import uri as uri_parser
9
9
  from cli.cloud.uri import URI, InvalidURIError, JoinURIError
10
- from cli.errors import ErrorPrinter
11
10
  from cli.typer import typer_utils
11
+ from cli.utils.console import print_hint
12
12
  from cli.utils.rest_helper import RestHelper as Rest
13
13
 
14
14
  HELP = """
15
15
  Manage files ([yellow]Beta feature not available for all customers[/yellow])
16
16
 
17
17
  Copy file from local to remote storage and vice versa, list and delete files.
18
-
19
18
  """
20
19
 
21
20
  app = typer_utils.create_typer(rich_markup_mode="rich", help=HELP)
@@ -73,5 +72,5 @@ def copy_file(
73
72
  try:
74
73
  return copy(project=project, source=source.value, dest=dest.value, overwrite=overwrite)
75
74
  except (InvalidURIError, JoinURIError, ValueError, FileNotFoundError, FileExistsError) as e:
76
- ErrorPrinter.print_hint(str(e))
75
+ print_hint(str(e))
77
76
  sys.exit(1)
cli/cloud/storage/copy.py CHANGED
@@ -5,6 +5,7 @@ from pathlib import Path
5
5
 
6
6
  from cli.cloud.resumable_upload import upload_signed_url
7
7
  from cli.cloud.uri import URI
8
+ from cli.utils.console import print_success
8
9
  from cli.utils.rest_helper import RestHelper as Rest
9
10
 
10
11
  _RCS_STORAGE_PATH = "/api/project/{project}/files/storage{path}"
@@ -63,7 +64,7 @@ def _upload_single_file(source: Path, target_uri: URI, project: str, overwrite:
63
64
  headers = json_res["headers"]
64
65
  upload_signed_url(url, source, headers)
65
66
 
66
- print(f"Uploaded {source} to {target_uri.path}")
67
+ print_success(f"Uploaded {source} to {target_uri.path}")
67
68
 
68
69
 
69
70
  def _download(source: URI, dest: Path, project: str, overwrite: bool = False) -> None:
cli/connect/connect.py CHANGED
@@ -8,8 +8,8 @@ import typer
8
8
  from typing_extensions import List
9
9
 
10
10
  from cli.broker.lib.broker import SubscribableSignal
11
- from cli.errors import ErrorPrinter
12
11
  from cli.typer import typer_utils
12
+ from cli.utils.console import print_hint
13
13
 
14
14
  from .protopie import protopie as ppie
15
15
 
@@ -81,18 +81,18 @@ def protopie( # noqa: PLR0913
81
81
  """
82
82
 
83
83
  if len(signal) > 0 and config is not None:
84
- ErrorPrinter.print_hint("You must choose either --signal or --config, not both")
84
+ print_hint("You must choose either --signal or --config, not both")
85
85
  sys.exit(1)
86
86
 
87
87
  if len(signal) == 0 and config is None:
88
- ErrorPrinter.print_hint("You must choose either --signal or --config")
88
+ print_hint("You must choose either --signal or --config")
89
89
  sys.exit(1)
90
90
 
91
91
  def to_subscribable_signal(sig: str) -> SubscribableSignal:
92
92
  arr = sig.split(":")
93
93
 
94
94
  if len(arr) != 2:
95
- ErrorPrinter.print_hint(f"--signal must have format namespace:signal ({sig})")
95
+ print_hint(f"--signal must have format namespace:signal ({sig})")
96
96
  sys.exit(1)
97
97
 
98
98
  return SubscribableSignal(namespace=arr[0], name=arr[1])
@@ -5,27 +5,22 @@ import json
5
5
  import os
6
6
  import sys
7
7
  import time
8
- import traceback
9
8
  from pathlib import Path
10
9
  from typing import Any, Dict, List, Tuple, Union
11
10
 
12
11
  import grpc
13
12
  import socketio
14
- from rich import print as pretty_print
15
- from rich.console import Console
16
13
  from socketio.exceptions import ConnectionError as SocketIoConnectionError
17
14
 
18
15
  from cli.broker.lib.broker import SubscribableSignal
19
16
  from cli.broker.lib.client import BrokerException, Client, SignalIdentifier, SignalsInFrame
20
- from cli.errors import ErrorPrinter
21
17
  from cli.settings import settings
18
+ from cli.utils.console import print_generic_error, print_generic_message, print_success, print_unformatted_to_stderr
22
19
 
23
20
  PP_CONNECT_APP_NAME = "RemotiveBridge"
24
21
 
25
22
  io = socketio.Client()
26
23
 
27
- err_console = Console(stderr=True)
28
-
29
24
  _has_received_signal = False
30
25
  is_connected = False
31
26
  config_path: Path
@@ -35,7 +30,7 @@ broker: Any
35
30
 
36
31
  @io.on("connect")
37
32
  def on_connect() -> None:
38
- print("Connected to ProtoPie Connect")
33
+ print_success("Connected to ProtoPie Connect")
39
34
  io.emit("ppBridgeApp", {"name": PP_CONNECT_APP_NAME})
40
35
  io.emit("PLUGIN_STARTED", {"name": PP_CONNECT_APP_NAME})
41
36
 
@@ -72,8 +67,8 @@ def get_signal_name(expression: str, s_name: str) -> str:
72
67
  sig_name = eval(f"s_name.{expression}")
73
68
  return str(sig_name)
74
69
  except Exception as e:
75
- ErrorPrinter.print_generic_error(f"Failed to evaluate your python expression {expression}")
76
- err_console.print(e)
70
+ print_generic_error(f"Failed to evaluate your python expression {expression}")
71
+ print_unformatted_to_stderr(e)
77
72
  # This was the only way I could make this work, exiting on another thread than main
78
73
  os._exit(1)
79
74
  else:
@@ -91,7 +86,7 @@ def _connect_to_broker(
91
86
  def on_signals(frame: SignalsInFrame) -> None:
92
87
  global _has_received_signal # noqa: PLW0603
93
88
  if not _has_received_signal:
94
- pretty_print("Bridge-app is properly receiving signals, you are good to go :thumbsup:")
89
+ print_generic_message("Bridge-app is properly receiving signals, you are good to go :thumbsup:")
95
90
  _has_received_signal = True
96
91
 
97
92
  for s in frame:
@@ -114,42 +109,42 @@ def grpc_connect(
114
109
  on_signals: Any, signals_to_subscribe_to: Union[List[SignalIdentifier], None] = None, on_change_only: bool = False
115
110
  ) -> None:
116
111
  try:
117
- pretty_print("Connecting and subscribing to broker...")
112
+ print_generic_message("Connecting and subscribing to broker...")
118
113
  subscription = None
119
114
  client = Client(client_id="cli")
120
115
  client.connect(url=broker, api_key=x_api_key)
121
116
  client.on_signals = on_signals
122
117
 
123
118
  if signals_to_subscribe_to is None:
124
- print("No sigs")
119
+ # TODO: use logs instead of print?
120
+ print_generic_error("No signals to subscribe to")
125
121
  return
126
122
  subscription = client.subscribe(signals_to_subscribe_to=signals_to_subscribe_to, changed_values_only=on_change_only)
127
- pretty_print("Subscription to broker completed")
128
- pretty_print("Waiting for signals...")
123
+ print_generic_message("Subscription to broker completed")
124
+ print_generic_message("Waiting for signals...")
129
125
 
130
126
  while True:
131
127
  time.sleep(1)
132
128
 
133
129
  except grpc.RpcError as e:
134
- err_console.print(":boom: [red]Problems connecting or subscribing[/red]")
130
+ print_generic_error("Problems connecting or subscribing")
135
131
  if isinstance(e, grpc.Call):
136
- print(f"{e.code()} - {e.details()}")
132
+ print_generic_error(f"{e.code()} - {e.details()}")
137
133
  else:
138
- print(e)
134
+ print_generic_error(e)
139
135
 
140
136
  except BrokerException as e:
141
- print(e)
137
+ print_generic_error(e)
142
138
  if subscription is not None:
143
139
  subscription.cancel()
144
140
 
145
141
  except KeyboardInterrupt:
146
- print("Keyboard interrupt received. Closing subscription.")
142
+ print_generic_message("Keyboard interrupt received. Closing subscription.")
147
143
  if subscription is not None:
148
144
  subscription.cancel()
149
145
 
150
146
  except Exception as e:
151
- print(traceback.format_exc())
152
- err_console.print(f":boom: {e}")
147
+ print_generic_error(e)
153
148
 
154
149
 
155
150
  def do_connect( # noqa: PLR0913
@@ -168,7 +163,7 @@ def do_connect( # noqa: PLR0913
168
163
 
169
164
  if broker_url.startswith("https"):
170
165
  if api_key is None:
171
- print("No --api-key, reading token from file")
166
+ print_generic_message("No --api-key, reading token from file")
172
167
  x_api_key = settings.get_active_token_secret()
173
168
  else:
174
169
  x_api_key = api_key
@@ -176,18 +171,15 @@ def do_connect( # noqa: PLR0913
176
171
  x_api_key = api_key
177
172
  try:
178
173
  io.connect(address)
179
- # if config is None:
180
- # raise ValueError("Config is None")
181
174
  config_path = config
182
175
  while is_connected is None:
183
176
  time.sleep(1)
184
- # if expression is not None:
185
177
  _connect_to_broker(signals_to_subscribe_to=signals, config=config, expression=expression, on_change_only=on_change_only)
186
178
  except SocketIoConnectionError as e:
187
- err_console.print(":boom: [bold red]Failed to connect to ProtoPie Connect[/bold red]")
188
- err_console.print(e)
179
+ print_generic_error("Failed to connect to ProtoPie Connect")
180
+ print_unformatted_to_stderr(e)
189
181
  sys.exit(1)
190
182
  except Exception as e:
191
- err_console.print(":boom: [bold red]Unexpected error[/bold red]")
192
- err_console.print(e)
183
+ print_generic_error("Unexpected error")
184
+ print_unformatted_to_stderr(e)
193
185
  sys.exit(1)