qwak-sdk 0.5.102__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.
- qwak_sdk/__init__.py +9 -0
- qwak_sdk/cli.py +79 -0
- qwak_sdk/commands/__init__.py +0 -0
- qwak_sdk/commands/_logic/__init__.py +0 -0
- qwak_sdk/commands/_logic/tools.py +6 -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/alerts/__init__.py +0 -0
- qwak_sdk/commands/alerts/alerts_commnad_group.py +18 -0
- qwak_sdk/commands/alerts/delete/__init__.py +0 -0
- qwak_sdk/commands/alerts/delete/_logic.py +5 -0
- qwak_sdk/commands/alerts/delete/ui.py +10 -0
- qwak_sdk/commands/alerts/list/__init__.py +0 -0
- qwak_sdk/commands/alerts/list/_logic.py +23 -0
- qwak_sdk/commands/alerts/list/ui.py +17 -0
- qwak_sdk/commands/alerts/register/__init__.py +0 -0
- qwak_sdk/commands/alerts/register/_logic.py +72 -0
- qwak_sdk/commands/alerts/register/ui.py +30 -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 +15 -0
- qwak_sdk/commands/audience/_logic/config/parser.py +30 -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 +59 -0
- qwak_sdk/commands/audience/_logic/config/v1/config_v1.py +23 -0
- qwak_sdk/commands/audience/_logic/config/v1/route_config.py +15 -0
- qwak_sdk/commands/audience/_logic/config/v1/spec.py +9 -0
- qwak_sdk/commands/audience/audience_api_dump.py +86 -0
- qwak_sdk/commands/audience/audience_commands_group.py +30 -0
- qwak_sdk/commands/audience/create/__init__.py +0 -0
- qwak_sdk/commands/audience/create/logic.py +41 -0
- qwak_sdk/commands/audience/create/ui.py +21 -0
- qwak_sdk/commands/audience/delete/__init__.py +0 -0
- qwak_sdk/commands/audience/delete/logic.py +13 -0
- qwak_sdk/commands/audience/delete/ui.py +17 -0
- qwak_sdk/commands/audience/get/__init__.py +0 -0
- qwak_sdk/commands/audience/get/logic.py +14 -0
- qwak_sdk/commands/audience/get/ui.py +25 -0
- qwak_sdk/commands/audience/list/__init__.py +0 -0
- qwak_sdk/commands/audience/list/logic.py +16 -0
- qwak_sdk/commands/audience/list/ui.py +26 -0
- qwak_sdk/commands/audience/update/__init__.py +0 -0
- qwak_sdk/commands/audience/update/logic.py +37 -0
- qwak_sdk/commands/audience/update/ui.py +26 -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 +152 -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 +36 -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/backfill/__init__.py +0 -0
- qwak_sdk/commands/feature_store/backfill/_logic.py +140 -0
- qwak_sdk/commands/feature_store/backfill/streaming/__init__.py +0 -0
- qwak_sdk/commands/feature_store/backfill/streaming/_logic.py +50 -0
- qwak_sdk/commands/feature_store/backfill/streaming/ui.py +67 -0
- qwak_sdk/commands/feature_store/backfill/ui.py +146 -0
- qwak_sdk/commands/feature_store/delete/__init__.py +0 -0
- qwak_sdk/commands/feature_store/delete/_logic.py +104 -0
- qwak_sdk/commands/feature_store/delete/ui.py +40 -0
- qwak_sdk/commands/feature_store/execution/__init__.py +0 -0
- qwak_sdk/commands/feature_store/execution/ui.py +19 -0
- qwak_sdk/commands/feature_store/feature_store_command_group.py +29 -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 +367 -0
- qwak_sdk/commands/feature_store/register/ui.py +111 -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 +39 -0
- qwak_sdk/commands/models/__init__.py +0 -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 +42 -0
- qwak_sdk/commands/models/build/_logic/client_logs/__init__.py +0 -0
- qwak_sdk/commands/models/build/_logic/client_logs/cli_phase_run_handler.py +123 -0
- qwak_sdk/commands/models/build/_logic/client_logs/cli_trigger_build_logger.py +19 -0
- qwak_sdk/commands/models/build/_logic/client_logs/logger.py +88 -0
- qwak_sdk/commands/models/build/_logic/client_logs/messages.py +36 -0
- qwak_sdk/commands/models/build/_logic/client_logs/spinner.py +14 -0
- qwak_sdk/commands/models/build/_logic/client_logs/trigger_build_logger.py +54 -0
- qwak_sdk/commands/models/build/_logic/client_logs/utils.py +12 -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 +20 -0
- qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/get_sdk_version_step.py +14 -0
- qwak_sdk/commands/models/build/_logic/phase/b_remote_register_qwak_build/__init__.py +16 -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 +55 -0
- qwak_sdk/commands/models/build/_logic/phase/c_deploy/deploy_build.py +61 -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 +60 -0
- qwak_sdk/commands/models/build/_logic/util/text.py +9 -0
- qwak_sdk/commands/models/build/_logic/wait_until_finished.py +27 -0
- qwak_sdk/commands/models/build/ui.py +337 -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 +39 -0
- qwak_sdk/commands/models/create/__init__.py +0 -0
- qwak_sdk/commands/models/create/_logic.py +36 -0
- qwak_sdk/commands/models/create/ui.py +43 -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 +25 -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 +68 -0
- qwak_sdk/commands/models/deployments/deploy/_logic/deploy_config.py +261 -0
- qwak_sdk/commands/models/deployments/deploy/_logic/deployment.py +405 -0
- qwak_sdk/commands/models/deployments/deploy/_logic/deployment_message_helpers.py +114 -0
- qwak_sdk/commands/models/deployments/deploy/_logic/deployment_response_handler.py +156 -0
- qwak_sdk/commands/models/deployments/deploy/_logic/deployment_size_mapper.py +96 -0
- qwak_sdk/commands/models/deployments/deploy/_logic/get_latest_successful_build.py +28 -0
- qwak_sdk/commands/models/deployments/deploy/_logic/local_deployment.py +193 -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 +15 -0
- qwak_sdk/commands/models/deployments/deploy/batch/_logic/deploy_executor.py +24 -0
- qwak_sdk/commands/models/deployments/deploy/batch/ui.py +126 -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 +21 -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 +75 -0
- qwak_sdk/commands/models/deployments/deploy/realtime/ui.py +209 -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 +213 -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 +249 -0
- qwak_sdk/commands/models/deployments/undeploy/ui.py +72 -0
- qwak_sdk/commands/models/describe/__init__.py +0 -0
- qwak_sdk/commands/models/describe/_logic.py +169 -0
- qwak_sdk/commands/models/describe/ui.py +35 -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 +81 -0
- qwak_sdk/commands/models/executions/start/ui.py +208 -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 +11 -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 +11 -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 +20 -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 +40 -0
- qwak_sdk/commands/models/list_models/__init__.py +0 -0
- qwak_sdk/commands/models/list_models/_logic.py +5 -0
- qwak_sdk/commands/models/list_models/ui.py +60 -0
- qwak_sdk/commands/models/metadata/__init__.py +0 -0
- qwak_sdk/commands/models/metadata/_logic.py +5 -0
- qwak_sdk/commands/models/metadata/ui.py +60 -0
- qwak_sdk/commands/models/models_command_group.py +44 -0
- qwak_sdk/commands/models/runtime/__init__.py +0 -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 +17 -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 +9 -0
- qwak_sdk/commands/projects/create/ui.py +68 -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 +24 -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 +45 -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/commands/workspaces/__init__.py +0 -0
- qwak_sdk/commands/workspaces/_logic/__init__.py +0 -0
- qwak_sdk/commands/workspaces/_logic/tools.py +44 -0
- qwak_sdk/commands/workspaces/_logic/workspace_validations.py +41 -0
- qwak_sdk/commands/workspaces/config/__init__.py +0 -0
- qwak_sdk/commands/workspaces/config/workspace_config.py +35 -0
- qwak_sdk/commands/workspaces/create/__init__.py +0 -0
- qwak_sdk/commands/workspaces/create/_logic.py +54 -0
- qwak_sdk/commands/workspaces/create/ui.py +48 -0
- qwak_sdk/commands/workspaces/delete/__init__.py +0 -0
- qwak_sdk/commands/workspaces/delete/_logic.py +30 -0
- qwak_sdk/commands/workspaces/delete/ui.py +23 -0
- qwak_sdk/commands/workspaces/start/__init__.py +0 -0
- qwak_sdk/commands/workspaces/start/_logic.py +30 -0
- qwak_sdk/commands/workspaces/start/ui.py +23 -0
- qwak_sdk/commands/workspaces/stop/__init__.py +0 -0
- qwak_sdk/commands/workspaces/stop/_logic.py +30 -0
- qwak_sdk/commands/workspaces/stop/ui.py +23 -0
- qwak_sdk/commands/workspaces/update/__init__.py +0 -0
- qwak_sdk/commands/workspaces/update/_logic.py +82 -0
- qwak_sdk/commands/workspaces/update/ui.py +57 -0
- qwak_sdk/commands/workspaces/workspaces_commands_group.py +23 -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_resource_not_found.py +2 -0
- qwak_sdk/inner/__init__.py +0 -0
- qwak_sdk/inner/file_registry.py +98 -0
- qwak_sdk/inner/tools/__init__.py +0 -0
- qwak_sdk/inner/tools/cli_tools.py +220 -0
- qwak_sdk/inner/tools/config_handler.py +27 -0
- qwak_sdk/inner/tools/dataclasses_utils.py +21 -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 +63 -0
- qwak_sdk/tools/log_handling.py +159 -0
- qwak_sdk/tools/utils.py +42 -0
- qwak_sdk-0.5.102.dist-info/METADATA +51 -0
- qwak_sdk-0.5.102.dist-info/RECORD +328 -0
- qwak_sdk-0.5.102.dist-info/WHEEL +4 -0
- qwak_sdk-0.5.102.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
import time
|
|
3
|
+
import warnings
|
|
4
|
+
from collections import namedtuple
|
|
5
|
+
from typing import Any, Callable, Dict, List, Tuple, Union
|
|
6
|
+
|
|
7
|
+
import click
|
|
8
|
+
from click import Context, OptionParser
|
|
9
|
+
from qwak.exceptions import QwakException
|
|
10
|
+
from qwak.inner.di_configuration import UserAccountConfiguration
|
|
11
|
+
from qwak.inner.di_configuration.session import Session
|
|
12
|
+
|
|
13
|
+
from qwak_sdk.inner.tools.tracking import log_event
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def get_user_identifiers(account: UserAccountConfiguration):
|
|
17
|
+
try:
|
|
18
|
+
user_id = account.get_user_config().api_key
|
|
19
|
+
identifier_cls = namedtuple("Identifier", ["user_id"])
|
|
20
|
+
return identifier_cls(user_id)
|
|
21
|
+
|
|
22
|
+
except QwakException:
|
|
23
|
+
# User might not be registered or have a valid API key
|
|
24
|
+
return None
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def profile_setter_wrapper(func: Callable):
|
|
28
|
+
@functools.wraps(func)
|
|
29
|
+
def wrapper(*args, **kwargs):
|
|
30
|
+
ctx = click.get_current_context()
|
|
31
|
+
Session().set_environment(ctx.params["environment"])
|
|
32
|
+
return func(*args, **kwargs)
|
|
33
|
+
|
|
34
|
+
return wrapper
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def usage_statistics_wrapper(func: Callable):
|
|
38
|
+
@functools.wraps(func)
|
|
39
|
+
def wrapper(*args, **kwargs):
|
|
40
|
+
ctx = click.get_current_context()
|
|
41
|
+
start_time = time.time()
|
|
42
|
+
|
|
43
|
+
account = UserAccountConfiguration()
|
|
44
|
+
user_identifiers = get_user_identifiers(account)
|
|
45
|
+
|
|
46
|
+
# If we could not get user identifiers for some reason (for example - user not logged in) - do not track
|
|
47
|
+
if not user_identifiers:
|
|
48
|
+
return func(*args, **kwargs)
|
|
49
|
+
|
|
50
|
+
event_properties = {
|
|
51
|
+
"command_group": ctx.command_path,
|
|
52
|
+
"commands": ctx.command.name,
|
|
53
|
+
"duration": time.time() - start_time,
|
|
54
|
+
}
|
|
55
|
+
try:
|
|
56
|
+
return_value = func(*args, **kwargs)
|
|
57
|
+
|
|
58
|
+
event_properties["response"] = return_value
|
|
59
|
+
event_properties["status"] = 0
|
|
60
|
+
log_event(
|
|
61
|
+
event_properties,
|
|
62
|
+
user_id=user_identifiers.user_id,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
return return_value
|
|
66
|
+
|
|
67
|
+
except BaseException as e:
|
|
68
|
+
command_status = 1
|
|
69
|
+
if type(e) == KeyboardInterrupt:
|
|
70
|
+
command_status = 1
|
|
71
|
+
|
|
72
|
+
event_properties["error_type"] = type(e).__name__
|
|
73
|
+
event_properties["error_message"] = str(e)
|
|
74
|
+
event_properties["status"] = command_status
|
|
75
|
+
|
|
76
|
+
log_event(
|
|
77
|
+
event_properties,
|
|
78
|
+
user_id=user_identifiers.user_id,
|
|
79
|
+
)
|
|
80
|
+
raise
|
|
81
|
+
|
|
82
|
+
return wrapper
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class DeprecatedOption(click.Option):
|
|
86
|
+
def __init__(self, *args, **kwargs):
|
|
87
|
+
self.deprecated = kwargs.pop("deprecated", ())
|
|
88
|
+
self.preferred = kwargs.pop("preferred", args[0][-1])
|
|
89
|
+
super(DeprecatedOption, self).__init__(*args, **kwargs)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class QwakCommand(click.Command):
|
|
93
|
+
def __init__(self, *args, **kwargs):
|
|
94
|
+
super().__init__(*args, **kwargs)
|
|
95
|
+
self.params.insert(
|
|
96
|
+
-1,
|
|
97
|
+
click.core.Option(
|
|
98
|
+
("--environment",),
|
|
99
|
+
default="default",
|
|
100
|
+
required=False,
|
|
101
|
+
is_eager=True,
|
|
102
|
+
help="Qwak environment",
|
|
103
|
+
),
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
def make_parser(self, ctx: Context) -> OptionParser:
|
|
107
|
+
parser = super(QwakCommand, self).make_parser(ctx)
|
|
108
|
+
|
|
109
|
+
# get the parser options
|
|
110
|
+
options = set(parser._short_opt.values())
|
|
111
|
+
options |= set(parser._long_opt.values())
|
|
112
|
+
|
|
113
|
+
for option in options:
|
|
114
|
+
if not isinstance(option.obj, DeprecatedOption):
|
|
115
|
+
continue
|
|
116
|
+
|
|
117
|
+
def make_process(an_option):
|
|
118
|
+
"""Construct a closure to the parser option processor"""
|
|
119
|
+
|
|
120
|
+
orig_process = an_option.process
|
|
121
|
+
deprecated = getattr(an_option.obj, "deprecated", None)
|
|
122
|
+
preferred = getattr(an_option.obj, "preferred", None)
|
|
123
|
+
|
|
124
|
+
if not deprecated:
|
|
125
|
+
f"Expected `deprecated` value for `{an_option.obj.name}`"
|
|
126
|
+
|
|
127
|
+
def process(value, state):
|
|
128
|
+
"""The function above us on the stack used 'opt' to
|
|
129
|
+
pick option from a dict, see if it is deprecated"""
|
|
130
|
+
|
|
131
|
+
# reach up the stack and get 'opt'
|
|
132
|
+
import inspect
|
|
133
|
+
|
|
134
|
+
frame = inspect.currentframe()
|
|
135
|
+
try:
|
|
136
|
+
opt = frame.f_back.f_locals.get("opt")
|
|
137
|
+
finally:
|
|
138
|
+
del frame
|
|
139
|
+
|
|
140
|
+
if opt in deprecated:
|
|
141
|
+
warnings.warn(
|
|
142
|
+
f"{opt} has been deprecated, use {preferred}."
|
|
143
|
+
f" {opt} will be removed in future releases.",
|
|
144
|
+
DeprecationWarning,
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
return orig_process(value, state)
|
|
148
|
+
|
|
149
|
+
return process
|
|
150
|
+
|
|
151
|
+
option.process = make_process(option)
|
|
152
|
+
|
|
153
|
+
return parser
|
|
154
|
+
|
|
155
|
+
@profile_setter_wrapper
|
|
156
|
+
@usage_statistics_wrapper
|
|
157
|
+
def invoke(self, ctx: click.Context) -> Any:
|
|
158
|
+
return super().invoke(ctx)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class DefaultCommandGroup(click.Group):
|
|
162
|
+
def __init__(self, *args, **kwargs):
|
|
163
|
+
self.default_cmd_name = kwargs.pop("default", None)
|
|
164
|
+
super().__init__(*args, **kwargs)
|
|
165
|
+
|
|
166
|
+
def parse_args(self, ctx, args):
|
|
167
|
+
if not args and self.default_cmd_name:
|
|
168
|
+
# No args provided? Insert default command
|
|
169
|
+
args.insert(0, self.default_cmd_name)
|
|
170
|
+
elif args:
|
|
171
|
+
# Grab the help tokens (usually ['--help', '-h'])
|
|
172
|
+
help_options = ctx.help_option_names
|
|
173
|
+
first_arg = args[0]
|
|
174
|
+
if first_arg not in self.commands and first_arg not in help_options:
|
|
175
|
+
if self.default_cmd_name:
|
|
176
|
+
args.insert(0, self.default_cmd_name)
|
|
177
|
+
return super().parse_args(ctx, args)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def ask_yesno(
|
|
181
|
+
question: str, force: bool, print_callback: Callable[[str], None] = print
|
|
182
|
+
) -> bool:
|
|
183
|
+
"""
|
|
184
|
+
Helper to get yes / no answer from user.
|
|
185
|
+
|
|
186
|
+
Args:
|
|
187
|
+
question: yes/no question to show the user
|
|
188
|
+
force: automatically returns True if force is True
|
|
189
|
+
print_callback: function to use for printing
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
True/False by user input (unless forced and then always True)
|
|
193
|
+
"""
|
|
194
|
+
|
|
195
|
+
print_callback(f"{question}")
|
|
196
|
+
if force:
|
|
197
|
+
print_callback("Forced yes")
|
|
198
|
+
return True
|
|
199
|
+
return click.confirm("continue?")
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def dictify_params(env_vars: Union[Dict[str, str], List[str], Tuple[str]]):
|
|
203
|
+
result = dict()
|
|
204
|
+
|
|
205
|
+
if env_vars is None:
|
|
206
|
+
return result
|
|
207
|
+
|
|
208
|
+
if isinstance(env_vars, dict):
|
|
209
|
+
return env_vars
|
|
210
|
+
|
|
211
|
+
if isinstance(env_vars, (list, tuple)):
|
|
212
|
+
for env_var in env_vars:
|
|
213
|
+
if "=" not in env_var:
|
|
214
|
+
raise QwakException(
|
|
215
|
+
f'The environment variable definition passed {env_var} is invalid. Format is "KEY=VALUE"'
|
|
216
|
+
)
|
|
217
|
+
split_param = env_var.split("=")
|
|
218
|
+
result[split_param[0]] = split_param[1]
|
|
219
|
+
|
|
220
|
+
return result
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from typing import Any, Tuple, Union
|
|
2
|
+
|
|
3
|
+
from qwak.clients.build_orchestrator import BuildOrchestratorClient
|
|
4
|
+
from qwak.clients.instance_template.client import InstanceTemplateManagementClient
|
|
5
|
+
from qwak.inner.build_config.build_config_v1 import BuildConfigV1
|
|
6
|
+
from qwak.inner.tool.run_config import QwakConfigBase, YamlConfigMixin
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def config_handler(
|
|
10
|
+
config: Union[QwakConfigBase, YamlConfigMixin, Any],
|
|
11
|
+
from_file: str,
|
|
12
|
+
out_conf: bool,
|
|
13
|
+
sections: Tuple[str, ...] = (),
|
|
14
|
+
**kwargs,
|
|
15
|
+
) -> Any:
|
|
16
|
+
conf: Union[QwakConfigBase, YamlConfigMixin] = config.from_yaml(from_file)
|
|
17
|
+
conf.merge_cli_argument(sections=sections, **kwargs)
|
|
18
|
+
|
|
19
|
+
if isinstance(conf, BuildConfigV1):
|
|
20
|
+
conf.fetch_base_docker_image_name(
|
|
21
|
+
BuildOrchestratorClient(), InstanceTemplateManagementClient()
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
if out_conf:
|
|
25
|
+
print(conf.to_yaml())
|
|
26
|
+
|
|
27
|
+
return conf
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
from typing import Any, Dict, List, Type, Union
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def create_dataclass_instance(dataclass_type: Type, input_dict: Dict[str, Any]) -> Any:
|
|
6
|
+
fields = {f.name: f.type for f in dataclasses.fields(dataclass_type)}
|
|
7
|
+
|
|
8
|
+
def construct_dataclass(
|
|
9
|
+
dc_type: Union[Type, List], value: Any
|
|
10
|
+
) -> Union[Type, List]:
|
|
11
|
+
if dataclasses.is_dataclass(dc_type):
|
|
12
|
+
return create_dataclass_instance(dc_type, value)
|
|
13
|
+
elif getattr(dc_type, "__origin__", None) is list: # This is a List
|
|
14
|
+
element_type = dc_type.__args__[0]
|
|
15
|
+
return [construct_dataclass(element_type, v) for v in value]
|
|
16
|
+
else:
|
|
17
|
+
return value
|
|
18
|
+
|
|
19
|
+
return dataclass_type(
|
|
20
|
+
**{k: construct_dataclass(fields[k], v) for k, v in input_dict.items()}
|
|
21
|
+
)
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import logging.config
|
|
3
|
+
import os
|
|
4
|
+
from logging.handlers import RotatingFileHandler
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
import yaml
|
|
9
|
+
from qwak.exceptions import QwakException
|
|
10
|
+
from qwak.inner.const import QwakConstants
|
|
11
|
+
|
|
12
|
+
DEFAULT_LOGGER_NAME = "qwak"
|
|
13
|
+
REMOTE_LOGGER_NAME = "qwak_remote"
|
|
14
|
+
MODEL_LOGGER_NAME = "qwak_model"
|
|
15
|
+
FEATURE_STORE_LOGGER_NAME = "feature_store"
|
|
16
|
+
BUILD_LOCAL_LOGGER_NAME = "build_local"
|
|
17
|
+
DOCKER_INTERNAL_LOGGER_NAME = "docker_internal"
|
|
18
|
+
|
|
19
|
+
ENVIRON_LOGGER_TYPE = "LOGGER_TYPE"
|
|
20
|
+
|
|
21
|
+
BUILD_LOCAL_FILE_HANDLER_NAME = "build_log_file_handler"
|
|
22
|
+
FILE_HANDLER_NAME = "file_handler"
|
|
23
|
+
CONSOLE_HANDLER_NAME = "console"
|
|
24
|
+
REMOTE_CONSOLE_HANDLER_NAME = "remote_console"
|
|
25
|
+
|
|
26
|
+
DEFINED_LOGGER_NAMES = {
|
|
27
|
+
DEFAULT_LOGGER_NAME,
|
|
28
|
+
REMOTE_LOGGER_NAME,
|
|
29
|
+
MODEL_LOGGER_NAME,
|
|
30
|
+
FEATURE_STORE_LOGGER_NAME,
|
|
31
|
+
BUILD_LOCAL_LOGGER_NAME,
|
|
32
|
+
DOCKER_INTERNAL_LOGGER_NAME,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
VERBOSITY_LEVEL_MAPPING = {0: logging.CRITICAL, 1: logging.INFO, 2: logging.DEBUG}
|
|
36
|
+
REVERSED_VERBOSITY_LEVEL_MAPPING = {
|
|
37
|
+
value: key for key, value in VERBOSITY_LEVEL_MAPPING.items()
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
AIRFLOW_ENV_FLAG = "AIRFLOW__LOGGING__REMOTE_LOGGING"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def setup_qwak_logger(
|
|
44
|
+
default_level: int = logging.INFO,
|
|
45
|
+
logger_name_handler_addition: str = None,
|
|
46
|
+
disable_existing_loggers: bool = False,
|
|
47
|
+
):
|
|
48
|
+
"""Setup qwak logger:
|
|
49
|
+
1. Rotating file in $HOME/.qwak/log/sdk.log (10MB * 5 files) (DEBUG level)
|
|
50
|
+
2. Stdout logger with colored logs. (INFO level)
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
default_level: Default logging level in case of failure
|
|
54
|
+
logger_name_handler_addition:
|
|
55
|
+
Logger name which the handlers of will be appended to all loggers which have handlers
|
|
56
|
+
Overriding stdout stream handler if exists
|
|
57
|
+
disable_existing_loggers: disables all existing loggers
|
|
58
|
+
|
|
59
|
+
Raises:
|
|
60
|
+
QwakException: If loading logging.yml fails or the preparation of the logging environment raises an exceptions
|
|
61
|
+
|
|
62
|
+
Notes:
|
|
63
|
+
1. https://docs.python.org/3/library/logging.html#logging-levels
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
config_file = Path(__file__).parent / "logging.yml"
|
|
67
|
+
if config_file.exists() and not non_qwak_logger_enabled():
|
|
68
|
+
with config_file.open(mode="rt") as f:
|
|
69
|
+
try:
|
|
70
|
+
# Creating log directory
|
|
71
|
+
log_path = Path(QwakConstants.QWAK_CONFIG_FOLDER)
|
|
72
|
+
log_path.mkdir(parents=True, exist_ok=True)
|
|
73
|
+
# Load logger configuration
|
|
74
|
+
config = yaml.safe_load(f.read())
|
|
75
|
+
config["handlers"][FILE_HANDLER_NAME]["filename"] = str(
|
|
76
|
+
log_path / "sdk.log"
|
|
77
|
+
)
|
|
78
|
+
config["handlers"][BUILD_LOCAL_FILE_HANDLER_NAME]["filename"] = str(
|
|
79
|
+
log_path / "sdk.log"
|
|
80
|
+
)
|
|
81
|
+
config["disable_existing_loggers"] = disable_existing_loggers
|
|
82
|
+
|
|
83
|
+
logging.config.dictConfig(config)
|
|
84
|
+
|
|
85
|
+
if logger_name_handler_addition:
|
|
86
|
+
if (
|
|
87
|
+
logger_name_handler_addition
|
|
88
|
+
in logging.Logger.manager.loggerDict
|
|
89
|
+
):
|
|
90
|
+
_add_logger_handlers(logger_name_handler_addition)
|
|
91
|
+
else:
|
|
92
|
+
print(
|
|
93
|
+
"Tried to set orphan loggers handlers with a non-existing logger name handlers'"
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
except Exception as e:
|
|
97
|
+
raise QwakException(
|
|
98
|
+
f"Error in Logging Configuration. Error message: {e}"
|
|
99
|
+
)
|
|
100
|
+
else:
|
|
101
|
+
logging.basicConfig(level=default_level)
|
|
102
|
+
print("Failed to load configuration file. Using default configs")
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _add_logger_handlers(logger_name):
|
|
106
|
+
"""
|
|
107
|
+
Add a specific logger handlers to all loggers
|
|
108
|
+
Override loggers StreamHandler handlers if the input logger has a StreamHandler
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
logger_name: logger name which consists of the handlers we wish to set
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
logger_handlers = logging.getLogger(logger_name).handlers
|
|
115
|
+
base_contains_stdout = any(
|
|
116
|
+
[
|
|
117
|
+
handler
|
|
118
|
+
for handler in logger_handlers
|
|
119
|
+
if type(handler) is logging.StreamHandler
|
|
120
|
+
]
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
for logger in [
|
|
124
|
+
logger
|
|
125
|
+
for logger in logging.Logger.manager.loggerDict.values()
|
|
126
|
+
if not isinstance(logger, logging.PlaceHolder)
|
|
127
|
+
]:
|
|
128
|
+
if logger.handlers:
|
|
129
|
+
logger.handlers = [
|
|
130
|
+
handler
|
|
131
|
+
for handler in logger.handlers
|
|
132
|
+
if base_contains_stdout and type(handler) is not logging.StreamHandler
|
|
133
|
+
] + logger_handlers
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def get_qwak_logger(
|
|
137
|
+
logger_name: Optional[str] = None, fallback_logger_name: Optional[str] = None
|
|
138
|
+
) -> logging.Logger:
|
|
139
|
+
"""Get qwak logger (Singleton)
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
logging.Logger: Qwak logger.
|
|
143
|
+
"""
|
|
144
|
+
if not logger_name:
|
|
145
|
+
logger_name = get_qwak_logger_name(fallback_logger_name)
|
|
146
|
+
|
|
147
|
+
if (logger_name not in DEFINED_LOGGER_NAMES) and not non_qwak_logger_enabled:
|
|
148
|
+
print("Failed to get requested logger name. Using default logger")
|
|
149
|
+
|
|
150
|
+
return logging.getLogger(logger_name)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def set_qwak_logger_stdout_verbosity_level(verbose: int, format: str = "text"):
|
|
154
|
+
"""Set qwak stdout to verbose (a.k.a DEBUG level)
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
verbose: Log verbosity level - 0: WARNING, 1:INFO, 2: DEBUG
|
|
158
|
+
|
|
159
|
+
Notes:
|
|
160
|
+
1. https://docs.python.org/3/library/logging.html#logging-levels
|
|
161
|
+
"""
|
|
162
|
+
if format == "json":
|
|
163
|
+
verbose = 0
|
|
164
|
+
logger: logging.Logger = get_qwak_logger()
|
|
165
|
+
logger.setLevel(VERBOSITY_LEVEL_MAPPING[verbose])
|
|
166
|
+
for handler in logger.handlers:
|
|
167
|
+
if isinstance(handler, logging.StreamHandler):
|
|
168
|
+
handler.setLevel(VERBOSITY_LEVEL_MAPPING[verbose])
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def get_qwak_logger_verbosity_level() -> Optional[int]:
|
|
172
|
+
"""Get current Qwak logger level.
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
int: Qwak logger level 10 < level < 50.
|
|
176
|
+
|
|
177
|
+
Notes:
|
|
178
|
+
1. https://docs.python.org/3/library/logging.html#logging-levels
|
|
179
|
+
2. when we update the log level through set_qwak_logger_stdout_verbosity_level we update all handler levels
|
|
180
|
+
thus returning the first stream handler should be correct
|
|
181
|
+
"""
|
|
182
|
+
|
|
183
|
+
logger: logging.Logger = get_qwak_logger()
|
|
184
|
+
|
|
185
|
+
for handler in logger.handlers:
|
|
186
|
+
if isinstance(handler, logging.StreamHandler):
|
|
187
|
+
return logging.getLevelName(handler.level)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def set_qwak_logger_propagate(prop: bool):
|
|
191
|
+
"""Set qwak logger propagation
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
prop: True if propagate else False
|
|
195
|
+
|
|
196
|
+
"""
|
|
197
|
+
get_qwak_logger().propagate = prop
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def translate_to_qwak_verbosity_level(loglevel: int) -> Optional[int]:
|
|
201
|
+
"""Get qwak equivalent of the logging verbosity levels
|
|
202
|
+
|
|
203
|
+
Args:
|
|
204
|
+
loglevel: logging log level int
|
|
205
|
+
"""
|
|
206
|
+
return REVERSED_VERBOSITY_LEVEL_MAPPING.get(loglevel, None)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def get_qwak_logger_name(fallback_logger_name: Optional[str] = None):
|
|
210
|
+
if fallback_logger_name:
|
|
211
|
+
return os.getenv(ENVIRON_LOGGER_TYPE, fallback_logger_name)
|
|
212
|
+
else:
|
|
213
|
+
return os.getenv(ENVIRON_LOGGER_TYPE, DEFAULT_LOGGER_NAME)
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def get_handler_from_logger(
|
|
217
|
+
logger: logging.Logger, handler_name: str
|
|
218
|
+
) -> logging.Handler:
|
|
219
|
+
matching_handlers = list(
|
|
220
|
+
filter(lambda h: h.get_name() == handler_name, logger.handlers)
|
|
221
|
+
)
|
|
222
|
+
if len(matching_handlers) == 0 and not non_qwak_logger_enabled:
|
|
223
|
+
raise QwakException(
|
|
224
|
+
f"Error in setting log file. Error message: handler of name {handler_name} was not found in logger"
|
|
225
|
+
)
|
|
226
|
+
elif len(matching_handlers) > 1:
|
|
227
|
+
raise QwakException(
|
|
228
|
+
f"Error in setting log file. Error message: handler of name {handler_name} was found more than once "
|
|
229
|
+
f"in logger"
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
return matching_handlers[0]
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def set_file_handler_log_file(
|
|
236
|
+
logger: logging.Logger, handler_name: str, log_file: Path
|
|
237
|
+
):
|
|
238
|
+
existing_handler = get_handler_from_logger(logger, handler_name)
|
|
239
|
+
if type(existing_handler) != RotatingFileHandler:
|
|
240
|
+
raise QwakException(
|
|
241
|
+
f"Error in setting log file. Error message: handler of name {handler_name} is not a file logger handler"
|
|
242
|
+
)
|
|
243
|
+
replacement_handler: RotatingFileHandler = copy_file_handler_from_existing(
|
|
244
|
+
existing_handler, log_file
|
|
245
|
+
)
|
|
246
|
+
logger.removeHandler(existing_handler)
|
|
247
|
+
logger.addHandler(replacement_handler)
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def copy_file_handler_from_existing(
|
|
251
|
+
handler: RotatingFileHandler, log_file: Path
|
|
252
|
+
) -> RotatingFileHandler:
|
|
253
|
+
return RotatingFileHandler(
|
|
254
|
+
log_file,
|
|
255
|
+
mode=handler.mode,
|
|
256
|
+
maxBytes=int(handler.maxBytes),
|
|
257
|
+
backupCount=int(handler.backupCount),
|
|
258
|
+
encoding=handler.encoding,
|
|
259
|
+
delay=handler.delay,
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
def set_handler_verbosity(logger: logging.Logger, handler_name: str, log_level: int):
|
|
264
|
+
handler = get_handler_from_logger(logger, handler_name)
|
|
265
|
+
handler.setLevel(log_level)
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def non_qwak_logger_enabled():
|
|
269
|
+
return os.getenv(AIRFLOW_ENV_FLAG) is not None
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
version: 1
|
|
2
|
+
disable_existing_loggers: false
|
|
3
|
+
|
|
4
|
+
formatters:
|
|
5
|
+
brief:
|
|
6
|
+
format: '%(message)s'
|
|
7
|
+
semi_precise:
|
|
8
|
+
format: "%(asctime)s [%(levelname)-5.5s] %(message)s"
|
|
9
|
+
datefmt: '%Y-%m-%d %H:%M:%S'
|
|
10
|
+
precise:
|
|
11
|
+
format: '%(asctime)s %(levelname)-8s %(module)s - %(lineno)d - %(message)s'
|
|
12
|
+
datefmt: '%Y-%m-%d %H:%M:%S'
|
|
13
|
+
remote:
|
|
14
|
+
class: pythonjsonlogger.json.JsonFormatter
|
|
15
|
+
format: '%(asctime)s %(process)d %(levelname)s %(module)s %(lineno)d %(message)s'
|
|
16
|
+
datefmt: '%Y-%m-%dT%H:%M:%S'
|
|
17
|
+
json:
|
|
18
|
+
class: pythonjsonlogger.json.JsonFormatter
|
|
19
|
+
format: '%(asctime)s %(process)d %(levelname)s %(module)s %(lineno)d %(message)s'
|
|
20
|
+
datefmt: '%Y-%m-%dT%H:%M:%S'
|
|
21
|
+
|
|
22
|
+
handlers:
|
|
23
|
+
console:
|
|
24
|
+
class : logging.StreamHandler
|
|
25
|
+
formatter: brief
|
|
26
|
+
level : INFO
|
|
27
|
+
stream : ext://sys.stdout
|
|
28
|
+
file_handler:
|
|
29
|
+
class: logging.handlers.RotatingFileHandler
|
|
30
|
+
level: DEBUG
|
|
31
|
+
formatter: precise
|
|
32
|
+
filename: ""
|
|
33
|
+
maxBytes: 10485760 # 10MB
|
|
34
|
+
backupCount: 5
|
|
35
|
+
encoding: utf8
|
|
36
|
+
remote_console:
|
|
37
|
+
class: logging.StreamHandler
|
|
38
|
+
formatter: remote
|
|
39
|
+
level: DEBUG
|
|
40
|
+
stream: ext://sys.stdout
|
|
41
|
+
model:
|
|
42
|
+
class: logging.StreamHandler
|
|
43
|
+
formatter: json
|
|
44
|
+
level: INFO
|
|
45
|
+
stream: ext://sys.stdout
|
|
46
|
+
build_log_file_handler:
|
|
47
|
+
class: logging.handlers.RotatingFileHandler
|
|
48
|
+
level: DEBUG
|
|
49
|
+
formatter: semi_precise
|
|
50
|
+
filename: ""
|
|
51
|
+
maxBytes: 10485760 # 10MB
|
|
52
|
+
backupCount: 5
|
|
53
|
+
encoding: utf8
|
|
54
|
+
|
|
55
|
+
loggers:
|
|
56
|
+
qwak:
|
|
57
|
+
level: DEBUG
|
|
58
|
+
handlers: [console, file_handler]
|
|
59
|
+
propagate: false
|
|
60
|
+
qwak_remote:
|
|
61
|
+
level: DEBUG
|
|
62
|
+
handlers: [remote_console]
|
|
63
|
+
propagate: false
|
|
64
|
+
qwak_model:
|
|
65
|
+
level: DEBUG
|
|
66
|
+
handlers: [model]
|
|
67
|
+
propagate: false
|
|
68
|
+
feature_store:
|
|
69
|
+
level: DEBUG
|
|
70
|
+
handlers: [model]
|
|
71
|
+
propagate: false
|
|
72
|
+
build_local:
|
|
73
|
+
level: DEBUG
|
|
74
|
+
handlers: [build_log_file_handler, console]
|
|
75
|
+
propagate: false
|
|
76
|
+
docker_internal:
|
|
77
|
+
level: DEBUG
|
|
78
|
+
handlers: [console]
|
|
79
|
+
propagate: false
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import platform
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
import requests
|
|
6
|
+
|
|
7
|
+
from qwak_sdk import __version__ as sdk_version
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _amplitude_url():
|
|
13
|
+
return "https://api2.amplitude.com/2/httpapi"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _platform_info():
|
|
17
|
+
return platform.platform()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _python_version():
|
|
21
|
+
return "{major}.{minor}.{micro}".format(
|
|
22
|
+
major=sys.version_info.major,
|
|
23
|
+
minor=sys.version_info.minor,
|
|
24
|
+
micro=sys.version_info.micro,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def log_event(properties, user_id):
|
|
29
|
+
properties["sdk_version"] = sdk_version
|
|
30
|
+
properties["python_version"] = _python_version()
|
|
31
|
+
properties["platform_info"] = _platform_info()
|
|
32
|
+
|
|
33
|
+
event = [
|
|
34
|
+
{
|
|
35
|
+
"event_type": "sdk-event",
|
|
36
|
+
"user_id": user_id,
|
|
37
|
+
"event_properties": properties,
|
|
38
|
+
"ip": "$remote",
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
event_data = {"events": event}
|
|
43
|
+
|
|
44
|
+
try:
|
|
45
|
+
return requests.post(_amplitude_url(), json=event_data, timeout=1)
|
|
46
|
+
except Exception as e:
|
|
47
|
+
logger.debug(str(e))
|
qwak_sdk/main.py
ADDED
|
File without changes
|
qwak_sdk/tools/colors.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
class Color:
|
|
2
|
+
PURPLE = "\033[95m"
|
|
3
|
+
CYAN = "\033[96m"
|
|
4
|
+
WHITE = "\033[97m"
|
|
5
|
+
GREY = "\033[98m"
|
|
6
|
+
DARKCYAN = "\033[36m"
|
|
7
|
+
BLUE = "\033[94m"
|
|
8
|
+
GREEN = "\033[92m"
|
|
9
|
+
YELLOW = "\033[93m"
|
|
10
|
+
RED = "\033[91m"
|
|
11
|
+
BOLD = "\033[1m"
|
|
12
|
+
UNDERLINE = "\033[4m"
|
|
13
|
+
END = "\033[0m"
|