thestage 0.5.46__py3-none-any.whl → 0.5.471__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 (49) hide show
  1. thestage/.env +5 -0
  2. thestage/__init__.py +2 -1
  3. thestage/cli_command.py +56 -0
  4. thestage/cli_command_helper.py +51 -0
  5. thestage/config/config_storage.py +5 -0
  6. thestage/controllers/base_controller.py +19 -15
  7. thestage/controllers/config_controller.py +30 -38
  8. thestage/controllers/container_controller.py +43 -79
  9. thestage/controllers/instance_controller.py +23 -40
  10. thestage/controllers/project_controller.py +95 -184
  11. thestage/controllers/utils_controller.py +12 -8
  12. thestage/debug_tests.py +12 -0
  13. thestage/entities/container.py +0 -5
  14. thestage/entities/rented_instance.py +0 -5
  15. thestage/entities/self_hosted_instance.py +0 -2
  16. thestage/helpers/error_handler.py +14 -14
  17. thestage/helpers/exception_hook.py +14 -0
  18. thestage/helpers/logger/app_logger.py +3 -4
  19. thestage/main.py +25 -13
  20. thestage/services/abstract_service.py +0 -40
  21. thestage/services/app_config_service.py +7 -6
  22. thestage/services/clients/.DS_Store +0 -0
  23. thestage/services/clients/thestage_api/api_client.py +54 -68
  24. thestage/services/clients/thestage_api/core/api_client_core.py +92 -9
  25. thestage/services/clients/thestage_api/dtos/container_response.py +1 -1
  26. thestage/services/clients/thestage_api/dtos/inference_simulator_model_response.py +1 -1
  27. thestage/services/clients/thestage_api/dtos/inference_simulator_response.py +1 -1
  28. thestage/services/clients/thestage_api/dtos/instance_rented_response.py +1 -1
  29. thestage/services/clients/thestage_api/dtos/selfhosted_instance_response.py +1 -1
  30. thestage/services/clients/thestage_api/dtos/task_controller/task_status_localized_map_response.py +1 -1
  31. thestage/services/clients/thestage_api/dtos/validate_token_response.py +11 -0
  32. thestage/services/config_provider/config_provider.py +75 -47
  33. thestage/services/connect/connect_service.py +11 -22
  34. thestage/services/container/container_service.py +6 -23
  35. thestage/services/core_files/config_entity.py +7 -1
  36. thestage/services/filesystem_service.py +2 -2
  37. thestage/services/instance/instance_service.py +12 -26
  38. thestage/services/logging/logging_service.py +17 -45
  39. thestage/services/project/project_service.py +33 -72
  40. thestage/services/remote_server_service.py +3 -4
  41. thestage/services/service_factory.py +21 -27
  42. thestage/services/validation_service.py +14 -9
  43. {thestage-0.5.46.dist-info → thestage-0.5.471.dist-info}/METADATA +3 -4
  44. {thestage-0.5.46.dist-info → thestage-0.5.471.dist-info}/RECORD +47 -41
  45. {thestage-0.5.46.dist-info → thestage-0.5.471.dist-info}/WHEEL +1 -1
  46. thestage/exceptions/http_error_exception.py +0 -12
  47. thestage/services/clients/thestage_api/core/api_client_abstract.py +0 -91
  48. {thestage-0.5.46.dist-info → thestage-0.5.471.dist-info}/LICENSE.txt +0 -0
  49. {thestage-0.5.46.dist-info → thestage-0.5.471.dist-info}/entry_points.txt +0 -0
@@ -18,7 +18,6 @@ from thestage.entities.project_task import ProjectTaskEntity
18
18
  from thestage.services.clients.thestage_api.core.http_client_exception import HttpClientException
19
19
  from thestage.services.clients.thestage_api.dtos.enums.inference_model_status import InferenceModelStatus
20
20
  from thestage.services.clients.thestage_api.dtos.enums.inference_simulator_status import InferenceSimulatorStatus
21
- from thestage.services.core_files.config_entity import ConfigEntity
22
21
  from thestage.color_scheme.color_scheme import ColorScheme
23
22
  from thestage.entities.enums.yes_no_response import YesOrNoResponse
24
23
  from thestage.exceptions.git_access_exception import GitAccessException
@@ -60,6 +59,7 @@ from rich import print
60
59
 
61
60
  class ProjectService(AbstractService):
62
61
  __thestage_api_client: TheStageApiClient = None
62
+ __config_provider: ConfigProvider = None
63
63
 
64
64
  def __init__(
65
65
  self,
@@ -69,9 +69,6 @@ class ProjectService(AbstractService):
69
69
  file_system_service: FileSystemService,
70
70
  git_local_client: GitLocalClient,
71
71
  ):
72
- super(ProjectService, self).__init__(
73
- config_provider=config_provider
74
- )
75
72
  self.__thestage_api_client = thestage_api_client
76
73
  self.__remote_server_service = remote_server_service
77
74
  self.__file_system_service = file_system_service
@@ -83,12 +80,11 @@ class ProjectService(AbstractService):
83
80
  @error_handler()
84
81
  def init_project(
85
82
  self,
86
- config: ConfigEntity,
87
83
  project_slug: str,
88
84
  ):
85
+ config = self.__config_provider.get_config()
89
86
  project: Optional[ProjectDto] = self.__thestage_api_client.get_project_by_slug(
90
87
  slug=project_slug,
91
- token=config.main.thestage_auth_token,
92
88
  )
93
89
 
94
90
  if not project:
@@ -124,7 +120,6 @@ class ProjectService(AbstractService):
124
120
 
125
121
  deploy_ssh_key = self.__thestage_api_client.get_project_deploy_ssh_key(
126
122
  slug=project.slug,
127
- token=config.main.thestage_auth_token
128
123
  )
129
124
 
130
125
  deploy_key_path = self.__config_provider.save_project_deploy_ssh_key(
@@ -167,16 +162,17 @@ class ProjectService(AbstractService):
167
162
  project_config.deploy_key_path = str(deploy_key_path)
168
163
  self.__config_provider.save_project_config(project_config=project_config)
169
164
 
165
+ typer.echo(__("Project successfully initialized at %path%", {"path": config.runtime.working_directory}))
166
+
170
167
 
171
168
  @error_handler()
172
169
  def clone_project(
173
170
  self,
174
- config: ConfigEntity,
175
171
  project_slug: str,
176
172
  ):
173
+ config = self.__config_provider.get_config()
177
174
  project: Optional[ProjectDto] = self.__thestage_api_client.get_project_by_slug(
178
175
  slug=project_slug,
179
- token=config.main.thestage_auth_token,
180
176
  )
181
177
 
182
178
  if not project:
@@ -199,7 +195,7 @@ class ProjectService(AbstractService):
199
195
  typer.echo(__("Unexpected Project error, missing Repository"))
200
196
  raise typer.Exit(1)
201
197
 
202
- deploy_ssh_key = self.__thestage_api_client.get_project_deploy_ssh_key(slug=project.slug, token=config.main.thestage_auth_token)
198
+ deploy_ssh_key = self.__thestage_api_client.get_project_deploy_ssh_key(slug=project.slug)
203
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)
204
200
 
205
201
  try:
@@ -226,18 +222,19 @@ class ProjectService(AbstractService):
226
222
  project_config.git_repository_url = project.git_repository_url
227
223
  project_config.deploy_key_path = str(deploy_key_path)
228
224
  self.__config_provider.save_project_config(project_config=project_config)
225
+ typer.echo(__("Project successfully cloned to %path%", {"path": config.runtime.working_directory}))
229
226
 
230
227
 
231
228
  @error_handler()
232
229
  def project_run_task(
233
230
  self,
234
- config: ConfigEntity,
235
231
  run_command: str,
236
232
  task_title: Optional[str] = None,
237
233
  commit_hash: Optional[str] = None,
238
234
  docker_container_slug: Optional[str] = None,
239
235
  ) -> Optional[TaskDto]:
240
- project_config: ProjectConfig = self.__get_fixed_project_config(config=config)
236
+ config = self.__config_provider.get_config()
237
+ project_config: ProjectConfig = self.__get_fixed_project_config()
241
238
  if not project_config:
242
239
  typer.echo(__("No project found at the path: %path%. Please initialize or clone a project first.", {"path": config.runtime.working_directory}))
243
240
  raise typer.Exit(1)
@@ -252,7 +249,6 @@ class ProjectService(AbstractService):
252
249
  typer.echo(f"Using default docker container for this project: '{container_slug_for_task}'")
253
250
 
254
251
  container: DockerContainerDto = self.__thestage_api_client.get_container(
255
- token=config.main.thestage_auth_token,
256
252
  container_slug=container_slug_for_task,
257
253
  )
258
254
 
@@ -384,7 +380,6 @@ class ProjectService(AbstractService):
384
380
  typer.echo(f'Commit message is empty. Task title is set to "{task_title}"')
385
381
 
386
382
  run_task_response: ProjectRunTaskResponse = self.__thestage_api_client.execute_project_task(
387
- token=config.main.thestage_auth_token,
388
383
  project_slug=project_config.slug,
389
384
  docker_container_slug=container_slug_for_task,
390
385
  run_command=run_command,
@@ -405,9 +400,8 @@ class ProjectService(AbstractService):
405
400
  raise typer.Exit(1)
406
401
 
407
402
  @error_handler()
408
- def cancel_task(self, task_id: int, config: ConfigEntity):
403
+ def cancel_task(self, task_id: int):
409
404
  cancel_result = self.__thestage_api_client.cancel_task(
410
- token=config.main.thestage_auth_token,
411
405
  task_id=task_id,
412
406
  )
413
407
 
@@ -420,7 +414,6 @@ class ProjectService(AbstractService):
420
414
  @error_handler()
421
415
  def project_run_inference_simulator(
422
416
  self,
423
- config: ConfigEntity,
424
417
  slug: Optional[str] = None,
425
418
  commit_hash: Optional[str] = None,
426
419
  rented_instance_unique_id: Optional[str] = None,
@@ -428,7 +421,8 @@ class ProjectService(AbstractService):
428
421
  inference_dir: Optional[str] = None,
429
422
  is_skip_installation: Optional[bool] = False,
430
423
  ) -> Optional[InferenceSimulatorDto]:
431
- project_config: ProjectConfig = self.__get_fixed_project_config(config=config)
424
+ config = self.__config_provider.get_config()
425
+ project_config: ProjectConfig = self.__get_fixed_project_config()
432
426
  if not project_config:
433
427
  typer.echo(__("No project found at the path: %path%. Please initialize or clone a project first. Or provide path to project using --working-directory option.",
434
428
  {"path": config.runtime.working_directory}))
@@ -442,12 +436,6 @@ class ProjectService(AbstractService):
442
436
  typer.echo(__("Error: Either a rented instance ID or a self-hosted instance unique ID must be provided."))
443
437
  raise typer.Exit(1)
444
438
 
445
- project_config: ProjectConfig = self.__config_provider.read_project_config()
446
- if not project_config:
447
- typer.echo(__("No project found at the path: %path%. Please initialize or clone a project first.",
448
- {"path": config.runtime.working_directory}))
449
- raise typer.Exit(1)
450
-
451
439
  if not commit_hash:
452
440
  is_git_folder = self.__git_local_client.is_present_local_git(path=config.runtime.working_directory)
453
441
  if not is_git_folder:
@@ -555,7 +543,6 @@ class ProjectService(AbstractService):
555
543
  slug = uid
556
544
 
557
545
  start_inference_simulator_response: ProjectStartInferenceSimulatorResponse = self.__thestage_api_client.start_project_inference_simulator(
558
- token=config.main.thestage_auth_token,
559
546
  project_slug=project_config.slug,
560
547
  commit_hash=commit_hash,
561
548
  slug=slug,
@@ -584,12 +571,10 @@ class ProjectService(AbstractService):
584
571
  @error_handler()
585
572
  def project_push_inference_simulator(
586
573
  self,
587
- config: ConfigEntity,
588
574
  slug: Optional[str] = None,
589
575
  ):
590
576
 
591
577
  push_inference_simulator_model_response: ProjectPushInferenceSimulatorModelResponse = self.__thestage_api_client.push_project_inference_simulator_model(
592
- token=config.main.thestage_auth_token,
593
578
  slug=slug,
594
579
  )
595
580
  if push_inference_simulator_model_response:
@@ -610,12 +595,10 @@ class ProjectService(AbstractService):
610
595
  @error_handler()
611
596
  def project_get_and_save_inference_simulator_metadata(
612
597
  self,
613
- config: ConfigEntity,
614
598
  slug: Optional[str] = None,
615
599
  file_path: Optional[str] = None,
616
600
  ):
617
601
  get_inference_metadata_response: GetInferenceSimulatorResponse = self.__thestage_api_client.get_inference_simulator(
618
- token=config.main.thestage_auth_token,
619
602
  slug=slug,
620
603
  )
621
604
 
@@ -649,14 +632,12 @@ class ProjectService(AbstractService):
649
632
  @error_handler()
650
633
  def get_project_inference_simulator_list(
651
634
  self,
652
- config: ConfigEntity,
653
635
  project_slug: str,
654
636
  statuses: List[str],
655
637
  row: int = 5,
656
638
  page: int = 1,
657
639
  ) -> PaginatedEntityList[InferenceSimulatorDto]:
658
640
  data: Optional[PaginatedEntityList[InferenceSimulatorDto]] = self.__thestage_api_client.get_inference_simulator_list_for_project(
659
- token=config.main.thestage_auth_token,
660
641
  statuses=statuses,
661
642
  project_slug=project_slug,
662
643
  page=page,
@@ -669,7 +650,6 @@ class ProjectService(AbstractService):
669
650
  @error_handler()
670
651
  def get_project_inference_simulator_model_list(
671
652
  self,
672
- config: ConfigEntity,
673
653
  project_slug: str,
674
654
  statuses: List[str],
675
655
  row: int = 5,
@@ -677,7 +657,6 @@ class ProjectService(AbstractService):
677
657
  ) -> PaginatedEntityList[InferenceSimulatorModelDto]:
678
658
  data: Optional[
679
659
  PaginatedEntityList[InferenceSimulatorModelDto]] = self.__thestage_api_client.get_inference_simulator_model_list_for_project(
680
- token=config.main.thestage_auth_token,
681
660
  statuses=statuses,
682
661
  project_slug=project_slug,
683
662
  page=page,
@@ -690,13 +669,11 @@ class ProjectService(AbstractService):
690
669
  @error_handler()
691
670
  def get_project_task_list(
692
671
  self,
693
- config: ConfigEntity,
694
672
  project_slug: str,
695
673
  row: int = 5,
696
674
  page: int = 1,
697
675
  ) -> PaginatedEntityList[TaskDto]:
698
676
  data: Optional[PaginatedEntityList[TaskDto]] = self.__thestage_api_client.get_task_list_for_project(
699
- token=config.main.thestage_auth_token,
700
677
  project_slug=project_slug,
701
678
  page=page,
702
679
  limit=row,
@@ -708,11 +685,11 @@ class ProjectService(AbstractService):
708
685
  @error_handler()
709
686
  def checkout_project(
710
687
  self,
711
- config: ConfigEntity,
712
688
  task_id: Optional[int],
713
689
  branch_name: Optional[str],
714
690
  ):
715
- project_config: ProjectConfig = self.__get_fixed_project_config(config=config)
691
+ config = self.__config_provider.get_config()
692
+ project_config: ProjectConfig = self.__get_fixed_project_config()
716
693
  if not project_config:
717
694
  typer.echo(__("This command is only allowed from within an initialized project directory"))
718
695
  raise typer.Exit(1)
@@ -721,10 +698,7 @@ class ProjectService(AbstractService):
721
698
  if task_id:
722
699
  task_view_response: Optional[TaskViewResponse] = None
723
700
  try:
724
- task_view_response = self.__thestage_api_client.get_task(
725
- token=config.main.thestage_auth_token,
726
- task_id=task_id,
727
- )
701
+ task_view_response = self.__thestage_api_client.get_task(task_id=task_id,)
728
702
  except HttpClientException as e:
729
703
  if e.get_status_code() == 400:
730
704
  typer.echo(f"Task {task_id} was not found")
@@ -847,7 +821,7 @@ class ProjectService(AbstractService):
847
821
 
848
822
 
849
823
  @error_handler()
850
- def set_default_container(self, config: ConfigEntity, container_uid: Optional[str]):
824
+ def set_default_container(self, container_uid: Optional[str]):
851
825
  project_config: ProjectConfig = self.__config_provider.read_project_config()
852
826
 
853
827
  if project_config is None:
@@ -856,7 +830,6 @@ class ProjectService(AbstractService):
856
830
 
857
831
  if container_uid:
858
832
  container: DockerContainerDto = self.__thestage_api_client.get_container(
859
- token=config.main.thestage_auth_token,
860
833
  container_slug=container_uid,
861
834
  )
862
835
  if container is None:
@@ -891,7 +864,7 @@ class ProjectService(AbstractService):
891
864
 
892
865
 
893
866
  @error_handler()
894
- def print_project_config(self, config):
867
+ def print_project_config(self):
895
868
  project_config: ProjectConfig = self.__config_provider.read_project_config()
896
869
 
897
870
  if project_config is None:
@@ -923,7 +896,7 @@ class ProjectService(AbstractService):
923
896
  typer.echo(f"before any regular git command to manage your local Project repository directly")
924
897
 
925
898
  @error_handler()
926
- def __get_fixed_project_config(self, config: ConfigEntity) -> Optional[ProjectConfig]:
899
+ def __get_fixed_project_config(self) -> Optional[ProjectConfig]:
927
900
  project_config: ProjectConfig = self.__config_provider.read_project_config()
928
901
  if project_config is None:
929
902
  return None
@@ -931,7 +904,6 @@ class ProjectService(AbstractService):
931
904
  if not Path(project_config.deploy_key_path).is_file():
932
905
  deploy_ssh_key = self.__thestage_api_client.get_project_deploy_ssh_key(
933
906
  slug=project_config.slug,
934
- token=config.main.thestage_auth_token
935
907
  )
936
908
 
937
909
  deploy_key_path = self.__config_provider.save_project_deploy_ssh_key(
@@ -949,13 +921,13 @@ class ProjectService(AbstractService):
949
921
  @error_handler()
950
922
  def project_deploy_inference_simulator_model_to_instance(
951
923
  self,
952
- config: ConfigEntity,
953
924
  unique_id: Optional[str] = None,
954
925
  unique_id_with_timestamp: Optional[str] = None,
955
926
  rented_instance_unique_id: Optional[str] = None,
956
927
  self_hosted_instance_unique_id: Optional[str] = None,
957
928
  ) -> None:
958
- project_config: ProjectConfig = self.__get_fixed_project_config(config=config)
929
+ config = self.__config_provider.get_config()
930
+ project_config: ProjectConfig = self.__get_fixed_project_config()
959
931
  if not project_config:
960
932
  typer.echo(
961
933
  __("No project found at the path: %path%. Please initialize or clone a project first. Or provide path to project using --working-directory option.",
@@ -970,15 +942,8 @@ class ProjectService(AbstractService):
970
942
  typer.echo(__("Error: Either a rented instance ID or a self-hosted instance unique ID must be provided."))
971
943
  raise typer.Exit(1)
972
944
 
973
- project_config: ProjectConfig = self.__config_provider.read_project_config()
974
- if not project_config:
975
- typer.echo(__("No project found at the path: %path%. Please initialize or clone a project first.",
976
- {"path": config.runtime.working_directory}))
977
- raise typer.Exit(1)
978
-
979
945
  typer.echo(__("Creating inference simulator with unique ID: %unique_id_with_timestamp%", {"unique_id_with_timestamp": unique_id_with_timestamp}))
980
946
  deploy_model_to_instance_response: DeployInferenceModelToInstanceResponse = self.__thestage_api_client.deploy_inference_model_to_instance(
981
- token=config.main.thestage_auth_token,
982
947
  unique_id=unique_id,
983
948
  unique_id_with_timestamp=unique_id_with_timestamp,
984
949
  rented_instance_unique_id=rented_instance_unique_id,
@@ -1003,14 +968,14 @@ class ProjectService(AbstractService):
1003
968
  @error_handler()
1004
969
  def project_deploy_inference_simulator_model_to_sagemaker(
1005
970
  self,
1006
- config: ConfigEntity,
1007
971
  unique_id: Optional[str] = None,
1008
972
  arn: Optional[str] = None,
1009
973
  instance_type: Optional[str] = None,
1010
974
  initial_variant_weight: Optional[float] = 1.0,
1011
975
  initial_instance_count: Optional[int] = None,
1012
976
  ) -> None:
1013
- project_config: ProjectConfig = self.__get_fixed_project_config(config=config)
977
+ config = self.__config_provider.get_config()
978
+ project_config: ProjectConfig = self.__get_fixed_project_config()
1014
979
  if not project_config:
1015
980
  typer.echo(
1016
981
  __("No project found at the path: %path%. Please initialize or clone a project first. Or provide path to project using --working-directory option.",
@@ -1036,7 +1001,6 @@ class ProjectService(AbstractService):
1036
1001
  raise typer.Exit(1)
1037
1002
 
1038
1003
  deploy_model_to_sagemaker_response: DeployInferenceModelToSagemakerResponse = self.__thestage_api_client.deploy_inference_model_to_sagemaker(
1039
- token=config.main.thestage_auth_token,
1040
1004
  unique_id=unique_id,
1041
1005
  arn=arn,
1042
1006
  )
@@ -1116,8 +1080,9 @@ class ProjectService(AbstractService):
1116
1080
 
1117
1081
 
1118
1082
  @error_handler()
1119
- def pull_project(self, config: ConfigEntity):
1120
- project_config: ProjectConfig = self.__get_fixed_project_config(config=config)
1083
+ def pull_project(self):
1084
+ config = self.__config_provider.get_config()
1085
+ project_config: ProjectConfig = self.__get_fixed_project_config()
1121
1086
  if not project_config:
1122
1087
  typer.echo(__("No project found at the path: %path%. Please initialize or clone a project first.", {"path": config.runtime.working_directory}))
1123
1088
  raise typer.Exit(1)
@@ -1130,8 +1095,9 @@ class ProjectService(AbstractService):
1130
1095
 
1131
1096
 
1132
1097
  @error_handler()
1133
- def reset_project(self, config: ConfigEntity):
1134
- project_config: ProjectConfig = self.__get_fixed_project_config(config=config)
1098
+ def reset_project(self):
1099
+ config = self.__config_provider.get_config()
1100
+ project_config: ProjectConfig = self.__get_fixed_project_config()
1135
1101
  if not project_config:
1136
1102
  typer.echo(__("No project found at the path: %path%. Please initialize or clone a project first.", {"path": config.runtime.working_directory}))
1137
1103
  raise typer.Exit(1)
@@ -1150,7 +1116,7 @@ class ProjectService(AbstractService):
1150
1116
 
1151
1117
 
1152
1118
  @error_handler()
1153
- def print_inference_simulator_list(self, config, project_uid, statuses, row, page):
1119
+ def print_inference_simulator_list(self, project_uid, statuses, row, page):
1154
1120
  if not project_uid:
1155
1121
  project_config: ProjectConfig = self.__config_provider.read_project_config()
1156
1122
  if not project_config:
@@ -1158,8 +1124,7 @@ class ProjectService(AbstractService):
1158
1124
  raise typer.Exit(1)
1159
1125
  project_uid = project_config.slug
1160
1126
 
1161
- inference_simulator_status_map = self.__thestage_api_client.get_inference_simulator_business_status_map(
1162
- config.main.thestage_auth_token)
1127
+ inference_simulator_status_map = self.__thestage_api_client.get_inference_simulator_business_status_map()
1163
1128
 
1164
1129
  if not statuses:
1165
1130
  statuses = ({key: inference_simulator_status_map[key] for key in [
@@ -1194,7 +1159,6 @@ class ProjectService(AbstractService):
1194
1159
  'statuses': backend_statuses,
1195
1160
  },
1196
1161
  mapper=ProjectInferenceSimulatorMapper(),
1197
- config=config,
1198
1162
  headers=list(map(lambda x: x.alias, ProjectInferenceSimulatorEntity.model_fields.values())),
1199
1163
  row=row,
1200
1164
  page=page,
@@ -1204,7 +1168,7 @@ class ProjectService(AbstractService):
1204
1168
 
1205
1169
 
1206
1170
  @error_handler()
1207
- def print_inference_simulator_model_list(self, config, project_uid, statuses, row, page):
1171
+ def print_inference_simulator_model_list(self, project_uid, statuses, row, page):
1208
1172
  if not project_uid:
1209
1173
  project_config: ProjectConfig = self.__config_provider.read_project_config()
1210
1174
  if not project_config:
@@ -1212,8 +1176,7 @@ class ProjectService(AbstractService):
1212
1176
  raise typer.Exit(1)
1213
1177
  project_uid = project_config.slug
1214
1178
 
1215
- inference_simulator_model_status_map = self.__thestage_api_client.get_inference_simulator_model_business_status_map(
1216
- config.main.thestage_auth_token)
1179
+ inference_simulator_model_status_map = self.__thestage_api_client.get_inference_simulator_model_business_status_map()
1217
1180
 
1218
1181
  if not statuses:
1219
1182
  statuses = ({key: inference_simulator_model_status_map[key] for key in [
@@ -1248,7 +1211,6 @@ class ProjectService(AbstractService):
1248
1211
  'statuses': backend_statuses,
1249
1212
  },
1250
1213
  mapper=ProjectInferenceSimulatorModelMapper(),
1251
- config=config,
1252
1214
  headers=list(map(lambda x: x.alias, ProjectInferenceSimulatorModelEntity.model_fields.values())),
1253
1215
  row=row,
1254
1216
  page=page,
@@ -1257,7 +1219,7 @@ class ProjectService(AbstractService):
1257
1219
  )
1258
1220
 
1259
1221
 
1260
- def print_task_list(self, config: ConfigEntity, project_uid, row, page):
1222
+ def print_task_list(self, project_uid, row, page):
1261
1223
  if not project_uid:
1262
1224
  project_config: ProjectConfig = self.__config_provider.read_project_config()
1263
1225
  if not project_config:
@@ -1271,7 +1233,6 @@ class ProjectService(AbstractService):
1271
1233
  'project_slug': project_uid,
1272
1234
  },
1273
1235
  mapper=ProjectTaskMapper(),
1274
- config=config,
1275
1236
  headers=list(map(lambda x: x.alias, ProjectTaskEntity.model_fields.values())),
1276
1237
  row=row,
1277
1238
  page=page,
@@ -27,6 +27,8 @@ old_value: int = 0
27
27
 
28
28
 
29
29
  class RemoteServerService:
30
+ __config_provider: ConfigProvider = None
31
+ __file_system_service: FileSystemService = None
30
32
 
31
33
  def __init__(
32
34
  self,
@@ -490,9 +492,9 @@ class RemoteServerService:
490
492
  dest_path: str,
491
493
  instance_path: str,
492
494
  copy_only_folder_contents: bool,
493
- config: ConfigEntity,
494
495
  depth: int = 0,
495
496
  ) -> List[SftpFileItemEntity]:
497
+ config = self.__config_provider.get_config()
496
498
  path_items = []
497
499
  try:
498
500
  root_stat = sftp.stat(current_path)
@@ -547,7 +549,6 @@ class RemoteServerService:
547
549
  instance_path=parent.instance_path,
548
550
  depth=depth + 1,
549
551
  copy_only_folder_contents=copy_only_folder_contents,
550
- config=config,
551
552
  ))
552
553
  return path_items
553
554
  except FileNotFoundError as ex:
@@ -568,7 +569,6 @@ class RemoteServerService:
568
569
  instance_path: str,
569
570
  copy_only_folder_contents: bool,
570
571
  private_key_path: Optional[str],
571
- config: ConfigEntity,
572
572
  ):
573
573
  has_error = False
574
574
 
@@ -581,7 +581,6 @@ class RemoteServerService:
581
581
  instance_path=instance_path,
582
582
  dest_path=dest_path,
583
583
  copy_only_folder_contents=copy_only_folder_contents,
584
- config=config,
585
584
  )
586
585
 
587
586
  if len(files) == 0:
@@ -1,5 +1,6 @@
1
1
  from typing import Optional
2
2
 
3
+ from thestage.services.config_provider.config_provider import ConfigProvider
3
4
  from thestage.services.connect.connect_service import ConnectService
4
5
  from thestage.services.filesystem_service import FileSystemService
5
6
  from thestage.services.logging.logging_service import LoggingService
@@ -10,73 +11,63 @@ from thestage.services.instance.instance_service import InstanceService
10
11
  from thestage.services.app_config_service import AppConfigService
11
12
  from thestage.services.clients.git.git_client import GitLocalClient
12
13
  from thestage.services.clients.thestage_api.api_client import TheStageApiClient
13
- from thestage.services.config_provider.config_provider import ConfigProvider
14
14
  from thestage.services.validation_service import ValidationService
15
15
 
16
16
 
17
17
  class ServiceFactory:
18
- __config_provider: Optional[ConfigProvider] = None
19
18
  __thestage_api_client: Optional[TheStageApiClient] = None
20
19
  __git_local_client: Optional[GitLocalClient] = None
21
20
  __file_system_service: Optional[FileSystemService] = None
21
+ __config_provider: Optional[ConfigProvider] = None
22
22
 
23
- def __init__(
24
- self,
25
- config_provider: Optional[ConfigProvider] = None,
26
- ):
27
- self.__config_provider = config_provider
28
-
29
- def get_config_provider(self) -> ConfigProvider:
30
- return self.__config_provider
31
23
 
32
- def get_validation_service(self, config_provider: Optional[ConfigProvider] = None,) -> ValidationService:
24
+ def get_validation_service(self) -> ValidationService:
33
25
  return ValidationService(
34
26
  thestage_api_client=self.get_thestage_api_client(),
35
- config_provider=config_provider if config_provider else self.__config_provider,
27
+ config_provider=self.get_config_provider(),
36
28
  )
37
29
 
38
- def get_instance_service(self, config_provider: Optional[ConfigProvider] = None) -> InstanceService:
30
+ def get_instance_service(self) -> InstanceService:
39
31
  return InstanceService(
40
32
  thestage_api_client=self.get_thestage_api_client(),
41
- config_provider=config_provider if config_provider else self.__config_provider,
42
33
  remote_server_service=self.get_remote_server_service(),
34
+ config_provider=self.get_config_provider(),
43
35
  )
44
36
 
45
- def get_container_service(self, config_provider: Optional[ConfigProvider] = None) -> ContainerService:
37
+ def get_container_service(self) -> ContainerService:
46
38
  return ContainerService(
47
39
  thestage_api_client=self.get_thestage_api_client(),
48
- config_provider=config_provider if config_provider else self.__config_provider,
49
40
  remote_server_service=self.get_remote_server_service(),
50
41
  file_system_service=self.get_file_system_service(),
42
+ config_provider=self.get_config_provider(),
51
43
  )
52
44
 
53
- def get_connect_service(self, config_provider: Optional[ConfigProvider] = None) -> ConnectService:
45
+ def get_connect_service(self) -> ConnectService:
54
46
  return ConnectService(
55
- config_provider=config_provider if config_provider else self.__config_provider,
56
47
  thestage_api_client=self.get_thestage_api_client(),
57
48
  instance_service=self.get_instance_service(),
58
49
  container_service=self.get_container_service(),
59
50
  logging_service=self.get_logging_service(),
60
51
  )
61
52
 
62
- def get_project_service(self, config_provider: Optional[ConfigProvider] = None) -> ProjectService:
53
+ def get_project_service(self) -> ProjectService:
63
54
  return ProjectService(
64
55
  thestage_api_client=self.get_thestage_api_client(),
65
- config_provider=config_provider if config_provider else self.__config_provider,
66
56
  remote_server_service=self.get_remote_server_service(),
67
57
  file_system_service=self.get_file_system_service(),
68
58
  git_local_client=self.get_git_local_client(),
59
+ config_provider=self.get_config_provider(),
69
60
  )
70
61
 
71
62
  def get_remote_server_service(self) -> RemoteServerService:
72
63
  return RemoteServerService(
73
- config_provider=self.get_config_provider(),
74
64
  file_system_service=self.get_file_system_service(),
65
+ config_provider=self.get_config_provider(),
75
66
  )
76
67
 
77
68
  def get_thestage_api_client(self) -> TheStageApiClient:
78
69
  if not self.__thestage_api_client:
79
- self.__thestage_api_client = TheStageApiClient(api_url=self.__config_provider.get_full_config().main.thestage_api_url)
70
+ self.__thestage_api_client = TheStageApiClient(config_provider=self.get_config_provider())
80
71
  return self.__thestage_api_client
81
72
 
82
73
  def get_git_local_client(self):
@@ -89,15 +80,18 @@ class ServiceFactory:
89
80
  self.__file_system_service = FileSystemService()
90
81
  return self.__file_system_service
91
82
 
92
- def get_app_config_service(self, config_provider: Optional[ConfigProvider] = None,) -> AppConfigService:
83
+ def get_app_config_service(self) -> AppConfigService:
93
84
  return AppConfigService(
94
- validation_service=self.get_validation_service(config_provider),
95
- config_provider=config_provider if config_provider else self.__config_provider,
85
+ config_provider=self.get_config_provider(),
86
+ validation_service=self.get_validation_service(),
96
87
  )
97
88
 
98
- def get_logging_service(self, config_provider: Optional[ConfigProvider] = None) -> LoggingService:
89
+ def get_logging_service(self) -> LoggingService:
99
90
  return LoggingService(
100
91
  thestage_api_client=self.get_thestage_api_client(),
101
- config_provider=config_provider if config_provider else self.__config_provider,
102
92
  )
103
93
 
94
+ def get_config_provider(self) -> ConfigProvider:
95
+ if not self.__config_provider:
96
+ self.__config_provider = ConfigProvider(self.get_file_system_service())
97
+ return self.__config_provider
@@ -1,13 +1,15 @@
1
1
  import typer
2
2
 
3
3
  from thestage.i18n.translation import __
4
- from thestage.services.config_provider.config_provider import ConfigProvider
4
+ # from thestage.main import update_allowed_commands
5
5
  from thestage.services.clients.thestage_api.api_client import TheStageApiClient
6
+ from thestage.services.config_provider.config_provider import ConfigProvider
6
7
  from thestage.services.core_files.config_entity import ConfigEntity
7
8
 
8
9
 
9
10
  class ValidationService:
10
11
  _thestage_api_client: TheStageApiClient = None
12
+ _config_provider: ConfigProvider = None
11
13
 
12
14
  def __init__(
13
15
  self,
@@ -18,10 +20,8 @@ class ValidationService:
18
20
  self._config_provider = config_provider
19
21
 
20
22
 
21
- def check_token(
22
- self,
23
- config: ConfigEntity,
24
- ):
23
+ def check_token(self):
24
+ config = self._config_provider.get_config()
25
25
  token = config.main.thestage_auth_token
26
26
  if not token:
27
27
  token: str = typer.prompt(
@@ -32,16 +32,21 @@ class ValidationService:
32
32
  )
33
33
 
34
34
  # TODO this fails with 503 error - AttributeError("'bytes' object has no attribute 'text'") from _parse_api_response method in core
35
- is_valid: bool = False
36
- if token:
37
- is_valid = self._thestage_api_client.validate_token(token=token)
35
+ if not token:
36
+ return
37
+
38
+ token_validate_response = self._thestage_api_client.validate_token(token=token)
39
+ is_valid = token_validate_response.is_success if token_validate_response else False
38
40
  if not is_valid:
39
41
  typer.echo(__(
40
42
  'API token is invalid: generate API token using TheStage AI WebApp'
41
43
  ))
42
44
  raise typer.Exit(1)
43
45
 
44
- config.main.thestage_auth_token = token
46
+ if config.main.thestage_auth_token != token:
47
+ config.main.thestage_auth_token = token
48
+ self._config_provider.update_config(updated_config=config)
49
+ self._config_provider.update_allowed_commands_and_is_token_valid(validate_token_response=token_validate_response)
45
50
 
46
51
 
47
52
  @staticmethod