thestage 0.5.44__py3-none-any.whl → 0.5.46__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 (26) hide show
  1. thestage/__init__.py +1 -1
  2. thestage/controllers/container_controller.py +0 -3
  3. thestage/controllers/instance_controller.py +8 -75
  4. thestage/controllers/project_controller.py +3 -121
  5. thestage/main.py +6 -1
  6. thestage/services/clients/git/git_client.py +2 -2
  7. thestage/services/clients/thestage_api/api_client.py +21 -43
  8. thestage/services/clients/thestage_api/dtos/enums/instance_rented_status.py +1 -0
  9. thestage/services/clients/thestage_api/dtos/enums/selfhosted_status.py +1 -1
  10. thestage/services/clients/thestage_api/dtos/{user_profile.py → user_controller/user_profile.py} +6 -3
  11. thestage/services/config_provider/config_provider.py +10 -29
  12. thestage/services/connect/connect_service.py +12 -5
  13. thestage/services/container/container_service.py +2 -2
  14. thestage/services/core_files/config_entity.py +2 -7
  15. thestage/services/filesystem_service.py +19 -2
  16. thestage/services/instance/instance_service.py +101 -7
  17. thestage/services/project/project_service.py +141 -2
  18. thestage/services/remote_server_service.py +2 -2
  19. thestage/services/service_factory.py +4 -4
  20. thestage/services/validation_service.py +0 -6
  21. {thestage-0.5.44.dist-info → thestage-0.5.46.dist-info}/METADATA +2 -2
  22. {thestage-0.5.44.dist-info → thestage-0.5.46.dist-info}/RECORD +25 -26
  23. {thestage-0.5.44.dist-info → thestage-0.5.46.dist-info}/WHEEL +1 -1
  24. thestage/services/clients/.DS_Store +0 -0
  25. {thestage-0.5.44.dist-info → thestage-0.5.46.dist-info}/LICENSE.txt +0 -0
  26. {thestage-0.5.44.dist-info → thestage-0.5.46.dist-info}/entry_points.txt +0 -0
@@ -10,7 +10,7 @@ from thestage.exceptions.file_system_exception import FileSystemException
10
10
  from thestage.services.core_files.config_entity import ConfigEntity
11
11
  from thestage.helpers.ssh_util import parse_private_key
12
12
  from thestage.services.connect.dto.remote_server_config import RemoteServerConfig
13
- from thestage.services.filesystem_service import FileSystemServiceCore
13
+ from thestage.services.filesystem_service import FileSystemService
14
14
  from thestage.services.project.dto.project_config import ProjectConfig
15
15
  from thestage.config import THESTAGE_CONFIG_DIR, THESTAGE_CONFIG_FILE, THESTAGE_AUTH_TOKEN, THESTAGE_API_URL
16
16
 
@@ -20,30 +20,27 @@ class ConfigProvider():
20
20
  _local_config_path: Optional[Path] = None
21
21
  _global_config_path: Optional[Path] = None
22
22
  _global_config_file: Optional[Path] = None
23
- _file_system_service = FileSystemServiceCore
23
+ _file_system_service = FileSystemService
24
24
 
25
25
 
26
26
  def __init__(
27
27
  self,
28
28
  local_path: Optional[str] = None,
29
29
  ):
30
- self._file_system_service = FileSystemServiceCore()
30
+ self._file_system_service = FileSystemService()
31
31
  if local_path:
32
32
  self._local_path = self._file_system_service.get_path(directory=local_path, auto_create=False)
33
33
 
34
- config_folder_name = self._file_system_service.get_path(f"{THESTAGE_CONFIG_DIR}", False)
35
- self._local_config_path = self._local_path.joinpath(config_folder_name)
34
+ self._local_config_path = self._local_path.joinpath(THESTAGE_CONFIG_DIR)
36
35
 
37
36
  home_dir = self._file_system_service.get_home_path()
38
- self._global_config_path = home_dir.joinpath(config_folder_name)
37
+ self._global_config_path = home_dir.joinpath(THESTAGE_CONFIG_DIR)
39
38
 
40
39
  if self._global_config_path:
41
40
  if not self._global_config_path.exists():
42
41
  self._file_system_service.create_if_not_exists_dir(self._global_config_path)
43
42
 
44
- self._global_config_file = self._global_config_path.joinpath(
45
- self._file_system_service.get_path(f"{THESTAGE_CONFIG_FILE}", False)
46
- )
43
+ self._global_config_file = self._global_config_path.joinpath(THESTAGE_CONFIG_FILE)
47
44
  if not self._global_config_file.exists():
48
45
  self._file_system_service.create_if_not_exists_file(self._global_config_file)
49
46
 
@@ -61,7 +58,7 @@ class ConfigProvider():
61
58
  if config_from_env:
62
59
  self.__update_config_values_dict(values_to_update=config_values, new_values=config_from_env)
63
60
 
64
- config_from_file = self.__read_config_file(self._global_config_file)
61
+ config_from_file = self._file_system_service.read_config_file(self._global_config_file)
65
62
  if config_from_file:
66
63
  self.__update_config_values_dict(values_to_update=config_values, new_values=config_from_file)
67
64
 
@@ -112,7 +109,7 @@ class ConfigProvider():
112
109
  if not project_data_filepath.exists():
113
110
  return None
114
111
 
115
- config_data = self.__read_config_file(project_data_filepath) if project_data_filepath and project_data_filepath.exists() else {}
112
+ config_data = self._file_system_service.read_config_file(project_data_filepath) if project_data_filepath and project_data_filepath.exists() else {}
116
113
  return ProjectConfig.model_validate(config_data)
117
114
 
118
115
 
@@ -165,7 +162,7 @@ class ConfigProvider():
165
162
  if not config_filepath.is_file():
166
163
  return None
167
164
 
168
- config_data = self.__read_config_file(config_filepath) if config_filepath and config_filepath.exists() else {}
165
+ config_data = self._file_system_service.read_config_file(config_filepath) if config_filepath and config_filepath.exists() else {}
169
166
  return RemoteServerConfig.model_validate(config_data)
170
167
 
171
168
 
@@ -188,22 +185,6 @@ class ConfigProvider():
188
185
  else:
189
186
  values_to_update['main'] = new_values['main']
190
187
 
191
-
192
- def __read_config_file(self, path: Path) -> Dict[str, Any]:
193
- result = {}
194
- try:
195
- if path and path.exists():
196
- with path.open("r") as file:
197
- try:
198
- if os.stat(path).st_size != 0:
199
- result = json.load(file)
200
- except JSONDecodeError:
201
- pass
202
- except OSError:
203
- raise FileSystemException(f"Could not open config file: {path}")
204
- return result
205
-
206
-
207
188
  @staticmethod
208
189
  def __save_config_file(data: Dict, file_path: Path):
209
190
  with open(file_path, 'w') as configfile:
@@ -211,7 +192,7 @@ class ConfigProvider():
211
192
 
212
193
 
213
194
  def save_config(self, config: ConfigEntity):
214
- data: Dict[str, Any] = self.__read_config_file(self._global_config_file)
195
+ data: Dict[str, Any] = self._file_system_service.read_config_file(self._global_config_file)
215
196
  data.update(config.model_dump(exclude_none=True, by_alias=True, exclude={'runtime', 'RUNTIME', 'daemon', 'DAEMON'}))
216
197
  self.__save_config_file(data=data, file_path=self._global_config_file)
217
198
 
@@ -50,20 +50,25 @@ class ConnectService(AbstractService):
50
50
  ):
51
51
  config = self._config_provider.get_full_config()
52
52
 
53
- # TODO make a single separate method that will return all needed info
54
53
  try:
55
- instance_selfhosted = self.__thestage_api_client.get_selfhosted_item(token=config.main.thestage_auth_token, instance_slug=uid)
54
+ instance_selfhosted = self.__thestage_api_client.get_selfhosted_instance(token=config.main.thestage_auth_token, instance_slug=uid)
56
55
  except HttpClientException as e:
56
+ if e.get_status_code() == 403:
57
+ typer.echo("Missing permission to view self-hosted instances")
57
58
  instance_selfhosted = None
58
59
 
59
60
  try:
60
- instance_rented = self.__thestage_api_client.get_rented_item(token=config.main.thestage_auth_token, instance_slug=uid)
61
+ instance_rented = self.__thestage_api_client.get_rented_instance(token=config.main.thestage_auth_token, instance_slug=uid)
61
62
  except HttpClientException as e:
63
+ if e.get_status_code() == 403:
64
+ typer.echo("Missing permission to view rented instances")
62
65
  instance_rented = None
63
66
 
64
67
  try:
65
68
  container = self.__thestage_api_client.get_container(token=config.main.thestage_auth_token, container_slug=uid, )
66
- except Exception as e:
69
+ except HttpClientException as e:
70
+ if e.get_status_code() == 403:
71
+ typer.echo("Missing permission to view containers")
67
72
  container = None
68
73
 
69
74
  task: Optional[TaskDto] = None
@@ -71,6 +76,8 @@ class ConnectService(AbstractService):
71
76
  try:
72
77
  task_view_response = self.__thestage_api_client.get_task(token=config.main.thestage_auth_token, task_id=int(uid))
73
78
  except HttpClientException as e:
79
+ if e.get_status_code() == 403:
80
+ typer.echo("Missing permission to view tasks")
74
81
  task_view_response = None
75
82
  if task_view_response and task_view_response.task:
76
83
  task = task_view_response.task
@@ -148,7 +155,7 @@ class ConnectService(AbstractService):
148
155
  instance_rented: Optional[InstanceRentedDto] = None
149
156
  if instance_slug:
150
157
  try:
151
- instance_rented = self.__thestage_api_client.get_rented_item(token=config.main.thestage_auth_token, instance_slug=instance_slug)
158
+ instance_rented = self.__thestage_api_client.get_rented_instance(token=config.main.thestage_auth_token, instance_slug=instance_slug)
152
159
  except HttpClientException as e:
153
160
  instance_rented = None
154
161
 
@@ -10,7 +10,7 @@ from thestage.services.clients.thestage_api.dtos.enums.container_status import D
10
10
  from thestage.entities.enums.shell_type import ShellType
11
11
  from thestage.services.clients.thestage_api.dtos.paginated_entity_list import PaginatedEntityList
12
12
  from thestage.services.container.mapper.container_mapper import ContainerMapper
13
- from thestage.services.filesystem_service import FileSystemServiceCore
13
+ from thestage.services.filesystem_service import FileSystemService
14
14
  from thestage.services.remote_server_service import RemoteServerService
15
15
  from thestage.i18n.translation import __
16
16
  from thestage.services.abstract_service import AbstractService
@@ -29,7 +29,7 @@ class ContainerService(AbstractService):
29
29
  thestage_api_client: TheStageApiClient,
30
30
  config_provider: ConfigProvider,
31
31
  remote_server_service: RemoteServerService,
32
- file_system_service: FileSystemServiceCore,
32
+ file_system_service: FileSystemService,
33
33
  ):
34
34
  super(ContainerService, self).__init__(
35
35
  config_provider=config_provider
@@ -7,11 +7,6 @@ class MainConfigEntity(BaseModel):
7
7
  thestage_auth_token: Optional[str] = Field(None, alias='thestage_auth_token')
8
8
  thestage_api_url: Optional[str] = Field(None, alias='thestage_api_url')
9
9
 
10
-
11
- class DaemonConfigEntity(BaseModel):
12
- daemon_token: Optional[str] = Field(None, alias='daemon_token')
13
- backend_api_url: Optional[str] = Field(None, alias='backend_api_url')
14
-
15
10
  # not saved to file
16
11
  class RuntimeConfigEntity(BaseModel):
17
12
  working_directory: Optional[str] = Field(None, alias='working_directory')
@@ -19,7 +14,7 @@ class RuntimeConfigEntity(BaseModel):
19
14
 
20
15
 
21
16
  class ConfigEntity(BaseModel):
17
+ global_config_path: str = Field(None, alias='global_config_path')
18
+ can_use_inference: bool = Field(None, alias='can_use_inference')
22
19
  main: MainConfigEntity = Field(default_factory=MainConfigEntity, alias='main')
23
20
  runtime: RuntimeConfigEntity = Field(default_factory=RuntimeConfigEntity, alias="runtime") # TODO merge with main
24
- daemon: DaemonConfigEntity = Field(default_factory=DaemonConfigEntity, alias="daemon") # TODO this should not be in core package
25
- start_on_daemon: bool = Field(False, alias='start_on_daemon') # TODO this should not be in core package
@@ -1,13 +1,15 @@
1
+ import json
1
2
  import os
2
3
  import shutil
4
+ from json import JSONDecodeError
3
5
  from pathlib import Path
4
- from typing import Optional, List
6
+ from typing import Optional, List, Dict, Any
5
7
 
6
8
  from thestage.entities.file_item import FileItemEntity
7
9
  from thestage.exceptions.file_system_exception import FileSystemException
8
10
 
9
11
 
10
- class FileSystemServiceCore:
12
+ class FileSystemService:
11
13
 
12
14
  def get_ssh_path(self) -> Optional[Path]:
13
15
  home_path = self.get_home_path()
@@ -114,3 +116,18 @@ class FileSystemServiceCore:
114
116
  real_path = self.get_path(directory=path, auto_create=False)
115
117
  if real_path and real_path.exists():
116
118
  shutil.rmtree(real_path)
119
+
120
+
121
+ def read_config_file(self, path: Path) -> Dict[str, Any]:
122
+ result = {}
123
+ try:
124
+ if path and path.exists():
125
+ with path.open("r") as file:
126
+ try:
127
+ if os.stat(path).st_size != 0:
128
+ result = json.load(file)
129
+ except JSONDecodeError:
130
+ pass
131
+ except OSError:
132
+ raise FileSystemException(f"Could not open config file: {path}")
133
+ return result
@@ -2,6 +2,9 @@ from pathlib import Path
2
2
  from typing import List, Optional, Dict
3
3
 
4
4
  import typer
5
+
6
+ from thestage.entities.rented_instance import RentedInstanceEntity
7
+ from thestage.entities.self_hosted_instance import SelfHostedInstanceEntity
5
8
  from thestage.services.core_files.config_entity import ConfigEntity
6
9
  from thestage.i18n.translation import __
7
10
  from thestage.services.clients.thestage_api.dtos.enums.selfhosted_status import SelfhostedBusinessStatus
@@ -13,6 +16,8 @@ from thestage.services.clients.thestage_api.dtos.instance_rented_response import
13
16
  from thestage.services.clients.thestage_api.dtos.paginated_entity_list import PaginatedEntityList
14
17
  from thestage.services.clients.thestage_api.dtos.selfhosted_instance_response import SelfHostedInstanceDto
15
18
  from thestage.services.config_provider.config_provider import ConfigProvider
19
+ from thestage.services.instance.mapper.instance_mapper import InstanceMapper
20
+ from thestage.services.instance.mapper.selfhosted_mapper import SelfHostedMapper
16
21
  from thestage.services.remote_server_service import RemoteServerService
17
22
 
18
23
 
@@ -32,22 +37,22 @@ class InstanceService(AbstractService):
32
37
  self.__thestage_api_client = thestage_api_client
33
38
  self.__remote_server_service = remote_server_service
34
39
 
35
- def get_rented_item(
40
+ def get_rented_instance(
36
41
  self,
37
42
  config: ConfigEntity,
38
43
  instance_slug: str,
39
44
  ) -> Optional[InstanceRentedDto]:
40
- return self.__thestage_api_client.get_rented_item(
45
+ return self.__thestage_api_client.get_rented_instance(
41
46
  token=config.main.thestage_auth_token,
42
47
  instance_slug=instance_slug,
43
48
  )
44
49
 
45
- def get_self_hosted_item(
50
+ def get_self_hosted_instance(
46
51
  self,
47
52
  config: ConfigEntity,
48
53
  instance_slug: str,
49
54
  ) -> Optional[SelfHostedInstanceDto]:
50
- return self.__thestage_api_client.get_selfhosted_item(
55
+ return self.__thestage_api_client.get_selfhosted_instance(
51
56
  token=config.main.thestage_auth_token,
52
57
  instance_slug=instance_slug,
53
58
  )
@@ -100,7 +105,7 @@ class InstanceService(AbstractService):
100
105
  typer.echo(__('Cannot connect to self-hosted instance: it is awaiting configuration'))
101
106
  raise typer.Exit(1)
102
107
  elif instance.frontend_status.status_key in [
103
- SelfhostedBusinessStatus.TERMINATED.name,
108
+ SelfhostedBusinessStatus.UNREACHABLE_DAEMON.name,
104
109
  SelfhostedBusinessStatus.DELETED.name,
105
110
  ]:
106
111
  typer.echo(__('Cannot connect to self-hosted instance: it may be turned off or unreachable'))
@@ -121,7 +126,7 @@ class InstanceService(AbstractService):
121
126
  config: ConfigEntity,
122
127
  input_ssh_key_path: Optional[str]
123
128
  ):
124
- instance = self.get_rented_item(config=config, instance_slug=instance_rented_slug)
129
+ instance = self.get_rented_instance(config=config, instance_slug=instance_rented_slug)
125
130
 
126
131
  if instance:
127
132
  self.check_instance_status_to_connect(
@@ -162,7 +167,7 @@ class InstanceService(AbstractService):
162
167
  username = 'root'
163
168
  typer.echo(__("No remote server username provided, using 'root' as username"))
164
169
 
165
- instance = self.get_self_hosted_item(config=config, instance_slug=selfhosted_instance_slug)
170
+ instance = self.get_self_hosted_instance(config=config, instance_slug=selfhosted_instance_slug)
166
171
 
167
172
  if instance:
168
173
  self.check_selfhosted_status_to_connect(
@@ -222,3 +227,92 @@ class InstanceService(AbstractService):
222
227
  limit=row,
223
228
  )
224
229
  return data
230
+
231
+
232
+ @error_handler()
233
+ def print_self_hosted_instance_list(self, config: ConfigEntity, statuses, row, page):
234
+ selfhosted_instance_status_map = self.__thestage_api_client.get_selfhosted_business_status_map(config.main.thestage_auth_token)
235
+
236
+ if not statuses:
237
+ statuses = ({key: selfhosted_instance_status_map[key] for key in [
238
+ SelfhostedBusinessStatus.AWAITING_CONFIGURATION,
239
+ SelfhostedBusinessStatus.RUNNING,
240
+ SelfhostedBusinessStatus.UNREACHABLE_DAEMON,
241
+ ]}).values()
242
+
243
+ if "all" in statuses:
244
+ statuses = selfhosted_instance_status_map.values()
245
+
246
+ for input_status_item in statuses:
247
+ if input_status_item not in selfhosted_instance_status_map.values():
248
+ typer.echo(__("'%invalid_status%' is not one of %valid_statuses%", {
249
+ 'invalid_status': input_status_item,
250
+ 'valid_statuses': str(list(selfhosted_instance_status_map.values()))
251
+ }))
252
+ raise typer.Exit(1)
253
+
254
+ typer.echo(__(
255
+ "Listing self-hosted instances with the following statuses: %statuses%, to view all self-hosted instances, use --status all",
256
+ placeholders={
257
+ 'statuses': ', '.join([status_item for status_item in statuses])
258
+ }))
259
+
260
+ backend_statuses: List[str] = [key for key, value in selfhosted_instance_status_map.items() if value in statuses]
261
+
262
+ self.print(
263
+ func_get_data=self.get_self_hosted_list,
264
+ func_special_params={
265
+ 'statuses': backend_statuses,
266
+ },
267
+ mapper=SelfHostedMapper(),
268
+ config=config,
269
+ headers=list(map(lambda x: x.alias, SelfHostedInstanceEntity.model_fields.values())),
270
+ row=row,
271
+ page=page,
272
+ show_index="never",
273
+ )
274
+
275
+
276
+ @error_handler()
277
+ def print_rented_instance_list(self, config: ConfigEntity, statuses, row, page):
278
+ instance_rented_status_map = self.__thestage_api_client.get_rented_business_status_map(config.main.thestage_auth_token)
279
+
280
+ if not statuses:
281
+ statuses = ({key: instance_rented_status_map[key] for key in [
282
+ InstanceRentedBusinessStatus.ONLINE,
283
+ InstanceRentedBusinessStatus.CREATING,
284
+ InstanceRentedBusinessStatus.TERMINATING,
285
+ InstanceRentedBusinessStatus.REBOOTING,
286
+ ]}).values()
287
+
288
+ if "all" in statuses:
289
+ statuses = instance_rented_status_map.values()
290
+
291
+ for input_status_item in statuses:
292
+ if input_status_item not in instance_rented_status_map.values():
293
+ typer.echo(__("'%invalid_status%' is not one of %valid_statuses%", {
294
+ 'invalid_status': input_status_item,
295
+ 'valid_statuses': str(list(instance_rented_status_map.values()))
296
+ }))
297
+ raise typer.Exit(1)
298
+
299
+ typer.echo(__(
300
+ "Listing rented server instances with the following statuses: %statuses%, to view all rented server instances, use --status all",
301
+ placeholders={
302
+ 'statuses': ', '.join([status_item for status_item in statuses])
303
+ }))
304
+
305
+ backend_statuses: List[str] = [key for key, value in instance_rented_status_map.items() if value in statuses]
306
+
307
+ self.print(
308
+ func_get_data=self.get_rented_list,
309
+ func_special_params={
310
+ 'statuses': backend_statuses,
311
+ },
312
+ mapper=InstanceMapper(),
313
+ config=config,
314
+ headers=list(map(lambda x: x.alias, RentedInstanceEntity.model_fields.values())),
315
+ row=row,
316
+ page=page,
317
+ show_index="never",
318
+ )
@@ -12,7 +12,12 @@ import typer
12
12
  from git import Commit
13
13
  from tabulate import tabulate
14
14
 
15
+ from thestage.entities.project_inference_simulator import ProjectInferenceSimulatorEntity
16
+ from thestage.entities.project_inference_simulator_model import ProjectInferenceSimulatorModelEntity
17
+ from thestage.entities.project_task import ProjectTaskEntity
15
18
  from thestage.services.clients.thestage_api.core.http_client_exception import HttpClientException
19
+ from thestage.services.clients.thestage_api.dtos.enums.inference_model_status import InferenceModelStatus
20
+ from thestage.services.clients.thestage_api.dtos.enums.inference_simulator_status import InferenceSimulatorStatus
16
21
  from thestage.services.core_files.config_entity import ConfigEntity
17
22
  from thestage.color_scheme.color_scheme import ColorScheme
18
23
  from thestage.entities.enums.yes_no_response import YesOrNoResponse
@@ -36,9 +41,12 @@ from thestage.services.clients.thestage_api.dtos.project_controller.project_star
36
41
  ProjectStartInferenceSimulatorResponse
37
42
  from thestage.services.clients.thestage_api.dtos.project_response import ProjectDto
38
43
  from thestage.services.clients.thestage_api.dtos.task_controller.task_view_response import TaskViewResponse
39
- from thestage.services.filesystem_service import FileSystemServiceCore
44
+ from thestage.services.filesystem_service import FileSystemService
40
45
  from thestage.services.project.dto.inference_simulator_dto import InferenceSimulatorDto
41
46
  from thestage.services.project.dto.inference_simulator_model_dto import InferenceSimulatorModelDto
47
+ from thestage.services.project.mapper.project_inference_simulator_mapper import ProjectInferenceSimulatorMapper
48
+ from thestage.services.project.mapper.project_inference_simulator_model_mapper import \
49
+ ProjectInferenceSimulatorModelMapper
42
50
  from thestage.services.task.dto.task_dto import TaskDto
43
51
  from thestage.services.project.dto.project_config import ProjectConfig
44
52
  from thestage.services.project.mapper.project_task_mapper import ProjectTaskMapper
@@ -58,7 +66,7 @@ class ProjectService(AbstractService):
58
66
  thestage_api_client: TheStageApiClient,
59
67
  config_provider: ConfigProvider,
60
68
  remote_server_service: RemoteServerService,
61
- file_system_service: FileSystemServiceCore,
69
+ file_system_service: FileSystemService,
62
70
  git_local_client: GitLocalClient,
63
71
  ):
64
72
  super(ProjectService, self).__init__(
@@ -1139,3 +1147,134 @@ class ProjectService(AbstractService):
1139
1147
  deploy_key_path=project_config.deploy_key_path,
1140
1148
  reset_to_origin=True
1141
1149
  )
1150
+
1151
+
1152
+ @error_handler()
1153
+ def print_inference_simulator_list(self, config, project_uid, statuses, row, page):
1154
+ if not project_uid:
1155
+ project_config: ProjectConfig = self.__config_provider.read_project_config()
1156
+ if not project_config:
1157
+ typer.echo(__("Provide the project unique ID or run this command from within an initialized project directory"))
1158
+ raise typer.Exit(1)
1159
+ project_uid = project_config.slug
1160
+
1161
+ inference_simulator_status_map = self.__thestage_api_client.get_inference_simulator_business_status_map(
1162
+ config.main.thestage_auth_token)
1163
+
1164
+ if not statuses:
1165
+ statuses = ({key: inference_simulator_status_map[key] for key in [
1166
+ InferenceSimulatorStatus.SCHEDULED,
1167
+ InferenceSimulatorStatus.CREATING,
1168
+ InferenceSimulatorStatus.RUNNING,
1169
+ ]}).values()
1170
+
1171
+ if "all" in statuses:
1172
+ statuses = inference_simulator_status_map.values()
1173
+
1174
+ for input_status_item in statuses:
1175
+ if input_status_item not in inference_simulator_status_map.values():
1176
+ typer.echo(__("'%invalid_status%' is not one of %valid_statuses%", {
1177
+ 'invalid_status': input_status_item,
1178
+ 'valid_statuses': str(list(inference_simulator_status_map.values()))
1179
+ }))
1180
+ raise typer.Exit(1)
1181
+
1182
+ typer.echo(__(
1183
+ "Listing inference simulators with the following statuses: %statuses%, to view all inference simulators, use --status all",
1184
+ placeholders={
1185
+ 'statuses': ', '.join([status_item for status_item in statuses])
1186
+ }))
1187
+
1188
+ backend_statuses: List[str] = [key for key, value in inference_simulator_status_map.items() if value in statuses]
1189
+
1190
+ self.print(
1191
+ func_get_data=self.get_project_inference_simulator_list,
1192
+ func_special_params={
1193
+ 'project_slug': project_uid,
1194
+ 'statuses': backend_statuses,
1195
+ },
1196
+ mapper=ProjectInferenceSimulatorMapper(),
1197
+ config=config,
1198
+ headers=list(map(lambda x: x.alias, ProjectInferenceSimulatorEntity.model_fields.values())),
1199
+ row=row,
1200
+ page=page,
1201
+ max_col_width=[100, 100, 100, 100, 100, 100, 100, 100],
1202
+ show_index="never",
1203
+ )
1204
+
1205
+
1206
+ @error_handler()
1207
+ def print_inference_simulator_model_list(self, config, project_uid, statuses, row, page):
1208
+ if not project_uid:
1209
+ project_config: ProjectConfig = self.__config_provider.read_project_config()
1210
+ if not project_config:
1211
+ typer.echo(__("Provide the project unique ID or run this command from within an initialized project directory"))
1212
+ raise typer.Exit(1)
1213
+ project_uid = project_config.slug
1214
+
1215
+ inference_simulator_model_status_map = self.__thestage_api_client.get_inference_simulator_model_business_status_map(
1216
+ config.main.thestage_auth_token)
1217
+
1218
+ if not statuses:
1219
+ statuses = ({key: inference_simulator_model_status_map[key] for key in [
1220
+ InferenceModelStatus.SCHEDULED,
1221
+ InferenceModelStatus.PROCESSING,
1222
+ InferenceModelStatus.PUSH_SUCCEED,
1223
+ ]}).values()
1224
+
1225
+ if "all" in statuses:
1226
+ statuses = inference_simulator_model_status_map.values()
1227
+
1228
+ for input_status_item in statuses:
1229
+ if input_status_item not in inference_simulator_model_status_map.values():
1230
+ typer.echo(__("'%invalid_status%' is not one of %valid_statuses%", {
1231
+ 'invalid_status': input_status_item,
1232
+ 'valid_statuses': str(list(inference_simulator_model_status_map.values()))
1233
+ }))
1234
+ raise typer.Exit(1)
1235
+
1236
+ typer.echo(__(
1237
+ "Listing inference simulator models with the following statuses: %statuses%, to view all inference simulator models, use --status all",
1238
+ placeholders={
1239
+ 'statuses': ', '.join([status_item for status_item in statuses])
1240
+ }))
1241
+
1242
+ backend_statuses: List[str] = [key for key, value in inference_simulator_model_status_map.items() if value in statuses]
1243
+
1244
+ self.print(
1245
+ func_get_data=self.get_project_inference_simulator_model_list,
1246
+ func_special_params={
1247
+ 'project_slug': project_uid,
1248
+ 'statuses': backend_statuses,
1249
+ },
1250
+ mapper=ProjectInferenceSimulatorModelMapper(),
1251
+ config=config,
1252
+ headers=list(map(lambda x: x.alias, ProjectInferenceSimulatorModelEntity.model_fields.values())),
1253
+ row=row,
1254
+ page=page,
1255
+ max_col_width=[100, 100, 100, 100, 100, 100, 100, 100],
1256
+ show_index="never",
1257
+ )
1258
+
1259
+
1260
+ def print_task_list(self, config: ConfigEntity, project_uid, row, page):
1261
+ if not project_uid:
1262
+ project_config: ProjectConfig = self.__config_provider.read_project_config()
1263
+ if not project_config:
1264
+ typer.echo(__("Provide the project unique ID or run this command from within an initialized project directory"))
1265
+ raise typer.Exit(1)
1266
+ project_uid = project_config.slug
1267
+
1268
+ self.print(
1269
+ func_get_data=self.get_project_task_list,
1270
+ func_special_params={
1271
+ 'project_slug': project_uid,
1272
+ },
1273
+ mapper=ProjectTaskMapper(),
1274
+ config=config,
1275
+ headers=list(map(lambda x: x.alias, ProjectTaskEntity.model_fields.values())),
1276
+ row=row,
1277
+ page=page,
1278
+ max_col_width=[100, 100, 100, 100, 100, 100, 100, 100],
1279
+ show_index="never",
1280
+ )
@@ -21,7 +21,7 @@ from thestage.helpers.ssh_util import parse_private_key
21
21
  from thestage.i18n.translation import __
22
22
  from thestage.services.clients.thestage_api.dtos.sftp_path_helper import SftpFileItemEntity
23
23
  from thestage.services.config_provider.config_provider import ConfigProvider
24
- from thestage.services.filesystem_service import FileSystemServiceCore
24
+ from thestage.services.filesystem_service import FileSystemService
25
25
 
26
26
  old_value: int = 0
27
27
 
@@ -30,7 +30,7 @@ class RemoteServerService:
30
30
 
31
31
  def __init__(
32
32
  self,
33
- file_system_service: FileSystemServiceCore,
33
+ file_system_service: FileSystemService,
34
34
  config_provider: ConfigProvider,
35
35
  ):
36
36
  self.__file_system_service = file_system_service
@@ -1,7 +1,7 @@
1
1
  from typing import Optional
2
2
 
3
3
  from thestage.services.connect.connect_service import ConnectService
4
- from thestage.services.filesystem_service import FileSystemServiceCore
4
+ from thestage.services.filesystem_service import FileSystemService
5
5
  from thestage.services.logging.logging_service import LoggingService
6
6
  from thestage.services.project.project_service import ProjectService
7
7
  from thestage.services.remote_server_service import RemoteServerService
@@ -18,7 +18,7 @@ class ServiceFactory:
18
18
  __config_provider: Optional[ConfigProvider] = None
19
19
  __thestage_api_client: Optional[TheStageApiClient] = None
20
20
  __git_local_client: Optional[GitLocalClient] = None
21
- __file_system_service: Optional[FileSystemServiceCore] = None
21
+ __file_system_service: Optional[FileSystemService] = None
22
22
 
23
23
  def __init__(
24
24
  self,
@@ -84,9 +84,9 @@ class ServiceFactory:
84
84
  self.__git_local_client = GitLocalClient(file_system_service=self.get_file_system_service())
85
85
  return self.__git_local_client
86
86
 
87
- def get_file_system_service(self) -> FileSystemServiceCore:
87
+ def get_file_system_service(self) -> FileSystemService:
88
88
  if not self.__file_system_service:
89
- self.__file_system_service = FileSystemServiceCore()
89
+ self.__file_system_service = FileSystemService()
90
90
  return self.__file_system_service
91
91
 
92
92
  def get_app_config_service(self, config_provider: Optional[ConfigProvider] = None,) -> AppConfigService:
@@ -53,10 +53,4 @@ class ValidationService:
53
53
  if not config.main.thestage_auth_token:
54
54
  present_token = False
55
55
 
56
- if config.start_on_daemon:
57
- if config.daemon and config.daemon.daemon_token:
58
- present_token = True
59
- else:
60
- present_token = False
61
-
62
56
  return present_token
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: thestage
3
- Version: 0.5.44
3
+ Version: 0.5.46
4
4
  Summary:
5
5
  Author: TheStage AI team
6
6
  Author-email: hello@thestage.ai
@@ -21,7 +21,7 @@ Requires-Dist: python-dotenv (>=1.0.0,<2.0.0)
21
21
  Requires-Dist: python-gettext-translations (>=1.1.0,<2.0.0)
22
22
  Requires-Dist: requests (>=2.31.0,<3.0.0)
23
23
  Requires-Dist: tabulate (>=0.9.0,<0.10.0)
24
- Requires-Dist: typer[all] (>=0.9.0,<0.10.0)
24
+ Requires-Dist: typer[all] (>=0.15.2,<0.16.0)
25
25
  Description-Content-Type: text/markdown
26
26
 
27
27
  # Introduction