django-bolt 0.2.0__cp310-abi3-win_amd64.whl → 0.2.2__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.2
4
4
  Classifier: Development Status :: 3 - Alpha
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -92,6 +92,7 @@ python manage.py runbolt --dev # for development with reload enabled
92
92
  [django-bolt] Workers: 1, Processes: 1
93
93
  [django-bolt] OpenAPI docs enabled at http://0.0.0.0:8000/docs/ #swagger docs builtin
94
94
 
95
+ python manage.py runbolt --processes 8 workers 1 #for deployment (depends on your cpu cores)
95
96
  # processes are python processes that handle request 1 actix worker
96
97
  ```
97
98
 
@@ -166,7 +167,11 @@ python manage.py runbolt --dev # for development with reload enabled
166
167
 
167
168
  - ✅ **Global Middleware** - Apply to all routes via `BoltAPI(middleware=[...])`
168
169
  - ✅ **Per-Route Middleware** - `@middleware`, `@rate_limit`, `@cors` decorators
169
- - ✅ **CORS Middleware** - Full CORS support with preflight
170
+ - ✅ **CORS Middleware** - Full CORS support with preflight handling
171
+ - Django settings integration (`CORS_ALLOWED_ORIGINS`, `CORS_ALLOW_ALL_ORIGINS`)
172
+ - Route-level overrides with `@cors()` decorator
173
+ - Origin validation, credentials support, preflight caching
174
+ - Runs entirely in Rust (zero GIL overhead)
170
175
  - ✅ **Rate Limiting** - Token bucket algorithm (in Rust, no GIL)
171
176
  - ✅ **Compression** - Automatic gzip/brotli/zstd compression (client-negotiated)
172
177
  - ✅ **Skip Middleware** - `@skip_middleware("cors", "rate_limit", "compression")`
@@ -190,13 +195,6 @@ python manage.py runbolt --dev # for development with reload enabled
190
195
  - Constant-time comparison (timing attack prevention)
191
196
  - Fast validation in Rust
192
197
 
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
198
  - ✅ **Permission Guards** (all run in Rust):
201
199
 
202
200
  - `AllowAny()` - Public access
@@ -374,24 +372,45 @@ async def login(username: str, password: str):
374
372
 
375
373
  **📖 See [docs/SECURITY.md](docs/SECURITY.md) for complete authentication documentation.**
376
374
 
377
- ### Middleware
375
+ ### Middleware & CORS
378
376
 
379
377
  ```python
380
378
  from django_bolt import BoltAPI
381
379
  from django_bolt.middleware import cors, rate_limit, skip_middleware
382
380
 
383
- # Global middleware
381
+ # Option 1: Use Django settings (recommended for production)
382
+ # In settings.py:
383
+ # CORS_ALLOWED_ORIGINS = ["https://example.com", "https://app.example.com"]
384
+ # CORS_ALLOW_CREDENTIALS = True
385
+ # CORS_MAX_AGE = 3600
386
+
387
+ api = BoltAPI() # Automatically reads Django CORS settings
388
+
389
+ # Option 2: Global middleware config
384
390
  api = BoltAPI(
385
391
  middleware_config={
386
392
  "cors": {
387
393
  "origins": ["http://localhost:3000"],
388
394
  "methods": ["GET", "POST", "PUT", "DELETE"],
389
395
  "credentials": True,
396
+ "max_age": 3600,
390
397
  }
391
398
  }
392
399
  )
393
400
 
394
- # Per-route rate limiting (runs in Rust, no GIL)
401
+ # Option 3: Per-route CORS override (overrides global/Django settings)
402
+ @api.get("/public-api")
403
+ @cors(origins=["*"], credentials=False) # Allow all origins
404
+ async def public_endpoint():
405
+ return {"message": "Public endpoint with custom CORS"}
406
+
407
+ # CORS with credentials and specific origins
408
+ @api.post("/auth-endpoint")
409
+ @cors(origins=["https://app.example.com"], credentials=True, max_age=3600)
410
+ async def auth_endpoint():
411
+ return {"message": "Authenticated endpoint with CORS"}
412
+
413
+ # Rate limiting (runs in Rust, no GIL)
395
414
  @api.get("/limited")
396
415
  @rate_limit(rps=100, burst=200, key="ip") # 100 req/s with burst of 200
397
416
  async def limited_endpoint():
@@ -403,12 +422,6 @@ async def limited_endpoint():
403
422
  async def user_limited():
404
423
  return {"message": "Per-user rate limiting"}
405
424
 
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
425
  # Skip global middleware
413
426
  @api.get("/no-cors")
414
427
  @skip_middleware("cors", "rate_limit")
@@ -606,4 +619,5 @@ Django-Bolt is open source and available under the MIT License.
606
619
 
607
620
  ---
608
621
 
609
- For questions, issues, or feature requests, please visit our [GitHub repository](https://github.com/FarhanAliRaza/django-bolt).
622
+ For questions, issues, or feature requests, please visit our [GitHub repository](https://github.com/FarhanAliRaza/django-bolt).
623
+
@@ -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.2.dist-info/METADATA,sha256=Df6mtO4KEFHivc0NVXio1G_8k-f1NF0jCMazmVgEVw8,21978
2
+ django_bolt-0.2.2.dist-info/WHEEL,sha256=4EDp_7DiFfWl1yYv5M4wSosAn5L_xgD1dyrQxQxfCx8,95
3
+ django_bolt-0.2.2.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=2_iF6HF1hgI4YXmW-dvJM81gPnL3PwHViqXv9QedDMo,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.2.dist-info/RECORD,,