remotivelabs-cli 0.0.25__py3-none-any.whl → 0.0.27__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. cli/broker/brokers.py +2 -2
  2. cli/broker/export.py +5 -5
  3. cli/broker/files.py +5 -5
  4. cli/broker/lib/broker.py +82 -51
  5. cli/broker/license_flows.py +11 -9
  6. cli/broker/licenses.py +2 -2
  7. cli/broker/playback.py +14 -34
  8. cli/broker/record.py +3 -3
  9. cli/broker/scripting.py +4 -4
  10. cli/broker/signals.py +20 -12
  11. cli/cloud/__init__.py +0 -1
  12. cli/cloud/auth.py +40 -35
  13. cli/cloud/auth_tokens.py +73 -37
  14. cli/cloud/brokers.py +24 -33
  15. cli/cloud/cloud_cli.py +7 -18
  16. cli/cloud/configs.py +28 -11
  17. cli/cloud/filestorage.py +63 -51
  18. cli/cloud/organisations.py +30 -0
  19. cli/cloud/projects.py +11 -8
  20. cli/cloud/recordings.py +148 -117
  21. cli/cloud/recordings_playback.py +52 -39
  22. cli/cloud/rest_helper.py +247 -196
  23. cli/cloud/resumable_upload.py +9 -8
  24. cli/cloud/sample_recordings.py +5 -5
  25. cli/cloud/service_account_tokens.py +18 -16
  26. cli/cloud/service_accounts.py +9 -9
  27. cli/connect/__init__.py +0 -1
  28. cli/connect/connect.py +7 -6
  29. cli/connect/protopie/protopie.py +32 -16
  30. cli/errors.py +6 -5
  31. cli/remotive.py +13 -9
  32. cli/requirements.txt +4 -1
  33. cli/settings.py +9 -9
  34. cli/tools/__init__.py +0 -1
  35. cli/tools/can/__init__.py +0 -1
  36. cli/tools/can/can.py +8 -8
  37. cli/tools/tools.py +2 -2
  38. {remotivelabs_cli-0.0.25.dist-info → remotivelabs_cli-0.0.27.dist-info}/METADATA +5 -3
  39. remotivelabs_cli-0.0.27.dist-info/RECORD +45 -0
  40. remotivelabs_cli-0.0.25.dist-info/RECORD +0 -44
  41. {remotivelabs_cli-0.0.25.dist-info → remotivelabs_cli-0.0.27.dist-info}/LICENSE +0 -0
  42. {remotivelabs_cli-0.0.25.dist-info → remotivelabs_cli-0.0.27.dist-info}/WHEEL +0 -0
  43. {remotivelabs_cli-0.0.25.dist-info → remotivelabs_cli-0.0.27.dist-info}/entry_points.txt +0 -0
@@ -3,20 +3,21 @@ from __future__ import annotations
3
3
  import datetime
4
4
  import json
5
5
  import os
6
+ import sys
6
7
  import tempfile
7
8
  from pathlib import Path
8
- from typing import List, Union
9
+ from typing import Any, List, Union
9
10
 
10
11
  import grpc
11
12
  import rich
12
13
  import typer
13
- from rich import print as rich_rprint
14
+ from rich import print as rich_print
14
15
  from rich.progress import Progress, SpinnerColumn, TextColumn
15
16
 
16
17
  from cli.errors import ErrorPrinter
17
18
 
18
19
  from ..broker.lib.broker import Broker, SubscribableSignal
19
- from . import rest_helper as rest
20
+ from .rest_helper import RestHelper as Rest
20
21
 
21
22
  app = typer.Typer(
22
23
  help="""
@@ -32,7 +33,7 @@ def play(
32
33
  project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT"),
33
34
  show_progress: bool = typer.Option(False, help="Show progress after started playing"),
34
35
  repeat: bool = typer.Option(False, help="Repeat recording - must keep command running in terminal"),
35
- ):
36
+ ) -> None:
36
37
  """
37
38
  Start playing a recording.
38
39
  There is no problem invoking play multiple times since if it is already playing the command will be ignored.
@@ -47,7 +48,7 @@ def pause(
47
48
  recording_session: str = typer.Argument(..., help="Recording session id", envvar="REMOTIVE_CLOUD_RECORDING_SESSION"),
48
49
  broker: str = typer.Option(None, help="Broker to use"),
49
50
  project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT"),
50
- ):
51
+ ) -> None:
51
52
  """
52
53
  Pause a recording
53
54
  """
@@ -59,7 +60,7 @@ def progress(
59
60
  recording_session: str = typer.Argument(..., help="Recording session id", envvar="REMOTIVE_CLOUD_RECORDING_SESSION"),
60
61
  broker: str = typer.Option(None, help="Broker to use"),
61
62
  project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT"),
62
- ):
63
+ ) -> None:
63
64
  """
64
65
  Shows progress of the recording playing.
65
66
  Use --repeat to have the recording replayed when it reaches the end.
@@ -73,7 +74,7 @@ def seek(
73
74
  seconds: int = typer.Option(..., min=0, help="Target offset in seconds"),
74
75
  broker: str = typer.Option(None, help="Broker to use"),
75
76
  project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT"),
76
- ):
77
+ ) -> None:
77
78
  """
78
79
  Seek seconds into a recording
79
80
  """
@@ -85,7 +86,7 @@ def stop(
85
86
  recording_session: str = typer.Argument(..., help="Recording session id", envvar="REMOTIVE_CLOUD_RECORDING_SESSION"),
86
87
  broker: str = typer.Option(None, help="Broker to use"),
87
88
  project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT"),
88
- ):
89
+ ) -> None:
89
90
  """
90
91
  Stop playing
91
92
  """
@@ -99,6 +100,7 @@ def read_scripted_code_file(file_path: Path) -> bytes:
99
100
  return file.read()
100
101
 
101
102
 
103
+ # pylint: disable=R0913
102
104
  @app.command()
103
105
  def subscribe(
104
106
  recording_session: str = typer.Argument(..., help="Recording session id", envvar="REMOTIVE_CLOUD_RECORDING_SESSION"),
@@ -116,7 +118,7 @@ def subscribe(
116
118
  ),
117
119
  on_change_only: bool = typer.Option(default=False, help="Only get signal if value is changed"),
118
120
  project: str = typer.Option(..., help="Project ID", envvar="REMOTIVE_CLOUD_PROJECT"),
119
- ):
121
+ ) -> None:
120
122
  """
121
123
  Allows you to subscribe to signals based on a mounted recording without knowing the broker URL.
122
124
  This simplifies when playing recordings from the cloud.
@@ -126,61 +128,66 @@ def subscribe(
126
128
  if script is None:
127
129
  if len(signal) == 0:
128
130
  ErrorPrinter.print_generic_error("You must use include at least one signal and one namespace or use script when subscribing")
129
- exit(1)
131
+ sys.exit(1)
130
132
  if script is not None:
131
133
  if len(signal) > 0:
132
134
  ErrorPrinter.print_generic_error("You must must not specify --signal when using --script")
133
- exit(1)
135
+ sys.exit(1)
134
136
 
135
137
  broker_client = _get_broker_info(project, recording_session, broker, "subscribe")
136
138
 
137
139
  try:
138
140
  if script is not None:
139
141
  script_src = read_scripted_code_file(script)
140
- broker_client.subscribe_on_script(script_src, lambda sig: rich_rprint(json.dumps(list(sig))), on_change_only)
142
+ broker_client.subscribe_on_script(script_src, lambda sig: rich_print(json.dumps(list(sig))), on_change_only)
141
143
  else:
142
144
 
143
145
  def to_subscribable_signal(sig: str):
144
146
  arr = sig.split(":")
145
147
  if len(arr) != 2:
146
148
  ErrorPrinter.print_hint(f"--signal must have format namespace:signal ({sig})")
147
- exit(1)
149
+ sys.exit(1)
148
150
  return SubscribableSignal(namespace=arr[0], name=arr[1])
149
151
 
150
152
  signals_to_subscribe_to = list(map(to_subscribable_signal, signal))
151
- broker_client.long_name_subscribe(signals_to_subscribe_to, lambda sig: rich_rprint(json.dumps(list(sig))), on_change_only)
153
+ broker_client.long_name_subscribe(signals_to_subscribe_to, lambda sig: rich_print(json.dumps(list(sig))), on_change_only)
152
154
  print("Subscribing to signals, press Ctrl+C to exit")
153
155
  except grpc.RpcError as rpc_error:
154
156
  ErrorPrinter.print_grpc_error(rpc_error)
155
157
 
156
- except Exception as e:
157
- ErrorPrinter.print_generic_error(e)
158
- exit(1)
158
+ except Exception as e: # pylint: disable=W0718
159
+ ErrorPrinter.print_generic_error(str(e))
160
+ sys.exit(1)
159
161
 
160
162
 
161
- def _do_change_playback_mode(
163
+ def _do_change_playback_mode( # noqa: C901
162
164
  mode: str,
163
165
  recording_session: str,
164
- broker: str,
166
+ brokerstr: str,
165
167
  project: str,
166
168
  seconds: int | None = None,
167
169
  progress_on_play: bool = False,
168
170
  repeat: bool = False,
169
- ): # noqa: C901
170
- response = rest.handle_get(f"/api/project/{project}/files/recording/{recording_session}", return_response=True)
171
+ ) -> None: # noqa: C901
172
+ # pylint: disable=R0913,R0912
173
+ response = Rest.handle_get(f"/api/project/{project}/files/recording/{recording_session}", return_response=True)
174
+ if response is None:
175
+ return
171
176
  r = json.loads(response.text)
172
- recordings: list = r["recordings"]
177
+ recordings: List[Any] = r["recordings"]
173
178
  files = list(map(lambda rec: {"recording": rec["fileName"], "namespace": rec["metadata"]["namespace"]}, recordings))
174
179
 
175
- broker_name = broker if broker is not None else "personal"
176
- response = rest.handle_get(f"/api/project/{project}/brokers/{broker_name}", return_response=True, allow_status_codes=[404])
180
+ broker_name = brokerstr if brokerstr is not None else "personal"
181
+ response = Rest.handle_get(f"/api/project/{project}/brokers/{broker_name}", return_response=True, allow_status_codes=[404])
182
+ if response is None:
183
+ return
177
184
  if response.status_code == 404:
178
185
  broker_arg = ""
179
- if broker is not None:
180
- broker_arg = f" --broker {broker} --ensure-broker-started"
186
+ if brokerstr is not None:
187
+ broker_arg = f" --broker {brokerstr} --ensure-broker-started"
181
188
  ErrorPrinter.print_generic_error("You need to mount the recording before you play")
182
189
  ErrorPrinter.print_hint(f"remotive cloud recordings mount {recording_session}{broker_arg} --project {project}")
183
- exit(1)
190
+ sys.exit(1)
184
191
 
185
192
  broker_info = json.loads(response.text)
186
193
  broker = Broker(broker_info["url"], None)
@@ -194,23 +201,26 @@ def _do_change_playback_mode(
194
201
  if progress_on_play or repeat:
195
202
  _track_progress(broker, repeat, files)
196
203
  elif mode == "seek":
197
- broker.seek(files, int(seconds * 1000000), True)
204
+ if seconds is not None:
205
+ broker.seek(files, int(seconds * 1000000), True)
206
+ else:
207
+ broker.seek(files, 0, True)
198
208
  elif mode == "stop":
199
209
  broker.seek(files, 0, True)
200
210
  elif mode == "status":
201
211
  _track_progress(broker, repeat, files)
202
212
  else:
203
- raise Exception(f"Illegal command {mode}")
213
+ raise ValueError(f"Illegal command {mode}")
204
214
 
205
215
 
206
- def _track_progress(broker: Broker, repeat: bool, files: List):
216
+ def _track_progress(broker: Broker, repeat: bool, files: List[Any]) -> None:
207
217
  p = Progress(SpinnerColumn(), TextColumn("[progress.description]{task.description}"), transient=True)
208
218
  t = p.add_task("label", total=1)
209
219
  if repeat:
210
220
  rich.print(":point_right: Keep this command running in terminal to keep the recording play with repeat")
211
221
  with p:
212
222
 
213
- def print_progress(offset: int, total: int, current_mode: str):
223
+ def print_progress(offset: int, total: int, current_mode: str) -> None:
214
224
  p.update(
215
225
  t,
216
226
  description=f"{(datetime.timedelta(seconds=offset))} " f"/ {(datetime.timedelta(seconds=total))} ({current_mode})",
@@ -219,14 +229,14 @@ def _track_progress(broker: Broker, repeat: bool, files: List):
219
229
  broker.listen_on_playback(repeat, files, print_progress)
220
230
 
221
231
 
222
- def _verify_recording_on_broker(broker: Broker, recording_session: str, mode: str, project: str):
232
+ def _verify_recording_on_broker(broker: Broker, recording_session: str, mode: str, project: str) -> None:
223
233
  try:
224
234
  # Here we try to verify that we are operating on a recording that is mounted on the
225
235
  # broker so we can verify this before we try playback and can also present some good
226
236
  # error messages
227
237
  tmp = os.path.join(tempfile.gettempdir(), os.urandom(24).hex())
228
238
  broker.download(".cloud.context", tmp, True)
229
- with open(tmp, "r") as f:
239
+ with open(tmp, "r", encoding="utf8") as f:
230
240
  json_context = json.loads(f.read())
231
241
  if json_context["recordingSessionId"] != recording_session:
232
242
  ErrorPrinter.print_generic_error(
@@ -234,29 +244,32 @@ def _verify_recording_on_broker(broker: Broker, recording_session: str, mode: st
234
244
  f"which not the same as you are trying to {mode}, use cmd below to mount this recording"
235
245
  )
236
246
  ErrorPrinter.print_hint(f"remotive cloud recordings mount {recording_session} --project {project}")
237
- exit(1)
247
+ sys.exit(1)
238
248
  except grpc.RpcError as rpc_error:
239
- if rpc_error.code() == grpc.StatusCode.NOT_FOUND:
249
+ if rpc_error.code() == grpc.StatusCode.NOT_FOUND: # pylint: disable=no-member
240
250
  ErrorPrinter.print_generic_error(f"You must use mount to prepare a recording before you can use {mode}")
241
251
  ErrorPrinter.print_hint(f"remotive cloud recordings mount {recording_session} --project {project}")
242
252
  else:
243
253
  ErrorPrinter.print_grpc_error(rpc_error)
244
- exit(1)
254
+ sys.exit(1)
245
255
 
246
256
 
247
257
  def _get_broker_info(project: str, recording_session: str, broker: Union[str, None], mode: str) -> Broker:
248
258
  # Verify it exists
249
- rest.handle_get(f"/api/project/{project}/files/recording/{recording_session}", return_response=True)
259
+ Rest.handle_get(f"/api/project/{project}/files/recording/{recording_session}", return_response=True)
250
260
 
251
261
  broker_name = broker if broker is not None else "personal"
252
- response = rest.handle_get(f"/api/project/{project}/brokers/{broker_name}", return_response=True, allow_status_codes=[404])
262
+ response = Rest.handle_get(f"/api/project/{project}/brokers/{broker_name}", return_response=True, allow_status_codes=[404])
263
+ if response is None:
264
+ ErrorPrinter.print_generic_error(f"No response from: /api/project/{project}/brokers/{broker_name}")
265
+ sys.exit(1)
253
266
  if response.status_code == 404:
254
267
  broker_arg = ""
255
268
  if broker is not None:
256
269
  broker_arg = f"--broker {broker} --ensure-broker-started"
257
270
  ErrorPrinter.print_generic_error("You need to mount the recording before you play")
258
271
  ErrorPrinter.print_hint(f"remotive cloud recordings mount {recording_session} {broker_arg} --project {project}")
259
- exit(1)
272
+ sys.exit(1)
260
273
  broker_info = json.loads(response.text)
261
274
  broker_client = Broker(broker_info["url"], None)
262
275
  _verify_recording_on_broker(broker_client, recording_session, mode, project)