thestage 0.6.6__py3-none-any.whl → 0.6.8__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 (194) hide show
  1. thestage/__init__.py +1 -1
  2. thestage/cli_command_helper.py +2 -2
  3. thestage/config/__init__.py +1 -1
  4. thestage/{services → config/business}/app_config_service.py +3 -4
  5. thestage/{services/config_provider → config/business}/config_provider.py +6 -5
  6. thestage/config/{config_storage.py → business/config_storage.py} +1 -1
  7. thestage/{services → config/business}/validation_service.py +9 -10
  8. thestage/{controllers/config_controller.py → config/communication/config_command.py} +7 -7
  9. thestage/{services/connect → connect/business}/connect_service.py +25 -22
  10. thestage/{services → connect/business}/remote_server_service.py +4 -5
  11. thestage/connect/communication/connect_api_client.py +84 -0
  12. thestage/{services/clients/thestage_api/dtos/ssh_key_controller → connect/dto}/add_ssh_key_to_user_response.py +0 -1
  13. thestage/{services/clients/thestage_api/dtos/ssh_key_controller → connect/dto}/add_ssh_public_key_to_instance_response.py +1 -4
  14. thestage/{services/clients/thestage_api/dtos/base_controller → connect/dto}/connect_resolve_response.py +1 -1
  15. thestage/controllers/base_controller.py +2 -2
  16. thestage/debug_main.dist.py +16 -14
  17. thestage/{services/container → docker_container/business}/container_service.py +120 -40
  18. thestage/{services/container → docker_container/business}/mapper/container_mapper.py +3 -3
  19. thestage/docker_container/communication/__init__.py +0 -0
  20. thestage/{controllers/container_controller.py → docker_container/communication/docker_command.py} +27 -86
  21. thestage/docker_container/communication/docker_container_api_client.py +99 -0
  22. thestage/docker_container/dto/__init__.py +0 -0
  23. thestage/docker_container/dto/container_action_request.py +11 -0
  24. thestage/{services/clients/thestage_api/dtos → docker_container/dto}/container_response.py +4 -4
  25. thestage/{services/clients/thestage_api/dtos/docker_container_controller → docker_container/dto}/docker_container_list_response.py +3 -5
  26. thestage/docker_container/dto/enum/__init__.py +0 -0
  27. thestage/git/__init__.py +0 -0
  28. thestage/git/business/__init__.py +0 -0
  29. thestage/git/communication/__init__.py +0 -0
  30. thestage/{services/clients/git → git/communication}/git_client.py +5 -5
  31. thestage/global_dto/__init__.py +0 -0
  32. thestage/global_dto/enums/__init__.py +0 -0
  33. thestage/helpers/error_handler.py +5 -5
  34. thestage/helpers/logger/app_logger.py +1 -3
  35. thestage/i18n/en_GB/messages.po +14 -14
  36. thestage/inference_model/__init__.py +0 -0
  37. thestage/inference_model/business/__init__.py +0 -0
  38. thestage/inference_model/business/inference_model_service.py +281 -0
  39. thestage/inference_model/business/mapper/__init__.py +0 -0
  40. thestage/{services/project/mapper/project_inference_simulator_model_mapper.py → inference_model/business/mapper/inference_model_mapper.py} +5 -5
  41. thestage/inference_model/communication/__init__.py +0 -0
  42. thestage/inference_model/communication/inference_model_api_client.py +139 -0
  43. thestage/inference_model/communication/inference_model_command.py +246 -0
  44. thestage/inference_model/dto/__init__.py +0 -0
  45. thestage/{services/clients/thestage_api/dtos/inference_controller → inference_model/dto}/deploy_inference_model_to_instance_request.py +0 -2
  46. thestage/{services/clients/thestage_api/dtos/inference_controller → inference_model/dto}/deploy_inference_model_to_instance_response.py +2 -1
  47. thestage/inference_model/dto/enum/__init__.py +0 -0
  48. thestage/{services/project/dto/inference_simulator_model_dto.py → inference_model/dto/inference_model.py} +1 -1
  49. thestage/{entities/project_inference_simulator_model.py → inference_model/dto/inference_model_entity.py} +2 -2
  50. thestage/{services/clients/thestage_api/dtos/inference_controller → inference_model/dto}/inference_simulator_model_list_for_project_response.py +2 -3
  51. thestage/{services/clients/thestage_api/dtos/project_controller/project_push_inference_simulator_model_request.py → inference_model/dto/push_inference_simulator_model_request.py} +1 -1
  52. thestage/{services/clients/thestage_api/dtos/project_controller/project_push_inference_simulator_model_response.py → inference_model/dto/push_inference_simulator_model_response.py} +1 -1
  53. thestage/inference_simulator/__init__.py +0 -0
  54. thestage/inference_simulator/business/__init__.py +0 -0
  55. thestage/inference_simulator/business/inference_simulator_service.py +338 -0
  56. thestage/inference_simulator/business/mapper/__init__.py +0 -0
  57. thestage/{services/project/mapper/project_inference_simulator_mapper.py → inference_simulator/business/mapper/inference_simulator_mapper.py} +5 -5
  58. thestage/inference_simulator/communication/__init__.py +0 -0
  59. thestage/inference_simulator/communication/inference_simulator_api_client.py +114 -0
  60. thestage/inference_simulator/communication/inference_simulator_command.py +347 -0
  61. thestage/inference_simulator/dto/__init__.py +0 -0
  62. thestage/inference_simulator/dto/enum/__init__.py +0 -0
  63. thestage/{services/clients/thestage_api/dtos/inference_controller → inference_simulator/dto}/get_inference_simulator_request.py +1 -1
  64. thestage/inference_simulator/dto/get_inference_simulator_response.py +12 -0
  65. thestage/{services/project/dto/inference_simulator_dto.py → inference_simulator/dto/inference_simulator.py} +1 -1
  66. thestage/{entities/project_inference_simulator.py → inference_simulator/dto/inference_simulator_entity.py} +1 -1
  67. thestage/{services/clients/thestage_api/dtos/inference_controller → inference_simulator/dto}/inference_simulator_list_response.py +2 -2
  68. thestage/{services/clients/thestage_api/dtos/project_controller/project_start_inference_simulator_request.py → inference_simulator/dto/start_inference_simulator_request.py} +1 -1
  69. thestage/inference_simulator/dto/start_inference_simulator_response.py +10 -0
  70. thestage/instance/__init__.py +0 -0
  71. thestage/instance/business/__init__.py +0 -0
  72. thestage/{services/instance → instance/business}/instance_service.py +26 -27
  73. thestage/instance/business/mapper/__init__.py +0 -0
  74. thestage/{services/instance/mapper/instance_mapper.py → instance/business/mapper/rented_instance_mapper.py} +3 -3
  75. thestage/{services/instance/mapper/selfhosted_mapper.py → instance/business/mapper/selfhosted_instance_mapper.py} +5 -7
  76. thestage/instance/communication/__init__.py +0 -0
  77. thestage/instance/communication/instance_api_client.py +150 -0
  78. thestage/{controllers/instance_controller.py → instance/communication/instance_command.py} +9 -9
  79. thestage/instance/dto/__init__.py +0 -0
  80. thestage/instance/dto/enum/__init__.py +0 -0
  81. thestage/{services/clients/thestage_api/dtos → instance/dto}/instance_detected_gpus.py +1 -2
  82. thestage/{services/clients/thestage_api/dtos → instance/dto}/instance_rented_response.py +2 -2
  83. thestage/{services/clients/thestage_api/dtos → instance/dto}/selfhosted_instance_response.py +2 -3
  84. thestage/logging/__init__.py +0 -0
  85. thestage/logging/business/__init__.py +0 -0
  86. thestage/{services/logging → logging/business}/logging_service.py +45 -36
  87. thestage/logging/communication/__init__.py +0 -0
  88. thestage/logging/communication/logging_api_client.py +63 -0
  89. thestage/logging/dto/__init__.py +0 -0
  90. thestage/{services/clients/thestage_api/dtos/logging_controller → logging/dto}/log_polling_response.py +2 -2
  91. thestage/{services/clients/thestage_api/dtos/logging_controller → logging/dto}/user_logs_query_response.py +2 -2
  92. thestage/main.py +48 -9
  93. thestage/project/__init__.py +0 -0
  94. thestage/project/business/__init__.py +0 -0
  95. thestage/project/business/project_service.py +480 -0
  96. thestage/project/communication/__init__.py +0 -0
  97. thestage/project/communication/project_api_client.py +46 -0
  98. thestage/project/communication/project_command.py +284 -0
  99. thestage/project/dto/__init__.py +0 -0
  100. thestage/{services/project → project}/dto/project_config.py +1 -2
  101. thestage/services/clients/thestage_api/core/api_client_core.py +1 -1
  102. thestage/services/clients/thestage_api/dtos/entity_filter_request.py +1 -1
  103. thestage/services/clients/thestage_api/dtos/sftp_path_helper.py +1 -1
  104. thestage/services/filesystem_service.py +2 -2
  105. thestage/services/service_factory.py +130 -43
  106. thestage/task/__init__.py +0 -0
  107. thestage/task/business/__init__.py +0 -0
  108. thestage/task/business/mapper/__init__.py +0 -0
  109. thestage/{services/project/mapper/project_task_mapper.py → task/business/mapper/task_mapper.py} +5 -5
  110. thestage/task/business/task_service.py +304 -0
  111. thestage/task/communication/__init__.py +0 -0
  112. thestage/task/communication/task_api_client.py +122 -0
  113. thestage/task/communication/task_command.py +212 -0
  114. thestage/task/dto/__init__.py +0 -0
  115. thestage/task/dto/enum/__init__.py +0 -0
  116. thestage/{services/clients/thestage_api/dtos/task_controller/task_list_for_project_response.py → task/dto/list_for_project_response.py} +2 -2
  117. thestage/{services/clients/thestage_api/dtos/project_controller/project_run_task_request.py → task/dto/run_task_request.py} +1 -1
  118. thestage/task/dto/run_task_response.py +13 -0
  119. thestage/{services/task/dto/task_dto.py → task/dto/task.py} +1 -4
  120. thestage/{entities/project_task.py → task/dto/task_entity.py} +1 -1
  121. thestage/{services/clients/thestage_api/dtos/task_controller/task_view_response.py → task/dto/view_response.py} +2 -2
  122. {thestage-0.6.6.dist-info → thestage-0.6.8.dist-info}/METADATA +2 -1
  123. thestage-0.6.8.dist-info/RECORD +219 -0
  124. {thestage-0.6.6.dist-info → thestage-0.6.8.dist-info}/WHEEL +1 -1
  125. thestage/controllers/project_controller.py +0 -1058
  126. thestage/services/clients/thestage_api/api_client.py +0 -753
  127. thestage/services/clients/thestage_api/dtos/container_param_request.py +0 -11
  128. thestage/services/clients/thestage_api/dtos/inference_controller/get_inference_simulator_response.py +0 -13
  129. thestage/services/clients/thestage_api/dtos/project_controller/project_run_task_response.py +0 -10
  130. thestage/services/clients/thestage_api/dtos/project_controller/project_start_inference_simulator_response.py +0 -10
  131. thestage/services/clients/thestage_api/dtos/user_controller/user_profile.py +0 -12
  132. thestage/services/project/project_service.py +0 -1283
  133. thestage-0.6.6.dist-info/RECORD +0 -167
  134. /thestage/{entities → color_scheme}/__init__.py +0 -0
  135. /thestage/{entities/enums → config/business}/__init__.py +0 -0
  136. /thestage/{services/clients/git → config/communication}/__init__.py +0 -0
  137. /thestage/{services/clients/thestage_api/dtos/enums → config/dto}/__init__.py +0 -0
  138. /thestage/{services/core_files → config/dto}/config_entity.py +0 -0
  139. /thestage/{services/connect → config}/dto/remote_server_config.py +0 -0
  140. /thestage/{services/config_provider → connect}/__init__.py +0 -0
  141. /thestage/{services/container → connect/business}/__init__.py +0 -0
  142. /thestage/{services/container/mapper → connect/communication}/__init__.py +0 -0
  143. /thestage/{services/instance → connect/dto}/__init__.py +0 -0
  144. /thestage/{services/clients/thestage_api/dtos/ssh_key_controller → connect/dto}/add_ssh_key_to_user_request.py +0 -0
  145. /thestage/{services/clients/thestage_api/dtos/ssh_key_controller → connect/dto}/add_ssh_public_key_to_instance_request.py +0 -0
  146. /thestage/{services/clients/thestage_api/dtos/ssh_key_controller → connect/dto}/is_user_has_public_ssh_key_request.py +0 -0
  147. /thestage/{services/clients/thestage_api/dtos/ssh_key_controller → connect/dto}/is_user_has_public_ssh_key_response.py +0 -0
  148. /thestage/{services/instance/mapper → docker_container}/__init__.py +0 -0
  149. /thestage/{services/project → docker_container/business}/__init__.py +0 -0
  150. /thestage/{services/project → docker_container/business}/mapper/__init__.py +0 -0
  151. /thestage/{entities/container.py → docker_container/dto/container_entity.py} +0 -0
  152. /thestage/{services/clients/thestage_api/dtos/docker_container_controller → docker_container/dto}/docker_container_list_request.py +0 -0
  153. /thestage/{services/clients/thestage_api/dtos → docker_container/dto}/docker_container_mapping.py +0 -0
  154. /thestage/{services/clients/thestage_api/dtos/enums → docker_container/dto/enum}/container_pending_action.py +0 -0
  155. /thestage/{services/clients/thestage_api/dtos/enums → docker_container/dto/enum}/container_status.py +0 -0
  156. /thestage/{services/logging/exception → exceptions}/log_polling_exception.py +0 -0
  157. /thestage/git/{ProgressPrinter.py → business/ProgressPrinter.py} +0 -0
  158. /thestage/{entities → global_dto}/enums/order_direction_type.py +0 -0
  159. /thestage/{entities → global_dto}/enums/shell_type.py +0 -0
  160. /thestage/{entities → global_dto}/enums/tail_output_type.py +0 -0
  161. /thestage/{entities → global_dto}/enums/yes_no_response.py +0 -0
  162. /thestage/{entities → global_dto}/file_item.py +0 -0
  163. /thestage/{services/clients/thestage_api/dtos/inference_controller → inference_model/dto}/deploy_inference_model_to_sagemaker_request.py +0 -0
  164. /thestage/{services/clients/thestage_api/dtos/inference_controller → inference_model/dto}/deploy_inference_model_to_sagemaker_response.py +0 -0
  165. /thestage/{services/clients/thestage_api/dtos/enums → inference_model/dto/enum}/inference_model_status.py +0 -0
  166. /thestage/{services/clients/thestage_api/dtos/inference_controller → inference_model/dto}/inference_simulator_model_list_for_project_request.py +0 -0
  167. /thestage/{services/clients/thestage_api/dtos → inference_model/dto}/inference_simulator_model_response.py +0 -0
  168. /thestage/{services/clients/thestage_api/dtos/enums → inference_simulator/dto/enum}/inference_simulator_status.py +0 -0
  169. /thestage/{services/clients/thestage_api/dtos/inference_controller → inference_simulator/dto}/inference_simulator_list_request.py +0 -0
  170. /thestage/{services/clients/thestage_api/dtos → inference_simulator/dto}/inference_simulator_response.py +0 -0
  171. /thestage/{services/clients/thestage_api/dtos/enums → instance/dto/enum}/cpu_type.py +0 -0
  172. /thestage/{services/clients/thestage_api/dtos/enums → instance/dto/enum}/gpu_name.py +0 -0
  173. /thestage/{services/clients/thestage_api/dtos/enums → instance/dto/enum}/instance_rented_status.py +0 -0
  174. /thestage/{services/clients/thestage_api/dtos/enums → instance/dto/enum}/provider_name.py +0 -0
  175. /thestage/{services/clients/thestage_api/dtos/enums → instance/dto/enum}/selfhosted_status.py +0 -0
  176. /thestage/{entities → instance/dto}/rented_instance.py +0 -0
  177. /thestage/{entities → instance/dto}/self_hosted_instance.py +0 -0
  178. /thestage/{services/logging → logging}/byte_print_style.py +0 -0
  179. /thestage/{services/clients/thestage_api/dtos/logging_controller → logging/dto}/docker_container_log_stream_request.py +0 -0
  180. /thestage/{services/logging → logging}/dto/log_message.py +0 -0
  181. /thestage/{services/clients/thestage_api/dtos/logging_controller → logging/dto}/log_polling_request.py +0 -0
  182. /thestage/{services/logging → logging}/dto/log_type.py +0 -0
  183. /thestage/{services/clients/thestage_api/dtos/logging_controller → logging/dto}/task_log_stream_request.py +0 -0
  184. /thestage/{services/clients/thestage_api/dtos/logging_controller → logging/dto}/user_logs_query_request.py +0 -0
  185. /thestage/{services/logging → logging}/logging_constants.py +0 -0
  186. /thestage/{services/clients/thestage_api/dtos/project_controller/project_get_deploy_ssh_key_request.py → project/dto/get_deploy_ssh_key_request.py} +0 -0
  187. /thestage/{services/clients/thestage_api/dtos/project_controller/project_get_deploy_ssh_key_response.py → project/dto/get_deploy_ssh_key_response.py} +0 -0
  188. /thestage/{services/clients/thestage_api/dtos → project/dto}/project_response.py +0 -0
  189. /thestage/{services/clients/thestage_api/dtos/enums → task/dto/enum}/task_execution_status.py +0 -0
  190. /thestage/{services/clients/thestage_api/dtos/enums → task/dto/enum}/task_status.py +0 -0
  191. /thestage/{services/clients/thestage_api/dtos/task_controller/task_list_for_project_request.py → task/dto/list_for_project_request.py} +0 -0
  192. /thestage/{services/clients/thestage_api/dtos/task_controller/task_status_localized_map_response.py → task/dto/status_localized_map_response.py} +0 -0
  193. {thestage-0.6.6.dist-info → thestage-0.6.8.dist-info}/entry_points.txt +0 -0
  194. {thestage-0.6.6.dist-info → thestage-0.6.8.dist-info}/licenses/LICENSE.txt +0 -0
@@ -12,9 +12,9 @@ from gitdb.exc import BadName
12
12
  from rich import print
13
13
 
14
14
  from thestage.color_scheme.color_scheme import ColorScheme
15
- from thestage.config import THESTAGE_CONFIG_DIR
15
+ from thestage.config.env_base import THESTAGE_CONFIG_DIR
16
16
  from thestage.exceptions.git_access_exception import GitAccessException
17
- from thestage.git.ProgressPrinter import ProgressPrinter
17
+ from thestage.git.business.ProgressPrinter import ProgressPrinter
18
18
  from thestage.services.filesystem_service import FileSystemService
19
19
 
20
20
 
@@ -33,7 +33,7 @@ class GitLocalClient:
33
33
  ):
34
34
  self.__file_system_service = file_system_service
35
35
 
36
- # todo delete this fuckery
36
+ # todo delete this
37
37
  def __get_repo(self, path: str) -> Repo:
38
38
  return git.Repo(path)
39
39
 
@@ -196,7 +196,7 @@ class GitLocalClient:
196
196
  ) -> Optional[str]:
197
197
  repo = self.__get_repo(path=path)
198
198
  if repo.head.is_detached:
199
- line_color = ColorScheme.GIT_HEADLESS
199
+ line_color = ColorScheme.GIT_HEADLESS.value
200
200
  print(f'[{line_color}]Committing in detached head state at {repo.head.commit.hexsha}[/{line_color}]')
201
201
  commit_name = name if name else f"Auto commit {str(datetime.datetime.now().date())}"
202
202
  commit = repo.git.commit('--allow-empty', '-m', commit_name, )
@@ -392,7 +392,7 @@ class GitLocalClient:
392
392
  repo.git.reset('--hard', f'origin/{repo.active_branch.name}')
393
393
  typer.echo(f'Branch "{repo.active_branch.name}" is now synced to its remote counterpart')
394
394
  else:
395
- typer.echo('simple branch reset is not implemented')
395
+ typer.echo('Simple branch reset is not implemented')
396
396
 
397
397
  # refers to a "headless commit" where something was committed while in detached head state and head is pointing at that commit
398
398
  def is_head_committed_in_headless_state(self, path: str) -> bool:
File without changes
File without changes
@@ -7,7 +7,7 @@ from click.exceptions import Exit, Abort
7
7
  from git import GitCommandError
8
8
  from paramiko.ssh_exception import PasswordRequiredException
9
9
 
10
- from thestage.config import THESTAGE_API_URL
10
+ from thestage.config.env_base import THESTAGE_API_URL
11
11
  from thestage.exceptions.file_system_exception import FileSystemException
12
12
  from thestage.exceptions.remote_server_exception import RemoteServerException
13
13
  from thestage.i18n.translation import __
@@ -26,7 +26,7 @@ def error_handler() -> Callable:
26
26
  result = f(*args, **kwargs)
27
27
  return result
28
28
  except AuthException as e1:
29
- typer.echo(__('Authentication failed: update API token'))
29
+ typer.echo(__('Authentication failed: update access token'))
30
30
  app_logger.error(f'{traceback.format_exc()}')
31
31
  raise typer.Exit(1)
32
32
  except BusinessLogicException as e2:
@@ -98,7 +98,7 @@ def error_handler() -> Callable:
98
98
  raise typer.Exit(1)
99
99
  except PasswordRequiredException as e11:
100
100
  # technically we can use encrypted keys but dealing with passwords is big bs
101
- typer.echo("Provided key requires password. Please use non-encrypted key.")
101
+ typer.echo("Provided key requires password. Use non-encrypted key.")
102
102
  app_logger.error(f'{traceback.format_exc()}')
103
103
  raise typer.Exit(1)
104
104
  except Exception as e100:
@@ -106,8 +106,8 @@ def error_handler() -> Callable:
106
106
  raise e100
107
107
  else:
108
108
  typer.echo(__('Undefined error occurred'))
109
- typer.echo(e100.__class__.__name__)
110
- print(traceback.format_exc())
109
+ # typer.echo(e100.__class__.__name__)
110
+ # print(traceback.format_exc())
111
111
  # TODO send all exceptions to backend?
112
112
  app_logger.error(f'{traceback.format_exc()}')
113
113
  raise typer.Exit(1)
@@ -3,10 +3,8 @@ import platform
3
3
  from logging.handlers import RotatingFileHandler
4
4
  from pathlib import Path
5
5
  from thestage import __app_name__, __version__
6
+ from thestage.config.env_base import THESTAGE_CONFIG_DIR, THESTAGE_LOGGING_FILE
6
7
 
7
- from thestage.config import THESTAGE_CONFIG_DIR
8
-
9
- from thestage.config import THESTAGE_LOGGING_FILE
10
8
  from thestage.exceptions.file_system_exception import FileSystemException
11
9
 
12
10
 
@@ -161,7 +161,7 @@ msgstr "Add URL to your own repository"
161
161
 
162
162
  # Branch: feature/add_new_method_for_containers
163
163
  #: tsr/controllers/sketch_controller.py
164
- msgid "This folder is not empty, we can not clone here"
164
+ msgid "This folder is not empty, we cannot clone here"
165
165
  msgstr "Cannot clone: the folder is not empty"
166
166
 
167
167
  # Branch: feature/add_new_method_for_containers
@@ -362,7 +362,7 @@ msgstr "Task title is required: please type or select to auto-generate"
362
362
 
363
363
  # Branch: feature/add_new_method_for_containers
364
364
  #: tsr/services/sketch/sketch_service.py
365
- msgid "Task title can not be empty"
365
+ msgid "Task title cannot be empty"
366
366
  msgstr "Task title is required"
367
367
 
368
368
  # Branch: feature/add_new_method_for_containers
@@ -427,7 +427,7 @@ msgstr "Incorrect slug specified: sketch not found"
427
427
 
428
428
  # Branch: feature/add_new_method_for_containers
429
429
  #: tsr/services/sketch/sketch_service.py
430
- msgid "You have local repo with remote, we can not work with this"
430
+ msgid "You have local repo with remote, we cannot work with this"
431
431
  msgstr "Your local repository is linked to a remote: this configuration is not supported for the current operation"
432
432
 
433
433
  # Branch: feature/add_new_method_for_containers
@@ -442,12 +442,12 @@ msgstr "Your local repo has been modified and is not empty, please create an emp
442
442
 
443
443
  # Branch: feature/add_new_method_for_containers
444
444
  #: tsr/services/sketch/sketch_service.py
445
- msgid "We can not add remote, something wrong"
445
+ msgid "We cannot add remote, something wrong"
446
446
  msgstr "Cannot add remote, something wrong"
447
447
 
448
448
  # Branch: feature/add_new_method_for_containers
449
449
  #: tsr/services/sketch/sketch_service.py
450
- msgid "You have local repo, we can not work with this"
450
+ msgid "You have local repo, we cannot work with this"
451
451
  msgstr "Local repository in use: not supported for current operation"
452
452
 
453
453
  # Branch: feature/add_new_method_for_containers
@@ -517,12 +517,12 @@ msgstr "Path not found"
517
517
 
518
518
  # Branch: feature/add_new_method_for_containers
519
519
  #: tsr/services/filesystem_service.py
520
- msgid "We can not make dir"
520
+ msgid "We cannot make dir"
521
521
  msgstr "Failed to create directory"
522
522
 
523
523
  # Branch: feature/add_new_method_for_containers
524
524
  #: tsr/services/filesystem_service.py
525
- msgid "We can not make file"
525
+ msgid "We cannot make file"
526
526
  msgstr "Failed to create file"
527
527
 
528
528
  # Branch: feature/add_new_method_for_containers
@@ -692,12 +692,12 @@ msgstr "Cannot connect to rented or self-hosted instance"
692
692
 
693
693
  # Branch: feature/add_new_method_for_containers
694
694
  #: tsr/services/container/container_service.py
695
- msgid "Container name not present, can not connect to container"
695
+ msgid "Container name not present, cannot connect to container"
696
696
  msgstr "Cannot connect to container: please specify container slug"
697
697
 
698
698
  # Branch: feature/add_new_method_for_containers
699
699
  #: tsr/services/container/container_service.py
700
- msgid "We can not get shell on container (bash, shell), please use standard shell"
700
+ msgid "We cannot get shell on container (bash, shell), please use standard shell"
701
701
  msgstr "Unable to access the requested shell (bash, shell) in the container: please use the default shell available in the container"
702
702
 
703
703
  # Branch: feature/add_new_method_for_containers
@@ -722,7 +722,7 @@ msgstr "Specify username to connect to server instance"
722
722
 
723
723
  # Branch: feature/add_new_method_for_containers
724
724
  #: tsr/services/container/container_service.py
725
- msgid "Container is running, can not start working server"
725
+ msgid "Container is running, cannot start working server"
726
726
  msgstr "Container is running: cannot start running container"
727
727
 
728
728
  # Branch: feature/add_new_method_for_containers
@@ -797,7 +797,7 @@ msgstr "Server instance slug not found"
797
797
 
798
798
  # Branch: feature/add_new_method_for_containers
799
799
  #: tsr/services/sketch/sketch_service.py
800
- msgid "Slug can not be empty"
800
+ msgid "Slug cannot be empty"
801
801
  msgstr "Specify slug"
802
802
 
803
803
  # Branch: main
@@ -928,17 +928,17 @@ msgstr ""
928
928
 
929
929
  # Branch: main
930
930
  #: tsr/services/container/container_service.py
931
- msgid "Error, can not find mapping folders"
931
+ msgid "Error, cannot find mapping folders"
932
932
  msgstr ""
933
933
 
934
934
  # Branch: main
935
935
  #: tsr/services/container/container_service.py
936
- msgid "Error, can not find mapping for /public folder"
936
+ msgid "Error, cannot find mapping for /public folder"
937
937
  msgstr ""
938
938
 
939
939
  # Branch: main
940
940
  #: tsr/services/remote_server_service.py
941
- msgid "Can not find mapping folders"
941
+ msgid "cannot find mapping folders"
942
942
  msgstr ""
943
943
 
944
944
  # Branch: main
File without changes
File without changes
@@ -0,0 +1,281 @@
1
+ import time
2
+ from datetime import datetime
3
+ from typing import Optional, List
4
+
5
+ import boto3
6
+ import typer
7
+
8
+ from thestage.config.business.config_provider import ConfigProvider
9
+ from thestage.helpers.error_handler import error_handler
10
+ from thestage.i18n.translation import __
11
+ from thestage.inference_model.business.mapper.inference_model_mapper import InferenceModelMapper
12
+ from thestage.inference_model.communication.inference_model_api_client import InferenceModelApiClient
13
+ from thestage.inference_model.dto.deploy_inference_model_to_instance_response import \
14
+ DeployInferenceModelToInstanceResponse
15
+ from thestage.inference_model.dto.deploy_inference_model_to_sagemaker_response import \
16
+ DeployInferenceModelToSagemakerResponse
17
+ from thestage.inference_model.dto.enum.inference_model_status import InferenceModelStatus
18
+ from thestage.inference_model.dto.inference_model import InferenceModel
19
+ from thestage.inference_model.dto.inference_model_entity import InferenceModelEntity
20
+ from thestage.project.business.project_service import ProjectService
21
+ from thestage.project.dto.project_config import ProjectConfig
22
+ from thestage.services.abstract_service import AbstractService
23
+ from thestage.services.clients.thestage_api.dtos.paginated_entity_list import PaginatedEntityList
24
+
25
+
26
+ class InferenceModelService(AbstractService):
27
+ def __init__(
28
+ self,
29
+ inference_model_api_client: InferenceModelApiClient,
30
+ config_provider: ConfigProvider,
31
+ project_service: ProjectService,
32
+ ):
33
+ self.__inference_model_api_client = inference_model_api_client
34
+ self.__config_provider = config_provider
35
+ self.__project_service = project_service
36
+
37
+
38
+ @error_handler()
39
+ def get_project_inference_simulator_model_list(
40
+ self,
41
+ project_public_id: Optional[str],
42
+ project_slug: Optional[str],
43
+ statuses: List[str],
44
+ row: int = 5,
45
+ page: int = 1,
46
+ ) -> PaginatedEntityList[InferenceModel]:
47
+ data: Optional[
48
+ PaginatedEntityList[InferenceModel]] = self.__inference_model_api_client.get_inference_simulator_model_list_for_project(
49
+ statuses=statuses,
50
+ project_public_id=project_public_id,
51
+ project_slug=project_slug,
52
+ page=page,
53
+ limit=row,
54
+ )
55
+
56
+ return data
57
+
58
+ @error_handler()
59
+ def project_deploy_inference_simulator_model_to_instance(
60
+ self,
61
+ model_public_id: Optional[str] = None,
62
+ model_slug: Optional[str] = None,
63
+ rented_instance_public_id: Optional[str] = None,
64
+ rented_instance_slug: Optional[str] = None,
65
+ self_hosted_instance_public_id: Optional[str] = None,
66
+ self_hosted_instance_slug: Optional[str] = None,
67
+ ) -> str:
68
+ config = self.__config_provider.get_config()
69
+ project_config: ProjectConfig = self.__project_service.get_fixed_project_config()
70
+ if not project_config:
71
+ typer.echo(
72
+ __("No project found at the path: %path%. Please initialize or clone a project first. Or provide path to project using --working-directory option.",
73
+ {"path": config.runtime.working_directory}))
74
+ raise typer.Exit(1)
75
+
76
+ instance_args_count = sum(v is not None for v in
77
+ [rented_instance_public_id, rented_instance_slug, self_hosted_instance_public_id,
78
+ self_hosted_instance_slug])
79
+ if instance_args_count != 1:
80
+ typer.echo("Please provide a single instance (rented or self-hosted) identifier - name or ID.")
81
+ raise typer.Exit(1)
82
+
83
+ model_args_count = sum(v is not None for v in [model_public_id, model_slug])
84
+ if model_args_count != 1:
85
+ typer.echo("Please provide a single model identifier - name or ID.")
86
+ raise typer.Exit(1)
87
+
88
+ typer.echo(f"Creating inference simulator")
89
+ deploy_model_to_instance_response: DeployInferenceModelToInstanceResponse = self.__inference_model_api_client.deploy_inference_model_to_instance(
90
+ model_public_id=model_public_id,
91
+ model_slug=model_slug,
92
+ rented_instance_public_id=rented_instance_public_id,
93
+ rented_instance_slug=rented_instance_slug,
94
+ self_hosted_instance_public_id=self_hosted_instance_public_id,
95
+ self_hosted_instance_slug=self_hosted_instance_slug,
96
+ )
97
+ if deploy_model_to_instance_response:
98
+ if deploy_model_to_instance_response.message:
99
+ typer.echo(deploy_model_to_instance_response.message)
100
+ if deploy_model_to_instance_response.is_success:
101
+ typer.echo("Inference simulator has been scheduled to run successfully.")
102
+ else:
103
+ typer.echo(__(
104
+ 'Failed to start inference simulator: %server_massage%',
105
+ {'server_massage': deploy_model_to_instance_response.message or ""}
106
+ ))
107
+ raise typer.Exit(1)
108
+ else:
109
+ typer.echo(__("Failed to start inference simulator"))
110
+ raise typer.Exit(1)
111
+
112
+ return deploy_model_to_instance_response.inferenceSimulatorPublicId
113
+
114
+
115
+ @error_handler()
116
+ def project_deploy_inference_simulator_model_to_sagemaker(
117
+ self,
118
+ model_public_id: Optional[str] = None,
119
+ model_slug: Optional[str] = None,
120
+ arn: Optional[str] = None,
121
+ instance_type: Optional[str] = None,
122
+ initial_variant_weight: Optional[float] = 1.0,
123
+ initial_instance_count: Optional[int] = None,
124
+ ) -> None:
125
+ config = self.__config_provider.get_config()
126
+ project_config: ProjectConfig = self.__project_service.get_fixed_project_config()
127
+ if not project_config:
128
+ typer.echo(
129
+ __("No project found at the path: %path%. Please initialize or clone a project first. Or provide path to project using --working-directory option.",
130
+ {"path": config.runtime.working_directory}))
131
+ raise typer.Exit(1)
132
+
133
+ if not instance_type:
134
+ typer.echo(__("Error: Instance type is required."))
135
+ raise typer.Exit(1)
136
+
137
+ if not initial_instance_count:
138
+ typer.echo(__("Error: Initial instance count is required."))
139
+ raise typer.Exit(1)
140
+
141
+ if not arn:
142
+ typer.echo(__("Error: ARN is required."))
143
+ raise typer.Exit(1)
144
+
145
+ project_config: ProjectConfig = self.__config_provider.read_project_config()
146
+ if not project_config:
147
+ typer.echo(__("No project found at the path: %path%. Please initialize or clone a project first.",
148
+ {"path": config.runtime.working_directory}))
149
+ raise typer.Exit(1)
150
+
151
+ deploy_model_to_sagemaker_response: DeployInferenceModelToSagemakerResponse = self.__inference_model_api_client.deploy_inference_model_to_sagemaker(
152
+ model_public_id=model_public_id,
153
+ model_slug=model_slug,
154
+ arn=arn,
155
+ )
156
+
157
+ if not deploy_model_to_sagemaker_response.is_success:
158
+ typer.echo(__(
159
+ 'Model deployment preparation failed: %server_massage%',
160
+ {'server_massage': deploy_model_to_sagemaker_response.message or ""}
161
+ ))
162
+ raise typer.Exit(1)
163
+
164
+ model_id = deploy_model_to_sagemaker_response.modelId
165
+ image_uri = deploy_model_to_sagemaker_response.ecrImageUrl
166
+ model_uri = deploy_model_to_sagemaker_response.s3ArtifactsUrl
167
+ region = "us-east-1"
168
+ sm_client = boto3.client('sagemaker', region_name=region)
169
+
170
+ try:
171
+ container = {
172
+ "Image": image_uri,
173
+ "ModelDataUrl": model_uri,
174
+ "Environment": {
175
+ "SAGEMAKER_TRITON_DEFAULT_MODEL_NAME": model_id,
176
+ "THESTAGE_API_URL": config.main.thestage_api_url,
177
+ "THESTAGE_AUTH_TOKEN": config.main.thestage_auth_token
178
+ },
179
+ }
180
+
181
+ sm_model_name = f"{model_slug}-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
182
+ create_model_response = sm_client.create_model(
183
+ ModelName=sm_model_name,
184
+ ExecutionRoleArn=arn,
185
+ PrimaryContainer=container,
186
+ )
187
+ typer.echo(f"Model created successfully. Model ARN: {create_model_response['ModelArn']}")
188
+
189
+ endpoint_config_name = f"{model_slug}-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
190
+ create_endpoint_config_response = sm_client.create_endpoint_config(
191
+ EndpointConfigName=endpoint_config_name,
192
+ ProductionVariants=[
193
+ {
194
+ "InstanceType": instance_type,
195
+ "InitialVariantWeight": initial_variant_weight,
196
+ "InitialInstanceCount": initial_instance_count,
197
+ "ModelName": sm_model_name,
198
+ "VariantName": "AllTraffic",
199
+ }
200
+ ],
201
+ )
202
+ typer.echo(
203
+ f"Endpoint configuration created successfully. Endpoint Config ARN: {create_endpoint_config_response['EndpointConfigArn']}")
204
+
205
+ endpoint_name = f"{model_slug}-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
206
+ create_endpoint_response = sm_client.create_endpoint(
207
+ EndpointName=endpoint_name,
208
+ EndpointConfigName=endpoint_config_name,
209
+ )
210
+ typer.echo(f"Endpoint created successfully. Endpoint ARN: {create_endpoint_response['EndpointArn']}")
211
+
212
+ typer.echo("Waiting for the endpoint to become active...")
213
+ while True:
214
+ resp = sm_client.describe_endpoint(EndpointName=endpoint_name)
215
+ status = resp["EndpointStatus"]
216
+ typer.echo(f"Status: {status}")
217
+ if status == "InService":
218
+ break
219
+ elif status == "Failed":
220
+ typer.echo(f"Endpoint creation failed. Reason: {resp.get('FailureReason', 'Unknown')}")
221
+ raise typer.Exit(1)
222
+ time.sleep(60)
223
+
224
+ typer.echo(f"Endpoint is ready. ARN: {resp['EndpointArn']} Status: {status}")
225
+
226
+ except Exception as e:
227
+ typer.echo(__("Failed to deploy the inference simulator model to SageMaker: %error%", {"error": str(e)}))
228
+ raise typer.Exit(1)
229
+
230
+
231
+ @error_handler()
232
+ def print_inference_simulator_model_list(self, project_public_id, project_slug, statuses, row, page):
233
+ if not project_public_id and not project_slug:
234
+ project_config: ProjectConfig = self.__config_provider.read_project_config()
235
+ if not project_config:
236
+ typer.echo(__("Provide the project unique ID or run this command from within an initialized project directory"))
237
+ raise typer.Exit(1)
238
+ project_public_id = project_config.public_id
239
+
240
+ inference_simulator_model_status_map = self.__inference_model_api_client.get_inference_simulator_model_business_status_map()
241
+
242
+ if not statuses:
243
+ statuses = ({key: inference_simulator_model_status_map[key] for key in [
244
+ InferenceModelStatus.SCHEDULED,
245
+ InferenceModelStatus.PROCESSING,
246
+ InferenceModelStatus.PUSH_SUCCEED,
247
+ ]}).values()
248
+
249
+ if "all" in statuses:
250
+ statuses = inference_simulator_model_status_map.values()
251
+
252
+ for input_status_item in statuses:
253
+ if input_status_item not in inference_simulator_model_status_map.values():
254
+ typer.echo(__("'%invalid_status%' is not one of %valid_statuses%", {
255
+ 'invalid_status': input_status_item,
256
+ 'valid_statuses': str(list(inference_simulator_model_status_map.values()))
257
+ }))
258
+ raise typer.Exit(1)
259
+
260
+ typer.echo(__(
261
+ "Listing inference simulator models with the following statuses: %statuses%, to view all inference simulator models, use --status all",
262
+ placeholders={
263
+ 'statuses': ', '.join([status_item for status_item in statuses])
264
+ }))
265
+
266
+ backend_statuses: List[str] = [key for key, value in inference_simulator_model_status_map.items() if value in statuses]
267
+
268
+ self.print(
269
+ func_get_data=self.get_project_inference_simulator_model_list,
270
+ func_special_params={
271
+ 'project_public_id': project_public_id,
272
+ 'project_slug': project_slug,
273
+ 'statuses': backend_statuses,
274
+ },
275
+ mapper=InferenceModelMapper(),
276
+ headers=list(map(lambda x: x.alias, InferenceModelEntity.model_fields.values())),
277
+ row=row,
278
+ page=page,
279
+ max_col_width=[100, 100, 100, 100, 25],
280
+ show_index="never",
281
+ )
File without changes
@@ -1,16 +1,16 @@
1
1
  from typing import Optional
2
2
 
3
- from thestage.entities.project_inference_simulator_model import ProjectInferenceSimulatorModelEntity
3
+ from thestage.inference_model.dto.inference_model_entity import InferenceModelEntity
4
4
  from thestage.services.abstract_mapper import AbstractMapper
5
- from thestage.services.project.dto.inference_simulator_model_dto import InferenceSimulatorModelDto
5
+ from thestage.inference_model.dto.inference_model import InferenceModel
6
6
 
7
7
 
8
- class ProjectInferenceSimulatorModelMapper(AbstractMapper):
9
- def build_entity(self, item: InferenceSimulatorModelDto) -> Optional[ProjectInferenceSimulatorModelEntity]:
8
+ class InferenceModelMapper(AbstractMapper):
9
+ def build_entity(self, item: InferenceModel) -> Optional[InferenceModelEntity]:
10
10
  if not item:
11
11
  return None
12
12
 
13
- return ProjectInferenceSimulatorModelEntity(
13
+ return InferenceModelEntity(
14
14
  public_id=item.public_id,
15
15
  slug=item.slug,
16
16
  status=item.status or '',
File without changes
@@ -0,0 +1,139 @@
1
+ from typing import Optional, List, Dict
2
+
3
+ from thestage.config.business.config_provider import ConfigProvider
4
+ from thestage.global_dto.enums.order_direction_type import OrderDirectionType
5
+ from thestage.helpers.error_handler import error_handler
6
+ from thestage.services.clients.thestage_api.core.api_client_core import TheStageApiClientCore
7
+ from thestage.services.clients.thestage_api.dtos.entity_filter_request import EntityFilterRequest
8
+ from thestage.services.clients.thestage_api.dtos.paginated_entity_list import PaginatedEntityList
9
+
10
+ from thestage.inference_model.dto.inference_model import InferenceModel
11
+ from thestage.inference_model.dto.inference_simulator_model_list_for_project_request import InferenceSimulatorModelListForProjectRequest
12
+ from thestage.inference_model.dto.inference_simulator_model_list_for_project_response import InferenceSimulatorModelListForProjectResponse
13
+ from thestage.inference_model.dto.push_inference_simulator_model_request import PushInferenceSimulatorModelRequest
14
+ from thestage.inference_model.dto.push_inference_simulator_model_response import PushInferenceSimulatorModelResponse
15
+ from thestage.inference_model.dto.inference_simulator_model_response import InferenceSimulatorModelStatusMapperResponse
16
+ from thestage.inference_model.dto.deploy_inference_model_to_instance_request import DeployInferenceModelToInstanceRequest
17
+ from thestage.inference_model.dto.deploy_inference_model_to_instance_response import DeployInferenceModelToInstanceResponse
18
+ from thestage.inference_model.dto.deploy_inference_model_to_sagemaker_request import DeployInferenceModelToSagemakerRequest
19
+ from thestage.inference_model.dto.deploy_inference_model_to_sagemaker_response import DeployInferenceModelToSagemakerResponse
20
+
21
+
22
+ class InferenceModelApiClient(TheStageApiClientCore):
23
+ def __init__(self, config_provider: ConfigProvider):
24
+ super().__init__(url=config_provider.get_config().main.thestage_api_url)
25
+ self.__config_provider = config_provider
26
+
27
+ def get_inference_simulator_model_list_for_project(
28
+ self,
29
+ project_public_id: Optional[str],
30
+ project_slug: Optional[str],
31
+ statuses: Optional[List[str]] = None,
32
+ page: int = 1,
33
+ limit: int = 10,
34
+ ) -> Optional[PaginatedEntityList[InferenceModel]]:
35
+ request = InferenceSimulatorModelListForProjectRequest(
36
+ projectPublicId=project_public_id,
37
+ projectSlug=project_slug,
38
+ statuses=statuses,
39
+ entityFilterRequest=EntityFilterRequest(
40
+ orderByField="createdAt",
41
+ orderByDirection=OrderDirectionType.DESC,
42
+ page=page,
43
+ limit=limit,
44
+ ),
45
+ )
46
+
47
+ response = self._request(
48
+ method='POST',
49
+ url='/user-api/v2/inference-simulator-model/list',
50
+ data=request.model_dump(),
51
+ token=self.__config_provider.get_config().main.thestage_auth_token,
52
+ )
53
+ result = InferenceSimulatorModelListForProjectResponse.model_validate(response) if response else None
54
+ return result.inferenceSimulatorModels if result and result.is_success else None
55
+
56
+
57
+ def push_project_inference_simulator_model(
58
+ self,
59
+ public_id: Optional[str],
60
+ slug: Optional[str],
61
+ ) -> Optional[PushInferenceSimulatorModelResponse]:
62
+ request = PushInferenceSimulatorModelRequest(
63
+ inferenceSimulatorPublicId=public_id,
64
+ inferenceSimulatorSlug=slug,
65
+ )
66
+
67
+ response = self._request(
68
+ method='POST',
69
+ url='/user-api/v2/inference-simulator/push-model',
70
+ data=request.model_dump(),
71
+ token=self.__config_provider.get_config().main.thestage_auth_token,
72
+ )
73
+
74
+ return PushInferenceSimulatorModelResponse.model_validate(response) if response else None
75
+
76
+
77
+ def get_inference_simulator_model_business_status_map(self) -> Optional[Dict[str, str]]:
78
+ response = self._request(
79
+ method='POST',
80
+ url='/user-api/v1/inference-simulator-model/status-localized-mapping',
81
+ data=None,
82
+ token=self.__config_provider.get_config().main.thestage_auth_token,
83
+ )
84
+
85
+ data = InferenceSimulatorModelStatusMapperResponse.model_validate(response) if response else None
86
+
87
+ return data.inference_simulator_model_status_map if data else None
88
+
89
+
90
+ @error_handler()
91
+ def deploy_inference_model_to_instance(
92
+ self,
93
+ model_public_id: str,
94
+ model_slug: str,
95
+ new_inference_simulator_slug: str,
96
+ rented_instance_public_id: Optional[str] = None,
97
+ rented_instance_slug: Optional[str] = None,
98
+ self_hosted_instance_public_id: Optional[str] = None,
99
+ self_hosted_instance_slug: Optional[str] = None,
100
+
101
+ ) -> Optional[DeployInferenceModelToInstanceResponse]:
102
+ request = DeployInferenceModelToInstanceRequest(
103
+ modelPublicId=model_public_id,
104
+ modelSlug=model_slug,
105
+ instanceRentedPublicId=rented_instance_public_id,
106
+ instanceRentedSlug=rented_instance_slug,
107
+ selfhostedInstancePublicId=self_hosted_instance_public_id,
108
+ selfhostedInstanceSlug=self_hosted_instance_slug
109
+ )
110
+
111
+ response = self._request(
112
+ method='POST',
113
+ url='/user-api/v2/inference-simulator-model/deploy/instance',
114
+ data=request.model_dump(),
115
+ token=self.__config_provider.get_config().main.thestage_auth_token,
116
+ )
117
+ return DeployInferenceModelToInstanceResponse.model_validate(response) if response else None
118
+
119
+
120
+ @error_handler()
121
+ def deploy_inference_model_to_sagemaker(
122
+ self,
123
+ model_public_id: Optional[str],
124
+ model_slug: Optional[str],
125
+ arn: Optional[str] = None,
126
+ ) -> Optional[DeployInferenceModelToSagemakerResponse]:
127
+ request = DeployInferenceModelToSagemakerRequest(
128
+ modelPublicId=model_public_id,
129
+ modelSlug=model_slug,
130
+ arn=arn,
131
+ )
132
+
133
+ response = self._request(
134
+ method='POST',
135
+ url='/user-api/v1/inference-simulator-model/grant-user-arn-access',
136
+ data=request.model_dump(),
137
+ token=self.__config_provider.get_config().main.thestage_auth_token,
138
+ )
139
+ return DeployInferenceModelToSagemakerResponse.model_validate(response) if response else None