arpakitlib 1.7.256__py3-none-any.whl → 1.8.0__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.
Files changed (281) hide show
  1. arpakitlib/{_arpakit_project_template → _arpakit_project_template_v1}/README.md +1 -1
  2. arpakitlib/{_arpakit_project_template/src → _arpakit_project_template_v1}/admin1/add_admin_in_app.py +6 -12
  3. arpakitlib/{_arpakit_project_template/src → _arpakit_project_template_v1}/admin1/admin_auth.py +2 -6
  4. arpakitlib/_arpakit_project_template_v1/admin1/model_view.py +95 -0
  5. arpakitlib/{_arpakit_project_template → _arpakit_project_template_v1}/alembic/env.py +3 -3
  6. arpakitlib/_arpakit_project_template_v1/api/asgi.py +3 -0
  7. arpakitlib/_arpakit_project_template_v1/api/auth.py +244 -0
  8. arpakitlib/_arpakit_project_template_v1/api/const.py +18 -0
  9. arpakitlib/_arpakit_project_template_v1/api/create_api_app.py +72 -0
  10. arpakitlib/_arpakit_project_template_v1/api/event.py +69 -0
  11. arpakitlib/_arpakit_project_template_v1/api/exception.py +39 -0
  12. arpakitlib/_arpakit_project_template_v1/api/exception_handler.py +297 -0
  13. arpakitlib/_arpakit_project_template_v1/api/openapi_ui.py +28 -0
  14. arpakitlib/_arpakit_project_template_v1/api/response.py +27 -0
  15. arpakitlib/{_arpakit_project_template/src → _arpakit_project_template_v1}/api/router/main_router.py +3 -2
  16. arpakitlib/_arpakit_project_template_v1/api/router/v1/arpakitlib_.py +27 -0
  17. arpakitlib/_arpakit_project_template_v1/api/router/v1/check_auth.py +30 -0
  18. arpakitlib/_arpakit_project_template_v1/api/router/v1/get_errors_info.py +24 -0
  19. arpakitlib/_arpakit_project_template_v1/api/router/v1/healthcheck.py +21 -0
  20. arpakitlib/_arpakit_project_template_v1/api/router/v1/main_router.py +54 -0
  21. arpakitlib/_arpakit_project_template_v1/api/router/v1/now_utc_datetime.py +21 -0
  22. arpakitlib/_arpakit_project_template_v1/api/router/v1/raise_fake_error.py +21 -0
  23. arpakitlib/_arpakit_project_template_v1/api/schema/base_schema.py +26 -0
  24. arpakitlib/_arpakit_project_template_v1/api/schema/common/in_.py +5 -0
  25. arpakitlib/_arpakit_project_template_v1/api/schema/common/out.py +60 -0
  26. arpakitlib/_arpakit_project_template_v1/api/schema/v1/in_.py +5 -0
  27. arpakitlib/_arpakit_project_template_v1/api/schema/v1/out.py +53 -0
  28. arpakitlib/_arpakit_project_template_v1/api/transmitted_api_data.py +66 -0
  29. arpakitlib/_arpakit_project_template_v1/arpakitlib_project_template.json +3 -0
  30. arpakitlib/{_arpakit_project_template/src → _arpakit_project_template_v1}/business_service/hello_world.py +1 -1
  31. arpakitlib/_arpakit_project_template_v1/business_service/remove_operations.py +51 -0
  32. arpakitlib/_arpakit_project_template_v1/command/alembic_history.sh +2 -0
  33. arpakitlib/_arpakit_project_template_v1/command/alembic_revision_autogenerate.sh +2 -0
  34. arpakitlib/{_arpakit_project_template/manage/json_beautify.py → _arpakit_project_template_v1/command/beautify_json.py} +2 -2
  35. arpakitlib/{_arpakit_project_template/src/core/_check_logging.py → _arpakit_project_template_v1/command/check_logging.py} +3 -3
  36. arpakitlib/_arpakit_project_template_v1/command/check_sqlalchemy_db.py +11 -0
  37. arpakitlib/_arpakit_project_template_v1/command/drop_json_db.py +13 -0
  38. arpakitlib/_arpakit_project_template_v1/command/drop_sqlalchemy_db.py +14 -0
  39. arpakitlib/{_arpakit_project_template/src/core/_generate_settings_env_example.py → _arpakit_project_template_v1/command/generate_settings_env_example.py} +4 -4
  40. arpakitlib/{_arpakit_project_template/manage → _arpakit_project_template_v1/command}/hello_world.py +2 -2
  41. arpakitlib/_arpakit_project_template_v1/command/init_json_db.py +11 -0
  42. arpakitlib/_arpakit_project_template_v1/command/init_sqlalchemy_db.py +11 -0
  43. arpakitlib/_arpakit_project_template_v1/command/reinit_json_db.py +13 -0
  44. arpakitlib/_arpakit_project_template_v1/command/reinit_sqlalchemy_db.py +13 -0
  45. arpakitlib/_arpakit_project_template_v1/command/remove_operations.py +13 -0
  46. arpakitlib/_arpakit_project_template_v1/command/remove_story_logs.py +16 -0
  47. arpakitlib/_arpakit_project_template_v1/command/rm_all_records_in_json_db.py +13 -0
  48. arpakitlib/{_arpakit_project_template/src/core/_show_settings.py → _arpakit_project_template_v1/command/show_settings.py} +3 -3
  49. arpakitlib/{_arpakit_project_template/src/api/_start_api_with_reload.py → _arpakit_project_template_v1/command/start_api_with_reload.py} +5 -5
  50. arpakitlib/{_arpakit_project_template/src/api/_start_api_without_reload.py → _arpakit_project_template_v1/command/start_api_without_reload.py} +5 -5
  51. arpakitlib/_arpakit_project_template_v1/command/start_async_operation_executor_worker.py +14 -0
  52. arpakitlib/_arpakit_project_template_v1/command/start_async_scheduled_operation_creator_worker.py +14 -0
  53. arpakitlib/_arpakit_project_template_v1/command/start_sync_operation_executor_worker.py +15 -0
  54. arpakitlib/_arpakit_project_template_v1/command/start_sync_operation_executor_workers.py +22 -0
  55. arpakitlib/_arpakit_project_template_v1/command/start_sync_scheduled_operation_creator_worker.py +12 -0
  56. arpakitlib/_arpakit_project_template_v1/core/cache_file_storage_in_dir.py +21 -0
  57. arpakitlib/{_arpakit_project_template/src → _arpakit_project_template_v1}/core/const.py +2 -9
  58. arpakitlib/_arpakit_project_template_v1/core/dump_file_storage_in_dir.py +21 -0
  59. arpakitlib/_arpakit_project_template_v1/core/media_file_storage_in_dir.py +21 -0
  60. arpakitlib/_arpakit_project_template_v1/core/settings.py +193 -0
  61. arpakitlib/_arpakit_project_template_v1/core/util.py +29 -0
  62. arpakitlib/{_arpakit_project_template → _arpakit_project_template_v1}/example.env +10 -5
  63. arpakitlib/{_arpakit_project_template/src → _arpakit_project_template_v1}/json_db/util.py +2 -2
  64. arpakitlib/_arpakit_project_template_v1/operation_execution/operation_executor_worker.py +256 -0
  65. arpakitlib/_arpakit_project_template_v1/operation_execution/scheduled_operation_creator_worker.py +106 -0
  66. arpakitlib/_arpakit_project_template_v1/operation_execution/scheduled_operations.py +49 -0
  67. arpakitlib/_arpakit_project_template_v1/operation_execution/util.py +29 -0
  68. arpakitlib/_arpakit_project_template_v1/resource/static/openapi-favicon.png +0 -0
  69. arpakitlib/_arpakit_project_template_v1/resource/static/swagger-ui/index.html +19 -0
  70. arpakitlib/_arpakit_project_template_v1/resource/static/swagger-ui/swagger-ui-bundle.js +2 -0
  71. arpakitlib/{ar_fastapi_static → _arpakit_project_template_v1/resource/static}/swagger-ui/swagger-ui-es-bundle-core.js +1 -1
  72. arpakitlib/_arpakit_project_template_v1/resource/static/swagger-ui/swagger-ui-es-bundle-core.js.map +1 -0
  73. arpakitlib/_arpakit_project_template_v1/resource/static/swagger-ui/swagger-ui-es-bundle.js +2 -0
  74. arpakitlib/_arpakit_project_template_v1/resource/static/swagger-ui/swagger-ui-standalone-preset.js +2 -0
  75. arpakitlib/{ar_fastapi_static → _arpakit_project_template_v1/resource/static}/swagger-ui/swagger-ui.js +1 -1
  76. arpakitlib/_arpakit_project_template_v1/resource/static/swagger-ui/swagger-ui.js.map +1 -0
  77. arpakitlib/_arpakit_project_template_v1/sandbox/sandbox_1.py +14 -0
  78. arpakitlib/_arpakit_project_template_v1/sandbox/sandbox_2.py +14 -0
  79. arpakitlib/_arpakit_project_template_v1/sandbox/sandbox_3.py +14 -0
  80. arpakitlib/_arpakit_project_template_v1/sandbox/sandbox_4.py +14 -0
  81. arpakitlib/_arpakit_project_template_v1/sandbox/sandbox_5.py +14 -0
  82. arpakitlib/_arpakit_project_template_v1/sandbox/sandbox_6.py +14 -0
  83. arpakitlib/_arpakit_project_template_v1/sandbox/sandbox_7.py +14 -0
  84. arpakitlib/{_arpakit_project_template/src/sqlalchemy_db/util.py → _arpakit_project_template_v1/sqlalchemy_db/sqlalchemy_db.py} +3 -11
  85. arpakitlib/_arpakit_project_template_v1/sqlalchemy_db/sqlalchemy_model.py +129 -0
  86. arpakitlib/_arpakit_project_template_v1/sqlalchemy_db/util.py +28 -0
  87. arpakitlib/{_arpakit_project_template/src/sandbox/sandbox_3.py → _arpakit_project_template_v1/test_data/make_test_data_1.py} +8 -3
  88. arpakitlib/{_arpakit_project_template/src/sandbox/sandbox_4.py → _arpakit_project_template_v1/test_data/make_test_data_2.py} +8 -3
  89. arpakitlib/{_arpakit_project_template/src/sandbox/sandbox_1.py → _arpakit_project_template_v1/test_data/make_test_data_3.py} +8 -3
  90. arpakitlib/{_arpakit_project_template/src/sandbox/sandbox_2.py → _arpakit_project_template_v1/test_data/make_test_data_4.py} +8 -3
  91. arpakitlib/_arpakit_project_template_v1/test_data/make_test_data_5.py +22 -0
  92. arpakitlib/_arpakit_project_template_v1/tg_bot/blank/blank.py +5 -0
  93. arpakitlib/{_arpakit_project_template/src → _arpakit_project_template_v1}/tg_bot/blank/util.py +1 -1
  94. arpakitlib/{_arpakit_project_template/src → _arpakit_project_template_v1}/tg_bot/const.py +6 -3
  95. arpakitlib/_arpakit_project_template_v1/tg_bot/event.py +51 -0
  96. arpakitlib/{_arpakit_project_template/src → _arpakit_project_template_v1}/tg_bot/filter/not_prod_mode.py +1 -1
  97. arpakitlib/{_arpakit_project_template/src → _arpakit_project_template_v1}/tg_bot/filter/prod_mode.py +1 -1
  98. arpakitlib/_arpakit_project_template_v1/tg_bot/middleware/init_user.py +24 -0
  99. arpakitlib/_arpakit_project_template_v1/tg_bot/middleware/middleware.py +12 -0
  100. arpakitlib/_arpakit_project_template_v1/tg_bot/router/arpakitlib_.py +10 -0
  101. arpakitlib/_arpakit_project_template_v1/tg_bot/router/error.py +15 -0
  102. arpakitlib/_arpakit_project_template_v1/tg_bot/router/healthcheck.py +10 -0
  103. arpakitlib/_arpakit_project_template_v1/tg_bot/router/main_router.py +14 -0
  104. arpakitlib/_arpakit_project_template_v1/tg_bot/start_tg_bot.py +34 -0
  105. arpakitlib/_arpakit_project_template_v1/tg_bot/tg_bot.py +24 -0
  106. arpakitlib/_arpakit_project_template_v1/tg_bot/tg_bot_dispatcher.py +19 -0
  107. arpakitlib/_arpakit_project_template_v1/tg_bot/transmitted_tg_data.py +58 -0
  108. arpakitlib/_arpakit_project_template_v1/util/read_arpakitlib_project_template_file.py +17 -0
  109. arpakitlib/ar_aiogram_util.py +41 -52
  110. arpakitlib/ar_arpakit_project_template_util.py +8 -11
  111. arpakitlib/ar_arpakitlib_cli_util.py +14 -5
  112. arpakitlib/ar_base_worker_util.py +35 -17
  113. arpakitlib/ar_class_util.py +11 -0
  114. arpakitlib/ar_func_util.py +19 -29
  115. arpakitlib/ar_http_request_util.py +10 -2
  116. arpakitlib/ar_need_type_util.py +3 -0
  117. arpakitlib/ar_rat_func_util.py +1 -1
  118. arpakitlib/ar_retry_func_util.py +4 -4
  119. arpakitlib/ar_schedule_uust_api_client_util.py +1 -1
  120. arpakitlib/ar_settings_util.py +3 -204
  121. arpakitlib/ar_sqladmin_util.py +7 -102
  122. arpakitlib/ar_sqlalchemy_util.py +65 -13
  123. arpakitlib/ar_type_util.py +0 -2
  124. {arpakitlib-1.7.256.dist-info → arpakitlib-1.8.0.dist-info}/METADATA +7 -6
  125. arpakitlib-1.8.0.dist-info/RECORD +251 -0
  126. {arpakitlib-1.7.256.dist-info → arpakitlib-1.8.0.dist-info}/WHEEL +1 -1
  127. arpakitlib/_arpakit_project_template/ARPAKITLIB +0 -1
  128. arpakitlib/_arpakit_project_template/manage/docker_ps.sh +0 -2
  129. arpakitlib/_arpakit_project_template/manage/git_branch.sh +0 -2
  130. arpakitlib/_arpakit_project_template/manage/poetry_add_plugin_export.sh +0 -2
  131. arpakitlib/_arpakit_project_template/manage/poetry_config_virtualenvs_in_project_true.sh +0 -2
  132. arpakitlib/_arpakit_project_template/manage/poetry_self_add_plugin_export.sh +0 -2
  133. arpakitlib/_arpakit_project_template/src/admin1/model_view.py +0 -1
  134. arpakitlib/_arpakit_project_template/src/api/asgi.py +0 -3
  135. arpakitlib/_arpakit_project_template/src/api/auth.py +0 -53
  136. arpakitlib/_arpakit_project_template/src/api/const.py +0 -13
  137. arpakitlib/_arpakit_project_template/src/api/create_api_app.py +0 -43
  138. arpakitlib/_arpakit_project_template/src/api/create_handle_exception_.py +0 -59
  139. arpakitlib/_arpakit_project_template/src/api/event.py +0 -83
  140. arpakitlib/_arpakit_project_template/src/api/router/v1/get_api_error_info.py +0 -27
  141. arpakitlib/_arpakit_project_template/src/api/router/v1/main_router.py +0 -15
  142. arpakitlib/_arpakit_project_template/src/api/schema/v1/in_.py +0 -1
  143. arpakitlib/_arpakit_project_template/src/api/schema/v1/out.py +0 -1
  144. arpakitlib/_arpakit_project_template/src/api/transmitted_api_data.py +0 -7
  145. arpakitlib/_arpakit_project_template/src/api/util.py +0 -44
  146. arpakitlib/_arpakit_project_template/src/core/settings.py +0 -21
  147. arpakitlib/_arpakit_project_template/src/core/util.py +0 -61
  148. arpakitlib/_arpakit_project_template/src/json_db/_drop_json_db.py +0 -13
  149. arpakitlib/_arpakit_project_template/src/json_db/_init_json_db.py +0 -11
  150. arpakitlib/_arpakit_project_template/src/json_db/_reinit_json_db.py +0 -13
  151. arpakitlib/_arpakit_project_template/src/json_db/_rm_all_records_in_json_db.py +0 -13
  152. arpakitlib/_arpakit_project_template/src/just_script/example.py +0 -16
  153. arpakitlib/_arpakit_project_template/src/operation_execution/_start_operation_executor_worker.py +0 -17
  154. arpakitlib/_arpakit_project_template/src/operation_execution/_start_scheduled_operation_creator_worker.py +0 -17
  155. arpakitlib/_arpakit_project_template/src/operation_execution/const.py +0 -9
  156. arpakitlib/_arpakit_project_template/src/operation_execution/operation_executor.py +0 -16
  157. arpakitlib/_arpakit_project_template/src/operation_execution/scheduled_operations.py +0 -29
  158. arpakitlib/_arpakit_project_template/src/operation_execution/util.py +0 -1
  159. arpakitlib/_arpakit_project_template/src/sandbox/sandbox_5.py +0 -17
  160. arpakitlib/_arpakit_project_template/src/sandbox/sandbox_6.py +0 -17
  161. arpakitlib/_arpakit_project_template/src/sandbox/sandbox_7.py +0 -17
  162. arpakitlib/_arpakit_project_template/src/sqlalchemy_db/_check_conn_sqlalchemy_db.py +0 -11
  163. arpakitlib/_arpakit_project_template/src/sqlalchemy_db/_drop_sqlalchemy_db.py +0 -13
  164. arpakitlib/_arpakit_project_template/src/sqlalchemy_db/_init_sqlalchemy_db.py +0 -11
  165. arpakitlib/_arpakit_project_template/src/sqlalchemy_db/_reinit_sqlalchemy_db.py +0 -13
  166. arpakitlib/_arpakit_project_template/src/sqlalchemy_db/_remove_operations.py +0 -15
  167. arpakitlib/_arpakit_project_template/src/sqlalchemy_db/_remove_story_logs.py +0 -16
  168. arpakitlib/_arpakit_project_template/src/sqlalchemy_db/sqlalchemy_model.py +0 -13
  169. arpakitlib/_arpakit_project_template/src/test_data/make_test_data_1.py +0 -8
  170. arpakitlib/_arpakit_project_template/src/test_data/make_test_data_2.py +0 -8
  171. arpakitlib/_arpakit_project_template/src/test_data/make_test_data_3.py +0 -8
  172. arpakitlib/_arpakit_project_template/src/test_data/make_test_data_4.py +0 -8
  173. arpakitlib/_arpakit_project_template/src/test_data/make_test_data_5.py +0 -8
  174. arpakitlib/_arpakit_project_template/src/tg_bot/blank/blank.py +0 -10
  175. arpakitlib/_arpakit_project_template/src/tg_bot/event.py +0 -39
  176. arpakitlib/_arpakit_project_template/src/tg_bot/handler/cmd_healthcheck.py +0 -0
  177. arpakitlib/_arpakit_project_template/src/tg_bot/router/error.py +0 -3
  178. arpakitlib/_arpakit_project_template/src/tg_bot/router/router.py +0 -7
  179. arpakitlib/_arpakit_project_template/src/tg_bot/start_tg_bot.py +0 -11
  180. arpakitlib/_arpakit_project_template/src/tg_bot/transmitted_tg_data.py +0 -6
  181. arpakitlib/_arpakit_project_template/src/tg_bot/util.py +0 -44
  182. arpakitlib/ar_api_key_util.py +0 -21
  183. arpakitlib/ar_fastapi_static/healthcheck +0 -1
  184. arpakitlib/ar_fastapi_static/swagger-ui/index.html +0 -19
  185. arpakitlib/ar_fastapi_static/swagger-ui/swagger-ui-bundle.js +0 -2
  186. arpakitlib/ar_fastapi_static/swagger-ui/swagger-ui-es-bundle-core.js.map +0 -1
  187. arpakitlib/ar_fastapi_static/swagger-ui/swagger-ui-es-bundle.js +0 -2
  188. arpakitlib/ar_fastapi_static/swagger-ui/swagger-ui-standalone-preset.js +0 -2
  189. arpakitlib/ar_fastapi_static/swagger-ui/swagger-ui.js.map +0 -1
  190. arpakitlib/ar_fastapi_util.py +0 -862
  191. arpakitlib/ar_operation_execution_util.py +0 -504
  192. arpakitlib/ar_sqlalchemy_model_util.py +0 -183
  193. arpakitlib-1.7.256.dist-info/RECORD +0 -236
  194. /arpakitlib/{_arpakit_project_template → _arpakit_project_template_v1}/.gitignore +0 -0
  195. /arpakitlib/{_arpakit_project_template → _arpakit_project_template_v1}/.python-version +0 -0
  196. /arpakitlib/{_arpakit_project_template → _arpakit_project_template_v1}/LICENSE +0 -0
  197. /arpakitlib/{_arpakit_project_template/manage → _arpakit_project_template_v1/additional_model}/__init__.py +0 -0
  198. /arpakitlib/{_arpakit_project_template/src → _arpakit_project_template_v1}/additional_model/additional_model.py +0 -0
  199. /arpakitlib/{_arpakit_project_template/manage/note → _arpakit_project_template_v1/admin1}/__init__.py +0 -0
  200. /arpakitlib/{_arpakit_project_template → _arpakit_project_template_v1}/alembic/README +0 -0
  201. /arpakitlib/{_arpakit_project_template → _arpakit_project_template_v1}/alembic/script.py.mako +0 -0
  202. /arpakitlib/{_arpakit_project_template → _arpakit_project_template_v1}/alembic.ini +0 -0
  203. /arpakitlib/{_arpakit_project_template/resource → _arpakit_project_template_v1/api}/__init__.py +0 -0
  204. /arpakitlib/{_arpakit_project_template/resource/static → _arpakit_project_template_v1/api/router}/__init__.py +0 -0
  205. /arpakitlib/{_arpakit_project_template/src → _arpakit_project_template_v1/api/router/v1}/__init__.py +0 -0
  206. /arpakitlib/{_arpakit_project_template/src/additional_model → _arpakit_project_template_v1/api/schema}/__init__.py +0 -0
  207. /arpakitlib/{_arpakit_project_template/src/admin1 → _arpakit_project_template_v1/api/schema/common}/__init__.py +0 -0
  208. /arpakitlib/{_arpakit_project_template/src/api → _arpakit_project_template_v1/api/schema/v1}/__init__.py +0 -0
  209. /arpakitlib/{_arpakit_project_template/manage/note/note_1.txt → _arpakit_project_template_v1/api/util.py} +0 -0
  210. /arpakitlib/{_arpakit_project_template/src/api/router → _arpakit_project_template_v1/business_service}/__init__.py +0 -0
  211. /arpakitlib/{_arpakit_project_template/src/api/router/v1 → _arpakit_project_template_v1/command}/__init__.py +0 -0
  212. /arpakitlib/{_arpakit_project_template/manage → _arpakit_project_template_v1/command}/alembic_upgrade_head .sh +0 -0
  213. /arpakitlib/{_arpakit_project_template/manage → _arpakit_project_template_v1/command}/docker_ps_a.sh +0 -0
  214. /arpakitlib/{_arpakit_project_template/manage → _arpakit_project_template_v1/command}/docker_rm_postgres.sh +0 -0
  215. /arpakitlib/{_arpakit_project_template/manage → _arpakit_project_template_v1/command}/docker_run_postgres.sh +0 -0
  216. /arpakitlib/{_arpakit_project_template/manage → _arpakit_project_template_v1/command}/docker_start_postgres.sh +0 -0
  217. /arpakitlib/{_arpakit_project_template/manage → _arpakit_project_template_v1/command}/docker_stop_postgres.sh +0 -0
  218. /arpakitlib/{_arpakit_project_template/manage → _arpakit_project_template_v1/command}/git_commit.sh +0 -0
  219. /arpakitlib/{_arpakit_project_template/manage → _arpakit_project_template_v1/command}/git_push_arpakit_company_github_1.sh +0 -0
  220. /arpakitlib/{_arpakit_project_template/manage → _arpakit_project_template_v1/command}/git_push_arpakit_company_gitlab_1.sh +0 -0
  221. /arpakitlib/{_arpakit_project_template/manage → _arpakit_project_template_v1/command}/git_push_arpakit_github_1.sh +0 -0
  222. /arpakitlib/{_arpakit_project_template/manage → _arpakit_project_template_v1/command}/git_push_arpakit_gitlab_1.sh +0 -0
  223. /arpakitlib/{_arpakit_project_template/manage/git_remote_v.sh → _arpakit_project_template_v1/command/git_remote.sh} +0 -0
  224. /arpakitlib/{_arpakit_project_template/manage → _arpakit_project_template_v1/command}/git_set_arpakit_company_origin.sh +0 -0
  225. /arpakitlib/{_arpakit_project_template/manage → _arpakit_project_template_v1/command}/git_set_arpakit_origin.sh +0 -0
  226. /arpakitlib/{_arpakit_project_template/manage → _arpakit_project_template_v1/command}/git_status.sh +0 -0
  227. /arpakitlib/{_arpakit_project_template/manage → _arpakit_project_template_v1/command}/poetry_check.sh +0 -0
  228. /arpakitlib/{_arpakit_project_template/manage → _arpakit_project_template_v1/command}/poetry_clear_cache.sh +0 -0
  229. /arpakitlib/{_arpakit_project_template/manage → _arpakit_project_template_v1/command}/poetry_config.sh +0 -0
  230. /arpakitlib/{_arpakit_project_template/manage → _arpakit_project_template_v1/command}/poetry_install.sh +0 -0
  231. /arpakitlib/{_arpakit_project_template/manage → _arpakit_project_template_v1/command}/poetry_lock.sh +0 -0
  232. /arpakitlib/{_arpakit_project_template/manage → _arpakit_project_template_v1/command}/poetry_remove_and_add_arpakitlib.sh +0 -0
  233. /arpakitlib/{_arpakit_project_template/manage → _arpakit_project_template_v1/command}/poetry_show.sh +0 -0
  234. /arpakitlib/{_arpakit_project_template/manage → _arpakit_project_template_v1/command}/poetry_show_arpakitlib.sh +0 -0
  235. /arpakitlib/{_arpakit_project_template/manage → _arpakit_project_template_v1/command}/poetry_update.sh +0 -0
  236. /arpakitlib/{_arpakit_project_template/manage → _arpakit_project_template_v1/command}/poetry_update_arpakitlib.sh +0 -0
  237. /arpakitlib/{_arpakit_project_template/src/api/schema → _arpakit_project_template_v1/core}/__init__.py +0 -0
  238. /arpakitlib/{_arpakit_project_template/src/api/schema/v1 → _arpakit_project_template_v1/json_db}/__init__.py +0 -0
  239. /arpakitlib/{_arpakit_project_template/src → _arpakit_project_template_v1}/json_db/json_db.py +0 -0
  240. /arpakitlib/{_arpakit_project_template/src/business_service → _arpakit_project_template_v1/note}/__init__.py +0 -0
  241. /arpakitlib/{_arpakit_project_template/manage/note/note_2.txt → _arpakit_project_template_v1/note/note_1.txt} +0 -0
  242. /arpakitlib/{_arpakit_project_template/manage/note/note_3.txt → _arpakit_project_template_v1/note/note_2.txt} +0 -0
  243. /arpakitlib/{_arpakit_project_template/manage/note/note_4.txt → _arpakit_project_template_v1/note/note_3.txt} +0 -0
  244. /arpakitlib/{_arpakit_project_template/manage/note/note_5.txt → _arpakit_project_template_v1/note/note_4.txt} +0 -0
  245. /arpakitlib/{_arpakit_project_template/src/core/__init__.py → _arpakit_project_template_v1/note/note_5.txt} +0 -0
  246. /arpakitlib/{_arpakit_project_template/src/json_db → _arpakit_project_template_v1/operation_execution}/__init__.py +0 -0
  247. /arpakitlib/{_arpakit_project_template/src/just_script/__init__.py → _arpakit_project_template_v1/operation_execution/const.py} +0 -0
  248. /arpakitlib/{_arpakit_project_template/src/operation_execution → _arpakit_project_template_v1/resource}/__init__.py +0 -0
  249. /arpakitlib/{_arpakit_project_template/src/sandbox → _arpakit_project_template_v1/resource/static}/__init__.py +0 -0
  250. /arpakitlib/{_arpakit_project_template → _arpakit_project_template_v1}/resource/static/healthcheck +0 -0
  251. /arpakitlib/{_arpakit_project_template → _arpakit_project_template_v1}/resource/static/helloworld +0 -0
  252. /arpakitlib/{ar_fastapi_static → _arpakit_project_template_v1/resource/static}/redoc/redoc.standalone.js +0 -0
  253. /arpakitlib/{ar_fastapi_static → _arpakit_project_template_v1/resource/static}/swagger-ui/favicon-16x16.png +0 -0
  254. /arpakitlib/{ar_fastapi_static → _arpakit_project_template_v1/resource/static}/swagger-ui/favicon-32x32.png +0 -0
  255. /arpakitlib/{ar_fastapi_static → _arpakit_project_template_v1/resource/static}/swagger-ui/index.css +0 -0
  256. /arpakitlib/{ar_fastapi_static → _arpakit_project_template_v1/resource/static}/swagger-ui/oauth2-redirect.html +0 -0
  257. /arpakitlib/{ar_fastapi_static → _arpakit_project_template_v1/resource/static}/swagger-ui/swagger-initializer.js +0 -0
  258. /arpakitlib/{ar_fastapi_static → _arpakit_project_template_v1/resource/static}/swagger-ui/swagger-ui-bundle.js.map +0 -0
  259. /arpakitlib/{ar_fastapi_static → _arpakit_project_template_v1/resource/static}/swagger-ui/swagger-ui-es-bundle.js.map +0 -0
  260. /arpakitlib/{ar_fastapi_static → _arpakit_project_template_v1/resource/static}/swagger-ui/swagger-ui-standalone-preset.js.map +0 -0
  261. /arpakitlib/{ar_fastapi_static → _arpakit_project_template_v1/resource/static}/swagger-ui/swagger-ui.css +0 -0
  262. /arpakitlib/{ar_fastapi_static → _arpakit_project_template_v1/resource/static}/swagger-ui/swagger-ui.css.map +0 -0
  263. /arpakitlib/{_arpakit_project_template/src/sqlalchemy_db → _arpakit_project_template_v1/sandbox}/__init__.py +0 -0
  264. /arpakitlib/{_arpakit_project_template/src/test_data → _arpakit_project_template_v1/sqlalchemy_db}/__init__.py +0 -0
  265. /arpakitlib/{_arpakit_project_template/src → _arpakit_project_template_v1}/sqlalchemy_db/const.py +0 -0
  266. /arpakitlib/{_arpakit_project_template/src/tg_bot → _arpakit_project_template_v1/test_data}/__init__.py +0 -0
  267. /arpakitlib/{_arpakit_project_template/src/tg_bot/blank → _arpakit_project_template_v1/tg_bot}/__init__.py +0 -0
  268. /arpakitlib/{_arpakit_project_template/src/tg_bot/filter → _arpakit_project_template_v1/tg_bot/blank}/__init__.py +0 -0
  269. /arpakitlib/{_arpakit_project_template/src/tg_bot/handler → _arpakit_project_template_v1/tg_bot/filter}/__init__.py +0 -0
  270. /arpakitlib/{_arpakit_project_template/src → _arpakit_project_template_v1}/tg_bot/kb/__init__.py +0 -0
  271. /arpakitlib/{_arpakit_project_template/src → _arpakit_project_template_v1}/tg_bot/kb/inline_/__init__.py +0 -0
  272. /arpakitlib/{_arpakit_project_template/src → _arpakit_project_template_v1}/tg_bot/kb/inline_/callback.py +0 -0
  273. /arpakitlib/{_arpakit_project_template/src → _arpakit_project_template_v1}/tg_bot/kb/inline_/common.py +0 -0
  274. /arpakitlib/{_arpakit_project_template/src → _arpakit_project_template_v1}/tg_bot/kb/static_/__init__.py +0 -0
  275. /arpakitlib/{_arpakit_project_template/src → _arpakit_project_template_v1}/tg_bot/kb/static_/common.py +0 -0
  276. /arpakitlib/{_arpakit_project_template/src → _arpakit_project_template_v1}/tg_bot/middleware/__init__.py +0 -0
  277. /arpakitlib/{_arpakit_project_template/src → _arpakit_project_template_v1}/tg_bot/router/__init__.py +0 -0
  278. /arpakitlib/{_arpakit_project_template/src/tg_bot/handler/cmd_arpakitlib.py → _arpakit_project_template_v1/tg_bot/util.py} +0 -0
  279. /arpakitlib/{_arpakit_project_template/src → _arpakit_project_template_v1}/util/__init__.py +0 -0
  280. {arpakitlib-1.7.256.dist-info → arpakitlib-1.8.0.dist-info}/LICENSE +0 -0
  281. {arpakitlib-1.7.256.dist-info → arpakitlib-1.8.0.dist-info}/entry_points.txt +0 -0
@@ -1,862 +0,0 @@
1
- # arpakit
2
-
3
- from __future__ import annotations
4
-
5
- import asyncio
6
- import datetime as dt
7
- import inspect
8
- import logging
9
- import os.path
10
- import pathlib
11
- from contextlib import suppress
12
- from typing import Any, Callable
13
-
14
- import fastapi.exceptions
15
- import fastapi.responses
16
- import fastapi.security
17
- import starlette.exceptions
18
- import starlette.requests
19
- import starlette.status
20
- from fastapi import FastAPI, APIRouter, Query, Security, Depends
21
- from fastapi.openapi.docs import get_swagger_ui_html, get_redoc_html
22
- from fastapi.security import APIKeyHeader
23
- from pydantic import BaseModel, ConfigDict
24
- from starlette import status
25
- from starlette.middleware.cors import CORSMiddleware
26
- from starlette.staticfiles import StaticFiles
27
-
28
- from arpakitlib.ar_datetime_util import now_utc_dt
29
- from arpakitlib.ar_dict_util import combine_dicts
30
- from arpakitlib.ar_enumeration_util import Enumeration
31
- from arpakitlib.ar_exception_util import exception_to_traceback_str
32
- from arpakitlib.ar_file_storage_in_dir_util import FileStorageInDir
33
- from arpakitlib.ar_func_util import raise_if_not_async_func, is_async_object
34
- from arpakitlib.ar_json_db_util import BaseJSONDb
35
- from arpakitlib.ar_json_util import safely_transfer_obj_to_json_str_to_json_obj, safely_transfer_obj_to_json_str
36
- from arpakitlib.ar_settings_util import BaseSettings2
37
- from arpakitlib.ar_sqlalchemy_model_util import StoryLogDBM, OperationDBM
38
- from arpakitlib.ar_sqlalchemy_util import SQLAlchemyDb
39
- from arpakitlib.ar_type_util import raise_for_type, raise_if_none
40
-
41
- _ARPAKIT_LIB_MODULE_VERSION = "3.0"
42
-
43
- _logger = logging.getLogger(__name__)
44
-
45
-
46
- class BaseSchema(BaseModel):
47
- model_config = ConfigDict(extra="ignore", arbitrary_types_allowed=True, from_attributes=True)
48
-
49
- @classmethod
50
- def __pydantic_init_subclass__(cls, **kwargs: Any) -> None:
51
- if not (
52
- cls.__name__.endswith("SO")
53
- or cls.__name__.endswith("SI")
54
- or cls.__name__.endswith("SchemaIn")
55
- or cls.__name__.endswith("SchemaOut")
56
- ):
57
- raise ValueError("APISchema class should ends with SO | SI | SchemaIn | SchemaOut")
58
- super().__init_subclass__(**kwargs)
59
-
60
-
61
- class BaseSI(BaseSchema):
62
- pass
63
-
64
-
65
- class BaseSO(BaseSchema):
66
- pass
67
-
68
-
69
- class SimpleSO(BaseSO):
70
- id: int
71
- long_id: str
72
- creation_dt: dt.datetime
73
-
74
-
75
- class BaseAPIErrorCodes(Enumeration):
76
- cannot_authorize = "CANNOT_AUTHORIZE"
77
- unknown_error = "UNKNOWN_ERROR"
78
- error_in_request = "ERROR_IN_REQUEST"
79
- not_found = "NOT_FOUND"
80
-
81
-
82
- class BaseAPIErrorSpecificationCodes(Enumeration):
83
- pass
84
-
85
-
86
- class ErrorSO(BaseSO):
87
- has_error: bool = True
88
- error_code: str | None = None
89
- error_specification_code: str | None = None
90
- error_description: str | None = None
91
- error_data: dict[str, Any] = {}
92
-
93
-
94
- class RawDataSO(BaseSO):
95
- data: dict[str, Any] = {}
96
-
97
-
98
- class DatetimeSO(BaseSO):
99
- date: dt.date
100
- datetime: dt.datetime | None = None
101
- year: int
102
- month: int
103
- day: int
104
- hour: int | None = None
105
- minute: int | None = None
106
- second: int | None = None
107
- microsecond: int | None = None
108
-
109
- @classmethod
110
- def from_datetime(cls, datetime_: dt.datetime):
111
- return cls(
112
- date=datetime_.date(),
113
- datetime=datetime_,
114
- year=datetime_.year,
115
- month=datetime_.month,
116
- day=datetime_.day,
117
- hour=datetime_.hour,
118
- minute=datetime_.minute,
119
- second=datetime_.second,
120
- microsecond=datetime_.microsecond
121
- )
122
-
123
- @classmethod
124
- def from_date(cls, date_: dt.date):
125
- return cls(
126
- date=date_,
127
- year=date_.year,
128
- month=date_.month,
129
- day=date_.day
130
- )
131
-
132
-
133
- class StoryLogSO(SimpleSO):
134
- level: str
135
- title: str | None
136
- data: dict[str, Any]
137
-
138
- @classmethod
139
- def from_story_log_dbm(cls, *, story_log_dbm: StoryLogDBM) -> StoryLogSO:
140
- return cls.model_validate(story_log_dbm.simple_dict(include_sd_properties=True))
141
-
142
-
143
- class OperationSO(SimpleSO):
144
- execution_start_dt: dt.datetime | None
145
- execution_finish_dt: dt.datetime | None
146
- status: str
147
- type: str
148
- input_data: dict[str, Any]
149
- output_data: dict[str, Any]
150
- error_data: dict[str, Any]
151
- duration_total_seconds: float | None
152
-
153
- @classmethod
154
- def from_operation_dbm(cls, *, operation_dbm: OperationDBM) -> OperationSO:
155
- return cls.model_validate(operation_dbm.simple_dict(include_sd_properties=True))
156
-
157
-
158
- class APIErrorInfoSO(BaseSO):
159
- api_error_codes: list[str] = []
160
- api_error_specification_codes: list[str] = []
161
-
162
-
163
- class APIJSONResponse(fastapi.responses.JSONResponse):
164
- def __init__(self, *, content: dict | list | BaseSO | None, status_code: int = starlette.status.HTTP_200_OK):
165
- if isinstance(content, dict):
166
- content = safely_transfer_obj_to_json_str_to_json_obj(content)
167
- elif isinstance(content, list):
168
- content = safely_transfer_obj_to_json_str_to_json_obj(content)
169
- elif isinstance(content, BaseSO):
170
- content = safely_transfer_obj_to_json_str_to_json_obj(content.model_dump())
171
- elif content is None:
172
- content = None
173
- else:
174
- raise ValueError(f"unknown content type, type(content)={type(content)}")
175
-
176
- self.content_ = content
177
- self.status_code_ = status_code
178
-
179
- super().__init__(
180
- content=content,
181
- status_code=status_code
182
- )
183
-
184
-
185
- class APIException(fastapi.exceptions.HTTPException):
186
- def __init__(
187
- self,
188
- *,
189
- status_code: int = starlette.status.HTTP_400_BAD_REQUEST,
190
- error_code: str | None = BaseAPIErrorCodes.unknown_error,
191
- error_specification_code: str | None = None,
192
- error_description: str | None = None,
193
- error_data: dict[str, Any] | None = None
194
- ):
195
- self.status_code = status_code
196
- self.error_code = error_code
197
- self.error_specification_code = error_specification_code
198
- self.error_description = error_description
199
- if error_data is None:
200
- error_data = {}
201
- self.error_data = error_data
202
-
203
- self.error_so = ErrorSO(
204
- has_error=True,
205
- error_code=self.error_code,
206
- error_specification_code=self.error_specification_code,
207
- error_description=self.error_description,
208
- error_data=self.error_data
209
- )
210
-
211
- super().__init__(
212
- status_code=self.status_code,
213
- detail=self.error_so.model_dump(mode="json")
214
- )
215
-
216
-
217
- def create_handle_exception(
218
- *,
219
- funcs_before: list[Callable | None] | None = None,
220
- async_funcs_after: list[Callable | None] | None = None,
221
- ) -> Callable:
222
- if funcs_before is None:
223
- funcs_before = []
224
- funcs_before = [v for v in funcs_before if v is not None]
225
-
226
- if async_funcs_after is None:
227
- async_funcs_after = []
228
- async_funcs_after = [v for v in async_funcs_after if v is not None]
229
-
230
- async def func(
231
- request: starlette.requests.Request,
232
- exception: Exception
233
- ) -> APIJSONResponse:
234
- status_code = starlette.status.HTTP_500_INTERNAL_SERVER_ERROR
235
-
236
- error_so = ErrorSO(
237
- has_error=True,
238
- error_code=BaseAPIErrorCodes.unknown_error,
239
- error_data={
240
- "exception_type": str(type(exception)),
241
- "exception_str": str(exception),
242
- "request.method": str(request.method),
243
- "request.url": str(request.url),
244
- "request.headers": str(request.headers),
245
- }
246
- )
247
-
248
- if isinstance(exception, APIException):
249
- old_error_data = error_so.error_data
250
- error_so = exception.error_so
251
- error_so.error_data = combine_dicts(old_error_data, error_so.error_data)
252
-
253
- elif isinstance(exception, starlette.exceptions.HTTPException):
254
- status_code = exception.status_code
255
- if status_code in (starlette.status.HTTP_403_FORBIDDEN, starlette.status.HTTP_401_UNAUTHORIZED):
256
- error_so.error_code = BaseAPIErrorCodes.cannot_authorize
257
- elif status_code == starlette.status.HTTP_404_NOT_FOUND:
258
- error_so.error_code = BaseAPIErrorCodes.not_found
259
- else:
260
- status_code = starlette.status.HTTP_500_INTERNAL_SERVER_ERROR
261
- with suppress(Exception):
262
- error_so.error_data["exception.detail"] = exception.detail
263
-
264
- elif isinstance(exception, fastapi.exceptions.RequestValidationError):
265
- status_code = starlette.status.HTTP_422_UNPROCESSABLE_ENTITY
266
- error_so.error_code = BaseAPIErrorCodes.error_in_request
267
- with suppress(Exception):
268
- error_so.error_data["exception.errors"] = str(exception.errors()) if exception.errors() else {}
269
-
270
- else:
271
- status_code = starlette.status.HTTP_500_INTERNAL_SERVER_ERROR
272
- error_so.error_code = BaseAPIErrorCodes.unknown_error
273
-
274
- if error_so.error_code is not None:
275
- error_so.error_code = error_so.error_code.upper().replace(" ", "_").strip()
276
-
277
- if error_so.error_specification_code is not None:
278
- error_so.error_specification_code = (
279
- error_so.error_specification_code.upper().replace(" ", "_").strip()
280
- )
281
-
282
- if error_so.error_code == BaseAPIErrorCodes.not_found:
283
- status_code = status.HTTP_404_NOT_FOUND
284
-
285
- if error_so.error_code == BaseAPIErrorCodes.cannot_authorize:
286
- status_code = status.HTTP_401_UNAUTHORIZED
287
-
288
- error_so.error_data["status_code"] = status_code
289
-
290
- # funcs_before
291
-
292
- _transmitted_kwargs = {}
293
- for func_before in funcs_before:
294
- _func_data = func_before(
295
- request=request, status_code=status_code, error_so=error_so, exception=exception,
296
- transmitted_kwargs=_transmitted_kwargs
297
- )
298
- if is_async_object(_func_data):
299
- _func_data = await _func_data
300
- if _func_data is not None:
301
- error_so, _transmitted_kwargs = _func_data[0], _func_data[1]
302
- raise_for_type(error_so, ErrorSO)
303
- raise_for_type(_transmitted_kwargs, dict)
304
-
305
- # async_funcs_after
306
-
307
- for async_func_after in async_funcs_after:
308
- raise_if_not_async_func(async_func_after)
309
- _ = asyncio.create_task(async_func_after(
310
- request=request, status_code=status_code, error_so=error_so, exception=exception
311
- ))
312
-
313
- return APIJSONResponse(
314
- content=error_so,
315
- status_code=status_code
316
- )
317
-
318
- return func
319
-
320
-
321
- def logging__api_func_before_in_handle_exception(
322
- *,
323
- ignore_api_error_codes: list[str] | None = None,
324
- ignore_status_codes: list[int] | None = None,
325
- ignore_exception_types: list[type[Exception]] | None = None,
326
- need_exc_info: bool = False
327
- ) -> Callable:
328
- current_func_name = inspect.currentframe().f_code.co_name
329
-
330
- def func(
331
- *,
332
- request: starlette.requests.Request,
333
- status_code: int,
334
- error_so: ErrorSO,
335
- exception: Exception,
336
- transmitted_kwargs: dict[str, Any],
337
- **kwargs
338
- ) -> (ErrorSO, dict[str, Any]):
339
- transmitted_kwargs[current_func_name] = now_utc_dt()
340
-
341
- if ignore_api_error_codes and error_so.error_code in ignore_api_error_codes:
342
- return error_so, transmitted_kwargs
343
-
344
- if ignore_status_codes and status_code in ignore_status_codes:
345
- return error_so, transmitted_kwargs
346
-
347
- if ignore_exception_types and (
348
- exception in ignore_exception_types or type(exception) in ignore_exception_types
349
- ):
350
- return error_so, transmitted_kwargs
351
-
352
- _logger.error(safely_transfer_obj_to_json_str(error_so.model_dump()), exc_info=need_exc_info)
353
-
354
- return func
355
-
356
-
357
- def story_log__api_func_before_in_handle_exception(
358
- *,
359
- sqlalchemy_db: SQLAlchemyDb,
360
- ignore_api_error_codes: list[str] | None = None,
361
- ignore_status_codes: list[int] | None = None,
362
- ignore_exception_types: list[type[Exception]] | None = None
363
- ) -> Callable:
364
- raise_for_type(sqlalchemy_db, SQLAlchemyDb)
365
-
366
- current_func_name = inspect.currentframe().f_code.co_name
367
-
368
- async def async_func(
369
- *,
370
- request: starlette.requests.Request,
371
- status_code: int,
372
- error_so: ErrorSO,
373
- exception: Exception,
374
- transmitted_kwargs: dict[str, Any],
375
- **kwargs
376
- ) -> (ErrorSO, dict[str, Any]):
377
- transmitted_kwargs[current_func_name] = now_utc_dt()
378
-
379
- if ignore_api_error_codes and error_so.error_code in ignore_api_error_codes:
380
- return error_so, transmitted_kwargs
381
-
382
- if ignore_status_codes and status_code in ignore_status_codes:
383
- return error_so, transmitted_kwargs
384
-
385
- if ignore_exception_types and (
386
- exception in ignore_exception_types or type(exception) in ignore_exception_types
387
- ):
388
- return error_so, transmitted_kwargs
389
-
390
- async with sqlalchemy_db.new_async_session() as session:
391
- story_log_dbm = StoryLogDBM(
392
- level=StoryLogDBM.Levels.error,
393
- title=f"{status_code}, {type(exception)}",
394
- data={
395
- "error_so": error_so.model_dump(),
396
- "traceback_str": exception_to_traceback_str(exception=exception)
397
- }
398
- )
399
- session.add(story_log_dbm)
400
- await session.commit()
401
- await session.refresh(story_log_dbm)
402
-
403
- error_so.error_data.update({"story_log_long_id": story_log_dbm.long_id})
404
- transmitted_kwargs["story_log_id"] = story_log_dbm.id
405
-
406
- return error_so, transmitted_kwargs
407
-
408
- return async_func
409
-
410
-
411
- def add_exception_handler_to_app(*, app: FastAPI, handle_exception: Callable) -> FastAPI:
412
- app.add_exception_handler(
413
- exc_class_or_status_code=Exception,
414
- handler=handle_exception
415
- )
416
- app.add_exception_handler(
417
- exc_class_or_status_code=ValueError,
418
- handler=handle_exception
419
- )
420
- app.add_exception_handler(
421
- exc_class_or_status_code=fastapi.exceptions.RequestValidationError,
422
- handler=handle_exception
423
- )
424
- app.add_exception_handler(
425
- exc_class_or_status_code=starlette.exceptions.HTTPException,
426
- handler=handle_exception
427
- )
428
- return app
429
-
430
-
431
- def add_swagger_to_app(
432
- *,
433
- app: FastAPI,
434
- favicon_url: str | None = None
435
- ):
436
- app.mount(
437
- "/ar_fastapi_static",
438
- StaticFiles(directory=os.path.join(str(pathlib.Path(__file__).parent), "ar_fastapi_static")),
439
- name="ar_fastapi_static"
440
- )
441
-
442
- @app.get("/docs", include_in_schema=False)
443
- async def custom_swagger_ui_html():
444
- return get_swagger_ui_html(
445
- openapi_url=app.openapi_url,
446
- title=app.title,
447
- swagger_js_url="/ar_fastapi_static/swagger-ui/swagger-ui-bundle.js",
448
- swagger_css_url="/ar_fastapi_static/swagger-ui/swagger-ui.css",
449
- swagger_favicon_url=favicon_url
450
- )
451
-
452
- @app.get("/redoc", include_in_schema=False)
453
- async def custom_redoc_html():
454
- return get_redoc_html(
455
- openapi_url=app.openapi_url,
456
- title=app.title,
457
- redoc_js_url="/ar_fastapi_static/redoc/redoc.standalone.js",
458
- redoc_favicon_url=favicon_url
459
- )
460
-
461
- return app
462
-
463
-
464
- def add_cors_to_app(*, app: FastAPI):
465
- app.add_middleware(
466
- CORSMiddleware,
467
- allow_origins=["*"],
468
- allow_credentials=True,
469
- allow_methods=["*"],
470
- allow_headers=["*"],
471
- )
472
- return app
473
-
474
-
475
- class HealthcheckSO(BaseSO):
476
- is_ok: bool = True
477
-
478
-
479
- class ARPAKITLibSO(BaseSO):
480
- arpakitlib: bool = True
481
-
482
-
483
- def create_needed_api_router():
484
- api_router = APIRouter()
485
-
486
- @api_router.get(
487
- "/healthcheck",
488
- response_model=HealthcheckSO | ErrorSO,
489
- status_code=starlette.status.HTTP_200_OK,
490
- tags=["Healthcheck"]
491
- )
492
- async def _():
493
- return APIJSONResponse(
494
- status_code=starlette.status.HTTP_200_OK,
495
- content=HealthcheckSO(is_ok=True)
496
- )
497
-
498
- @api_router.get(
499
- "/arpakitlib",
500
- response_model=ARPAKITLibSO | ErrorSO,
501
- status_code=starlette.status.HTTP_200_OK,
502
- tags=["arpakitlib"]
503
- )
504
- async def _():
505
- return APIJSONResponse(
506
- status_code=starlette.status.HTTP_200_OK,
507
- content=ARPAKITLibSO(arpakitlib=True)
508
- )
509
-
510
- return api_router
511
-
512
-
513
- class BaseStartupAPIEvent:
514
- def __init__(self, *args, **kwargs):
515
- self._logger = logging.getLogger()
516
-
517
- async def async_on_startup(self, *args, **kwargs):
518
- self._logger.info("on_startup starts")
519
- self._logger.info("on_startup ends")
520
-
521
-
522
- class BaseShutdownAPIEvent:
523
- def __init__(self, *args, **kwargs):
524
- self._logger = logging.getLogger()
525
-
526
- async def async_on_shutdown(self, *args, **kwargs):
527
- self._logger.info("on_shutdown starts")
528
- self._logger.info("on_shutdown ends")
529
-
530
-
531
- class BaseTransmittedAPIData(BaseModel):
532
- model_config = ConfigDict(extra="ignore", arbitrary_types_allowed=True, from_attributes=True)
533
-
534
-
535
- class SimpleTransmittedAPIData(BaseTransmittedAPIData):
536
- settings: BaseSettings2 | None = None
537
-
538
-
539
- class AdvancedTransmittedAPIData(SimpleTransmittedAPIData):
540
- sqlalchemy_db: SQLAlchemyDb | None = None
541
- json_db: BaseJSONDb | None = None
542
- media_file_storage_in_dir: FileStorageInDir | None = None
543
- cache_file_storage_in_dir: FileStorageInDir | None = None
544
- dump_file_storage_in_dir: FileStorageInDir | None = None
545
-
546
-
547
- def get_transmitted_api_data(request: starlette.requests.Request) -> BaseTransmittedAPIData:
548
- return request.app.state.transmitted_api_data
549
-
550
-
551
- class BaseAPIAuthData(BaseModel):
552
- model_config = ConfigDict(extra="forbid", arbitrary_types_allowed=True, from_attributes=True)
553
-
554
- require_api_key_string: bool = False
555
- require_token_string: bool = False
556
-
557
- require_correct_api_key: bool = False
558
- require_correct_token: bool = False
559
-
560
- token_string: str | None = None
561
- api_key_string: str | None = None
562
-
563
- is_token_correct: bool | None = None
564
- is_api_key_correct: bool | None = None
565
-
566
-
567
- def base_api_auth(
568
- *,
569
- require_api_key_string: bool = False,
570
- require_token_string: bool = False,
571
- validate_api_key_func: Callable | None = None,
572
- validate_token_func: Callable | None = None,
573
- correct_api_keys: str | list[str] | None = None,
574
- correct_tokens: str | list[str] | None = None,
575
- require_correct_api_key: bool = False,
576
- require_correct_token: bool = False,
577
- **kwargs
578
- ) -> Callable:
579
- if isinstance(correct_api_keys, str):
580
- correct_api_keys = [correct_api_keys]
581
- if correct_api_keys is not None:
582
- raise_for_type(correct_api_keys, list)
583
- validate_api_key_func = lambda *args, **kwargs_: kwargs_["api_key_string"] in correct_api_keys
584
-
585
- if isinstance(correct_tokens, str):
586
- correct_tokens = [correct_tokens]
587
- if correct_tokens is not None:
588
- raise_for_type(correct_tokens, list)
589
- validate_token_func = lambda *args, **kwargs_: kwargs_["token_string"] in correct_tokens
590
-
591
- if require_correct_api_key:
592
- raise_if_none(validate_api_key_func)
593
- require_api_key_string = True
594
-
595
- if require_correct_token:
596
- raise_if_none(validate_token_func)
597
- require_token_string = True
598
-
599
- async def func(
600
- *,
601
- ac: fastapi.security.HTTPAuthorizationCredentials | None = fastapi.Security(
602
- fastapi.security.HTTPBearer(auto_error=False)
603
- ),
604
- api_key_string: str | None = Security(
605
- APIKeyHeader(name="apikey", auto_error=False)
606
- ),
607
- request: starlette.requests.Request,
608
- transmitted_api_data: BaseTransmittedAPIData = Depends(get_transmitted_api_data)
609
- ) -> BaseAPIAuthData:
610
-
611
- api_auth_data = BaseAPIAuthData(
612
- require_api_key_string=require_api_key_string,
613
- require_token_string=require_token_string,
614
- require_correct_api_key=require_correct_api_key,
615
- require_correct_token=require_correct_token
616
- )
617
-
618
- # parse api_key
619
-
620
- api_auth_data.api_key_string = api_key_string
621
-
622
- if not api_auth_data.api_key_string and "api_key" in request.headers.keys():
623
- api_auth_data.api_key_string = request.headers["api_key"]
624
- if not api_auth_data.api_key_string and "api-key" in request.headers.keys():
625
- api_auth_data.api_key_string = request.headers["api-key"]
626
- if not api_auth_data.api_key_string and "apikey" in request.headers.keys():
627
- api_auth_data.api_key_string = request.headers["apikey"]
628
-
629
- if not api_auth_data.api_key_string and "api_key" in request.query_params.keys():
630
- api_auth_data.api_key_string = request.query_params["api_key"]
631
- if not api_auth_data.api_key_string and "api-key" in request.query_params.keys():
632
- api_auth_data.api_key_string = request.query_params["api-key"]
633
- if not api_auth_data.api_key_string and "apikey" in request.query_params.keys():
634
- api_auth_data.api_key_string = request.query_params["apikey"]
635
-
636
- # parse token
637
-
638
- api_auth_data.token_string = ac.credentials if ac and ac.credentials and ac.credentials.strip() else None
639
-
640
- if not api_auth_data.token_string and "token" in request.headers.keys():
641
- api_auth_data.token_string = request.headers["token"]
642
-
643
- if not api_auth_data.token_string and "user_token" in request.headers.keys():
644
- api_auth_data.token_string = request.headers["user_token"]
645
- if not api_auth_data.token_string and "user-token" in request.headers.keys():
646
- api_auth_data.token_string = request.headers["user-token"]
647
- if not api_auth_data.token_string and "usertoken" in request.headers.keys():
648
- api_auth_data.token_string = request.headers["usertoken"]
649
-
650
- if not api_auth_data.token_string and "token" in request.query_params.keys():
651
- api_auth_data.token_string = request.query_params["token"]
652
-
653
- if not api_auth_data.token_string and "user_token" in request.query_params.keys():
654
- api_auth_data.token_string = request.query_params["user_token"]
655
- if not api_auth_data.token_string and "user-token" in request.query_params.keys():
656
- api_auth_data.token_string = request.query_params["user-token"]
657
- if not api_auth_data.token_string and "usertoken" in request.query_params.keys():
658
- api_auth_data.token_string = request.query_params["usertoken"]
659
-
660
- if api_auth_data.token_string:
661
- api_auth_data.token_string = api_auth_data.token_string.strip()
662
- if not api_auth_data.token_string:
663
- api_auth_data.token_string = None
664
-
665
- # require_api_key_string
666
-
667
- if require_api_key_string and not api_auth_data.api_key_string:
668
- raise APIException(
669
- status_code=starlette.status.HTTP_401_UNAUTHORIZED,
670
- error_code=BaseAPIErrorCodes.cannot_authorize,
671
- error_data=safely_transfer_obj_to_json_str_to_json_obj(api_auth_data.model_dump())
672
- )
673
-
674
- # require_token_string
675
-
676
- if require_token_string and not api_auth_data.token_string:
677
- raise APIException(
678
- status_code=starlette.status.HTTP_401_UNAUTHORIZED,
679
- error_code=BaseAPIErrorCodes.cannot_authorize,
680
- error_data=safely_transfer_obj_to_json_str_to_json_obj(api_auth_data.model_dump())
681
- )
682
-
683
- # validate_api_key_func
684
-
685
- if validate_api_key_func is not None:
686
- validate_api_key_func_res = validate_api_key_func(
687
- api_key_string=api_auth_data.api_key_string,
688
- token_string=api_auth_data.token_string,
689
- base_api_auth_data=api_auth_data,
690
- transmitted_api_data=transmitted_api_data,
691
- request=request,
692
- **kwargs
693
- )
694
- if is_async_object(validate_api_key_func_res):
695
- validate_api_key_func_res = await validate_api_key_func_res
696
- api_auth_data.is_api_key_correct = validate_api_key_func_res
697
-
698
- # validate_token_func
699
-
700
- if validate_token_func is not None:
701
- validate_token_func_res = validate_token_func(
702
- api_key_string=api_auth_data.api_key_string,
703
- token_string=api_auth_data.token_string,
704
- base_api_auth_data=api_auth_data,
705
- transmitted_api_data=transmitted_api_data,
706
- request=request,
707
- **kwargs
708
- )
709
- if is_async_object(validate_token_func_res):
710
- validate_token_func_res = await validate_token_func_res
711
- api_auth_data.is_token_correct = validate_token_func_res
712
-
713
- # require_correct_api_key
714
-
715
- if require_correct_api_key:
716
- if not api_auth_data.is_api_key_correct:
717
- raise APIException(
718
- status_code=starlette.status.HTTP_401_UNAUTHORIZED,
719
- error_code=BaseAPIErrorCodes.cannot_authorize,
720
- error_description="not api_auth_data.is_api_key_correct",
721
- error_data=safely_transfer_obj_to_json_str_to_json_obj(api_auth_data.model_dump()),
722
- )
723
-
724
- # require_correct_token
725
-
726
- if require_correct_token:
727
- if not api_auth_data.is_token_correct:
728
- raise APIException(
729
- status_code=starlette.status.HTTP_401_UNAUTHORIZED,
730
- error_code=BaseAPIErrorCodes.cannot_authorize,
731
- error_description="not api_auth_data.is_token_correct",
732
- error_data=safely_transfer_obj_to_json_str_to_json_obj(api_auth_data.model_dump())
733
- )
734
-
735
- return api_auth_data
736
-
737
- return func
738
-
739
-
740
- def simple_api_router_for_testing():
741
- router = APIRouter(tags=["Testing"])
742
-
743
- @router.get(
744
- "/raise_fake_exception_1",
745
- response_model=ErrorSO
746
- )
747
- async def _():
748
- raise fastapi.HTTPException(status_code=starlette.status.HTTP_500_INTERNAL_SERVER_ERROR)
749
-
750
- @router.get(
751
- "/raise_fake_exception_2",
752
- response_model=ErrorSO
753
- )
754
- async def _():
755
- raise APIException(
756
- error_code="raise_fake_exception_2",
757
- error_specification_code="raise_fake_exception_2",
758
- error_description="raise_fake_exception_2"
759
- )
760
-
761
- @router.get(
762
- "/raise_fake_exception_3",
763
- response_model=ErrorSO
764
- )
765
- async def _():
766
- raise Exception("raise_fake_exception_3")
767
-
768
- @router.get(
769
- "/check_params_1",
770
- response_model=ErrorSO
771
- )
772
- async def _(name: int = Query()):
773
- return RawDataSO(data={"name": name})
774
-
775
- return router
776
-
777
-
778
- def create_fastapi_app(
779
- *,
780
- title: str = "arpakitlib FastAPI",
781
- description: str | None = "arpakitlib FastAPI",
782
- handle_exception_: Callable | None = None,
783
- startup_api_events: list[BaseStartupAPIEvent | None] | None = None,
784
- shutdown_api_events: list[BaseShutdownAPIEvent | None] | None = None,
785
- transmitted_api_data: BaseTransmittedAPIData = BaseTransmittedAPIData(),
786
- main_api_router: APIRouter = simple_api_router_for_testing(),
787
- contact: dict[str, Any] | None = None,
788
- media_dirpath: str | None = None,
789
- static_dirpath: str | None = None
790
- ):
791
- _logger.info("start")
792
-
793
- if handle_exception_ is None:
794
- handle_exception_ = create_handle_exception(
795
- funcs_before=[
796
- logging__api_func_before_in_handle_exception()
797
- ]
798
- )
799
-
800
- if not startup_api_events:
801
- startup_api_events = [BaseStartupAPIEvent()]
802
- startup_api_events = [v for v in startup_api_events if v is not None]
803
-
804
- if not shutdown_api_events:
805
- shutdown_api_events = [BaseShutdownAPIEvent()]
806
- shutdown_api_events = [v for v in shutdown_api_events if v is not None]
807
-
808
- app = FastAPI(
809
- title=title,
810
- description=description,
811
- docs_url=None,
812
- redoc_url=None,
813
- openapi_url="/openapi",
814
- on_startup=[api_startup_event.async_on_startup for api_startup_event in startup_api_events],
815
- on_shutdown=[api_shutdown_event.async_on_shutdown for api_shutdown_event in shutdown_api_events],
816
- contact=contact
817
- )
818
-
819
- if media_dirpath is not None:
820
- if not os.path.exists(media_dirpath):
821
- os.makedirs(media_dirpath, exist_ok=True)
822
- app.mount("/media", StaticFiles(directory=media_dirpath), name="media")
823
-
824
- if static_dirpath is not None:
825
- if not os.path.exists(static_dirpath):
826
- os.makedirs(static_dirpath, exist_ok=True)
827
- app.mount("/static", StaticFiles(directory=static_dirpath), name="static")
828
-
829
- app.state.transmitted_api_data = transmitted_api_data
830
-
831
- add_cors_to_app(app=app)
832
-
833
- add_swagger_to_app(app=app)
834
-
835
- add_exception_handler_to_app(
836
- app=app,
837
- handle_exception=handle_exception_
838
- )
839
-
840
- app.include_router(
841
- router=create_needed_api_router(),
842
- prefix=""
843
- )
844
-
845
- app.include_router(router=main_api_router)
846
-
847
- _logger.info("finish")
848
-
849
- return app
850
-
851
-
852
- def __example():
853
- pass
854
-
855
-
856
- async def __async_example():
857
- pass
858
-
859
-
860
- if __name__ == '__main__':
861
- __example()
862
- asyncio.run(__async_example())