bustapi 0.14.1__tar.gz → 0.14.3__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.
- {bustapi-0.14.1 → bustapi-0.14.3}/CHANGELOG.md +11 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/Cargo.lock +10 -176
- {bustapi-0.14.1 → bustapi-0.14.3}/Cargo.toml +1 -1
- {bustapi-0.14.1 → bustapi-0.14.3}/PKG-INFO +1 -1
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/changelog.md +11 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/pyproject.toml +1 -1
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/__init__.py +1 -1
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/app.py +32 -1
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/core/helpers.py +2 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/routing/decorators.py +40 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/websocket.py +23 -35
- {bustapi-0.14.1 → bustapi-0.14.3}/src/websocket/session.rs +3 -1
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/test_issue_29.py +49 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/- +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/.github/FUNDING.yml +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/.github/workflows/ci-multiplatform.yml +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/.github/workflows/ci.yml +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/.github/workflows/docs.yml +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/.github/workflows/manual-publish.yml +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/.gitignore +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/.python-version +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/AGENT_KNOWLEDGE.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/Dockerfile +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/LICENSE +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/README.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/benchmarks/CACHE_BENCHMARK.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/benchmarks/README.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/benchmarks/app.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/benchmarks/benchmark_all.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/benchmarks/benchmark_avg.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/benchmarks/benchmark_cache.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/benchmarks/benchmark_combined.png +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/benchmarks/bustapi.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/benchmarks/bustapi_bench.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/benchmarks/bustapi_internal.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/benchmarks/comparison_bench.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/benchmarks/comprehensive_benchmark.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/benchmarks/gen_graph.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/benchmarks/quick_bench.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/benchmarks/resource_bench.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/benchmarks/rps_comparison.png +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/benchmarks/run_comparison_auto.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/benchmarks/ws_benchmark.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/advanced/async.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/advanced/blueprints.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/advanced/dependency_injection.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/advanced/deployment.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/advanced/middleware.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/advanced/security.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/advanced/validation.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/api-reference.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/assets/logo.png +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/complete-api-reference.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/deployment-performance-guide.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/deployment.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/examples-guide.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/index.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/installation.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/overrides/.gitkeep +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/quickstart.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/release_track.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/site/advanced/async_support.html +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/site/advanced/blueprints.html +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/site/advanced/dependency_injection.html +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/site/advanced/middleware.html +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/site/advanced/validation.html +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/site/api/all.html +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/site/api/app.html +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/site/api/context.html +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/site/api/utilities.html +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/site/assets/logo.png +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/site/changelog.html +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/site/core_concepts/request_data.html +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/site/core_concepts/responses.html +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/site/core_concepts/routing.html +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/site/core_concepts/templates.html +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/site/examples/index.html +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/site/getting_started/index.html +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/site/getting_started/quickstart.html +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/site/index.html +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/site/script.js +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/site/style.css +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/stylesheets/extra.css +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/user-guide/authentication.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/user-guide/caching.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/user-guide/cli.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/user-guide/database.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/user-guide/documentation.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/user-guide/error_handling.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/user-guide/jwt.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/user-guide/logging.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/user-guide/multiprocessing.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/user-guide/request_data.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/user-guide/responses.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/user-guide/routing.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/user-guide/sessions.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/user-guide/static_files.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/user-guide/templates.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/user-guide/turbo-routes.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/user-guide/video-streaming.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/docs/websockets.md +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/advanced/08_auto_docs.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/advanced/12_test_modes.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/advanced/13_error_handling.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/advanced/14_middleware.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/advanced/16_middleware_session.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/advanced/20_file_uploads.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/advanced/24_body_and_depends.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/advanced/27_video_stream.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/advanced/28_websocket.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/advanced/29_turbo_websocket.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/basics/01_hello_world.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/basics/02_parameters.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/basics/03_async.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/basics/04_request_data.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/basics/19_all_types.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/database/07_database_raw.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/database/10_database_sqlmodel.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/routing/06_blueprints.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/routing/09_complex_routing.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/routing/21_path_validation.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/routing/22_path_docs.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/routing/23_query_validation.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/routing/blueprint_with_jwt.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/security/10_rate_limit_demo.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/security/11_security_demo.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/security/17_jwt_auth.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/security/17_safe_features.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/security/18_jwt_cookies.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/security/18_safe_advanced.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/security/18_session_login.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/templates/05_templates.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/templates/26_complex_template.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/templates/templates/index.html +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/turbo/cache_test.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/turbo/fair_benchmark.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/turbo/typed_turbo_example.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/ws/app.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/ws/templates/index.html +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/ws/websockets_demo.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/examples/ws/ws_limit.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/mkdocs.yml +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/auth/__init__.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/auth/csrf.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/auth/decorators.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/auth/login.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/auth/password.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/auth/tokens.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/auth/user.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/cli/__init__.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/cli/main.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/context.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/core/__init__.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/core/asgi.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/core/exceptions.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/core/logging.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/dependencies.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/dispatch.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/documentation/__init__.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/documentation/generator.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/extraction.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/fastapi_compat.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/hooks.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/http/__init__.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/http/request.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/http/response.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/jwt.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/logging.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/middleware.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/multiprocess.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/params.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/py.typed +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/responses.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/routing/__init__.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/routing/blueprints.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/safe/__init__.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/safe/concurrency.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/safe/types.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/security/__init__.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/security/extension.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/security/rate_limit.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/server/__init__.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/server/runner.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/server/wsgi.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/sessions.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/templating/__init__.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/templating/engine.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/templating/mixin.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/testing/__init__.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/testing/client.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/python/bustapi/utils.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/run_all_examples.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/scratch/test_abort.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/scratch/test_headers.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/bindings/app.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/bindings/converters.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/bindings/handlers.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/bindings/mod.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/bindings/request.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/bindings/typed_turbo.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/bindings/websocket.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/crypto.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/jwt.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/lib.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/logger.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/rate_limiter.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/request/methods.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/request/mod.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/request/tests.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/response/builders.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/response/methods.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/response/mod.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/router/handlers.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/router/matching.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/router/middleware.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/router/mod.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/router/tests.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/server/handlers.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/server/mod.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/server/startup.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/server/stream.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/static_files.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/templating.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/watcher.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/websocket/config.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/websocket/mod.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/src/websocket/turbo.rs +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/static/style.css +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/templates/base.html +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/templates/complex.html +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/docs_test_all.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/docs_test_api_reference.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/docs_test_installation.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/docs_test_quickstart.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/docs_test_simple.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/test_050_features.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/test_async_hooks.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/test_async_login.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/test_auth.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/test_discussion_21.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/test_discussion_22.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/test_discussion_28.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/test_examples.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/test_hot_reload.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/test_issue_18.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/test_issue_23.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/test_issue_24.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/test_jwt.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/test_jwt_cookies.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/test_login_manager.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/test_middleware.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/test_multiprocess_stability.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/test_new_examples.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/test_orm_conflict.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/test_path_standalone.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/test_path_validation.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/test_rate_limit_rust.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/test_safe.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/test_security_unit.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/test_sessions.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/test_zero_copy.py +0 -0
- {bustapi-0.14.1 → bustapi-0.14.3}/tests/verify_router.py +0 -0
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented here.
|
|
4
4
|
|
|
5
|
+
## [0.14.3] - 2026-06-19
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- **WebSocket Handshake**: Fixed a bug where client-initiated close frames (e.g. `socket.close()` in JS) were not properly echoed back by the Rust backend to complete the WebSocket close handshake. `on_disconnect` and `on_binary` handlers are now fully thread-safe and trigger cleanly.
|
|
9
|
+
- **WebSocket Config**: Clarified the usage of `WebSocketConfig` instance for the `config` parameter in WebSocket routes.
|
|
10
|
+
|
|
11
|
+
## [0.14.2] - 2026-06-18
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
- **Template `url_for` Availability**: `url_for` is now automatically injected into the Jinja2 template context within `render_template()`, matching Flask's built-in behaviour. Previously, `{{ url_for('endpoint') }}` would raise `'url_for' is undefined` in templates unless manually added via a context processor.
|
|
15
|
+
|
|
5
16
|
## [0.14.1] - 2026-06-17
|
|
6
17
|
|
|
7
18
|
### Fixed
|
|
@@ -432,7 +432,7 @@ checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
|
|
|
432
432
|
|
|
433
433
|
[[package]]
|
|
434
434
|
name = "bustapi_core"
|
|
435
|
-
version = "0.14.
|
|
435
|
+
version = "0.14.3"
|
|
436
436
|
dependencies = [
|
|
437
437
|
"actix-files",
|
|
438
438
|
"actix-http",
|
|
@@ -476,9 +476,9 @@ dependencies = [
|
|
|
476
476
|
|
|
477
477
|
[[package]]
|
|
478
478
|
name = "bytes"
|
|
479
|
-
version = "1.
|
|
479
|
+
version = "1.12.0"
|
|
480
480
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
481
|
-
checksum = "
|
|
481
|
+
checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593"
|
|
482
482
|
|
|
483
483
|
[[package]]
|
|
484
484
|
name = "bytestring"
|
|
@@ -992,16 +992,14 @@ dependencies = [
|
|
|
992
992
|
|
|
993
993
|
[[package]]
|
|
994
994
|
name = "getrandom"
|
|
995
|
-
version = "0.4.
|
|
995
|
+
version = "0.4.3"
|
|
996
996
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
997
|
-
checksum = "
|
|
997
|
+
checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099"
|
|
998
998
|
dependencies = [
|
|
999
999
|
"cfg-if",
|
|
1000
1000
|
"libc",
|
|
1001
1001
|
"r-efi 6.0.0",
|
|
1002
1002
|
"rand_core 0.10.1",
|
|
1003
|
-
"wasip2",
|
|
1004
|
-
"wasip3",
|
|
1005
1003
|
]
|
|
1006
1004
|
|
|
1007
1005
|
[[package]]
|
|
@@ -1039,15 +1037,6 @@ version = "0.14.5"
|
|
|
1039
1037
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1040
1038
|
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
|
1041
1039
|
|
|
1042
|
-
[[package]]
|
|
1043
|
-
name = "hashbrown"
|
|
1044
|
-
version = "0.15.5"
|
|
1045
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1046
|
-
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
|
1047
|
-
dependencies = [
|
|
1048
|
-
"foldhash",
|
|
1049
|
-
]
|
|
1050
|
-
|
|
1051
1040
|
[[package]]
|
|
1052
1041
|
name = "hashbrown"
|
|
1053
1042
|
version = "0.17.1"
|
|
@@ -1228,12 +1217,6 @@ dependencies = [
|
|
|
1228
1217
|
"zerovec",
|
|
1229
1218
|
]
|
|
1230
1219
|
|
|
1231
|
-
[[package]]
|
|
1232
|
-
name = "id-arena"
|
|
1233
|
-
version = "2.3.0"
|
|
1234
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1235
|
-
checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
|
|
1236
|
-
|
|
1237
1220
|
[[package]]
|
|
1238
1221
|
name = "ident_case"
|
|
1239
1222
|
version = "1.0.1"
|
|
@@ -1275,8 +1258,6 @@ checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
|
|
|
1275
1258
|
dependencies = [
|
|
1276
1259
|
"equivalent",
|
|
1277
1260
|
"hashbrown 0.17.1",
|
|
1278
|
-
"serde",
|
|
1279
|
-
"serde_core",
|
|
1280
1261
|
]
|
|
1281
1262
|
|
|
1282
1263
|
[[package]]
|
|
@@ -1367,12 +1348,6 @@ version = "1.5.0"
|
|
|
1367
1348
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1368
1349
|
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
|
1369
1350
|
|
|
1370
|
-
[[package]]
|
|
1371
|
-
name = "leb128fmt"
|
|
1372
|
-
version = "0.1.0"
|
|
1373
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1374
|
-
checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
|
|
1375
|
-
|
|
1376
1351
|
[[package]]
|
|
1377
1352
|
name = "libc"
|
|
1378
1353
|
version = "0.2.186"
|
|
@@ -1486,9 +1461,9 @@ dependencies = [
|
|
|
1486
1461
|
|
|
1487
1462
|
[[package]]
|
|
1488
1463
|
name = "minijinja"
|
|
1489
|
-
version = "2.
|
|
1464
|
+
version = "2.21.0"
|
|
1490
1465
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1491
|
-
checksum = "
|
|
1466
|
+
checksum = "cb3d648e68cea56d9858d535ee28f9538404e2dd8cb08ed0bd05dca379477f39"
|
|
1492
1467
|
dependencies = [
|
|
1493
1468
|
"memo-map",
|
|
1494
1469
|
"serde",
|
|
@@ -1702,16 +1677,6 @@ dependencies = [
|
|
|
1702
1677
|
"zerocopy",
|
|
1703
1678
|
]
|
|
1704
1679
|
|
|
1705
|
-
[[package]]
|
|
1706
|
-
name = "prettyplease"
|
|
1707
|
-
version = "0.2.37"
|
|
1708
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1709
|
-
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
|
|
1710
|
-
dependencies = [
|
|
1711
|
-
"proc-macro2",
|
|
1712
|
-
"syn",
|
|
1713
|
-
]
|
|
1714
|
-
|
|
1715
1680
|
[[package]]
|
|
1716
1681
|
name = "proc-macro2"
|
|
1717
1682
|
version = "1.0.106"
|
|
@@ -1832,7 +1797,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
1832
1797
|
checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207"
|
|
1833
1798
|
dependencies = [
|
|
1834
1799
|
"chacha20",
|
|
1835
|
-
"getrandom 0.4.
|
|
1800
|
+
"getrandom 0.4.3",
|
|
1836
1801
|
"rand_core 0.10.1",
|
|
1837
1802
|
]
|
|
1838
1803
|
|
|
@@ -2162,7 +2127,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
2162
2127
|
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
|
|
2163
2128
|
dependencies = [
|
|
2164
2129
|
"fastrand",
|
|
2165
|
-
"getrandom 0.4.
|
|
2130
|
+
"getrandom 0.4.3",
|
|
2166
2131
|
"once_cell",
|
|
2167
2132
|
"rustix",
|
|
2168
2133
|
"windows-sys 0.61.2",
|
|
@@ -2438,16 +2403,7 @@ version = "1.0.4+wasi-0.2.12"
|
|
|
2438
2403
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2439
2404
|
checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487"
|
|
2440
2405
|
dependencies = [
|
|
2441
|
-
"wit-bindgen
|
|
2442
|
-
]
|
|
2443
|
-
|
|
2444
|
-
[[package]]
|
|
2445
|
-
name = "wasip3"
|
|
2446
|
-
version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
|
|
2447
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2448
|
-
checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
|
|
2449
|
-
dependencies = [
|
|
2450
|
-
"wit-bindgen 0.51.0",
|
|
2406
|
+
"wit-bindgen",
|
|
2451
2407
|
]
|
|
2452
2408
|
|
|
2453
2409
|
[[package]]
|
|
@@ -2495,40 +2451,6 @@ dependencies = [
|
|
|
2495
2451
|
"unicode-ident",
|
|
2496
2452
|
]
|
|
2497
2453
|
|
|
2498
|
-
[[package]]
|
|
2499
|
-
name = "wasm-encoder"
|
|
2500
|
-
version = "0.244.0"
|
|
2501
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2502
|
-
checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319"
|
|
2503
|
-
dependencies = [
|
|
2504
|
-
"leb128fmt",
|
|
2505
|
-
"wasmparser",
|
|
2506
|
-
]
|
|
2507
|
-
|
|
2508
|
-
[[package]]
|
|
2509
|
-
name = "wasm-metadata"
|
|
2510
|
-
version = "0.244.0"
|
|
2511
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2512
|
-
checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909"
|
|
2513
|
-
dependencies = [
|
|
2514
|
-
"anyhow",
|
|
2515
|
-
"indexmap",
|
|
2516
|
-
"wasm-encoder",
|
|
2517
|
-
"wasmparser",
|
|
2518
|
-
]
|
|
2519
|
-
|
|
2520
|
-
[[package]]
|
|
2521
|
-
name = "wasmparser"
|
|
2522
|
-
version = "0.244.0"
|
|
2523
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2524
|
-
checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
|
|
2525
|
-
dependencies = [
|
|
2526
|
-
"bitflags",
|
|
2527
|
-
"hashbrown 0.15.5",
|
|
2528
|
-
"indexmap",
|
|
2529
|
-
"semver",
|
|
2530
|
-
]
|
|
2531
|
-
|
|
2532
2454
|
[[package]]
|
|
2533
2455
|
name = "winapi-util"
|
|
2534
2456
|
version = "0.1.11"
|
|
@@ -2762,100 +2684,12 @@ version = "0.53.1"
|
|
|
2762
2684
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2763
2685
|
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
|
|
2764
2686
|
|
|
2765
|
-
[[package]]
|
|
2766
|
-
name = "wit-bindgen"
|
|
2767
|
-
version = "0.51.0"
|
|
2768
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2769
|
-
checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
|
|
2770
|
-
dependencies = [
|
|
2771
|
-
"wit-bindgen-rust-macro",
|
|
2772
|
-
]
|
|
2773
|
-
|
|
2774
2687
|
[[package]]
|
|
2775
2688
|
name = "wit-bindgen"
|
|
2776
2689
|
version = "0.57.1"
|
|
2777
2690
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2778
2691
|
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
|
|
2779
2692
|
|
|
2780
|
-
[[package]]
|
|
2781
|
-
name = "wit-bindgen-core"
|
|
2782
|
-
version = "0.51.0"
|
|
2783
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2784
|
-
checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc"
|
|
2785
|
-
dependencies = [
|
|
2786
|
-
"anyhow",
|
|
2787
|
-
"heck",
|
|
2788
|
-
"wit-parser",
|
|
2789
|
-
]
|
|
2790
|
-
|
|
2791
|
-
[[package]]
|
|
2792
|
-
name = "wit-bindgen-rust"
|
|
2793
|
-
version = "0.51.0"
|
|
2794
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2795
|
-
checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21"
|
|
2796
|
-
dependencies = [
|
|
2797
|
-
"anyhow",
|
|
2798
|
-
"heck",
|
|
2799
|
-
"indexmap",
|
|
2800
|
-
"prettyplease",
|
|
2801
|
-
"syn",
|
|
2802
|
-
"wasm-metadata",
|
|
2803
|
-
"wit-bindgen-core",
|
|
2804
|
-
"wit-component",
|
|
2805
|
-
]
|
|
2806
|
-
|
|
2807
|
-
[[package]]
|
|
2808
|
-
name = "wit-bindgen-rust-macro"
|
|
2809
|
-
version = "0.51.0"
|
|
2810
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2811
|
-
checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a"
|
|
2812
|
-
dependencies = [
|
|
2813
|
-
"anyhow",
|
|
2814
|
-
"prettyplease",
|
|
2815
|
-
"proc-macro2",
|
|
2816
|
-
"quote",
|
|
2817
|
-
"syn",
|
|
2818
|
-
"wit-bindgen-core",
|
|
2819
|
-
"wit-bindgen-rust",
|
|
2820
|
-
]
|
|
2821
|
-
|
|
2822
|
-
[[package]]
|
|
2823
|
-
name = "wit-component"
|
|
2824
|
-
version = "0.244.0"
|
|
2825
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2826
|
-
checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
|
|
2827
|
-
dependencies = [
|
|
2828
|
-
"anyhow",
|
|
2829
|
-
"bitflags",
|
|
2830
|
-
"indexmap",
|
|
2831
|
-
"log",
|
|
2832
|
-
"serde",
|
|
2833
|
-
"serde_derive",
|
|
2834
|
-
"serde_json",
|
|
2835
|
-
"wasm-encoder",
|
|
2836
|
-
"wasm-metadata",
|
|
2837
|
-
"wasmparser",
|
|
2838
|
-
"wit-parser",
|
|
2839
|
-
]
|
|
2840
|
-
|
|
2841
|
-
[[package]]
|
|
2842
|
-
name = "wit-parser"
|
|
2843
|
-
version = "0.244.0"
|
|
2844
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2845
|
-
checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736"
|
|
2846
|
-
dependencies = [
|
|
2847
|
-
"anyhow",
|
|
2848
|
-
"id-arena",
|
|
2849
|
-
"indexmap",
|
|
2850
|
-
"log",
|
|
2851
|
-
"semver",
|
|
2852
|
-
"serde",
|
|
2853
|
-
"serde_derive",
|
|
2854
|
-
"serde_json",
|
|
2855
|
-
"unicode-xid",
|
|
2856
|
-
"wasmparser",
|
|
2857
|
-
]
|
|
2858
|
-
|
|
2859
2693
|
[[package]]
|
|
2860
2694
|
name = "writeable"
|
|
2861
2695
|
version = "0.6.3"
|
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented here.
|
|
4
4
|
|
|
5
|
+
## [0.14.3] - 2026-06-19
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- **WebSocket Handshake**: Fixed a bug where client-initiated close frames (e.g. `socket.close()` in JS) were not properly echoed back by the Rust backend to complete the WebSocket close handshake. `on_disconnect` and `on_binary` handlers are now fully thread-safe and trigger cleanly.
|
|
9
|
+
- **WebSocket Config**: Clarified the usage of `WebSocketConfig` instance for the `config` parameter in WebSocket routes.
|
|
10
|
+
|
|
11
|
+
## [0.14.2] - 2026-06-18
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
- **Template `url_for` Availability**: `url_for` is now automatically injected into the Jinja2 template context within `render_template()`, matching Flask's built-in behaviour. Previously, `{{ url_for('endpoint') }}` would raise `'url_for' is undefined` in templates unless manually added via a context processor.
|
|
15
|
+
|
|
5
16
|
## [0.14.1] - 2026-06-17
|
|
6
17
|
|
|
7
18
|
### Fixed
|
|
@@ -82,7 +82,9 @@ class BustAPI(
|
|
|
82
82
|
self.teardown_request_funcs: List[Callable] = []
|
|
83
83
|
self.teardown_appcontext_funcs: List[Callable] = []
|
|
84
84
|
self.blueprints: Dict[str, Blueprint] = {}
|
|
85
|
-
|
|
85
|
+
from .routing.decorators import Map
|
|
86
|
+
|
|
87
|
+
self.url_map = Map()
|
|
86
88
|
self._url_rules: List[Dict[str, Any]] = []
|
|
87
89
|
self.path_validators: Dict[tuple, Dict[str, Any]] = {}
|
|
88
90
|
self.query_validators: Dict[tuple, Dict[str, tuple]] = {}
|
|
@@ -237,13 +239,42 @@ class BustAPI(
|
|
|
237
239
|
|
|
238
240
|
def _dispatch_not_found(self, rust_request, params=None):
|
|
239
241
|
from .core.exceptions import NotFound
|
|
242
|
+
from .utils import async_to_sync
|
|
240
243
|
|
|
241
244
|
try:
|
|
242
245
|
request = Request._from_rust_request(rust_request)
|
|
243
246
|
request.app = self
|
|
244
247
|
token = _request_ctx.set(request)
|
|
245
248
|
try:
|
|
249
|
+
session = None
|
|
250
|
+
if self.secret_key:
|
|
251
|
+
session = self.session_interface.open_session(self, request)
|
|
252
|
+
request.session = session
|
|
253
|
+
|
|
254
|
+
bp = (
|
|
255
|
+
self.blueprints.get(request.blueprint)
|
|
256
|
+
if request.blueprint
|
|
257
|
+
else None
|
|
258
|
+
)
|
|
259
|
+
before_funcs = (
|
|
260
|
+
bp.before_request_funcs if bp else []
|
|
261
|
+
) + self.before_request_funcs
|
|
262
|
+
if before_funcs:
|
|
263
|
+
for before_func in before_funcs:
|
|
264
|
+
res = before_func()
|
|
265
|
+
if inspect.isawaitable(res):
|
|
266
|
+
res = async_to_sync(res)
|
|
267
|
+
if res is not None:
|
|
268
|
+
response = self._make_response(res)
|
|
269
|
+
if session:
|
|
270
|
+
self.session_interface.save_session(
|
|
271
|
+
self, session, response
|
|
272
|
+
)
|
|
273
|
+
return self._response_to_rust_format(response)
|
|
274
|
+
|
|
246
275
|
response = self._handle_exception(NotFound())
|
|
276
|
+
if session is not None:
|
|
277
|
+
self.session_interface.save_session(self, session, response)
|
|
247
278
|
return self._response_to_rust_format(response)
|
|
248
279
|
finally:
|
|
249
280
|
_request_ctx.reset(token)
|
|
@@ -356,6 +356,8 @@ def render_template(template_name: str, **context) -> Response:
|
|
|
356
356
|
context["current_app"] = _current_app
|
|
357
357
|
except RuntimeError:
|
|
358
358
|
pass
|
|
359
|
+
if "url_for" not in context:
|
|
360
|
+
context["url_for"] = url_for
|
|
359
361
|
|
|
360
362
|
# Run template context processors
|
|
361
363
|
try:
|
|
@@ -7,6 +7,46 @@ import re
|
|
|
7
7
|
from typing import Any, Callable, Optional
|
|
8
8
|
|
|
9
9
|
|
|
10
|
+
class Map:
|
|
11
|
+
"""
|
|
12
|
+
Flask-compatible url_map class to store and iterate rules.
|
|
13
|
+
Allows multiple rules for the same path pattern (e.g. GET and POST on same path).
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self):
|
|
17
|
+
self._rules = []
|
|
18
|
+
|
|
19
|
+
def __setitem__(self, key, value):
|
|
20
|
+
self._rules.append((key, value))
|
|
21
|
+
|
|
22
|
+
def items(self):
|
|
23
|
+
return self._rules
|
|
24
|
+
|
|
25
|
+
def __iter__(self):
|
|
26
|
+
return iter(r for r, _ in self._rules)
|
|
27
|
+
|
|
28
|
+
def __contains__(self, key):
|
|
29
|
+
return any(r == key for r, _ in self._rules)
|
|
30
|
+
|
|
31
|
+
def __getitem__(self, key):
|
|
32
|
+
for r, val in reversed(self._rules):
|
|
33
|
+
if r == key:
|
|
34
|
+
return val
|
|
35
|
+
raise KeyError(key)
|
|
36
|
+
|
|
37
|
+
def get(self, key, default=None):
|
|
38
|
+
try:
|
|
39
|
+
return self[key]
|
|
40
|
+
except KeyError:
|
|
41
|
+
return default
|
|
42
|
+
|
|
43
|
+
def clear(self):
|
|
44
|
+
self._rules.clear()
|
|
45
|
+
|
|
46
|
+
def __len__(self):
|
|
47
|
+
return len(self._rules)
|
|
48
|
+
|
|
49
|
+
|
|
10
50
|
class RouteRegistration:
|
|
11
51
|
"""Mixin providing Flask-compatible route decorators."""
|
|
12
52
|
|
|
@@ -197,61 +197,49 @@ class WebSocketHandler:
|
|
|
197
197
|
if hasattr(task, "add_done_callback"):
|
|
198
198
|
task.add_done_callback(_task_done_callback)
|
|
199
199
|
|
|
200
|
+
def _get_loop(self, session_id: int):
|
|
201
|
+
"""Find the asyncio loop associated with a session."""
|
|
202
|
+
if hasattr(self, "_background_loop") and self._background_loop:
|
|
203
|
+
return self._background_loop
|
|
204
|
+
task = self._tasks.get(session_id)
|
|
205
|
+
if task:
|
|
206
|
+
try:
|
|
207
|
+
return task.get_loop()
|
|
208
|
+
except Exception:
|
|
209
|
+
pass
|
|
210
|
+
return None
|
|
211
|
+
|
|
200
212
|
def on_message(self, session_id: int, message: str) -> None:
|
|
201
213
|
"""Called when a text message is received."""
|
|
202
214
|
if session_id in self._connections:
|
|
203
215
|
ws = self._connections[session_id]
|
|
204
|
-
|
|
205
|
-
# than the WebSocket's loop (Background thread), we must use thread-safe scheduling.
|
|
206
|
-
# We need to find the loop associated with this WebSocket's handler.
|
|
207
|
-
loop = None
|
|
208
|
-
if hasattr(self, "_background_loop") and self._background_loop:
|
|
209
|
-
loop = self._background_loop
|
|
210
|
-
else:
|
|
211
|
-
# Fallback: try to get loop from registered task?
|
|
212
|
-
pass
|
|
213
|
-
|
|
216
|
+
loop = self._get_loop(session_id)
|
|
214
217
|
if loop:
|
|
215
218
|
loop.call_soon_threadsafe(ws._receive_message, message)
|
|
216
219
|
else:
|
|
217
|
-
# If no specific background loop, imply we are reusing the main loop?
|
|
218
|
-
# But if we are in Actix thread, main loop might be running in main thread.
|
|
219
|
-
# call_soon_threadsafe is safe to call from any thread to target loop.
|
|
220
|
-
# However, if we don't have 'loop' var ...
|
|
221
|
-
# ws._messages is bound to a loop. We should get it.
|
|
222
|
-
# asyncio.Queue doesn't expose public ._loop, but we can try to guess.
|
|
223
|
-
# Actually, check self._tasks[session_id].get_loop() if available py3.7+
|
|
224
|
-
task = self._tasks.get(session_id)
|
|
225
|
-
if task:
|
|
226
|
-
try:
|
|
227
|
-
loop = task.get_loop()
|
|
228
|
-
loop.call_soon_threadsafe(ws._receive_message, message)
|
|
229
|
-
return
|
|
230
|
-
except:
|
|
231
|
-
pass
|
|
232
|
-
|
|
233
|
-
# Fallback to direct call if we can't find loop (risk of race)
|
|
234
220
|
ws._receive_message(message)
|
|
235
221
|
|
|
236
|
-
return None
|
|
237
|
-
|
|
238
222
|
def on_binary(self, session_id: int, data: bytes) -> None:
|
|
239
223
|
"""Called when binary data is received."""
|
|
240
224
|
if session_id in self._connections:
|
|
241
225
|
ws = self._connections[session_id]
|
|
242
|
-
# Convert if necessary, but data should come as bytes/list from bindings
|
|
243
|
-
# If bindings use Vec<u8> -> list[int] in Python usually?
|
|
244
|
-
# Or bytes?
|
|
245
|
-
# Let's assume bytes for now or cast.
|
|
246
226
|
if isinstance(data, list):
|
|
247
227
|
data = bytes(data)
|
|
248
|
-
|
|
228
|
+
loop = self._get_loop(session_id)
|
|
229
|
+
if loop:
|
|
230
|
+
loop.call_soon_threadsafe(ws._receive_message, data)
|
|
231
|
+
else:
|
|
232
|
+
ws._receive_message(data)
|
|
249
233
|
|
|
250
234
|
def on_disconnect(self, session_id: int, reason: Optional[str] = None) -> None:
|
|
251
235
|
"""Called when a client disconnects."""
|
|
252
236
|
if session_id in self._connections:
|
|
253
237
|
ws = self._connections[session_id]
|
|
254
|
-
|
|
238
|
+
loop = self._get_loop(session_id)
|
|
239
|
+
if loop:
|
|
240
|
+
loop.call_soon_threadsafe(ws._receive_close, reason)
|
|
241
|
+
else:
|
|
242
|
+
ws._receive_close(reason)
|
|
255
243
|
del self._connections[session_id]
|
|
256
244
|
|
|
257
245
|
self._cleanup_task(session_id)
|
|
@@ -214,12 +214,14 @@ pub async fn handle_websocket(
|
|
|
214
214
|
}
|
|
215
215
|
Message::Close(reason) => {
|
|
216
216
|
let sid = ws_session.id;
|
|
217
|
-
let reason_str = reason.
|
|
217
|
+
let reason_str = reason.as_ref().and_then(|r| r.description.clone());
|
|
218
218
|
let handler_ref = Python::attach(|py| handler_for_messages.clone_ref(py));
|
|
219
219
|
|
|
220
220
|
Python::attach(|py| {
|
|
221
221
|
let _ = handler_ref.call_method1(py, "on_disconnect", (sid, reason_str));
|
|
222
222
|
});
|
|
223
|
+
|
|
224
|
+
let _ = session.close(reason).await;
|
|
223
225
|
break;
|
|
224
226
|
}
|
|
225
227
|
_ => {
|
|
@@ -117,3 +117,52 @@ def test_blueprint_advanced_features():
|
|
|
117
117
|
res = client.get("/trigger_401")
|
|
118
118
|
assert res.status_code == 401
|
|
119
119
|
assert res.json["error"] == "app_401"
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def test_blueprint_multiple_methods_for_same_rule():
|
|
123
|
+
app = BustAPI()
|
|
124
|
+
app.secret_key = "test-secret-key"
|
|
125
|
+
|
|
126
|
+
unblocked_routes = ["/auth/login"]
|
|
127
|
+
|
|
128
|
+
@app.before_request
|
|
129
|
+
def login_before_visit():
|
|
130
|
+
from bustapi import redirect, request, session
|
|
131
|
+
|
|
132
|
+
if not (
|
|
133
|
+
"user_id" in session
|
|
134
|
+
or request.path in unblocked_routes
|
|
135
|
+
or request.path.startswith("/static")
|
|
136
|
+
):
|
|
137
|
+
session["came_from"] = request.path
|
|
138
|
+
return redirect(url_for("auth.login"))
|
|
139
|
+
|
|
140
|
+
auth = Blueprint("auth", __name__, url_prefix="/auth")
|
|
141
|
+
|
|
142
|
+
@auth.get("/login", endpoint="login")
|
|
143
|
+
def login_get():
|
|
144
|
+
return "GET Login Page"
|
|
145
|
+
|
|
146
|
+
@auth.post("/login")
|
|
147
|
+
def login_post():
|
|
148
|
+
return "POST Login Page"
|
|
149
|
+
|
|
150
|
+
app.register_blueprint(auth)
|
|
151
|
+
|
|
152
|
+
from bustapi.testing import BustTestClient
|
|
153
|
+
|
|
154
|
+
with BustTestClient(app) as client:
|
|
155
|
+
# GET / should redirect to /auth/login
|
|
156
|
+
res = client.get("/")
|
|
157
|
+
assert res.status_code == 302
|
|
158
|
+
assert res.headers["Location"] == "/auth/login"
|
|
159
|
+
|
|
160
|
+
# GET /auth/login should load fine (200)
|
|
161
|
+
res_login_get = client.get("/auth/login")
|
|
162
|
+
assert res_login_get.status_code == 200
|
|
163
|
+
assert res_login_get.get_data(as_text=True) == "GET Login Page"
|
|
164
|
+
|
|
165
|
+
# POST /auth/login should load fine (200)
|
|
166
|
+
res_login_post = client.post("/auth/login")
|
|
167
|
+
assert res_login_post.status_code == 200
|
|
168
|
+
assert res_login_post.get_data(as_text=True) == "POST Login Page"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|