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,189 @@
1
+ import logging
2
+ from abc import ABC, abstractmethod
3
+ from pathlib import Path
4
+
5
+ from qwak.exceptions import QwakException
6
+ from yaspin.core import Yaspin
7
+
8
+ from qwak_sdk.tools.colors import Color
9
+
10
+ from .messages import (
11
+ FAILED_CONTACT_QWAK_SUPPORT,
12
+ FAILED_CONTACT_QWAK_SUPPORT_PROGRAMMATIC,
13
+ )
14
+ from .utils import zip_logs
15
+
16
+
17
+ class BuildRunHandler(ABC):
18
+ @abstractmethod
19
+ def handle_phase_in_progress(self, phase_id: str):
20
+ pass
21
+
22
+ @abstractmethod
23
+ def handle_phase_finished_successfully(
24
+ self, phase_id: str, duration_in_seconds: int
25
+ ):
26
+ pass
27
+
28
+ @abstractmethod
29
+ def handle_contact_support_error(
30
+ self, build_id: str, phase_id: str, ex: BaseException, duration_in_seconds: int
31
+ ):
32
+ pass
33
+
34
+ @abstractmethod
35
+ def handle_remote_build_error(
36
+ self, build_id: str, phase_id: str, ex: BaseException, duration_in_seconds: int
37
+ ):
38
+ pass
39
+
40
+ @abstractmethod
41
+ def handle_keyboard_interrupt(
42
+ self, build_id: str, phase_id: str, duration_in_seconds: int
43
+ ):
44
+ pass
45
+
46
+ @abstractmethod
47
+ def handle_pipeline_exception(
48
+ self, build_id: str, phase_id: str, ex: BaseException, duration_in_seconds: int
49
+ ):
50
+ pass
51
+
52
+ @abstractmethod
53
+ def handle_pipeline_quiet_exception(
54
+ self, build_id: str, phase_id: str, ex: BaseException, duration_in_seconds: int
55
+ ):
56
+ pass
57
+
58
+ def build_phase_to_human_readable_string(self, phase_id: str):
59
+ return phase_id[len("BuildPhase.") :].replace("_", " ").capitalize()
60
+
61
+
62
+ class CLIBuildRunner(BuildRunHandler):
63
+ def __init__(self, sp: Yaspin, log_path: Path):
64
+ self.sp = sp
65
+ self.log_path = str(log_path)
66
+
67
+ def handle_phase_in_progress(self, phase_id: str):
68
+ logging.debug(
69
+ f"Build phase in progress: {self.build_phase_to_human_readable_string(phase_id)}"
70
+ )
71
+
72
+ def handle_phase_finished_successfully(
73
+ self, phase_id: str, duration_in_seconds: int
74
+ ):
75
+ if self.sp:
76
+ self.sp.ok("✅")
77
+
78
+ logging.debug(
79
+ f"Phase successfully finished: {self.build_phase_to_human_readable_string(phase_id)} after {duration_in_seconds} seconds"
80
+ )
81
+
82
+ def __report_failure(self, phase_id: str, duration_in_seconds: int):
83
+ logging.debug(
84
+ f"Build phase failed: {self.build_phase_to_human_readable_string(phase_id)} after {duration_in_seconds} seconds"
85
+ )
86
+
87
+ def handle_contact_support_error(
88
+ self, build_id: str, phase_id: str, ex: BaseException, duration_in_seconds: int
89
+ ):
90
+ print(f"\n{ex}")
91
+ print(
92
+ FAILED_CONTACT_QWAK_SUPPORT.format(
93
+ build_id=build_id,
94
+ log_file=Path(self.log_path).parent / build_id,
95
+ )
96
+ )
97
+ zip_logs(log_path=self.log_path, build_id=build_id)
98
+ self.__report_failure(phase_id, duration_in_seconds)
99
+ exit(1)
100
+
101
+ def handle_remote_build_error(
102
+ self, build_id: str, phase_id: str, ex: BaseException, duration_in_seconds: int
103
+ ):
104
+ if self.sp:
105
+ self.sp.fail("💥")
106
+ print(f"\n{Color.RED}{ex}")
107
+ else:
108
+ print(f"\n{ex}")
109
+ self.__report_failure(phase_id, duration_in_seconds)
110
+ exit(1)
111
+
112
+ def handle_keyboard_interrupt(
113
+ self, build_id: str, phase_id: str, duration_in_seconds: int
114
+ ):
115
+ print(f"\n{Color.RED}Stopping Qwak build (ctrl-c)")
116
+ zip_logs(log_path=self.log_path, build_id=build_id)
117
+ self.__report_failure(phase_id, duration_in_seconds)
118
+ exit(1)
119
+
120
+ def handle_pipeline_exception(
121
+ self, build_id: str, phase_id: str, ex: BaseException, duration_in_seconds: int
122
+ ):
123
+ if self.sp:
124
+ self.sp.fail("💥")
125
+ print(f"\n{Color.RED}{ex}")
126
+ zip_logs(
127
+ log_path=self.log_path,
128
+ build_id=build_id,
129
+ )
130
+ self.__report_failure(phase_id, duration_in_seconds)
131
+ exit(1)
132
+
133
+ def handle_pipeline_quiet_exception(
134
+ self, build_id: str, phase_id: str, ex: BaseException, duration_in_seconds: int
135
+ ):
136
+ if self.sp:
137
+ self.sp.ok("‼️")
138
+ self.__report_failure(phase_id, duration_in_seconds)
139
+
140
+
141
+ class ProgrammaticBuildRunner(BuildRunHandler):
142
+ def handle_phase_in_progress(self, phase_id: str):
143
+ logging.debug(
144
+ f"Build phase in progress: {self.build_phase_to_human_readable_string(phase_id)}"
145
+ )
146
+
147
+ def handle_phase_finished_successfully(
148
+ self, phase_id: str, duration_in_seconds: int
149
+ ):
150
+ logging.debug(
151
+ f"Phase successfully finished: {self.build_phase_to_human_readable_string(phase_id)} after {duration_in_seconds} seconds"
152
+ )
153
+
154
+ def __report_failure(self, phase_id: str, duration_in_seconds: int):
155
+ logging.debug(
156
+ f"Build phase failed: {self.build_phase_to_human_readable_string(phase_id)} after {duration_in_seconds} seconds"
157
+ )
158
+
159
+ def handle_contact_support_error(
160
+ self, build_id: str, phase_id: str, ex: BaseException, duration_in_seconds: int
161
+ ):
162
+ print(
163
+ FAILED_CONTACT_QWAK_SUPPORT_PROGRAMMATIC.format(
164
+ build_id=build_id,
165
+ )
166
+ )
167
+ self.__report_failure(phase_id, duration_in_seconds)
168
+ raise QwakException(str(ex))
169
+
170
+ def handle_keyboard_interrupt(
171
+ self, build_id: str, phase_id: str, duration_in_seconds: int
172
+ ):
173
+ self.__report_failure(phase_id, duration_in_seconds)
174
+
175
+ def handle_pipeline_exception(
176
+ self, build_id: str, phase_id: str, ex: BaseException, duration_in_seconds: int
177
+ ):
178
+ self.__report_failure(phase_id, duration_in_seconds)
179
+ raise QwakException(str(ex))
180
+
181
+ def handle_pipeline_quiet_exception(
182
+ self, build_id: str, phase_id: str, ex: BaseException, duration_in_seconds: int
183
+ ):
184
+ self.__report_failure(phase_id, duration_in_seconds)
185
+
186
+ def handle_remote_build_error(
187
+ self, build_id: str, phase_id: str, ex: BaseException, duration_in_seconds: int
188
+ ):
189
+ self.handle_pipeline_exception(build_id, phase_id, ex, duration_in_seconds)
@@ -0,0 +1,125 @@
1
+ from typing import Tuple
2
+
3
+ from qwak.exceptions import QuietError
4
+
5
+ from qwak_sdk.commands.models.build._logic.context import Context
6
+ from qwak_sdk.exceptions import QwakGeneralBuildException
7
+ from qwak_sdk.exceptions.qwak_remote_build_failed import QwakRemoteBuildFailedException
8
+
9
+ from ..build_steps import StepsPipeline, remote_build_steps
10
+ from ..config.config_v1 import ConfigV1
11
+ from ..interface.notifier_interface import Notifier
12
+ from .build_run_handlers import BuildRunHandler, CLIBuildRunner, ProgrammaticBuildRunner
13
+ from .logger import build_logger
14
+ from .messages import SUCCESS_MSG_REMOTE, SUCCESS_MSG_REMOTE_WITH_DEPLOY
15
+ from .notifier_impl import NotifierImpl
16
+ from .spinner import spinner
17
+ from .time_source import Stopwatch, SystemClockTimeSource, TimeSource
18
+ from .utils import zip_logs
19
+
20
+
21
+ def execute_build_pipeline(
22
+ config: ConfigV1,
23
+ json_logs: bool,
24
+ programmatic: bool = False,
25
+ ):
26
+ with build_logger(config=config, json_logs=json_logs) as (
27
+ logger,
28
+ log_path,
29
+ ):
30
+ pipeline, success_msg = create_pipeline(config)
31
+
32
+ time_source = SystemClockTimeSource()
33
+ for phase in pipeline.phases:
34
+ phase_details = phase.get_phase_details()
35
+ notifier = NotifierImpl(
36
+ logger,
37
+ prefix="" if json_logs else phase_details.get_description(),
38
+ phase_details=phase_details,
39
+ )
40
+
41
+ if programmatic:
42
+ build_runner = ProgrammaticBuildRunner()
43
+ phase_run(phase, pipeline.context, build_runner, notifier, time_source)
44
+ else:
45
+ with spinner(
46
+ text=phase_details.get_description(),
47
+ show=(config.verbose == 0 and not json_logs),
48
+ ) as sp:
49
+ notifier.set_spinner(sp)
50
+ build_runner = CLIBuildRunner(sp, log_path)
51
+ phase_run(
52
+ phase, pipeline.context, build_runner, notifier, time_source
53
+ )
54
+
55
+ print(
56
+ success_msg.format(
57
+ build_id=pipeline.context.build_id,
58
+ model_id=pipeline.context.model_id,
59
+ project_uuid=pipeline.context.project_uuid,
60
+ )
61
+ )
62
+ zip_logs(log_path=log_path, build_id=pipeline.context.build_id)
63
+
64
+ return pipeline.context.build_id
65
+
66
+
67
+ def phase_run(
68
+ phase: StepsPipeline,
69
+ context: Context,
70
+ build_runner: BuildRunHandler,
71
+ notifier: Notifier,
72
+ time_source: TimeSource,
73
+ ):
74
+ build_id = context.build_id
75
+ current_step_phase = None
76
+ stop_watch = Stopwatch(time_source)
77
+ try:
78
+ for step in phase.steps:
79
+ current_step_phase = str(step.build_phase)
80
+ step.set_notifier(notifier)
81
+ build_runner.handle_phase_in_progress(current_step_phase)
82
+
83
+ step.execute()
84
+
85
+ phase_duration = stop_watch.elapsed_time_in_seconds()
86
+ build_runner.handle_phase_finished_successfully(
87
+ current_step_phase, phase_duration
88
+ )
89
+ except QwakGeneralBuildException as e:
90
+ phase_duration = stop_watch.elapsed_time_in_seconds()
91
+ build_runner.handle_contact_support_error(
92
+ build_id, current_step_phase, e, phase_duration
93
+ )
94
+ except QwakRemoteBuildFailedException as e:
95
+ phase_duration = stop_watch.elapsed_time_in_seconds()
96
+ build_runner.handle_remote_build_error(
97
+ build_id, current_step_phase, e, phase_duration
98
+ )
99
+ except KeyboardInterrupt:
100
+ phase_duration = stop_watch.elapsed_time_in_seconds()
101
+ build_runner.handle_keyboard_interrupt(
102
+ build_id, current_step_phase, phase_duration
103
+ )
104
+ except BaseException as e:
105
+ notifier.exception("Failed", e)
106
+ phase_duration = stop_watch.elapsed_time_in_seconds()
107
+ if not isinstance(e, QuietError):
108
+ build_runner.handle_pipeline_exception(
109
+ build_id, current_step_phase, e, phase_duration
110
+ )
111
+ else:
112
+ build_runner.handle_pipeline_quiet_exception(
113
+ build_id, current_step_phase, e, phase_duration
114
+ )
115
+
116
+
117
+ def create_pipeline(
118
+ config: ConfigV1,
119
+ ) -> Tuple[StepsPipeline, str]:
120
+ success_message = (
121
+ SUCCESS_MSG_REMOTE_WITH_DEPLOY if config.deploy else SUCCESS_MSG_REMOTE
122
+ )
123
+ pipeline = remote_build_steps(config)
124
+
125
+ return pipeline, success_message
@@ -0,0 +1,88 @@
1
+ import contextlib
2
+ import logging
3
+ import os
4
+ import platform
5
+ import shutil
6
+ import sys
7
+ import uuid
8
+ from pathlib import Path
9
+
10
+ from qwak_sdk import __version__ as qwak_sdk_version
11
+ from qwak_sdk.commands.models.build._logic.config.config_v1 import ConfigV1
12
+ from qwak_sdk.commands.models.build._logic.constant.host_resource import (
13
+ HOST_QWAK_HIDDEN_FOLDER,
14
+ )
15
+ from qwak_sdk.inner.tools.logger import setup_qwak_logger
16
+ from qwak_sdk.inner.tools.logger.logger import (
17
+ BUILD_LOCAL_FILE_HANDLER_NAME,
18
+ BUILD_LOCAL_LOGGER_NAME,
19
+ CONSOLE_HANDLER_NAME,
20
+ REMOTE_CONSOLE_HANDLER_NAME,
21
+ REMOTE_LOGGER_NAME,
22
+ VERBOSITY_LEVEL_MAPPING,
23
+ get_qwak_logger,
24
+ non_qwak_logger_enabled,
25
+ set_file_handler_log_file,
26
+ set_handler_verbosity,
27
+ )
28
+
29
+ BUILDS_LOGS = HOST_QWAK_HIDDEN_FOLDER / "logs" / "build"
30
+ BUILD_LOG_NAME = "build.log"
31
+ MAX_LOGS_NUMBER = 15
32
+
33
+
34
+ @contextlib.contextmanager
35
+ def build_logger(config: ConfigV1, json_logs: bool):
36
+ log_path = BUILDS_LOGS / config.build_properties.model_id / str(uuid.uuid4())[:4]
37
+ log_path.mkdir(parents=True, exist_ok=True)
38
+ try:
39
+ (log_path / "build_config.yml").write_text(config.to_yaml())
40
+ log_system_information(log_path)
41
+
42
+ log_file = log_path / BUILD_LOG_NAME
43
+ setup_qwak_logger()
44
+ yield setup_logger(
45
+ log_file=log_file, verbosity_level=config.verbose, json_logs=json_logs
46
+ ), log_path
47
+ finally:
48
+ # Cleanup - Save only x last zips
49
+ logs_zip_sorted_by_data = sorted(
50
+ BUILDS_LOGS.rglob("**/*"), key=os.path.getmtime
51
+ )[:-MAX_LOGS_NUMBER]
52
+ path: Path
53
+ for path in logs_zip_sorted_by_data:
54
+ if path.is_file():
55
+ os.remove(path)
56
+ elif path.is_dir():
57
+ shutil.rmtree(path, ignore_errors=True)
58
+
59
+
60
+ def setup_logger(
61
+ log_file: Path, verbosity_level: int, json_logs: bool
62
+ ) -> logging.Logger:
63
+ # Init logger
64
+ fallback_logger_name = (
65
+ BUILD_LOCAL_LOGGER_NAME if not json_logs else REMOTE_LOGGER_NAME
66
+ )
67
+ logger = get_qwak_logger(fallback_logger_name=fallback_logger_name)
68
+
69
+ if not non_qwak_logger_enabled():
70
+ if logger.name == BUILD_LOCAL_LOGGER_NAME:
71
+ set_file_handler_log_file(logger, BUILD_LOCAL_FILE_HANDLER_NAME, log_file)
72
+ set_handler_verbosity(
73
+ logger, CONSOLE_HANDLER_NAME, VERBOSITY_LEVEL_MAPPING[verbosity_level]
74
+ )
75
+ elif logger.name == REMOTE_LOGGER_NAME and json_logs:
76
+ set_handler_verbosity(
77
+ logger,
78
+ REMOTE_CONSOLE_HANDLER_NAME,
79
+ VERBOSITY_LEVEL_MAPPING[verbosity_level],
80
+ )
81
+
82
+ return logger
83
+
84
+
85
+ def log_system_information(destination: Path):
86
+ (destination / "python_version").write_text(sys.version)
87
+ (destination / "qwak_sdk_version").write_text(qwak_sdk_version)
88
+ (destination / "os_detail").write_text(platform.platform())
@@ -0,0 +1,40 @@
1
+ BUILD_LOGS_URL = (
2
+ "https://app.qwak.ai/projects/{project_uuid}/{model_id}/build/{build_id}"
3
+ )
4
+
5
+ SUCCESS_MSG_REMOTE = """
6
+ Build ID \033[4m{build_id}\033[0m triggered remotely
7
+
8
+ ########### To follow build logs using CLI
9
+ qwak models builds logs -b {build_id} --follow
10
+
11
+ ########### To follow build logs using Qwak platform
12
+ https://app.qwak.ai/projects/{project_uuid}/{model_id}/build/{build_id}
13
+ """
14
+
15
+ SUCCESS_MSG_REMOTE_WITH_DEPLOY = """
16
+ Build ID \033[4m{build_id}\033[0m finished successfully and deployed
17
+
18
+ ########### To view the model using Qwak platform
19
+ https://app.qwak.ai/projects/{project_uuid}/{model_id}
20
+ """
21
+
22
+ FAILED_CONTACT_QWAK_SUPPORT = """
23
+ Build ID \033[4m{build_id}\033[0m failed!!
24
+ You can share the logs from \033[4m{log_file}.zip\033[0m with Qwak support.
25
+ """
26
+
27
+ FAILED_CONTACT_QWAK_SUPPORT_PROGRAMMATIC = """
28
+ Build ID \033[4m{build_id}\033[0m failed!!
29
+ """
30
+
31
+ FAILED_REMOTE_BUILD_SUGGESTION = """
32
+ Your build failed. You can check the reason for the failure in the Qwak Platform:
33
+ https://app.qwak.ai/projects/{project_uuid}/{model_id}/build/{build_id}
34
+ """
35
+
36
+ FAILED_DEPLOY_BUILD_SUGGESTION = """
37
+ Deploying the build Failed. You can check the reason for the failure in the Qwak Platform:
38
+ https://app.qwak.ai/projects/{project_uuid}/{model_id}?tabId=1
39
+ Since the build finished successfully, you can try and redeploy it either from the platform or from the CLI
40
+ """
@@ -0,0 +1,49 @@
1
+ import logging
2
+ from logging import Logger
3
+
4
+ from yaspin.core import Yaspin
5
+
6
+ from qwak_sdk.commands.models.build._logic.constant.step_description import PhaseDetails
7
+ from qwak_sdk.commands.models.build._logic.interface.notifier_interface import Notifier
8
+
9
+
10
+ class NotifierImpl(Notifier):
11
+ def __init__(
12
+ self, logger: Logger, prefix: str, phase_details: PhaseDetails
13
+ ) -> None:
14
+ self.logger = logging.LoggerAdapter(
15
+ logger,
16
+ {
17
+ "phase": phase_details.get_description(),
18
+ "phase_id": phase_details.get_id(),
19
+ },
20
+ )
21
+ self.prefix = f"{prefix} - " if prefix else ""
22
+ self.spinner = None
23
+
24
+ def set_spinner(self, spinner: Yaspin):
25
+ self.spinner = spinner
26
+
27
+ def exception(self, line: str, e: BaseException) -> None:
28
+ self.logger.error(
29
+ f"""Message: {line}
30
+ Exception: {e}
31
+ """,
32
+ exc_info=False,
33
+ )
34
+
35
+ def error(self, line: str) -> None:
36
+ self.logger.error(f"{self.prefix}{line}")
37
+
38
+ def warning(self, line: str) -> None:
39
+ self.logger.warning(f"{self.prefix}{line}")
40
+
41
+ def info(self, line: str) -> None:
42
+ self.logger.info(f"{self.prefix}{line}")
43
+
44
+ def debug(self, line: str) -> None:
45
+ self.logger.debug(f"{self.prefix}{line}")
46
+
47
+ def spinner_text(self, line: str) -> None:
48
+ if self.spinner:
49
+ self.spinner.text = f"{self.prefix}{line}"
@@ -0,0 +1,14 @@
1
+ from contextlib import contextmanager
2
+ from typing import Generator, Optional
3
+
4
+ from yaspin import yaspin
5
+ from yaspin.core import Yaspin
6
+
7
+
8
+ @contextmanager
9
+ def spinner(text: Optional[str], show: bool) -> Generator[Yaspin, None, None]:
10
+ if show:
11
+ with yaspin(text=text, color="blue", timer=True).bold as sp:
12
+ yield sp
13
+ else:
14
+ yield
@@ -0,0 +1,37 @@
1
+ from abc import ABC, abstractmethod
2
+ from time import time
3
+ from typing import List
4
+
5
+
6
+ class TimeSource(ABC):
7
+ @abstractmethod
8
+ def current_epoch_time(self) -> int:
9
+ pass
10
+
11
+
12
+ class Stopwatch:
13
+ def __init__(self, time_source: TimeSource):
14
+ self.time_source = time_source
15
+ self.start_time = self.time_source.current_epoch_time()
16
+
17
+ def elapsed_time_in_seconds(self) -> int:
18
+ end_time = self.time_source.current_epoch_time()
19
+ return end_time - self.start_time
20
+
21
+
22
+ class SystemClockTimeSource(TimeSource):
23
+ def current_epoch_time(self) -> int:
24
+ return int(time())
25
+
26
+
27
+ class MockClockTimeSource(TimeSource):
28
+ def __init__(self, time_values=None):
29
+ self.time_values = []
30
+ if time_values:
31
+ self.time_values = list(time_values)
32
+
33
+ def current_epoch_time(self) -> int:
34
+ return self.time_values.pop(0)
35
+
36
+ def set_epoch_time_values(self, values: List[int]) -> None:
37
+ self.time_values = values
@@ -0,0 +1,12 @@
1
+ import shutil
2
+ from pathlib import Path
3
+
4
+
5
+ def zip_logs(log_path: str, build_id: str):
6
+ if build_id:
7
+ shutil.make_archive(
8
+ base_name=str(Path(log_path).parent / build_id),
9
+ format="zip",
10
+ root_dir=log_path,
11
+ )
12
+ shutil.rmtree(log_path, ignore_errors=True)