qwak-sdk 0.1.0__py3-none-any.whl → 0.2.20rc0__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.
Potentially problematic release.
This version of qwak-sdk might be problematic. Click here for more details.
- qwak_sdk/__init__.py +9 -0
- qwak_sdk/cli.py +51 -0
- qwak_sdk/commands/admin/__init__.py +0 -0
- qwak_sdk/commands/admin/admin_commands_group.py +17 -0
- qwak_sdk/commands/admin/apikeys/__init__.py +0 -0
- qwak_sdk/commands/admin/apikeys/api_keys_commands_group.py +17 -0
- qwak_sdk/commands/admin/apikeys/generate/__init__.py +0 -0
- qwak_sdk/commands/admin/apikeys/generate/_logic.py +21 -0
- qwak_sdk/commands/admin/apikeys/generate/ui.py +45 -0
- qwak_sdk/commands/admin/apikeys/revoke/__init__.py +0 -0
- qwak_sdk/commands/admin/apikeys/revoke/_logic.py +22 -0
- qwak_sdk/commands/admin/apikeys/revoke/ui.py +31 -0
- qwak_sdk/commands/audience/__init__.py +0 -0
- qwak_sdk/commands/audience/_logic/__init__.py +0 -0
- qwak_sdk/commands/audience/_logic/config/__init__.py +0 -0
- qwak_sdk/commands/audience/_logic/config/config_base.py +16 -0
- qwak_sdk/commands/audience/_logic/config/parser.py +28 -0
- qwak_sdk/commands/audience/_logic/config/v1/__init__.py +0 -0
- qwak_sdk/commands/audience/_logic/config/v1/audience_config.py +26 -0
- qwak_sdk/commands/audience/_logic/config/v1/conditions_config.py +60 -0
- qwak_sdk/commands/audience/_logic/config/v1/config_v1.py +24 -0
- qwak_sdk/commands/audience/_logic/config/v1/route_config.py +14 -0
- qwak_sdk/commands/audience/_logic/config/v1/spec.py +11 -0
- qwak_sdk/commands/auto_scalling/__init__.py +0 -0
- qwak_sdk/commands/auto_scalling/_logic/__init__.py +0 -0
- qwak_sdk/commands/auto_scalling/_logic/config/__init__.py +3 -0
- qwak_sdk/commands/auto_scalling/_logic/config/config.py +100 -0
- qwak_sdk/commands/auto_scalling/_logic/config/parser.py +21 -0
- qwak_sdk/commands/auto_scalling/attach/__init__.py +0 -0
- qwak_sdk/commands/auto_scalling/attach/_logic.py +43 -0
- qwak_sdk/commands/auto_scalling/attach/ui.py +21 -0
- qwak_sdk/commands/auto_scalling/autoscaling_commands_group.py +15 -0
- qwak_sdk/commands/automations/__init__.py +0 -0
- qwak_sdk/commands/automations/automations_commands_group.py +30 -0
- qwak_sdk/commands/automations/delete/__init__.py +0 -0
- qwak_sdk/commands/automations/delete/_logic.py +6 -0
- qwak_sdk/commands/automations/delete/ui.py +23 -0
- qwak_sdk/commands/automations/executions/__init__.py +0 -0
- qwak_sdk/commands/automations/executions/executions_commands_group.py +14 -0
- qwak_sdk/commands/automations/executions/list/__init__.py +0 -0
- qwak_sdk/commands/automations/executions/list/_logic.py +8 -0
- qwak_sdk/commands/automations/executions/list/ui.py +25 -0
- qwak_sdk/commands/automations/list/__init__.py +0 -0
- qwak_sdk/commands/automations/list/_logic.py +8 -0
- qwak_sdk/commands/automations/list/ui.py +21 -0
- qwak_sdk/commands/automations/register/__init__.py +0 -0
- qwak_sdk/commands/automations/register/_logic.py +43 -0
- qwak_sdk/commands/automations/register/ui.py +44 -0
- qwak_sdk/commands/feature_store/__init__.py +0 -0
- qwak_sdk/commands/feature_store/delete/__init__.py +0 -0
- qwak_sdk/commands/feature_store/delete/_logic.py +52 -0
- qwak_sdk/commands/feature_store/delete/ui.py +40 -0
- qwak_sdk/commands/feature_store/feature_store_command_group.py +25 -0
- qwak_sdk/commands/feature_store/list/__init__.py +0 -0
- qwak_sdk/commands/feature_store/list/ui.py +140 -0
- qwak_sdk/commands/feature_store/pause/__init__.py +0 -0
- qwak_sdk/commands/feature_store/pause/ui.py +18 -0
- qwak_sdk/commands/feature_store/register/__init__.py +0 -0
- qwak_sdk/commands/feature_store/register/_logic.py +289 -0
- qwak_sdk/commands/feature_store/register/ui.py +105 -0
- qwak_sdk/commands/feature_store/resume/__init__.py +0 -0
- qwak_sdk/commands/feature_store/resume/ui.py +18 -0
- qwak_sdk/commands/feature_store/trigger/__init__.py +0 -0
- qwak_sdk/commands/feature_store/trigger/ui.py +32 -0
- qwak_sdk/commands/models/__init__.py +0 -0
- qwak_sdk/commands/models/_logic/__init__.py +0 -0
- qwak_sdk/commands/models/_logic/variations.py +55 -0
- qwak_sdk/commands/models/build/__init__.py +0 -0
- qwak_sdk/commands/models/build/_logic/__init__.py +0 -0
- qwak_sdk/commands/models/build/_logic/build_steps.py +68 -0
- qwak_sdk/commands/models/build/_logic/client_logs/__init__.py +0 -0
- qwak_sdk/commands/models/build/_logic/client_logs/build_run_handlers.py +189 -0
- qwak_sdk/commands/models/build/_logic/client_logs/cli_ui.py +125 -0
- qwak_sdk/commands/models/build/_logic/client_logs/logger.py +88 -0
- qwak_sdk/commands/models/build/_logic/client_logs/messages.py +40 -0
- qwak_sdk/commands/models/build/_logic/client_logs/notifier_impl.py +49 -0
- qwak_sdk/commands/models/build/_logic/client_logs/spinner.py +14 -0
- qwak_sdk/commands/models/build/_logic/client_logs/time_source.py +37 -0
- qwak_sdk/commands/models/build/_logic/client_logs/utils.py +12 -0
- qwak_sdk/commands/models/build/_logic/config/config_v1.py +253 -0
- qwak_sdk/commands/models/build/_logic/constant/host_resource.py +4 -0
- qwak_sdk/commands/models/build/_logic/constant/step_description.py +29 -0
- qwak_sdk/commands/models/build/_logic/constant/temp_dir.py +2 -0
- qwak_sdk/commands/models/build/_logic/constant/upload_tag.py +5 -0
- qwak_sdk/commands/models/build/_logic/context.py +62 -0
- qwak_sdk/commands/models/build/_logic/interface/__init__.py +0 -0
- qwak_sdk/commands/models/build/_logic/interface/notifier_interface.py +29 -0
- qwak_sdk/commands/models/build/_logic/interface/step_inteface.py +29 -0
- qwak_sdk/commands/models/build/_logic/phase/__init__.py +0 -0
- qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/__init__.py +14 -0
- qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/fetch_model_step/__init__.py +0 -0
- qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/fetch_model_step/fetch_model_step.py +42 -0
- qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/fetch_model_step/fetch_strategy_manager/__init__.py +0 -0
- qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/fetch_model_step/fetch_strategy_manager/common.py +33 -0
- qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/fetch_model_step/fetch_strategy_manager/fetch_strategy_manager.py +60 -0
- qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/fetch_model_step/fetch_strategy_manager/strategy/__init__.py +0 -0
- qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/fetch_model_step/fetch_strategy_manager/strategy/folder/__init__.py +0 -0
- qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/fetch_model_step/fetch_strategy_manager/strategy/folder/folder_strategy.py +73 -0
- qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/fetch_model_step/fetch_strategy_manager/strategy/git/__init__.py +0 -0
- qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/fetch_model_step/fetch_strategy_manager/strategy/git/git_strategy.py +149 -0
- qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/fetch_model_step/fetch_strategy_manager/strategy/strategy.py +69 -0
- qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/fetch_model_step/fetch_strategy_manager/strategy/zip/__init__.py +0 -0
- qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/fetch_model_step/fetch_strategy_manager/strategy/zip/zip_strategy.py +64 -0
- qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/post_fetch_validation_step.py +117 -0
- qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/pre_fetch_validation_step.py +135 -0
- qwak_sdk/commands/models/build/_logic/phase/b_remote_register_qwak_build/__init__.py +11 -0
- qwak_sdk/commands/models/build/_logic/phase/b_remote_register_qwak_build/cleanup_step.py +20 -0
- qwak_sdk/commands/models/build/_logic/phase/b_remote_register_qwak_build/start_remote_build_step.py +42 -0
- qwak_sdk/commands/models/build/_logic/phase/b_remote_register_qwak_build/upload_step.py +349 -0
- qwak_sdk/commands/models/build/_logic/phase/c_deploy/__init__.py +6 -0
- qwak_sdk/commands/models/build/_logic/phase/c_deploy/build_polling_status.py +54 -0
- qwak_sdk/commands/models/build/_logic/phase/c_deploy/deploy_build.py +44 -0
- qwak_sdk/commands/models/build/_logic/util/__init__.py +0 -0
- qwak_sdk/commands/models/build/_logic/util/protobuf_factory.py +45 -0
- qwak_sdk/commands/models/build/_logic/util/step_decorator.py +37 -0
- qwak_sdk/commands/models/build/_logic/util/text.py +9 -0
- qwak_sdk/commands/models/build/ui.py +241 -0
- qwak_sdk/commands/models/builds/__init__.py +0 -0
- qwak_sdk/commands/models/builds/builds_commands_group.py +16 -0
- qwak_sdk/commands/models/builds/cancel/__init__.py +0 -0
- qwak_sdk/commands/models/builds/cancel/_logic.py +5 -0
- qwak_sdk/commands/models/builds/cancel/ui.py +15 -0
- qwak_sdk/commands/models/builds/logs/__init__.py +0 -0
- qwak_sdk/commands/models/builds/logs/ui.py +35 -0
- qwak_sdk/commands/models/builds/status/__init__.py +0 -0
- qwak_sdk/commands/models/builds/status/_logic.py +6 -0
- qwak_sdk/commands/models/builds/status/ui.py +30 -0
- qwak_sdk/commands/models/create/__init__.py +0 -0
- qwak_sdk/commands/models/create/_logic.py +35 -0
- qwak_sdk/commands/models/create/ui.py +27 -0
- qwak_sdk/commands/models/delete/__init__.py +0 -0
- qwak_sdk/commands/models/delete/_logic.py +5 -0
- qwak_sdk/commands/models/delete/ui.py +16 -0
- qwak_sdk/commands/models/deployments/__init__.py +0 -0
- qwak_sdk/commands/models/deployments/deploy/__init__.py +0 -0
- qwak_sdk/commands/models/deployments/deploy/_logic/__init__.py +0 -0
- qwak_sdk/commands/models/deployments/deploy/_logic/advance_deployment_options_handler.py +31 -0
- qwak_sdk/commands/models/deployments/deploy/_logic/base_deploy_executor.py +64 -0
- qwak_sdk/commands/models/deployments/deploy/_logic/deploy_config.py +241 -0
- qwak_sdk/commands/models/deployments/deploy/_logic/deployment.py +405 -0
- qwak_sdk/commands/models/deployments/deploy/_logic/deployment_message_helpers.py +98 -0
- qwak_sdk/commands/models/deployments/deploy/_logic/deployment_response_handler.py +154 -0
- qwak_sdk/commands/models/deployments/deploy/_logic/deployment_size_mapper.py +21 -0
- qwak_sdk/commands/models/deployments/deploy/_logic/get_latest_successful_build.py +31 -0
- qwak_sdk/commands/models/deployments/deploy/_logic/variations.py +79 -0
- qwak_sdk/commands/models/deployments/deploy/batch/__init__.py +0 -0
- qwak_sdk/commands/models/deployments/deploy/batch/_logic/__init__.py +0 -0
- qwak_sdk/commands/models/deployments/deploy/batch/_logic/advanced_deployment_mapper.py +14 -0
- qwak_sdk/commands/models/deployments/deploy/batch/_logic/deploy_executor.py +24 -0
- qwak_sdk/commands/models/deployments/deploy/batch/ui.py +104 -0
- qwak_sdk/commands/models/deployments/deploy/deploy_commands_group.py +19 -0
- qwak_sdk/commands/models/deployments/deploy/realtime/__init__.py +0 -0
- qwak_sdk/commands/models/deployments/deploy/realtime/_logic/__init__.py +0 -0
- qwak_sdk/commands/models/deployments/deploy/realtime/_logic/advanced_deployment_mapper.py +20 -0
- qwak_sdk/commands/models/deployments/deploy/realtime/_logic/deploy_executor.py +24 -0
- qwak_sdk/commands/models/deployments/deploy/realtime/_logic/serving_strategy_mapper.py +105 -0
- qwak_sdk/commands/models/deployments/deploy/realtime/ui.py +179 -0
- qwak_sdk/commands/models/deployments/deploy/streaming/__init__.py +0 -0
- qwak_sdk/commands/models/deployments/deploy/streaming/_logic/__init__.py +0 -0
- qwak_sdk/commands/models/deployments/deploy/streaming/_logic/deploy_executor.py +24 -0
- qwak_sdk/commands/models/deployments/deploy/streaming/_logic/serving_strategy_mapper.py +38 -0
- qwak_sdk/commands/models/deployments/deploy/streaming/ui.py +196 -0
- qwak_sdk/commands/models/deployments/undeploy/__init__.py +0 -0
- qwak_sdk/commands/models/deployments/undeploy/_logic/__init__.py +0 -0
- qwak_sdk/commands/models/deployments/undeploy/_logic/request_undeploy.py +176 -0
- qwak_sdk/commands/models/deployments/undeploy/_logic/variations.py +74 -0
- qwak_sdk/commands/models/deployments/undeploy/ui.py +78 -0
- qwak_sdk/commands/models/executions/__init__.py +0 -0
- qwak_sdk/commands/models/executions/cancel/__init__.py +0 -0
- qwak_sdk/commands/models/executions/cancel/_logic.py +9 -0
- qwak_sdk/commands/models/executions/cancel/ui.py +27 -0
- qwak_sdk/commands/models/executions/execution_commands_group.py +24 -0
- qwak_sdk/commands/models/executions/report/__init__.py +0 -0
- qwak_sdk/commands/models/executions/report/_logic.py +14 -0
- qwak_sdk/commands/models/executions/report/ui.py +43 -0
- qwak_sdk/commands/models/executions/start/__init__.py +0 -0
- qwak_sdk/commands/models/executions/start/_logic.py +16 -0
- qwak_sdk/commands/models/executions/start/ui.py +176 -0
- qwak_sdk/commands/models/executions/status/__init__.py +0 -0
- qwak_sdk/commands/models/executions/status/_logic.py +13 -0
- qwak_sdk/commands/models/executions/status/ui.py +27 -0
- qwak_sdk/commands/models/init/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/initialize_model_structure.py +40 -0
- qwak_sdk/commands/models/init/_logic/template/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/churn/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/churn/cookiecutter.json +3 -0
- qwak_sdk/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/main/__init__.py +5 -0
- qwak_sdk/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/main/conda.yml +10 -0
- qwak_sdk/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/main/data.csv +1001 -0
- qwak_sdk/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/main/model.py +95 -0
- qwak_sdk/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/tests/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/tests/it/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/tests/it/test_churn.py +32 -0
- qwak_sdk/commands/models/init/_logic/template/credit_risk/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/credit_risk/cookiecutter.json +3 -0
- qwak_sdk/commands/models/init/_logic/template/credit_risk/{{cookiecutter.model_directory}}/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/credit_risk/{{cookiecutter.model_directory}}/main/__init__.py +5 -0
- qwak_sdk/commands/models/init/_logic/template/credit_risk/{{cookiecutter.model_directory}}/main/conda.yml +10 -0
- qwak_sdk/commands/models/init/_logic/template/credit_risk/{{cookiecutter.model_directory}}/main/data.csv +1001 -0
- qwak_sdk/commands/models/init/_logic/template/credit_risk/{{cookiecutter.model_directory}}/main/model.py +108 -0
- qwak_sdk/commands/models/init/_logic/template/general/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/general/cookiecutter.json +6 -0
- qwak_sdk/commands/models/init/_logic/template/general/{{cookiecutter.model_directory}}/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/general/{{cookiecutter.model_directory}}/{{cookiecutter.main_directory}}/__init__.py +5 -0
- qwak_sdk/commands/models/init/_logic/template/general/{{cookiecutter.model_directory}}/{{cookiecutter.main_directory}}/conda.yml +8 -0
- qwak_sdk/commands/models/init/_logic/template/general/{{cookiecutter.model_directory}}/{{cookiecutter.main_directory}}/model.py +66 -0
- qwak_sdk/commands/models/init/_logic/template/general/{{cookiecutter.model_directory}}/{{cookiecutter.test_directory}}/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/general/{{cookiecutter.model_directory}}/{{cookiecutter.test_directory}}/test_qwak_model.py +5 -0
- qwak_sdk/commands/models/init/_logic/template/titanic/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/titanic/cookiecutter.json +3 -0
- qwak_sdk/commands/models/init/_logic/template/titanic/{{cookiecutter.model_directory}}/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/titanic/{{cookiecutter.model_directory}}/main/__init__.py +5 -0
- qwak_sdk/commands/models/init/_logic/template/titanic/{{cookiecutter.model_directory}}/main/conda.yml +10 -0
- qwak_sdk/commands/models/init/_logic/template/titanic/{{cookiecutter.model_directory}}/main/model.py +98 -0
- qwak_sdk/commands/models/init/_logic/template/titanic/{{cookiecutter.model_directory}}/tests/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/titanic/{{cookiecutter.model_directory}}/tests/it/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/titanic/{{cookiecutter.model_directory}}/tests/it/test_titanic.py +24 -0
- qwak_sdk/commands/models/init/_logic/template/titanic_poetry/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/titanic_poetry/cookiecutter.json +3 -0
- qwak_sdk/commands/models/init/_logic/template/titanic_poetry/{{cookiecutter.model_directory}}/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/titanic_poetry/{{cookiecutter.model_directory}}/main/__init__.py +5 -0
- qwak_sdk/commands/models/init/_logic/template/titanic_poetry/{{cookiecutter.model_directory}}/main/model.py +98 -0
- qwak_sdk/commands/models/init/_logic/template/titanic_poetry/{{cookiecutter.model_directory}}/main/pyproject.toml +18 -0
- qwak_sdk/commands/models/init/_logic/template/titanic_poetry/{{cookiecutter.model_directory}}/tests/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/titanic_poetry/{{cookiecutter.model_directory}}/tests/it/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/titanic_poetry/{{cookiecutter.model_directory}}/tests/it/test_titanic.py +25 -0
- qwak_sdk/commands/models/init/ui.py +61 -0
- qwak_sdk/commands/models/list/__init__.py +0 -0
- qwak_sdk/commands/models/list/_logic.py +5 -0
- qwak_sdk/commands/models/list/ui.py +31 -0
- qwak_sdk/commands/models/models_command_group.py +36 -0
- qwak_sdk/commands/models/runtime/__init__.py +0 -0
- qwak_sdk/commands/models/runtime/feedback/__init__.py +0 -0
- qwak_sdk/commands/models/runtime/feedback/_logic.py +81 -0
- qwak_sdk/commands/models/runtime/feedback/ui.py +45 -0
- qwak_sdk/commands/models/runtime/logs/__init__.py +0 -0
- qwak_sdk/commands/models/runtime/logs/ui.py +63 -0
- qwak_sdk/commands/models/runtime/runtime_commands_group.py +21 -0
- qwak_sdk/commands/models/runtime/traffic_update/__init__.py +0 -0
- qwak_sdk/commands/models/runtime/traffic_update/_logic/__init__.py +0 -0
- qwak_sdk/commands/models/runtime/traffic_update/_logic/execute_runtime_update_traffic.py +54 -0
- qwak_sdk/commands/models/runtime/traffic_update/_logic/variations.py +84 -0
- qwak_sdk/commands/models/runtime/traffic_update/ui.py +37 -0
- qwak_sdk/commands/models/runtime/update/__init__.py +0 -0
- qwak_sdk/commands/models/runtime/update/_logic.py +9 -0
- qwak_sdk/commands/models/runtime/update/ui.py +15 -0
- qwak_sdk/commands/projects/__init__.py +0 -0
- qwak_sdk/commands/projects/create/__init__.py +0 -0
- qwak_sdk/commands/projects/create/_logic.py +6 -0
- qwak_sdk/commands/projects/create/ui.py +21 -0
- qwak_sdk/commands/projects/delete/__init__.py +0 -0
- qwak_sdk/commands/projects/delete/_logic.py +6 -0
- qwak_sdk/commands/projects/delete/ui.py +15 -0
- qwak_sdk/commands/projects/list/__init__.py +0 -0
- qwak_sdk/commands/projects/list/_logic.py +6 -0
- qwak_sdk/commands/projects/list/ui.py +36 -0
- qwak_sdk/commands/projects/projects_command_group.py +19 -0
- qwak_sdk/commands/secrets/__init__.py +0 -0
- qwak_sdk/commands/secrets/delete/__init__.py +0 -0
- qwak_sdk/commands/secrets/delete/_logic.py +5 -0
- qwak_sdk/commands/secrets/delete/ui.py +21 -0
- qwak_sdk/commands/secrets/get/__init__.py +0 -0
- qwak_sdk/commands/secrets/get/_logic.py +5 -0
- qwak_sdk/commands/secrets/get/ui.py +17 -0
- qwak_sdk/commands/secrets/secrets_commands_group.py +19 -0
- qwak_sdk/commands/secrets/set/__init__.py +0 -0
- qwak_sdk/commands/secrets/set/_logic.py +5 -0
- qwak_sdk/commands/secrets/set/ui.py +16 -0
- qwak_sdk/commands/ui_tools.py +18 -0
- qwak_sdk/common/__init__.py +0 -0
- qwak_sdk/common/run_config/__init__.py +22 -0
- qwak_sdk/common/run_config/base.py +101 -0
- qwak_sdk/common/run_config/utils.py +249 -0
- qwak_sdk/exceptions/__init__.py +11 -0
- qwak_sdk/exceptions/qwak_command_exception.py +2 -0
- qwak_sdk/exceptions/qwak_deploy_new_build_failed.py +5 -0
- qwak_sdk/exceptions/qwak_general_build_exception.py +13 -0
- qwak_sdk/exceptions/qwak_remote_build_failed.py +5 -0
- qwak_sdk/exceptions/qwak_resource_not_found.py +2 -0
- qwak_sdk/exceptions/qwak_suggestion_exception.py +27 -0
- qwak_sdk/inner/__init__.py +0 -0
- qwak_sdk/inner/file_registry.py +97 -0
- qwak_sdk/inner/tools/__init__.py +0 -0
- qwak_sdk/inner/tools/cli_tools.py +159 -0
- qwak_sdk/inner/tools/config_handler.py +18 -0
- qwak_sdk/inner/tools/logger/__init__.py +3 -0
- qwak_sdk/inner/tools/logger/logger.py +269 -0
- qwak_sdk/inner/tools/logger/logging.yml +79 -0
- qwak_sdk/inner/tools/tracking.py +47 -0
- qwak_sdk/main.py +9 -0
- qwak_sdk/tools/__init__.py +0 -0
- qwak_sdk/tools/colors.py +13 -0
- qwak_sdk/tools/files.py +9 -0
- qwak_sdk/tools/log_handling.py +146 -0
- qwak_sdk/tools/utils.py +46 -0
- qwak_sdk-0.2.20rc0.dist-info/METADATA +42 -0
- qwak_sdk-0.2.20rc0.dist-info/RECORD +302 -0
- {qwak_sdk-0.1.0.dist-info → qwak_sdk-0.2.20rc0.dist-info}/WHEEL +1 -2
- qwak_sdk-0.2.20rc0.dist-info/entry_points.txt +3 -0
- qwak_sdk-0.1.0.dist-info/METADATA +0 -19
- qwak_sdk-0.1.0.dist-info/RECORD +0 -5
- qwak_sdk-0.1.0.dist-info/top_level.txt +0 -1
- {qwak-sdk → qwak_sdk/commands}/__init__.py +0 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import shutil
|
|
4
|
+
import tempfile
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import TYPE_CHECKING, Optional, Union
|
|
7
|
+
|
|
8
|
+
from qwak.exceptions import QwakException
|
|
9
|
+
|
|
10
|
+
from qwak_sdk.exceptions import QwakSuggestionException
|
|
11
|
+
from qwak_sdk.tools.files import copytree
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from qwak_sdk.commands.models.build import Notifier
|
|
15
|
+
|
|
16
|
+
try:
|
|
17
|
+
from git import Repo
|
|
18
|
+
from git.exc import GitError
|
|
19
|
+
except ImportError:
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
from ..strategy import Strategy, get_ignore_pattern
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class GitStrategy(Strategy):
|
|
27
|
+
def fetch(
|
|
28
|
+
self,
|
|
29
|
+
src: Union[str, Path],
|
|
30
|
+
dest: str,
|
|
31
|
+
git_branch: str,
|
|
32
|
+
git_credentials: str,
|
|
33
|
+
custom_dependencies_path: str,
|
|
34
|
+
main_dir: str,
|
|
35
|
+
**kwargs,
|
|
36
|
+
) -> str:
|
|
37
|
+
self.notifier.debug(f"Fetching Model code from git repository - {src}")
|
|
38
|
+
with tempfile.TemporaryDirectory() as clone_dest:
|
|
39
|
+
git_url, git_subdirectory = split_git_url_and_subdirectory(uri=src)
|
|
40
|
+
self.notifier.debug(
|
|
41
|
+
f"Fetching model code from git {git_url}, Model located in {git_subdirectory}"
|
|
42
|
+
)
|
|
43
|
+
git_commit_id = self.clone_and_checkout_repo(
|
|
44
|
+
clone_dest=clone_dest,
|
|
45
|
+
git_url=git_url,
|
|
46
|
+
git_branch=git_branch,
|
|
47
|
+
git_credentials=git_credentials,
|
|
48
|
+
)
|
|
49
|
+
self.copy_model(
|
|
50
|
+
clone_dest=clone_dest,
|
|
51
|
+
git_subdirectory=git_subdirectory,
|
|
52
|
+
model_dest=dest,
|
|
53
|
+
custom_dependencies_path=custom_dependencies_path,
|
|
54
|
+
main_dir=main_dir,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
return git_commit_id
|
|
58
|
+
|
|
59
|
+
def clone_and_checkout_repo(
|
|
60
|
+
self,
|
|
61
|
+
clone_dest: str,
|
|
62
|
+
git_url: str,
|
|
63
|
+
git_branch: str,
|
|
64
|
+
git_credentials: str,
|
|
65
|
+
) -> str:
|
|
66
|
+
git_remote_url = get_git_remote_uri(
|
|
67
|
+
self.notifier,
|
|
68
|
+
url=git_url,
|
|
69
|
+
git_credentials=git_credentials,
|
|
70
|
+
)
|
|
71
|
+
git_commit_id = clone_and_checkout_repo(
|
|
72
|
+
git_repo_url=git_remote_url, to_path=clone_dest, git_branch=git_branch
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
return git_commit_id
|
|
76
|
+
|
|
77
|
+
def copy_model(
|
|
78
|
+
self,
|
|
79
|
+
clone_dest: str,
|
|
80
|
+
git_subdirectory: str,
|
|
81
|
+
model_dest: str,
|
|
82
|
+
custom_dependencies_path: Optional[str],
|
|
83
|
+
main_dir: str,
|
|
84
|
+
):
|
|
85
|
+
ignore_patterns, patterns_for_printing = get_ignore_pattern(
|
|
86
|
+
Path(clone_dest) / git_subdirectory, main_dir, self.notifier
|
|
87
|
+
)
|
|
88
|
+
self.notifier.debug(
|
|
89
|
+
f"Will ignore the following files: {patterns_for_printing}."
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
# Copy model
|
|
93
|
+
copytree(
|
|
94
|
+
src=Path(clone_dest) / git_subdirectory,
|
|
95
|
+
dst=model_dest,
|
|
96
|
+
dirs_exist_ok=True,
|
|
97
|
+
ignore=ignore_patterns,
|
|
98
|
+
)
|
|
99
|
+
self.notifier.debug("Model copied from git repository")
|
|
100
|
+
|
|
101
|
+
# Copy custom dependencies path
|
|
102
|
+
if custom_dependencies_path:
|
|
103
|
+
git_custom_dependencies_path = Path(clone_dest) / Path(
|
|
104
|
+
custom_dependencies_path
|
|
105
|
+
)
|
|
106
|
+
if git_custom_dependencies_path.is_file():
|
|
107
|
+
shutil.copy(
|
|
108
|
+
src=git_custom_dependencies_path,
|
|
109
|
+
dst=Path(model_dest) / git_custom_dependencies_path.name,
|
|
110
|
+
)
|
|
111
|
+
self.notifier.debug("Custom dependency file copied from git repository")
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def split_git_url_and_subdirectory(uri):
|
|
115
|
+
subdirectory = ""
|
|
116
|
+
parsed_uri = uri
|
|
117
|
+
if "#" in uri:
|
|
118
|
+
subdirectory = uri[uri.find("#") + 1 :]
|
|
119
|
+
parsed_uri = uri[: uri.find("#")]
|
|
120
|
+
if subdirectory and "." in subdirectory:
|
|
121
|
+
raise QwakException("'.' is not allowed in project subdirectory paths.")
|
|
122
|
+
return parsed_uri, subdirectory
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def get_git_remote_uri(notifier: Notifier, url: str, git_credentials: str) -> str:
|
|
126
|
+
if git_credentials:
|
|
127
|
+
url_start_index = url.find("://") + 3
|
|
128
|
+
url = f"{url[:url_start_index]}{git_credentials}@{url[url_start_index:]}"
|
|
129
|
+
else:
|
|
130
|
+
notifier.warning("Git credentials secret has been provided")
|
|
131
|
+
|
|
132
|
+
return url
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def clone_and_checkout_repo(git_repo_url: str, to_path: str, git_branch: str) -> str:
|
|
136
|
+
try:
|
|
137
|
+
repo = Repo.clone_from(url=git_repo_url, to_path=to_path)
|
|
138
|
+
repo.submodule_update(init=True, recursive=True)
|
|
139
|
+
if git_branch in repo.branches:
|
|
140
|
+
repo.git.checkout(git_branch)
|
|
141
|
+
else:
|
|
142
|
+
repo.git.checkout("-b", git_branch, f"{repo.remote()}/{git_branch}")
|
|
143
|
+
return repo.head.object.hexsha
|
|
144
|
+
except GitError as e:
|
|
145
|
+
raise QwakSuggestionException(
|
|
146
|
+
src_exception=e,
|
|
147
|
+
message="Unable to clone git repository",
|
|
148
|
+
suggestion="Please check you git credentials",
|
|
149
|
+
)
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import shutil
|
|
4
|
+
from abc import ABC, abstractmethod
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import TYPE_CHECKING, Any, Callable, Optional, Tuple, Union
|
|
7
|
+
|
|
8
|
+
_IGNORED_PATTERNS = [r"\..*", r"__pycache__"]
|
|
9
|
+
QWAK_IGNORE_FILE_NAME = ".qwakignore"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from qwak_sdk.commands.models.build import Notifier
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def load_patterns_from_ignore_file(notifier: Notifier, ignore_file_path: Path):
|
|
17
|
+
ignore_file_path = Path(ignore_file_path)
|
|
18
|
+
if ignore_file_path.is_file():
|
|
19
|
+
notifier.info(
|
|
20
|
+
f"Found a Qwak ignore file {ignore_file_path} - will ignore listed patterns"
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
with ignore_file_path.open("r") as ignore_file:
|
|
24
|
+
patterns_to_ignore = [
|
|
25
|
+
pattern.strip() for pattern in ignore_file.readlines()
|
|
26
|
+
]
|
|
27
|
+
notifier.debug(
|
|
28
|
+
f"Patterns from Qwak ignore file detected - {str(patterns_to_ignore)}"
|
|
29
|
+
)
|
|
30
|
+
return patterns_to_ignore
|
|
31
|
+
|
|
32
|
+
notifier.debug("no Qwak ignore file was found, skipping")
|
|
33
|
+
return []
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_ignore_pattern(
|
|
37
|
+
src: str, main_dir: str, notifier: Notifier
|
|
38
|
+
) -> Tuple[Callable[[Any, list[str]], set[str]], list[str]]:
|
|
39
|
+
if (Path(src) / main_dir / QWAK_IGNORE_FILE_NAME).is_file():
|
|
40
|
+
ignore_file_path = Path(src) / main_dir / QWAK_IGNORE_FILE_NAME
|
|
41
|
+
else:
|
|
42
|
+
ignore_file_path = Path(src) / QWAK_IGNORE_FILE_NAME
|
|
43
|
+
|
|
44
|
+
ignored_patterns = (
|
|
45
|
+
load_patterns_from_ignore_file(
|
|
46
|
+
notifier=notifier, ignore_file_path=ignore_file_path
|
|
47
|
+
)
|
|
48
|
+
+ _IGNORED_PATTERNS
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
return shutil.ignore_patterns(*ignored_patterns), ignored_patterns
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class Strategy(ABC):
|
|
55
|
+
def __init__(self, notifier: Notifier):
|
|
56
|
+
self.notifier = notifier
|
|
57
|
+
|
|
58
|
+
@abstractmethod
|
|
59
|
+
def fetch(
|
|
60
|
+
self,
|
|
61
|
+
src: Union[str, Path],
|
|
62
|
+
dest: str,
|
|
63
|
+
git_branch: str,
|
|
64
|
+
git_credentials: str,
|
|
65
|
+
model_id: str,
|
|
66
|
+
build_id: str,
|
|
67
|
+
custom_dependency_path: Optional[str],
|
|
68
|
+
) -> Optional[str]:
|
|
69
|
+
pass
|
|
File without changes
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import shutil
|
|
2
|
+
import tempfile
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Optional, Union
|
|
5
|
+
from zipfile import ZipFile
|
|
6
|
+
|
|
7
|
+
from qwak_sdk.exceptions import QwakSuggestionException
|
|
8
|
+
from qwak_sdk.tools.files import copytree
|
|
9
|
+
|
|
10
|
+
from ...common import get_git_commit_id
|
|
11
|
+
from ..strategy import Strategy, get_ignore_pattern
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ZipStrategy(Strategy):
|
|
15
|
+
def fetch(
|
|
16
|
+
self,
|
|
17
|
+
src: Union[str, Path],
|
|
18
|
+
dest: str,
|
|
19
|
+
custom_dependencies_path: Optional[str],
|
|
20
|
+
main_dir: str,
|
|
21
|
+
**kwargs,
|
|
22
|
+
) -> Optional[str]:
|
|
23
|
+
self.notifier.info(f"Fetching Model code from local zip file - {src}")
|
|
24
|
+
try:
|
|
25
|
+
with tempfile.TemporaryDirectory() as temp_extraction_target:
|
|
26
|
+
with ZipFile(src) as zip_file:
|
|
27
|
+
zip_file.extractall(path=temp_extraction_target)
|
|
28
|
+
|
|
29
|
+
git_commit_id = get_git_commit_id(
|
|
30
|
+
temp_extraction_target, self.notifier
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
ignore_patterns, patterns_for_printing = get_ignore_pattern(
|
|
34
|
+
temp_extraction_target,
|
|
35
|
+
main_dir,
|
|
36
|
+
self.notifier,
|
|
37
|
+
)
|
|
38
|
+
self.notifier.info(
|
|
39
|
+
f"Will ignore the following files: {patterns_for_printing}."
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
copytree(
|
|
43
|
+
src=temp_extraction_target,
|
|
44
|
+
dst=dest,
|
|
45
|
+
ignore=ignore_patterns,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# Copy custom dependencies path
|
|
49
|
+
if (
|
|
50
|
+
custom_dependencies_path
|
|
51
|
+
and Path(custom_dependencies_path).is_file()
|
|
52
|
+
):
|
|
53
|
+
shutil.copy(
|
|
54
|
+
src=custom_dependencies_path,
|
|
55
|
+
dst=Path(dest) / Path(custom_dependencies_path).name,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
return git_commit_id
|
|
59
|
+
except Exception as e:
|
|
60
|
+
raise QwakSuggestionException(
|
|
61
|
+
message="Unable to unzip zipped file",
|
|
62
|
+
src_exception=e,
|
|
63
|
+
suggestion=f"Please make sure that {src} has read permissions",
|
|
64
|
+
)
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import List
|
|
4
|
+
|
|
5
|
+
from qwak_sdk.commands.models.build._logic.constant.temp_dir import TEMP_LOCAL_MODEL_DIR
|
|
6
|
+
from qwak_sdk.commands.models.build._logic.context import DependencyManagerType
|
|
7
|
+
from qwak_sdk.commands.models.build._logic.interface.step_inteface import Step
|
|
8
|
+
from qwak_sdk.commands.models.build._logic.util.step_decorator import (
|
|
9
|
+
build_failure_handler,
|
|
10
|
+
)
|
|
11
|
+
from qwak_sdk.exceptions import QwakSuggestionException
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class DependencyFileObject:
|
|
16
|
+
dep_file_name: List[str]
|
|
17
|
+
lock_file_name: str = field(default="")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
DEPS_MANAGER_FILE_MAP = {
|
|
21
|
+
DependencyManagerType.PIP: DependencyFileObject(dep_file_name=["requirements.txt"]),
|
|
22
|
+
DependencyManagerType.POETRY: DependencyFileObject(
|
|
23
|
+
dep_file_name=["pyproject.toml"], lock_file_name="poetry.lock"
|
|
24
|
+
),
|
|
25
|
+
DependencyManagerType.CONDA: DependencyFileObject(
|
|
26
|
+
dep_file_name=["conda.yml", "conda.yaml"]
|
|
27
|
+
),
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class PostFetchValidationStep(Step):
|
|
32
|
+
def description(self) -> str:
|
|
33
|
+
return "Post model fetch validation"
|
|
34
|
+
|
|
35
|
+
@build_failure_handler()
|
|
36
|
+
def execute(self) -> None:
|
|
37
|
+
self.validate_dependencies()
|
|
38
|
+
self.configure_base_docker_image()
|
|
39
|
+
|
|
40
|
+
def validate_dependencies(self):
|
|
41
|
+
if (
|
|
42
|
+
not Path(self.config.build_properties.model_uri.uri).is_dir()
|
|
43
|
+
or self.config.build_env.python_env.dependency_file_path
|
|
44
|
+
):
|
|
45
|
+
self.notifier.debug("Validating dependency file exists")
|
|
46
|
+
model_uri, main_dir = (
|
|
47
|
+
self.context.host_temp_local_build_dir / TEMP_LOCAL_MODEL_DIR,
|
|
48
|
+
self.config.build_properties.model_uri.main_dir,
|
|
49
|
+
)
|
|
50
|
+
(
|
|
51
|
+
self.context.dependency_manager_type,
|
|
52
|
+
self.context.model_relative_dependency_file,
|
|
53
|
+
self.context.model_relative_dependency_lock_file,
|
|
54
|
+
) = find_dependency_files(model_uri, main_dir, self.notifier)
|
|
55
|
+
|
|
56
|
+
if (
|
|
57
|
+
self.context.dependency_manager_type
|
|
58
|
+
and self.context.model_relative_dependency_file
|
|
59
|
+
):
|
|
60
|
+
return
|
|
61
|
+
|
|
62
|
+
self.notifier.error("Dependency file wasn't found, failing...")
|
|
63
|
+
raise QwakSuggestionException(
|
|
64
|
+
message="Dependency file isn't found",
|
|
65
|
+
suggestion="Make sure your model include one of dependencies manager: pip/poetry/conda",
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
def configure_base_docker_image(self):
|
|
69
|
+
base_image = self.config.build_env.docker.base_image
|
|
70
|
+
if (not base_image) and self.config.build_env.remote.resources.gpu_type:
|
|
71
|
+
base_image = "qwakai/qwak:gpu-py39"
|
|
72
|
+
self.context.base_image = base_image
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def find_file_location(model_uri, main_dir, filename) -> Path:
|
|
76
|
+
file_locations: List[Path] = [
|
|
77
|
+
model_uri / filename,
|
|
78
|
+
model_uri / main_dir / filename,
|
|
79
|
+
]
|
|
80
|
+
for file in file_locations:
|
|
81
|
+
if file.is_file():
|
|
82
|
+
return file
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def find_dependency_files(model_uri, main_dir, notifier):
|
|
86
|
+
dependency_manager_type = None
|
|
87
|
+
model_relative_dependency_file = None
|
|
88
|
+
model_relative_dependency_lock_file = None
|
|
89
|
+
for dep_type, dependency_file_object in DEPS_MANAGER_FILE_MAP.items():
|
|
90
|
+
for filename in dependency_file_object.dep_file_name:
|
|
91
|
+
dep_file_path = find_file_location(model_uri, main_dir, filename)
|
|
92
|
+
if dep_file_path:
|
|
93
|
+
notifier.info(
|
|
94
|
+
f"Found dependency type: {dep_type.name} by file: {dep_file_path}"
|
|
95
|
+
)
|
|
96
|
+
dependency_manager_type = dep_type
|
|
97
|
+
model_relative_dependency_file = dep_file_path.relative_to(model_uri)
|
|
98
|
+
if dependency_file_object.lock_file_name:
|
|
99
|
+
dep_lock_file_path = find_file_location(
|
|
100
|
+
model_uri,
|
|
101
|
+
main_dir,
|
|
102
|
+
dependency_file_object.lock_file_name,
|
|
103
|
+
)
|
|
104
|
+
if dep_lock_file_path:
|
|
105
|
+
notifier.info(
|
|
106
|
+
f"Found dependency lock file {dep_lock_file_path}"
|
|
107
|
+
)
|
|
108
|
+
model_relative_dependency_lock_file = (
|
|
109
|
+
dep_lock_file_path.relative_to(model_uri)
|
|
110
|
+
)
|
|
111
|
+
break
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
dependency_manager_type,
|
|
115
|
+
model_relative_dependency_file,
|
|
116
|
+
model_relative_dependency_lock_file,
|
|
117
|
+
)
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import uuid
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from qwak.clients.secret_service import SecretServiceClient
|
|
5
|
+
|
|
6
|
+
from qwak_sdk.commands.models.build._logic.constant.host_resource import (
|
|
7
|
+
HOST_TEMP_BUILD_DIR,
|
|
8
|
+
)
|
|
9
|
+
from qwak_sdk.commands.models.build._logic.interface.step_inteface import Step
|
|
10
|
+
from qwak_sdk.commands.models.build._logic.phase.a_fetch_model_code.post_fetch_validation_step import (
|
|
11
|
+
find_dependency_files,
|
|
12
|
+
)
|
|
13
|
+
from qwak_sdk.commands.models.build._logic.util.step_decorator import (
|
|
14
|
+
build_failure_handler,
|
|
15
|
+
)
|
|
16
|
+
from qwak_sdk.commands.models.build._logic.util.text import snake_case
|
|
17
|
+
from qwak_sdk.exceptions import QwakSuggestionException
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class PreFetchValidationStep(Step):
|
|
21
|
+
DEFAULT_CPUS = 2
|
|
22
|
+
DEFAULT_MEMORY = "4Gi"
|
|
23
|
+
|
|
24
|
+
def description(self) -> str:
|
|
25
|
+
return "Pre model fetch validation"
|
|
26
|
+
|
|
27
|
+
def execute(self) -> None:
|
|
28
|
+
self.validate_build_properties()
|
|
29
|
+
self.create_build_id()
|
|
30
|
+
self.collect_model_id()
|
|
31
|
+
self.create_build_dir()
|
|
32
|
+
self.collect_git_credentials()
|
|
33
|
+
self.validate_dependencies()
|
|
34
|
+
self.validate_cpu_gpu_resources()
|
|
35
|
+
|
|
36
|
+
def validate_build_properties(self):
|
|
37
|
+
if not self.config.build_properties.model_uri.uri:
|
|
38
|
+
error_message = "Model uri wasn't set"
|
|
39
|
+
self.notifier.error(f"{error_message}, failing...")
|
|
40
|
+
|
|
41
|
+
raise QwakSuggestionException(
|
|
42
|
+
message=error_message,
|
|
43
|
+
suggestion="Make sure your build properties object contains model uri argument",
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
@build_failure_handler()
|
|
47
|
+
def collect_model_id(self):
|
|
48
|
+
model_id = self.config.build_properties.model_id
|
|
49
|
+
model = self.context.client_models_management.get_model(
|
|
50
|
+
model_id=model_id,
|
|
51
|
+
exception_on_missing=False,
|
|
52
|
+
)
|
|
53
|
+
if not model:
|
|
54
|
+
suggestion = f"Create model {model_id} or check model ID spelling"
|
|
55
|
+
snake_case_model_id = snake_case(model_id)
|
|
56
|
+
if self.context.client_models_management.is_model_exists(
|
|
57
|
+
snake_case_model_id
|
|
58
|
+
):
|
|
59
|
+
suggestion = f"Try using model ID {snake_case_model_id} instead"
|
|
60
|
+
raise QwakSuggestionException(
|
|
61
|
+
message=f"Model ID {model_id} isn't found",
|
|
62
|
+
suggestion=suggestion,
|
|
63
|
+
)
|
|
64
|
+
self.context.project_uuid = model.project_id
|
|
65
|
+
self.context.model_uuid = model.uuid
|
|
66
|
+
self.context.model_id = model_id
|
|
67
|
+
|
|
68
|
+
def create_build_id(self):
|
|
69
|
+
self.context.build_id = str(uuid.uuid4())
|
|
70
|
+
self.notifier.info(f"Generated build ID - {self.context.build_id}")
|
|
71
|
+
|
|
72
|
+
def create_build_dir(self):
|
|
73
|
+
build_dir = HOST_TEMP_BUILD_DIR / self.context.model_id / self.context.build_id
|
|
74
|
+
build_dir.mkdir(exist_ok=True, parents=True)
|
|
75
|
+
self.context.host_temp_local_build_dir = build_dir
|
|
76
|
+
self.notifier.debug(f"Build directory created - {build_dir}")
|
|
77
|
+
|
|
78
|
+
def collect_git_credentials(self):
|
|
79
|
+
if self.config.build_properties.model_uri.git_credentials:
|
|
80
|
+
self.context.git_credentials = (
|
|
81
|
+
self.config.build_properties.model_uri.git_credentials
|
|
82
|
+
)
|
|
83
|
+
elif self.config.build_properties.model_uri.git_credentials_secret:
|
|
84
|
+
self.context.git_credentials = SecretServiceClient().get_secret(
|
|
85
|
+
self.config.build_properties.model_uri.git_credentials_secret
|
|
86
|
+
)
|
|
87
|
+
else:
|
|
88
|
+
self.notifier.debug("Git credentials isn't configured")
|
|
89
|
+
|
|
90
|
+
def validate_dependencies(self):
|
|
91
|
+
if (
|
|
92
|
+
Path(self.config.build_properties.model_uri.uri).is_dir()
|
|
93
|
+
and not self.config.build_env.python_env.dependency_file_path
|
|
94
|
+
):
|
|
95
|
+
model_uri, main_dir = (
|
|
96
|
+
Path(self.config.build_properties.model_uri.uri),
|
|
97
|
+
self.config.build_properties.model_uri.main_dir,
|
|
98
|
+
)
|
|
99
|
+
(
|
|
100
|
+
self.context.dependency_manager_type,
|
|
101
|
+
self.context.model_relative_dependency_file,
|
|
102
|
+
self.context.model_relative_dependency_lock_file,
|
|
103
|
+
) = find_dependency_files(model_uri, main_dir, self.notifier)
|
|
104
|
+
|
|
105
|
+
if (
|
|
106
|
+
self.context.dependency_manager_type
|
|
107
|
+
and self.context.model_relative_dependency_file
|
|
108
|
+
):
|
|
109
|
+
return
|
|
110
|
+
|
|
111
|
+
self.notifier.error("Dependency file wasn't found, failing...")
|
|
112
|
+
raise QwakSuggestionException(
|
|
113
|
+
message="Dependency file isn't found",
|
|
114
|
+
suggestion="Make sure your model include one of dependencies manager: pip/poetry/conda",
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
def validate_cpu_gpu_resources(self):
|
|
118
|
+
gpu_configured = (
|
|
119
|
+
self.config.build_env.remote.resources.gpu_type
|
|
120
|
+
or self.config.build_env.remote.resources.gpu_amount
|
|
121
|
+
)
|
|
122
|
+
cpu_configured = (
|
|
123
|
+
self.config.build_env.remote.resources.cpus
|
|
124
|
+
or self.config.build_env.remote.resources.memory
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
if cpu_configured and gpu_configured:
|
|
128
|
+
raise QwakSuggestionException(
|
|
129
|
+
message="CPU and GPU configured together, Invalid configuration.",
|
|
130
|
+
suggestion="Please configure only CPU or GPU",
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
if not (cpu_configured or gpu_configured):
|
|
134
|
+
self.config.build_env.remote.resources.cpus = self.DEFAULT_CPUS
|
|
135
|
+
self.config.build_env.remote.resources.memory = self.DEFAULT_MEMORY
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from .cleanup_step import CleanupStep
|
|
2
|
+
from .start_remote_build_step import StartRemoteBuildStep
|
|
3
|
+
from .upload_step import UploadStep
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def get_remote_register_qwak_build_steps():
|
|
7
|
+
return [
|
|
8
|
+
UploadStep(),
|
|
9
|
+
StartRemoteBuildStep(),
|
|
10
|
+
CleanupStep(),
|
|
11
|
+
]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
from qwak_sdk.commands.models.build._logic.interface.step_inteface import Step
|
|
4
|
+
from qwak_sdk.commands.models.build._logic.util.step_decorator import (
|
|
5
|
+
cleaning_up_after_build,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class CleanupStep(Step):
|
|
10
|
+
def description(self) -> str:
|
|
11
|
+
return "Clean build artifacts"
|
|
12
|
+
|
|
13
|
+
def execute(self) -> None:
|
|
14
|
+
self.notifier.debug(
|
|
15
|
+
"Cleanup environment - Deleting file and intermediate images"
|
|
16
|
+
)
|
|
17
|
+
if os.getenv("POD_NAME"):
|
|
18
|
+
self.notifier.debug("Skipping cleanup - Remote executor is temporary")
|
|
19
|
+
else:
|
|
20
|
+
cleaning_up_after_build(self)
|
qwak_sdk/commands/models/build/_logic/phase/b_remote_register_qwak_build/start_remote_build_step.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from copy import deepcopy
|
|
2
|
+
|
|
3
|
+
from qwak_sdk import __version__ as qwak_sdk_version
|
|
4
|
+
from qwak_sdk.commands.models.build._logic.constant.upload_tag import (
|
|
5
|
+
BUILD_CONFIG_TAG,
|
|
6
|
+
MODEL_CODE_TAG,
|
|
7
|
+
QWAK_SDK_VERSION_TAG,
|
|
8
|
+
)
|
|
9
|
+
from qwak_sdk.commands.models.build._logic.interface.step_inteface import Step
|
|
10
|
+
from qwak_sdk.commands.models.build._logic.util.step_decorator import (
|
|
11
|
+
build_failure_handler,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class StartRemoteBuildStep(Step):
|
|
16
|
+
def description(self) -> str:
|
|
17
|
+
return "Start remote build"
|
|
18
|
+
|
|
19
|
+
@build_failure_handler()
|
|
20
|
+
def execute(self) -> None:
|
|
21
|
+
self.notifier.info(f"Start remote build - {self.context.build_id}")
|
|
22
|
+
config_copy = deepcopy(self.config)
|
|
23
|
+
config_copy.build_properties.build_id = self.context.build_id
|
|
24
|
+
self.context.client_builds_orchestrator.build_model(
|
|
25
|
+
build_conf=config_copy,
|
|
26
|
+
build_v1_flag=False,
|
|
27
|
+
build_config_url=self.get_download_url(BUILD_CONFIG_TAG),
|
|
28
|
+
qwak_sdk_version_url=self.get_download_url(QWAK_SDK_VERSION_TAG),
|
|
29
|
+
resolved_model_url=self.get_download_url(MODEL_CODE_TAG),
|
|
30
|
+
git_commit_id=self.context.git_commit_id,
|
|
31
|
+
sdk_version=qwak_sdk_version,
|
|
32
|
+
)
|
|
33
|
+
self.notifier.info("Remote build started successfully")
|
|
34
|
+
|
|
35
|
+
def get_download_url(self, tag: str) -> str:
|
|
36
|
+
return (
|
|
37
|
+
self.context.client_builds_orchestrator.get_build_versioning_download_url(
|
|
38
|
+
model_id=self.config.build_properties.model_id,
|
|
39
|
+
build_id=self.context.build_id,
|
|
40
|
+
tag=tag,
|
|
41
|
+
).download_url
|
|
42
|
+
)
|