django-bolt 0.2.4__tar.gz → 0.2.5__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.

Potentially problematic release.


This version of django-bolt might be problematic. Click here for more details.

Files changed (247) hide show
  1. {django_bolt-0.2.4 → django_bolt-0.2.5}/Cargo.lock +1 -1
  2. {django_bolt-0.2.4 → django_bolt-0.2.5}/Cargo.toml +1 -1
  3. {django_bolt-0.2.4 → django_bolt-0.2.5}/PKG-INFO +1 -1
  4. {django_bolt-0.2.4 → django_bolt-0.2.5}/pyproject.toml +1 -1
  5. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/management/commands/runbolt.py +9 -2
  6. {django_bolt-0.2.4 → django_bolt-0.2.5}/src/direct_stream.rs +27 -27
  7. {django_bolt-0.2.4 → django_bolt-0.2.5}/src/error.rs +43 -19
  8. {django_bolt-0.2.4 → django_bolt-0.2.5}/src/handler.rs +41 -41
  9. {django_bolt-0.2.4 → django_bolt-0.2.5}/src/json.rs +1 -1
  10. {django_bolt-0.2.4 → django_bolt-0.2.5}/src/metadata.rs +10 -3
  11. {django_bolt-0.2.4 → django_bolt-0.2.5}/src/middleware/auth.rs +37 -24
  12. {django_bolt-0.2.4 → django_bolt-0.2.5}/src/middleware/mod.rs +1 -1
  13. {django_bolt-0.2.4 → django_bolt-0.2.5}/src/middleware/rate_limit.rs +8 -7
  14. django_bolt-0.2.5/src/permissions.rs +91 -0
  15. {django_bolt-0.2.4 → django_bolt-0.2.5}/src/request.rs +5 -5
  16. {django_bolt-0.2.4 → django_bolt-0.2.5}/src/router.rs +6 -2
  17. {django_bolt-0.2.4 → django_bolt-0.2.5}/src/server.rs +86 -46
  18. {django_bolt-0.2.4 → django_bolt-0.2.5}/src/state.rs +1 -1
  19. {django_bolt-0.2.4 → django_bolt-0.2.5}/src/test_state.rs +224 -121
  20. {django_bolt-0.2.4 → django_bolt-0.2.5}/src/validation.rs +2 -2
  21. django_bolt-0.2.4/src/permissions.rs +0 -102
  22. {django_bolt-0.2.4 → django_bolt-0.2.5}/.github/workflows/CI.yml +0 -0
  23. {django_bolt-0.2.4 → django_bolt-0.2.5}/.gitignore +0 -0
  24. {django_bolt-0.2.4 → django_bolt-0.2.5}/.python-version +0 -0
  25. {django_bolt-0.2.4 → django_bolt-0.2.5}/BENCHMARK_BASELINE.md +0 -0
  26. {django_bolt-0.2.4 → django_bolt-0.2.5}/BENCHMARK_DEV.md +0 -0
  27. {django_bolt-0.2.4 → django_bolt-0.2.5}/CLAUDE.md +0 -0
  28. {django_bolt-0.2.4 → django_bolt-0.2.5}/Makefile +0 -0
  29. {django_bolt-0.2.4 → django_bolt-0.2.5}/README.md +0 -0
  30. {django_bolt-0.2.4 → django_bolt-0.2.5}/TODO.md +0 -0
  31. {django_bolt-0.2.4 → django_bolt-0.2.5}/docs/ANNOTATION_GUIDE.md +0 -0
  32. {django_bolt-0.2.4 → django_bolt-0.2.5}/docs/ASYNC_DJANGO.md +0 -0
  33. {django_bolt-0.2.4 → django_bolt-0.2.5}/docs/CLASS_BASED_VIEWS.md +0 -0
  34. {django_bolt-0.2.4 → django_bolt-0.2.5}/docs/COMPRESSION.md +0 -0
  35. {django_bolt-0.2.4 → django_bolt-0.2.5}/docs/DEPENDENCY_INJECTION.md +0 -0
  36. {django_bolt-0.2.4 → django_bolt-0.2.5}/docs/DJANGO_ADMIN.md +0 -0
  37. {django_bolt-0.2.4 → django_bolt-0.2.5}/docs/EXCEPTIONS.md +0 -0
  38. {django_bolt-0.2.4 → django_bolt-0.2.5}/docs/GETTING_STARTED.md +0 -0
  39. {django_bolt-0.2.4 → django_bolt-0.2.5}/docs/GIL_OPTIMIZATION.md +0 -0
  40. {django_bolt-0.2.4 → django_bolt-0.2.5}/docs/LOGGING.md +0 -0
  41. {django_bolt-0.2.4 → django_bolt-0.2.5}/docs/MIDDLEWARE.md +0 -0
  42. {django_bolt-0.2.4 → django_bolt-0.2.5}/docs/OPENAPI.md +0 -0
  43. {django_bolt-0.2.4 → django_bolt-0.2.5}/docs/OPENAPI_ERROR_RESPONSES.md +0 -0
  44. {django_bolt-0.2.4 → django_bolt-0.2.5}/docs/OPENAPI_METADATA_IMPLEMENTATION.md +0 -0
  45. {django_bolt-0.2.4 → django_bolt-0.2.5}/docs/PAGINATION.md +0 -0
  46. {django_bolt-0.2.4 → django_bolt-0.2.5}/docs/PUBLISHING.md +0 -0
  47. {django_bolt-0.2.4 → django_bolt-0.2.5}/docs/README.md +0 -0
  48. {django_bolt-0.2.4 → django_bolt-0.2.5}/docs/RESPONSES.md +0 -0
  49. {django_bolt-0.2.4 → django_bolt-0.2.5}/docs/SECURITY.md +0 -0
  50. {django_bolt-0.2.4 → django_bolt-0.2.5}/docs/SERIALIZATION.md +0 -0
  51. {django_bolt-0.2.4 → django_bolt-0.2.5}/docs/TESTING_UTILITIES.md +0 -0
  52. {django_bolt-0.2.4 → django_bolt-0.2.5}/docs/favicon.png +0 -0
  53. {django_bolt-0.2.4 → django_bolt-0.2.5}/docs/icon.png +0 -0
  54. {django_bolt-0.2.4 → django_bolt-0.2.5}/docs/logo.png +0 -0
  55. {django_bolt-0.2.4 → django_bolt-0.2.5}/pytest.ini +0 -0
  56. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/__init__.py +0 -0
  57. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/_json.py +0 -0
  58. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/admin/__init__.py +0 -0
  59. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/admin/admin_detection.py +0 -0
  60. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/admin/asgi_bridge.py +0 -0
  61. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/admin/routes.py +0 -0
  62. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/admin/static.py +0 -0
  63. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/admin/static_routes.py +0 -0
  64. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/api.py +0 -0
  65. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/apps.py +0 -0
  66. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/async_collector.py +0 -0
  67. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/auth/__init__.py +0 -0
  68. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/auth/backends.py +0 -0
  69. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/auth/guards.py +0 -0
  70. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/auth/jwt_utils.py +0 -0
  71. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/auth/revocation.py +0 -0
  72. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/auth/token.py +0 -0
  73. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/binding.py +0 -0
  74. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/bootstrap.py +0 -0
  75. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/cli.py +0 -0
  76. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/compression.py +0 -0
  77. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/decorators.py +0 -0
  78. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/dependencies.py +0 -0
  79. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/error_handlers.py +0 -0
  80. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/exceptions.py +0 -0
  81. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/health.py +0 -0
  82. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/logging/__init__.py +0 -0
  83. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/logging/config.py +0 -0
  84. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/logging/middleware.py +0 -0
  85. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/management/__init__.py +0 -0
  86. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/management/commands/__init__.py +0 -0
  87. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/middleware/__init__.py +0 -0
  88. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/middleware/compiler.py +0 -0
  89. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/middleware/middleware.py +0 -0
  90. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/__init__.py +0 -0
  91. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/config.py +0 -0
  92. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/plugins.py +0 -0
  93. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/routes.py +0 -0
  94. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/schema_generator.py +0 -0
  95. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/__init__.py +0 -0
  96. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/base.py +0 -0
  97. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/callback.py +0 -0
  98. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/components.py +0 -0
  99. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/contact.py +0 -0
  100. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/discriminator.py +0 -0
  101. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/encoding.py +0 -0
  102. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/enums.py +0 -0
  103. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/example.py +0 -0
  104. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/external_documentation.py +0 -0
  105. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/header.py +0 -0
  106. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/info.py +0 -0
  107. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/license.py +0 -0
  108. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/link.py +0 -0
  109. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/media_type.py +0 -0
  110. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/oauth_flow.py +0 -0
  111. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/oauth_flows.py +0 -0
  112. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/open_api.py +0 -0
  113. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/operation.py +0 -0
  114. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/parameter.py +0 -0
  115. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/path_item.py +0 -0
  116. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/paths.py +0 -0
  117. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/reference.py +0 -0
  118. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/request_body.py +0 -0
  119. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/response.py +0 -0
  120. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/responses.py +0 -0
  121. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/schema.py +0 -0
  122. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/security_requirement.py +0 -0
  123. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/security_scheme.py +0 -0
  124. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/server.py +0 -0
  125. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/server_variable.py +0 -0
  126. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/tag.py +0 -0
  127. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/openapi/spec/xml.py +0 -0
  128. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/pagination.py +0 -0
  129. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/param_functions.py +0 -0
  130. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/params.py +0 -0
  131. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/request_parsing.py +0 -0
  132. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/responses.py +0 -0
  133. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/router.py +0 -0
  134. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/serialization.py +0 -0
  135. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/status_codes.py +0 -0
  136. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/testing/__init__.py +0 -0
  137. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/testing/client.py +0 -0
  138. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/testing/helpers.py +0 -0
  139. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/types.py +0 -0
  140. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/typing.py +0 -0
  141. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/django_bolt/views.py +0 -0
  142. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/README.md +0 -0
  143. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/bench/__init__.py +0 -0
  144. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/bench/admin.py +0 -0
  145. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/bench/api.py +0 -0
  146. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/bench/apps.py +0 -0
  147. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/bench/migrations/0001_initial.py +0 -0
  148. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/bench/migrations/__init__.py +0 -0
  149. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/bench/models.py +0 -0
  150. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/bench/tests.py +0 -0
  151. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/bench/views.py +0 -0
  152. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/manage.py +0 -0
  153. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/100B +0 -0
  154. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/100B.txt +0 -0
  155. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/100K +0 -0
  156. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/100K.json +0 -0
  157. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/100K.txt +0 -0
  158. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/10K +0 -0
  159. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/10K.json +0 -0
  160. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/10K.txt +0 -0
  161. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/1K +0 -0
  162. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/1K.json +0 -0
  163. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/1K.txt +0 -0
  164. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/1M +0 -0
  165. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/1M.json +0 -0
  166. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/1M.txt +0 -0
  167. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/500K +0 -0
  168. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/500K.json +0 -0
  169. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/500K.txt +0 -0
  170. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/5M +0 -0
  171. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/5M.json +0 -0
  172. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/5M.txt +0 -0
  173. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/FILE_UPLOAD_1K +0 -0
  174. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/FILE_UPLOAD_1K_HEADERS.json +0 -0
  175. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/FORM_URLENCODED_1K +0 -0
  176. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/FORM_URLENCODED_1K_HEADERS.json +0 -0
  177. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/MULTIPART_1K +0 -0
  178. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/MULTIPART_1K_HEADERS.json +0 -0
  179. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/__init__.py +0 -0
  180. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/objects.py +0 -0
  181. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/persons_100.json +0 -0
  182. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/persons_50.json +0 -0
  183. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/test_data/persons_500.json +0 -0
  184. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/testproject/__init__.py +0 -0
  185. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/testproject/api.py +0 -0
  186. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/testproject/asgi.py +0 -0
  187. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/testproject/settings.py +0 -0
  188. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/testproject/test_api.py +0 -0
  189. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/testproject/urls.py +0 -0
  190. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/testproject/views.py +0 -0
  191. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/testproject/wsgi.py +0 -0
  192. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/users/__init__.py +0 -0
  193. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/users/admin.py +0 -0
  194. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/users/api.py +0 -0
  195. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/users/apps.py +0 -0
  196. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/users/migrations/0001_initial.py +0 -0
  197. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/users/migrations/__init__.py +0 -0
  198. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/users/models.py +0 -0
  199. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/users/tests.py +0 -0
  200. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/example/users/views.py +0 -0
  201. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/__init__.py +0 -0
  202. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/admin_tests/__init__.py +0 -0
  203. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/admin_tests/conftest.py +0 -0
  204. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/admin_tests/test_admin_with_django.py +0 -0
  205. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/admin_tests/urls.py +0 -0
  206. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/cbv/__init__.py +0 -0
  207. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/cbv/test_class_views.py +0 -0
  208. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/cbv/test_class_views_django_orm.py +0 -0
  209. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/cbv/test_class_views_features.py +0 -0
  210. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/cbv/test_class_views_with_client.py +0 -0
  211. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/conftest.py +0 -0
  212. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/test_action_decorator.py +0 -0
  213. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/test_auth_secret_key.py +0 -0
  214. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/test_cors_implementation.py +0 -0
  215. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/test_decorator_syntax.py +0 -0
  216. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/test_error_handling.py +0 -0
  217. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/test_file_response.py +0 -0
  218. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/test_global_cors.py +0 -0
  219. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/test_guards_auth.py +0 -0
  220. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/test_guards_integration.py +0 -0
  221. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/test_health.py +0 -0
  222. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/test_integration_validation.py +0 -0
  223. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/test_json_validation.py +0 -0
  224. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/test_jwt_auth.py +0 -0
  225. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/test_jwt_token.py +0 -0
  226. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/test_logging.py +0 -0
  227. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/test_logging_merge.py +0 -0
  228. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/test_middleware.py +0 -0
  229. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/test_middleware_server.py +0 -0
  230. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/test_model_viewset.py +0 -0
  231. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/test_models.py +0 -0
  232. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/test_openapi_docs.py +0 -0
  233. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/test_openapi_metadata.py +0 -0
  234. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/test_pagination.py +0 -0
  235. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/test_parameter_validation.py +0 -0
  236. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/test_request_get.py +0 -0
  237. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/test_syntax.py +0 -0
  238. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/test_testing_utilities.py +0 -0
  239. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/test_testing_utilities_simple.py +0 -0
  240. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/test_types.py +0 -0
  241. {django_bolt-0.2.4 → django_bolt-0.2.5}/python/tests/test_viewset_unified.py +0 -0
  242. {django_bolt-0.2.4 → django_bolt-0.2.5}/scripts/benchmark.sh +0 -0
  243. {django_bolt-0.2.4 → django_bolt-0.2.5}/scripts/install_hey.sh +0 -0
  244. {django_bolt-0.2.4 → django_bolt-0.2.5}/scripts/release.sh +0 -0
  245. {django_bolt-0.2.4 → django_bolt-0.2.5}/src/lib.rs +0 -0
  246. {django_bolt-0.2.4 → django_bolt-0.2.5}/src/streaming.rs +0 -0
  247. {django_bolt-0.2.4 → django_bolt-0.2.5}/src/testing.rs +0 -0
@@ -599,7 +599,7 @@ dependencies = [
599
599
 
600
600
  [[package]]
601
601
  name = "django-bolt"
602
- version = "0.2.4"
602
+ version = "0.2.5"
603
603
  dependencies = [
604
604
  "actix-cors",
605
605
  "actix-files",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "django-bolt"
3
- version = "0.2.4"
3
+ version = "0.2.5"
4
4
  edition = "2021"
5
5
  readme = "README.md"
6
6
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-bolt
3
- Version: 0.2.4
3
+ Version: 0.2.5
4
4
  Classifier: Development Status :: 3 - Alpha
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "django-bolt"
7
- version = "0.2.4"
7
+ version = "0.2.5"
8
8
  description = "High-performance API framework for Django with Rust-powered endpoints delivering 60k+ RPS"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -22,7 +22,7 @@ class Command(BaseCommand):
22
22
  "--processes", type=int, default=1, help="Number of processes (default: 1)"
23
23
  )
24
24
  parser.add_argument(
25
- "--workers", type=int, default=2, help="Workers per process (default: 2)"
25
+ "--workers", type=int, default=1, help="Workers per process (default: 1)"
26
26
  )
27
27
  parser.add_argument(
28
28
  "--no-admin",
@@ -34,6 +34,12 @@ class Command(BaseCommand):
34
34
  action="store_true",
35
35
  help="Enable auto-reload on file changes (development mode)"
36
36
  )
37
+ parser.add_argument(
38
+ "--backlog",
39
+ type=int,
40
+ default=1024,
41
+ help="Socket listen backlog size (default: 1024)"
42
+ )
37
43
 
38
44
  def handle(self, *args, **options):
39
45
  processes = options['processes']
@@ -246,9 +252,10 @@ class Command(BaseCommand):
246
252
  else:
247
253
  self.stdout.write(self.style.SUCCESS(f"[django-bolt] Starting server on http://{options['host']}:{options['port']}"))
248
254
  self.stdout.write(f"[django-bolt] Workers: {options['workers']}, Processes: {options['processes']}")
249
- # Set environment variable for Rust to read worker count
255
+ # Set environment variable for Rust to read worker count and backlog
250
256
  import os
251
257
  os.environ['DJANGO_BOLT_WORKERS'] = str(options['workers'])
258
+ os.environ['DJANGO_BOLT_BACKLOG'] = str(options['backlog'])
252
259
 
253
260
  # Determine compression config (server-level in Actix)
254
261
  # Priority: Django setting > first API with compression config
@@ -20,11 +20,11 @@ impl PythonDirectStream {
20
20
  pub fn new(content: Py<PyAny>) -> Self {
21
21
  // Determine if we should collect or stream
22
22
  let collect_threshold = 8192; // 8KB threshold for SSE
23
-
23
+
24
24
  // Resolve iterator and check if async
25
25
  let (iterator, is_async) = Python::attach(|py| {
26
26
  let obj = content.bind(py);
27
-
27
+
28
28
  // If callable, call it to get iterator
29
29
  let target = if obj.is_callable() {
30
30
  match obj.call0() {
@@ -34,11 +34,11 @@ impl PythonDirectStream {
34
34
  } else {
35
35
  content.clone_ref(py)
36
36
  };
37
-
37
+
38
38
  let bound = target.bind(py);
39
- let is_async = bound.hasattr("__aiter__").unwrap_or(false)
39
+ let is_async = bound.hasattr("__aiter__").unwrap_or(false)
40
40
  || bound.hasattr("__anext__").unwrap_or(false);
41
-
41
+
42
42
  // For sync iterators, get the iterator object
43
43
  let iter = if !is_async {
44
44
  if bound.hasattr("__next__").unwrap_or(false) {
@@ -62,10 +62,10 @@ impl PythonDirectStream {
62
62
  target
63
63
  }
64
64
  };
65
-
65
+
66
66
  (iter, is_async)
67
67
  });
68
-
68
+
69
69
  Self {
70
70
  iterator: Some(iterator),
71
71
  is_async,
@@ -75,20 +75,20 @@ impl PythonDirectStream {
75
75
  collect_threshold,
76
76
  }
77
77
  }
78
-
78
+
79
79
  /// Try to collect small responses for optimization
80
80
  pub fn try_collect_small(&mut self) -> Option<Bytes> {
81
81
  if self.is_async || self.exhausted {
82
82
  return None;
83
83
  }
84
-
84
+
85
85
  let mut collected = Vec::new();
86
86
  let mut total_size = 0usize;
87
-
87
+
88
88
  Python::attach(|py| {
89
89
  if let Some(ref iter) = self.iterator {
90
90
  let bound = iter.bind(py);
91
-
91
+
92
92
  // Try to collect up to threshold
93
93
  while total_size < self.collect_threshold {
94
94
  match bound.call_method0("__next__") {
@@ -109,7 +109,7 @@ impl PythonDirectStream {
109
109
  }
110
110
  }
111
111
  });
112
-
112
+
113
113
  if self.exhausted && total_size < self.collect_threshold {
114
114
  // Small response - return all as one
115
115
  let mut result = Vec::with_capacity(total_size);
@@ -129,24 +129,24 @@ impl PythonDirectStream {
129
129
 
130
130
  impl Stream for PythonDirectStream {
131
131
  type Item = Result<Bytes, std::io::Error>;
132
-
132
+
133
133
  fn poll_next(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
134
134
  if self.exhausted && self.buffer.is_empty() {
135
135
  return Poll::Ready(None);
136
136
  }
137
-
137
+
138
138
  // Return buffered items first
139
139
  if !self.buffer.is_empty() {
140
140
  return Poll::Ready(Some(Ok(self.buffer.remove(0))));
141
141
  }
142
-
142
+
143
143
  if self.is_async {
144
144
  // Async iterators not supported in direct stream yet
145
145
  // This should have been handled by try_collect_small or fallback
146
146
  self.exhausted = true;
147
147
  return Poll::Ready(None);
148
148
  }
149
-
149
+
150
150
  // Sync iterator - get next chunk directly
151
151
  let next = Python::attach(|py| {
152
152
  if let Some(ref iter) = self.iterator {
@@ -164,7 +164,7 @@ impl Stream for PythonDirectStream {
164
164
  None
165
165
  }
166
166
  });
167
-
167
+
168
168
  match next {
169
169
  Some(bytes) => Poll::Ready(Some(Ok(bytes))),
170
170
  None => {
@@ -174,7 +174,7 @@ impl Stream for PythonDirectStream {
174
174
  } else {
175
175
  Poll::Ready(Some(Err(std::io::Error::new(
176
176
  std::io::ErrorKind::Other,
177
- "Iterator error"
177
+ "Iterator error",
178
178
  ))))
179
179
  }
180
180
  }
@@ -188,28 +188,28 @@ fn convert_to_bytes(value: &Bound<'_, PyAny>) -> Option<Bytes> {
188
188
  if let Ok(s) = value.downcast::<PyString>() {
189
189
  return Some(Bytes::from(s.to_string_lossy().into_owned()));
190
190
  }
191
-
191
+
192
192
  if let Ok(b) = value.downcast::<PyBytes>() {
193
193
  return Some(Bytes::copy_from_slice(b.as_bytes()));
194
194
  }
195
-
195
+
196
196
  // Try extract string
197
197
  if let Ok(s) = value.extract::<String>() {
198
198
  return Some(Bytes::from(s));
199
199
  }
200
-
200
+
201
201
  // Try __bytes__ method
202
202
  if let Ok(bobj) = value.call_method0("__bytes__") {
203
203
  if let Ok(b) = bobj.downcast::<PyBytes>() {
204
204
  return Some(Bytes::copy_from_slice(b.as_bytes()));
205
205
  }
206
206
  }
207
-
207
+
208
208
  // Last resort: str()
209
209
  if let Ok(s) = value.str() {
210
210
  return Some(Bytes::from(s.to_string()));
211
211
  }
212
-
212
+
213
213
  None
214
214
  }
215
215
 
@@ -218,9 +218,9 @@ pub fn create_sse_response(
218
218
  content: Py<PyAny>,
219
219
  ) -> Result<actix_web::HttpResponse, actix_web::Error> {
220
220
  use actix_web::HttpResponse;
221
-
221
+
222
222
  let mut stream = PythonDirectStream::new(content);
223
-
223
+
224
224
  // Try to collect small responses
225
225
  if let Some(body) = stream.try_collect_small() {
226
226
  // Small response - send as single body
@@ -230,11 +230,11 @@ pub fn create_sse_response(
230
230
  .append_header(("X-Accel-Buffering", "no"))
231
231
  .body(body));
232
232
  }
233
-
233
+
234
234
  // Large response - use streaming
235
235
  Ok(HttpResponse::Ok()
236
236
  .content_type("text/event-stream")
237
237
  .append_header(("Cache-Control", "no-cache"))
238
238
  .append_header(("X-Accel-Buffering", "no"))
239
239
  .streaming(Box::pin(stream)))
240
- }
240
+ }
@@ -1,21 +1,27 @@
1
- use actix_web::{HttpResponse, http::StatusCode};
1
+ use actix_web::{http::StatusCode, HttpResponse};
2
2
  use pyo3::prelude::*;
3
3
  use pyo3::types::PyDict;
4
4
 
5
5
  /// Extract error information from a Python HTTPException
6
- pub fn extract_http_exception(_py: Python, exc: &Bound<PyAny>) -> Option<(u16, String, Vec<(String, String)>, Option<Py<PyAny>>)> {
6
+ pub fn extract_http_exception(
7
+ _py: Python,
8
+ exc: &Bound<PyAny>,
9
+ ) -> Option<(u16, String, Vec<(String, String)>, Option<Py<PyAny>>)> {
7
10
  // Try to extract HTTPException fields
8
- let status_code: u16 = exc.getattr("status_code")
11
+ let status_code: u16 = exc
12
+ .getattr("status_code")
9
13
  .ok()
10
14
  .and_then(|v| v.extract().ok())
11
15
  .unwrap_or(500);
12
16
 
13
- let detail: String = exc.getattr("detail")
17
+ let detail: String = exc
18
+ .getattr("detail")
14
19
  .ok()
15
20
  .and_then(|v| v.extract().ok())
16
21
  .unwrap_or_else(|| "Internal Server Error".to_string());
17
22
 
18
- let headers: Vec<(String, String)> = exc.getattr("headers")
23
+ let headers: Vec<(String, String)> = exc
24
+ .getattr("headers")
19
25
  .ok()
20
26
  .and_then(|h| {
21
27
  if let Ok(dict) = h.downcast::<PyDict>() {
@@ -32,9 +38,10 @@ pub fn extract_http_exception(_py: Python, exc: &Bound<PyAny>) -> Option<(u16, S
32
38
  })
33
39
  .unwrap_or_else(|| Vec::new());
34
40
 
35
- let extra: Option<Py<PyAny>> = exc.getattr("extra")
36
- .ok()
37
- .and_then(|e| if e.is_none() { None } else { Some(e.unbind()) });
41
+ let extra: Option<Py<PyAny>> =
42
+ exc.getattr("extra")
43
+ .ok()
44
+ .and_then(|e| if e.is_none() { None } else { Some(e.unbind()) });
38
45
 
39
46
  Some((status_code, detail, headers, extra))
40
47
  }
@@ -45,7 +52,8 @@ pub fn is_http_exception(py: Python, exc: &Bound<PyAny>) -> bool {
45
52
  let exceptions_module = py.import("django_bolt.exceptions")?;
46
53
  let http_exc_class = exceptions_module.getattr("HTTPException")?;
47
54
  exc.is_instance(&http_exc_class)
48
- })().unwrap_or(false)
55
+ })()
56
+ .unwrap_or(false)
49
57
  }
50
58
 
51
59
  /// Check if a Python exception is a ValidationError
@@ -55,7 +63,8 @@ pub fn is_validation_error(py: Python, exc: &Bound<PyAny>) -> bool {
55
63
  let msgspec = py.import("msgspec")?;
56
64
  let val_err_class = msgspec.getattr("ValidationError")?;
57
65
  exc.is_instance(&val_err_class)
58
- })().unwrap_or(false);
66
+ })()
67
+ .unwrap_or(false);
59
68
 
60
69
  if is_msgspec {
61
70
  return true;
@@ -66,7 +75,8 @@ pub fn is_validation_error(py: Python, exc: &Bound<PyAny>) -> bool {
66
75
  let exceptions_module = py.import("django_bolt.exceptions")?;
67
76
  let val_exc_class = exceptions_module.getattr("ValidationException")?;
68
77
  exc.is_instance(&val_exc_class)
69
- })().unwrap_or(false)
78
+ })()
79
+ .unwrap_or(false)
70
80
  }
71
81
 
72
82
  /// Build an error response from exception information
@@ -120,7 +130,8 @@ pub fn handle_python_exception(
120
130
  let django_conf = py.import("django.conf")?;
121
131
  let settings = django_conf.getattr("settings")?;
122
132
  settings.getattr("DEBUG")?.extract::<bool>()
123
- })().unwrap_or(debug);
133
+ })()
134
+ .unwrap_or(debug);
124
135
  // Check if it's an HTTPException
125
136
  if is_http_exception(py, exc) {
126
137
  if let Some((status_code, detail, headers, extra)) = extract_http_exception(py, exc) {
@@ -137,15 +148,20 @@ pub fn handle_python_exception(
137
148
  let response_tuple = handle_exception.call1((exc, debug))?;
138
149
 
139
150
  // Extract (status_code, headers, body)
140
- if let Ok((status, headers, body)) = response_tuple.extract::<(u16, Vec<(String, String)>, Vec<u8>)>() {
141
- let status_code = StatusCode::from_u16(status).unwrap_or(StatusCode::UNPROCESSABLE_ENTITY);
151
+ if let Ok((status, headers, body)) =
152
+ response_tuple.extract::<(u16, Vec<(String, String)>, Vec<u8>)>()
153
+ {
154
+ let status_code =
155
+ StatusCode::from_u16(status).unwrap_or(StatusCode::UNPROCESSABLE_ENTITY);
142
156
  let mut response = HttpResponse::build(status_code);
143
157
  for (k, v) in headers {
144
158
  response.append_header((k, v));
145
159
  }
146
160
  Ok(response.body(body))
147
161
  } else {
148
- Err(PyErr::new::<pyo3::exceptions::PyTypeError, _>("Invalid response format"))
162
+ Err(PyErr::new::<pyo3::exceptions::PyTypeError, _>(
163
+ "Invalid response format",
164
+ ))
149
165
  }
150
166
  })();
151
167
 
@@ -156,7 +172,10 @@ pub fn handle_python_exception(
156
172
 
157
173
  // Generic exception handling
158
174
  let exc_str = exc.to_string();
159
- let exc_type = exc.get_type().name().ok()
175
+ let exc_type = exc
176
+ .get_type()
177
+ .name()
178
+ .ok()
160
179
  .map(|s| s.to_string())
161
180
  .unwrap_or_else(|| "Exception".to_string());
162
181
 
@@ -170,7 +189,8 @@ pub fn handle_python_exception(
170
189
  let tb = format_exception.call1((exc_type, exc, tb_attr))?;
171
190
  let tb_list: Vec<String> = tb.extract()?;
172
191
  Ok(tb_list.join(""))
173
- })().unwrap_or_else(|_| "Traceback unavailable".to_string());
192
+ })()
193
+ .unwrap_or_else(|_| "Traceback unavailable".to_string());
174
194
 
175
195
  (
176
196
  format!("{}: {}", exc_type, exc_str),
@@ -181,14 +201,18 @@ pub fn handle_python_exception(
181
201
  escape_json(&traceback),
182
202
  escape_json(path),
183
203
  escape_json(method),
184
- ))
204
+ )),
185
205
  )
186
206
  } else {
187
207
  ("Internal Server Error".to_string(), None)
188
208
  };
189
209
 
190
210
  let body = if let Some(extra) = extra_info {
191
- format!(r#"{{"detail":"{}","extra":{}}}"#, escape_json(&detail), extra)
211
+ format!(
212
+ r#"{{"detail":"{}","extra":{}}}"#,
213
+ escape_json(&detail),
214
+ extra
215
+ )
192
216
  } else {
193
217
  format!(r#"{{"detail":"{}"}}"#, escape_json(&detail))
194
218
  };
@@ -53,9 +53,10 @@ fn add_cors_headers_rust(
53
53
 
54
54
  // Add exposed headers using cached HeaderValue
55
55
  if let Some(ref cached_val) = cors_config.expose_headers_header {
56
- response
57
- .headers_mut()
58
- .insert(actix_web::http::header::ACCESS_CONTROL_EXPOSE_HEADERS, cached_val.clone());
56
+ response.headers_mut().insert(
57
+ actix_web::http::header::ACCESS_CONTROL_EXPOSE_HEADERS,
58
+ cached_val.clone(),
59
+ );
59
60
  }
60
61
  return true; // Origin allowed
61
62
  }
@@ -65,15 +66,17 @@ fn add_cors_headers_rust(
65
66
 
66
67
  // Handle allow_all_origins (wildcard) without credentials
67
68
  if cors_config.allow_all_origins {
68
- response
69
- .headers_mut()
70
- .insert(actix_web::http::header::ACCESS_CONTROL_ALLOW_ORIGIN, HeaderValue::from_static("*"));
69
+ response.headers_mut().insert(
70
+ actix_web::http::header::ACCESS_CONTROL_ALLOW_ORIGIN,
71
+ HeaderValue::from_static("*"),
72
+ );
71
73
 
72
74
  // Add exposed headers using cached HeaderValue
73
75
  if let Some(ref cached_val) = cors_config.expose_headers_header {
74
- response
75
- .headers_mut()
76
- .insert(actix_web::http::header::ACCESS_CONTROL_EXPOSE_HEADERS, cached_val.clone());
76
+ response.headers_mut().insert(
77
+ actix_web::http::header::ACCESS_CONTROL_EXPOSE_HEADERS,
78
+ cached_val.clone(),
79
+ );
77
80
  }
78
81
  return true; // Origin allowed (wildcard)
79
82
  }
@@ -99,10 +102,16 @@ fn add_cors_headers_rust(
99
102
 
100
103
  // Check regex match using route-level regexes, then global regexes
101
104
  let regex_match = if !cors_config.compiled_origin_regexes.is_empty() {
102
- cors_config.compiled_origin_regexes.iter().any(|re| re.is_match(req_origin))
105
+ cors_config
106
+ .compiled_origin_regexes
107
+ .iter()
108
+ .any(|re| re.is_match(req_origin))
103
109
  } else {
104
110
  !state.cors_origin_regexes.is_empty()
105
- && state.cors_origin_regexes.iter().any(|re| re.is_match(req_origin))
111
+ && state
112
+ .cors_origin_regexes
113
+ .iter()
114
+ .any(|re| re.is_match(req_origin))
106
115
  };
107
116
 
108
117
  // Origin not allowed
@@ -133,9 +142,10 @@ fn add_cors_headers_rust(
133
142
 
134
143
  // Add exposed headers using cached HeaderValue (zero allocations)
135
144
  if let Some(ref cached_val) = cors_config.expose_headers_header {
136
- response
137
- .headers_mut()
138
- .insert(actix_web::http::header::ACCESS_CONTROL_EXPOSE_HEADERS, cached_val.clone());
145
+ response.headers_mut().insert(
146
+ actix_web::http::header::ACCESS_CONTROL_EXPOSE_HEADERS,
147
+ cached_val.clone(),
148
+ );
139
149
  }
140
150
 
141
151
  true // Origin allowed
@@ -145,23 +155,26 @@ fn add_cors_headers_rust(
145
155
  fn add_cors_preflight_headers(response: &mut HttpResponse, cors_config: &CorsConfig) {
146
156
  // Use cached HeaderValue for methods (zero allocations)
147
157
  if let Some(ref cached_val) = cors_config.methods_header {
148
- response
149
- .headers_mut()
150
- .insert(actix_web::http::header::ACCESS_CONTROL_ALLOW_METHODS, cached_val.clone());
158
+ response.headers_mut().insert(
159
+ actix_web::http::header::ACCESS_CONTROL_ALLOW_METHODS,
160
+ cached_val.clone(),
161
+ );
151
162
  }
152
163
 
153
164
  // Use cached HeaderValue for headers (zero allocations)
154
165
  if let Some(ref cached_val) = cors_config.headers_header {
155
- response
156
- .headers_mut()
157
- .insert(actix_web::http::header::ACCESS_CONTROL_ALLOW_HEADERS, cached_val.clone());
166
+ response.headers_mut().insert(
167
+ actix_web::http::header::ACCESS_CONTROL_ALLOW_HEADERS,
168
+ cached_val.clone(),
169
+ );
158
170
  }
159
171
 
160
172
  // Use cached HeaderValue for max_age (zero allocations)
161
173
  if let Some(ref cached_val) = cors_config.max_age_header {
162
- response
163
- .headers_mut()
164
- .insert(actix_web::http::header::ACCESS_CONTROL_MAX_AGE, cached_val.clone());
174
+ response.headers_mut().insert(
175
+ actix_web::http::header::ACCESS_CONTROL_MAX_AGE,
176
+ cached_val.clone(),
177
+ );
165
178
  }
166
179
 
167
180
  // Add Vary headers for preflight requests
@@ -220,12 +233,8 @@ pub async fn handle_request(
220
233
  req.headers().get("origin").and_then(|v| v.to_str().ok());
221
234
 
222
235
  // Validate origin and add CORS headers
223
- let origin_allowed = add_cors_headers_rust(
224
- &mut response,
225
- origin,
226
- cors_cfg,
227
- &state,
228
- );
236
+ let origin_allowed =
237
+ add_cors_headers_rust(&mut response, origin, cors_cfg, &state);
229
238
 
230
239
  // CRITICAL: Only add preflight headers if origin was validated
231
240
  // Per RFC 6454, preflight must validate origin before granting access
@@ -590,12 +599,7 @@ pub async fn handle_request(
590
599
  if let Some(ref route_meta) = route_metadata {
591
600
  if let Some(ref cors_cfg) = route_meta.cors_config {
592
601
  let origin = req.headers().get("origin").and_then(|v| v.to_str().ok());
593
- let _ = add_cors_headers_rust(
594
- &mut response,
595
- origin,
596
- cors_cfg,
597
- &state,
598
- );
602
+ let _ = add_cors_headers_rust(&mut response, origin, cors_cfg, &state);
599
603
  }
600
604
  }
601
605
 
@@ -719,12 +723,8 @@ pub async fn handle_request(
719
723
  if let Some(ref cors_cfg) = route_meta.cors_config {
720
724
  let origin =
721
725
  req.headers().get("origin").and_then(|v| v.to_str().ok());
722
- let _ = add_cors_headers_rust(
723
- &mut response,
724
- origin,
725
- cors_cfg,
726
- &state,
727
- );
726
+ let _ =
727
+ add_cors_headers_rust(&mut response, origin, cors_cfg, &state);
728
728
  }
729
729
  }
730
730
  return response;
@@ -1,2 +1,2 @@
1
1
  // This module contains JSON serialization utilities that are currently unused
2
- // but kept for potential future optimizations
2
+ // but kept for potential future optimizations
@@ -109,10 +109,14 @@ impl CorsConfig {
109
109
 
110
110
  // Compile origin regex patterns at startup
111
111
  config.origin_regexes = origin_regexes.clone();
112
- config.compiled_origin_regexes = origin_regexes.iter()
112
+ config.compiled_origin_regexes = origin_regexes
113
+ .iter()
113
114
  .filter_map(|pattern| {
114
115
  Regex::new(pattern).ok().or_else(|| {
115
- eprintln!("[django-bolt] Warning: Invalid route-level CORS origin regex pattern: {}", pattern);
116
+ eprintln!(
117
+ "[django-bolt] Warning: Invalid route-level CORS origin regex pattern: {}",
118
+ pattern
119
+ );
116
120
  None
117
121
  })
118
122
  })
@@ -331,7 +335,10 @@ fn parse_cors_config(dict: &HashMap<String, Py<PyAny>>, py: Python) -> Option<Co
331
335
  }
332
336
 
333
337
  /// Parse rate limiting configuration from middleware dict
334
- fn parse_rate_limit_config(dict: &HashMap<String, Py<PyAny>>, py: Python) -> Option<RateLimitConfig> {
338
+ fn parse_rate_limit_config(
339
+ dict: &HashMap<String, Py<PyAny>>,
340
+ py: Python,
341
+ ) -> Option<RateLimitConfig> {
335
342
  let mut config = RateLimitConfig::default();
336
343
 
337
344
  // Parse rps (required)