thestage 0.6.5__py3-none-any.whl → 0.6.7__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 (75) 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 +151 -106
  6. thestage/controllers/instance_controller.py +35 -9
  7. thestage/controllers/project_controller.py +335 -89
  8. thestage/entities/container.py +5 -3
  9. thestage/entities/project_inference_simulator.py +2 -1
  10. thestage/entities/project_inference_simulator_model.py +2 -2
  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 +1 -1
  15. thestage/main.py +1 -1
  16. thestage/services/clients/git/git_client.py +1 -1
  17. thestage/services/clients/thestage_api/api_client.py +142 -109
  18. thestage/services/clients/thestage_api/dtos/base_controller/connect_resolve_response.py +22 -0
  19. thestage/services/clients/thestage_api/dtos/container_param_request.py +1 -1
  20. thestage/services/clients/thestage_api/dtos/container_response.py +1 -21
  21. thestage/services/clients/thestage_api/dtos/docker_container_controller/docker_container_list_request.py +2 -1
  22. thestage/services/clients/thestage_api/dtos/inference_controller/deploy_inference_model_to_instance_request.py +5 -1
  23. thestage/services/clients/thestage_api/dtos/inference_controller/deploy_inference_model_to_instance_response.py +2 -1
  24. thestage/services/clients/thestage_api/dtos/inference_controller/deploy_inference_model_to_sagemaker_request.py +1 -0
  25. thestage/services/clients/thestage_api/dtos/inference_controller/get_inference_simulator_request.py +2 -1
  26. thestage/services/clients/thestage_api/dtos/inference_controller/{inference_simulator_list_for_project_request.py → inference_simulator_list_request.py} +3 -2
  27. thestage/services/clients/thestage_api/dtos/inference_controller/{inference_simulator_list_for_project_response.py → inference_simulator_list_response.py} +1 -1
  28. thestage/services/clients/thestage_api/dtos/inference_controller/inference_simulator_model_list_for_project_request.py +2 -1
  29. thestage/services/clients/thestage_api/dtos/instance_rented_response.py +4 -37
  30. thestage/services/clients/thestage_api/dtos/logging_controller/log_polling_request.py +3 -3
  31. thestage/services/clients/thestage_api/dtos/logging_controller/user_logs_query_request.py +3 -11
  32. thestage/services/clients/thestage_api/dtos/project_controller/project_get_deploy_ssh_key_request.py +1 -0
  33. thestage/services/clients/thestage_api/dtos/project_controller/project_push_inference_simulator_model_request.py +2 -1
  34. thestage/services/clients/thestage_api/dtos/project_controller/project_run_task_request.py +2 -4
  35. thestage/services/clients/thestage_api/dtos/project_controller/project_run_task_response.py +3 -0
  36. thestage/services/clients/thestage_api/dtos/project_controller/project_start_inference_simulator_request.py +5 -3
  37. thestage/services/clients/thestage_api/dtos/project_response.py +3 -15
  38. thestage/services/clients/thestage_api/dtos/selfhosted_instance_response.py +2 -20
  39. thestage/services/clients/thestage_api/dtos/ssh_key_controller/add_ssh_key_to_user_response.py +1 -1
  40. thestage/services/clients/thestage_api/dtos/ssh_key_controller/add_ssh_public_key_to_instance_request.py +4 -2
  41. thestage/services/clients/thestage_api/dtos/ssh_key_controller/is_user_has_public_ssh_key_response.py +1 -1
  42. thestage/services/clients/thestage_api/dtos/task_controller/task_list_for_project_request.py +4 -1
  43. thestage/services/clients/thestage_api/dtos/task_controller/task_view_response.py +0 -2
  44. thestage/services/config_provider/config_provider.py +2 -2
  45. thestage/services/connect/connect_service.py +77 -74
  46. thestage/services/container/container_service.py +120 -41
  47. thestage/services/container/mapper/container_mapper.py +2 -1
  48. thestage/services/instance/instance_service.py +13 -20
  49. thestage/services/instance/mapper/instance_mapper.py +1 -3
  50. thestage/services/instance/mapper/selfhosted_mapper.py +3 -4
  51. thestage/services/logging/logging_service.py +45 -48
  52. thestage/services/project/dto/inference_simulator_dto.py +1 -10
  53. thestage/services/project/dto/inference_simulator_model_dto.py +2 -10
  54. thestage/services/project/dto/project_config.py +2 -2
  55. thestage/services/project/mapper/project_inference_simulator_mapper.py +1 -0
  56. thestage/services/project/mapper/project_inference_simulator_model_mapper.py +2 -2
  57. thestage/services/project/mapper/project_task_mapper.py +2 -3
  58. thestage/services/project/project_service.py +174 -140
  59. thestage/services/remote_server_service.py +1 -0
  60. thestage/services/task/dto/task_dto.py +3 -23
  61. {thestage-0.6.5.dist-info → thestage-0.6.7.dist-info}/METADATA +4 -2
  62. {thestage-0.6.5.dist-info → thestage-0.6.7.dist-info}/RECORD +65 -74
  63. {thestage-0.6.5.dist-info → thestage-0.6.7.dist-info}/WHEEL +1 -1
  64. thestage/services/clients/thestage_api/dtos/cloud_provider_region.py +0 -19
  65. thestage/services/clients/thestage_api/dtos/docker_container_assigned_device.py +0 -10
  66. thestage/services/clients/thestage_api/dtos/enums/currency_type.py +0 -10
  67. thestage/services/clients/thestage_api/dtos/enums/daemon_status.py +0 -9
  68. thestage/services/clients/thestage_api/dtos/enums/disk_type.py +0 -7
  69. thestage/services/clients/thestage_api/dtos/enums/drive_type.py +0 -7
  70. thestage/services/clients/thestage_api/dtos/enums/instance_type.py +0 -7
  71. thestage/services/clients/thestage_api/dtos/enums/location_region.py +0 -11
  72. thestage/services/clients/thestage_api/dtos/enums/power_status.py +0 -10
  73. thestage/services/clients/thestage_api/dtos/price_definition.py +0 -14
  74. {thestage-0.6.5.dist-info → thestage-0.6.7.dist-info}/entry_points.txt +0 -0
  75. {thestage-0.6.5.dist-info → thestage-0.6.7.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,43 +245,48 @@ 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(
272
- text=f"Would you like to set '{docker_container_slug}' as a default container for this project installation?",
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(
281
+ text=f"Would you like to set the container '{container.slug}' (ID: '{container.public_id}') as default for this project installation?",
273
282
  show_choices=True,
274
283
  default=YesOrNoResponse.YES.value,
275
284
  type=click.Choice([r.value for r in YesOrNoResponse]),
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,11 @@ 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}")
418
+ if run_task_response.tasksInQueue:
419
+ typer.echo(f"There are tasks in queue ahead of this new task:")
420
+ for queued_task_item in run_task_response.tasksInQueue:
421
+ typer.echo(f"{queued_task_item.public_id} - {queued_task_item.frontend_status.status_translation}")
409
422
  return run_task_response.task
410
423
  else:
411
424
  typer.echo(f'The task failed with an error: {run_task_response.message}')
@@ -415,23 +428,25 @@ class ProjectService(AbstractService):
415
428
  raise typer.Exit(1)
416
429
 
417
430
  @error_handler()
418
- def cancel_task(self, task_id: int):
431
+ def cancel_task(self, task_public_id: str):
419
432
  cancel_result = self.__thestage_api_client.cancel_task(
420
- task_id=task_id,
433
+ task_public_id=task_public_id,
421
434
  )
422
435
 
423
436
  if cancel_result.is_success:
424
- typer.echo(f'Task {task_id} has been canceled')
437
+ typer.echo(f'Task {task_public_id} has been canceled')
425
438
  else:
426
- typer.echo(f'Task {task_id} could not be canceled: {cancel_result.message}')
439
+ typer.echo(f'Task {task_public_id} could not be canceled: {cancel_result.message}')
427
440
 
428
441
 
429
442
  @error_handler()
430
443
  def project_run_inference_simulator(
431
444
  self,
432
445
  commit_hash: Optional[str] = None,
433
- rented_instance_unique_id: Optional[str] = None,
434
- self_hosted_instance_unique_id: Optional[str] = None,
446
+ rented_instance_public_id: Optional[str] = None,
447
+ rented_instance_slug: Optional[str] = None,
448
+ self_hosted_instance_public_id: Optional[str] = None,
449
+ self_hosted_instance_slug: Optional[str] = None,
435
450
  inference_dir: Optional[str] = None,
436
451
  is_skip_installation: Optional[bool] = False,
437
452
  files_to_add: Optional[str] = None,
@@ -444,16 +459,12 @@ class ProjectService(AbstractService):
444
459
  {"path": config.runtime.working_directory}))
445
460
  raise typer.Exit(1)
446
461
 
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."))
462
+ 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])
463
+ if instance_args_count != 1:
464
+ typer.echo("Please provide a single instance (rented or self-hosted) identifier - name or ID.")
453
465
  raise typer.Exit(1)
454
466
 
455
467
  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
468
  if has_wrong_args:
458
469
  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
470
  print(warning_msg)
@@ -555,10 +566,12 @@ class ProjectService(AbstractService):
555
566
  commit_hash = commit.hexsha
556
567
 
557
568
  start_inference_simulator_response: ProjectStartInferenceSimulatorResponse = self.__thestage_api_client.start_project_inference_simulator(
558
- project_slug=project_config.slug,
569
+ project_public_id=project_config.public_id,
559
570
  commit_hash=commit_hash,
560
- rented_instance_unique_id=rented_instance_unique_id,
561
- self_hosted_instance_unique_id=self_hosted_instance_unique_id,
571
+ rented_instance_public_id=rented_instance_public_id,
572
+ rented_instance_slug=rented_instance_slug,
573
+ self_hosted_instance_public_id=self_hosted_instance_public_id,
574
+ self_hosted_instance_slug=self_hosted_instance_slug,
562
575
  inference_dir=inference_dir,
563
576
  is_skip_installation=is_skip_installation,
564
577
  )
@@ -582,10 +595,12 @@ class ProjectService(AbstractService):
582
595
  @error_handler()
583
596
  def project_push_inference_simulator(
584
597
  self,
598
+ public_id: Optional[str] = None,
585
599
  slug: Optional[str] = None,
586
600
  ):
587
601
 
588
602
  push_inference_simulator_model_response: ProjectPushInferenceSimulatorModelResponse = self.__thestage_api_client.push_project_inference_simulator_model(
603
+ public_id=public_id,
589
604
  slug=slug,
590
605
  )
591
606
  if push_inference_simulator_model_response:
@@ -606,25 +621,27 @@ class ProjectService(AbstractService):
606
621
  @error_handler()
607
622
  def project_get_and_save_inference_simulator_metadata(
608
623
  self,
609
- slug: Optional[str] = None,
624
+ inference_simulator_public_id: Optional[str] = None,
625
+ inference_simulator_slug: Optional[str] = None,
610
626
  file_path: Optional[str] = None,
611
627
  ):
612
628
  get_inference_metadata_response: GetInferenceSimulatorResponse = self.__thestage_api_client.get_inference_simulator(
613
- slug=slug,
629
+ public_id=inference_simulator_public_id,
630
+ slug=inference_simulator_slug,
614
631
  )
615
632
 
616
633
  metadata = get_inference_metadata_response.inferenceSimulator.qlip_serve_metadata
617
634
 
618
635
  if metadata:
619
636
  typer.echo("qlip_serve_metadata:")
620
- typer.echo(json.dumps(json.loads(metadata), indent=4))
637
+ typer.echo(json.dumps(metadata, indent=4))
621
638
 
622
639
  if not file_path:
623
640
  file_path = Path(os.getcwd()) / "metadata.json"
624
641
  typer.echo(__("No file path provided. Saving metadata to %file_path%", {"file_path": str(file_path)}))
625
642
 
626
643
  try:
627
- parsed_metadata = json.loads(metadata)
644
+ parsed_metadata = metadata
628
645
 
629
646
  output_file = Path(file_path)
630
647
  output_file.parent.mkdir(parents=True, exist_ok=True)
@@ -643,13 +660,15 @@ class ProjectService(AbstractService):
643
660
  @error_handler()
644
661
  def get_project_inference_simulator_list(
645
662
  self,
646
- project_slug: str,
663
+ project_public_id: Optional[str],
664
+ project_slug: Optional[str],
647
665
  statuses: List[str],
648
666
  row: int = 5,
649
667
  page: int = 1,
650
668
  ) -> PaginatedEntityList[InferenceSimulatorDto]:
651
- data: Optional[PaginatedEntityList[InferenceSimulatorDto]] = self.__thestage_api_client.get_inference_simulator_list_for_project(
669
+ data: Optional[PaginatedEntityList[InferenceSimulatorDto]] = self.__thestage_api_client.get_inference_simulator_list(
652
670
  statuses=statuses,
671
+ project_public_id=project_public_id,
653
672
  project_slug=project_slug,
654
673
  page=page,
655
674
  limit=row,
@@ -661,7 +680,8 @@ class ProjectService(AbstractService):
661
680
  @error_handler()
662
681
  def get_project_inference_simulator_model_list(
663
682
  self,
664
- project_slug: str,
683
+ project_public_id: Optional[str],
684
+ project_slug: Optional[str],
665
685
  statuses: List[str],
666
686
  row: int = 5,
667
687
  page: int = 1,
@@ -669,22 +689,7 @@ class ProjectService(AbstractService):
669
689
  data: Optional[
670
690
  PaginatedEntityList[InferenceSimulatorModelDto]] = self.__thestage_api_client.get_inference_simulator_model_list_for_project(
671
691
  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(
692
+ project_public_id=project_public_id,
688
693
  project_slug=project_slug,
689
694
  page=page,
690
695
  limit=row,
@@ -696,7 +701,7 @@ class ProjectService(AbstractService):
696
701
  @error_handler()
697
702
  def checkout_project(
698
703
  self,
699
- task_id: Optional[int],
704
+ task_public_id: Optional[str],
700
705
  branch_name: Optional[str],
701
706
  ):
702
707
  config = self.__config_provider.get_config()
@@ -706,21 +711,21 @@ class ProjectService(AbstractService):
706
711
  raise typer.Exit(1)
707
712
 
708
713
  target_commit_hash: Optional[str] = None
709
- if task_id:
714
+ if task_public_id:
710
715
  task_view_response: Optional[TaskViewResponse] = None
711
716
  try:
712
- task_view_response = self.__thestage_api_client.get_task(task_id=task_id,)
717
+ task_view_response = self.__thestage_api_client.get_task(task_public_id=task_public_id)
713
718
  except HttpClientException as e:
714
719
  if e.get_status_code() == 400:
715
- typer.echo(f"Task {task_id} was not found")
720
+ typer.echo(f"Task {task_public_id} was not found")
716
721
  # overriding arguments here
717
- branch_name = str(task_id)
718
- task_id = None
722
+ branch_name = str(task_public_id)
723
+ task_public_id = None
719
724
 
720
725
  if task_view_response and task_view_response.task:
721
726
  target_commit_hash = task_view_response.task.commit_hash
722
727
  if not target_commit_hash:
723
- typer.echo(f"Provided task ({task_id}) has no commit hash") # possible legacy problems
728
+ typer.echo(f"Provided task ({task_public_id}) has no commit hash") # possible legacy problems
724
729
  raise typer.Exit(1)
725
730
 
726
731
  is_commit_allowed: bool = True
@@ -833,48 +838,40 @@ class ProjectService(AbstractService):
833
838
 
834
839
 
835
840
  @error_handler()
836
- def set_default_container(self, container_uid: Optional[str]):
841
+ def set_default_container(
842
+ self,
843
+ container_public_id: Optional[str],
844
+ container_slug: Optional[str],
845
+ ):
837
846
  project_config: ProjectConfig = self.__config_provider.read_project_config()
838
847
 
839
848
  if project_config is None:
840
849
  typer.echo(f"No project found in working directory")
841
850
  raise typer.Exit(1)
842
851
 
843
- if container_uid:
852
+ container: Optional[DockerContainerDto] = None
853
+ if container_slug or container_public_id:
844
854
  container: DockerContainerDto = self.__thestage_api_client.get_container(
845
- container_slug=container_uid,
855
+ container_public_id=container_public_id,
856
+ container_slug=container_slug,
846
857
  )
847
858
  if container is None:
848
- typer.echo(f"Could not find container '{container_uid}'")
859
+ typer.echo(f"Could not find container '{container_slug or container_public_id}'")
849
860
  raise typer.Exit(1)
850
861
 
851
- if container.project_id != project_config.id:
852
- typer.echo(f"Provided container '{container_uid}' is not related to project '{project_config.slug}'")
862
+ if container.project.public_id != project_config.public_id:
863
+ typer.echo(f"Provided container '{container_slug or container_public_id}' is not related to current project '{project_config.public_id}'")
853
864
  raise typer.Exit(1)
854
865
 
855
866
  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}'")
867
+ typer.echo(f"Note: provided container '{container_slug or container_public_id}' is in status '{container.frontend_status.status_translation}'")
857
868
 
858
- project_config.default_container_uid = container_uid
869
+ project_config.default_container_public_id = container.public_id if container else None
859
870
  project_config.prompt_for_default_container = False
860
871
  self.__config_provider.save_project_config(project_config=project_config)
861
872
  typer.echo("Default container settings were updated")
862
873
 
863
874
 
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
875
  @error_handler()
879
876
  def print_project_config(self):
880
877
  project_config: ProjectConfig = self.__config_provider.read_project_config()
@@ -888,10 +885,13 @@ class ProjectService(AbstractService):
888
885
  typer.echo(tabulate(
889
886
  [
890
887
  [
891
- "Project unique ID", project_config.slug
888
+ "Project ID", project_config.public_id
892
889
  ],
893
890
  [
894
- "Default docker container unique ID", project_config.default_container_uid if project_config.default_container_uid else "<None>"
891
+ "Project name", project_config.slug
892
+ ],
893
+ [
894
+ "Default docker container ID", project_config.default_container_public_id if project_config.default_container_public_id else "<None>"
895
895
  ],
896
896
  [
897
897
  "Deploy key path", project_config.deploy_key_path if is_deploy_key_exists else "<None>"
@@ -913,15 +913,19 @@ class ProjectService(AbstractService):
913
913
  if project_config is None:
914
914
  return None
915
915
 
916
+ if project_config.public_id is None:
917
+ project = self.__thestage_api_client.get_project(public_id=None, slug=project_config.slug)
918
+ project_config.public_id = project.public_id
919
+ self.__config_provider.save_project_config(project_config=project_config)
920
+
916
921
  if not Path(project_config.deploy_key_path).is_file():
917
922
  deploy_ssh_key = self.__thestage_api_client.get_project_deploy_ssh_key(
918
- slug=project_config.slug,
923
+ public_id=project_config.public_id,
919
924
  )
920
925
 
921
926
  deploy_key_path = self.__config_provider.save_project_deploy_ssh_key(
922
927
  deploy_ssh_key=deploy_ssh_key,
923
- project_slug=project_config.slug,
924
- project_id=project_config.id,
928
+ project_public_id=project_config.public_id,
925
929
  )
926
930
 
927
931
  project_config.deploy_key_path = deploy_key_path
@@ -933,11 +937,13 @@ class ProjectService(AbstractService):
933
937
  @error_handler()
934
938
  def project_deploy_inference_simulator_model_to_instance(
935
939
  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,
940
- ) -> None:
940
+ model_public_id: Optional[str] = None,
941
+ model_slug: Optional[str] = None,
942
+ rented_instance_public_id: Optional[str] = None,
943
+ rented_instance_slug: Optional[str] = None,
944
+ self_hosted_instance_public_id: Optional[str] = None,
945
+ self_hosted_instance_slug: Optional[str] = None,
946
+ ) -> str:
941
947
  config = self.__config_provider.get_config()
942
948
  project_config: ProjectConfig = self.__get_fixed_project_config()
943
949
  if not project_config:
@@ -946,26 +952,30 @@ class ProjectService(AbstractService):
946
952
  {"path": config.runtime.working_directory}))
947
953
  raise typer.Exit(1)
948
954
 
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."))
955
+ 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])
956
+ if instance_args_count != 1:
957
+ typer.echo("Please provide a single instance (rented or self-hosted) identifier - name or ID.")
951
958
  raise typer.Exit(1)
952
959
 
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."))
960
+ model_args_count = sum(v is not None for v in [model_public_id, model_slug])
961
+ if model_args_count != 1:
962
+ typer.echo("Please provide a single model identifier - name or ID.")
955
963
  raise typer.Exit(1)
956
964
 
957
- typer.echo(__("Creating inference simulator with unique ID: %unique_id_with_timestamp%", {"unique_id_with_timestamp": unique_id_with_timestamp}))
965
+ typer.echo(f"Creating inference simulator")
958
966
  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
967
+ model_public_id=model_public_id,
968
+ model_slug=model_slug,
969
+ rented_instance_public_id=rented_instance_public_id,
970
+ rented_instance_slug=rented_instance_slug,
971
+ self_hosted_instance_public_id=self_hosted_instance_public_id,
972
+ self_hosted_instance_slug=self_hosted_instance_slug,
963
973
  )
964
974
  if deploy_model_to_instance_response:
965
975
  if deploy_model_to_instance_response.message:
966
976
  typer.echo(deploy_model_to_instance_response.message)
967
977
  if deploy_model_to_instance_response.is_success:
968
- typer.echo("Inference simulator has been scheduled to run successfully.")
978
+ typer.echo(f"Inference simulator '{deploy_model_to_instance_response.inferenceSimulatorPublicId}' has been scheduled to run successfully.")
969
979
  else:
970
980
  typer.echo(__(
971
981
  'Inference simulator failed to run with an error: %server_massage%',
@@ -976,11 +986,14 @@ class ProjectService(AbstractService):
976
986
  typer.echo(__("Inference simulator failed to run with an error"))
977
987
  raise typer.Exit(1)
978
988
 
989
+ return deploy_model_to_instance_response.inferenceSimulatorPublicId
990
+
979
991
 
980
992
  @error_handler()
981
993
  def project_deploy_inference_simulator_model_to_sagemaker(
982
994
  self,
983
- unique_id: Optional[str] = None,
995
+ model_public_id: Optional[str] = None,
996
+ model_slug: Optional[str] = None,
984
997
  arn: Optional[str] = None,
985
998
  instance_type: Optional[str] = None,
986
999
  initial_variant_weight: Optional[float] = 1.0,
@@ -1013,7 +1026,8 @@ class ProjectService(AbstractService):
1013
1026
  raise typer.Exit(1)
1014
1027
 
1015
1028
  deploy_model_to_sagemaker_response: DeployInferenceModelToSagemakerResponse = self.__thestage_api_client.deploy_inference_model_to_sagemaker(
1016
- unique_id=unique_id,
1029
+ model_public_id=model_public_id,
1030
+ model_slug=model_slug,
1017
1031
  arn=arn,
1018
1032
  )
1019
1033
 
@@ -1041,7 +1055,7 @@ class ProjectService(AbstractService):
1041
1055
  },
1042
1056
  }
1043
1057
 
1044
- sm_model_name = f"{unique_id}-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
1058
+ sm_model_name = f"{model_slug}-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
1045
1059
  create_model_response = sm_client.create_model(
1046
1060
  ModelName=sm_model_name,
1047
1061
  ExecutionRoleArn=arn,
@@ -1049,7 +1063,7 @@ class ProjectService(AbstractService):
1049
1063
  )
1050
1064
  typer.echo(f"Model created successfully. Model ARN: {create_model_response['ModelArn']}")
1051
1065
 
1052
- endpoint_config_name = f"{unique_id}-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
1066
+ endpoint_config_name = f"{model_slug}-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
1053
1067
  create_endpoint_config_response = sm_client.create_endpoint_config(
1054
1068
  EndpointConfigName=endpoint_config_name,
1055
1069
  ProductionVariants=[
@@ -1065,7 +1079,7 @@ class ProjectService(AbstractService):
1065
1079
  typer.echo(
1066
1080
  f"Endpoint configuration created successfully. Endpoint Config ARN: {create_endpoint_config_response['EndpointConfigArn']}")
1067
1081
 
1068
- endpoint_name = f"{unique_id}-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
1082
+ endpoint_name = f"{model_slug}-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
1069
1083
  create_endpoint_response = sm_client.create_endpoint(
1070
1084
  EndpointName=endpoint_name,
1071
1085
  EndpointConfigName=endpoint_config_name,
@@ -1128,13 +1142,13 @@ class ProjectService(AbstractService):
1128
1142
 
1129
1143
 
1130
1144
  @error_handler()
1131
- def print_inference_simulator_list(self, project_uid, statuses, row, page):
1132
- if not project_uid:
1145
+ def print_inference_simulator_list(self, project_public_id, project_slug, statuses, row, page):
1146
+ if not project_public_id and not project_slug:
1133
1147
  project_config: ProjectConfig = self.__config_provider.read_project_config()
1134
1148
  if not project_config:
1135
- typer.echo(__("Provide the project unique ID or run this command from within an initialized project directory"))
1149
+ typer.echo(__("Provide the project identifier or run this command from within an initialized project directory"))
1136
1150
  raise typer.Exit(1)
1137
- project_uid = project_config.slug
1151
+ project_public_id = project_config.public_id
1138
1152
 
1139
1153
  inference_simulator_status_map = self.__thestage_api_client.get_inference_simulator_business_status_map()
1140
1154
 
@@ -1167,7 +1181,8 @@ class ProjectService(AbstractService):
1167
1181
  self.print(
1168
1182
  func_get_data=self.get_project_inference_simulator_list,
1169
1183
  func_special_params={
1170
- 'project_slug': project_uid,
1184
+ 'project_public_id': project_public_id,
1185
+ 'project_slug': project_slug,
1171
1186
  'statuses': backend_statuses,
1172
1187
  },
1173
1188
  mapper=ProjectInferenceSimulatorMapper(),
@@ -1180,13 +1195,13 @@ class ProjectService(AbstractService):
1180
1195
 
1181
1196
 
1182
1197
  @error_handler()
1183
- def print_inference_simulator_model_list(self, project_uid, statuses, row, page):
1184
- if not project_uid:
1198
+ def print_inference_simulator_model_list(self, project_public_id, project_slug, statuses, row, page):
1199
+ if not project_public_id and not project_slug:
1185
1200
  project_config: ProjectConfig = self.__config_provider.read_project_config()
1186
1201
  if not project_config:
1187
- typer.echo(__("Provide the project unique ID or run this command from within an initialized project directory"))
1202
+ typer.echo(__("Provide the project identifier or run this command from within an initialized project directory"))
1188
1203
  raise typer.Exit(1)
1189
- project_uid = project_config.slug
1204
+ project_public_id = project_config.public_id
1190
1205
 
1191
1206
  inference_simulator_model_status_map = self.__thestage_api_client.get_inference_simulator_model_business_status_map()
1192
1207
 
@@ -1219,30 +1234,32 @@ class ProjectService(AbstractService):
1219
1234
  self.print(
1220
1235
  func_get_data=self.get_project_inference_simulator_model_list,
1221
1236
  func_special_params={
1222
- 'project_slug': project_uid,
1237
+ 'project_public_id': project_public_id,
1238
+ 'project_slug': project_slug,
1223
1239
  'statuses': backend_statuses,
1224
1240
  },
1225
1241
  mapper=ProjectInferenceSimulatorModelMapper(),
1226
1242
  headers=list(map(lambda x: x.alias, ProjectInferenceSimulatorModelEntity.model_fields.values())),
1227
1243
  row=row,
1228
1244
  page=page,
1229
- max_col_width=[100, 100, 100, 100, 100, 100, 100, 100],
1245
+ max_col_width=[100, 100, 100, 100, 25],
1230
1246
  show_index="never",
1231
1247
  )
1232
1248
 
1233
1249
 
1234
- def print_task_list(self, project_uid, row, page):
1235
- if not project_uid:
1250
+ def print_task_list(self, project_public_id: Optional[str], project_slug: Optional[str], row, page):
1251
+ if not project_slug and not project_public_id:
1236
1252
  project_config: ProjectConfig = self.__config_provider.read_project_config()
1237
1253
  if not project_config:
1238
- typer.echo(__("Provide the project unique ID or run this command from within an initialized project directory"))
1254
+ typer.echo(__("Provide the project identifier or run this command from within an initialized project directory"))
1239
1255
  raise typer.Exit(1)
1240
- project_uid = project_config.slug
1256
+ project_public_id = project_config.public_id
1241
1257
 
1242
1258
  self.print(
1243
1259
  func_get_data=self.get_project_task_list,
1244
1260
  func_special_params={
1245
- 'project_slug': project_uid,
1261
+ 'project_public_id': project_public_id,
1262
+ 'project_slug': project_slug,
1246
1263
  },
1247
1264
  mapper=ProjectTaskMapper(),
1248
1265
  headers=list(map(lambda x: x.alias, ProjectTaskEntity.model_fields.values())),
@@ -1251,3 +1268,20 @@ class ProjectService(AbstractService):
1251
1268
  max_col_width=[100, 100, 100, 100, 100, 100, 100, 100],
1252
1269
  show_index="never",
1253
1270
  )
1271
+
1272
+ @error_handler()
1273
+ def get_project_task_list(
1274
+ self,
1275
+ project_public_id: Optional[str],
1276
+ project_slug: Optional[str],
1277
+ row: int = 5,
1278
+ page: int = 1,
1279
+ ) -> PaginatedEntityList[TaskDto]:
1280
+ data: Optional[PaginatedEntityList[TaskDto]] = self.__thestage_api_client.get_task_list_for_project(
1281
+ project_public_id=project_public_id,
1282
+ project_slug=project_slug,
1283
+ page=page,
1284
+ limit=row,
1285
+ )
1286
+
1287
+ return data