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.

Files changed (305) hide show
  1. qwak_sdk/__init__.py +9 -0
  2. qwak_sdk/cli.py +51 -0
  3. qwak_sdk/commands/admin/__init__.py +0 -0
  4. qwak_sdk/commands/admin/admin_commands_group.py +17 -0
  5. qwak_sdk/commands/admin/apikeys/__init__.py +0 -0
  6. qwak_sdk/commands/admin/apikeys/api_keys_commands_group.py +17 -0
  7. qwak_sdk/commands/admin/apikeys/generate/__init__.py +0 -0
  8. qwak_sdk/commands/admin/apikeys/generate/_logic.py +21 -0
  9. qwak_sdk/commands/admin/apikeys/generate/ui.py +45 -0
  10. qwak_sdk/commands/admin/apikeys/revoke/__init__.py +0 -0
  11. qwak_sdk/commands/admin/apikeys/revoke/_logic.py +22 -0
  12. qwak_sdk/commands/admin/apikeys/revoke/ui.py +31 -0
  13. qwak_sdk/commands/audience/__init__.py +0 -0
  14. qwak_sdk/commands/audience/_logic/__init__.py +0 -0
  15. qwak_sdk/commands/audience/_logic/config/__init__.py +0 -0
  16. qwak_sdk/commands/audience/_logic/config/config_base.py +16 -0
  17. qwak_sdk/commands/audience/_logic/config/parser.py +28 -0
  18. qwak_sdk/commands/audience/_logic/config/v1/__init__.py +0 -0
  19. qwak_sdk/commands/audience/_logic/config/v1/audience_config.py +26 -0
  20. qwak_sdk/commands/audience/_logic/config/v1/conditions_config.py +60 -0
  21. qwak_sdk/commands/audience/_logic/config/v1/config_v1.py +24 -0
  22. qwak_sdk/commands/audience/_logic/config/v1/route_config.py +14 -0
  23. qwak_sdk/commands/audience/_logic/config/v1/spec.py +11 -0
  24. qwak_sdk/commands/auto_scalling/__init__.py +0 -0
  25. qwak_sdk/commands/auto_scalling/_logic/__init__.py +0 -0
  26. qwak_sdk/commands/auto_scalling/_logic/config/__init__.py +3 -0
  27. qwak_sdk/commands/auto_scalling/_logic/config/config.py +100 -0
  28. qwak_sdk/commands/auto_scalling/_logic/config/parser.py +21 -0
  29. qwak_sdk/commands/auto_scalling/attach/__init__.py +0 -0
  30. qwak_sdk/commands/auto_scalling/attach/_logic.py +43 -0
  31. qwak_sdk/commands/auto_scalling/attach/ui.py +21 -0
  32. qwak_sdk/commands/auto_scalling/autoscaling_commands_group.py +15 -0
  33. qwak_sdk/commands/automations/__init__.py +0 -0
  34. qwak_sdk/commands/automations/automations_commands_group.py +30 -0
  35. qwak_sdk/commands/automations/delete/__init__.py +0 -0
  36. qwak_sdk/commands/automations/delete/_logic.py +6 -0
  37. qwak_sdk/commands/automations/delete/ui.py +23 -0
  38. qwak_sdk/commands/automations/executions/__init__.py +0 -0
  39. qwak_sdk/commands/automations/executions/executions_commands_group.py +14 -0
  40. qwak_sdk/commands/automations/executions/list/__init__.py +0 -0
  41. qwak_sdk/commands/automations/executions/list/_logic.py +8 -0
  42. qwak_sdk/commands/automations/executions/list/ui.py +25 -0
  43. qwak_sdk/commands/automations/list/__init__.py +0 -0
  44. qwak_sdk/commands/automations/list/_logic.py +8 -0
  45. qwak_sdk/commands/automations/list/ui.py +21 -0
  46. qwak_sdk/commands/automations/register/__init__.py +0 -0
  47. qwak_sdk/commands/automations/register/_logic.py +43 -0
  48. qwak_sdk/commands/automations/register/ui.py +44 -0
  49. qwak_sdk/commands/feature_store/__init__.py +0 -0
  50. qwak_sdk/commands/feature_store/delete/__init__.py +0 -0
  51. qwak_sdk/commands/feature_store/delete/_logic.py +52 -0
  52. qwak_sdk/commands/feature_store/delete/ui.py +40 -0
  53. qwak_sdk/commands/feature_store/feature_store_command_group.py +25 -0
  54. qwak_sdk/commands/feature_store/list/__init__.py +0 -0
  55. qwak_sdk/commands/feature_store/list/ui.py +140 -0
  56. qwak_sdk/commands/feature_store/pause/__init__.py +0 -0
  57. qwak_sdk/commands/feature_store/pause/ui.py +18 -0
  58. qwak_sdk/commands/feature_store/register/__init__.py +0 -0
  59. qwak_sdk/commands/feature_store/register/_logic.py +289 -0
  60. qwak_sdk/commands/feature_store/register/ui.py +105 -0
  61. qwak_sdk/commands/feature_store/resume/__init__.py +0 -0
  62. qwak_sdk/commands/feature_store/resume/ui.py +18 -0
  63. qwak_sdk/commands/feature_store/trigger/__init__.py +0 -0
  64. qwak_sdk/commands/feature_store/trigger/ui.py +32 -0
  65. qwak_sdk/commands/models/__init__.py +0 -0
  66. qwak_sdk/commands/models/_logic/__init__.py +0 -0
  67. qwak_sdk/commands/models/_logic/variations.py +55 -0
  68. qwak_sdk/commands/models/build/__init__.py +0 -0
  69. qwak_sdk/commands/models/build/_logic/__init__.py +0 -0
  70. qwak_sdk/commands/models/build/_logic/build_steps.py +68 -0
  71. qwak_sdk/commands/models/build/_logic/client_logs/__init__.py +0 -0
  72. qwak_sdk/commands/models/build/_logic/client_logs/build_run_handlers.py +189 -0
  73. qwak_sdk/commands/models/build/_logic/client_logs/cli_ui.py +125 -0
  74. qwak_sdk/commands/models/build/_logic/client_logs/logger.py +88 -0
  75. qwak_sdk/commands/models/build/_logic/client_logs/messages.py +40 -0
  76. qwak_sdk/commands/models/build/_logic/client_logs/notifier_impl.py +49 -0
  77. qwak_sdk/commands/models/build/_logic/client_logs/spinner.py +14 -0
  78. qwak_sdk/commands/models/build/_logic/client_logs/time_source.py +37 -0
  79. qwak_sdk/commands/models/build/_logic/client_logs/utils.py +12 -0
  80. qwak_sdk/commands/models/build/_logic/config/config_v1.py +253 -0
  81. qwak_sdk/commands/models/build/_logic/constant/host_resource.py +4 -0
  82. qwak_sdk/commands/models/build/_logic/constant/step_description.py +29 -0
  83. qwak_sdk/commands/models/build/_logic/constant/temp_dir.py +2 -0
  84. qwak_sdk/commands/models/build/_logic/constant/upload_tag.py +5 -0
  85. qwak_sdk/commands/models/build/_logic/context.py +62 -0
  86. qwak_sdk/commands/models/build/_logic/interface/__init__.py +0 -0
  87. qwak_sdk/commands/models/build/_logic/interface/notifier_interface.py +29 -0
  88. qwak_sdk/commands/models/build/_logic/interface/step_inteface.py +29 -0
  89. qwak_sdk/commands/models/build/_logic/phase/__init__.py +0 -0
  90. qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/__init__.py +14 -0
  91. qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/fetch_model_step/__init__.py +0 -0
  92. qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/fetch_model_step/fetch_model_step.py +42 -0
  93. qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/fetch_model_step/fetch_strategy_manager/__init__.py +0 -0
  94. qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/fetch_model_step/fetch_strategy_manager/common.py +33 -0
  95. qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/fetch_model_step/fetch_strategy_manager/fetch_strategy_manager.py +60 -0
  96. qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/fetch_model_step/fetch_strategy_manager/strategy/__init__.py +0 -0
  97. qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/fetch_model_step/fetch_strategy_manager/strategy/folder/__init__.py +0 -0
  98. qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/fetch_model_step/fetch_strategy_manager/strategy/folder/folder_strategy.py +73 -0
  99. qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/fetch_model_step/fetch_strategy_manager/strategy/git/__init__.py +0 -0
  100. qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/fetch_model_step/fetch_strategy_manager/strategy/git/git_strategy.py +149 -0
  101. qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/fetch_model_step/fetch_strategy_manager/strategy/strategy.py +69 -0
  102. qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/fetch_model_step/fetch_strategy_manager/strategy/zip/__init__.py +0 -0
  103. qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/fetch_model_step/fetch_strategy_manager/strategy/zip/zip_strategy.py +64 -0
  104. qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/post_fetch_validation_step.py +117 -0
  105. qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/pre_fetch_validation_step.py +135 -0
  106. qwak_sdk/commands/models/build/_logic/phase/b_remote_register_qwak_build/__init__.py +11 -0
  107. qwak_sdk/commands/models/build/_logic/phase/b_remote_register_qwak_build/cleanup_step.py +20 -0
  108. qwak_sdk/commands/models/build/_logic/phase/b_remote_register_qwak_build/start_remote_build_step.py +42 -0
  109. qwak_sdk/commands/models/build/_logic/phase/b_remote_register_qwak_build/upload_step.py +349 -0
  110. qwak_sdk/commands/models/build/_logic/phase/c_deploy/__init__.py +6 -0
  111. qwak_sdk/commands/models/build/_logic/phase/c_deploy/build_polling_status.py +54 -0
  112. qwak_sdk/commands/models/build/_logic/phase/c_deploy/deploy_build.py +44 -0
  113. qwak_sdk/commands/models/build/_logic/util/__init__.py +0 -0
  114. qwak_sdk/commands/models/build/_logic/util/protobuf_factory.py +45 -0
  115. qwak_sdk/commands/models/build/_logic/util/step_decorator.py +37 -0
  116. qwak_sdk/commands/models/build/_logic/util/text.py +9 -0
  117. qwak_sdk/commands/models/build/ui.py +241 -0
  118. qwak_sdk/commands/models/builds/__init__.py +0 -0
  119. qwak_sdk/commands/models/builds/builds_commands_group.py +16 -0
  120. qwak_sdk/commands/models/builds/cancel/__init__.py +0 -0
  121. qwak_sdk/commands/models/builds/cancel/_logic.py +5 -0
  122. qwak_sdk/commands/models/builds/cancel/ui.py +15 -0
  123. qwak_sdk/commands/models/builds/logs/__init__.py +0 -0
  124. qwak_sdk/commands/models/builds/logs/ui.py +35 -0
  125. qwak_sdk/commands/models/builds/status/__init__.py +0 -0
  126. qwak_sdk/commands/models/builds/status/_logic.py +6 -0
  127. qwak_sdk/commands/models/builds/status/ui.py +30 -0
  128. qwak_sdk/commands/models/create/__init__.py +0 -0
  129. qwak_sdk/commands/models/create/_logic.py +35 -0
  130. qwak_sdk/commands/models/create/ui.py +27 -0
  131. qwak_sdk/commands/models/delete/__init__.py +0 -0
  132. qwak_sdk/commands/models/delete/_logic.py +5 -0
  133. qwak_sdk/commands/models/delete/ui.py +16 -0
  134. qwak_sdk/commands/models/deployments/__init__.py +0 -0
  135. qwak_sdk/commands/models/deployments/deploy/__init__.py +0 -0
  136. qwak_sdk/commands/models/deployments/deploy/_logic/__init__.py +0 -0
  137. qwak_sdk/commands/models/deployments/deploy/_logic/advance_deployment_options_handler.py +31 -0
  138. qwak_sdk/commands/models/deployments/deploy/_logic/base_deploy_executor.py +64 -0
  139. qwak_sdk/commands/models/deployments/deploy/_logic/deploy_config.py +241 -0
  140. qwak_sdk/commands/models/deployments/deploy/_logic/deployment.py +405 -0
  141. qwak_sdk/commands/models/deployments/deploy/_logic/deployment_message_helpers.py +98 -0
  142. qwak_sdk/commands/models/deployments/deploy/_logic/deployment_response_handler.py +154 -0
  143. qwak_sdk/commands/models/deployments/deploy/_logic/deployment_size_mapper.py +21 -0
  144. qwak_sdk/commands/models/deployments/deploy/_logic/get_latest_successful_build.py +31 -0
  145. qwak_sdk/commands/models/deployments/deploy/_logic/variations.py +79 -0
  146. qwak_sdk/commands/models/deployments/deploy/batch/__init__.py +0 -0
  147. qwak_sdk/commands/models/deployments/deploy/batch/_logic/__init__.py +0 -0
  148. qwak_sdk/commands/models/deployments/deploy/batch/_logic/advanced_deployment_mapper.py +14 -0
  149. qwak_sdk/commands/models/deployments/deploy/batch/_logic/deploy_executor.py +24 -0
  150. qwak_sdk/commands/models/deployments/deploy/batch/ui.py +104 -0
  151. qwak_sdk/commands/models/deployments/deploy/deploy_commands_group.py +19 -0
  152. qwak_sdk/commands/models/deployments/deploy/realtime/__init__.py +0 -0
  153. qwak_sdk/commands/models/deployments/deploy/realtime/_logic/__init__.py +0 -0
  154. qwak_sdk/commands/models/deployments/deploy/realtime/_logic/advanced_deployment_mapper.py +20 -0
  155. qwak_sdk/commands/models/deployments/deploy/realtime/_logic/deploy_executor.py +24 -0
  156. qwak_sdk/commands/models/deployments/deploy/realtime/_logic/serving_strategy_mapper.py +105 -0
  157. qwak_sdk/commands/models/deployments/deploy/realtime/ui.py +179 -0
  158. qwak_sdk/commands/models/deployments/deploy/streaming/__init__.py +0 -0
  159. qwak_sdk/commands/models/deployments/deploy/streaming/_logic/__init__.py +0 -0
  160. qwak_sdk/commands/models/deployments/deploy/streaming/_logic/deploy_executor.py +24 -0
  161. qwak_sdk/commands/models/deployments/deploy/streaming/_logic/serving_strategy_mapper.py +38 -0
  162. qwak_sdk/commands/models/deployments/deploy/streaming/ui.py +196 -0
  163. qwak_sdk/commands/models/deployments/undeploy/__init__.py +0 -0
  164. qwak_sdk/commands/models/deployments/undeploy/_logic/__init__.py +0 -0
  165. qwak_sdk/commands/models/deployments/undeploy/_logic/request_undeploy.py +176 -0
  166. qwak_sdk/commands/models/deployments/undeploy/_logic/variations.py +74 -0
  167. qwak_sdk/commands/models/deployments/undeploy/ui.py +78 -0
  168. qwak_sdk/commands/models/executions/__init__.py +0 -0
  169. qwak_sdk/commands/models/executions/cancel/__init__.py +0 -0
  170. qwak_sdk/commands/models/executions/cancel/_logic.py +9 -0
  171. qwak_sdk/commands/models/executions/cancel/ui.py +27 -0
  172. qwak_sdk/commands/models/executions/execution_commands_group.py +24 -0
  173. qwak_sdk/commands/models/executions/report/__init__.py +0 -0
  174. qwak_sdk/commands/models/executions/report/_logic.py +14 -0
  175. qwak_sdk/commands/models/executions/report/ui.py +43 -0
  176. qwak_sdk/commands/models/executions/start/__init__.py +0 -0
  177. qwak_sdk/commands/models/executions/start/_logic.py +16 -0
  178. qwak_sdk/commands/models/executions/start/ui.py +176 -0
  179. qwak_sdk/commands/models/executions/status/__init__.py +0 -0
  180. qwak_sdk/commands/models/executions/status/_logic.py +13 -0
  181. qwak_sdk/commands/models/executions/status/ui.py +27 -0
  182. qwak_sdk/commands/models/init/__init__.py +0 -0
  183. qwak_sdk/commands/models/init/_logic/__init__.py +0 -0
  184. qwak_sdk/commands/models/init/_logic/initialize_model_structure.py +40 -0
  185. qwak_sdk/commands/models/init/_logic/template/__init__.py +0 -0
  186. qwak_sdk/commands/models/init/_logic/template/churn/__init__.py +0 -0
  187. qwak_sdk/commands/models/init/_logic/template/churn/cookiecutter.json +3 -0
  188. qwak_sdk/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/__init__.py +0 -0
  189. qwak_sdk/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/main/__init__.py +5 -0
  190. qwak_sdk/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/main/conda.yml +10 -0
  191. qwak_sdk/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/main/data.csv +1001 -0
  192. qwak_sdk/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/main/model.py +95 -0
  193. qwak_sdk/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/tests/__init__.py +0 -0
  194. qwak_sdk/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/tests/it/__init__.py +0 -0
  195. qwak_sdk/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/tests/it/test_churn.py +32 -0
  196. qwak_sdk/commands/models/init/_logic/template/credit_risk/__init__.py +0 -0
  197. qwak_sdk/commands/models/init/_logic/template/credit_risk/cookiecutter.json +3 -0
  198. qwak_sdk/commands/models/init/_logic/template/credit_risk/{{cookiecutter.model_directory}}/__init__.py +0 -0
  199. qwak_sdk/commands/models/init/_logic/template/credit_risk/{{cookiecutter.model_directory}}/main/__init__.py +5 -0
  200. qwak_sdk/commands/models/init/_logic/template/credit_risk/{{cookiecutter.model_directory}}/main/conda.yml +10 -0
  201. qwak_sdk/commands/models/init/_logic/template/credit_risk/{{cookiecutter.model_directory}}/main/data.csv +1001 -0
  202. qwak_sdk/commands/models/init/_logic/template/credit_risk/{{cookiecutter.model_directory}}/main/model.py +108 -0
  203. qwak_sdk/commands/models/init/_logic/template/general/__init__.py +0 -0
  204. qwak_sdk/commands/models/init/_logic/template/general/cookiecutter.json +6 -0
  205. qwak_sdk/commands/models/init/_logic/template/general/{{cookiecutter.model_directory}}/__init__.py +0 -0
  206. qwak_sdk/commands/models/init/_logic/template/general/{{cookiecutter.model_directory}}/{{cookiecutter.main_directory}}/__init__.py +5 -0
  207. qwak_sdk/commands/models/init/_logic/template/general/{{cookiecutter.model_directory}}/{{cookiecutter.main_directory}}/conda.yml +8 -0
  208. qwak_sdk/commands/models/init/_logic/template/general/{{cookiecutter.model_directory}}/{{cookiecutter.main_directory}}/model.py +66 -0
  209. qwak_sdk/commands/models/init/_logic/template/general/{{cookiecutter.model_directory}}/{{cookiecutter.test_directory}}/__init__.py +0 -0
  210. qwak_sdk/commands/models/init/_logic/template/general/{{cookiecutter.model_directory}}/{{cookiecutter.test_directory}}/test_qwak_model.py +5 -0
  211. qwak_sdk/commands/models/init/_logic/template/titanic/__init__.py +0 -0
  212. qwak_sdk/commands/models/init/_logic/template/titanic/cookiecutter.json +3 -0
  213. qwak_sdk/commands/models/init/_logic/template/titanic/{{cookiecutter.model_directory}}/__init__.py +0 -0
  214. qwak_sdk/commands/models/init/_logic/template/titanic/{{cookiecutter.model_directory}}/main/__init__.py +5 -0
  215. qwak_sdk/commands/models/init/_logic/template/titanic/{{cookiecutter.model_directory}}/main/conda.yml +10 -0
  216. qwak_sdk/commands/models/init/_logic/template/titanic/{{cookiecutter.model_directory}}/main/model.py +98 -0
  217. qwak_sdk/commands/models/init/_logic/template/titanic/{{cookiecutter.model_directory}}/tests/__init__.py +0 -0
  218. qwak_sdk/commands/models/init/_logic/template/titanic/{{cookiecutter.model_directory}}/tests/it/__init__.py +0 -0
  219. qwak_sdk/commands/models/init/_logic/template/titanic/{{cookiecutter.model_directory}}/tests/it/test_titanic.py +24 -0
  220. qwak_sdk/commands/models/init/_logic/template/titanic_poetry/__init__.py +0 -0
  221. qwak_sdk/commands/models/init/_logic/template/titanic_poetry/cookiecutter.json +3 -0
  222. qwak_sdk/commands/models/init/_logic/template/titanic_poetry/{{cookiecutter.model_directory}}/__init__.py +0 -0
  223. qwak_sdk/commands/models/init/_logic/template/titanic_poetry/{{cookiecutter.model_directory}}/main/__init__.py +5 -0
  224. qwak_sdk/commands/models/init/_logic/template/titanic_poetry/{{cookiecutter.model_directory}}/main/model.py +98 -0
  225. qwak_sdk/commands/models/init/_logic/template/titanic_poetry/{{cookiecutter.model_directory}}/main/pyproject.toml +18 -0
  226. qwak_sdk/commands/models/init/_logic/template/titanic_poetry/{{cookiecutter.model_directory}}/tests/__init__.py +0 -0
  227. qwak_sdk/commands/models/init/_logic/template/titanic_poetry/{{cookiecutter.model_directory}}/tests/it/__init__.py +0 -0
  228. qwak_sdk/commands/models/init/_logic/template/titanic_poetry/{{cookiecutter.model_directory}}/tests/it/test_titanic.py +25 -0
  229. qwak_sdk/commands/models/init/ui.py +61 -0
  230. qwak_sdk/commands/models/list/__init__.py +0 -0
  231. qwak_sdk/commands/models/list/_logic.py +5 -0
  232. qwak_sdk/commands/models/list/ui.py +31 -0
  233. qwak_sdk/commands/models/models_command_group.py +36 -0
  234. qwak_sdk/commands/models/runtime/__init__.py +0 -0
  235. qwak_sdk/commands/models/runtime/feedback/__init__.py +0 -0
  236. qwak_sdk/commands/models/runtime/feedback/_logic.py +81 -0
  237. qwak_sdk/commands/models/runtime/feedback/ui.py +45 -0
  238. qwak_sdk/commands/models/runtime/logs/__init__.py +0 -0
  239. qwak_sdk/commands/models/runtime/logs/ui.py +63 -0
  240. qwak_sdk/commands/models/runtime/runtime_commands_group.py +21 -0
  241. qwak_sdk/commands/models/runtime/traffic_update/__init__.py +0 -0
  242. qwak_sdk/commands/models/runtime/traffic_update/_logic/__init__.py +0 -0
  243. qwak_sdk/commands/models/runtime/traffic_update/_logic/execute_runtime_update_traffic.py +54 -0
  244. qwak_sdk/commands/models/runtime/traffic_update/_logic/variations.py +84 -0
  245. qwak_sdk/commands/models/runtime/traffic_update/ui.py +37 -0
  246. qwak_sdk/commands/models/runtime/update/__init__.py +0 -0
  247. qwak_sdk/commands/models/runtime/update/_logic.py +9 -0
  248. qwak_sdk/commands/models/runtime/update/ui.py +15 -0
  249. qwak_sdk/commands/projects/__init__.py +0 -0
  250. qwak_sdk/commands/projects/create/__init__.py +0 -0
  251. qwak_sdk/commands/projects/create/_logic.py +6 -0
  252. qwak_sdk/commands/projects/create/ui.py +21 -0
  253. qwak_sdk/commands/projects/delete/__init__.py +0 -0
  254. qwak_sdk/commands/projects/delete/_logic.py +6 -0
  255. qwak_sdk/commands/projects/delete/ui.py +15 -0
  256. qwak_sdk/commands/projects/list/__init__.py +0 -0
  257. qwak_sdk/commands/projects/list/_logic.py +6 -0
  258. qwak_sdk/commands/projects/list/ui.py +36 -0
  259. qwak_sdk/commands/projects/projects_command_group.py +19 -0
  260. qwak_sdk/commands/secrets/__init__.py +0 -0
  261. qwak_sdk/commands/secrets/delete/__init__.py +0 -0
  262. qwak_sdk/commands/secrets/delete/_logic.py +5 -0
  263. qwak_sdk/commands/secrets/delete/ui.py +21 -0
  264. qwak_sdk/commands/secrets/get/__init__.py +0 -0
  265. qwak_sdk/commands/secrets/get/_logic.py +5 -0
  266. qwak_sdk/commands/secrets/get/ui.py +17 -0
  267. qwak_sdk/commands/secrets/secrets_commands_group.py +19 -0
  268. qwak_sdk/commands/secrets/set/__init__.py +0 -0
  269. qwak_sdk/commands/secrets/set/_logic.py +5 -0
  270. qwak_sdk/commands/secrets/set/ui.py +16 -0
  271. qwak_sdk/commands/ui_tools.py +18 -0
  272. qwak_sdk/common/__init__.py +0 -0
  273. qwak_sdk/common/run_config/__init__.py +22 -0
  274. qwak_sdk/common/run_config/base.py +101 -0
  275. qwak_sdk/common/run_config/utils.py +249 -0
  276. qwak_sdk/exceptions/__init__.py +11 -0
  277. qwak_sdk/exceptions/qwak_command_exception.py +2 -0
  278. qwak_sdk/exceptions/qwak_deploy_new_build_failed.py +5 -0
  279. qwak_sdk/exceptions/qwak_general_build_exception.py +13 -0
  280. qwak_sdk/exceptions/qwak_remote_build_failed.py +5 -0
  281. qwak_sdk/exceptions/qwak_resource_not_found.py +2 -0
  282. qwak_sdk/exceptions/qwak_suggestion_exception.py +27 -0
  283. qwak_sdk/inner/__init__.py +0 -0
  284. qwak_sdk/inner/file_registry.py +97 -0
  285. qwak_sdk/inner/tools/__init__.py +0 -0
  286. qwak_sdk/inner/tools/cli_tools.py +159 -0
  287. qwak_sdk/inner/tools/config_handler.py +18 -0
  288. qwak_sdk/inner/tools/logger/__init__.py +3 -0
  289. qwak_sdk/inner/tools/logger/logger.py +269 -0
  290. qwak_sdk/inner/tools/logger/logging.yml +79 -0
  291. qwak_sdk/inner/tools/tracking.py +47 -0
  292. qwak_sdk/main.py +9 -0
  293. qwak_sdk/tools/__init__.py +0 -0
  294. qwak_sdk/tools/colors.py +13 -0
  295. qwak_sdk/tools/files.py +9 -0
  296. qwak_sdk/tools/log_handling.py +146 -0
  297. qwak_sdk/tools/utils.py +46 -0
  298. qwak_sdk-0.2.20rc0.dist-info/METADATA +42 -0
  299. qwak_sdk-0.2.20rc0.dist-info/RECORD +302 -0
  300. {qwak_sdk-0.1.0.dist-info → qwak_sdk-0.2.20rc0.dist-info}/WHEEL +1 -2
  301. qwak_sdk-0.2.20rc0.dist-info/entry_points.txt +3 -0
  302. qwak_sdk-0.1.0.dist-info/METADATA +0 -19
  303. qwak_sdk-0.1.0.dist-info/RECORD +0 -5
  304. qwak_sdk-0.1.0.dist-info/top_level.txt +0 -1
  305. {qwak-sdk → qwak_sdk/commands}/__init__.py +0 -0
@@ -0,0 +1,349 @@
1
+ from __future__ import annotations
2
+
3
+ import fnmatch
4
+ import os
5
+ import re
6
+ import shutil
7
+ from pathlib import Path
8
+ from typing import TYPE_CHECKING, Any, Iterable, List, Optional, Tuple
9
+
10
+ import requests
11
+ from qwak.exceptions import QwakException
12
+
13
+ from qwak_sdk.commands.models.build._logic.constant.temp_dir import TEMP_LOCAL_MODEL_DIR
14
+ from qwak_sdk.commands.models.build._logic.constant.upload_tag import (
15
+ BUILD_CONFIG_TAG,
16
+ MODEL_CODE_TAG,
17
+ QWAK_SDK_VERSION_TAG,
18
+ SKINNY_MODEL_CODE_TAG,
19
+ )
20
+ from qwak_sdk.commands.models.build._logic.interface.step_inteface import Step
21
+ from qwak_sdk.commands.models.build._logic.util.step_decorator import (
22
+ build_failure_handler,
23
+ )
24
+ from qwak_sdk.exceptions import QwakGeneralBuildException
25
+ from qwak_sdk.tools.files import copytree
26
+
27
+ if TYPE_CHECKING:
28
+ from qwak_sdk.commands.models.build._logic import Notifier
29
+
30
+ from qwak_sdk import __version__ as qwak_sdk_version
31
+
32
+ _MAX_FILE_SIZE_BYTES = 10000000
33
+ _IGNORED_PATTERNS = [r"\..*", r"__pycache__"]
34
+ _LOG_PREFIX = "Saving Qwak Model"
35
+ QWAK_IGNORE_FILE_NAME = ".qwakignore"
36
+
37
+ # Hidden directories setting
38
+ HIDDEN_FILES_PREFIX = "."
39
+ HIDDEN_DIRS_TO_INCLUDE = [".dvc"]
40
+
41
+
42
+ class UploadStep(Step):
43
+ def description(self) -> str:
44
+ return _LOG_PREFIX
45
+
46
+ @build_failure_handler()
47
+ def execute(self) -> None:
48
+ files_tag_iterator = self.create_files_to_upload()
49
+ files_total_size = sum(
50
+ file.stat().st_size for (file, tag) in files_tag_iterator
51
+ )
52
+ upload_so_far = 0
53
+ for file, tag in files_tag_iterator:
54
+ if file.exists():
55
+ pre_signed_url = self.upload_file(
56
+ file=file,
57
+ tag=tag,
58
+ all_files_size_to_upload=files_total_size,
59
+ read_so_far=upload_so_far,
60
+ )
61
+ upload_so_far += file.stat().st_size
62
+
63
+ if tag == MODEL_CODE_TAG:
64
+ self.context.model_code_remote_url = str(pre_signed_url).split("?")[
65
+ 0
66
+ ]
67
+
68
+ def create_files_to_upload(self) -> Tuple[List[Tuple[Path, Any]], int]:
69
+ ignored_patterns = (
70
+ load_patterns_from_ignore_file(
71
+ notifier=self.notifier,
72
+ ignore_file_path=self.context.host_temp_local_build_dir
73
+ / TEMP_LOCAL_MODEL_DIR
74
+ / self.config.build_properties.model_uri.main_dir
75
+ / QWAK_IGNORE_FILE_NAME,
76
+ )
77
+ + _IGNORED_PATTERNS
78
+ )
79
+
80
+ # copy 'main' and 'tests' directories
81
+ dirs_to_include = [self.config.build_properties.model_uri.main_dir, "tests"]
82
+ deps_folders = (
83
+ self.config.build_properties.model_uri.dependency_required_folders
84
+ )
85
+ if deps_folders:
86
+ self.notifier.debug(
87
+ f"Adding dependency folders to model code: {deps_folders}"
88
+ )
89
+ dirs_to_include += deps_folders
90
+
91
+ self.notifier.debug("Zipping skinny model code")
92
+ skinny_size_zip_file = zip_model(
93
+ build_dir=self.context.host_temp_local_build_dir,
94
+ dependency_file=self.context.model_relative_dependency_file,
95
+ dirs_to_include=dirs_to_include,
96
+ zip_name="skinny_size_model_code",
97
+ ignored_patterns=ignored_patterns,
98
+ max_bytes=_MAX_FILE_SIZE_BYTES,
99
+ )
100
+
101
+ # Full size model
102
+ self.notifier.debug("Zipping full model code")
103
+ full_size_zip_file = zip_model(
104
+ build_dir=self.context.host_temp_local_build_dir,
105
+ dependency_file=self.context.model_relative_dependency_file,
106
+ dirs_to_include=dirs_to_include,
107
+ zip_name="full_size_model_code",
108
+ ignored_patterns=ignored_patterns,
109
+ )
110
+
111
+ # Dump config file for upload
112
+ config_file_temp = self.context.host_temp_local_build_dir / "build.conf"
113
+ config_file_temp.write_text(self.config.to_yaml())
114
+
115
+ # Dump qwak-sdk version for upload
116
+ qwak_sdk_version_temp = self.context.host_temp_local_build_dir / "VERSION"
117
+ qwak_sdk_version_temp.write_text(qwak_sdk_version)
118
+
119
+ files_tag_iterator = [
120
+ (full_size_zip_file, MODEL_CODE_TAG),
121
+ (skinny_size_zip_file, SKINNY_MODEL_CODE_TAG),
122
+ (qwak_sdk_version_temp, QWAK_SDK_VERSION_TAG),
123
+ (config_file_temp, BUILD_CONFIG_TAG),
124
+ ]
125
+
126
+ return files_tag_iterator
127
+
128
+ def upload_file(
129
+ self, file: Path, tag: str, all_files_size_to_upload: int, read_so_far: int
130
+ ):
131
+ self.notifier.debug(f"Upload file {file}")
132
+
133
+ pre_signed_url = self.get_pre_signed_upload_url(tag=tag)
134
+ self.upload_file_to_s3(
135
+ upload_url=pre_signed_url,
136
+ file=file,
137
+ all_files_size_to_upload=all_files_size_to_upload,
138
+ read_so_far=read_so_far,
139
+ )
140
+
141
+ self.notifier.debug(f"Upload file {file} completed")
142
+
143
+ return pre_signed_url
144
+
145
+ def get_pre_signed_upload_url(self, tag: str) -> str:
146
+ try:
147
+ self.notifier.debug(f"Getting pre-signed url for S3 upload - tag {tag}")
148
+
149
+ pre_signed_url = (
150
+ self.context.client_builds_orchestrator.get_build_versioning_upload_url(
151
+ build_id=self.context.build_id,
152
+ model_id=self.context.model_id,
153
+ tag=tag,
154
+ ).upload_url
155
+ )
156
+
157
+ self.notifier.debug("Pre-signed url generated successfully")
158
+
159
+ return pre_signed_url
160
+ except QwakException as e:
161
+ raise QwakGeneralBuildException(
162
+ message="Unable to get pre-signed url for uploading model",
163
+ src_exception=e,
164
+ )
165
+
166
+ def upload_file_to_s3(
167
+ self,
168
+ upload_url: str,
169
+ file: Path,
170
+ all_files_size_to_upload: int,
171
+ read_so_far: int,
172
+ ):
173
+ try:
174
+ self.notifier.debug(f"Upload file {file} to Qwak storage")
175
+
176
+ http_response = requests.put( # nosec B113
177
+ url=upload_url,
178
+ data=UploadInChunks(
179
+ file=file,
180
+ notifier=self.notifier,
181
+ chunk_size_bytes=10,
182
+ all_files_size_to_upload=all_files_size_to_upload,
183
+ read_so_far=read_so_far,
184
+ ),
185
+ headers={"content-type": "text/plain"},
186
+ )
187
+ if http_response.status_code != 200:
188
+ raise QwakException(
189
+ f"Status: [{http_response.status_code}], "
190
+ f"reason: [{http_response.reason}]"
191
+ )
192
+
193
+ self.notifier.debug(f"File {file} uploaded to Qwak storage successfully")
194
+ except Exception as e:
195
+ raise QwakGeneralBuildException(
196
+ message="Fail uploading model to S3 storage.",
197
+ src_exception=e,
198
+ )
199
+
200
+
201
+ def load_patterns_from_ignore_file(notifier: Notifier, ignore_file_path: Path):
202
+ if Path(ignore_file_path).is_file():
203
+ notifier.info("Found a Qwak ignore file - will ignore listed patterns")
204
+
205
+ with open(ignore_file_path, "r") as igonre_file:
206
+ patterns_to_ignore = [
207
+ pattern.strip() for pattern in igonre_file.readlines()
208
+ ]
209
+ notifier.debug(
210
+ f"Patterns from Qwak igonre file detected - {str(patterns_to_ignore)}"
211
+ )
212
+ return patterns_to_ignore
213
+
214
+ notifier.debug("no Qwak ignore file was found, skipping")
215
+ return []
216
+
217
+
218
+ def _replace_large_files_with_too_large_file_message(
219
+ filtered_model: Path, max_bytes: Optional[int]
220
+ ):
221
+ def does_exceed_size(file: Path):
222
+ file_size = file.lstat().st_size
223
+ return file_size > max_bytes, file.lstat().st_size
224
+
225
+ if max_bytes is None:
226
+ return
227
+
228
+ for root, dirs, files in os.walk(filtered_model):
229
+ for file in files:
230
+ file_path = Path(os.path.join(root, file))
231
+ replace_content, file_size = does_exceed_size(file_path)
232
+ if replace_content:
233
+ Path(file_path).write_text(
234
+ f"File is too big to display. Size: {file_size} bytes"
235
+ )
236
+
237
+
238
+ def zip_model(
239
+ build_dir: Path,
240
+ dependency_file: Path,
241
+ dirs_to_include: list[str],
242
+ zip_name: str,
243
+ ignored_patterns: Iterable[str],
244
+ max_bytes: Optional[int] = None,
245
+ ):
246
+ try:
247
+ filtered_model = build_dir / zip_name
248
+ ignored_patterns = get_files_to_ignore(
249
+ directory=build_dir / TEMP_LOCAL_MODEL_DIR, patterns=ignored_patterns
250
+ )
251
+
252
+ for included_dir in dirs_to_include:
253
+ dir_to_copy = build_dir / TEMP_LOCAL_MODEL_DIR / included_dir
254
+ if dir_to_copy.is_dir():
255
+ copytree(
256
+ src=build_dir / TEMP_LOCAL_MODEL_DIR / included_dir,
257
+ dst=filtered_model / included_dir,
258
+ ignore=shutil.ignore_patterns(*ignored_patterns),
259
+ dirs_exist_ok=True,
260
+ )
261
+
262
+ deps_file = build_dir / TEMP_LOCAL_MODEL_DIR / dependency_file
263
+
264
+ shutil.copy(deps_file, filtered_model / dependency_file)
265
+
266
+ _replace_large_files_with_too_large_file_message(filtered_model, max_bytes)
267
+
268
+ zip_path = Path(
269
+ shutil.make_archive(
270
+ base_name=str(filtered_model),
271
+ format="zip",
272
+ root_dir=filtered_model,
273
+ )
274
+ )
275
+
276
+ shutil.rmtree(filtered_model)
277
+ return zip_path
278
+
279
+ except Exception as e:
280
+ raise QwakGeneralBuildException(
281
+ message="Unable to zip model before upload",
282
+ src_exception=e,
283
+ )
284
+
285
+
286
+ def get_files_to_ignore(directory: Path, patterns: Iterable[str] = ()):
287
+ def ignore_hidden(file: Path, exclusions: List[str]):
288
+ name = os.path.basename(os.path.abspath(file))
289
+ is_hidden = name.startswith(HIDDEN_FILES_PREFIX) and (
290
+ name != QWAK_IGNORE_FILE_NAME and name not in exclusions
291
+ )
292
+ return is_hidden
293
+
294
+ def is_ignore_by_pattern(file: Path):
295
+ return (
296
+ len(
297
+ [
298
+ pattern
299
+ for pattern in patterns
300
+ if re.search(fnmatch.translate(pattern), str(file))
301
+ ]
302
+ )
303
+ != 0
304
+ )
305
+
306
+ return [
307
+ file.name
308
+ for file in Path(directory).rglob("*")
309
+ if is_ignore_by_pattern(file)
310
+ or ignore_hidden(file, exclusions=HIDDEN_DIRS_TO_INCLUDE)
311
+ ]
312
+
313
+
314
+ class UploadInChunks(object):
315
+ def __init__(
316
+ self,
317
+ file: Path,
318
+ notifier: Notifier,
319
+ all_files_size_to_upload: int,
320
+ read_so_far: int = 0,
321
+ chunk_size_bytes: int = 1 << 13,
322
+ ):
323
+ self._file = file
324
+ self._chunk_size = chunk_size_bytes
325
+ self._total_size = self._file.stat().st_size
326
+ self._read_so_far = read_so_far
327
+ self._notifier = notifier
328
+ self._all_files_size_to_upload = (
329
+ all_files_size_to_upload # Used for calculating percentage for both files
330
+ )
331
+ self._last_percent_update = 0
332
+
333
+ def __iter__(self):
334
+ with self._file.open("rb") as file:
335
+ while True:
336
+ data = file.read(self._chunk_size)
337
+ if not data:
338
+ break
339
+ self._read_so_far += len(data)
340
+ percent = self._read_so_far * 1e2 / self._all_files_size_to_upload
341
+ msg = "{percent:3.0f}%".format(percent=percent)
342
+ if int(percent / 10) > self._last_percent_update:
343
+ self._notifier.info(msg) # Updating only after 10 percent change
344
+ self._last_percent_update = int(percent / 10)
345
+ self._notifier.spinner_text(line=msg)
346
+ yield data
347
+
348
+ def __len__(self):
349
+ return self._total_size
@@ -0,0 +1,6 @@
1
+ from .build_polling_status import BuildPollingStatusStep
2
+ from .deploy_build import DeployBuildStep
3
+
4
+
5
+ def get_deploy_stepss():
6
+ return [BuildPollingStatusStep(), DeployBuildStep()]
@@ -0,0 +1,54 @@
1
+ from __future__ import annotations
2
+
3
+ import time
4
+
5
+ from _qwak_proto.qwak.build.v1.build_api_pb2 import GetBuildResponse
6
+ from _qwak_proto.qwak.build.v1.build_pb2 import BuildStatus
7
+
8
+ from qwak_sdk.commands.models.build._logic.client_logs.messages import (
9
+ FAILED_REMOTE_BUILD_SUGGESTION,
10
+ )
11
+ from qwak_sdk.commands.models.build._logic.interface.step_inteface import Step
12
+ from qwak_sdk.exceptions.qwak_remote_build_failed import QwakRemoteBuildFailedException
13
+
14
+
15
+ class BuildPollingStatusStep(Step):
16
+ FINITE_BUILD_STATUSES = {
17
+ BuildStatus.REMOTE_BUILD_CANCELLED,
18
+ BuildStatus.REMOTE_BUILD_TIMED_OUT,
19
+ BuildStatus.FAILED,
20
+ BuildStatus.SUCCESSFUL,
21
+ }
22
+ SLEEP_BETWEEN_STATUS_CHECK = 10
23
+ REMOTE_BUILD_FAILURE_EXCEPTION_FORMAT = "Your build failed with status {status}"
24
+
25
+ def description(self) -> str:
26
+ return "Polling on Build Status"
27
+
28
+ def execute(self) -> None:
29
+ self.notifier.info("Waiting for build to finish")
30
+ status = self.wait_for_finite_build_status()
31
+ if status != BuildStatus.SUCCESSFUL:
32
+ raise QwakRemoteBuildFailedException(
33
+ message=self.REMOTE_BUILD_FAILURE_EXCEPTION_FORMAT.format(
34
+ status=BuildStatus.Name(status)
35
+ ),
36
+ suggestion=FAILED_REMOTE_BUILD_SUGGESTION.format(
37
+ build_id=self.context.build_id,
38
+ model_id=self.context.model_id,
39
+ project_uuid=self.context.project_uuid,
40
+ ),
41
+ )
42
+ self.notifier.info("Your build finished successfully")
43
+
44
+ def wait_for_finite_build_status(self) -> BuildStatus:
45
+ self.notifier.spinner_text(line="Waiting for build to finish")
46
+ while True:
47
+ result: GetBuildResponse = (
48
+ self.context.client_builds_orchestrator.get_build(self.context.build_id)
49
+ )
50
+ status: BuildStatus = result.build.build_status
51
+ if status in self.FINITE_BUILD_STATUSES:
52
+ return status
53
+ self.notifier.debug(f"Build status is currently {BuildStatus.Name(status)}")
54
+ time.sleep(self.SLEEP_BETWEEN_STATUS_CHECK)
@@ -0,0 +1,44 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Dict
4
+
5
+ from qwak_sdk.commands.models.build._logic.client_logs.messages import (
6
+ FAILED_DEPLOY_BUILD_SUGGESTION,
7
+ )
8
+ from qwak_sdk.commands.models.build._logic.interface.step_inteface import Step
9
+ from qwak_sdk.commands.models.deployments.deploy.realtime.ui import deploy_realtime
10
+ from qwak_sdk.exceptions.qwak_deploy_new_build_failed import (
11
+ QwakDeployNewBuildFailedException,
12
+ )
13
+
14
+
15
+ class DeployBuildStep(Step):
16
+ SMALL_DEPLOYMENT: Dict[str, Any] = {
17
+ "pods": 1,
18
+ "cpus": 2,
19
+ "memory": 2048,
20
+ }
21
+ DEPLOY_FAILURE_EXCEPTION_MESSAGE = "Deploying the build failed due to {e}"
22
+
23
+ def description(self) -> str:
24
+ return "Deploying Build"
25
+
26
+ def execute(self) -> None:
27
+ self.notifier.info(f"Deploying build {self.context.build_id}")
28
+ try:
29
+ deploy_config = {
30
+ "build_id": self.context.build_id,
31
+ "model_id": self.context.model_id,
32
+ }
33
+ deploy_config.update(self.SMALL_DEPLOYMENT)
34
+ deploy_realtime(from_file=None, out_conf=False, sync=False, **deploy_config)
35
+ self.notifier.info(f"Finished deploying build {self.context.build_id}")
36
+ except Exception as e:
37
+ raise QwakDeployNewBuildFailedException(
38
+ message=self.DEPLOY_FAILURE_EXCEPTION_MESSAGE.format(e=e),
39
+ suggestion=FAILED_DEPLOY_BUILD_SUGGESTION.format(
40
+ build_id=self.context.build_id,
41
+ model_id=self.context.model_id,
42
+ project_uuid=self.context.project_uuid,
43
+ ),
44
+ )
File without changes
@@ -0,0 +1,45 @@
1
+ from qwak.exceptions import QwakException
2
+
3
+
4
+ def protobuf_factory(
5
+ protobuf_class, exclude_fields=None, include_only=None, mapping=None
6
+ ):
7
+ def get_final_field_names(cls):
8
+ fields = dict(cls.__dataclass_fields__)
9
+ all_field_names = set(fields.keys())
10
+ excluded_fields = set(exclude_fields) if exclude_fields else set()
11
+ included_fields = set(include_only) if include_only else all_field_names
12
+ unrecognized_fields = included_fields.difference(all_field_names)
13
+ if unrecognized_fields:
14
+ raise QwakException(
15
+ f"Unknown fields were included: {list(unrecognized_fields)}"
16
+ )
17
+ return included_fields.difference(excluded_fields)
18
+
19
+ def protofy_decorator(cls):
20
+ if not hasattr(cls, "__dataclass_fields__"):
21
+ raise QwakException("Protofy must receive a dataclass")
22
+
23
+ fields_mapping = mapping if mapping else {}
24
+ final_field_names = get_final_field_names(cls)
25
+
26
+ def to_proto(self) -> protobuf_class:
27
+ final_fields = {}
28
+ for field_name in final_field_names:
29
+ field_val = self.__getattribute__(field_name)
30
+ field_name = (
31
+ fields_mapping[field_name]
32
+ if field_name in fields_mapping
33
+ else field_name
34
+ )
35
+ final_fields[field_name] = (
36
+ field_val.to_proto()
37
+ if hasattr(field_val, "to_proto")
38
+ else field_val
39
+ )
40
+ return protobuf_class(**final_fields)
41
+
42
+ setattr(cls, "to_proto", to_proto)
43
+ return cls
44
+
45
+ return protofy_decorator
@@ -0,0 +1,37 @@
1
+ import os
2
+ import shutil
3
+ from functools import wraps
4
+ from typing import TYPE_CHECKING
5
+
6
+ from qwak.exceptions import QuietError
7
+
8
+ from qwak_sdk.commands.models.build._logic.interface.step_inteface import Step
9
+
10
+ if TYPE_CHECKING:
11
+ from qwak_sdk.commands.models.build import Notifier
12
+
13
+
14
+ def build_failure_handler(should_fail_build: bool = True):
15
+ def _exception_handler(func):
16
+ @wraps(func)
17
+ def inner_function(*args, **kwargs):
18
+ try:
19
+ func(*args, **kwargs)
20
+ except BaseException as e:
21
+ if should_fail_build and not isinstance(e, QuietError):
22
+ notifier: Notifier = args[0].notifier
23
+ notifier.error(
24
+ "Build failed with Exception. See the stack trace above."
25
+ )
26
+ cleaning_up_after_build(args[0])
27
+ raise e
28
+
29
+ return inner_function
30
+
31
+ return _exception_handler
32
+
33
+
34
+ def cleaning_up_after_build(step: Step):
35
+ if os.getenv("QWAK_DEBUG") != "true":
36
+ step.notifier.debug("Removing Qwak temp artifacts directory")
37
+ shutil.rmtree(step.context.host_temp_local_build_dir, ignore_errors=True)
@@ -0,0 +1,9 @@
1
+ from re import sub
2
+
3
+
4
+ def snake_case(s):
5
+ return "_".join(
6
+ sub(
7
+ "([A-Z][a-z]+)", r" \1", sub("([A-Z]+)", r" \1", s.replace("-", " "))
8
+ ).split()
9
+ ).lower()