thestage 0.6.4__py3-none-any.whl → 0.6.6__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 (73) hide show
  1. thestage/__init__.py +1 -1
  2. thestage/color_scheme/color_scheme.py +1 -0
  3. thestage/controllers/base_controller.py +4 -3
  4. thestage/controllers/config_controller.py +16 -4
  5. thestage/controllers/container_controller.py +147 -49
  6. thestage/controllers/instance_controller.py +35 -9
  7. thestage/controllers/project_controller.py +334 -86
  8. thestage/entities/container.py +5 -3
  9. thestage/entities/project_inference_simulator.py +2 -1
  10. thestage/entities/project_inference_simulator_model.py +1 -1
  11. thestage/entities/project_task.py +2 -3
  12. thestage/entities/rented_instance.py +2 -2
  13. thestage/entities/self_hosted_instance.py +2 -2
  14. thestage/helpers/error_handler.py +3 -3
  15. thestage/services/clients/git/git_client.py +8 -12
  16. thestage/services/clients/thestage_api/api_client.py +144 -109
  17. thestage/services/clients/thestage_api/dtos/base_controller/connect_resolve_response.py +21 -0
  18. thestage/services/clients/thestage_api/dtos/container_param_request.py +1 -1
  19. thestage/services/clients/thestage_api/dtos/container_response.py +1 -21
  20. thestage/services/clients/thestage_api/dtos/docker_container_controller/docker_container_list_request.py +2 -1
  21. thestage/services/clients/thestage_api/dtos/inference_controller/deploy_inference_model_to_instance_request.py +7 -1
  22. thestage/services/clients/thestage_api/dtos/inference_controller/deploy_inference_model_to_instance_response.py +0 -1
  23. thestage/services/clients/thestage_api/dtos/inference_controller/deploy_inference_model_to_sagemaker_request.py +1 -0
  24. thestage/services/clients/thestage_api/dtos/inference_controller/get_inference_simulator_request.py +2 -1
  25. thestage/services/clients/thestage_api/dtos/inference_controller/{inference_simulator_list_for_project_request.py → inference_simulator_list_request.py} +3 -2
  26. thestage/services/clients/thestage_api/dtos/inference_controller/{inference_simulator_list_for_project_response.py → inference_simulator_list_response.py} +1 -1
  27. thestage/services/clients/thestage_api/dtos/inference_controller/inference_simulator_model_list_for_project_request.py +2 -1
  28. thestage/services/clients/thestage_api/dtos/instance_rented_response.py +4 -37
  29. thestage/services/clients/thestage_api/dtos/logging_controller/log_polling_request.py +3 -3
  30. thestage/services/clients/thestage_api/dtos/logging_controller/user_logs_query_request.py +3 -11
  31. thestage/services/clients/thestage_api/dtos/project_controller/project_get_deploy_ssh_key_request.py +1 -0
  32. thestage/services/clients/thestage_api/dtos/project_controller/project_push_inference_simulator_model_request.py +2 -1
  33. thestage/services/clients/thestage_api/dtos/project_controller/project_run_task_request.py +2 -4
  34. thestage/services/clients/thestage_api/dtos/project_controller/project_start_inference_simulator_request.py +5 -3
  35. thestage/services/clients/thestage_api/dtos/project_response.py +3 -15
  36. thestage/services/clients/thestage_api/dtos/selfhosted_instance_response.py +2 -20
  37. thestage/services/clients/thestage_api/dtos/ssh_key_controller/add_ssh_key_to_user_response.py +1 -1
  38. thestage/services/clients/thestage_api/dtos/ssh_key_controller/add_ssh_public_key_to_instance_request.py +4 -2
  39. thestage/services/clients/thestage_api/dtos/ssh_key_controller/is_user_has_public_ssh_key_response.py +1 -1
  40. thestage/services/clients/thestage_api/dtos/task_controller/task_list_for_project_request.py +4 -1
  41. thestage/services/clients/thestage_api/dtos/task_controller/task_view_response.py +0 -2
  42. thestage/services/config_provider/config_provider.py +2 -2
  43. thestage/services/connect/connect_service.py +76 -73
  44. thestage/services/container/container_service.py +23 -19
  45. thestage/services/container/mapper/container_mapper.py +2 -1
  46. thestage/services/instance/instance_service.py +13 -20
  47. thestage/services/instance/mapper/instance_mapper.py +1 -3
  48. thestage/services/instance/mapper/selfhosted_mapper.py +3 -4
  49. thestage/services/logging/logging_service.py +40 -40
  50. thestage/services/project/dto/inference_simulator_dto.py +1 -10
  51. thestage/services/project/dto/inference_simulator_model_dto.py +2 -10
  52. thestage/services/project/dto/project_config.py +3 -2
  53. thestage/services/project/mapper/project_inference_simulator_mapper.py +1 -0
  54. thestage/services/project/mapper/project_inference_simulator_model_mapper.py +3 -3
  55. thestage/services/project/mapper/project_task_mapper.py +2 -3
  56. thestage/services/project/project_service.py +161 -131
  57. thestage/services/remote_server_service.py +1 -0
  58. thestage/services/task/dto/task_dto.py +3 -23
  59. {thestage-0.6.4.dist-info → thestage-0.6.6.dist-info}/METADATA +3 -2
  60. {thestage-0.6.4.dist-info → thestage-0.6.6.dist-info}/RECORD +63 -72
  61. {thestage-0.6.4.dist-info → thestage-0.6.6.dist-info}/WHEEL +1 -1
  62. thestage/services/clients/thestage_api/dtos/cloud_provider_region.py +0 -19
  63. thestage/services/clients/thestage_api/dtos/docker_container_assigned_device.py +0 -10
  64. thestage/services/clients/thestage_api/dtos/enums/currency_type.py +0 -10
  65. thestage/services/clients/thestage_api/dtos/enums/daemon_status.py +0 -9
  66. thestage/services/clients/thestage_api/dtos/enums/disk_type.py +0 -7
  67. thestage/services/clients/thestage_api/dtos/enums/drive_type.py +0 -7
  68. thestage/services/clients/thestage_api/dtos/enums/instance_type.py +0 -7
  69. thestage/services/clients/thestage_api/dtos/enums/location_region.py +0 -11
  70. thestage/services/clients/thestage_api/dtos/enums/power_status.py +0 -10
  71. thestage/services/clients/thestage_api/dtos/price_definition.py +0 -14
  72. {thestage-0.6.4.dist-info → thestage-0.6.6.dist-info}/entry_points.txt +0 -0
  73. {thestage-0.6.4.dist-info → thestage-0.6.6.dist-info/licenses}/LICENSE.txt +0 -0
@@ -80,11 +80,13 @@ class ProjectService(AbstractService):
80
80
  @error_handler()
81
81
  def init_project(
82
82
  self,
83
- project_slug: str,
83
+ project_slug: Optional[str] = None,
84
+ project_public_id: Optional[str] = None,
84
85
  ):
85
86
  config = self.__config_provider.get_config()
86
- project: Optional[ProjectDto] = self.__thestage_api_client.get_project_by_slug(
87
+ project: Optional[ProjectDto] = self.__thestage_api_client.get_project(
87
88
  slug=project_slug,
89
+ public_id=project_public_id,
88
90
  )
89
91
 
90
92
  if not project:
@@ -119,13 +121,12 @@ class ProjectService(AbstractService):
119
121
  raise typer.Exit(0)
120
122
 
121
123
  deploy_ssh_key = self.__thestage_api_client.get_project_deploy_ssh_key(
122
- slug=project.slug,
124
+ public_id=project.public_id,
123
125
  )
124
126
 
125
127
  deploy_key_path = self.__config_provider.save_project_deploy_ssh_key(
126
128
  deploy_ssh_key=deploy_ssh_key,
127
- project_slug=project.slug,
128
- project_id=project.id,
129
+ project_public_id=project.public_id,
129
130
  )
130
131
 
131
132
  if is_git_folder:
@@ -156,7 +157,7 @@ class ProjectService(AbstractService):
156
157
  self.__git_local_client.git_add_all(repo_path=config.runtime.working_directory)
157
158
 
158
159
  project_config = ProjectConfig()
159
- project_config.id = project.id
160
+ project_config.public_id = project.public_id
160
161
  project_config.slug = project.slug
161
162
  project_config.git_repository_url = project.git_repository_url
162
163
  project_config.deploy_key_path = str(deploy_key_path)
@@ -169,10 +170,12 @@ class ProjectService(AbstractService):
169
170
  def clone_project(
170
171
  self,
171
172
  project_slug: str,
173
+ project_public_id: str
172
174
  ):
173
175
  config = self.__config_provider.get_config()
174
- project: Optional[ProjectDto] = self.__thestage_api_client.get_project_by_slug(
176
+ project: Optional[ProjectDto] = self.__thestage_api_client.get_project(
175
177
  slug=project_slug,
178
+ public_id=project_public_id
176
179
  )
177
180
 
178
181
  if not project:
@@ -195,8 +198,8 @@ class ProjectService(AbstractService):
195
198
  typer.echo(__("Unexpected Project error, missing Repository"))
196
199
  raise typer.Exit(1)
197
200
 
198
- deploy_ssh_key = self.__thestage_api_client.get_project_deploy_ssh_key(slug=project.slug)
199
- deploy_key_path = self.__config_provider.save_project_deploy_ssh_key(deploy_ssh_key=deploy_ssh_key, project_slug=project.slug, project_id=project.id)
201
+ deploy_ssh_key = self.__thestage_api_client.get_project_deploy_ssh_key(public_id=project.public_id)
202
+ deploy_key_path = self.__config_provider.save_project_deploy_ssh_key(deploy_ssh_key=deploy_ssh_key, project_public_id=project.public_id,)
200
203
 
201
204
  try:
202
205
  self.__git_local_client.clone(
@@ -217,7 +220,7 @@ class ProjectService(AbstractService):
217
220
  raise typer.Exit(1)
218
221
 
219
222
  project_config = ProjectConfig()
220
- project_config.id = project.id
223
+ project_config.public_id = project.public_id
221
224
  project_config.slug = project.slug
222
225
  project_config.git_repository_url = project.git_repository_url
223
226
  project_config.deploy_key_path = str(deploy_key_path)
@@ -229,9 +232,10 @@ class ProjectService(AbstractService):
229
232
  def project_run_task(
230
233
  self,
231
234
  run_command: str,
235
+ docker_container_slug: str,
236
+ docker_container_public_id: str,
232
237
  task_title: Optional[str] = None,
233
238
  commit_hash: Optional[str] = None,
234
- docker_container_slug: Optional[str] = None,
235
239
  files_to_add: Optional[str] = None,
236
240
  is_skip_auto_commit: Optional[bool] = False,
237
241
  ) -> Optional[TaskDto]:
@@ -241,34 +245,39 @@ class ProjectService(AbstractService):
241
245
  typer.echo(__("No project found at the path: %path%. Please initialize or clone a project first.", {"path": config.runtime.working_directory}))
242
246
  raise typer.Exit(1)
243
247
 
244
- if not docker_container_slug and not project_config.default_container_uid:
245
- typer.echo(__('Docker container unique ID is required'))
248
+ if not docker_container_public_id and not docker_container_slug and not project_config.default_container_public_id:
249
+ typer.echo(__('Docker container ID or name is required'))
246
250
  raise typer.Exit(1)
247
251
 
248
- container_slug_for_task = docker_container_slug if docker_container_slug else project_config.default_container_uid
249
-
250
- if not docker_container_slug:
251
- typer.echo(f"Using default docker container for this project: '{container_slug_for_task}'")
252
+ final_container_public_id = docker_container_public_id
253
+ final_container_slug = docker_container_slug
254
+ if not final_container_public_id and not final_container_slug:
255
+ final_container_public_id = project_config.default_container_public_id
256
+ typer.echo(f"Using default docker container for this project: '{project_config.default_container_public_id}'")
252
257
 
253
258
  container: DockerContainerDto = self.__thestage_api_client.get_container(
254
- container_slug=container_slug_for_task,
259
+ container_slug=final_container_slug,
260
+ container_public_id=final_container_public_id
255
261
  )
256
262
 
257
263
  if container is None:
258
- typer.echo(f"Could not find container '{container_slug_for_task}'")
259
- if project_config.default_container_uid == container_slug_for_task:
260
- project_config.default_container_uid = None
264
+ if final_container_slug:
265
+ typer.echo(f"Could not find container with name '{final_container_slug}'")
266
+ if final_container_public_id:
267
+ typer.echo(f"Could not find container with ID '{final_container_public_id}'")
268
+ if project_config.default_container_public_id == final_container_public_id:
269
+ project_config.default_container_public_id = None
261
270
  project_config.prompt_for_default_container = True
262
271
  self.__config_provider.save_project_config(project_config=project_config)
263
272
  typer.echo(f"Default container settings were reset")
264
273
  raise typer.Exit(1)
265
274
 
266
- if container.project_id != project_config.id:
267
- typer.echo(f"Provided container '{docker_container_slug}' is not related to project '{project_config.slug}'")
275
+ if container.project.public_id != project_config.public_id:
276
+ typer.echo(f"Provided container '{container.public_id}' is not related to project '{project_config.public_id}'")
268
277
  raise typer.Exit(1)
269
278
 
270
- if (project_config.prompt_for_default_container is None or project_config.prompt_for_default_container) and docker_container_slug and (project_config.default_container_uid != docker_container_slug):
271
- set_default_container_slug: str = typer.prompt(
279
+ if (project_config.prompt_for_default_container is None or project_config.prompt_for_default_container) and (docker_container_slug or docker_container_public_id) and (project_config.default_container_public_id != container.public_id):
280
+ set_default_container_answer: str = typer.prompt(
272
281
  text=f"Would you like to set '{docker_container_slug}' as a default container for this project installation?",
273
282
  show_choices=True,
274
283
  default=YesOrNoResponse.YES.value,
@@ -276,8 +285,8 @@ class ProjectService(AbstractService):
276
285
  show_default=True,
277
286
  )
278
287
  project_config.prompt_for_default_container = False
279
- if set_default_container_slug == YesOrNoResponse.YES.value:
280
- project_config.default_container_uid = docker_container_slug
288
+ if set_default_container_answer == YesOrNoResponse.YES.value:
289
+ project_config.default_container_public_id = container.public_id
281
290
 
282
291
  self.__config_provider.save_project_config(project_config=project_config)
283
292
 
@@ -395,8 +404,8 @@ class ProjectService(AbstractService):
395
404
  typer.echo(f'Commit message is empty. Task title is set to "{task_title}"')
396
405
 
397
406
  run_task_response: ProjectRunTaskResponse = self.__thestage_api_client.execute_project_task(
398
- project_slug=project_config.slug,
399
- docker_container_slug=container_slug_for_task,
407
+ project_public_id=project_config.public_id,
408
+ docker_container_public_id=container.public_id,
400
409
  run_command=run_command,
401
410
  commit_hash=commit_hash,
402
411
  task_title=task_title,
@@ -405,7 +414,7 @@ class ProjectService(AbstractService):
405
414
  if run_task_response.message:
406
415
  print(f"[{ColorScheme.WARNING.value}]{run_task_response.message}[{ColorScheme.WARNING.value}]")
407
416
  if run_task_response.is_success and run_task_response.task:
408
- typer.echo(f"Task '{run_task_response.task.title}' has been scheduled successfully. Task ID: {run_task_response.task.id}")
417
+ typer.echo(f"Task '{run_task_response.task.title}' has been scheduled successfully. Task ID: {run_task_response.task.public_id}")
409
418
  return run_task_response.task
410
419
  else:
411
420
  typer.echo(f'The task failed with an error: {run_task_response.message}')
@@ -415,23 +424,25 @@ class ProjectService(AbstractService):
415
424
  raise typer.Exit(1)
416
425
 
417
426
  @error_handler()
418
- def cancel_task(self, task_id: int):
427
+ def cancel_task(self, task_public_id: str):
419
428
  cancel_result = self.__thestage_api_client.cancel_task(
420
- task_id=task_id,
429
+ task_public_id=task_public_id,
421
430
  )
422
431
 
423
432
  if cancel_result.is_success:
424
- typer.echo(f'Task {task_id} has been canceled')
433
+ typer.echo(f'Task {task_public_id} has been canceled')
425
434
  else:
426
- typer.echo(f'Task {task_id} could not be canceled: {cancel_result.message}')
435
+ typer.echo(f'Task {task_public_id} could not be canceled: {cancel_result.message}')
427
436
 
428
437
 
429
438
  @error_handler()
430
439
  def project_run_inference_simulator(
431
440
  self,
432
441
  commit_hash: Optional[str] = None,
433
- rented_instance_unique_id: Optional[str] = None,
434
- self_hosted_instance_unique_id: Optional[str] = None,
442
+ rented_instance_public_id: Optional[str] = None,
443
+ rented_instance_slug: Optional[str] = None,
444
+ self_hosted_instance_public_id: Optional[str] = None,
445
+ self_hosted_instance_slug: Optional[str] = None,
435
446
  inference_dir: Optional[str] = None,
436
447
  is_skip_installation: Optional[bool] = False,
437
448
  files_to_add: Optional[str] = None,
@@ -444,16 +455,12 @@ class ProjectService(AbstractService):
444
455
  {"path": config.runtime.working_directory}))
445
456
  raise typer.Exit(1)
446
457
 
447
- if rented_instance_unique_id and self_hosted_instance_unique_id:
448
- typer.echo(__("Error: Cannot provide both rented and self-hosted instance unique IDs."))
449
- raise typer.Exit(1)
450
-
451
- if not rented_instance_unique_id and not self_hosted_instance_unique_id:
452
- typer.echo(__("Error: Either a rented instance ID or a self-hosted instance unique ID must be provided."))
458
+ instance_args_count = sum(v is not None for v in [rented_instance_public_id, rented_instance_slug, self_hosted_instance_public_id, self_hosted_instance_slug])
459
+ if instance_args_count != 1:
460
+ typer.echo("Please provide a single instance (rented or self-hosted) identifier - name or ID.")
453
461
  raise typer.Exit(1)
454
462
 
455
463
  has_wrong_args = files_to_add and commit_hash or is_skip_auto_commit and commit_hash or files_to_add and is_skip_auto_commit
456
-
457
464
  if has_wrong_args:
458
465
  warning_msg = f"[{ColorScheme.WARNING.value}][WARNING] You can provide only one of the following arguments: --commit-hash, --files-add, --skip-autocommit[{ColorScheme.WARNING.value}]"
459
466
  print(warning_msg)
@@ -555,10 +562,12 @@ class ProjectService(AbstractService):
555
562
  commit_hash = commit.hexsha
556
563
 
557
564
  start_inference_simulator_response: ProjectStartInferenceSimulatorResponse = self.__thestage_api_client.start_project_inference_simulator(
558
- project_slug=project_config.slug,
565
+ project_public_id=project_config.public_id,
559
566
  commit_hash=commit_hash,
560
- rented_instance_unique_id=rented_instance_unique_id,
561
- self_hosted_instance_unique_id=self_hosted_instance_unique_id,
567
+ rented_instance_public_id=rented_instance_public_id,
568
+ rented_instance_slug=rented_instance_slug,
569
+ self_hosted_instance_public_id=self_hosted_instance_public_id,
570
+ self_hosted_instance_slug=self_hosted_instance_slug,
562
571
  inference_dir=inference_dir,
563
572
  is_skip_installation=is_skip_installation,
564
573
  )
@@ -582,10 +591,12 @@ class ProjectService(AbstractService):
582
591
  @error_handler()
583
592
  def project_push_inference_simulator(
584
593
  self,
594
+ public_id: Optional[str] = None,
585
595
  slug: Optional[str] = None,
586
596
  ):
587
597
 
588
598
  push_inference_simulator_model_response: ProjectPushInferenceSimulatorModelResponse = self.__thestage_api_client.push_project_inference_simulator_model(
599
+ public_id=public_id,
589
600
  slug=slug,
590
601
  )
591
602
  if push_inference_simulator_model_response:
@@ -606,11 +617,13 @@ class ProjectService(AbstractService):
606
617
  @error_handler()
607
618
  def project_get_and_save_inference_simulator_metadata(
608
619
  self,
609
- slug: Optional[str] = None,
620
+ inference_simulator_public_id: Optional[str] = None,
621
+ inference_simulator_slug: Optional[str] = None,
610
622
  file_path: Optional[str] = None,
611
623
  ):
612
624
  get_inference_metadata_response: GetInferenceSimulatorResponse = self.__thestage_api_client.get_inference_simulator(
613
- slug=slug,
625
+ public_id=inference_simulator_public_id,
626
+ slug=inference_simulator_slug,
614
627
  )
615
628
 
616
629
  metadata = get_inference_metadata_response.inferenceSimulator.qlip_serve_metadata
@@ -643,13 +656,15 @@ class ProjectService(AbstractService):
643
656
  @error_handler()
644
657
  def get_project_inference_simulator_list(
645
658
  self,
646
- project_slug: str,
659
+ project_public_id: Optional[str],
660
+ project_slug: Optional[str],
647
661
  statuses: List[str],
648
662
  row: int = 5,
649
663
  page: int = 1,
650
664
  ) -> PaginatedEntityList[InferenceSimulatorDto]:
651
- data: Optional[PaginatedEntityList[InferenceSimulatorDto]] = self.__thestage_api_client.get_inference_simulator_list_for_project(
665
+ data: Optional[PaginatedEntityList[InferenceSimulatorDto]] = self.__thestage_api_client.get_inference_simulator_list(
652
666
  statuses=statuses,
667
+ project_public_id=project_public_id,
653
668
  project_slug=project_slug,
654
669
  page=page,
655
670
  limit=row,
@@ -661,7 +676,8 @@ class ProjectService(AbstractService):
661
676
  @error_handler()
662
677
  def get_project_inference_simulator_model_list(
663
678
  self,
664
- project_slug: str,
679
+ project_public_id: Optional[str],
680
+ project_slug: Optional[str],
665
681
  statuses: List[str],
666
682
  row: int = 5,
667
683
  page: int = 1,
@@ -669,22 +685,7 @@ class ProjectService(AbstractService):
669
685
  data: Optional[
670
686
  PaginatedEntityList[InferenceSimulatorModelDto]] = self.__thestage_api_client.get_inference_simulator_model_list_for_project(
671
687
  statuses=statuses,
672
- project_slug=project_slug,
673
- page=page,
674
- limit=row,
675
- )
676
-
677
- return data
678
-
679
-
680
- @error_handler()
681
- def get_project_task_list(
682
- self,
683
- project_slug: str,
684
- row: int = 5,
685
- page: int = 1,
686
- ) -> PaginatedEntityList[TaskDto]:
687
- data: Optional[PaginatedEntityList[TaskDto]] = self.__thestage_api_client.get_task_list_for_project(
688
+ project_public_id=project_public_id,
688
689
  project_slug=project_slug,
689
690
  page=page,
690
691
  limit=row,
@@ -696,7 +697,7 @@ class ProjectService(AbstractService):
696
697
  @error_handler()
697
698
  def checkout_project(
698
699
  self,
699
- task_id: Optional[int],
700
+ task_public_id: Optional[str],
700
701
  branch_name: Optional[str],
701
702
  ):
702
703
  config = self.__config_provider.get_config()
@@ -706,21 +707,21 @@ class ProjectService(AbstractService):
706
707
  raise typer.Exit(1)
707
708
 
708
709
  target_commit_hash: Optional[str] = None
709
- if task_id:
710
+ if task_public_id:
710
711
  task_view_response: Optional[TaskViewResponse] = None
711
712
  try:
712
- task_view_response = self.__thestage_api_client.get_task(task_id=task_id,)
713
+ task_view_response = self.__thestage_api_client.get_task(task_public_id=task_public_id)
713
714
  except HttpClientException as e:
714
715
  if e.get_status_code() == 400:
715
- typer.echo(f"Task {task_id} was not found")
716
+ typer.echo(f"Task {task_public_id} was not found")
716
717
  # overriding arguments here
717
- branch_name = str(task_id)
718
- task_id = None
718
+ branch_name = str(task_public_id)
719
+ task_public_id = None
719
720
 
720
721
  if task_view_response and task_view_response.task:
721
722
  target_commit_hash = task_view_response.task.commit_hash
722
723
  if not target_commit_hash:
723
- typer.echo(f"Provided task ({task_id}) has no commit hash") # possible legacy problems
724
+ typer.echo(f"Provided task ({task_public_id}) has no commit hash") # possible legacy problems
724
725
  raise typer.Exit(1)
725
726
 
726
727
  is_commit_allowed: bool = True
@@ -833,48 +834,40 @@ class ProjectService(AbstractService):
833
834
 
834
835
 
835
836
  @error_handler()
836
- def set_default_container(self, container_uid: Optional[str]):
837
+ def set_default_container(
838
+ self,
839
+ container_public_id: Optional[str],
840
+ container_slug: Optional[str],
841
+ ):
837
842
  project_config: ProjectConfig = self.__config_provider.read_project_config()
838
843
 
839
844
  if project_config is None:
840
845
  typer.echo(f"No project found in working directory")
841
846
  raise typer.Exit(1)
842
847
 
843
- if container_uid:
848
+ container: Optional[DockerContainerDto] = None
849
+ if container_slug or container_public_id:
844
850
  container: DockerContainerDto = self.__thestage_api_client.get_container(
845
- container_slug=container_uid,
851
+ container_public_id=container_public_id,
852
+ container_slug=container_slug,
846
853
  )
847
854
  if container is None:
848
- typer.echo(f"Could not find container '{container_uid}'")
855
+ typer.echo(f"Could not find container '{container_slug or container_public_id}'")
849
856
  raise typer.Exit(1)
850
857
 
851
- if container.project_id != project_config.id:
852
- typer.echo(f"Provided container '{container_uid}' is not related to project '{project_config.slug}'")
858
+ if container.project.public_id != project_config.public_id:
859
+ typer.echo(f"Provided container '{container_slug or container_public_id}' is not related to current project '{project_config.public_id}'")
853
860
  raise typer.Exit(1)
854
861
 
855
862
  if container.frontend_status.status_key != DockerContainerStatus.RUNNING:
856
- typer.echo(f"Note: provided container '{container_uid}' is in status '{container.frontend_status.status_translation}'")
863
+ typer.echo(f"Note: provided container '{container_slug or container_public_id}' is in status '{container.frontend_status.status_translation}'")
857
864
 
858
- project_config.default_container_uid = container_uid
865
+ project_config.default_container_public_id = container.public_id if container else None
859
866
  project_config.prompt_for_default_container = False
860
867
  self.__config_provider.save_project_config(project_config=project_config)
861
868
  typer.echo("Default container settings were updated")
862
869
 
863
870
 
864
- @error_handler()
865
- def unset_default_container(self):
866
- project_config: ProjectConfig = self.__config_provider.read_project_config()
867
-
868
- if project_config is None:
869
- typer.echo(f"No project found in working directory")
870
- raise typer.Exit(1)
871
-
872
- project_config.default_container_uid = None
873
- project_config.prompt_for_default_container = True # True or False?
874
- self.__config_provider.save_project_config(project_config=project_config)
875
- typer.echo("Default container settings were updated")
876
-
877
-
878
871
  @error_handler()
879
872
  def print_project_config(self):
880
873
  project_config: ProjectConfig = self.__config_provider.read_project_config()
@@ -888,10 +881,13 @@ class ProjectService(AbstractService):
888
881
  typer.echo(tabulate(
889
882
  [
890
883
  [
891
- "Project unique ID", project_config.slug
884
+ "Project ID", project_config.public_id
892
885
  ],
893
886
  [
894
- "Default docker container unique ID", project_config.default_container_uid if project_config.default_container_uid else "<None>"
887
+ "Project name", project_config.slug
888
+ ],
889
+ [
890
+ "Default docker container ID", project_config.default_container_public_id if project_config.default_container_public_id else "<None>"
895
891
  ],
896
892
  [
897
893
  "Deploy key path", project_config.deploy_key_path if is_deploy_key_exists else "<None>"
@@ -913,15 +909,19 @@ class ProjectService(AbstractService):
913
909
  if project_config is None:
914
910
  return None
915
911
 
912
+ if project_config.public_id is None:
913
+ project = self.__thestage_api_client.get_project(public_id=None, slug=project_config.slug)
914
+ project_config.public_id = project.public_id
915
+ self.__config_provider.save_project_config(project_config=project_config)
916
+
916
917
  if not Path(project_config.deploy_key_path).is_file():
917
918
  deploy_ssh_key = self.__thestage_api_client.get_project_deploy_ssh_key(
918
- slug=project_config.slug,
919
+ public_id=project_config.public_id,
919
920
  )
920
921
 
921
922
  deploy_key_path = self.__config_provider.save_project_deploy_ssh_key(
922
923
  deploy_ssh_key=deploy_ssh_key,
923
- project_slug=project_config.slug,
924
- project_id=project_config.id,
924
+ project_public_id=project_config.public_id,
925
925
  )
926
926
 
927
927
  project_config.deploy_key_path = deploy_key_path
@@ -933,10 +933,13 @@ class ProjectService(AbstractService):
933
933
  @error_handler()
934
934
  def project_deploy_inference_simulator_model_to_instance(
935
935
  self,
936
- unique_id: Optional[str] = None,
937
- unique_id_with_timestamp: Optional[str] = None,
938
- rented_instance_unique_id: Optional[str] = None,
939
- self_hosted_instance_unique_id: Optional[str] = None,
936
+ model_public_id: Optional[str] = None,
937
+ model_slug: Optional[str] = None,
938
+ new_inference_simulator_slug: Optional[str] = None,
939
+ rented_instance_public_id: Optional[str] = None,
940
+ rented_instance_slug: Optional[str] = None,
941
+ self_hosted_instance_public_id: Optional[str] = None,
942
+ self_hosted_instance_slug: Optional[str] = None,
940
943
  ) -> None:
941
944
  config = self.__config_provider.get_config()
942
945
  project_config: ProjectConfig = self.__get_fixed_project_config()
@@ -946,20 +949,25 @@ class ProjectService(AbstractService):
946
949
  {"path": config.runtime.working_directory}))
947
950
  raise typer.Exit(1)
948
951
 
949
- if rented_instance_unique_id and self_hosted_instance_unique_id:
950
- typer.echo(__("Error: Cannot provide both rented and self-hosted instance unique IDs."))
952
+ instance_args_count = sum(v is not None for v in [rented_instance_public_id, rented_instance_slug, self_hosted_instance_public_id, self_hosted_instance_slug])
953
+ if instance_args_count != 1:
954
+ typer.echo("Please provide a single instance (rented or self-hosted) identifier - name or ID.")
951
955
  raise typer.Exit(1)
952
956
 
953
- if not rented_instance_unique_id and not self_hosted_instance_unique_id:
954
- typer.echo(__("Error: Either a rented instance ID or a self-hosted instance unique ID must be provided."))
957
+ model_args_count = sum(v is not None for v in [model_public_id, model_slug])
958
+ if model_args_count != 1:
959
+ typer.echo("Please provide a single model identifier - name or ID.")
955
960
  raise typer.Exit(1)
956
961
 
957
- typer.echo(__("Creating inference simulator with unique ID: %unique_id_with_timestamp%", {"unique_id_with_timestamp": unique_id_with_timestamp}))
962
+ typer.echo(f"Creating inference simulator with unique ID: {new_inference_simulator_slug}")
958
963
  deploy_model_to_instance_response: DeployInferenceModelToInstanceResponse = self.__thestage_api_client.deploy_inference_model_to_instance(
959
- unique_id=unique_id,
960
- unique_id_with_timestamp=unique_id_with_timestamp,
961
- rented_instance_unique_id=rented_instance_unique_id,
962
- self_hosted_instance_unique_id=self_hosted_instance_unique_id
964
+ model_public_id=model_public_id,
965
+ model_slug=model_slug,
966
+ new_inference_simulator_slug=new_inference_simulator_slug,
967
+ rented_instance_public_id=rented_instance_public_id,
968
+ rented_instance_slug=rented_instance_slug,
969
+ self_hosted_instance_public_id=self_hosted_instance_public_id,
970
+ self_hosted_instance_slug=self_hosted_instance_slug,
963
971
  )
964
972
  if deploy_model_to_instance_response:
965
973
  if deploy_model_to_instance_response.message:
@@ -980,7 +988,8 @@ class ProjectService(AbstractService):
980
988
  @error_handler()
981
989
  def project_deploy_inference_simulator_model_to_sagemaker(
982
990
  self,
983
- unique_id: Optional[str] = None,
991
+ model_public_id: Optional[str] = None,
992
+ model_slug: Optional[str] = None,
984
993
  arn: Optional[str] = None,
985
994
  instance_type: Optional[str] = None,
986
995
  initial_variant_weight: Optional[float] = 1.0,
@@ -1013,7 +1022,8 @@ class ProjectService(AbstractService):
1013
1022
  raise typer.Exit(1)
1014
1023
 
1015
1024
  deploy_model_to_sagemaker_response: DeployInferenceModelToSagemakerResponse = self.__thestage_api_client.deploy_inference_model_to_sagemaker(
1016
- unique_id=unique_id,
1025
+ model_public_id=model_public_id,
1026
+ model_slug=model_slug,
1017
1027
  arn=arn,
1018
1028
  )
1019
1029
 
@@ -1041,7 +1051,7 @@ class ProjectService(AbstractService):
1041
1051
  },
1042
1052
  }
1043
1053
 
1044
- sm_model_name = f"{unique_id}-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
1054
+ sm_model_name = f"{model_slug}-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
1045
1055
  create_model_response = sm_client.create_model(
1046
1056
  ModelName=sm_model_name,
1047
1057
  ExecutionRoleArn=arn,
@@ -1049,7 +1059,7 @@ class ProjectService(AbstractService):
1049
1059
  )
1050
1060
  typer.echo(f"Model created successfully. Model ARN: {create_model_response['ModelArn']}")
1051
1061
 
1052
- endpoint_config_name = f"{unique_id}-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
1062
+ endpoint_config_name = f"{model_slug}-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
1053
1063
  create_endpoint_config_response = sm_client.create_endpoint_config(
1054
1064
  EndpointConfigName=endpoint_config_name,
1055
1065
  ProductionVariants=[
@@ -1065,7 +1075,7 @@ class ProjectService(AbstractService):
1065
1075
  typer.echo(
1066
1076
  f"Endpoint configuration created successfully. Endpoint Config ARN: {create_endpoint_config_response['EndpointConfigArn']}")
1067
1077
 
1068
- endpoint_name = f"{unique_id}-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
1078
+ endpoint_name = f"{model_slug}-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
1069
1079
  create_endpoint_response = sm_client.create_endpoint(
1070
1080
  EndpointName=endpoint_name,
1071
1081
  EndpointConfigName=endpoint_config_name,
@@ -1128,13 +1138,13 @@ class ProjectService(AbstractService):
1128
1138
 
1129
1139
 
1130
1140
  @error_handler()
1131
- def print_inference_simulator_list(self, project_uid, statuses, row, page):
1132
- if not project_uid:
1141
+ def print_inference_simulator_list(self, project_public_id, project_slug, statuses, row, page):
1142
+ if not project_public_id and not project_slug:
1133
1143
  project_config: ProjectConfig = self.__config_provider.read_project_config()
1134
1144
  if not project_config:
1135
1145
  typer.echo(__("Provide the project unique ID or run this command from within an initialized project directory"))
1136
1146
  raise typer.Exit(1)
1137
- project_uid = project_config.slug
1147
+ project_public_id = project_config.public_id
1138
1148
 
1139
1149
  inference_simulator_status_map = self.__thestage_api_client.get_inference_simulator_business_status_map()
1140
1150
 
@@ -1167,7 +1177,8 @@ class ProjectService(AbstractService):
1167
1177
  self.print(
1168
1178
  func_get_data=self.get_project_inference_simulator_list,
1169
1179
  func_special_params={
1170
- 'project_slug': project_uid,
1180
+ 'project_public_id': project_public_id,
1181
+ 'project_slug': project_slug,
1171
1182
  'statuses': backend_statuses,
1172
1183
  },
1173
1184
  mapper=ProjectInferenceSimulatorMapper(),
@@ -1180,13 +1191,13 @@ class ProjectService(AbstractService):
1180
1191
 
1181
1192
 
1182
1193
  @error_handler()
1183
- def print_inference_simulator_model_list(self, project_uid, statuses, row, page):
1184
- if not project_uid:
1194
+ def print_inference_simulator_model_list(self, project_public_id, project_slug, statuses, row, page):
1195
+ if not project_public_id and not project_slug:
1185
1196
  project_config: ProjectConfig = self.__config_provider.read_project_config()
1186
1197
  if not project_config:
1187
1198
  typer.echo(__("Provide the project unique ID or run this command from within an initialized project directory"))
1188
1199
  raise typer.Exit(1)
1189
- project_uid = project_config.slug
1200
+ project_public_id = project_config.public_id
1190
1201
 
1191
1202
  inference_simulator_model_status_map = self.__thestage_api_client.get_inference_simulator_model_business_status_map()
1192
1203
 
@@ -1219,7 +1230,8 @@ class ProjectService(AbstractService):
1219
1230
  self.print(
1220
1231
  func_get_data=self.get_project_inference_simulator_model_list,
1221
1232
  func_special_params={
1222
- 'project_slug': project_uid,
1233
+ 'project_public_id': project_public_id,
1234
+ 'project_slug': project_slug,
1223
1235
  'statuses': backend_statuses,
1224
1236
  },
1225
1237
  mapper=ProjectInferenceSimulatorModelMapper(),
@@ -1231,18 +1243,19 @@ class ProjectService(AbstractService):
1231
1243
  )
1232
1244
 
1233
1245
 
1234
- def print_task_list(self, project_uid, row, page):
1235
- if not project_uid:
1246
+ def print_task_list(self, project_public_id: Optional[str], project_slug: Optional[str], row, page):
1247
+ if not project_slug and not project_public_id:
1236
1248
  project_config: ProjectConfig = self.__config_provider.read_project_config()
1237
1249
  if not project_config:
1238
1250
  typer.echo(__("Provide the project unique ID or run this command from within an initialized project directory"))
1239
1251
  raise typer.Exit(1)
1240
- project_uid = project_config.slug
1252
+ project_public_id = project_config.public_id
1241
1253
 
1242
1254
  self.print(
1243
1255
  func_get_data=self.get_project_task_list,
1244
1256
  func_special_params={
1245
- 'project_slug': project_uid,
1257
+ 'project_public_id': project_public_id,
1258
+ 'project_slug': project_slug,
1246
1259
  },
1247
1260
  mapper=ProjectTaskMapper(),
1248
1261
  headers=list(map(lambda x: x.alias, ProjectTaskEntity.model_fields.values())),
@@ -1251,3 +1264,20 @@ class ProjectService(AbstractService):
1251
1264
  max_col_width=[100, 100, 100, 100, 100, 100, 100, 100],
1252
1265
  show_index="never",
1253
1266
  )
1267
+
1268
+ @error_handler()
1269
+ def get_project_task_list(
1270
+ self,
1271
+ project_public_id: Optional[str],
1272
+ project_slug: Optional[str],
1273
+ row: int = 5,
1274
+ page: int = 1,
1275
+ ) -> PaginatedEntityList[TaskDto]:
1276
+ data: Optional[PaginatedEntityList[TaskDto]] = self.__thestage_api_client.get_task_list_for_project(
1277
+ project_public_id=project_public_id,
1278
+ project_slug=project_slug,
1279
+ page=page,
1280
+ limit=row,
1281
+ )
1282
+
1283
+ return data
@@ -116,6 +116,7 @@ class RemoteServerService:
116
116
  username: str,
117
117
  private_key_path: Optional[str],
118
118
  ):
119
+ typer.echo(f"Connecting to {username}@{ip_address}")
119
120
  try:
120
121
  if private_key_path:
121
122
  os.system(f"ssh -o PreferredAuthentications=publickey -o 'IdentitiesOnly=yes' -i {private_key_path} {username}@{ip_address}")