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
@@ -1,7 +1,6 @@
1
1
  from typing import Optional, List, Tuple, Dict, Iterator
2
2
 
3
3
  import httpx
4
- import requests
5
4
 
6
5
  from thestage.helpers.error_handler import error_handler
7
6
  from thestage.services.clients.thestage_api.core.api_client_core import TheStageApiClientCore
@@ -34,11 +33,8 @@ from thestage.services.clients.thestage_api.dtos.inference_simulator_model_respo
34
33
  InferenceSimulatorModelStatusMapperResponse
35
34
  from thestage.services.clients.thestage_api.dtos.inference_simulator_response import \
36
35
  InferenceSimulatorStatusMapperResponse
37
- from thestage.services.clients.thestage_api.dtos.logging_controller.docker_container_log_stream_request import \
38
- DockerContainerLogStreamRequest
39
36
  from thestage.services.clients.thestage_api.dtos.logging_controller.log_polling_request import LogPollingRequest
40
37
  from thestage.services.clients.thestage_api.dtos.logging_controller.log_polling_response import LogPollingResponse
41
- from thestage.services.clients.thestage_api.dtos.logging_controller.task_log_stream_request import TaskLogStreamRequest
42
38
  from thestage.services.clients.thestage_api.dtos.logging_controller.user_logs_query_request import UserLogsQueryRequest
43
39
  from thestage.services.clients.thestage_api.dtos.logging_controller.user_logs_query_response import \
44
40
  UserLogsQueryResponse
@@ -89,19 +85,25 @@ from thestage.services.clients.thestage_api.dtos.instance_rented_response import
89
85
  InstanceRentedDto, InstanceRentedItemResponse, InstanceRentedBusinessStatusMapperResponse
90
86
 
91
87
  from thestage.services.clients.thestage_api.dtos.base_response import TheStageBaseResponse
92
- from thestage.services.clients.thestage_api.dtos.user_controller.user_profile import UserProfileResponse
88
+ from thestage.services.config_provider.config_provider import ConfigProvider
93
89
  from thestage.services.project.dto.inference_simulator_dto import InferenceSimulatorDto
94
90
  from thestage.services.project.dto.inference_simulator_model_dto import InferenceSimulatorModelDto
95
91
  from thestage.services.task.dto.task_dto import TaskDto
96
92
 
97
93
 
98
94
  class TheStageApiClient(TheStageApiClientCore):
99
- def __init__(self, api_url: str, timeout: int = 90):
100
- super().__init__(timeout=timeout, url=api_url)
95
+ __config_provider: ConfigProvider = None
96
+
97
+ def __init__(
98
+ self,
99
+ config_provider: ConfigProvider,
100
+ ):
101
+ # TODO this is super bullshit, remove all abstract classes
102
+ super().__init__(url=config_provider.get_config().main.thestage_api_url)
103
+ self.__config_provider = config_provider
101
104
 
102
105
  def get_task(
103
106
  self,
104
- token: str,
105
107
  task_id: int,
106
108
  ) -> Optional[TaskViewResponse]:
107
109
  data = {
@@ -112,7 +114,7 @@ class TheStageApiClient(TheStageApiClientCore):
112
114
  method='POST',
113
115
  url='/user-api/v1/task/view',
114
116
  data=data,
115
- token=token,
117
+ token=self.__config_provider.get_config().main.thestage_auth_token,
116
118
  )
117
119
 
118
120
  result = TaskViewResponse.model_validate(response) if response else None
@@ -120,7 +122,6 @@ class TheStageApiClient(TheStageApiClientCore):
120
122
 
121
123
  def get_task_list_for_project(
122
124
  self,
123
- token: str,
124
125
  project_slug: str,
125
126
  page: int = 1,
126
127
  limit: int = 10,
@@ -139,7 +140,7 @@ class TheStageApiClient(TheStageApiClientCore):
139
140
  method='POST',
140
141
  url='/user-api/v1/task/list-for-project',
141
142
  data=request.model_dump(),
142
- token=token,
143
+ token=self.__config_provider.get_config().main.thestage_auth_token,
143
144
  )
144
145
 
145
146
  result = TaskListForProjectResponse.model_validate(response) if response else None
@@ -147,7 +148,6 @@ class TheStageApiClient(TheStageApiClientCore):
147
148
 
148
149
  def get_inference_simulator_list_for_project(
149
150
  self,
150
- token: str,
151
151
  project_slug: str,
152
152
  statuses: List[str] = [],
153
153
  page: int = 1,
@@ -168,14 +168,13 @@ class TheStageApiClient(TheStageApiClientCore):
168
168
  method='POST',
169
169
  url='/user-api/v1/project/inference-simulator/list',
170
170
  data=request.model_dump(),
171
- token=token,
171
+ token=self.__config_provider.get_config().main.thestage_auth_token,
172
172
  )
173
173
  result = InferenceSimulatorListForProjectResponse.model_validate(response) if response else None
174
174
  return result.inferenceSimulators if result and result.is_success else None
175
175
 
176
176
  def get_inference_simulator_model_list_for_project(
177
177
  self,
178
- token: str,
179
178
  project_slug: str,
180
179
  statuses: Optional[List[str]] = None,
181
180
  page: int = 1,
@@ -196,14 +195,13 @@ class TheStageApiClient(TheStageApiClientCore):
196
195
  method='POST',
197
196
  url='/user-api/v1/project/inference-simulator-model/list',
198
197
  data=request.model_dump(),
199
- token=token,
198
+ token=self.__config_provider.get_config().main.thestage_auth_token,
200
199
  )
201
200
  result = InferenceSimulatorModelListForProjectResponse.model_validate(response) if response else None
202
201
  return result.inferenceSimulatorModels if result and result.is_success else None
203
202
 
204
203
  def get_rented_instance_list(
205
204
  self,
206
- token: str,
207
205
  statuses: List[str],
208
206
  query: Optional[str] = None,
209
207
  page: int = 1,
@@ -227,30 +225,30 @@ class TheStageApiClient(TheStageApiClientCore):
227
225
  method='POST',
228
226
  url='/user-api/v2/instance-rented/list',
229
227
  data=data,
230
- token=token,
228
+ token=self.__config_provider.get_config().main.thestage_auth_token,
231
229
  )
232
230
 
233
231
  result = InstanceRentedListResponse.model_validate(response) if response else None
234
232
  return result.paginated_list if result and result.paginated_list else ([], None)
235
233
 
236
- def get_rented_business_status_map(self, token: str, ) -> Optional[Dict[str, str]]:
234
+ def get_rented_business_status_map(self) -> Optional[Dict[str, str]]:
237
235
  response = self._request(
238
236
  method='POST',
239
237
  url='/user-api/v2/instance-rented/business-status-localized-map',
240
238
  data=None,
241
- token=token,
239
+ token=self.__config_provider.get_config().main.thestage_auth_token,
242
240
  )
243
241
 
244
242
  data = InstanceRentedBusinessStatusMapperResponse.model_validate(response) if response else None
245
243
 
246
244
  return data.instance_rented_business_status_map if data else None
247
245
 
248
- def get_task_localized_status_map(self, token: str, ) -> Optional[Dict[str, str]]:
246
+ def get_task_localized_status_map(self) -> Optional[Dict[str, str]]:
249
247
  response = self._request(
250
248
  method='POST',
251
249
  url='/user-api/v1/task/status-localized-mapping',
252
250
  data=None,
253
- token=token,
251
+ token=self.__config_provider.get_config().main.thestage_auth_token,
254
252
  )
255
253
 
256
254
  data = TaskStatusLocalizedMapResponse.model_validate(response) if response else None
@@ -259,7 +257,6 @@ class TheStageApiClient(TheStageApiClientCore):
259
257
 
260
258
  def get_rented_instance(
261
259
  self,
262
- token: str,
263
260
  instance_slug: Optional[str] = None,
264
261
  instance_id: Optional[int] = None,
265
262
  ) -> Optional[InstanceRentedDto]:
@@ -274,14 +271,13 @@ class TheStageApiClient(TheStageApiClientCore):
274
271
  method='POST',
275
272
  url='/user-api/v2/instance-rented/view-by-slug',
276
273
  data=data,
277
- token=token,
274
+ token=self.__config_provider.get_config().main.thestage_auth_token,
278
275
  )
279
276
 
280
277
  return InstanceRentedItemResponse.model_validate(response).instance_rented if response else None
281
278
 
282
279
  def get_selfhosted_instance(
283
280
  self,
284
- token: str,
285
281
  instance_slug: Optional[str] = None,
286
282
  instance_id: Optional[int] = None,
287
283
  ) -> Optional[SelfHostedInstanceDto]:
@@ -296,14 +292,13 @@ class TheStageApiClient(TheStageApiClientCore):
296
292
  method='POST',
297
293
  url='/user-api/v2/self-hosted-instance/view-by-slug',
298
294
  data=data,
299
- token=token,
295
+ token=self.__config_provider.get_config().main.thestage_auth_token,
300
296
  )
301
297
 
302
298
  return SelfHostedRentedItemResponse.model_validate(response).selfhosted_instance if response else None
303
299
 
304
300
  def get_selfhosted_instance_list(
305
301
  self,
306
- token: str,
307
302
  statuses: List[str],
308
303
  query: Optional[str] = None,
309
304
  page: int = 1,
@@ -327,18 +322,18 @@ class TheStageApiClient(TheStageApiClientCore):
327
322
  method='POST',
328
323
  url='/user-api/v2/self-hosted-instance/list',
329
324
  data=data,
330
- token=token,
325
+ token=self.__config_provider.get_config().main.thestage_auth_token,
331
326
  )
332
327
 
333
328
  result = SelfHostedInstanceListResponse.model_validate(response) if response else None
334
329
  return result.paginated_list if result and result.paginated_list else ([], None)
335
330
 
336
- def get_selfhosted_business_status_map(self, token: str, ) -> Optional[Dict[str, str]]:
331
+ def get_selfhosted_business_status_map(self) -> Optional[Dict[str, str]]:
337
332
  response = self._request(
338
333
  method='POST',
339
334
  url='/user-api/v2/self-hosted-instance/business-status-localized-map',
340
335
  data=None,
341
- token=token,
336
+ token=self.__config_provider.get_config().main.thestage_auth_token,
342
337
  )
343
338
 
344
339
  data = SelfHostedRentedRentedBusinessStatusMapperResponse.model_validate(response) if response else None
@@ -347,7 +342,6 @@ class TheStageApiClient(TheStageApiClientCore):
347
342
 
348
343
  def cancel_task(
349
344
  self,
350
- token: str,
351
345
  task_id: int,
352
346
  ) -> Optional[TheStageBaseResponse]:
353
347
  data = {
@@ -358,7 +352,7 @@ class TheStageApiClient(TheStageApiClientCore):
358
352
  method='POST',
359
353
  url='/user-api/v1/task/cancel-task',
360
354
  data=data,
361
- token=token,
355
+ token=self.__config_provider.get_config().main.thestage_auth_token,
362
356
  )
363
357
 
364
358
  result = TheStageBaseResponse.model_validate(response) if response else None
@@ -366,7 +360,6 @@ class TheStageApiClient(TheStageApiClientCore):
366
360
 
367
361
  def get_container_list(
368
362
  self,
369
- token: str,
370
363
  project_id: Optional[int] = None,
371
364
  statuses: List[str] = [],
372
365
  page: int = 1,
@@ -387,7 +380,7 @@ class TheStageApiClient(TheStageApiClientCore):
387
380
  method='POST',
388
381
  url='/user-api/v1/docker-container/list',
389
382
  data=request.model_dump(),
390
- token=token,
383
+ token=self.__config_provider.get_config().main.thestage_auth_token
391
384
  )
392
385
 
393
386
  result = DockerContainerListResponse.model_validate(response) if response else None
@@ -396,7 +389,6 @@ class TheStageApiClient(TheStageApiClientCore):
396
389
 
397
390
  def get_container(
398
391
  self,
399
- token: str,
400
392
  container_slug: Optional[str] = None,
401
393
  container_id: Optional[int] = None,
402
394
  ) -> Optional[DockerContainerDto]:
@@ -416,14 +408,13 @@ class TheStageApiClient(TheStageApiClientCore):
416
408
  method='POST',
417
409
  url='/user-api/v1/docker-container/view',
418
410
  data=data,
419
- token=token,
411
+ token=self.__config_provider.get_config().main.thestage_auth_token,
420
412
  )
421
413
 
422
414
  return DockerContainerViewResponse.model_validate(response).docker_container if response else None
423
415
 
424
416
  def container_action(
425
417
  self,
426
- token: str,
427
418
  request_param: DockerContainerActionRequestDto,
428
419
  ) -> TheStageBaseResponse:
429
420
 
@@ -431,24 +422,24 @@ class TheStageApiClient(TheStageApiClientCore):
431
422
  method='POST',
432
423
  url='/user-api/v1/docker-container/action',
433
424
  data=request_param.model_dump(by_alias=True),
434
- token=token,
425
+ token=self.__config_provider.get_config().main.thestage_auth_token,
435
426
  )
436
427
 
437
428
  result = TheStageBaseResponse.model_validate(response) if response else None
438
429
  return result
439
430
 
440
- def get_container_business_status_map(self, token: str, ) -> Optional[Dict[str, str]]:
431
+ def get_container_business_status_map(self) -> Optional[Dict[str, str]]:
441
432
  response = self._request(
442
433
  method='POST',
443
434
  url='/user-api/v1/docker-container/status-localized-mapping',
444
435
  data=None,
445
- token=token,
436
+ token=self.__config_provider.get_config().main.thestage_auth_token,
446
437
  )
447
438
 
448
439
  data = ContainerBusinessStatusMapperResponse.model_validate(response) if response else None
449
440
  return data.docker_container_status_map if data else None
450
441
 
451
- def get_project_by_slug(self, slug: str, token: str) -> Optional[ProjectDto]:
442
+ def get_project_by_slug(self, slug: str) -> Optional[ProjectDto]:
452
443
  data = {
453
444
  "projectSlug": slug,
454
445
  }
@@ -457,14 +448,14 @@ class TheStageApiClient(TheStageApiClientCore):
457
448
  method='POST',
458
449
  url='/user-api/v1/project/view-by-slug',
459
450
  data=data,
460
- token=token,
451
+ token=self.__config_provider.get_config().main.thestage_auth_token,
461
452
  )
462
453
 
463
454
  result = ProjectViewResponse.model_validate(response) if response else None
464
455
  project = ProjectDto.model_validate(result.project) if result else None
465
456
  return project if result and result.is_success else None
466
457
 
467
- def get_project_deploy_ssh_key(self, slug: str, token: str) -> str:
458
+ def get_project_deploy_ssh_key(self, slug: str) -> str:
468
459
  request = ProjectGetDeploySshKeyRequest(
469
460
  projectSlug=slug
470
461
  )
@@ -473,7 +464,7 @@ class TheStageApiClient(TheStageApiClientCore):
473
464
  method='POST',
474
465
  url='/user-api/v1/project/get-deploy-ssh-key',
475
466
  data=request.model_dump(),
476
- token=token,
467
+ token=self.__config_provider.get_config().main.thestage_auth_token,
477
468
  )
478
469
 
479
470
  result = ProjectGetDeploySshKeyResponse.model_validate(response) if response else None
@@ -481,7 +472,6 @@ class TheStageApiClient(TheStageApiClientCore):
481
472
 
482
473
  def execute_project_task(
483
474
  self,
484
- token: str,
485
475
  project_slug: str,
486
476
  run_command: str,
487
477
  task_title: str,
@@ -500,15 +490,16 @@ class TheStageApiClient(TheStageApiClientCore):
500
490
  method='POST',
501
491
  url='/user-api/v1/project/execute-task',
502
492
  data=request.model_dump(),
503
- token=token,
493
+ token=self.__config_provider.get_config().main.thestage_auth_token,
504
494
  )
505
495
 
506
496
  return ProjectRunTaskResponse.model_validate(response) if response else None
507
497
 
508
- async def poll_logs_httpx(self, token: str, docker_container_id: Optional[int], last_log_timestamp: str,
498
+ async def poll_logs_httpx(self, docker_container_id: Optional[int], last_log_timestamp: str,
509
499
  last_log_id: str, task_id: Optional[int] = None,
510
500
  inference_simulator_id: Optional[int] = None) -> Optional[LogPollingResponse]:
511
501
  request_headers = {'Content-Type': 'application/json'}
502
+ token = self.__config_provider.get_config().main.thestage_auth_token
512
503
  if token: request_headers['Authorization'] = f"Bearer {token}"
513
504
 
514
505
  request = LogPollingRequest(
@@ -529,7 +520,7 @@ class TheStageApiClient(TheStageApiClientCore):
529
520
 
530
521
  return LogPollingResponse.model_validate(response.json()) if response else None
531
522
 
532
- def add_public_ssh_key_to_user(self, token: str, public_key: str, note: str) -> AddSshKeyToUserResponse:
523
+ def add_public_ssh_key_to_user(self, public_key: str, note: str) -> AddSshKeyToUserResponse:
533
524
  request = AddSshKeyToUserRequest(
534
525
  sshKey=public_key,
535
526
  note=note
@@ -539,13 +530,13 @@ class TheStageApiClient(TheStageApiClientCore):
539
530
  method='POST',
540
531
  url='/user-api/v1/ssh-key/add-public-key-to-user',
541
532
  data=request.model_dump(),
542
- token=token,
533
+ token=self.__config_provider.get_config().main.thestage_auth_token,
543
534
  )
544
535
 
545
536
  result = AddSshKeyToUserResponse.model_validate(response) if response else None
546
537
  return result
547
538
 
548
- def is_user_has_ssh_public_key(self, token: str, public_key: str) -> IsUserHasSshPublicKeyResponse:
539
+ def is_user_has_ssh_public_key(self, public_key: str) -> IsUserHasSshPublicKeyResponse:
549
540
  request = IsUserHasSshPublicKeyRequest(
550
541
  sshKey=public_key,
551
542
  )
@@ -554,13 +545,13 @@ class TheStageApiClient(TheStageApiClientCore):
554
545
  method='POST',
555
546
  url='/user-api/v1/ssh-key/is-user-has-public-ssh-key',
556
547
  data=request.model_dump(),
557
- token=token,
548
+ token=self.__config_provider.get_config().main.thestage_auth_token,
558
549
  )
559
550
 
560
551
  result = IsUserHasSshPublicKeyResponse.model_validate(response) if response else None
561
552
  return result
562
553
 
563
- def add_public_ssh_key_to_instance_rented(self, token: str, instance_rented_id: int,
554
+ def add_public_ssh_key_to_instance_rented(self, instance_rented_id: int,
564
555
  ssh_key_pair_id: int) -> AddSshPublicKeyToInstanceResponse:
565
556
  request = AddSshPublicKeyToInstanceRequest(
566
557
  instanceRentedId=instance_rented_id,
@@ -571,7 +562,7 @@ class TheStageApiClient(TheStageApiClientCore):
571
562
  method='POST',
572
563
  url='/user-api/v1/ssh-key/add-public-ssh-key-to-instance-rented',
573
564
  data=request.model_dump(),
574
- token=token,
565
+ token=self.__config_provider.get_config().main.thestage_auth_token,
575
566
  )
576
567
 
577
568
  result = AddSshPublicKeyToInstanceResponse.model_validate(response) if response else None
@@ -579,7 +570,6 @@ class TheStageApiClient(TheStageApiClientCore):
579
570
 
580
571
  def start_project_inference_simulator(
581
572
  self,
582
- token: str,
583
573
  project_slug: str,
584
574
  slug: str,
585
575
  commit_hash: Optional[str] = None,
@@ -602,14 +592,13 @@ class TheStageApiClient(TheStageApiClientCore):
602
592
  method='POST',
603
593
  url='/user-api/v1/project/inference-simulator/create',
604
594
  data=request.model_dump(),
605
- token=token,
595
+ token=self.__config_provider.get_config().main.thestage_auth_token,
606
596
  )
607
597
 
608
598
  return ProjectStartInferenceSimulatorResponse.model_validate(response) if response else None
609
599
 
610
600
  def push_project_inference_simulator_model(
611
601
  self,
612
- token: str,
613
602
  slug: str,
614
603
  ) -> Optional[ProjectPushInferenceSimulatorModelResponse]:
615
604
  request = ProjectPushInferenceSimulatorModelRequest(
@@ -620,29 +609,29 @@ class TheStageApiClient(TheStageApiClientCore):
620
609
  method='POST',
621
610
  url='/user-api/v1/project/inference-simulator/push-model',
622
611
  data=request.model_dump(),
623
- token=token,
612
+ token=self.__config_provider.get_config().main.thestage_auth_token,
624
613
  )
625
614
 
626
615
  return ProjectPushInferenceSimulatorModelResponse.model_validate(response) if response else None
627
616
 
628
- def get_inference_simulator_business_status_map(self, token: str, ) -> Optional[Dict[str, str]]:
617
+ def get_inference_simulator_business_status_map(self) -> Optional[Dict[str, str]]:
629
618
  response = self._request(
630
619
  method='POST',
631
620
  url='/user-api/v1/inference-simulator/status-localized-mapping',
632
621
  data=None,
633
- token=token,
622
+ token=self.__config_provider.get_config().main.thestage_auth_token,
634
623
  )
635
624
 
636
625
  data = InferenceSimulatorStatusMapperResponse.model_validate(response) if response else None
637
626
 
638
627
  return data.inference_simulator_status_map if data else None
639
628
 
640
- def get_inference_simulator_model_business_status_map(self, token: str, ) -> Optional[Dict[str, str]]:
629
+ def get_inference_simulator_model_business_status_map(self) -> Optional[Dict[str, str]]:
641
630
  response = self._request(
642
631
  method='POST',
643
632
  url='/user-api/v1/inference-simulator-model/status-localized-mapping',
644
633
  data=None,
645
- token=token,
634
+ token=self.__config_provider.get_config().main.thestage_auth_token,
646
635
  )
647
636
 
648
637
  data = InferenceSimulatorModelStatusMapperResponse.model_validate(response) if response else None
@@ -652,7 +641,6 @@ class TheStageApiClient(TheStageApiClientCore):
652
641
  @error_handler()
653
642
  def get_inference_simulator(
654
643
  self,
655
- token: str,
656
644
  slug: str,
657
645
  ) -> Optional[GetInferenceSimulatorResponse]:
658
646
  request = GetInferenceSimulatorRequest(
@@ -663,14 +651,13 @@ class TheStageApiClient(TheStageApiClientCore):
663
651
  method='POST',
664
652
  url='/user-api/v1/inference-simulator/get',
665
653
  data=request.model_dump(),
666
- token=token,
654
+ token=self.__config_provider.get_config().main.thestage_auth_token,
667
655
  )
668
656
  return GetInferenceSimulatorResponse.model_validate(response) if response else None
669
657
 
670
658
  @error_handler()
671
659
  def deploy_inference_model_to_instance(
672
660
  self,
673
- token: str,
674
661
  unique_id: str,
675
662
  unique_id_with_timestamp: str,
676
663
  rented_instance_unique_id: Optional[str] = None,
@@ -688,14 +675,13 @@ class TheStageApiClient(TheStageApiClientCore):
688
675
  method='POST',
689
676
  url='/user-api/v1/inference-simulator-model/deploy/instance',
690
677
  data=request.model_dump(),
691
- token=token,
678
+ token=self.__config_provider.get_config().main.thestage_auth_token,
692
679
  )
693
680
  return DeployInferenceModelToInstanceResponse.model_validate(response) if response else None
694
681
 
695
682
  @error_handler()
696
683
  def deploy_inference_model_to_sagemaker(
697
684
  self,
698
- token: str,
699
685
  unique_id: str,
700
686
  arn: Optional[str] = None,
701
687
  ) -> Optional[DeployInferenceModelToSagemakerResponse]:
@@ -708,11 +694,11 @@ class TheStageApiClient(TheStageApiClientCore):
708
694
  method='POST',
709
695
  url='/user-api/v1/inference-simulator-model/grant-user-arn-access',
710
696
  data=request.model_dump(),
711
- token=token,
697
+ token=self.__config_provider.get_config().main.thestage_auth_token,
712
698
  )
713
699
  return DeployInferenceModelToSagemakerResponse.model_validate(response) if response else None
714
700
 
715
- def query_user_logs(self, token: str, limit: int, task_id: Optional[int] = None,
701
+ def query_user_logs(self, limit: int, task_id: Optional[int] = None,
716
702
  inference_simulator_id: Optional[int] = None,
717
703
  container_id: Optional[int] = None) -> UserLogsQueryResponse:
718
704
  request = UserLogsQueryRequest(
@@ -727,7 +713,7 @@ class TheStageApiClient(TheStageApiClientCore):
727
713
  method='POST',
728
714
  url='/user-api/v1/logging/query-user-logs',
729
715
  data=request.model_dump(),
730
- token=token,
716
+ token=self.__config_provider.get_config().main.thestage_auth_token,
731
717
  )
732
718
 
733
719
  result = UserLogsQueryResponse.model_validate(response) if response else None
@@ -1,16 +1,21 @@
1
- from typing import Optional, List, Tuple
1
+ import json
2
+ from typing import Optional
2
3
 
3
- from thestage.services.clients.thestage_api.core.api_client_abstract import TheStageApiClientAbstract
4
- from thestage.services.clients.thestage_api.dtos.base_response import TheStageBaseResponse
4
+ import requests
5
+
6
+ from thestage.config import THESTAGE_API_URL
7
+ from thestage.exceptions.auth_exception import AuthException
5
8
  from thestage import __version__
9
+ from thestage.services.clients.thestage_api.core.http_client_exception import HttpClientException
10
+ from thestage.services.clients.thestage_api.dtos.validate_token_response import ValidateTokenResponse
6
11
 
7
12
 
8
- class TheStageApiClientCore(TheStageApiClientAbstract):
13
+ class TheStageApiClientCore:
14
+ def __init__(self, url: Optional[str] = None):
15
+ self.__api_url = url
9
16
 
10
- def __init__(self, timeout: int = 90, url: Optional[str] = None):
11
- super(TheStageApiClientCore, self).__init__(timeout=timeout, url=url)
12
17
 
13
- def validate_token(self, token: str) -> bool:
18
+ def validate_token(self, token: str) -> ValidateTokenResponse:
14
19
  data = {
15
20
  "userApiToken": token,
16
21
  "cliVersion": __version__,
@@ -21,5 +26,83 @@ class TheStageApiClientCore(TheStageApiClientAbstract):
21
26
  url='/user-api/v1/validate-token',
22
27
  data=data,
23
28
  )
24
- result = TheStageBaseResponse.model_validate(response) if response else None
25
- return result.is_success if result else False
29
+ result = ValidateTokenResponse.model_validate(response) if response else None
30
+ return result
31
+
32
+
33
+ def _get_host(self, ) -> str:
34
+ return self.__api_url or THESTAGE_API_URL
35
+
36
+ def _request(
37
+ self,
38
+ method: str,
39
+ url: str,
40
+ data: dict = None,
41
+ query_params: dict = None,
42
+ headers: Optional[dict] = None,
43
+ token: Optional[str] = None,
44
+ ):
45
+ if not data:
46
+ data = {}
47
+
48
+ host = self._get_host()
49
+ url = f'{host}{url}'
50
+
51
+ request_headers = {
52
+ 'Content-Type': 'application/json',
53
+ }
54
+
55
+ if token:
56
+ request_headers['Authorization'] = f"Bearer {token}"
57
+
58
+ if headers:
59
+ request_headers.update(headers)
60
+ response = requests.request(
61
+ method=method,
62
+ url=url,
63
+ json=data,
64
+ params=query_params,
65
+ headers=request_headers,
66
+ timeout=90,
67
+
68
+ )
69
+ return self._parse_api_response(response)
70
+
71
+
72
+ @staticmethod
73
+ def _parse_api_response(raw_response):
74
+ content_type = raw_response.headers.get('content-type')
75
+ message_error = None
76
+ if content_type == 'application/json':
77
+ try:
78
+ result = raw_response.json()
79
+ message_error = result.get('message', None)
80
+ except json.JSONDecodeError:
81
+ raise HttpClientException(
82
+ message=f"Failed to parse server response",
83
+ status_code=raw_response.status_code,
84
+ )
85
+ else:
86
+ result = raw_response.content.text()
87
+
88
+ if raw_response.status_code == 401:
89
+ raise AuthException(
90
+ message=f"Unauthorized",
91
+ )
92
+ elif raw_response.status_code == 403:
93
+ raise HttpClientException(
94
+ message=f"{message_error if message_error else 'Forbidden'} ({raw_response.status_code})",
95
+ status_code=raw_response.status_code,
96
+ )
97
+ elif raw_response.status_code >= 400:
98
+ raise HttpClientException(
99
+ message=f"{message_error if message_error else 'Request error'} ({raw_response.status_code})",
100
+ status_code=raw_response.status_code,
101
+ )
102
+ elif raw_response.status_code < 200 or raw_response.status_code > 300:
103
+ raise HttpClientException(
104
+ message=f"{message_error if message_error else 'Request error'} ({raw_response.status_code})",
105
+ status_code=raw_response.status_code,
106
+ )
107
+
108
+ return result
@@ -64,4 +64,4 @@ class DockerContainerViewResponse(TheStageBaseResponse):
64
64
  class ContainerBusinessStatusMapperResponse(TheStageBasePaginatedResponse):
65
65
  model_config = ConfigDict(use_enum_values=True)
66
66
 
67
- docker_container_status_map: Dict[str, str] = Field(default=dict, alias='dockerContainerStatusMap')
67
+ docker_container_status_map: Dict[str, str] = Field(default={}, alias='dockerContainerStatusMap')
@@ -8,4 +8,4 @@ from thestage.services.clients.thestage_api.dtos.base_response import TheStageBa
8
8
  class InferenceSimulatorModelStatusMapperResponse(TheStageBasePaginatedResponse):
9
9
  model_config = ConfigDict(use_enum_values=True)
10
10
 
11
- inference_simulator_model_status_map: Dict[str, str] = Field(default=dict, alias='inferenceSimulatorModelStatusMap')
11
+ inference_simulator_model_status_map: Dict[str, str] = Field(default={}, alias='inferenceSimulatorModelStatusMap')
@@ -8,4 +8,4 @@ from thestage.services.clients.thestage_api.dtos.base_response import TheStageBa
8
8
  class InferenceSimulatorStatusMapperResponse(TheStageBasePaginatedResponse):
9
9
  model_config = ConfigDict(use_enum_values=True)
10
10
 
11
- inference_simulator_status_map: Dict[str, str] = Field(default=dict, alias='inferenceSimulatorStatusMap')
11
+ inference_simulator_status_map: Dict[str, str] = Field(default={}, alias='inferenceSimulatorStatusMap')
@@ -68,4 +68,4 @@ class InstanceRentedItemResponse(TheStageBasePaginatedResponse):
68
68
  class InstanceRentedBusinessStatusMapperResponse(TheStageBasePaginatedResponse):
69
69
  model_config = ConfigDict(use_enum_values=True)
70
70
 
71
- instance_rented_business_status_map: Dict[str, str] = Field(default=dict, alias='instanceRentedBusinessStatusMap')
71
+ instance_rented_business_status_map: Dict[str, str] = Field(default={}, alias='instanceRentedBusinessStatusMap')
@@ -53,4 +53,4 @@ class SelfHostedRentedItemResponse(TheStageBasePaginatedResponse):
53
53
  class SelfHostedRentedRentedBusinessStatusMapperResponse(TheStageBasePaginatedResponse):
54
54
  model_config = ConfigDict(use_enum_values=True)
55
55
 
56
- selfhosted_instance_business_status_map: Dict[str, str] = Field(default=dict, alias='selfhostedInstanceBusinessStatusMap')
56
+ selfhosted_instance_business_status_map: Dict[str, str] = Field(default={}, alias='selfhostedInstanceBusinessStatusMap')
@@ -6,4 +6,4 @@ from thestage.services.clients.thestage_api.dtos.base_response import TheStageBa
6
6
 
7
7
 
8
8
  class TaskStatusLocalizedMapResponse(TheStageBaseResponse):
9
- taskStatusMap: Dict[str, str] = Field(default=dict, alias='taskStatusMap')
9
+ taskStatusMap: Dict[str, str] = Field(default={}, alias='taskStatusMap')