thestage 0.6.2__py3-none-any.whl → 0.6.3__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.
- thestage/.env +4 -5
- thestage/__init__.py +3 -3
- thestage/__main__.py +9 -9
- thestage/cli_command.py +56 -56
- thestage/cli_command_helper.py +51 -51
- thestage/color_scheme/color_scheme.py +7 -7
- thestage/config/__init__.py +18 -18
- thestage/config/config_storage.py +5 -5
- thestage/config/env_base.py +7 -7
- thestage/controllers/__init__.py +0 -0
- thestage/controllers/base_controller.py +67 -67
- thestage/controllers/config_controller.py +137 -137
- thestage/controllers/container_controller.py +389 -389
- thestage/controllers/instance_controller.py +183 -183
- thestage/controllers/project_controller.py +810 -810
- thestage/controllers/utils_controller.py +32 -32
- thestage/debug_main.dist.py +28 -28
- thestage/entities/__init__.py +0 -0
- thestage/entities/container.py +17 -17
- thestage/entities/enums/__init__.py +0 -0
- thestage/entities/enums/order_direction_type.py +6 -6
- thestage/entities/enums/shell_type.py +7 -7
- thestage/entities/enums/tail_output_type.py +6 -6
- thestage/entities/enums/yes_no_response.py +7 -7
- thestage/entities/file_item.py +27 -27
- thestage/entities/project_inference_simulator.py +18 -18
- thestage/entities/project_inference_simulator_model.py +16 -16
- thestage/entities/project_task.py +19 -19
- thestage/entities/rented_instance.py +19 -19
- thestage/entities/self_hosted_instance.py +18 -18
- thestage/exceptions/__init__.py +0 -0
- thestage/exceptions/auth_exception.py +6 -6
- thestage/exceptions/base_exception.py +13 -13
- thestage/exceptions/business_logic_exception.py +6 -6
- thestage/exceptions/config_exception.py +6 -6
- thestage/exceptions/file_system_exception.py +6 -6
- thestage/exceptions/git_access_exception.py +17 -17
- thestage/exceptions/remote_server_exception.py +24 -24
- thestage/git/ProgressPrinter.py +22 -22
- thestage/helpers/__init__.py +0 -0
- thestage/helpers/error_handler.py +115 -115
- thestage/helpers/exception_hook.py +14 -14
- thestage/helpers/logger/__init__.py +0 -0
- thestage/helpers/logger/app_logger.py +50 -50
- thestage/helpers/ssh_util.py +38 -38
- thestage/i18n/en_GB/messages.po +947 -947
- thestage/i18n/translation.py +9 -9
- thestage/main.py +36 -36
- thestage/services/.env +6 -6
- thestage/services/__init__.py +0 -0
- thestage/services/abstract_mapper.py +9 -9
- thestage/services/abstract_service.py +87 -87
- thestage/services/app_config_service.py +52 -52
- thestage/services/clients/__init__.py +0 -0
- thestage/services/clients/git/__init__.py +0 -0
- thestage/services/clients/git/git_client.py +436 -436
- thestage/services/clients/thestage_api/__init__.py +0 -0
- thestage/services/clients/thestage_api/api_client.py +718 -718
- thestage/services/clients/thestage_api/core/api_client_core.py +108 -108
- thestage/services/clients/thestage_api/core/http_client_exception.py +12 -12
- thestage/services/clients/thestage_api/dtos/__init__.py +0 -0
- thestage/services/clients/thestage_api/dtos/base_response.py +13 -13
- thestage/services/clients/thestage_api/dtos/cloud_provider_region.py +19 -19
- thestage/services/clients/thestage_api/dtos/container_param_request.py +11 -11
- thestage/services/clients/thestage_api/dtos/container_response.py +67 -67
- thestage/services/clients/thestage_api/dtos/docker_container_assigned_device.py +10 -10
- thestage/services/clients/thestage_api/dtos/docker_container_controller/docker_container_list_request.py +13 -13
- thestage/services/clients/thestage_api/dtos/docker_container_controller/docker_container_list_response.py +13 -13
- thestage/services/clients/thestage_api/dtos/docker_container_mapping.py +10 -10
- thestage/services/clients/thestage_api/dtos/entity_filter_request.py +14 -14
- thestage/services/clients/thestage_api/dtos/enums/__init__.py +0 -0
- thestage/services/clients/thestage_api/dtos/enums/container_pending_action.py +10 -10
- thestage/services/clients/thestage_api/dtos/enums/container_status.py +17 -17
- thestage/services/clients/thestage_api/dtos/enums/cpu_type.py +8 -8
- thestage/services/clients/thestage_api/dtos/enums/currency_type.py +10 -10
- thestage/services/clients/thestage_api/dtos/enums/daemon_status.py +9 -9
- thestage/services/clients/thestage_api/dtos/enums/disk_type.py +7 -7
- thestage/services/clients/thestage_api/dtos/enums/drive_type.py +7 -7
- thestage/services/clients/thestage_api/dtos/enums/gpu_name.py +8 -8
- thestage/services/clients/thestage_api/dtos/enums/inference_model_status.py +9 -9
- thestage/services/clients/thestage_api/dtos/enums/inference_simulator_status.py +15 -15
- thestage/services/clients/thestage_api/dtos/enums/instance_rented_status.py +17 -17
- thestage/services/clients/thestage_api/dtos/enums/instance_type.py +7 -7
- thestage/services/clients/thestage_api/dtos/enums/location_region.py +11 -11
- thestage/services/clients/thestage_api/dtos/enums/power_status.py +10 -10
- thestage/services/clients/thestage_api/dtos/enums/provider_name.py +11 -11
- thestage/services/clients/thestage_api/dtos/enums/selfhosted_status.py +10 -10
- thestage/services/clients/thestage_api/dtos/enums/task_execution_status.py +12 -12
- thestage/services/clients/thestage_api/dtos/enums/task_status.py +12 -12
- thestage/services/clients/thestage_api/dtos/frontend_status.py +10 -10
- thestage/services/clients/thestage_api/dtos/inference_controller/deploy_inference_model_to_instance_request.py +13 -13
- thestage/services/clients/thestage_api/dtos/inference_controller/deploy_inference_model_to_instance_response.py +13 -13
- thestage/services/clients/thestage_api/dtos/inference_controller/deploy_inference_model_to_sagemaker_request.py +12 -12
- thestage/services/clients/thestage_api/dtos/inference_controller/deploy_inference_model_to_sagemaker_response.py +12 -12
- thestage/services/clients/thestage_api/dtos/inference_controller/get_inference_simulator_request.py +10 -10
- thestage/services/clients/thestage_api/dtos/inference_controller/get_inference_simulator_response.py +13 -13
- thestage/services/clients/thestage_api/dtos/inference_controller/inference_simulator_list_for_project_request.py +14 -14
- thestage/services/clients/thestage_api/dtos/inference_controller/inference_simulator_list_for_project_response.py +12 -12
- thestage/services/clients/thestage_api/dtos/inference_controller/inference_simulator_model_list_for_project_request.py +12 -12
- thestage/services/clients/thestage_api/dtos/inference_controller/inference_simulator_model_list_for_project_response.py +13 -13
- thestage/services/clients/thestage_api/dtos/inference_simulator_model_response.py +11 -11
- thestage/services/clients/thestage_api/dtos/inference_simulator_response.py +11 -11
- thestage/services/clients/thestage_api/dtos/installed_service.py +17 -17
- thestage/services/clients/thestage_api/dtos/instance_detected_gpus.py +20 -20
- thestage/services/clients/thestage_api/dtos/instance_rented_response.py +71 -71
- thestage/services/clients/thestage_api/dtos/logging_controller/docker_container_log_stream_request.py +7 -7
- thestage/services/clients/thestage_api/dtos/logging_controller/log_polling_request.py +13 -13
- thestage/services/clients/thestage_api/dtos/logging_controller/log_polling_response.py +14 -14
- thestage/services/clients/thestage_api/dtos/logging_controller/task_log_stream_request.py +7 -7
- thestage/services/clients/thestage_api/dtos/logging_controller/user_logs_query_request.py +21 -21
- thestage/services/clients/thestage_api/dtos/logging_controller/user_logs_query_response.py +14 -14
- thestage/services/clients/thestage_api/dtos/paginated_entity_list.py +11 -11
- thestage/services/clients/thestage_api/dtos/pagination_data.py +10 -10
- thestage/services/clients/thestage_api/dtos/price_definition.py +14 -14
- thestage/services/clients/thestage_api/dtos/project_controller/project_get_deploy_ssh_key_request.py +7 -7
- thestage/services/clients/thestage_api/dtos/project_controller/project_get_deploy_ssh_key_response.py +10 -10
- thestage/services/clients/thestage_api/dtos/project_controller/project_push_inference_simulator_model_request.py +8 -8
- thestage/services/clients/thestage_api/dtos/project_controller/project_push_inference_simulator_model_response.py +6 -6
- thestage/services/clients/thestage_api/dtos/project_controller/project_run_task_request.py +15 -15
- thestage/services/clients/thestage_api/dtos/project_controller/project_run_task_response.py +10 -10
- thestage/services/clients/thestage_api/dtos/project_controller/project_start_inference_simulator_request.py +13 -13
- thestage/services/clients/thestage_api/dtos/project_controller/project_start_inference_simulator_response.py +10 -10
- thestage/services/clients/thestage_api/dtos/project_response.py +32 -32
- thestage/services/clients/thestage_api/dtos/selfhosted_instance_response.py +56 -56
- thestage/services/clients/thestage_api/dtos/sftp_path_helper.py +13 -13
- thestage/services/clients/thestage_api/dtos/ssh_key_controller/add_ssh_key_to_user_request.py +8 -8
- thestage/services/clients/thestage_api/dtos/ssh_key_controller/add_ssh_key_to_user_response.py +11 -11
- thestage/services/clients/thestage_api/dtos/ssh_key_controller/add_ssh_public_key_to_instance_request.py +8 -8
- thestage/services/clients/thestage_api/dtos/ssh_key_controller/add_ssh_public_key_to_instance_response.py +11 -11
- thestage/services/clients/thestage_api/dtos/ssh_key_controller/is_user_has_public_ssh_key_request.py +7 -7
- thestage/services/clients/thestage_api/dtos/ssh_key_controller/is_user_has_public_ssh_key_response.py +12 -12
- thestage/services/clients/thestage_api/dtos/task_controller/task_list_for_project_request.py +10 -10
- thestage/services/clients/thestage_api/dtos/task_controller/task_list_for_project_response.py +12 -12
- thestage/services/clients/thestage_api/dtos/task_controller/task_status_localized_map_response.py +9 -9
- thestage/services/clients/thestage_api/dtos/task_controller/task_view_response.py +12 -12
- thestage/services/clients/thestage_api/dtos/user_controller/user_profile.py +12 -12
- thestage/services/clients/thestage_api/dtos/validate_token_response.py +11 -11
- thestage/services/config_provider/__init__.py +0 -0
- thestage/services/config_provider/config_provider.py +237 -237
- thestage/services/connect/connect_service.py +193 -196
- thestage/services/connect/dto/remote_server_config.py +9 -9
- thestage/services/container/__init__.py +0 -0
- thestage/services/container/container_service.py +374 -374
- thestage/services/container/mapper/__init__.py +0 -0
- thestage/services/container/mapper/container_mapper.py +30 -30
- thestage/services/core_files/config_entity.py +26 -26
- thestage/services/filesystem_service.py +133 -133
- thestage/services/instance/__init__.py +0 -0
- thestage/services/instance/instance_service.py +303 -303
- thestage/services/instance/mapper/__init__.py +0 -0
- thestage/services/instance/mapper/instance_mapper.py +24 -24
- thestage/services/instance/mapper/selfhosted_mapper.py +33 -33
- thestage/services/logging/byte_print_style.py +5 -5
- thestage/services/logging/dto/log_message.py +15 -15
- thestage/services/logging/dto/log_type.py +6 -6
- thestage/services/logging/exception/log_polling_exception.py +6 -6
- thestage/services/logging/logging_constants.py +3 -3
- thestage/services/logging/logging_service.py +367 -367
- thestage/services/project/__init__.py +0 -0
- thestage/services/project/dto/inference_simulator_dto.py +22 -22
- thestage/services/project/dto/inference_simulator_model_dto.py +20 -20
- thestage/services/project/dto/project_config.py +14 -14
- thestage/services/project/mapper/__init__.py +0 -0
- thestage/services/project/mapper/project_inference_simulator_mapper.py +21 -21
- thestage/services/project/mapper/project_inference_simulator_model_mapper.py +21 -21
- thestage/services/project/mapper/project_task_mapper.py +22 -22
- thestage/services/project/project_service.py +1253 -1253
- thestage/services/remote_server_service.py +609 -609
- thestage/services/service_factory.py +97 -97
- thestage/services/task/dto/task_dto.py +40 -40
- thestage/services/validation_service.py +61 -61
- {thestage-0.6.2.dist-info → thestage-0.6.3.dist-info}/LICENSE.txt +12 -12
- {thestage-0.6.2.dist-info → thestage-0.6.3.dist-info}/METADATA +3 -2
- thestage-0.6.3.dist-info/RECORD +176 -0
- {thestage-0.6.2.dist-info → thestage-0.6.3.dist-info}/WHEEL +1 -1
- thestage-0.6.2.dist-info/RECORD +0 -176
- {thestage-0.6.2.dist-info → thestage-0.6.3.dist-info}/entry_points.txt +0 -0
|
@@ -1,810 +1,810 @@
|
|
|
1
|
-
import time
|
|
2
|
-
from pathlib import Path
|
|
3
|
-
from typing import Optional, List
|
|
4
|
-
|
|
5
|
-
import re
|
|
6
|
-
|
|
7
|
-
import typer
|
|
8
|
-
from typing_extensions import Annotated
|
|
9
|
-
|
|
10
|
-
from thestage.cli_command import CliCommand
|
|
11
|
-
from thestage.cli_command_helper import get_command_group_help_panel, get_command_metadata, check_command_permission
|
|
12
|
-
from thestage.controllers.utils_controller import validate_config_and_get_service_factory, get_current_directory
|
|
13
|
-
from thestage.helpers.logger.app_logger import app_logger
|
|
14
|
-
from thestage.i18n.translation import __
|
|
15
|
-
from thestage.services.clients.thestage_api.dtos.inference_controller.get_inference_simulator_response import \
|
|
16
|
-
GetInferenceSimulatorResponse
|
|
17
|
-
from thestage.services.logging.logging_service import LoggingService
|
|
18
|
-
from thestage.services.project.project_service import ProjectService
|
|
19
|
-
from thestage.services.task.dto.task_dto import TaskDto
|
|
20
|
-
|
|
21
|
-
app = typer.Typer(no_args_is_help=True, help=__("Manage projects"))
|
|
22
|
-
inference_simulators_app = typer.Typer(no_args_is_help=True, help="Manage project inference simulators")
|
|
23
|
-
inference_simulator_model_app = typer.Typer(no_args_is_help=True, help="Manage project inference simulator models")
|
|
24
|
-
task_app = typer.Typer(no_args_is_help=True, help=__("Manage project tasks"))
|
|
25
|
-
config_app = typer.Typer(no_args_is_help=True, help=__("Manage project config"))
|
|
26
|
-
|
|
27
|
-
app.add_typer(inference_simulators_app, name="inference-simulator", rich_help_panel=get_command_group_help_panel())
|
|
28
|
-
app.add_typer(inference_simulator_model_app, name="model", rich_help_panel=get_command_group_help_panel())
|
|
29
|
-
app.add_typer(task_app, name="task", rich_help_panel=get_command_group_help_panel())
|
|
30
|
-
app.add_typer(config_app, name="config", rich_help_panel=get_command_group_help_panel())
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
@app.command(name='clone', no_args_is_help=True, help=__("Clone project repository to empty directory"), **get_command_metadata(CliCommand.PROJECT_CLONE))
|
|
34
|
-
def clone(
|
|
35
|
-
project_uid: str = typer.Argument(
|
|
36
|
-
help=__("Project unique ID"),
|
|
37
|
-
),
|
|
38
|
-
working_directory: Optional[str] = typer.Option(
|
|
39
|
-
None,
|
|
40
|
-
"--working-directory",
|
|
41
|
-
"-wd",
|
|
42
|
-
help=__("Full path to the working directory: current directory used by default"),
|
|
43
|
-
is_eager=False,
|
|
44
|
-
),
|
|
45
|
-
):
|
|
46
|
-
command_name = CliCommand.PROJECT_CLONE
|
|
47
|
-
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
48
|
-
check_command_permission(command_name)
|
|
49
|
-
|
|
50
|
-
if not working_directory:
|
|
51
|
-
working_directory = get_current_directory().joinpath(project_uid)
|
|
52
|
-
|
|
53
|
-
service_factory = validate_config_and_get_service_factory(working_directory=working_directory)
|
|
54
|
-
project_service = service_factory.get_project_service()
|
|
55
|
-
|
|
56
|
-
project_service.clone_project(
|
|
57
|
-
project_slug=project_uid,
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
raise typer.Exit(0)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
@app.command(name='init', no_args_is_help=True, help=__("Initialize project repository with existing files"), **get_command_metadata(CliCommand.PROJECT_INIT))
|
|
64
|
-
def init(
|
|
65
|
-
project_uid: Optional[str] = typer.Argument(
|
|
66
|
-
help=__("Project unique ID"),
|
|
67
|
-
),
|
|
68
|
-
working_directory: Optional[str] = typer.Option(
|
|
69
|
-
None,
|
|
70
|
-
"--working-directory",
|
|
71
|
-
"-wd",
|
|
72
|
-
help=__("Full path to working directory"),
|
|
73
|
-
is_eager=False,
|
|
74
|
-
),
|
|
75
|
-
):
|
|
76
|
-
command_name = CliCommand.PROJECT_INIT
|
|
77
|
-
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
78
|
-
check_command_permission(command_name)
|
|
79
|
-
|
|
80
|
-
service_factory = validate_config_and_get_service_factory(working_directory=working_directory)
|
|
81
|
-
project_service = service_factory.get_project_service()
|
|
82
|
-
project_config = service_factory.get_config_provider().read_project_config()
|
|
83
|
-
|
|
84
|
-
if project_config:
|
|
85
|
-
typer.echo(__("Directory is initialized and already contains working project"))
|
|
86
|
-
raise typer.Exit(1)
|
|
87
|
-
|
|
88
|
-
project_service.init_project(
|
|
89
|
-
project_slug=project_uid,
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
raise typer.Exit(0)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
@app.command(name='run', no_args_is_help=True, help=__("Run a task within the project. By default, it uses the latest commit from the main branch and streams real-time task logs."), **get_command_metadata(CliCommand.PROJECT_RUN))
|
|
96
|
-
def run(
|
|
97
|
-
command: Annotated[List[str], typer.Argument(
|
|
98
|
-
help=__("Command to run (required)"),
|
|
99
|
-
)],
|
|
100
|
-
commit_hash: Optional[str] = typer.Option(
|
|
101
|
-
None,
|
|
102
|
-
'--commit-hash',
|
|
103
|
-
'-hash',
|
|
104
|
-
help=__("Commit hash to use. By default, the current HEAD commit is used."),
|
|
105
|
-
is_eager=False,
|
|
106
|
-
),
|
|
107
|
-
docker_container_slug: Optional[str] = typer.Option(
|
|
108
|
-
None,
|
|
109
|
-
'--container-uid',
|
|
110
|
-
'-cid',
|
|
111
|
-
help=__("Docker container unique ID"),
|
|
112
|
-
is_eager=False,
|
|
113
|
-
),
|
|
114
|
-
working_directory: Optional[str] = typer.Option(
|
|
115
|
-
None,
|
|
116
|
-
"--working-directory",
|
|
117
|
-
"-wd",
|
|
118
|
-
help=__("Full path to working directory"),
|
|
119
|
-
show_default=False,
|
|
120
|
-
is_eager=False,
|
|
121
|
-
),
|
|
122
|
-
enable_log_stream: Optional[bool] = typer.Option(
|
|
123
|
-
True,
|
|
124
|
-
" /--no-logs",
|
|
125
|
-
" /-nl",
|
|
126
|
-
help=__("Disable real-time log streaming"),
|
|
127
|
-
is_eager=False,
|
|
128
|
-
),
|
|
129
|
-
task_title: Optional[str] = typer.Option(
|
|
130
|
-
None,
|
|
131
|
-
"--title",
|
|
132
|
-
"-t",
|
|
133
|
-
help=__("Provide a custom task title. Git commit message is used by default."),
|
|
134
|
-
is_eager=False,
|
|
135
|
-
),
|
|
136
|
-
files_to_add: Optional[str] = typer.Option(
|
|
137
|
-
None,
|
|
138
|
-
"--files-add",
|
|
139
|
-
"-fa",
|
|
140
|
-
help=__("Files to add to the commit. You can add files by their relative path from the working directory with a comma as a separator."),
|
|
141
|
-
is_eager=False,
|
|
142
|
-
),
|
|
143
|
-
is_skip_auto_commit: Optional[bool] = typer.Option(
|
|
144
|
-
False,
|
|
145
|
-
"--skip-autocommit",
|
|
146
|
-
"-sa",
|
|
147
|
-
help=__("Skip automatic commit of the changes"),
|
|
148
|
-
is_eager=False,
|
|
149
|
-
),
|
|
150
|
-
):
|
|
151
|
-
command_name = CliCommand.PROJECT_RUN
|
|
152
|
-
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
153
|
-
check_command_permission(command_name)
|
|
154
|
-
|
|
155
|
-
if not command:
|
|
156
|
-
typer.echo(__('Command is required'))
|
|
157
|
-
raise typer.Exit(1)
|
|
158
|
-
|
|
159
|
-
service_factory = validate_config_and_get_service_factory(working_directory=working_directory)
|
|
160
|
-
project_service = service_factory.get_project_service()
|
|
161
|
-
|
|
162
|
-
task: Optional[TaskDto] = project_service.project_run_task(
|
|
163
|
-
run_command=" ".join(command),
|
|
164
|
-
commit_hash=commit_hash,
|
|
165
|
-
docker_container_slug=docker_container_slug,
|
|
166
|
-
task_title=task_title,
|
|
167
|
-
files_to_add=files_to_add,
|
|
168
|
-
is_skip_auto_commit=is_skip_auto_commit,
|
|
169
|
-
)
|
|
170
|
-
|
|
171
|
-
if enable_log_stream:
|
|
172
|
-
logging_service: LoggingService = service_factory.get_logging_service()
|
|
173
|
-
logging_service.stream_task_logs_with_controls(task_id=task.id)
|
|
174
|
-
|
|
175
|
-
raise typer.Exit(0)
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
@task_app.command(name='cancel', no_args_is_help=True, help=__("Cancel a task by ID"), **get_command_metadata(CliCommand.PROJECT_TASK_CANCEL))
|
|
179
|
-
def cancel_task(
|
|
180
|
-
task_id: Annotated[int, typer.Argument(
|
|
181
|
-
help=__("Task ID (required)"),
|
|
182
|
-
)],
|
|
183
|
-
):
|
|
184
|
-
command_name = CliCommand.PROJECT_TASK_CANCEL
|
|
185
|
-
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
186
|
-
check_command_permission(command_name)
|
|
187
|
-
|
|
188
|
-
if not task_id:
|
|
189
|
-
typer.echo(__('Task ID is required'))
|
|
190
|
-
raise typer.Exit(1)
|
|
191
|
-
|
|
192
|
-
service_factory = validate_config_and_get_service_factory()
|
|
193
|
-
project_service = service_factory.get_project_service()
|
|
194
|
-
|
|
195
|
-
project_service.cancel_task(
|
|
196
|
-
task_id=task_id
|
|
197
|
-
)
|
|
198
|
-
|
|
199
|
-
raise typer.Exit(0)
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
@task_app.command("ls", help=__("List tasks"), **get_command_metadata(CliCommand.PROJECT_TASK_LS))
|
|
203
|
-
def list_runs(
|
|
204
|
-
project_uid: Annotated[str, typer.Argument(help=__("Project unique ID. By default, project info is taken from the current directory"), metavar="OPTIONAL")] = None,
|
|
205
|
-
row: int = typer.Option(
|
|
206
|
-
5,
|
|
207
|
-
'--row',
|
|
208
|
-
'-r',
|
|
209
|
-
help=__("Set number of rows displayed per page"),
|
|
210
|
-
is_eager=False,
|
|
211
|
-
),
|
|
212
|
-
page: int = typer.Option(
|
|
213
|
-
1,
|
|
214
|
-
'--page',
|
|
215
|
-
'-p',
|
|
216
|
-
help=__("Set starting page for displaying output"),
|
|
217
|
-
is_eager=False,
|
|
218
|
-
),
|
|
219
|
-
):
|
|
220
|
-
command_name = CliCommand.PROJECT_TASK_LS
|
|
221
|
-
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
222
|
-
check_command_permission(command_name)
|
|
223
|
-
|
|
224
|
-
service_factory = validate_config_and_get_service_factory()
|
|
225
|
-
project_service: ProjectService = service_factory.get_project_service()
|
|
226
|
-
|
|
227
|
-
project_service.print_task_list(project_uid, row, page)
|
|
228
|
-
|
|
229
|
-
typer.echo(__("Tasks listing complete"))
|
|
230
|
-
raise typer.Exit(0)
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
@task_app.command(name="logs", no_args_is_help=True, help=__("Stream real-time task logs or view last logs for a task"), **get_command_metadata(CliCommand.PROJECT_TASK_LOGS))
|
|
234
|
-
def task_logs(
|
|
235
|
-
task_id: Optional[int] = typer.Argument(help=__("Task ID"),),
|
|
236
|
-
logs_number: Optional[int] = typer.Option(
|
|
237
|
-
None,
|
|
238
|
-
'--number',
|
|
239
|
-
'-n',
|
|
240
|
-
help=__("Display a number of latest log entries. No real-time stream if provided."),
|
|
241
|
-
is_eager=False,
|
|
242
|
-
),
|
|
243
|
-
):
|
|
244
|
-
command_name = CliCommand.PROJECT_TASK_LOGS
|
|
245
|
-
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
246
|
-
check_command_permission(command_name)
|
|
247
|
-
|
|
248
|
-
if not task_id:
|
|
249
|
-
typer.echo(__('Task ID is required'))
|
|
250
|
-
raise typer.Exit(1)
|
|
251
|
-
|
|
252
|
-
service_factory = validate_config_and_get_service_factory()
|
|
253
|
-
logging_service: LoggingService = service_factory.get_logging_service()
|
|
254
|
-
|
|
255
|
-
if logs_number is None:
|
|
256
|
-
logging_service.stream_task_logs_with_controls(task_id=task_id)
|
|
257
|
-
else:
|
|
258
|
-
logging_service.print_last_task_logs(task_id=task_id, logs_number=logs_number)
|
|
259
|
-
|
|
260
|
-
app_logger.info(f'Task logs - end')
|
|
261
|
-
raise typer.Exit(0)
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
@app.command(name='checkout', no_args_is_help=True, help=__("Checkout project repository to a specific reference"), **get_command_metadata(CliCommand.PROJECT_CHECKOUT))
|
|
265
|
-
def checkout_project(
|
|
266
|
-
reference: Optional[str] = typer.Argument(
|
|
267
|
-
help=__("Task ID or branch name to checkout. '/' will try to identify the main branch."),
|
|
268
|
-
),
|
|
269
|
-
working_directory: Optional[str] = typer.Option(
|
|
270
|
-
None,
|
|
271
|
-
"--working-directory",
|
|
272
|
-
"-wd",
|
|
273
|
-
help=__("Full path to working directory"),
|
|
274
|
-
is_eager=False,
|
|
275
|
-
),
|
|
276
|
-
):
|
|
277
|
-
command_name = CliCommand.PROJECT_CHECKOUT
|
|
278
|
-
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
279
|
-
check_command_permission(command_name)
|
|
280
|
-
|
|
281
|
-
service_factory = validate_config_and_get_service_factory(working_directory=working_directory)
|
|
282
|
-
project_service = service_factory.get_project_service()
|
|
283
|
-
|
|
284
|
-
task_id: Optional[int] = None
|
|
285
|
-
branch_name: Optional[str] = None
|
|
286
|
-
|
|
287
|
-
if reference == "/":
|
|
288
|
-
pass
|
|
289
|
-
elif reference.isdigit():
|
|
290
|
-
task_id = int(reference)
|
|
291
|
-
else:
|
|
292
|
-
branch_name = reference
|
|
293
|
-
|
|
294
|
-
project_service.checkout_project(
|
|
295
|
-
task_id=task_id,
|
|
296
|
-
branch_name=branch_name,
|
|
297
|
-
)
|
|
298
|
-
|
|
299
|
-
raise typer.Exit(0)
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
@app.command(name='pull', help=__("Pulls the changes from the remote project repository. Equivalent to 'git pull'."), **get_command_metadata(CliCommand.PROJECT_PULL))
|
|
303
|
-
def pull_project(
|
|
304
|
-
working_directory: Optional[str] = typer.Option(
|
|
305
|
-
None,
|
|
306
|
-
"--working-directory",
|
|
307
|
-
"-wd",
|
|
308
|
-
help=__("Full path to working directory"),
|
|
309
|
-
is_eager=False,
|
|
310
|
-
),
|
|
311
|
-
):
|
|
312
|
-
command_name = CliCommand.PROJECT_PULL
|
|
313
|
-
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
314
|
-
check_command_permission(command_name)
|
|
315
|
-
|
|
316
|
-
service_factory = validate_config_and_get_service_factory(working_directory=working_directory)
|
|
317
|
-
project_service = service_factory.get_project_service()
|
|
318
|
-
|
|
319
|
-
project_service.pull_project()
|
|
320
|
-
|
|
321
|
-
raise typer.Exit(0)
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
@app.command(name='reset', help=__("Resets the current project branch to remote counterpart. All working tree changes will be lost. Equivalent to 'git fetch && git reset --hard origin/{ref}'."), **get_command_metadata(CliCommand.PROJECT_RESET))
|
|
325
|
-
def reset_project(
|
|
326
|
-
working_directory: Optional[str] = typer.Option(
|
|
327
|
-
None,
|
|
328
|
-
"--working-directory",
|
|
329
|
-
"-wd",
|
|
330
|
-
help=__("Full path to working directory"),
|
|
331
|
-
is_eager=False,
|
|
332
|
-
),
|
|
333
|
-
):
|
|
334
|
-
command_name = CliCommand.PROJECT_RESET
|
|
335
|
-
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
336
|
-
check_command_permission(command_name)
|
|
337
|
-
|
|
338
|
-
service_factory = validate_config_and_get_service_factory(working_directory=working_directory)
|
|
339
|
-
project_service = service_factory.get_project_service()
|
|
340
|
-
|
|
341
|
-
project_service.reset_project()
|
|
342
|
-
|
|
343
|
-
raise typer.Exit(0)
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
@config_app.command(name='set-default-container', no_args_is_help=True, help=__("Set default docker container for a project installation"), **get_command_metadata(CliCommand.PROJECT_CONFIG_SET_DEFAULT_CONTAINER))
|
|
347
|
-
def set_default_container(
|
|
348
|
-
container_uid: Annotated[Optional[str], typer.Argument(
|
|
349
|
-
help=__("Unique ID of the container to use by default for running tasks"),
|
|
350
|
-
)] = None,
|
|
351
|
-
unset_default_container: Optional[bool] = typer.Option(
|
|
352
|
-
False,
|
|
353
|
-
"--unset",
|
|
354
|
-
"-u",
|
|
355
|
-
help=__("Unsets the default docker container"),
|
|
356
|
-
is_eager=False,
|
|
357
|
-
),
|
|
358
|
-
working_directory: Optional[str] = typer.Option(
|
|
359
|
-
None,
|
|
360
|
-
"--working-directory",
|
|
361
|
-
"-wd",
|
|
362
|
-
help=__("Full path to working directory"),
|
|
363
|
-
is_eager=False,
|
|
364
|
-
),
|
|
365
|
-
):
|
|
366
|
-
command_name = CliCommand.PROJECT_CONFIG_SET_DEFAULT_CONTAINER
|
|
367
|
-
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
368
|
-
check_command_permission(command_name)
|
|
369
|
-
|
|
370
|
-
service_factory = validate_config_and_get_service_factory(working_directory=working_directory)
|
|
371
|
-
|
|
372
|
-
if unset_default_container and container_uid:
|
|
373
|
-
typer.echo("Container unique ID is provided along with unset flag. Please pick one.")
|
|
374
|
-
raise typer.Exit(1)
|
|
375
|
-
|
|
376
|
-
if not unset_default_container and not container_uid:
|
|
377
|
-
typer.echo("Provide container unique ID or use '--unset' flag")
|
|
378
|
-
raise typer.Exit(1)
|
|
379
|
-
|
|
380
|
-
project_service = service_factory.get_project_service()
|
|
381
|
-
|
|
382
|
-
project_service.set_default_container(
|
|
383
|
-
container_uid=container_uid,
|
|
384
|
-
)
|
|
385
|
-
|
|
386
|
-
raise typer.Exit(0)
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
@config_app.command(name='get', no_args_is_help=False, help=__("View config for a local project installation"), **get_command_metadata(CliCommand.PROJECT_CONFIG_GET))
|
|
390
|
-
def get_project_config(
|
|
391
|
-
working_directory: Optional[str] = typer.Option(
|
|
392
|
-
None,
|
|
393
|
-
"--working-directory",
|
|
394
|
-
"-wd",
|
|
395
|
-
help=__("Full path to working directory"),
|
|
396
|
-
is_eager=False,
|
|
397
|
-
),
|
|
398
|
-
):
|
|
399
|
-
command_name = CliCommand.PROJECT_CONFIG_GET
|
|
400
|
-
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
401
|
-
check_command_permission(command_name)
|
|
402
|
-
|
|
403
|
-
service_factory = validate_config_and_get_service_factory(working_directory=working_directory)
|
|
404
|
-
project_service = service_factory.get_project_service()
|
|
405
|
-
|
|
406
|
-
project_service.print_project_config()
|
|
407
|
-
|
|
408
|
-
raise typer.Exit(0)
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
@inference_simulators_app.command(name='run', no_args_is_help=True, help="Run an inference simulator within the project", **get_command_metadata(CliCommand.PROJECT_INFERENCE_SIMULATOR_RUN))
|
|
412
|
-
def run_inference_simulator(
|
|
413
|
-
rented_instance_unique_id: Optional[str] = typer.Option(
|
|
414
|
-
None,
|
|
415
|
-
'--rented-instance-unique-id',
|
|
416
|
-
'-ruid',
|
|
417
|
-
help=__("The rented instance unique ID on which the inference simulator will run"),
|
|
418
|
-
is_eager=False,
|
|
419
|
-
),
|
|
420
|
-
self_hosted_instance_unique_id: Optional[str] = typer.Option(
|
|
421
|
-
None,
|
|
422
|
-
'--self-hosted-instance-unique-id',
|
|
423
|
-
'-suid',
|
|
424
|
-
help=__("The self-hosted instance unique ID on which the inference simulator will run"),
|
|
425
|
-
is_eager=False,
|
|
426
|
-
),
|
|
427
|
-
commit_hash: Optional[str] = typer.Option(
|
|
428
|
-
None,
|
|
429
|
-
'--commit-hash',
|
|
430
|
-
'-hash',
|
|
431
|
-
help=__("Commit hash to use. By default, the current HEAD commit is used."),
|
|
432
|
-
is_eager=False,
|
|
433
|
-
),
|
|
434
|
-
working_directory: Optional[str] = typer.Option(
|
|
435
|
-
None,
|
|
436
|
-
"--working-directory",
|
|
437
|
-
"-wd",
|
|
438
|
-
help=__("Full path to working directory. By default, the current directory is used"),
|
|
439
|
-
show_default=False,
|
|
440
|
-
is_eager=False,
|
|
441
|
-
),
|
|
442
|
-
enable_log_stream: Optional[bool] = typer.Option(
|
|
443
|
-
True,
|
|
444
|
-
" /--no-logs",
|
|
445
|
-
" /-nl",
|
|
446
|
-
help=__("Disable real-time log streaming"),
|
|
447
|
-
is_eager=False,
|
|
448
|
-
),
|
|
449
|
-
is_skip_installation: Optional[bool] = typer.Option(
|
|
450
|
-
False,
|
|
451
|
-
"--skip-installation",
|
|
452
|
-
"-si",
|
|
453
|
-
help=__("Skip installing dependencies from requirements.txt and install.sh"),
|
|
454
|
-
is_eager=False,
|
|
455
|
-
),
|
|
456
|
-
files_to_add: Optional[str] = typer.Option(
|
|
457
|
-
None,
|
|
458
|
-
"--files-add",
|
|
459
|
-
"-fa",
|
|
460
|
-
help=__("Files to add to the commit. You can add files by their relative path from the working directory with a comma as a separator."),
|
|
461
|
-
is_eager=False,
|
|
462
|
-
),
|
|
463
|
-
is_skip_auto_commit: Optional[bool] = typer.Option(
|
|
464
|
-
False,
|
|
465
|
-
"--skip-autocommit",
|
|
466
|
-
"-sa",
|
|
467
|
-
help=__("Skip automatic commit of the changes"),
|
|
468
|
-
is_eager=False,
|
|
469
|
-
),
|
|
470
|
-
):
|
|
471
|
-
command_name = CliCommand.PROJECT_INFERENCE_SIMULATOR_RUN
|
|
472
|
-
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
473
|
-
check_command_permission(command_name)
|
|
474
|
-
|
|
475
|
-
service_factory = validate_config_and_get_service_factory(working_directory=working_directory)
|
|
476
|
-
config = service_factory.get_config_provider().get_config()
|
|
477
|
-
|
|
478
|
-
working_dir_path = Path(working_directory) if working_directory else Path(config.runtime.working_directory)
|
|
479
|
-
inference_files = list(working_dir_path.rglob("inference.py"))
|
|
480
|
-
if not inference_files:
|
|
481
|
-
typer.echo("No inference.py file found in the project directory.")
|
|
482
|
-
raise typer.Exit(1)
|
|
483
|
-
elif len(inference_files) == 1:
|
|
484
|
-
selected_inference = inference_files[0]
|
|
485
|
-
else:
|
|
486
|
-
choices = [str(path.relative_to(working_dir_path)) for path in inference_files]
|
|
487
|
-
typer.echo("Multiple inference.py files found:")
|
|
488
|
-
for idx, choice in enumerate(choices, start=1):
|
|
489
|
-
typer.echo(f"{idx}) {choice}")
|
|
490
|
-
choice_str = typer.prompt("Choose which inference.py to use")
|
|
491
|
-
try:
|
|
492
|
-
choice_index = int(choice_str)
|
|
493
|
-
except ValueError:
|
|
494
|
-
raise typer.BadParameter("Invalid input. Please enter a number.")
|
|
495
|
-
if not (1 <= choice_index <= len(choices)):
|
|
496
|
-
raise typer.BadParameter("Choice out of range.")
|
|
497
|
-
selected_inference = inference_files[choice_index - 1]
|
|
498
|
-
|
|
499
|
-
relative_inference = selected_inference.relative_to(working_dir_path)
|
|
500
|
-
parent_dir = relative_inference.parent
|
|
501
|
-
if parent_dir == Path("."):
|
|
502
|
-
inference_dir = "/"
|
|
503
|
-
else:
|
|
504
|
-
inference_dir = f"{parent_dir.as_posix()}/"
|
|
505
|
-
typer.echo(f"Selected inference file relative path: {inference_dir}")
|
|
506
|
-
|
|
507
|
-
project_service = service_factory.get_project_service()
|
|
508
|
-
|
|
509
|
-
inference_simulator = project_service.project_run_inference_simulator(
|
|
510
|
-
commit_hash=commit_hash,
|
|
511
|
-
rented_instance_unique_id=rented_instance_unique_id,
|
|
512
|
-
self_hosted_instance_unique_id=self_hosted_instance_unique_id,
|
|
513
|
-
inference_dir=inference_dir,
|
|
514
|
-
is_skip_installation=is_skip_installation,
|
|
515
|
-
files_to_add=files_to_add,
|
|
516
|
-
is_skip_auto_commit=is_skip_auto_commit,
|
|
517
|
-
)
|
|
518
|
-
|
|
519
|
-
if enable_log_stream:
|
|
520
|
-
logging_service: LoggingService = service_factory.get_logging_service()
|
|
521
|
-
|
|
522
|
-
logging_service.stream_inference_simulator_logs_with_controls(
|
|
523
|
-
slug=inference_simulator.slug
|
|
524
|
-
)
|
|
525
|
-
raise typer.Exit(0)
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
@inference_simulators_app.command(name='save-metadata', no_args_is_help=True, help="Get and save inference simulator metadata", **get_command_metadata(CliCommand.PROJECT_INFERENCE_SIMULATOR_SAVE_METADATA))
|
|
529
|
-
def get_and_save_inference_simulator_metadata(
|
|
530
|
-
unique_id: Optional[str] = typer.Argument(help=__("Inference simulator unique ID"),),
|
|
531
|
-
file_path: Optional[str] = typer.Option(
|
|
532
|
-
None,
|
|
533
|
-
"--file-path",
|
|
534
|
-
"-fp",
|
|
535
|
-
help=__("Full path to a new file. By default metadata is saved to the current directory as metadata.json"),
|
|
536
|
-
show_default=False,
|
|
537
|
-
is_eager=False,
|
|
538
|
-
),
|
|
539
|
-
):
|
|
540
|
-
command_name = CliCommand.PROJECT_INFERENCE_SIMULATOR_SAVE_METADATA
|
|
541
|
-
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
542
|
-
check_command_permission(command_name)
|
|
543
|
-
|
|
544
|
-
service_factory = validate_config_and_get_service_factory()
|
|
545
|
-
project_service = service_factory.get_project_service()
|
|
546
|
-
|
|
547
|
-
project_service.project_get_and_save_inference_simulator_metadata(
|
|
548
|
-
file_path=file_path,
|
|
549
|
-
slug=unique_id,
|
|
550
|
-
)
|
|
551
|
-
|
|
552
|
-
raise typer.Exit(0)
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
@inference_simulators_app.command(name='push', no_args_is_help=True, help="Push an inference simulator within the project to model registry", **get_command_metadata(CliCommand.PROJECT_INFERENCE_SIMULATOR_PUSH))
|
|
556
|
-
def push_inference_simulator(
|
|
557
|
-
unique_id: Optional[str] = typer.Argument(help=__("Inference simulator unique ID"),),
|
|
558
|
-
):
|
|
559
|
-
command_name = CliCommand.PROJECT_INFERENCE_SIMULATOR_PUSH
|
|
560
|
-
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
561
|
-
check_command_permission(command_name)
|
|
562
|
-
|
|
563
|
-
service_factory = validate_config_and_get_service_factory()
|
|
564
|
-
project_service = service_factory.get_project_service()
|
|
565
|
-
|
|
566
|
-
project_service.project_push_inference_simulator(
|
|
567
|
-
slug=unique_id,
|
|
568
|
-
)
|
|
569
|
-
|
|
570
|
-
raise typer.Exit(0)
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
@inference_simulators_app.command("ls", help=__("List inference simulators"), **get_command_metadata(CliCommand.PROJECT_INFERENCE_SIMULATOR_LS))
|
|
574
|
-
def list_inference_simulators(
|
|
575
|
-
project_uid: Annotated[str, typer.Argument(help=__("Project unique ID. By default, project info is taken from the current directory"), metavar="OPTIONAL")] = None,
|
|
576
|
-
row: int = typer.Option(
|
|
577
|
-
5,
|
|
578
|
-
'--row',
|
|
579
|
-
'-r',
|
|
580
|
-
help=__("Set number of rows displayed per page"),
|
|
581
|
-
is_eager=False,
|
|
582
|
-
),
|
|
583
|
-
page: int = typer.Option(
|
|
584
|
-
1,
|
|
585
|
-
'--page',
|
|
586
|
-
'-p',
|
|
587
|
-
help=__("Set starting page for displaying output"),
|
|
588
|
-
is_eager=False,
|
|
589
|
-
),
|
|
590
|
-
statuses: List[str] = typer.Option(
|
|
591
|
-
None,
|
|
592
|
-
'--status',
|
|
593
|
-
'-s',
|
|
594
|
-
help=__("Filter by status, use --status all to list all inference simulators"),
|
|
595
|
-
is_eager=False,
|
|
596
|
-
),
|
|
597
|
-
):
|
|
598
|
-
command_name = CliCommand.PROJECT_INFERENCE_SIMULATOR_LS
|
|
599
|
-
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
600
|
-
check_command_permission(command_name)
|
|
601
|
-
|
|
602
|
-
service_factory = validate_config_and_get_service_factory()
|
|
603
|
-
project_service: ProjectService = service_factory.get_project_service()
|
|
604
|
-
|
|
605
|
-
project_service.print_inference_simulator_list(project_uid, statuses, row, page)
|
|
606
|
-
|
|
607
|
-
typer.echo(__("Inference simulators listing complete"))
|
|
608
|
-
raise typer.Exit(0)
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
@inference_simulator_model_app.command("ls", help=__("List inference simulator models"), **get_command_metadata(CliCommand.PROJECT_MODEL_LS))
|
|
612
|
-
def list_inference_simulator_models(
|
|
613
|
-
project_uid: Annotated[str, typer.Argument(help=__("Project unique ID. By default, project info is taken from the current directory"), metavar="OPTIONAL")] = None,
|
|
614
|
-
row: int = typer.Option(
|
|
615
|
-
5,
|
|
616
|
-
'--row',
|
|
617
|
-
'-r',
|
|
618
|
-
help=__("Set number of rows displayed per page"),
|
|
619
|
-
is_eager=False,
|
|
620
|
-
),
|
|
621
|
-
page: int = typer.Option(
|
|
622
|
-
1,
|
|
623
|
-
'--page',
|
|
624
|
-
'-p',
|
|
625
|
-
help=__("Set starting page for displaying output"),
|
|
626
|
-
is_eager=False,
|
|
627
|
-
),
|
|
628
|
-
statuses: List[str] = typer.Option(
|
|
629
|
-
None,
|
|
630
|
-
'--status',
|
|
631
|
-
'-s',
|
|
632
|
-
help=__("Filter by status, use --status all to list all inference simulator models"),
|
|
633
|
-
is_eager=False,
|
|
634
|
-
),
|
|
635
|
-
):
|
|
636
|
-
command_name = CliCommand.PROJECT_MODEL_LS
|
|
637
|
-
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
638
|
-
check_command_permission(command_name)
|
|
639
|
-
|
|
640
|
-
service_factory = validate_config_and_get_service_factory()
|
|
641
|
-
project_service: ProjectService = service_factory.get_project_service()
|
|
642
|
-
|
|
643
|
-
project_service.print_inference_simulator_model_list(project_uid, statuses, row, page)
|
|
644
|
-
|
|
645
|
-
typer.echo(__("Inference simulator models listing complete"))
|
|
646
|
-
raise typer.Exit(0)
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
@inference_simulators_app.command(name="logs", no_args_is_help=True, help=__("Stream real-time task logs or view last logs for an inference simulator"), **get_command_metadata(CliCommand.PROJECT_INFERENCE_SIMULATOR_LOGS))
|
|
650
|
-
def inference_simulator_logs(
|
|
651
|
-
unique_id: Optional[str] = typer.Argument(help=__("Inference simulator unique ID"),),
|
|
652
|
-
logs_number: Optional[int] = typer.Option(
|
|
653
|
-
None,
|
|
654
|
-
'--number',
|
|
655
|
-
'-n',
|
|
656
|
-
help=__("Display a number of latest log entries. No real-time stream if provided."),
|
|
657
|
-
is_eager=False,
|
|
658
|
-
),
|
|
659
|
-
):
|
|
660
|
-
command_name = CliCommand.PROJECT_INFERENCE_SIMULATOR_LOGS
|
|
661
|
-
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
662
|
-
check_command_permission(command_name)
|
|
663
|
-
|
|
664
|
-
if not unique_id:
|
|
665
|
-
typer.echo(__('Inference simulator UID is required'))
|
|
666
|
-
raise typer.Exit(1)
|
|
667
|
-
|
|
668
|
-
service_factory = validate_config_and_get_service_factory()
|
|
669
|
-
logging_service: LoggingService = service_factory.get_logging_service()
|
|
670
|
-
|
|
671
|
-
if logs_number is None:
|
|
672
|
-
logging_service.stream_inference_simulator_logs_with_controls(
|
|
673
|
-
slug=unique_id
|
|
674
|
-
)
|
|
675
|
-
else:
|
|
676
|
-
get_inference_simulator_response: Optional[GetInferenceSimulatorResponse] = service_factory.get_thestage_api_client().get_inference_simulator(
|
|
677
|
-
slug=unique_id,
|
|
678
|
-
)
|
|
679
|
-
if not get_inference_simulator_response:
|
|
680
|
-
typer.echo(__("Inference simulator with UID %uid% not found", {"uid": unique_id}))
|
|
681
|
-
raise typer.Exit(1)
|
|
682
|
-
else:
|
|
683
|
-
inference_simulator_id = get_inference_simulator_response.inferenceSimulator.id
|
|
684
|
-
logging_service.print_last_inference_simulator_logs(inference_simulator_id=inference_simulator_id, logs_number=logs_number)
|
|
685
|
-
|
|
686
|
-
app_logger.info(f'Inference simulator logs - end')
|
|
687
|
-
raise typer.Exit(0)
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
@inference_simulator_model_app.command("deploy-instance", no_args_is_help=True, help=__("Deploy an inference simulator model to an instance"), **get_command_metadata(CliCommand.PROJECT_MODEL_DEPLOY_INSTANCE))
|
|
691
|
-
def deploy_inference_simulator_model_to_instance(
|
|
692
|
-
unique_id: Optional[str] = typer.Argument(help=__("Inference simulator model unique ID"), ),
|
|
693
|
-
rented_instance_unique_id: Optional[str] = typer.Option(
|
|
694
|
-
None,
|
|
695
|
-
'--rented-instance-unique-id',
|
|
696
|
-
'-ruid',
|
|
697
|
-
help=__("The rented instance unique ID on which the inference simulator model will be deployed"),
|
|
698
|
-
is_eager=False,
|
|
699
|
-
),
|
|
700
|
-
self_hosted_instance_unique_id: Optional[str] = typer.Option(
|
|
701
|
-
None,
|
|
702
|
-
'--self-hosted-instance-unique-id',
|
|
703
|
-
'-suid',
|
|
704
|
-
help=__("The self-hosted instance unique ID on which the inference simulator model will be deployed"),
|
|
705
|
-
is_eager=False,
|
|
706
|
-
),
|
|
707
|
-
working_directory: Optional[str] = typer.Option(
|
|
708
|
-
None,
|
|
709
|
-
"--working-directory",
|
|
710
|
-
"-wd",
|
|
711
|
-
help=__("Full path to working directory. By default, the current directory is used"),
|
|
712
|
-
show_default=False,
|
|
713
|
-
is_eager=False,
|
|
714
|
-
),
|
|
715
|
-
enable_log_stream: Optional[bool] = typer.Option(
|
|
716
|
-
True,
|
|
717
|
-
" /--no-logs",
|
|
718
|
-
" /-nl",
|
|
719
|
-
help=__("Disable real-time log streaming"),
|
|
720
|
-
is_eager=False,
|
|
721
|
-
),
|
|
722
|
-
):
|
|
723
|
-
command_name = CliCommand.PROJECT_MODEL_DEPLOY_INSTANCE
|
|
724
|
-
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
725
|
-
check_command_permission(command_name)
|
|
726
|
-
|
|
727
|
-
if unique_id and not re.match(r"^[a-zA-Z0-9-]+$", unique_id):
|
|
728
|
-
raise typer.BadParameter(__("Invalid UID format. The UID can only contain letters, numbers, and hyphens."))
|
|
729
|
-
|
|
730
|
-
unique_id_with_timestamp = f"{unique_id}-{int(time.time())}"
|
|
731
|
-
|
|
732
|
-
service_factory = validate_config_and_get_service_factory(working_directory=working_directory)
|
|
733
|
-
project_service = service_factory.get_project_service()
|
|
734
|
-
|
|
735
|
-
project_service.project_deploy_inference_simulator_model_to_instance(
|
|
736
|
-
unique_id=unique_id,
|
|
737
|
-
unique_id_with_timestamp=unique_id_with_timestamp,
|
|
738
|
-
rented_instance_unique_id=rented_instance_unique_id,
|
|
739
|
-
self_hosted_instance_unique_id=self_hosted_instance_unique_id,
|
|
740
|
-
)
|
|
741
|
-
|
|
742
|
-
if enable_log_stream:
|
|
743
|
-
logging_service: LoggingService = service_factory.get_logging_service()
|
|
744
|
-
|
|
745
|
-
logging_service.stream_inference_simulator_logs_with_controls(
|
|
746
|
-
slug=unique_id_with_timestamp
|
|
747
|
-
)
|
|
748
|
-
raise typer.Exit(0)
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
@inference_simulator_model_app.command("deploy-sagemaker", no_args_is_help=True, help=__("Deploy an inference simulator model to SageMaker"), **get_command_metadata(CliCommand.PROJECT_MODEL_DEPLOY_SAGEMAKER))
|
|
752
|
-
def deploy_inference_simulator_model_to_sagemaker(
|
|
753
|
-
unique_id: Optional[str] = typer.Argument(help=__("Inference simulator model unique ID"), ),
|
|
754
|
-
arn: Optional[str] = typer.Option(
|
|
755
|
-
None,
|
|
756
|
-
'--amazon-resource-name',
|
|
757
|
-
'-arn',
|
|
758
|
-
help=__("The Amazon Resource Name of the IAM Role to use, e.g., arn:aws:iam::{aws_account_id}:role/{role}"),
|
|
759
|
-
is_eager=False,
|
|
760
|
-
),
|
|
761
|
-
working_directory: Optional[str] = typer.Option(
|
|
762
|
-
None,
|
|
763
|
-
"--working-directory",
|
|
764
|
-
"-wd",
|
|
765
|
-
help=__("Full path to working directory. By default, the current directory is used"),
|
|
766
|
-
show_default=False,
|
|
767
|
-
is_eager=False,
|
|
768
|
-
),
|
|
769
|
-
instance_type: Optional[str] = typer.Option(
|
|
770
|
-
None,
|
|
771
|
-
'--instance-type',
|
|
772
|
-
'-it',
|
|
773
|
-
help=__("Instance type on which the inference simulator model will be deployed"),
|
|
774
|
-
is_eager=False,
|
|
775
|
-
),
|
|
776
|
-
initial_variant_weight: Optional[float] = typer.Option(
|
|
777
|
-
None,
|
|
778
|
-
"--initial-variant-weight",
|
|
779
|
-
"-ivw",
|
|
780
|
-
help=__("Initial Variant Weight. By default 1.0"),
|
|
781
|
-
show_default=False,
|
|
782
|
-
is_eager=False,
|
|
783
|
-
),
|
|
784
|
-
initial_instance_count: Optional[int] = typer.Option(
|
|
785
|
-
None,
|
|
786
|
-
"--initial-instance-count",
|
|
787
|
-
"-iic",
|
|
788
|
-
help=__("Initial Instance Count"),
|
|
789
|
-
show_default=False,
|
|
790
|
-
is_eager=False,
|
|
791
|
-
),
|
|
792
|
-
|
|
793
|
-
):
|
|
794
|
-
command_name = CliCommand.PROJECT_MODEL_DEPLOY_SAGEMAKER
|
|
795
|
-
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
796
|
-
check_command_permission(command_name)
|
|
797
|
-
|
|
798
|
-
if unique_id and not re.match(r"^[a-zA-Z0-9-]+$", unique_id):
|
|
799
|
-
raise typer.BadParameter(__("Invalid UID format. The UID can only contain letters, numbers, and hyphens."))
|
|
800
|
-
|
|
801
|
-
service_factory = validate_config_and_get_service_factory(working_directory=working_directory)
|
|
802
|
-
project_service = service_factory.get_project_service()
|
|
803
|
-
|
|
804
|
-
project_service.project_deploy_inference_simulator_model_to_sagemaker(
|
|
805
|
-
unique_id=unique_id,
|
|
806
|
-
arn=arn,
|
|
807
|
-
instance_type=instance_type,
|
|
808
|
-
initial_variant_weight=initial_variant_weight,
|
|
809
|
-
initial_instance_count=initial_instance_count,
|
|
810
|
-
)
|
|
1
|
+
import time
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Optional, List
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
from typing_extensions import Annotated
|
|
9
|
+
|
|
10
|
+
from thestage.cli_command import CliCommand
|
|
11
|
+
from thestage.cli_command_helper import get_command_group_help_panel, get_command_metadata, check_command_permission
|
|
12
|
+
from thestage.controllers.utils_controller import validate_config_and_get_service_factory, get_current_directory
|
|
13
|
+
from thestage.helpers.logger.app_logger import app_logger
|
|
14
|
+
from thestage.i18n.translation import __
|
|
15
|
+
from thestage.services.clients.thestage_api.dtos.inference_controller.get_inference_simulator_response import \
|
|
16
|
+
GetInferenceSimulatorResponse
|
|
17
|
+
from thestage.services.logging.logging_service import LoggingService
|
|
18
|
+
from thestage.services.project.project_service import ProjectService
|
|
19
|
+
from thestage.services.task.dto.task_dto import TaskDto
|
|
20
|
+
|
|
21
|
+
app = typer.Typer(no_args_is_help=True, help=__("Manage projects"))
|
|
22
|
+
inference_simulators_app = typer.Typer(no_args_is_help=True, help="Manage project inference simulators")
|
|
23
|
+
inference_simulator_model_app = typer.Typer(no_args_is_help=True, help="Manage project inference simulator models")
|
|
24
|
+
task_app = typer.Typer(no_args_is_help=True, help=__("Manage project tasks"))
|
|
25
|
+
config_app = typer.Typer(no_args_is_help=True, help=__("Manage project config"))
|
|
26
|
+
|
|
27
|
+
app.add_typer(inference_simulators_app, name="inference-simulator", rich_help_panel=get_command_group_help_panel())
|
|
28
|
+
app.add_typer(inference_simulator_model_app, name="model", rich_help_panel=get_command_group_help_panel())
|
|
29
|
+
app.add_typer(task_app, name="task", rich_help_panel=get_command_group_help_panel())
|
|
30
|
+
app.add_typer(config_app, name="config", rich_help_panel=get_command_group_help_panel())
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@app.command(name='clone', no_args_is_help=True, help=__("Clone project repository to empty directory"), **get_command_metadata(CliCommand.PROJECT_CLONE))
|
|
34
|
+
def clone(
|
|
35
|
+
project_uid: str = typer.Argument(
|
|
36
|
+
help=__("Project unique ID"),
|
|
37
|
+
),
|
|
38
|
+
working_directory: Optional[str] = typer.Option(
|
|
39
|
+
None,
|
|
40
|
+
"--working-directory",
|
|
41
|
+
"-wd",
|
|
42
|
+
help=__("Full path to the working directory: current directory used by default"),
|
|
43
|
+
is_eager=False,
|
|
44
|
+
),
|
|
45
|
+
):
|
|
46
|
+
command_name = CliCommand.PROJECT_CLONE
|
|
47
|
+
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
48
|
+
check_command_permission(command_name)
|
|
49
|
+
|
|
50
|
+
if not working_directory:
|
|
51
|
+
working_directory = get_current_directory().joinpath(project_uid)
|
|
52
|
+
|
|
53
|
+
service_factory = validate_config_and_get_service_factory(working_directory=working_directory)
|
|
54
|
+
project_service = service_factory.get_project_service()
|
|
55
|
+
|
|
56
|
+
project_service.clone_project(
|
|
57
|
+
project_slug=project_uid,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
raise typer.Exit(0)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@app.command(name='init', no_args_is_help=True, help=__("Initialize project repository with existing files"), **get_command_metadata(CliCommand.PROJECT_INIT))
|
|
64
|
+
def init(
|
|
65
|
+
project_uid: Optional[str] = typer.Argument(
|
|
66
|
+
help=__("Project unique ID"),
|
|
67
|
+
),
|
|
68
|
+
working_directory: Optional[str] = typer.Option(
|
|
69
|
+
None,
|
|
70
|
+
"--working-directory",
|
|
71
|
+
"-wd",
|
|
72
|
+
help=__("Full path to working directory"),
|
|
73
|
+
is_eager=False,
|
|
74
|
+
),
|
|
75
|
+
):
|
|
76
|
+
command_name = CliCommand.PROJECT_INIT
|
|
77
|
+
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
78
|
+
check_command_permission(command_name)
|
|
79
|
+
|
|
80
|
+
service_factory = validate_config_and_get_service_factory(working_directory=working_directory)
|
|
81
|
+
project_service = service_factory.get_project_service()
|
|
82
|
+
project_config = service_factory.get_config_provider().read_project_config()
|
|
83
|
+
|
|
84
|
+
if project_config:
|
|
85
|
+
typer.echo(__("Directory is initialized and already contains working project"))
|
|
86
|
+
raise typer.Exit(1)
|
|
87
|
+
|
|
88
|
+
project_service.init_project(
|
|
89
|
+
project_slug=project_uid,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
raise typer.Exit(0)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@app.command(name='run', no_args_is_help=True, help=__("Run a task within the project. By default, it uses the latest commit from the main branch and streams real-time task logs."), **get_command_metadata(CliCommand.PROJECT_RUN))
|
|
96
|
+
def run(
|
|
97
|
+
command: Annotated[List[str], typer.Argument(
|
|
98
|
+
help=__("Command to run (required)"),
|
|
99
|
+
)],
|
|
100
|
+
commit_hash: Optional[str] = typer.Option(
|
|
101
|
+
None,
|
|
102
|
+
'--commit-hash',
|
|
103
|
+
'-hash',
|
|
104
|
+
help=__("Commit hash to use. By default, the current HEAD commit is used."),
|
|
105
|
+
is_eager=False,
|
|
106
|
+
),
|
|
107
|
+
docker_container_slug: Optional[str] = typer.Option(
|
|
108
|
+
None,
|
|
109
|
+
'--container-uid',
|
|
110
|
+
'-cid',
|
|
111
|
+
help=__("Docker container unique ID"),
|
|
112
|
+
is_eager=False,
|
|
113
|
+
),
|
|
114
|
+
working_directory: Optional[str] = typer.Option(
|
|
115
|
+
None,
|
|
116
|
+
"--working-directory",
|
|
117
|
+
"-wd",
|
|
118
|
+
help=__("Full path to working directory"),
|
|
119
|
+
show_default=False,
|
|
120
|
+
is_eager=False,
|
|
121
|
+
),
|
|
122
|
+
enable_log_stream: Optional[bool] = typer.Option(
|
|
123
|
+
True,
|
|
124
|
+
" /--no-logs",
|
|
125
|
+
" /-nl",
|
|
126
|
+
help=__("Disable real-time log streaming"),
|
|
127
|
+
is_eager=False,
|
|
128
|
+
),
|
|
129
|
+
task_title: Optional[str] = typer.Option(
|
|
130
|
+
None,
|
|
131
|
+
"--title",
|
|
132
|
+
"-t",
|
|
133
|
+
help=__("Provide a custom task title. Git commit message is used by default."),
|
|
134
|
+
is_eager=False,
|
|
135
|
+
),
|
|
136
|
+
files_to_add: Optional[str] = typer.Option(
|
|
137
|
+
None,
|
|
138
|
+
"--files-add",
|
|
139
|
+
"-fa",
|
|
140
|
+
help=__("Files to add to the commit. You can add files by their relative path from the working directory with a comma as a separator."),
|
|
141
|
+
is_eager=False,
|
|
142
|
+
),
|
|
143
|
+
is_skip_auto_commit: Optional[bool] = typer.Option(
|
|
144
|
+
False,
|
|
145
|
+
"--skip-autocommit",
|
|
146
|
+
"-sa",
|
|
147
|
+
help=__("Skip automatic commit of the changes"),
|
|
148
|
+
is_eager=False,
|
|
149
|
+
),
|
|
150
|
+
):
|
|
151
|
+
command_name = CliCommand.PROJECT_RUN
|
|
152
|
+
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
153
|
+
check_command_permission(command_name)
|
|
154
|
+
|
|
155
|
+
if not command:
|
|
156
|
+
typer.echo(__('Command is required'))
|
|
157
|
+
raise typer.Exit(1)
|
|
158
|
+
|
|
159
|
+
service_factory = validate_config_and_get_service_factory(working_directory=working_directory)
|
|
160
|
+
project_service = service_factory.get_project_service()
|
|
161
|
+
|
|
162
|
+
task: Optional[TaskDto] = project_service.project_run_task(
|
|
163
|
+
run_command=" ".join(command),
|
|
164
|
+
commit_hash=commit_hash,
|
|
165
|
+
docker_container_slug=docker_container_slug,
|
|
166
|
+
task_title=task_title,
|
|
167
|
+
files_to_add=files_to_add,
|
|
168
|
+
is_skip_auto_commit=is_skip_auto_commit,
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
if enable_log_stream:
|
|
172
|
+
logging_service: LoggingService = service_factory.get_logging_service()
|
|
173
|
+
logging_service.stream_task_logs_with_controls(task_id=task.id)
|
|
174
|
+
|
|
175
|
+
raise typer.Exit(0)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
@task_app.command(name='cancel', no_args_is_help=True, help=__("Cancel a task by ID"), **get_command_metadata(CliCommand.PROJECT_TASK_CANCEL))
|
|
179
|
+
def cancel_task(
|
|
180
|
+
task_id: Annotated[int, typer.Argument(
|
|
181
|
+
help=__("Task ID (required)"),
|
|
182
|
+
)],
|
|
183
|
+
):
|
|
184
|
+
command_name = CliCommand.PROJECT_TASK_CANCEL
|
|
185
|
+
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
186
|
+
check_command_permission(command_name)
|
|
187
|
+
|
|
188
|
+
if not task_id:
|
|
189
|
+
typer.echo(__('Task ID is required'))
|
|
190
|
+
raise typer.Exit(1)
|
|
191
|
+
|
|
192
|
+
service_factory = validate_config_and_get_service_factory()
|
|
193
|
+
project_service = service_factory.get_project_service()
|
|
194
|
+
|
|
195
|
+
project_service.cancel_task(
|
|
196
|
+
task_id=task_id
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
raise typer.Exit(0)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
@task_app.command("ls", help=__("List tasks"), **get_command_metadata(CliCommand.PROJECT_TASK_LS))
|
|
203
|
+
def list_runs(
|
|
204
|
+
project_uid: Annotated[str, typer.Argument(help=__("Project unique ID. By default, project info is taken from the current directory"), metavar="OPTIONAL")] = None,
|
|
205
|
+
row: int = typer.Option(
|
|
206
|
+
5,
|
|
207
|
+
'--row',
|
|
208
|
+
'-r',
|
|
209
|
+
help=__("Set number of rows displayed per page"),
|
|
210
|
+
is_eager=False,
|
|
211
|
+
),
|
|
212
|
+
page: int = typer.Option(
|
|
213
|
+
1,
|
|
214
|
+
'--page',
|
|
215
|
+
'-p',
|
|
216
|
+
help=__("Set starting page for displaying output"),
|
|
217
|
+
is_eager=False,
|
|
218
|
+
),
|
|
219
|
+
):
|
|
220
|
+
command_name = CliCommand.PROJECT_TASK_LS
|
|
221
|
+
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
222
|
+
check_command_permission(command_name)
|
|
223
|
+
|
|
224
|
+
service_factory = validate_config_and_get_service_factory()
|
|
225
|
+
project_service: ProjectService = service_factory.get_project_service()
|
|
226
|
+
|
|
227
|
+
project_service.print_task_list(project_uid, row, page)
|
|
228
|
+
|
|
229
|
+
typer.echo(__("Tasks listing complete"))
|
|
230
|
+
raise typer.Exit(0)
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
@task_app.command(name="logs", no_args_is_help=True, help=__("Stream real-time task logs or view last logs for a task"), **get_command_metadata(CliCommand.PROJECT_TASK_LOGS))
|
|
234
|
+
def task_logs(
|
|
235
|
+
task_id: Optional[int] = typer.Argument(help=__("Task ID"),),
|
|
236
|
+
logs_number: Optional[int] = typer.Option(
|
|
237
|
+
None,
|
|
238
|
+
'--number',
|
|
239
|
+
'-n',
|
|
240
|
+
help=__("Display a number of latest log entries. No real-time stream if provided."),
|
|
241
|
+
is_eager=False,
|
|
242
|
+
),
|
|
243
|
+
):
|
|
244
|
+
command_name = CliCommand.PROJECT_TASK_LOGS
|
|
245
|
+
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
246
|
+
check_command_permission(command_name)
|
|
247
|
+
|
|
248
|
+
if not task_id:
|
|
249
|
+
typer.echo(__('Task ID is required'))
|
|
250
|
+
raise typer.Exit(1)
|
|
251
|
+
|
|
252
|
+
service_factory = validate_config_and_get_service_factory()
|
|
253
|
+
logging_service: LoggingService = service_factory.get_logging_service()
|
|
254
|
+
|
|
255
|
+
if logs_number is None:
|
|
256
|
+
logging_service.stream_task_logs_with_controls(task_id=task_id)
|
|
257
|
+
else:
|
|
258
|
+
logging_service.print_last_task_logs(task_id=task_id, logs_number=logs_number)
|
|
259
|
+
|
|
260
|
+
app_logger.info(f'Task logs - end')
|
|
261
|
+
raise typer.Exit(0)
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
@app.command(name='checkout', no_args_is_help=True, help=__("Checkout project repository to a specific reference"), **get_command_metadata(CliCommand.PROJECT_CHECKOUT))
|
|
265
|
+
def checkout_project(
|
|
266
|
+
reference: Optional[str] = typer.Argument(
|
|
267
|
+
help=__("Task ID or branch name to checkout. '/' will try to identify the main branch."),
|
|
268
|
+
),
|
|
269
|
+
working_directory: Optional[str] = typer.Option(
|
|
270
|
+
None,
|
|
271
|
+
"--working-directory",
|
|
272
|
+
"-wd",
|
|
273
|
+
help=__("Full path to working directory"),
|
|
274
|
+
is_eager=False,
|
|
275
|
+
),
|
|
276
|
+
):
|
|
277
|
+
command_name = CliCommand.PROJECT_CHECKOUT
|
|
278
|
+
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
279
|
+
check_command_permission(command_name)
|
|
280
|
+
|
|
281
|
+
service_factory = validate_config_and_get_service_factory(working_directory=working_directory)
|
|
282
|
+
project_service = service_factory.get_project_service()
|
|
283
|
+
|
|
284
|
+
task_id: Optional[int] = None
|
|
285
|
+
branch_name: Optional[str] = None
|
|
286
|
+
|
|
287
|
+
if reference == "/":
|
|
288
|
+
pass
|
|
289
|
+
elif reference.isdigit():
|
|
290
|
+
task_id = int(reference)
|
|
291
|
+
else:
|
|
292
|
+
branch_name = reference
|
|
293
|
+
|
|
294
|
+
project_service.checkout_project(
|
|
295
|
+
task_id=task_id,
|
|
296
|
+
branch_name=branch_name,
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
raise typer.Exit(0)
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
@app.command(name='pull', help=__("Pulls the changes from the remote project repository. Equivalent to 'git pull'."), **get_command_metadata(CliCommand.PROJECT_PULL))
|
|
303
|
+
def pull_project(
|
|
304
|
+
working_directory: Optional[str] = typer.Option(
|
|
305
|
+
None,
|
|
306
|
+
"--working-directory",
|
|
307
|
+
"-wd",
|
|
308
|
+
help=__("Full path to working directory"),
|
|
309
|
+
is_eager=False,
|
|
310
|
+
),
|
|
311
|
+
):
|
|
312
|
+
command_name = CliCommand.PROJECT_PULL
|
|
313
|
+
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
314
|
+
check_command_permission(command_name)
|
|
315
|
+
|
|
316
|
+
service_factory = validate_config_and_get_service_factory(working_directory=working_directory)
|
|
317
|
+
project_service = service_factory.get_project_service()
|
|
318
|
+
|
|
319
|
+
project_service.pull_project()
|
|
320
|
+
|
|
321
|
+
raise typer.Exit(0)
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
@app.command(name='reset', help=__("Resets the current project branch to remote counterpart. All working tree changes will be lost. Equivalent to 'git fetch && git reset --hard origin/{ref}'."), **get_command_metadata(CliCommand.PROJECT_RESET))
|
|
325
|
+
def reset_project(
|
|
326
|
+
working_directory: Optional[str] = typer.Option(
|
|
327
|
+
None,
|
|
328
|
+
"--working-directory",
|
|
329
|
+
"-wd",
|
|
330
|
+
help=__("Full path to working directory"),
|
|
331
|
+
is_eager=False,
|
|
332
|
+
),
|
|
333
|
+
):
|
|
334
|
+
command_name = CliCommand.PROJECT_RESET
|
|
335
|
+
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
336
|
+
check_command_permission(command_name)
|
|
337
|
+
|
|
338
|
+
service_factory = validate_config_and_get_service_factory(working_directory=working_directory)
|
|
339
|
+
project_service = service_factory.get_project_service()
|
|
340
|
+
|
|
341
|
+
project_service.reset_project()
|
|
342
|
+
|
|
343
|
+
raise typer.Exit(0)
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
@config_app.command(name='set-default-container', no_args_is_help=True, help=__("Set default docker container for a project installation"), **get_command_metadata(CliCommand.PROJECT_CONFIG_SET_DEFAULT_CONTAINER))
|
|
347
|
+
def set_default_container(
|
|
348
|
+
container_uid: Annotated[Optional[str], typer.Argument(
|
|
349
|
+
help=__("Unique ID of the container to use by default for running tasks"),
|
|
350
|
+
)] = None,
|
|
351
|
+
unset_default_container: Optional[bool] = typer.Option(
|
|
352
|
+
False,
|
|
353
|
+
"--unset",
|
|
354
|
+
"-u",
|
|
355
|
+
help=__("Unsets the default docker container"),
|
|
356
|
+
is_eager=False,
|
|
357
|
+
),
|
|
358
|
+
working_directory: Optional[str] = typer.Option(
|
|
359
|
+
None,
|
|
360
|
+
"--working-directory",
|
|
361
|
+
"-wd",
|
|
362
|
+
help=__("Full path to working directory"),
|
|
363
|
+
is_eager=False,
|
|
364
|
+
),
|
|
365
|
+
):
|
|
366
|
+
command_name = CliCommand.PROJECT_CONFIG_SET_DEFAULT_CONTAINER
|
|
367
|
+
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
368
|
+
check_command_permission(command_name)
|
|
369
|
+
|
|
370
|
+
service_factory = validate_config_and_get_service_factory(working_directory=working_directory)
|
|
371
|
+
|
|
372
|
+
if unset_default_container and container_uid:
|
|
373
|
+
typer.echo("Container unique ID is provided along with unset flag. Please pick one.")
|
|
374
|
+
raise typer.Exit(1)
|
|
375
|
+
|
|
376
|
+
if not unset_default_container and not container_uid:
|
|
377
|
+
typer.echo("Provide container unique ID or use '--unset' flag")
|
|
378
|
+
raise typer.Exit(1)
|
|
379
|
+
|
|
380
|
+
project_service = service_factory.get_project_service()
|
|
381
|
+
|
|
382
|
+
project_service.set_default_container(
|
|
383
|
+
container_uid=container_uid,
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
raise typer.Exit(0)
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
@config_app.command(name='get', no_args_is_help=False, help=__("View config for a local project installation"), **get_command_metadata(CliCommand.PROJECT_CONFIG_GET))
|
|
390
|
+
def get_project_config(
|
|
391
|
+
working_directory: Optional[str] = typer.Option(
|
|
392
|
+
None,
|
|
393
|
+
"--working-directory",
|
|
394
|
+
"-wd",
|
|
395
|
+
help=__("Full path to working directory"),
|
|
396
|
+
is_eager=False,
|
|
397
|
+
),
|
|
398
|
+
):
|
|
399
|
+
command_name = CliCommand.PROJECT_CONFIG_GET
|
|
400
|
+
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
401
|
+
check_command_permission(command_name)
|
|
402
|
+
|
|
403
|
+
service_factory = validate_config_and_get_service_factory(working_directory=working_directory)
|
|
404
|
+
project_service = service_factory.get_project_service()
|
|
405
|
+
|
|
406
|
+
project_service.print_project_config()
|
|
407
|
+
|
|
408
|
+
raise typer.Exit(0)
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
@inference_simulators_app.command(name='run', no_args_is_help=True, help="Run an inference simulator within the project", **get_command_metadata(CliCommand.PROJECT_INFERENCE_SIMULATOR_RUN))
|
|
412
|
+
def run_inference_simulator(
|
|
413
|
+
rented_instance_unique_id: Optional[str] = typer.Option(
|
|
414
|
+
None,
|
|
415
|
+
'--rented-instance-unique-id',
|
|
416
|
+
'-ruid',
|
|
417
|
+
help=__("The rented instance unique ID on which the inference simulator will run"),
|
|
418
|
+
is_eager=False,
|
|
419
|
+
),
|
|
420
|
+
self_hosted_instance_unique_id: Optional[str] = typer.Option(
|
|
421
|
+
None,
|
|
422
|
+
'--self-hosted-instance-unique-id',
|
|
423
|
+
'-suid',
|
|
424
|
+
help=__("The self-hosted instance unique ID on which the inference simulator will run"),
|
|
425
|
+
is_eager=False,
|
|
426
|
+
),
|
|
427
|
+
commit_hash: Optional[str] = typer.Option(
|
|
428
|
+
None,
|
|
429
|
+
'--commit-hash',
|
|
430
|
+
'-hash',
|
|
431
|
+
help=__("Commit hash to use. By default, the current HEAD commit is used."),
|
|
432
|
+
is_eager=False,
|
|
433
|
+
),
|
|
434
|
+
working_directory: Optional[str] = typer.Option(
|
|
435
|
+
None,
|
|
436
|
+
"--working-directory",
|
|
437
|
+
"-wd",
|
|
438
|
+
help=__("Full path to working directory. By default, the current directory is used"),
|
|
439
|
+
show_default=False,
|
|
440
|
+
is_eager=False,
|
|
441
|
+
),
|
|
442
|
+
enable_log_stream: Optional[bool] = typer.Option(
|
|
443
|
+
True,
|
|
444
|
+
" /--no-logs",
|
|
445
|
+
" /-nl",
|
|
446
|
+
help=__("Disable real-time log streaming"),
|
|
447
|
+
is_eager=False,
|
|
448
|
+
),
|
|
449
|
+
is_skip_installation: Optional[bool] = typer.Option(
|
|
450
|
+
False,
|
|
451
|
+
"--skip-installation",
|
|
452
|
+
"-si",
|
|
453
|
+
help=__("Skip installing dependencies from requirements.txt and install.sh"),
|
|
454
|
+
is_eager=False,
|
|
455
|
+
),
|
|
456
|
+
files_to_add: Optional[str] = typer.Option(
|
|
457
|
+
None,
|
|
458
|
+
"--files-add",
|
|
459
|
+
"-fa",
|
|
460
|
+
help=__("Files to add to the commit. You can add files by their relative path from the working directory with a comma as a separator."),
|
|
461
|
+
is_eager=False,
|
|
462
|
+
),
|
|
463
|
+
is_skip_auto_commit: Optional[bool] = typer.Option(
|
|
464
|
+
False,
|
|
465
|
+
"--skip-autocommit",
|
|
466
|
+
"-sa",
|
|
467
|
+
help=__("Skip automatic commit of the changes"),
|
|
468
|
+
is_eager=False,
|
|
469
|
+
),
|
|
470
|
+
):
|
|
471
|
+
command_name = CliCommand.PROJECT_INFERENCE_SIMULATOR_RUN
|
|
472
|
+
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
473
|
+
check_command_permission(command_name)
|
|
474
|
+
|
|
475
|
+
service_factory = validate_config_and_get_service_factory(working_directory=working_directory)
|
|
476
|
+
config = service_factory.get_config_provider().get_config()
|
|
477
|
+
|
|
478
|
+
working_dir_path = Path(working_directory) if working_directory else Path(config.runtime.working_directory)
|
|
479
|
+
inference_files = list(working_dir_path.rglob("inference.py"))
|
|
480
|
+
if not inference_files:
|
|
481
|
+
typer.echo("No inference.py file found in the project directory.")
|
|
482
|
+
raise typer.Exit(1)
|
|
483
|
+
elif len(inference_files) == 1:
|
|
484
|
+
selected_inference = inference_files[0]
|
|
485
|
+
else:
|
|
486
|
+
choices = [str(path.relative_to(working_dir_path)) for path in inference_files]
|
|
487
|
+
typer.echo("Multiple inference.py files found:")
|
|
488
|
+
for idx, choice in enumerate(choices, start=1):
|
|
489
|
+
typer.echo(f"{idx}) {choice}")
|
|
490
|
+
choice_str = typer.prompt("Choose which inference.py to use")
|
|
491
|
+
try:
|
|
492
|
+
choice_index = int(choice_str)
|
|
493
|
+
except ValueError:
|
|
494
|
+
raise typer.BadParameter("Invalid input. Please enter a number.")
|
|
495
|
+
if not (1 <= choice_index <= len(choices)):
|
|
496
|
+
raise typer.BadParameter("Choice out of range.")
|
|
497
|
+
selected_inference = inference_files[choice_index - 1]
|
|
498
|
+
|
|
499
|
+
relative_inference = selected_inference.relative_to(working_dir_path)
|
|
500
|
+
parent_dir = relative_inference.parent
|
|
501
|
+
if parent_dir == Path("."):
|
|
502
|
+
inference_dir = "/"
|
|
503
|
+
else:
|
|
504
|
+
inference_dir = f"{parent_dir.as_posix()}/"
|
|
505
|
+
typer.echo(f"Selected inference file relative path: {inference_dir}")
|
|
506
|
+
|
|
507
|
+
project_service = service_factory.get_project_service()
|
|
508
|
+
|
|
509
|
+
inference_simulator = project_service.project_run_inference_simulator(
|
|
510
|
+
commit_hash=commit_hash,
|
|
511
|
+
rented_instance_unique_id=rented_instance_unique_id,
|
|
512
|
+
self_hosted_instance_unique_id=self_hosted_instance_unique_id,
|
|
513
|
+
inference_dir=inference_dir,
|
|
514
|
+
is_skip_installation=is_skip_installation,
|
|
515
|
+
files_to_add=files_to_add,
|
|
516
|
+
is_skip_auto_commit=is_skip_auto_commit,
|
|
517
|
+
)
|
|
518
|
+
|
|
519
|
+
if enable_log_stream:
|
|
520
|
+
logging_service: LoggingService = service_factory.get_logging_service()
|
|
521
|
+
|
|
522
|
+
logging_service.stream_inference_simulator_logs_with_controls(
|
|
523
|
+
slug=inference_simulator.slug
|
|
524
|
+
)
|
|
525
|
+
raise typer.Exit(0)
|
|
526
|
+
|
|
527
|
+
|
|
528
|
+
@inference_simulators_app.command(name='save-metadata', no_args_is_help=True, help="Get and save inference simulator metadata", **get_command_metadata(CliCommand.PROJECT_INFERENCE_SIMULATOR_SAVE_METADATA))
|
|
529
|
+
def get_and_save_inference_simulator_metadata(
|
|
530
|
+
unique_id: Optional[str] = typer.Argument(help=__("Inference simulator unique ID"),),
|
|
531
|
+
file_path: Optional[str] = typer.Option(
|
|
532
|
+
None,
|
|
533
|
+
"--file-path",
|
|
534
|
+
"-fp",
|
|
535
|
+
help=__("Full path to a new file. By default metadata is saved to the current directory as metadata.json"),
|
|
536
|
+
show_default=False,
|
|
537
|
+
is_eager=False,
|
|
538
|
+
),
|
|
539
|
+
):
|
|
540
|
+
command_name = CliCommand.PROJECT_INFERENCE_SIMULATOR_SAVE_METADATA
|
|
541
|
+
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
542
|
+
check_command_permission(command_name)
|
|
543
|
+
|
|
544
|
+
service_factory = validate_config_and_get_service_factory()
|
|
545
|
+
project_service = service_factory.get_project_service()
|
|
546
|
+
|
|
547
|
+
project_service.project_get_and_save_inference_simulator_metadata(
|
|
548
|
+
file_path=file_path,
|
|
549
|
+
slug=unique_id,
|
|
550
|
+
)
|
|
551
|
+
|
|
552
|
+
raise typer.Exit(0)
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
@inference_simulators_app.command(name='push', no_args_is_help=True, help="Push an inference simulator within the project to model registry", **get_command_metadata(CliCommand.PROJECT_INFERENCE_SIMULATOR_PUSH))
|
|
556
|
+
def push_inference_simulator(
|
|
557
|
+
unique_id: Optional[str] = typer.Argument(help=__("Inference simulator unique ID"),),
|
|
558
|
+
):
|
|
559
|
+
command_name = CliCommand.PROJECT_INFERENCE_SIMULATOR_PUSH
|
|
560
|
+
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
561
|
+
check_command_permission(command_name)
|
|
562
|
+
|
|
563
|
+
service_factory = validate_config_and_get_service_factory()
|
|
564
|
+
project_service = service_factory.get_project_service()
|
|
565
|
+
|
|
566
|
+
project_service.project_push_inference_simulator(
|
|
567
|
+
slug=unique_id,
|
|
568
|
+
)
|
|
569
|
+
|
|
570
|
+
raise typer.Exit(0)
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
@inference_simulators_app.command("ls", help=__("List inference simulators"), **get_command_metadata(CliCommand.PROJECT_INFERENCE_SIMULATOR_LS))
|
|
574
|
+
def list_inference_simulators(
|
|
575
|
+
project_uid: Annotated[str, typer.Argument(help=__("Project unique ID. By default, project info is taken from the current directory"), metavar="OPTIONAL")] = None,
|
|
576
|
+
row: int = typer.Option(
|
|
577
|
+
5,
|
|
578
|
+
'--row',
|
|
579
|
+
'-r',
|
|
580
|
+
help=__("Set number of rows displayed per page"),
|
|
581
|
+
is_eager=False,
|
|
582
|
+
),
|
|
583
|
+
page: int = typer.Option(
|
|
584
|
+
1,
|
|
585
|
+
'--page',
|
|
586
|
+
'-p',
|
|
587
|
+
help=__("Set starting page for displaying output"),
|
|
588
|
+
is_eager=False,
|
|
589
|
+
),
|
|
590
|
+
statuses: List[str] = typer.Option(
|
|
591
|
+
None,
|
|
592
|
+
'--status',
|
|
593
|
+
'-s',
|
|
594
|
+
help=__("Filter by status, use --status all to list all inference simulators"),
|
|
595
|
+
is_eager=False,
|
|
596
|
+
),
|
|
597
|
+
):
|
|
598
|
+
command_name = CliCommand.PROJECT_INFERENCE_SIMULATOR_LS
|
|
599
|
+
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
600
|
+
check_command_permission(command_name)
|
|
601
|
+
|
|
602
|
+
service_factory = validate_config_and_get_service_factory()
|
|
603
|
+
project_service: ProjectService = service_factory.get_project_service()
|
|
604
|
+
|
|
605
|
+
project_service.print_inference_simulator_list(project_uid, statuses, row, page)
|
|
606
|
+
|
|
607
|
+
typer.echo(__("Inference simulators listing complete"))
|
|
608
|
+
raise typer.Exit(0)
|
|
609
|
+
|
|
610
|
+
|
|
611
|
+
@inference_simulator_model_app.command("ls", help=__("List inference simulator models"), **get_command_metadata(CliCommand.PROJECT_MODEL_LS))
|
|
612
|
+
def list_inference_simulator_models(
|
|
613
|
+
project_uid: Annotated[str, typer.Argument(help=__("Project unique ID. By default, project info is taken from the current directory"), metavar="OPTIONAL")] = None,
|
|
614
|
+
row: int = typer.Option(
|
|
615
|
+
5,
|
|
616
|
+
'--row',
|
|
617
|
+
'-r',
|
|
618
|
+
help=__("Set number of rows displayed per page"),
|
|
619
|
+
is_eager=False,
|
|
620
|
+
),
|
|
621
|
+
page: int = typer.Option(
|
|
622
|
+
1,
|
|
623
|
+
'--page',
|
|
624
|
+
'-p',
|
|
625
|
+
help=__("Set starting page for displaying output"),
|
|
626
|
+
is_eager=False,
|
|
627
|
+
),
|
|
628
|
+
statuses: List[str] = typer.Option(
|
|
629
|
+
None,
|
|
630
|
+
'--status',
|
|
631
|
+
'-s',
|
|
632
|
+
help=__("Filter by status, use --status all to list all inference simulator models"),
|
|
633
|
+
is_eager=False,
|
|
634
|
+
),
|
|
635
|
+
):
|
|
636
|
+
command_name = CliCommand.PROJECT_MODEL_LS
|
|
637
|
+
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
638
|
+
check_command_permission(command_name)
|
|
639
|
+
|
|
640
|
+
service_factory = validate_config_and_get_service_factory()
|
|
641
|
+
project_service: ProjectService = service_factory.get_project_service()
|
|
642
|
+
|
|
643
|
+
project_service.print_inference_simulator_model_list(project_uid, statuses, row, page)
|
|
644
|
+
|
|
645
|
+
typer.echo(__("Inference simulator models listing complete"))
|
|
646
|
+
raise typer.Exit(0)
|
|
647
|
+
|
|
648
|
+
|
|
649
|
+
@inference_simulators_app.command(name="logs", no_args_is_help=True, help=__("Stream real-time task logs or view last logs for an inference simulator"), **get_command_metadata(CliCommand.PROJECT_INFERENCE_SIMULATOR_LOGS))
|
|
650
|
+
def inference_simulator_logs(
|
|
651
|
+
unique_id: Optional[str] = typer.Argument(help=__("Inference simulator unique ID"),),
|
|
652
|
+
logs_number: Optional[int] = typer.Option(
|
|
653
|
+
None,
|
|
654
|
+
'--number',
|
|
655
|
+
'-n',
|
|
656
|
+
help=__("Display a number of latest log entries. No real-time stream if provided."),
|
|
657
|
+
is_eager=False,
|
|
658
|
+
),
|
|
659
|
+
):
|
|
660
|
+
command_name = CliCommand.PROJECT_INFERENCE_SIMULATOR_LOGS
|
|
661
|
+
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
662
|
+
check_command_permission(command_name)
|
|
663
|
+
|
|
664
|
+
if not unique_id:
|
|
665
|
+
typer.echo(__('Inference simulator UID is required'))
|
|
666
|
+
raise typer.Exit(1)
|
|
667
|
+
|
|
668
|
+
service_factory = validate_config_and_get_service_factory()
|
|
669
|
+
logging_service: LoggingService = service_factory.get_logging_service()
|
|
670
|
+
|
|
671
|
+
if logs_number is None:
|
|
672
|
+
logging_service.stream_inference_simulator_logs_with_controls(
|
|
673
|
+
slug=unique_id
|
|
674
|
+
)
|
|
675
|
+
else:
|
|
676
|
+
get_inference_simulator_response: Optional[GetInferenceSimulatorResponse] = service_factory.get_thestage_api_client().get_inference_simulator(
|
|
677
|
+
slug=unique_id,
|
|
678
|
+
)
|
|
679
|
+
if not get_inference_simulator_response:
|
|
680
|
+
typer.echo(__("Inference simulator with UID %uid% not found", {"uid": unique_id}))
|
|
681
|
+
raise typer.Exit(1)
|
|
682
|
+
else:
|
|
683
|
+
inference_simulator_id = get_inference_simulator_response.inferenceSimulator.id
|
|
684
|
+
logging_service.print_last_inference_simulator_logs(inference_simulator_id=inference_simulator_id, logs_number=logs_number)
|
|
685
|
+
|
|
686
|
+
app_logger.info(f'Inference simulator logs - end')
|
|
687
|
+
raise typer.Exit(0)
|
|
688
|
+
|
|
689
|
+
|
|
690
|
+
@inference_simulator_model_app.command("deploy-instance", no_args_is_help=True, help=__("Deploy an inference simulator model to an instance"), **get_command_metadata(CliCommand.PROJECT_MODEL_DEPLOY_INSTANCE))
|
|
691
|
+
def deploy_inference_simulator_model_to_instance(
|
|
692
|
+
unique_id: Optional[str] = typer.Argument(help=__("Inference simulator model unique ID"), ),
|
|
693
|
+
rented_instance_unique_id: Optional[str] = typer.Option(
|
|
694
|
+
None,
|
|
695
|
+
'--rented-instance-unique-id',
|
|
696
|
+
'-ruid',
|
|
697
|
+
help=__("The rented instance unique ID on which the inference simulator model will be deployed"),
|
|
698
|
+
is_eager=False,
|
|
699
|
+
),
|
|
700
|
+
self_hosted_instance_unique_id: Optional[str] = typer.Option(
|
|
701
|
+
None,
|
|
702
|
+
'--self-hosted-instance-unique-id',
|
|
703
|
+
'-suid',
|
|
704
|
+
help=__("The self-hosted instance unique ID on which the inference simulator model will be deployed"),
|
|
705
|
+
is_eager=False,
|
|
706
|
+
),
|
|
707
|
+
working_directory: Optional[str] = typer.Option(
|
|
708
|
+
None,
|
|
709
|
+
"--working-directory",
|
|
710
|
+
"-wd",
|
|
711
|
+
help=__("Full path to working directory. By default, the current directory is used"),
|
|
712
|
+
show_default=False,
|
|
713
|
+
is_eager=False,
|
|
714
|
+
),
|
|
715
|
+
enable_log_stream: Optional[bool] = typer.Option(
|
|
716
|
+
True,
|
|
717
|
+
" /--no-logs",
|
|
718
|
+
" /-nl",
|
|
719
|
+
help=__("Disable real-time log streaming"),
|
|
720
|
+
is_eager=False,
|
|
721
|
+
),
|
|
722
|
+
):
|
|
723
|
+
command_name = CliCommand.PROJECT_MODEL_DEPLOY_INSTANCE
|
|
724
|
+
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
725
|
+
check_command_permission(command_name)
|
|
726
|
+
|
|
727
|
+
if unique_id and not re.match(r"^[a-zA-Z0-9-]+$", unique_id):
|
|
728
|
+
raise typer.BadParameter(__("Invalid UID format. The UID can only contain letters, numbers, and hyphens."))
|
|
729
|
+
|
|
730
|
+
unique_id_with_timestamp = f"{unique_id}-{int(time.time())}"
|
|
731
|
+
|
|
732
|
+
service_factory = validate_config_and_get_service_factory(working_directory=working_directory)
|
|
733
|
+
project_service = service_factory.get_project_service()
|
|
734
|
+
|
|
735
|
+
project_service.project_deploy_inference_simulator_model_to_instance(
|
|
736
|
+
unique_id=unique_id,
|
|
737
|
+
unique_id_with_timestamp=unique_id_with_timestamp,
|
|
738
|
+
rented_instance_unique_id=rented_instance_unique_id,
|
|
739
|
+
self_hosted_instance_unique_id=self_hosted_instance_unique_id,
|
|
740
|
+
)
|
|
741
|
+
|
|
742
|
+
if enable_log_stream:
|
|
743
|
+
logging_service: LoggingService = service_factory.get_logging_service()
|
|
744
|
+
|
|
745
|
+
logging_service.stream_inference_simulator_logs_with_controls(
|
|
746
|
+
slug=unique_id_with_timestamp
|
|
747
|
+
)
|
|
748
|
+
raise typer.Exit(0)
|
|
749
|
+
|
|
750
|
+
|
|
751
|
+
@inference_simulator_model_app.command("deploy-sagemaker", no_args_is_help=True, help=__("Deploy an inference simulator model to SageMaker"), **get_command_metadata(CliCommand.PROJECT_MODEL_DEPLOY_SAGEMAKER))
|
|
752
|
+
def deploy_inference_simulator_model_to_sagemaker(
|
|
753
|
+
unique_id: Optional[str] = typer.Argument(help=__("Inference simulator model unique ID"), ),
|
|
754
|
+
arn: Optional[str] = typer.Option(
|
|
755
|
+
None,
|
|
756
|
+
'--amazon-resource-name',
|
|
757
|
+
'-arn',
|
|
758
|
+
help=__("The Amazon Resource Name of the IAM Role to use, e.g., arn:aws:iam::{aws_account_id}:role/{role}"),
|
|
759
|
+
is_eager=False,
|
|
760
|
+
),
|
|
761
|
+
working_directory: Optional[str] = typer.Option(
|
|
762
|
+
None,
|
|
763
|
+
"--working-directory",
|
|
764
|
+
"-wd",
|
|
765
|
+
help=__("Full path to working directory. By default, the current directory is used"),
|
|
766
|
+
show_default=False,
|
|
767
|
+
is_eager=False,
|
|
768
|
+
),
|
|
769
|
+
instance_type: Optional[str] = typer.Option(
|
|
770
|
+
None,
|
|
771
|
+
'--instance-type',
|
|
772
|
+
'-it',
|
|
773
|
+
help=__("Instance type on which the inference simulator model will be deployed"),
|
|
774
|
+
is_eager=False,
|
|
775
|
+
),
|
|
776
|
+
initial_variant_weight: Optional[float] = typer.Option(
|
|
777
|
+
None,
|
|
778
|
+
"--initial-variant-weight",
|
|
779
|
+
"-ivw",
|
|
780
|
+
help=__("Initial Variant Weight. By default 1.0"),
|
|
781
|
+
show_default=False,
|
|
782
|
+
is_eager=False,
|
|
783
|
+
),
|
|
784
|
+
initial_instance_count: Optional[int] = typer.Option(
|
|
785
|
+
None,
|
|
786
|
+
"--initial-instance-count",
|
|
787
|
+
"-iic",
|
|
788
|
+
help=__("Initial Instance Count"),
|
|
789
|
+
show_default=False,
|
|
790
|
+
is_eager=False,
|
|
791
|
+
),
|
|
792
|
+
|
|
793
|
+
):
|
|
794
|
+
command_name = CliCommand.PROJECT_MODEL_DEPLOY_SAGEMAKER
|
|
795
|
+
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
796
|
+
check_command_permission(command_name)
|
|
797
|
+
|
|
798
|
+
if unique_id and not re.match(r"^[a-zA-Z0-9-]+$", unique_id):
|
|
799
|
+
raise typer.BadParameter(__("Invalid UID format. The UID can only contain letters, numbers, and hyphens."))
|
|
800
|
+
|
|
801
|
+
service_factory = validate_config_and_get_service_factory(working_directory=working_directory)
|
|
802
|
+
project_service = service_factory.get_project_service()
|
|
803
|
+
|
|
804
|
+
project_service.project_deploy_inference_simulator_model_to_sagemaker(
|
|
805
|
+
unique_id=unique_id,
|
|
806
|
+
arn=arn,
|
|
807
|
+
instance_type=instance_type,
|
|
808
|
+
initial_variant_weight=initial_variant_weight,
|
|
809
|
+
initial_instance_count=initial_instance_count,
|
|
810
|
+
)
|