django-bolt 0.1.0__cp310-abi3-win_amd64.whl → 0.1.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.

Files changed (56) hide show
  1. django_bolt/__init__.py +2 -2
  2. django_bolt/_core.pyd +0 -0
  3. django_bolt/_json.py +169 -0
  4. django_bolt/admin/static_routes.py +15 -21
  5. django_bolt/api.py +181 -61
  6. django_bolt/auth/__init__.py +2 -2
  7. django_bolt/decorators.py +15 -3
  8. django_bolt/dependencies.py +30 -24
  9. django_bolt/error_handlers.py +2 -1
  10. django_bolt/openapi/plugins.py +3 -2
  11. django_bolt/openapi/schema_generator.py +65 -20
  12. django_bolt/pagination.py +2 -1
  13. django_bolt/responses.py +3 -2
  14. django_bolt/serialization.py +5 -4
  15. {django_bolt-0.1.0.dist-info → django_bolt-0.1.2.dist-info}/METADATA +181 -201
  16. {django_bolt-0.1.0.dist-info → django_bolt-0.1.2.dist-info}/RECORD +18 -55
  17. django_bolt/auth/README.md +0 -464
  18. django_bolt/auth/REVOCATION_EXAMPLE.md +0 -391
  19. django_bolt/tests/__init__.py +0 -0
  20. django_bolt/tests/admin_tests/__init__.py +0 -1
  21. django_bolt/tests/admin_tests/conftest.py +0 -6
  22. django_bolt/tests/admin_tests/test_admin_with_django.py +0 -278
  23. django_bolt/tests/admin_tests/urls.py +0 -9
  24. django_bolt/tests/cbv/__init__.py +0 -0
  25. django_bolt/tests/cbv/test_class_views.py +0 -570
  26. django_bolt/tests/cbv/test_class_views_django_orm.py +0 -703
  27. django_bolt/tests/cbv/test_class_views_features.py +0 -1173
  28. django_bolt/tests/cbv/test_class_views_with_client.py +0 -622
  29. django_bolt/tests/conftest.py +0 -165
  30. django_bolt/tests/test_action_decorator.py +0 -399
  31. django_bolt/tests/test_auth_secret_key.py +0 -83
  32. django_bolt/tests/test_decorator_syntax.py +0 -159
  33. django_bolt/tests/test_error_handling.py +0 -481
  34. django_bolt/tests/test_file_response.py +0 -192
  35. django_bolt/tests/test_global_cors.py +0 -172
  36. django_bolt/tests/test_guards_auth.py +0 -441
  37. django_bolt/tests/test_guards_integration.py +0 -303
  38. django_bolt/tests/test_health.py +0 -283
  39. django_bolt/tests/test_integration_validation.py +0 -400
  40. django_bolt/tests/test_json_validation.py +0 -536
  41. django_bolt/tests/test_jwt_auth.py +0 -327
  42. django_bolt/tests/test_jwt_token.py +0 -458
  43. django_bolt/tests/test_logging.py +0 -837
  44. django_bolt/tests/test_logging_merge.py +0 -419
  45. django_bolt/tests/test_middleware.py +0 -492
  46. django_bolt/tests/test_middleware_server.py +0 -230
  47. django_bolt/tests/test_model_viewset.py +0 -323
  48. django_bolt/tests/test_models.py +0 -24
  49. django_bolt/tests/test_pagination.py +0 -1258
  50. django_bolt/tests/test_parameter_validation.py +0 -178
  51. django_bolt/tests/test_syntax.py +0 -626
  52. django_bolt/tests/test_testing_utilities.py +0 -163
  53. django_bolt/tests/test_testing_utilities_simple.py +0 -123
  54. django_bolt/tests/test_viewset_unified.py +0 -346
  55. {django_bolt-0.1.0.dist-info → django_bolt-0.1.2.dist-info}/WHEEL +0 -0
  56. {django_bolt-0.1.0.dist-info → django_bolt-0.1.2.dist-info}/entry_points.txt +0 -0
@@ -1,492 +0,0 @@
1
- """
2
- Test middleware functionality in Django-Bolt
3
- """
4
- import asyncio
5
- import json
6
- import time
7
- import jwt
8
- import pytest
9
- from django_bolt import BoltAPI
10
- from django_bolt.middleware import (
11
- rate_limit, cors, skip_middleware,
12
- Middleware, MiddlewareGroup, CORSMiddleware, RateLimitMiddleware
13
- )
14
- from django_bolt.auth import JWTAuthentication, APIKeyAuthentication
15
- from django_bolt.auth import IsAuthenticated
16
- import msgspec
17
-
18
-
19
- # Test models
20
- class ItemModel(msgspec.Struct):
21
- id: int
22
- name: str
23
-
24
-
25
- # Custom test middleware
26
- class CustomTestMiddleware(Middleware):
27
- def __init__(self, name: str):
28
- self.name = name
29
- self.call_count = 0
30
-
31
- async def process_request(self, request, call_next):
32
- self.call_count += 1
33
- # Add marker to context
34
- if request.get("context"):
35
- request["context"][f"test_{self.name}"] = True
36
- response = await call_next(request)
37
- return response
38
-
39
-
40
- class TestMiddlewareDecorators:
41
- """Test middleware decorator functionality"""
42
-
43
- def test_rate_limit_decorator(self):
44
- """Test rate limit decorator attaches metadata"""
45
- api = BoltAPI()
46
-
47
- @api.get("/limited")
48
- @rate_limit(rps=50, burst=100, key="ip")
49
- async def limited_endpoint():
50
- return {"status": "ok"}
51
-
52
- # Check that middleware metadata was attached
53
- handler = api._handlers[0]
54
- assert hasattr(handler, '__bolt_middleware__')
55
- middleware = handler.__bolt_middleware__
56
- assert len(middleware) > 0
57
- assert middleware[0]['type'] == 'rate_limit'
58
- assert middleware[0]['rps'] == 50
59
- assert middleware[0]['burst'] == 100
60
- assert middleware[0]['key'] == 'ip'
61
-
62
- def test_cors_decorator(self):
63
- """Test CORS decorator attaches metadata"""
64
- api = BoltAPI()
65
-
66
- @api.get("/cors-test")
67
- @cors(origins=["http://localhost:3000"], credentials=True, max_age=7200)
68
- async def cors_endpoint():
69
- return {"status": "ok"}
70
-
71
- handler = api._handlers[0]
72
- assert hasattr(handler, '__bolt_middleware__')
73
- middleware = handler.__bolt_middleware__
74
- assert len(middleware) > 0
75
- assert middleware[0]['type'] == 'cors'
76
- assert middleware[0]['origins'] == ["http://localhost:3000"]
77
- assert middleware[0]['credentials'] == True
78
- assert middleware[0]['max_age'] == 7200
79
-
80
- def test_auth_via_guards(self):
81
- """Test authentication via guards parameter"""
82
- api = BoltAPI()
83
-
84
- @api.get(
85
- "/protected",
86
- auth=[JWTAuthentication(secret="test-secret", algorithms=["HS256", "HS384"])],
87
- guards=[IsAuthenticated()]
88
- )
89
- async def protected_endpoint():
90
- return {"status": "ok"}
91
-
92
- # Check that middleware metadata was compiled
93
- handler_id = 0
94
- assert handler_id in api._handler_middleware
95
- meta = api._handler_middleware[handler_id]
96
- assert 'auth_backends' in meta
97
- assert len(meta['auth_backends']) > 0
98
- assert meta['auth_backends'][0]['type'] == 'jwt'
99
- assert meta['auth_backends'][0]['secret'] == 'test-secret'
100
- assert meta['auth_backends'][0]['algorithms'] == ["HS256", "HS384"]
101
-
102
- def test_skip_middleware_decorator(self):
103
- """Test skip middleware decorator"""
104
- api = BoltAPI()
105
-
106
- @api.get("/no-middleware")
107
- @skip_middleware("cors", "rate_limit")
108
- async def no_middleware_endpoint():
109
- return {"status": "ok"}
110
-
111
- handler = api._handlers[0]
112
- assert hasattr(handler, '__bolt_skip_middleware__')
113
- skip = handler.__bolt_skip_middleware__
114
- assert "cors" in skip
115
- assert "rate_limit" in skip
116
-
117
- def test_multiple_middleware(self):
118
- """Test multiple middleware decorators on same route"""
119
- api = BoltAPI()
120
-
121
- @api.post(
122
- "/secure",
123
- auth=[APIKeyAuthentication(api_keys={"key1", "key2"})],
124
- guards=[IsAuthenticated()]
125
- )
126
- @rate_limit(rps=10)
127
- @cors(origins=["https://app.example.com"])
128
- async def secure_endpoint(data: dict):
129
- return {"received": data}
130
-
131
- handler = api._handlers[0]
132
- middleware = handler.__bolt_middleware__
133
- assert len(middleware) == 2 # rate_limit and cors
134
-
135
- # Check they're all there
136
- types = [m['type'] for m in middleware]
137
- assert 'rate_limit' in types
138
- assert 'cors' in types
139
-
140
- # Check auth is in metadata
141
- meta = api._handler_middleware[0]
142
- assert 'auth_backends' in meta
143
- assert len(meta['auth_backends']) > 0
144
-
145
-
146
- class TestMiddlewareGroups:
147
- """Test middleware grouping functionality"""
148
-
149
- def test_middleware_group_creation(self):
150
- """Test creating and combining middleware groups"""
151
- cors_mw = CORSMiddleware(origins=["http://localhost:3000"])
152
- rate_mw = RateLimitMiddleware(rps=100)
153
-
154
- group1 = MiddlewareGroup(cors_mw, rate_mw)
155
- assert len(group1.middleware) == 2
156
-
157
- # Test combining groups
158
- group2 = MiddlewareGroup(cors_mw)
159
- combined = group1 + group2
160
- assert len(combined.middleware) == 3
161
-
162
-
163
- class TestGlobalMiddleware:
164
- """Test global middleware configuration"""
165
-
166
- def test_global_middleware_config(self):
167
- """Test setting global middleware via BoltAPI constructor"""
168
- api = BoltAPI(
169
- middleware_config={
170
- 'cors': {
171
- 'origins': ['*'],
172
- 'credentials': False
173
- },
174
- 'rate_limit': {
175
- 'rps': 1000,
176
- 'burst': 2000,
177
- 'key': 'ip'
178
- }
179
- }
180
- )
181
-
182
- assert 'cors' in api.middleware_config
183
- assert 'rate_limit' in api.middleware_config
184
- assert api.middleware_config['cors']['origins'] == ['*']
185
- assert api.middleware_config['rate_limit']['rps'] == 1000
186
-
187
- def test_global_middleware_instances(self):
188
- """Test setting global middleware instances"""
189
- cors_mw = CORSMiddleware(origins=["http://localhost:3000"])
190
- rate_mw = RateLimitMiddleware(rps=500)
191
-
192
- api = BoltAPI(middleware=[cors_mw, rate_mw])
193
-
194
- assert len(api.middleware) == 2
195
- assert api.middleware[0] == cors_mw
196
- assert api.middleware[1] == rate_mw
197
-
198
-
199
- class TestMiddlewareMetadata:
200
- """Test middleware metadata compilation"""
201
-
202
- def test_middleware_metadata_compilation(self):
203
- """Test that middleware metadata is compiled correctly"""
204
- api = BoltAPI(
205
- middleware_config={
206
- 'cors': {'origins': ['*']}
207
- }
208
- )
209
-
210
- @api.get("/test")
211
- @rate_limit(rps=100)
212
- async def test_endpoint():
213
- return {"status": "ok"}
214
-
215
- # Check handler middleware metadata
216
- assert len(api._handler_middleware) > 0
217
- handler_id = 0
218
- meta = api._handler_middleware[handler_id]
219
-
220
- assert 'middleware' in meta
221
- assert len(meta['middleware']) == 2 # Global CORS + route rate_limit
222
-
223
- # Check types
224
- types = [m['type'] for m in meta['middleware']]
225
- assert 'cors' in types
226
- assert 'rate_limit' in types
227
-
228
- def test_skip_global_middleware(self):
229
- """Test skipping global middleware on specific routes"""
230
- api = BoltAPI(
231
- middleware_config={
232
- 'cors': {'origins': ['*']},
233
- 'rate_limit': {'rps': 100}
234
- }
235
- )
236
-
237
- @api.get("/no-cors")
238
- @skip_middleware("cors")
239
- async def no_cors_endpoint():
240
- return {"status": "ok"}
241
-
242
- handler_id = 0
243
- meta = api._handler_middleware[handler_id]
244
-
245
- # Should only have rate_limit, not cors
246
- assert len(meta['middleware']) == 1
247
- assert meta['middleware'][0]['type'] == 'rate_limit'
248
- assert 'cors' in meta['skip']
249
-
250
-
251
- class TestMiddlewareExecution:
252
- """Test middleware execution in the pipeline"""
253
-
254
- @pytest.mark.asyncio
255
- async def test_request_dispatch_with_middleware(self):
256
- """Test that dispatch works with middleware metadata"""
257
- api = BoltAPI()
258
-
259
- @api.get("/test")
260
- @cors(origins=["*"])
261
- async def test_endpoint(request: dict):
262
- # Access context
263
- context = request.get("context")
264
- return {
265
- "has_context": context is not None,
266
- "context_type": type(context).__name__ if context else None
267
- }
268
-
269
- # Create test request
270
- test_request = {
271
- "method": "GET",
272
- "path": "/test",
273
- "body": b"",
274
- "params": {},
275
- "query": {},
276
- "headers": {},
277
- "cookies": {},
278
- "context": None # Will be populated by middleware
279
- }
280
-
281
- # Get handler
282
- handler = api._handlers[0]
283
-
284
- # Dispatch
285
- result = await api._dispatch(handler, test_request)
286
- status, headers, body = result
287
-
288
- assert status == 200
289
- data = json.loads(body)
290
- assert "has_context" in data
291
-
292
- @pytest.mark.asyncio
293
- async def test_custom_middleware_execution(self):
294
- """Test custom middleware execution"""
295
- test_mw = CustomTestMiddleware("test1")
296
- api = BoltAPI(middleware=[test_mw])
297
-
298
- @api.get("/test")
299
- async def test_endpoint():
300
- return {"status": "ok"}
301
-
302
- # Note: This tests the Python side only
303
- # Rust middleware execution happens in the server
304
- assert test_mw.call_count == 0 # Not executed yet
305
-
306
- @pytest.mark.asyncio
307
- async def test_response_model_with_middleware(self):
308
- """Test response model validation with middleware"""
309
- api = BoltAPI()
310
-
311
- @api.post("/items", response_model=ItemModel)
312
- @cors(origins=["*"])
313
- async def create_item(item: ItemModel) -> ItemModel:
314
- return item
315
-
316
- test_request = {
317
- "method": "POST",
318
- "path": "/items",
319
- "body": msgspec.json.encode({"id": 1, "name": "Test"}),
320
- "params": {},
321
- "query": {},
322
- "headers": {"content-type": "application/json"},
323
- "cookies": {},
324
- "context": None
325
- }
326
-
327
- handler = api._handlers[0]
328
- result = await api._dispatch(handler, test_request)
329
- status, headers, body = result
330
-
331
- assert status == 200
332
- data = msgspec.json.decode(body)
333
- assert data["id"] == 1
334
- assert data["name"] == "Test"
335
-
336
-
337
- class TestAuthTokenGeneration:
338
- """Test JWT token generation for auth testing"""
339
-
340
- def test_generate_valid_jwt(self):
341
- """Generate a valid JWT token for testing"""
342
- secret = "test-secret"
343
- payload = {
344
- "sub": "user123",
345
- "exp": int(time.time()) + 3600, # 1 hour from now
346
- "iat": int(time.time()),
347
- "custom_claim": "test_value"
348
- }
349
-
350
- token = jwt.encode(payload, secret, algorithm="HS256")
351
- assert token is not None
352
-
353
- # Verify we can decode it
354
- decoded = jwt.decode(token, secret, algorithms=["HS256"])
355
- assert decoded["sub"] == "user123"
356
- assert decoded["custom_claim"] == "test_value"
357
-
358
- def test_generate_expired_jwt(self):
359
- """Generate an expired JWT token for testing"""
360
- secret = "test-secret"
361
- payload = {
362
- "sub": "user123",
363
- "exp": int(time.time()) - 3600, # 1 hour ago
364
- "iat": int(time.time()) - 7200
365
- }
366
-
367
- token = jwt.encode(payload, secret, algorithm="HS256")
368
-
369
- # Should raise error when verifying
370
- with pytest.raises(jwt.ExpiredSignatureError):
371
- jwt.decode(token, secret, algorithms=["HS256"])
372
-
373
- def test_generate_invalid_signature_jwt(self):
374
- """Generate a JWT with wrong signature"""
375
- secret = "test-secret"
376
- wrong_secret = "wrong-secret"
377
- payload = {
378
- "sub": "user123",
379
- "exp": int(time.time()) + 3600
380
- }
381
-
382
- token = jwt.encode(payload, wrong_secret, algorithm="HS256")
383
-
384
- # Should raise error when verifying with correct secret
385
- with pytest.raises(jwt.InvalidSignatureError):
386
- jwt.decode(token, secret, algorithms=["HS256"])
387
-
388
-
389
- class TestMiddlewareIntegration:
390
- """Integration tests for middleware with actual server"""
391
-
392
- def test_middleware_registration(self):
393
- """Test that middleware gets registered with Rust"""
394
- api = BoltAPI()
395
-
396
- @api.get("/middleware-test")
397
- @rate_limit(rps=100)
398
- @cors(origins=["http://localhost:3000"])
399
- async def test_endpoint():
400
- return {"status": "ok"}
401
-
402
- # Check routes are registered
403
- assert len(api._routes) == 1
404
- method, path, handler_id, handler = api._routes[0]
405
- assert method == "GET"
406
- assert path == "/middleware-test"
407
-
408
- # Check middleware metadata
409
- assert handler_id in api._handler_middleware
410
- meta = api._handler_middleware[handler_id]
411
- assert len(meta['middleware']) == 2
412
-
413
- types = [m['type'] for m in meta['middleware']]
414
- assert 'rate_limit' in types
415
- assert 'cors' in types
416
-
417
- def test_preflight_route(self):
418
- """Test OPTIONS preflight handling"""
419
- api = BoltAPI()
420
-
421
- @api.get("/api/data")
422
- @cors(
423
- origins=["http://localhost:3000", "https://app.example.com"],
424
- methods=["GET", "POST", "PUT"],
425
- headers=["Content-Type", "Authorization", "X-Custom"],
426
- credentials=True,
427
- max_age=7200
428
- )
429
- async def get_data():
430
- return {"data": [1, 2, 3]}
431
-
432
- # The preflight will be handled by Rust middleware
433
- # Here we just verify the metadata is correct
434
- meta = api._handler_middleware[0]
435
- cors_config = next(m for m in meta['middleware'] if m['type'] == 'cors')
436
-
437
- assert cors_config['origins'] == ["http://localhost:3000", "https://app.example.com"]
438
- assert cors_config['methods'] == ["GET", "POST", "PUT"]
439
- assert cors_config['headers'] == ["Content-Type", "Authorization", "X-Custom"]
440
- assert cors_config['credentials'] == True
441
- assert cors_config['max_age'] == 7200
442
-
443
-
444
- if __name__ == "__main__":
445
- # Run basic tests
446
- print("Testing middleware decorators...")
447
- test_decorators = TestMiddlewareDecorators()
448
- test_decorators.test_rate_limit_decorator()
449
- test_decorators.test_cors_decorator()
450
- test_decorators.test_auth_via_guards()
451
- test_decorators.test_skip_middleware_decorator()
452
- test_decorators.test_multiple_middleware()
453
- print("✓ Decorator tests passed")
454
-
455
- print("\nTesting middleware groups...")
456
- test_groups = TestMiddlewareGroups()
457
- test_groups.test_middleware_group_creation()
458
- print("✓ Group tests passed")
459
-
460
- print("\nTesting global middleware...")
461
- test_global = TestGlobalMiddleware()
462
- test_global.test_global_middleware_config()
463
- test_global.test_global_middleware_instances()
464
- print("✓ Global middleware tests passed")
465
-
466
- print("\nTesting middleware metadata...")
467
- test_meta = TestMiddlewareMetadata()
468
- test_meta.test_middleware_metadata_compilation()
469
- test_meta.test_skip_global_middleware()
470
- print("✓ Metadata tests passed")
471
-
472
- print("\nTesting JWT generation...")
473
- test_auth = TestAuthTokenGeneration()
474
- test_auth.test_generate_valid_jwt()
475
- test_auth.test_generate_expired_jwt()
476
- test_auth.test_generate_invalid_signature_jwt()
477
- print("✓ JWT tests passed")
478
-
479
- print("\nTesting middleware integration...")
480
- test_integration = TestMiddlewareIntegration()
481
- test_integration.test_middleware_registration()
482
- test_integration.test_preflight_route()
483
- print("✓ Integration tests passed")
484
-
485
- print("\nRunning async tests...")
486
- test_exec = TestMiddlewareExecution()
487
- asyncio.run(test_exec.test_request_dispatch_with_middleware())
488
- asyncio.run(test_exec.test_custom_middleware_execution())
489
- asyncio.run(test_exec.test_response_model_with_middleware())
490
- print("✓ Async execution tests passed")
491
-
492
- print("\n✅ All middleware tests passed!")