django-bolt 0.2.0__cp310-abi3-win_amd64.whl → 0.2.3__cp310-abi3-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

django_bolt/_core.pyd CHANGED
Binary file
@@ -2,9 +2,8 @@
2
2
 
3
3
  Provides test clients for in-memory testing without subprocess/network overhead.
4
4
  """
5
- from django_bolt.testing.client import TestClient, AsyncTestClient
5
+ from django_bolt.testing.client import TestClient
6
6
 
7
7
  __all__ = [
8
8
  "TestClient",
9
- "AsyncTestClient",
10
9
  ]
@@ -129,6 +129,31 @@ class TestClient(httpx.Client):
129
129
 
130
130
  __test__ = False # Tell pytest this is not a test class
131
131
 
132
+ @staticmethod
133
+ def _read_cors_settings_from_django() -> list[str] | None:
134
+ """Read CORS_ALLOWED_ORIGINS from Django settings (same as production server).
135
+
136
+ Returns:
137
+ List of allowed origins from Django settings, or None if not configured
138
+ """
139
+ try:
140
+ from django.conf import settings
141
+
142
+ # Check if CORS_ALLOWED_ORIGINS is defined
143
+ if hasattr(settings, 'CORS_ALLOWED_ORIGINS'):
144
+ origins = settings.CORS_ALLOWED_ORIGINS
145
+ if isinstance(origins, (list, tuple)):
146
+ return list(origins)
147
+
148
+ # Check for CORS_ALLOW_ALL_ORIGINS (wildcard)
149
+ if hasattr(settings, 'CORS_ALLOW_ALL_ORIGINS') and settings.CORS_ALLOW_ALL_ORIGINS:
150
+ return ["*"]
151
+
152
+ return None
153
+ except (ImportError, AttributeError):
154
+ # Django not configured or settings not available
155
+ return None
156
+
132
157
  def __init__(
133
158
  self,
134
159
  api: BoltAPI,
@@ -136,6 +161,7 @@ class TestClient(httpx.Client):
136
161
  raise_server_exceptions: bool = True,
137
162
  use_http_layer: bool = False,
138
163
  cors_allowed_origins: list[str] | None = None,
164
+ read_django_settings: bool = True,
139
165
  **kwargs: Any,
140
166
  ):
141
167
  """Initialize test client.
@@ -146,11 +172,19 @@ class TestClient(httpx.Client):
146
172
  raise_server_exceptions: If True, raise exceptions from handlers
147
173
  use_http_layer: If True, route through Actix HTTP layer (enables testing
148
174
  CORS, rate limiting, compression). Default False for fast tests.
149
- cors_allowed_origins: Global CORS allowed origins for testing
175
+ cors_allowed_origins: Global CORS allowed origins for testing.
176
+ If None and read_django_settings=True, reads from Django settings.
177
+ read_django_settings: If True, read CORS_ALLOWED_ORIGINS from Django settings
178
+ when cors_allowed_origins is None. Default True.
150
179
  **kwargs: Additional arguments passed to httpx.Client
151
180
  """
152
181
  from django_bolt import _core
153
182
 
183
+ # If cors_allowed_origins not provided and read_django_settings=True,
184
+ # read from Django settings (same as production server does)
185
+ if cors_allowed_origins is None and read_django_settings:
186
+ cors_allowed_origins = self._read_cors_settings_from_django()
187
+
154
188
  # Create test app instance
155
189
  self.app_id = _core.create_test_app(api._dispatch, False, cors_allowed_origins)
156
190
 
@@ -193,82 +227,3 @@ class TestClient(httpx.Client):
193
227
  except:
194
228
  pass
195
229
  return super().__exit__(*args)
196
-
197
-
198
- class AsyncTestClient(httpx.AsyncClient):
199
- """Asynchronous test client for django-bolt using per-instance test state."""
200
-
201
- __test__ = False # Tell pytest this is not a test class
202
-
203
- def __init__(
204
- self,
205
- api: BoltAPI,
206
- base_url: str = "http://testserver.local",
207
- raise_server_exceptions: bool = True,
208
- use_http_layer: bool = False,
209
- cors_allowed_origins: list[str] | None = None,
210
- **kwargs: Any,
211
- ):
212
- """Initialize async test client.
213
-
214
- Args:
215
- api: BoltAPI instance to test
216
- base_url: Base URL for requests
217
- raise_server_exceptions: If True, raise exceptions from handlers
218
- use_http_layer: If True, route through Actix HTTP layer (enables testing
219
- CORS, rate limiting, compression). Default False for fast tests.
220
- cors_allowed_origins: Global CORS allowed origins for testing
221
- **kwargs: Additional arguments passed to httpx.AsyncClient
222
- """
223
- from django_bolt import _core
224
-
225
- # Create test app instance
226
- self.app_id = _core.create_test_app(api._dispatch, False, cors_allowed_origins)
227
-
228
- # Register routes
229
- rust_routes = [
230
- (method, path, handler_id, handler)
231
- for method, path, handler_id, handler in api._routes
232
- ]
233
- _core.register_test_routes(self.app_id, rust_routes)
234
-
235
- # Register middleware metadata if any exists
236
- if api._handler_middleware:
237
- middleware_data = [
238
- (handler_id, meta)
239
- for handler_id, meta in api._handler_middleware.items()
240
- ]
241
- _core.register_test_middleware_metadata(self.app_id, middleware_data)
242
-
243
- # Ensure runtime is ready
244
- _core.ensure_test_runtime(self.app_id)
245
-
246
- # Create async transport
247
- class AsyncTransport(httpx.AsyncBaseTransport):
248
- def __init__(self, app_id: int, raise_exceptions: bool, use_http_layer: bool):
249
- self._sync_transport = BoltTestTransport(app_id, raise_exceptions, use_http_layer)
250
-
251
- async def handle_async_request(self, request: httpx.Request) -> httpx.Response:
252
- return self._sync_transport.handle_request(request)
253
-
254
- super().__init__(
255
- base_url=base_url,
256
- transport=AsyncTransport(self.app_id, raise_server_exceptions, use_http_layer),
257
- follow_redirects=True,
258
- **kwargs,
259
- )
260
- self.api = api
261
-
262
- async def __aenter__(self):
263
- """Enter async context manager."""
264
- return await super().__aenter__()
265
-
266
- async def __aexit__(self, *args):
267
- """Exit async context manager and cleanup test app."""
268
- from django_bolt import _core
269
-
270
- try:
271
- _core.destroy_test_app(self.app_id)
272
- except:
273
- pass
274
- return await super().__aexit__(*args)
@@ -4,7 +4,7 @@ from __future__ import annotations
4
4
  from typing import Any
5
5
 
6
6
  from django_bolt import BoltAPI
7
- from django_bolt.testing.client import AsyncTestClient, TestClient
7
+ from django_bolt.testing.client import TestClient
8
8
 
9
9
 
10
10
  def create_test_client(
@@ -48,46 +48,3 @@ def create_test_client(
48
48
  bootstrap_django=bootstrap_django,
49
49
  **kwargs,
50
50
  )
51
-
52
-
53
- def create_async_test_client(
54
- api: BoltAPI,
55
- base_url: str = "http://testserver.local",
56
- raise_server_exceptions: bool = True,
57
- bootstrap_django: bool = True,
58
- **kwargs: Any,
59
- ) -> AsyncTestClient:
60
- """Create an asynchronous test client.
61
-
62
- Args:
63
- api: BoltAPI instance to test
64
- base_url: Base URL for requests
65
- raise_server_exceptions: If True, raise handler exceptions instead of 500 responses
66
- **kwargs: Additional httpx.AsyncClient arguments
67
-
68
- Returns:
69
- AsyncTestClient instance
70
-
71
- Example:
72
- from django_bolt import BoltAPI
73
- from django_bolt.testing import create_async_test_client
74
-
75
- api = BoltAPI()
76
-
77
- @api.get("/users/{user_id}")
78
- async def get_user(user_id: int):
79
- return {"id": user_id, "name": "Test User"}
80
-
81
- async def test_get_user():
82
- async with create_async_test_client(api) as client:
83
- response = await client.get("/users/123")
84
- assert response.status_code == 200
85
- assert response.json()["id"] == 123
86
- """
87
- return AsyncTestClient(
88
- api=api,
89
- base_url=base_url,
90
- raise_server_exceptions=raise_server_exceptions,
91
- bootstrap_django=bootstrap_django,
92
- **kwargs,
93
- )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-bolt
3
- Version: 0.2.0
3
+ Version: 0.2.3
4
4
  Classifier: Development Status :: 3 - Alpha
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -24,6 +24,7 @@ Requires-Dist: django>=4.2
24
24
  Requires-Dist: click>=8.1
25
25
  Requires-Dist: msgspec>=0.18
26
26
  Requires-Dist: multipart>=1.3
27
+ Requires-Dist: pyjwt>=2.10.1
27
28
  Requires-Dist: pyyaml>=6.0 ; extra == 'yaml'
28
29
  Provides-Extra: yaml
29
30
  Summary: High-performance API framework for Django with Rust-powered endpoints delivering 60k+ RPS
@@ -92,6 +93,7 @@ python manage.py runbolt --dev # for development with reload enabled
92
93
  [django-bolt] Workers: 1, Processes: 1
93
94
  [django-bolt] OpenAPI docs enabled at http://0.0.0.0:8000/docs/ #swagger docs builtin
94
95
 
96
+ python manage.py runbolt --processes 8 workers 1 #for deployment (depends on your cpu cores)
95
97
  # processes are python processes that handle request 1 actix worker
96
98
  ```
97
99
 
@@ -166,7 +168,11 @@ python manage.py runbolt --dev # for development with reload enabled
166
168
 
167
169
  - ✅ **Global Middleware** - Apply to all routes via `BoltAPI(middleware=[...])`
168
170
  - ✅ **Per-Route Middleware** - `@middleware`, `@rate_limit`, `@cors` decorators
169
- - ✅ **CORS Middleware** - Full CORS support with preflight
171
+ - ✅ **CORS Middleware** - Full CORS support with preflight handling
172
+ - Django settings integration (`CORS_ALLOWED_ORIGINS`, `CORS_ALLOW_ALL_ORIGINS`)
173
+ - Route-level overrides with `@cors()` decorator
174
+ - Origin validation, credentials support, preflight caching
175
+ - Runs entirely in Rust (zero GIL overhead)
170
176
  - ✅ **Rate Limiting** - Token bucket algorithm (in Rust, no GIL)
171
177
  - ✅ **Compression** - Automatic gzip/brotli/zstd compression (client-negotiated)
172
178
  - ✅ **Skip Middleware** - `@skip_middleware("cors", "rate_limit", "compression")`
@@ -190,13 +196,6 @@ python manage.py runbolt --dev # for development with reload enabled
190
196
  - Constant-time comparison (timing attack prevention)
191
197
  - Fast validation in Rust
192
198
 
193
- - ✅ **Session Authentication** - **Complete** (Django session integration)
194
-
195
- - Django session backend integration
196
- - Automatic user lookup from session
197
- - Compatible with Django's session middleware
198
- - Supports both cookie-based and custom session stores
199
-
200
199
  - ✅ **Permission Guards** (all run in Rust):
201
200
 
202
201
  - `AllowAny()` - Public access
@@ -374,24 +373,45 @@ async def login(username: str, password: str):
374
373
 
375
374
  **📖 See [docs/SECURITY.md](docs/SECURITY.md) for complete authentication documentation.**
376
375
 
377
- ### Middleware
376
+ ### Middleware & CORS
378
377
 
379
378
  ```python
380
379
  from django_bolt import BoltAPI
381
380
  from django_bolt.middleware import cors, rate_limit, skip_middleware
382
381
 
383
- # Global middleware
382
+ # Option 1: Use Django settings (recommended for production)
383
+ # In settings.py:
384
+ # CORS_ALLOWED_ORIGINS = ["https://example.com", "https://app.example.com"]
385
+ # CORS_ALLOW_CREDENTIALS = True
386
+ # CORS_MAX_AGE = 3600
387
+
388
+ api = BoltAPI() # Automatically reads Django CORS settings
389
+
390
+ # Option 2: Global middleware config
384
391
  api = BoltAPI(
385
392
  middleware_config={
386
393
  "cors": {
387
394
  "origins": ["http://localhost:3000"],
388
395
  "methods": ["GET", "POST", "PUT", "DELETE"],
389
396
  "credentials": True,
397
+ "max_age": 3600,
390
398
  }
391
399
  }
392
400
  )
393
401
 
394
- # Per-route rate limiting (runs in Rust, no GIL)
402
+ # Option 3: Per-route CORS override (overrides global/Django settings)
403
+ @api.get("/public-api")
404
+ @cors(origins=["*"], credentials=False) # Allow all origins
405
+ async def public_endpoint():
406
+ return {"message": "Public endpoint with custom CORS"}
407
+
408
+ # CORS with credentials and specific origins
409
+ @api.post("/auth-endpoint")
410
+ @cors(origins=["https://app.example.com"], credentials=True, max_age=3600)
411
+ async def auth_endpoint():
412
+ return {"message": "Authenticated endpoint with CORS"}
413
+
414
+ # Rate limiting (runs in Rust, no GIL)
395
415
  @api.get("/limited")
396
416
  @rate_limit(rps=100, burst=200, key="ip") # 100 req/s with burst of 200
397
417
  async def limited_endpoint():
@@ -403,12 +423,6 @@ async def limited_endpoint():
403
423
  async def user_limited():
404
424
  return {"message": "Per-user rate limiting"}
405
425
 
406
- # Custom CORS for specific route
407
- @api.get("/public")
408
- @cors(origins=["https://example.com"], credentials=True, max_age=3600)
409
- async def public_endpoint():
410
- return {"message": "Public endpoint with CORS"}
411
-
412
426
  # Skip global middleware
413
427
  @api.get("/no-cors")
414
428
  @skip_middleware("cors", "rate_limit")
@@ -606,4 +620,5 @@ Django-Bolt is open source and available under the MIT License.
606
620
 
607
621
  ---
608
622
 
609
- For questions, issues, or feature requests, please visit our [GitHub repository](https://github.com/FarhanAliRaza/django-bolt).
623
+ For questions, issues, or feature requests, please visit our [GitHub repository](https://github.com/FarhanAliRaza/django-bolt).
624
+
@@ -1,8 +1,8 @@
1
- django_bolt-0.2.0.dist-info/METADATA,sha256=TiRxH-lX6g4ZTac9BorIcf27ZJbBD-HioI1_WxvB-OQ,21293
2
- django_bolt-0.2.0.dist-info/WHEEL,sha256=4EDp_7DiFfWl1yYv5M4wSosAn5L_xgD1dyrQxQxfCx8,95
3
- django_bolt-0.2.0.dist-info/entry_points.txt,sha256=cUEGAdiOY6BryNhsgOS_50AONPPHajI3yvhqr56ZiaU,51
1
+ django_bolt-0.2.3.dist-info/METADATA,sha256=xrjcnw-AiqNcaJNTR9zjgP4cc26YTXJQhANvRaa-EkY,22007
2
+ django_bolt-0.2.3.dist-info/WHEEL,sha256=4EDp_7DiFfWl1yYv5M4wSosAn5L_xgD1dyrQxQxfCx8,95
3
+ django_bolt-0.2.3.dist-info/entry_points.txt,sha256=cUEGAdiOY6BryNhsgOS_50AONPPHajI3yvhqr56ZiaU,51
4
4
  django_bolt/__init__.py,sha256=fhXQUJR5SO-GwhF_2N9w0UK6rIFx7kWGfpOPyIKvB9Q,3139
5
- django_bolt/_core.pyd,sha256=1EA3IogC0D9ZShXU0qI6tM9Ud5Xmn-QoHa3BVSSM_X4,8905728
5
+ django_bolt/_core.pyd,sha256=D_Mam9MZpy5OxV3_xC61vdndqwH4AqIr0hNFfE-zXg4,8941568
6
6
  django_bolt/_json.py,sha256=oGxi29DHB8UYvbqjtqtrP6gThk7Qonlw333c4_cTr6s,4917
7
7
  django_bolt/admin/__init__.py,sha256=BNN1afSvWvt-377rNzZLdNDEvKyMZXkmB_0MhTxAN8k,601
8
8
  django_bolt/admin/admin_detection.py,sha256=1yQkLx9rF5DLMjJqbx8n4c82UgS9JEAnUcPdRfFqAXk,5825
@@ -83,9 +83,9 @@ django_bolt/responses.py,sha256=B0LXHN431c1-o93DC_xTF-wrnv8CMxn-1Sd0Yi4cwjE,7238
83
83
  django_bolt/router.py,sha256=wTFsPasg5Sh5hgdFp1kCmUrK6ugwRPWEj7PsxWOc9lc,1532
84
84
  django_bolt/serialization.py,sha256=Uza6jzQPTFxTQHnXEWBEDYY-3xDOGZinBSRE0T4KK28,8825
85
85
  django_bolt/status_codes.py,sha256=jTZ32kPwj3tC23jh6uC1Ci1P9EKttywsvyWINQIEwGg,9386
86
- django_bolt/testing/__init__.py,sha256=5UDYTmdyKkkY5ENlOlZcK0twbsLSylpjlp7oFgqNC-0,257
87
- django_bolt/testing/client.py,sha256=X1DXulzJHuN3RKvyMhEP4yhymc2UrUDBrnngho-m1yA,10008
88
- django_bolt/testing/helpers.py,sha256=Vv-4KuIbOVfCWQvohKpO37u59uhrhpWnRU5bWzbK5rg,2820
86
+ django_bolt/testing/__init__.py,sha256=TgJjct2WucKL7HyrbMuQfplNptlCPhu4CL-WQZxaoRY,216
87
+ django_bolt/testing/client.py,sha256=Yx7N1lfXmJcH4yF--6K0YehtPY2_wiwb8U3a0qQoqDE,8616
88
+ django_bolt/testing/helpers.py,sha256=hq2HD1IEwHuW8tMgZO9ZW6BFdcE_JQXaV8sZc58LBDc,1472
89
89
  django_bolt/typing.py,sha256=sGlFUUXY8EJbYWCgARgNGLZPu7SaxxohZaSx1SRLYaE,8686
90
90
  django_bolt/views.py,sha256=KewSpL6g-zZxXnEkwun6hueX3S_Eji-d2dawzoqe-GM,41715
91
- django_bolt-0.2.0.dist-info/RECORD,,
91
+ django_bolt-0.2.3.dist-info/RECORD,,