bustapi 0.13.9__tar.gz → 0.14.1__tar.gz

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 (262) hide show
  1. {bustapi-0.13.9 → bustapi-0.14.1}/.gitignore +2 -1
  2. {bustapi-0.13.9 → bustapi-0.14.1}/CHANGELOG.md +13 -0
  3. {bustapi-0.13.9 → bustapi-0.14.1}/Cargo.lock +29 -33
  4. {bustapi-0.13.9 → bustapi-0.14.1}/Cargo.toml +1 -1
  5. {bustapi-0.13.9 → bustapi-0.14.1}/PKG-INFO +1 -1
  6. {bustapi-0.13.9 → bustapi-0.14.1}/docs/changelog.md +13 -0
  7. {bustapi-0.13.9 → bustapi-0.14.1}/pyproject.toml +1 -1
  8. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/__init__.py +1 -1
  9. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/app.py +34 -15
  10. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/auth/login.py +43 -3
  11. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/core/helpers.py +11 -0
  12. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/dispatch.py +42 -12
  13. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/http/request.py +8 -0
  14. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/routing/blueprints.py +31 -16
  15. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/sessions.py +3 -1
  16. {bustapi-0.13.9 → bustapi-0.14.1}/tests/test_async_login.py +28 -0
  17. bustapi-0.14.1/tests/test_issue_29.py +119 -0
  18. {bustapi-0.13.9 → bustapi-0.14.1}/tests/test_login_manager.py +51 -0
  19. {bustapi-0.13.9 → bustapi-0.14.1}/- +0 -0
  20. {bustapi-0.13.9 → bustapi-0.14.1}/.github/FUNDING.yml +0 -0
  21. {bustapi-0.13.9 → bustapi-0.14.1}/.github/workflows/ci-multiplatform.yml +0 -0
  22. {bustapi-0.13.9 → bustapi-0.14.1}/.github/workflows/ci.yml +0 -0
  23. {bustapi-0.13.9 → bustapi-0.14.1}/.github/workflows/docs.yml +0 -0
  24. {bustapi-0.13.9 → bustapi-0.14.1}/.github/workflows/manual-publish.yml +0 -0
  25. {bustapi-0.13.9 → bustapi-0.14.1}/.python-version +0 -0
  26. {bustapi-0.13.9 → bustapi-0.14.1}/AGENT_KNOWLEDGE.md +0 -0
  27. {bustapi-0.13.9 → bustapi-0.14.1}/Dockerfile +0 -0
  28. {bustapi-0.13.9 → bustapi-0.14.1}/LICENSE +0 -0
  29. {bustapi-0.13.9 → bustapi-0.14.1}/README.md +0 -0
  30. {bustapi-0.13.9 → bustapi-0.14.1}/benchmarks/CACHE_BENCHMARK.md +0 -0
  31. {bustapi-0.13.9 → bustapi-0.14.1}/benchmarks/README.md +0 -0
  32. {bustapi-0.13.9 → bustapi-0.14.1}/benchmarks/app.py +0 -0
  33. {bustapi-0.13.9 → bustapi-0.14.1}/benchmarks/benchmark_all.py +0 -0
  34. {bustapi-0.13.9 → bustapi-0.14.1}/benchmarks/benchmark_avg.py +0 -0
  35. {bustapi-0.13.9 → bustapi-0.14.1}/benchmarks/benchmark_cache.py +0 -0
  36. {bustapi-0.13.9 → bustapi-0.14.1}/benchmarks/benchmark_combined.png +0 -0
  37. {bustapi-0.13.9 → bustapi-0.14.1}/benchmarks/bustapi.md +0 -0
  38. {bustapi-0.13.9 → bustapi-0.14.1}/benchmarks/bustapi_bench.py +0 -0
  39. {bustapi-0.13.9 → bustapi-0.14.1}/benchmarks/bustapi_internal.py +0 -0
  40. {bustapi-0.13.9 → bustapi-0.14.1}/benchmarks/comparison_bench.py +0 -0
  41. {bustapi-0.13.9 → bustapi-0.14.1}/benchmarks/comprehensive_benchmark.py +0 -0
  42. {bustapi-0.13.9 → bustapi-0.14.1}/benchmarks/gen_graph.py +0 -0
  43. {bustapi-0.13.9 → bustapi-0.14.1}/benchmarks/quick_bench.py +0 -0
  44. {bustapi-0.13.9 → bustapi-0.14.1}/benchmarks/resource_bench.py +0 -0
  45. {bustapi-0.13.9 → bustapi-0.14.1}/benchmarks/rps_comparison.png +0 -0
  46. {bustapi-0.13.9 → bustapi-0.14.1}/benchmarks/run_comparison_auto.py +0 -0
  47. {bustapi-0.13.9 → bustapi-0.14.1}/benchmarks/ws_benchmark.py +0 -0
  48. {bustapi-0.13.9 → bustapi-0.14.1}/docs/advanced/async.md +0 -0
  49. {bustapi-0.13.9 → bustapi-0.14.1}/docs/advanced/blueprints.md +0 -0
  50. {bustapi-0.13.9 → bustapi-0.14.1}/docs/advanced/dependency_injection.md +0 -0
  51. {bustapi-0.13.9 → bustapi-0.14.1}/docs/advanced/deployment.md +0 -0
  52. {bustapi-0.13.9 → bustapi-0.14.1}/docs/advanced/middleware.md +0 -0
  53. {bustapi-0.13.9 → bustapi-0.14.1}/docs/advanced/security.md +0 -0
  54. {bustapi-0.13.9 → bustapi-0.14.1}/docs/advanced/validation.md +0 -0
  55. {bustapi-0.13.9 → bustapi-0.14.1}/docs/api-reference.md +0 -0
  56. {bustapi-0.13.9 → bustapi-0.14.1}/docs/assets/logo.png +0 -0
  57. {bustapi-0.13.9 → bustapi-0.14.1}/docs/complete-api-reference.md +0 -0
  58. {bustapi-0.13.9 → bustapi-0.14.1}/docs/deployment-performance-guide.md +0 -0
  59. {bustapi-0.13.9 → bustapi-0.14.1}/docs/deployment.md +0 -0
  60. {bustapi-0.13.9 → bustapi-0.14.1}/docs/examples-guide.md +0 -0
  61. {bustapi-0.13.9 → bustapi-0.14.1}/docs/index.md +0 -0
  62. {bustapi-0.13.9 → bustapi-0.14.1}/docs/installation.md +0 -0
  63. {bustapi-0.13.9 → bustapi-0.14.1}/docs/overrides/.gitkeep +0 -0
  64. {bustapi-0.13.9 → bustapi-0.14.1}/docs/quickstart.md +0 -0
  65. {bustapi-0.13.9 → bustapi-0.14.1}/docs/release_track.md +0 -0
  66. {bustapi-0.13.9 → bustapi-0.14.1}/docs/site/advanced/async_support.html +0 -0
  67. {bustapi-0.13.9 → bustapi-0.14.1}/docs/site/advanced/blueprints.html +0 -0
  68. {bustapi-0.13.9 → bustapi-0.14.1}/docs/site/advanced/dependency_injection.html +0 -0
  69. {bustapi-0.13.9 → bustapi-0.14.1}/docs/site/advanced/middleware.html +0 -0
  70. {bustapi-0.13.9 → bustapi-0.14.1}/docs/site/advanced/validation.html +0 -0
  71. {bustapi-0.13.9 → bustapi-0.14.1}/docs/site/api/all.html +0 -0
  72. {bustapi-0.13.9 → bustapi-0.14.1}/docs/site/api/app.html +0 -0
  73. {bustapi-0.13.9 → bustapi-0.14.1}/docs/site/api/context.html +0 -0
  74. {bustapi-0.13.9 → bustapi-0.14.1}/docs/site/api/utilities.html +0 -0
  75. {bustapi-0.13.9 → bustapi-0.14.1}/docs/site/assets/logo.png +0 -0
  76. {bustapi-0.13.9 → bustapi-0.14.1}/docs/site/changelog.html +0 -0
  77. {bustapi-0.13.9 → bustapi-0.14.1}/docs/site/core_concepts/request_data.html +0 -0
  78. {bustapi-0.13.9 → bustapi-0.14.1}/docs/site/core_concepts/responses.html +0 -0
  79. {bustapi-0.13.9 → bustapi-0.14.1}/docs/site/core_concepts/routing.html +0 -0
  80. {bustapi-0.13.9 → bustapi-0.14.1}/docs/site/core_concepts/templates.html +0 -0
  81. {bustapi-0.13.9 → bustapi-0.14.1}/docs/site/examples/index.html +0 -0
  82. {bustapi-0.13.9 → bustapi-0.14.1}/docs/site/getting_started/index.html +0 -0
  83. {bustapi-0.13.9 → bustapi-0.14.1}/docs/site/getting_started/quickstart.html +0 -0
  84. {bustapi-0.13.9 → bustapi-0.14.1}/docs/site/index.html +0 -0
  85. {bustapi-0.13.9 → bustapi-0.14.1}/docs/site/script.js +0 -0
  86. {bustapi-0.13.9 → bustapi-0.14.1}/docs/site/style.css +0 -0
  87. {bustapi-0.13.9 → bustapi-0.14.1}/docs/stylesheets/extra.css +0 -0
  88. {bustapi-0.13.9 → bustapi-0.14.1}/docs/user-guide/authentication.md +0 -0
  89. {bustapi-0.13.9 → bustapi-0.14.1}/docs/user-guide/caching.md +0 -0
  90. {bustapi-0.13.9 → bustapi-0.14.1}/docs/user-guide/cli.md +0 -0
  91. {bustapi-0.13.9 → bustapi-0.14.1}/docs/user-guide/database.md +0 -0
  92. {bustapi-0.13.9 → bustapi-0.14.1}/docs/user-guide/documentation.md +0 -0
  93. {bustapi-0.13.9 → bustapi-0.14.1}/docs/user-guide/error_handling.md +0 -0
  94. {bustapi-0.13.9 → bustapi-0.14.1}/docs/user-guide/jwt.md +0 -0
  95. {bustapi-0.13.9 → bustapi-0.14.1}/docs/user-guide/logging.md +0 -0
  96. {bustapi-0.13.9 → bustapi-0.14.1}/docs/user-guide/multiprocessing.md +0 -0
  97. {bustapi-0.13.9 → bustapi-0.14.1}/docs/user-guide/request_data.md +0 -0
  98. {bustapi-0.13.9 → bustapi-0.14.1}/docs/user-guide/responses.md +0 -0
  99. {bustapi-0.13.9 → bustapi-0.14.1}/docs/user-guide/routing.md +0 -0
  100. {bustapi-0.13.9 → bustapi-0.14.1}/docs/user-guide/sessions.md +0 -0
  101. {bustapi-0.13.9 → bustapi-0.14.1}/docs/user-guide/static_files.md +0 -0
  102. {bustapi-0.13.9 → bustapi-0.14.1}/docs/user-guide/templates.md +0 -0
  103. {bustapi-0.13.9 → bustapi-0.14.1}/docs/user-guide/turbo-routes.md +0 -0
  104. {bustapi-0.13.9 → bustapi-0.14.1}/docs/user-guide/video-streaming.md +0 -0
  105. {bustapi-0.13.9 → bustapi-0.14.1}/docs/websockets.md +0 -0
  106. {bustapi-0.13.9 → bustapi-0.14.1}/examples/advanced/08_auto_docs.py +0 -0
  107. {bustapi-0.13.9 → bustapi-0.14.1}/examples/advanced/12_test_modes.py +0 -0
  108. {bustapi-0.13.9 → bustapi-0.14.1}/examples/advanced/13_error_handling.py +0 -0
  109. {bustapi-0.13.9 → bustapi-0.14.1}/examples/advanced/14_middleware.py +0 -0
  110. {bustapi-0.13.9 → bustapi-0.14.1}/examples/advanced/16_middleware_session.py +0 -0
  111. {bustapi-0.13.9 → bustapi-0.14.1}/examples/advanced/20_file_uploads.py +0 -0
  112. {bustapi-0.13.9 → bustapi-0.14.1}/examples/advanced/24_body_and_depends.py +0 -0
  113. {bustapi-0.13.9 → bustapi-0.14.1}/examples/advanced/27_video_stream.py +0 -0
  114. {bustapi-0.13.9 → bustapi-0.14.1}/examples/advanced/28_websocket.py +0 -0
  115. {bustapi-0.13.9 → bustapi-0.14.1}/examples/advanced/29_turbo_websocket.py +0 -0
  116. {bustapi-0.13.9 → bustapi-0.14.1}/examples/basics/01_hello_world.py +0 -0
  117. {bustapi-0.13.9 → bustapi-0.14.1}/examples/basics/02_parameters.py +0 -0
  118. {bustapi-0.13.9 → bustapi-0.14.1}/examples/basics/03_async.py +0 -0
  119. {bustapi-0.13.9 → bustapi-0.14.1}/examples/basics/04_request_data.py +0 -0
  120. {bustapi-0.13.9 → bustapi-0.14.1}/examples/basics/19_all_types.py +0 -0
  121. {bustapi-0.13.9 → bustapi-0.14.1}/examples/database/07_database_raw.py +0 -0
  122. {bustapi-0.13.9 → bustapi-0.14.1}/examples/database/10_database_sqlmodel.py +0 -0
  123. {bustapi-0.13.9 → bustapi-0.14.1}/examples/routing/06_blueprints.py +0 -0
  124. {bustapi-0.13.9 → bustapi-0.14.1}/examples/routing/09_complex_routing.py +0 -0
  125. {bustapi-0.13.9 → bustapi-0.14.1}/examples/routing/21_path_validation.py +0 -0
  126. {bustapi-0.13.9 → bustapi-0.14.1}/examples/routing/22_path_docs.py +0 -0
  127. {bustapi-0.13.9 → bustapi-0.14.1}/examples/routing/23_query_validation.py +0 -0
  128. {bustapi-0.13.9 → bustapi-0.14.1}/examples/routing/blueprint_with_jwt.py +0 -0
  129. {bustapi-0.13.9 → bustapi-0.14.1}/examples/security/10_rate_limit_demo.py +0 -0
  130. {bustapi-0.13.9 → bustapi-0.14.1}/examples/security/11_security_demo.py +0 -0
  131. {bustapi-0.13.9 → bustapi-0.14.1}/examples/security/17_jwt_auth.py +0 -0
  132. {bustapi-0.13.9 → bustapi-0.14.1}/examples/security/17_safe_features.py +0 -0
  133. {bustapi-0.13.9 → bustapi-0.14.1}/examples/security/18_jwt_cookies.py +0 -0
  134. {bustapi-0.13.9 → bustapi-0.14.1}/examples/security/18_safe_advanced.py +0 -0
  135. {bustapi-0.13.9 → bustapi-0.14.1}/examples/security/18_session_login.py +0 -0
  136. {bustapi-0.13.9 → bustapi-0.14.1}/examples/templates/05_templates.py +0 -0
  137. {bustapi-0.13.9 → bustapi-0.14.1}/examples/templates/26_complex_template.py +0 -0
  138. {bustapi-0.13.9 → bustapi-0.14.1}/examples/templates/templates/index.html +0 -0
  139. {bustapi-0.13.9 → bustapi-0.14.1}/examples/turbo/cache_test.py +0 -0
  140. {bustapi-0.13.9 → bustapi-0.14.1}/examples/turbo/fair_benchmark.py +0 -0
  141. {bustapi-0.13.9 → bustapi-0.14.1}/examples/turbo/typed_turbo_example.py +0 -0
  142. {bustapi-0.13.9 → bustapi-0.14.1}/examples/ws/app.py +0 -0
  143. {bustapi-0.13.9 → bustapi-0.14.1}/examples/ws/templates/index.html +0 -0
  144. {bustapi-0.13.9 → bustapi-0.14.1}/examples/ws/websockets_demo.py +0 -0
  145. {bustapi-0.13.9 → bustapi-0.14.1}/examples/ws/ws_limit.py +0 -0
  146. {bustapi-0.13.9 → bustapi-0.14.1}/mkdocs.yml +0 -0
  147. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/auth/__init__.py +0 -0
  148. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/auth/csrf.py +0 -0
  149. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/auth/decorators.py +0 -0
  150. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/auth/password.py +0 -0
  151. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/auth/tokens.py +0 -0
  152. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/auth/user.py +0 -0
  153. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/cli/__init__.py +0 -0
  154. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/cli/main.py +0 -0
  155. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/context.py +0 -0
  156. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/core/__init__.py +0 -0
  157. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/core/asgi.py +0 -0
  158. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/core/exceptions.py +0 -0
  159. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/core/logging.py +0 -0
  160. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/dependencies.py +0 -0
  161. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/documentation/__init__.py +0 -0
  162. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/documentation/generator.py +0 -0
  163. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/extraction.py +0 -0
  164. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/fastapi_compat.py +0 -0
  165. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/hooks.py +0 -0
  166. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/http/__init__.py +0 -0
  167. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/http/response.py +0 -0
  168. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/jwt.py +0 -0
  169. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/logging.py +0 -0
  170. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/middleware.py +0 -0
  171. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/multiprocess.py +0 -0
  172. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/params.py +0 -0
  173. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/py.typed +0 -0
  174. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/responses.py +0 -0
  175. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/routing/__init__.py +0 -0
  176. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/routing/decorators.py +0 -0
  177. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/safe/__init__.py +0 -0
  178. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/safe/concurrency.py +0 -0
  179. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/safe/types.py +0 -0
  180. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/security/__init__.py +0 -0
  181. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/security/extension.py +0 -0
  182. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/security/rate_limit.py +0 -0
  183. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/server/__init__.py +0 -0
  184. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/server/runner.py +0 -0
  185. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/server/wsgi.py +0 -0
  186. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/templating/__init__.py +0 -0
  187. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/templating/engine.py +0 -0
  188. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/templating/mixin.py +0 -0
  189. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/testing/__init__.py +0 -0
  190. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/testing/client.py +0 -0
  191. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/utils.py +0 -0
  192. {bustapi-0.13.9 → bustapi-0.14.1}/python/bustapi/websocket.py +0 -0
  193. {bustapi-0.13.9 → bustapi-0.14.1}/run_all_examples.py +0 -0
  194. {bustapi-0.13.9 → bustapi-0.14.1}/scratch/test_abort.py +0 -0
  195. {bustapi-0.13.9 → bustapi-0.14.1}/scratch/test_headers.py +0 -0
  196. {bustapi-0.13.9 → bustapi-0.14.1}/src/bindings/app.rs +0 -0
  197. {bustapi-0.13.9 → bustapi-0.14.1}/src/bindings/converters.rs +0 -0
  198. {bustapi-0.13.9 → bustapi-0.14.1}/src/bindings/handlers.rs +0 -0
  199. {bustapi-0.13.9 → bustapi-0.14.1}/src/bindings/mod.rs +0 -0
  200. {bustapi-0.13.9 → bustapi-0.14.1}/src/bindings/request.rs +0 -0
  201. {bustapi-0.13.9 → bustapi-0.14.1}/src/bindings/typed_turbo.rs +0 -0
  202. {bustapi-0.13.9 → bustapi-0.14.1}/src/bindings/websocket.rs +0 -0
  203. {bustapi-0.13.9 → bustapi-0.14.1}/src/crypto.rs +0 -0
  204. {bustapi-0.13.9 → bustapi-0.14.1}/src/jwt.rs +0 -0
  205. {bustapi-0.13.9 → bustapi-0.14.1}/src/lib.rs +0 -0
  206. {bustapi-0.13.9 → bustapi-0.14.1}/src/logger.rs +0 -0
  207. {bustapi-0.13.9 → bustapi-0.14.1}/src/rate_limiter.rs +0 -0
  208. {bustapi-0.13.9 → bustapi-0.14.1}/src/request/methods.rs +0 -0
  209. {bustapi-0.13.9 → bustapi-0.14.1}/src/request/mod.rs +0 -0
  210. {bustapi-0.13.9 → bustapi-0.14.1}/src/request/tests.rs +0 -0
  211. {bustapi-0.13.9 → bustapi-0.14.1}/src/response/builders.rs +0 -0
  212. {bustapi-0.13.9 → bustapi-0.14.1}/src/response/methods.rs +0 -0
  213. {bustapi-0.13.9 → bustapi-0.14.1}/src/response/mod.rs +0 -0
  214. {bustapi-0.13.9 → bustapi-0.14.1}/src/router/handlers.rs +0 -0
  215. {bustapi-0.13.9 → bustapi-0.14.1}/src/router/matching.rs +0 -0
  216. {bustapi-0.13.9 → bustapi-0.14.1}/src/router/middleware.rs +0 -0
  217. {bustapi-0.13.9 → bustapi-0.14.1}/src/router/mod.rs +0 -0
  218. {bustapi-0.13.9 → bustapi-0.14.1}/src/router/tests.rs +0 -0
  219. {bustapi-0.13.9 → bustapi-0.14.1}/src/server/handlers.rs +0 -0
  220. {bustapi-0.13.9 → bustapi-0.14.1}/src/server/mod.rs +0 -0
  221. {bustapi-0.13.9 → bustapi-0.14.1}/src/server/startup.rs +0 -0
  222. {bustapi-0.13.9 → bustapi-0.14.1}/src/server/stream.rs +0 -0
  223. {bustapi-0.13.9 → bustapi-0.14.1}/src/static_files.rs +0 -0
  224. {bustapi-0.13.9 → bustapi-0.14.1}/src/templating.rs +0 -0
  225. {bustapi-0.13.9 → bustapi-0.14.1}/src/watcher.rs +0 -0
  226. {bustapi-0.13.9 → bustapi-0.14.1}/src/websocket/config.rs +0 -0
  227. {bustapi-0.13.9 → bustapi-0.14.1}/src/websocket/mod.rs +0 -0
  228. {bustapi-0.13.9 → bustapi-0.14.1}/src/websocket/session.rs +0 -0
  229. {bustapi-0.13.9 → bustapi-0.14.1}/src/websocket/turbo.rs +0 -0
  230. {bustapi-0.13.9 → bustapi-0.14.1}/static/style.css +0 -0
  231. {bustapi-0.13.9 → bustapi-0.14.1}/templates/base.html +0 -0
  232. {bustapi-0.13.9 → bustapi-0.14.1}/templates/complex.html +0 -0
  233. {bustapi-0.13.9 → bustapi-0.14.1}/tests/docs_test_all.py +0 -0
  234. {bustapi-0.13.9 → bustapi-0.14.1}/tests/docs_test_api_reference.py +0 -0
  235. {bustapi-0.13.9 → bustapi-0.14.1}/tests/docs_test_installation.py +0 -0
  236. {bustapi-0.13.9 → bustapi-0.14.1}/tests/docs_test_quickstart.py +0 -0
  237. {bustapi-0.13.9 → bustapi-0.14.1}/tests/docs_test_simple.py +0 -0
  238. {bustapi-0.13.9 → bustapi-0.14.1}/tests/test_050_features.py +0 -0
  239. {bustapi-0.13.9 → bustapi-0.14.1}/tests/test_async_hooks.py +0 -0
  240. {bustapi-0.13.9 → bustapi-0.14.1}/tests/test_auth.py +0 -0
  241. {bustapi-0.13.9 → bustapi-0.14.1}/tests/test_discussion_21.py +0 -0
  242. {bustapi-0.13.9 → bustapi-0.14.1}/tests/test_discussion_22.py +0 -0
  243. {bustapi-0.13.9 → bustapi-0.14.1}/tests/test_discussion_28.py +0 -0
  244. {bustapi-0.13.9 → bustapi-0.14.1}/tests/test_examples.py +0 -0
  245. {bustapi-0.13.9 → bustapi-0.14.1}/tests/test_hot_reload.py +0 -0
  246. {bustapi-0.13.9 → bustapi-0.14.1}/tests/test_issue_18.py +0 -0
  247. {bustapi-0.13.9 → bustapi-0.14.1}/tests/test_issue_23.py +0 -0
  248. {bustapi-0.13.9 → bustapi-0.14.1}/tests/test_issue_24.py +0 -0
  249. {bustapi-0.13.9 → bustapi-0.14.1}/tests/test_jwt.py +0 -0
  250. {bustapi-0.13.9 → bustapi-0.14.1}/tests/test_jwt_cookies.py +0 -0
  251. {bustapi-0.13.9 → bustapi-0.14.1}/tests/test_middleware.py +0 -0
  252. {bustapi-0.13.9 → bustapi-0.14.1}/tests/test_multiprocess_stability.py +0 -0
  253. {bustapi-0.13.9 → bustapi-0.14.1}/tests/test_new_examples.py +0 -0
  254. {bustapi-0.13.9 → bustapi-0.14.1}/tests/test_orm_conflict.py +0 -0
  255. {bustapi-0.13.9 → bustapi-0.14.1}/tests/test_path_standalone.py +0 -0
  256. {bustapi-0.13.9 → bustapi-0.14.1}/tests/test_path_validation.py +0 -0
  257. {bustapi-0.13.9 → bustapi-0.14.1}/tests/test_rate_limit_rust.py +0 -0
  258. {bustapi-0.13.9 → bustapi-0.14.1}/tests/test_safe.py +0 -0
  259. {bustapi-0.13.9 → bustapi-0.14.1}/tests/test_security_unit.py +0 -0
  260. {bustapi-0.13.9 → bustapi-0.14.1}/tests/test_sessions.py +0 -0
  261. {bustapi-0.13.9 → bustapi-0.14.1}/tests/test_zero_copy.py +0 -0
  262. {bustapi-0.13.9 → bustapi-0.14.1}/tests/verify_router.py +0 -0
@@ -164,4 +164,5 @@ ignore/*.md
164
164
  ignore/
165
165
  issues/
166
166
 
167
- *.db
167
+ *.db
168
+ scratch/
@@ -2,9 +2,22 @@
2
2
 
3
3
  All notable changes to this project will be documented here.
4
4
 
5
+ ## [0.14.1] - 2026-06-17
6
+
7
+ ### Fixed
8
+ - **Auth Login**: Resolved `RuntimeWarning: coroutine 'load_user' was never awaited` when using an asynchronous `user_loader` callback with `login_user(user_id)`. The loader's return value is now correctly run/awaited synchronously.
9
+ - **Session Expiration**: Replaced deprecated `datetime.utcnow()` with timezone-aware `datetime.now(timezone.utc)` to avoid future Python compatibility deprecation warnings.
10
+
11
+ ## [0.14.0] - 2026-06-17
12
+
13
+ ### Added
14
+ - **Auth Login**: Enhanced `login_user()` to accept a raw `user_id` (string, integer, or UUID) directly as the user argument, resolving Discussion #27.
15
+ - **Blueprint Routing Stabilization**: Stabilized Blueprint routing structure (Issue #29) with support for relative `url_for()` endpoint resolution, nested lifecycle hooks (`before_request`, `after_request`, `teardown_request`), and blueprint-specific error handlers (`@bp.errorhandler`).
16
+
5
17
  ## [0.13.9] - 2026-06-12
6
18
 
7
19
  ### Fixed
20
+ - **Blueprint Routing**: Fixed an issue where routes registered via `app.register_blueprint()` were not added to the application's `url_map`. This ensures `url_for()` can correctly reverse-map Blueprint endpoints (Issue #29).
8
21
  - **Session Permanence**: Fixed a bug in `SessionMixin` where `session.permanent` was not serialized into the session payload, causing it to drop across requests. It now functions correctly as a persistent session setting.
9
22
  - **Login Manager Remember**: `login_user(user, remember=True)` now automatically sets `session.permanent = True` as expected, tying persistent logins to the application's permanent session lifetime configuration.
10
23
 
@@ -318,9 +318,9 @@ checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3"
318
318
 
319
319
  [[package]]
320
320
  name = "alloc-stdlib"
321
- version = "0.2.2"
321
+ version = "0.2.4"
322
322
  source = "registry+https://github.com/rust-lang/crates.io-index"
323
- checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece"
323
+ checksum = "0e76a019e91224d279006ff972f1e984179a6e9feb050adba6ce8274aef23195"
324
324
  dependencies = [
325
325
  "alloc-no-stdlib",
326
326
  ]
@@ -405,9 +405,9 @@ dependencies = [
405
405
 
406
406
  [[package]]
407
407
  name = "brotli"
408
- version = "8.0.3"
408
+ version = "8.0.4"
409
409
  source = "registry+https://github.com/rust-lang/crates.io-index"
410
- checksum = "8119e4516436f5708bbc474a9d395bf12f1b5395e93a92a56e647ac3388c8610"
410
+ checksum = "5cc91aac060a7a1e25823bdccbfb6af1875b88f17c6daac97894eed8207166b3"
411
411
  dependencies = [
412
412
  "alloc-no-stdlib",
413
413
  "alloc-stdlib",
@@ -416,9 +416,9 @@ dependencies = [
416
416
 
417
417
  [[package]]
418
418
  name = "brotli-decompressor"
419
- version = "5.0.1"
419
+ version = "5.0.3"
420
420
  source = "registry+https://github.com/rust-lang/crates.io-index"
421
- checksum = "5962523e1b92ce1b5e793d9169b9943eece10d39f62550bc04bb605d75b94924"
421
+ checksum = "3a32acac15fe1967bc3986b2a6347dffc965602354ea6f450ad07e8bfd253583"
422
422
  dependencies = [
423
423
  "alloc-no-stdlib",
424
424
  "alloc-stdlib",
@@ -432,7 +432,7 @@ checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
432
432
 
433
433
  [[package]]
434
434
  name = "bustapi_core"
435
- version = "0.13.9"
435
+ version = "0.14.1"
436
436
  dependencies = [
437
437
  "actix-files",
438
438
  "actix-http",
@@ -491,9 +491,9 @@ dependencies = [
491
491
 
492
492
  [[package]]
493
493
  name = "cc"
494
- version = "1.2.63"
494
+ version = "1.2.64"
495
495
  source = "registry+https://github.com/rust-lang/crates.io-index"
496
- checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f"
496
+ checksum = "dad887fd958be91b5098c0248def011f4523ab786cd411be668777e55063501f"
497
497
  dependencies = [
498
498
  "find-msvc-tools",
499
499
  "jobserver",
@@ -722,9 +722,6 @@ name = "deranged"
722
722
  version = "0.5.8"
723
723
  source = "registry+https://github.com/rust-lang/crates.io-index"
724
724
  checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
725
- dependencies = [
726
- "powerfmt",
727
- ]
728
725
 
729
726
  [[package]]
730
727
  name = "derive_more"
@@ -1329,9 +1326,9 @@ dependencies = [
1329
1326
 
1330
1327
  [[package]]
1331
1328
  name = "js-sys"
1332
- version = "0.3.100"
1329
+ version = "0.3.102"
1333
1330
  source = "registry+https://github.com/rust-lang/crates.io-index"
1334
- checksum = "f2025f20d7a4fa7785846e7b63d10a76d3f1cee98ee5cb79ea59703f95e42162"
1331
+ checksum = "03d04c30968dffe80775bd4d7fb676131cd04a1fb46d2686dbffbaec2d9dfd31"
1335
1332
  dependencies = [
1336
1333
  "cfg-if",
1337
1334
  "futures-util",
@@ -2132,9 +2129,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
2132
2129
 
2133
2130
  [[package]]
2134
2131
  name = "syn"
2135
- version = "2.0.117"
2132
+ version = "2.0.118"
2136
2133
  source = "registry+https://github.com/rust-lang/crates.io-index"
2137
- checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
2134
+ checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
2138
2135
  dependencies = [
2139
2136
  "proc-macro2",
2140
2137
  "quote",
@@ -2202,12 +2199,11 @@ dependencies = [
2202
2199
 
2203
2200
  [[package]]
2204
2201
  name = "time"
2205
- version = "0.3.47"
2202
+ version = "0.3.49"
2206
2203
  source = "registry+https://github.com/rust-lang/crates.io-index"
2207
- checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c"
2204
+ checksum = "711a53c2d47bbd818258c498c8dbfe186a2526c631495cfe7e078567f86b8469"
2208
2205
  dependencies = [
2209
2206
  "deranged",
2210
- "itoa",
2211
2207
  "num-conv",
2212
2208
  "powerfmt",
2213
2209
  "serde_core",
@@ -2217,15 +2213,15 @@ dependencies = [
2217
2213
 
2218
2214
  [[package]]
2219
2215
  name = "time-core"
2220
- version = "0.1.8"
2216
+ version = "0.1.9"
2221
2217
  source = "registry+https://github.com/rust-lang/crates.io-index"
2222
- checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca"
2218
+ checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109"
2223
2219
 
2224
2220
  [[package]]
2225
2221
  name = "time-macros"
2226
- version = "0.2.27"
2222
+ version = "0.2.29"
2227
2223
  source = "registry+https://github.com/rust-lang/crates.io-index"
2228
- checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215"
2224
+ checksum = "71c652a3727a9cbb9a02f707f530b618ce00d0ccd762009c8c23bd191df3c17d"
2229
2225
  dependencies = [
2230
2226
  "num-conv",
2231
2227
  "time-core",
@@ -2438,9 +2434,9 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
2438
2434
 
2439
2435
  [[package]]
2440
2436
  name = "wasip2"
2441
- version = "1.0.3+wasi-0.2.9"
2437
+ version = "1.0.4+wasi-0.2.12"
2442
2438
  source = "registry+https://github.com/rust-lang/crates.io-index"
2443
- checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6"
2439
+ checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487"
2444
2440
  dependencies = [
2445
2441
  "wit-bindgen 0.57.1",
2446
2442
  ]
@@ -2456,9 +2452,9 @@ dependencies = [
2456
2452
 
2457
2453
  [[package]]
2458
2454
  name = "wasm-bindgen"
2459
- version = "0.2.123"
2455
+ version = "0.2.125"
2460
2456
  source = "registry+https://github.com/rust-lang/crates.io-index"
2461
- checksum = "a254a4b10c19a76f09a27640e7ffbf9bc30bf67e16a3bf28aaefa4920fe81563"
2457
+ checksum = "8ddb3f79143bced6de84270411622a2699cee572fc0875aeaf1e7867cf9fca1a"
2462
2458
  dependencies = [
2463
2459
  "cfg-if",
2464
2460
  "once_cell",
@@ -2469,9 +2465,9 @@ dependencies = [
2469
2465
 
2470
2466
  [[package]]
2471
2467
  name = "wasm-bindgen-macro"
2472
- version = "0.2.123"
2468
+ version = "0.2.125"
2473
2469
  source = "registry+https://github.com/rust-lang/crates.io-index"
2474
- checksum = "24a40fc75b0ec6f3746ceb10d36f53a93dcd68a93b11b6445983945d79eba0dc"
2470
+ checksum = "4e21a184b13fb19e157296e2c46056aec9092264fab83e4ba59e68c61b323c3d"
2475
2471
  dependencies = [
2476
2472
  "quote",
2477
2473
  "wasm-bindgen-macro-support",
@@ -2479,9 +2475,9 @@ dependencies = [
2479
2475
 
2480
2476
  [[package]]
2481
2477
  name = "wasm-bindgen-macro-support"
2482
- version = "0.2.123"
2478
+ version = "0.2.125"
2483
2479
  source = "registry+https://github.com/rust-lang/crates.io-index"
2484
- checksum = "908f34bd9b9ce3d4caf07b72dfab63d61504d156856c6bd3cd87fa350cf3985b"
2480
+ checksum = "fecefd9c35bd935a20fc3fc344b5f29138961e4f47fb03297d88f2587afb5ebd"
2485
2481
  dependencies = [
2486
2482
  "bumpalo",
2487
2483
  "proc-macro2",
@@ -2492,9 +2488,9 @@ dependencies = [
2492
2488
 
2493
2489
  [[package]]
2494
2490
  name = "wasm-bindgen-shared"
2495
- version = "0.2.123"
2491
+ version = "0.2.125"
2496
2492
  source = "registry+https://github.com/rust-lang/crates.io-index"
2497
- checksum = "7acbf7616c27b194bbb550bf77ed0c2c3e5b7fd1260a93082b95fb7f47959b92"
2493
+ checksum = "23939e44bb9a5d7576fa2b563dc2e136628f1224e88a8deed09e04858b77871f"
2498
2494
  dependencies = [
2499
2495
  "unicode-ident",
2500
2496
  ]
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "bustapi_core"
3
- version = "0.13.9"
3
+ version = "0.14.1"
4
4
  edition = "2021"
5
5
  readme = "README.md"
6
6
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bustapi
3
- Version: 0.13.9
3
+ Version: 0.14.1
4
4
  Classifier: Development Status :: 3 - Alpha
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -2,9 +2,22 @@
2
2
 
3
3
  All notable changes to this project will be documented here.
4
4
 
5
+ ## [0.14.1] - 2026-06-17
6
+
7
+ ### Fixed
8
+ - **Auth Login**: Resolved `RuntimeWarning: coroutine 'load_user' was never awaited` when using an asynchronous `user_loader` callback with `login_user(user_id)`. The loader's return value is now correctly run/awaited synchronously.
9
+ - **Session Expiration**: Replaced deprecated `datetime.utcnow()` with timezone-aware `datetime.now(timezone.utc)` to avoid future Python compatibility deprecation warnings.
10
+
11
+ ## [0.14.0] - 2026-06-17
12
+
13
+ ### Added
14
+ - **Auth Login**: Enhanced `login_user()` to accept a raw `user_id` (string, integer, or UUID) directly as the user argument, resolving Discussion #27.
15
+ - **Blueprint Routing Stabilization**: Stabilized Blueprint routing structure (Issue #29) with support for relative `url_for()` endpoint resolution, nested lifecycle hooks (`before_request`, `after_request`, `teardown_request`), and blueprint-specific error handlers (`@bp.errorhandler`).
16
+
5
17
  ## [0.13.9] - 2026-06-12
6
18
 
7
19
  ### Fixed
20
+ - **Blueprint Routing**: Fixed an issue where routes registered via `app.register_blueprint()` were not added to the application's `url_map`. This ensures `url_for()` can correctly reverse-map Blueprint endpoints (Issue #29).
8
21
  - **Session Permanence**: Fixed a bug in `SessionMixin` where `session.permanent` was not serialized into the session payload, causing it to drop across requests. It now functions correctly as a persistent session setting.
9
22
  - **Login Manager Remember**: `login_user(user, remember=True)` now automatically sets `session.permanent = True` as expected, tying persistent logins to the application's permanent session lifetime configuration.
10
23
 
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "bustapi"
7
- version = "0.13.9"
7
+ version = "0.14.1"
8
8
  description = "High-performance Python web framework with Rust backend"
9
9
  authors = [
10
10
  {name = "GrandpaEJ", email = ""}
@@ -22,7 +22,7 @@ import platform
22
22
  import sys
23
23
  from http import HTTPStatus
24
24
 
25
- __version__ = "0.13.9"
25
+ __version__ = "0.14.1"
26
26
  __author__ = "BustAPI" # with GrandpaEJ
27
27
  __email__ = ""
28
28
 
@@ -144,7 +144,6 @@ class BustAPI(
144
144
  raise RuntimeError(f"Failed to initialize Rust backend: {e}") from e
145
145
 
146
146
  def register_blueprint(self, blueprint: Blueprint, **options) -> None:
147
- url_prefix = options.get("url_prefix", blueprint.url_prefix)
148
147
  self.blueprints[blueprint.name] = blueprint
149
148
 
150
149
  # Register blueprint template context processors
@@ -155,20 +154,8 @@ class BustAPI(
155
154
  blueprint.app_context_processor_funcs
156
155
  )
157
156
 
158
- for rule, endpoint, view_func, methods in blueprint.deferred_functions:
159
- if url_prefix:
160
- rule = url_prefix.rstrip("/") + "/" + rule.lstrip("/")
161
- full_endpoint = f"{blueprint.name}.{endpoint}"
162
- self.view_functions[full_endpoint] = view_func
163
- for method in methods:
164
- if inspect.iscoroutinefunction(view_func):
165
- self._rust_app.add_async_route(
166
- method, rule, create_async_wrapper(self, view_func, rule)
167
- )
168
- else:
169
- self._rust_app.add_route(
170
- method, rule, create_sync_wrapper(self, view_func, rule)
171
- )
157
+ # Register all deferred functions (routes, hooks, etc.)
158
+ blueprint.register(self, options)
172
159
 
173
160
  def add_websocket_route(
174
161
  self, path: str, handler: Any, config: Optional[Any] = None
@@ -184,6 +171,38 @@ class BustAPI(
184
171
  return make_response(*args)
185
172
 
186
173
  def _handle_exception(self, exception: Exception) -> Response:
174
+ from .http.request import request
175
+
176
+ # 1. Try blueprint-specific error handlers first
177
+ bp = (
178
+ self.blueprints.get(request.blueprint)
179
+ if (request and request.blueprint)
180
+ else None
181
+ )
182
+ if bp:
183
+ for exc_class_or_code, handler in bp.error_handler_spec.items():
184
+ if isinstance(exc_class_or_code, type) and isinstance(
185
+ exception, exc_class_or_code
186
+ ):
187
+ rv = handler(exception)
188
+ return (
189
+ self._make_response(*rv)
190
+ if isinstance(rv, tuple)
191
+ else self._make_response(rv)
192
+ )
193
+ elif isinstance(exc_class_or_code, int):
194
+ if (
195
+ hasattr(exception, "code")
196
+ and exception.code == exc_class_or_code
197
+ ):
198
+ rv = handler(exception)
199
+ return (
200
+ self._make_response(*rv)
201
+ if isinstance(rv, tuple)
202
+ else self._make_response(rv)
203
+ )
204
+
205
+ # 2. Try app-wide error handlers
187
206
  for exc_class_or_code, handler in self.error_handler_spec.items():
188
207
  if isinstance(exc_class_or_code, type) and isinstance(
189
208
  exception, exc_class_or_code
@@ -94,7 +94,7 @@ def login_user(user, remember: bool = False, fresh: bool = True) -> bool:
94
94
  Log in a user.
95
95
 
96
96
  Args:
97
- user: User object (must have get_id() method)
97
+ user: User object (must have get_id() method) or user_id (str, int)
98
98
  remember: Create persistent session
99
99
  fresh: Mark session as fresh (from password login)
100
100
 
@@ -106,6 +106,8 @@ def login_user(user, remember: bool = False, fresh: bool = True) -> bool:
106
106
  if not session:
107
107
  return False
108
108
 
109
+ is_user_id = False
110
+
109
111
  # Get user ID
110
112
  # 1. Support custom conflict-free get_login_id() first
111
113
  user_id = getattr(user, "get_login_id", lambda: None)()
@@ -122,7 +124,14 @@ def login_user(user, remember: bool = False, fresh: bool = True) -> bool:
122
124
  try:
123
125
  user_id = str(user.id)
124
126
  except AttributeError:
125
- return False
127
+ # 5. Check if `user` itself is the user ID (string, integer, etc.)
128
+ import uuid
129
+
130
+ if isinstance(user, (str, int, uuid.UUID)):
131
+ user_id = str(user)
132
+ is_user_id = True
133
+ else:
134
+ return False
126
135
 
127
136
  # Get login manager config
128
137
  login_manager = getattr(request, "app", None)
@@ -146,7 +155,38 @@ def login_user(user, remember: bool = False, fresh: bool = True) -> bool:
146
155
  session.permanent = True
147
156
 
148
157
  # Update request
149
- request._login_user = user
158
+ if is_user_id:
159
+ loaded_user = None
160
+ if login_manager and login_manager._user_loader_callback:
161
+ import inspect
162
+
163
+ try:
164
+ res = login_manager._user_loader_callback(user_id)
165
+ if inspect.isawaitable(res):
166
+ from ..utils import async_to_sync
167
+
168
+ loaded_user = async_to_sync(res)
169
+ else:
170
+ loaded_user = res
171
+ except Exception:
172
+ pass
173
+
174
+ if loaded_user is not None:
175
+ request._login_user = loaded_user
176
+ else:
177
+ from .user import BaseUser
178
+
179
+ class SimpleUser(BaseUser):
180
+ def __init__(self, uid: str):
181
+ self.id = uid
182
+
183
+ def get_id(self) -> str:
184
+ return self.id
185
+
186
+ request._login_user = SimpleUser(user_id)
187
+ else:
188
+ request._login_user = user
189
+
150
190
  request._login_fresh = fresh
151
191
 
152
192
  return True
@@ -59,6 +59,17 @@ def url_for(endpoint: str, **values) -> str:
59
59
  # Get current application to access url_map
60
60
  app = _get_current_object()
61
61
 
62
+ # Handle relative endpoint (e.g. '.index' -> 'blueprint.index')
63
+ if endpoint.startswith("."):
64
+ from ..http.request import request
65
+
66
+ if request and request.blueprint:
67
+ endpoint = f"{request.blueprint}{endpoint}"
68
+ else:
69
+ raise RuntimeError(
70
+ "Working outside of request context or no blueprint active"
71
+ )
72
+
62
73
  # Find rule for endpoint
63
74
  rule = None
64
75
  for r, options in app.url_map.items():
@@ -130,8 +130,12 @@ def create_sync_wrapper(app: "BustAPI", handler: Callable, rule: str) -> Callabl
130
130
  request.session = session
131
131
 
132
132
  # 3. Before Request Hooks
133
- if app.before_request_funcs:
134
- for before_func in app.before_request_funcs:
133
+ bp = app.blueprints.get(request.blueprint) if request.blueprint else None
134
+ before_funcs = (
135
+ bp.before_request_funcs if bp else []
136
+ ) + app.before_request_funcs
137
+ if before_funcs:
138
+ for before_func in before_funcs:
135
139
  res = before_func()
136
140
  if inspect.isawaitable(res):
137
141
  res = async_to_sync(res)
@@ -262,8 +266,12 @@ def create_sync_wrapper(app: "BustAPI", handler: Callable, rule: str) -> Callabl
262
266
  # 5. Pipeline Cleanup and Hooks
263
267
  if app.middleware_manager.middlewares:
264
268
  response = app.middleware_manager.process_response(request, response)
265
- if app.after_request_funcs:
266
- for after_func in app.after_request_funcs:
269
+ bp = app.blueprints.get(request.blueprint) if request.blueprint else None
270
+ after_funcs = (
271
+ bp.after_request_funcs if bp else []
272
+ ) + app.after_request_funcs
273
+ if after_funcs:
274
+ for after_func in after_funcs:
267
275
  res = after_func(response)
268
276
  if inspect.isawaitable(res):
269
277
  res = async_to_sync(res)
@@ -276,8 +284,12 @@ def create_sync_wrapper(app: "BustAPI", handler: Callable, rule: str) -> Callabl
276
284
  except Exception as e:
277
285
  return app._response_to_rust_format(app._handle_exception(e))
278
286
  finally:
279
- if app.teardown_request_funcs:
280
- for f in app.teardown_request_funcs:
287
+ bp = app.blueprints.get(request.blueprint) if request.blueprint else None
288
+ teardown_funcs = (
289
+ bp.teardown_request_funcs if bp else []
290
+ ) + app.teardown_request_funcs
291
+ if teardown_funcs:
292
+ for f in teardown_funcs:
281
293
  try:
282
294
  res = f(None)
283
295
  if inspect.isawaitable(res):
@@ -325,8 +337,14 @@ def create_async_wrapper(app: "BustAPI", handler: Callable, rule: str) -> Callab
325
337
  session = app.session_interface.open_session(app, request)
326
338
  request.session = session
327
339
 
328
- if app.before_request_funcs:
329
- for before_func in app.before_request_funcs:
340
+ bp = (
341
+ app.blueprints.get(request.blueprint) if request.blueprint else None
342
+ )
343
+ before_funcs = (
344
+ bp.before_request_funcs if bp else []
345
+ ) + app.before_request_funcs
346
+ if before_funcs:
347
+ for before_func in before_funcs:
330
348
  res = before_func()
331
349
  if inspect.isawaitable(res):
332
350
  res = await res
@@ -424,8 +442,14 @@ def create_async_wrapper(app: "BustAPI", handler: Callable, rule: str) -> Callab
424
442
  response = app.middleware_manager.process_response(
425
443
  request, response
426
444
  )
427
- if app.after_request_funcs:
428
- for after_func in app.after_request_funcs:
445
+ bp = (
446
+ app.blueprints.get(request.blueprint) if request.blueprint else None
447
+ )
448
+ after_funcs = (
449
+ bp.after_request_funcs if bp else []
450
+ ) + app.after_request_funcs
451
+ if after_funcs:
452
+ for after_func in after_funcs:
429
453
  res = after_func(response)
430
454
  if inspect.isawaitable(res):
431
455
  res = await res
@@ -438,8 +462,14 @@ def create_async_wrapper(app: "BustAPI", handler: Callable, rule: str) -> Callab
438
462
  except Exception as e:
439
463
  return app._handle_exception(e)
440
464
  finally:
441
- if app.teardown_request_funcs:
442
- for f in app.teardown_request_funcs:
465
+ bp = (
466
+ app.blueprints.get(request.blueprint) if request.blueprint else None
467
+ )
468
+ teardown_funcs = (
469
+ bp.teardown_request_funcs if bp else []
470
+ ) + app.teardown_request_funcs
471
+ if teardown_funcs:
472
+ for f in teardown_funcs:
443
473
  try:
444
474
  res = f(None)
445
475
  if inspect.isawaitable(res):
@@ -49,6 +49,7 @@ class Request:
49
49
  self._user = None
50
50
  self._login_user = None
51
51
  self._login_fresh = None
52
+ self.endpoint = None
52
53
 
53
54
  @classmethod
54
55
  def _from_rust_request(cls, rust_request) -> "Request":
@@ -363,6 +364,13 @@ class Request:
363
364
  """Set the authenticated user."""
364
365
  self._user = value
365
366
 
367
+ @property
368
+ def blueprint(self) -> Optional[str]:
369
+ """The name of the current blueprint, if any."""
370
+ if self.endpoint and "." in self.endpoint:
371
+ return self.endpoint.split(".", 1)[0]
372
+ return None
373
+
366
374
 
367
375
  class EnvironHeaders:
368
376
  """