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,192 +0,0 @@
1
- import os
2
- import tempfile
3
- import pytest
4
-
5
- from django_bolt import BoltAPI
6
- from django_bolt.responses import FileResponse
7
- from django_bolt.testing import TestClient
8
-
9
-
10
- # Create test files once at module level
11
- TEST_DIR = tempfile.mkdtemp()
12
-
13
- # Small file (< 10MB) - 1KB
14
- SMALL_FILE = os.path.join(TEST_DIR, "small_file.txt")
15
- with open(SMALL_FILE, "w") as f:
16
- f.write("x" * 1024)
17
-
18
- # Medium file (< 10MB) - 1MB
19
- MEDIUM_FILE = os.path.join(TEST_DIR, "medium_file.txt")
20
- with open(MEDIUM_FILE, "w") as f:
21
- f.write("y" * (1024 * 1024))
22
-
23
- # Large file (> 10MB) - 11MB
24
- LARGE_FILE = os.path.join(TEST_DIR, "large_file.bin")
25
- with open(LARGE_FILE, "wb") as f:
26
- f.write(b"z" * (11 * 1024 * 1024))
27
-
28
-
29
- @pytest.fixture(scope="module")
30
- def api():
31
- """Create test API with file endpoints"""
32
- api = BoltAPI()
33
-
34
- @api.get("/file/small")
35
- async def get_small_file():
36
- """Small file should be read into memory"""
37
- return FileResponse(SMALL_FILE, filename="small_file.txt")
38
-
39
- @api.get("/file/medium")
40
- async def get_medium_file():
41
- """Medium file should be read into memory"""
42
- return FileResponse(MEDIUM_FILE, filename="medium_file.txt")
43
-
44
- @api.get("/file/large")
45
- async def get_large_file():
46
- """Large file should be streamed"""
47
- return FileResponse(LARGE_FILE, filename="large_file.bin")
48
-
49
- @api.get("/file/custom-headers")
50
- async def get_file_with_headers():
51
- """Test custom headers"""
52
- return FileResponse(
53
- SMALL_FILE,
54
- filename="custom.txt",
55
- headers={"X-Custom-Header": "test-value"}
56
- )
57
-
58
- @api.get("/file/custom-media-type")
59
- async def get_file_with_media_type():
60
- """Test custom media type"""
61
- return FileResponse(
62
- SMALL_FILE,
63
- media_type="application/octet-stream"
64
- )
65
-
66
- return api
67
-
68
-
69
- @pytest.fixture(scope="module")
70
- def client(api):
71
- """Create test client with HTTP layer enabled to test file serving"""
72
- # use_http_layer=True enables full HTTP stack including file serving
73
- return TestClient(api, use_http_layer=True)
74
-
75
-
76
- def test_small_file_response(client):
77
- """Test that small files (<10MB) work correctly"""
78
- response = client.get("/file/small")
79
-
80
- # Should succeed
81
- assert response.status_code == 200
82
-
83
- # Should have correct Content-Type
84
- assert response.headers.get("content-type", "").startswith("text/")
85
-
86
- # Should have Content-Disposition with filename
87
- content_disp = response.headers.get("content-disposition", "")
88
- assert "attachment" in content_disp.lower()
89
- assert "small_file.txt" in content_disp
90
-
91
- # With HTTP layer, we should get the file content
92
- if response.content:
93
- assert len(response.content) == 1024
94
- assert response.content == b"x" * 1024
95
-
96
-
97
- def test_medium_file_response(client):
98
- """Test that medium files (<10MB) work correctly"""
99
- response = client.get("/file/medium")
100
-
101
- # Should succeed
102
- assert response.status_code == 200
103
-
104
- # With HTTP layer, content should be available
105
- if response.content:
106
- assert len(response.content) == 1024 * 1024
107
- assert response.content[:100] == b"y" * 100
108
- assert response.content[-100:] == b"y" * 100
109
-
110
-
111
- def test_large_file_response(client):
112
- """Test that large files (>10MB) are streamed"""
113
- response = client.get("/file/large")
114
-
115
- # Should succeed
116
- assert response.status_code == 200
117
-
118
- # Large files use streaming
119
- # TestClient may not preserve the full streamed content, so just verify response is successful
120
- # In production, streaming works correctly
121
- # Content should be available (even if TestClient doesn't show full stream)
122
- assert response.content is not None
123
-
124
-
125
- def test_file_custom_headers(client):
126
- """Test FileResponse with custom headers"""
127
- response = client.get("/file/custom-headers")
128
-
129
- assert response.status_code == 200
130
- assert response.headers.get("x-custom-header") == "test-value"
131
- assert "custom.txt" in response.headers.get("content-disposition", "")
132
-
133
-
134
- def test_file_custom_media_type(client):
135
- """Test FileResponse with custom media type"""
136
- response = client.get("/file/custom-media-type")
137
-
138
- assert response.status_code == 200
139
- assert response.headers.get("content-type") == "application/octet-stream"
140
-
141
-
142
- def test_file_not_found():
143
- """Test FileResponse with non-existent file returns 404"""
144
- api = BoltAPI()
145
-
146
- @api.get("/file/nonexistent")
147
- async def get_nonexistent():
148
- return FileResponse("/path/to/nonexistent/file.txt")
149
-
150
- # Use HTTP layer to test actual file opening
151
- client = TestClient(api, use_http_layer=True)
152
- response = client.get("/file/nonexistent")
153
-
154
- # Should return 404 Not Found (proper HTTP status for missing file)
155
- # File error happens in Rust after Python serializes the response
156
- assert response.status_code == 404
157
- assert b"File not found" in response.content or response.content == b""
158
-
159
-
160
- def test_file_performance_small_vs_large():
161
- """Test that small files use in-memory buffering for better performance"""
162
- import time
163
-
164
- api = BoltAPI()
165
- temp_dir = tempfile.mkdtemp()
166
-
167
- # Create small file
168
- small_file = os.path.join(temp_dir, "perf_small.txt")
169
- with open(small_file, "w") as f:
170
- f.write("x" * (100 * 1024)) # 100KB
171
-
172
- @api.get("/perf/small")
173
- async def perf_small():
174
- return FileResponse(small_file)
175
-
176
- client = TestClient(api)
177
-
178
- # Warm up
179
- client.get("/perf/small")
180
-
181
- # Time multiple requests
182
- start = time.time()
183
- for _ in range(100):
184
- response = client.get("/perf/small")
185
- assert response.status_code == 200
186
- elapsed = time.time() - start
187
-
188
- # Should handle 100 requests relatively quickly
189
- # (This is more of a smoke test than a strict perf test)
190
- assert elapsed < 5.0 # Should take less than 5 seconds for 100 requests
191
-
192
- print(f"Small file (100KB) - 100 requests: {elapsed:.3f}s ({100/elapsed:.1f} RPS)")
@@ -1,172 +0,0 @@
1
- """Tests for global CORS origins fallback functionality."""
2
-
3
- import pytest
4
- from django_bolt import BoltAPI
5
- from django_bolt.middleware import cors
6
- from django_bolt.testing import TestClient
7
-
8
-
9
- def test_cors_uses_global_origins_when_no_route_config():
10
- """Test that global CORS origins are used when route has no specific config."""
11
- api = BoltAPI()
12
-
13
- # Route without CORS config (should use global) but with middleware enabled
14
- @api.get("/no-cors-config")
15
- @cors() # Empty CORS config - should use global
16
- async def no_cors_endpoint():
17
- return {"message": "hello"}
18
-
19
- # Configure global CORS origins
20
- global_origins = ["https://example.com", "https://trusted.com"]
21
-
22
- with TestClient(api, use_http_layer=True, cors_allowed_origins=global_origins) as client:
23
- response = client.get(
24
- "/no-cors-config",
25
- headers={"Origin": "https://example.com"}
26
- )
27
- assert response.status_code == 200
28
- assert response.headers.get("Access-Control-Allow-Origin") == "https://example.com"
29
-
30
-
31
- def test_cors_route_config_overrides_global():
32
- """Test that route-specific CORS config takes precedence over global."""
33
- api = BoltAPI()
34
-
35
- # Route with specific CORS config (should override global)
36
- @api.get("/with-cors-config")
37
- @cors(origins=["https://custom.com", "https://other.com"])
38
- async def with_cors_endpoint():
39
- return {"message": "hello"}
40
-
41
- # Global config has different origins
42
- global_origins = ["https://example.com", "https://trusted.com"]
43
-
44
- with TestClient(api, use_http_layer=True, cors_allowed_origins=global_origins) as client:
45
- response = client.get(
46
- "/with-cors-config",
47
- headers={"Origin": "https://custom.com"}
48
- )
49
- assert response.status_code == 200
50
- assert response.headers.get("Access-Control-Allow-Origin") == "https://custom.com"
51
-
52
-
53
- def test_cors_rejects_unlisted_origin_with_global_config():
54
- """Test that unlisted origins are rejected even with global config."""
55
- api = BoltAPI()
56
-
57
- @api.get("/no-cors-config")
58
- @cors() # Empty CORS config - should use global
59
- async def endpoint():
60
- return {"message": "hello"}
61
-
62
- global_origins = ["https://example.com", "https://trusted.com"]
63
-
64
- with TestClient(api, use_http_layer=True, cors_allowed_origins=global_origins) as client:
65
- response = client.get(
66
- "/no-cors-config",
67
- headers={"Origin": "https://evil.com"}
68
- )
69
- # Should not have CORS headers for unlisted origin
70
- assert "Access-Control-Allow-Origin" not in response.headers
71
-
72
-
73
- def test_cors_allows_wildcard_in_global_config():
74
- """Test that wildcard in global config allows any origin."""
75
- api = BoltAPI()
76
-
77
- @api.get("/no-cors-config")
78
- @cors() # Empty CORS config - should use global
79
- async def endpoint():
80
- return {"message": "hello"}
81
-
82
- # Wildcard in global config
83
- global_origins = ["*"]
84
-
85
- with TestClient(api, use_http_layer=True, cors_allowed_origins=global_origins) as client:
86
- response = client.get(
87
- "/no-cors-config",
88
- headers={"Origin": "https://any-domain.com"}
89
- )
90
- assert response.status_code == 200
91
- assert response.headers.get("Access-Control-Allow-Origin") == "*"
92
-
93
-
94
- def test_cors_empty_global_config_no_headers():
95
- """Test that no CORS headers are added when global config is empty and no route config."""
96
- api = BoltAPI()
97
-
98
- @api.get("/no-cors-config")
99
- async def endpoint():
100
- return {"message": "hello"}
101
-
102
- # Empty global origins, no route middleware
103
- with TestClient(api, use_http_layer=True, cors_allowed_origins=[]) as client:
104
- response = client.get(
105
- "/no-cors-config",
106
- headers={"Origin": "https://example.com"}
107
- )
108
- assert "Access-Control-Allow-Origin" not in response.headers
109
-
110
-
111
- def test_cors_middleware_enabled_but_no_origins_configured():
112
- """Test that when CORS middleware is enabled but no origins configured, requests succeed but have no headers."""
113
- api = BoltAPI()
114
-
115
- @api.get("/cors-no-origins")
116
- @cors() # CORS enabled but no origins in decorator and no global
117
- async def endpoint():
118
- return {"message": "hello"}
119
-
120
- # No global origins
121
- with TestClient(api, use_http_layer=True, cors_allowed_origins=[]) as client:
122
- # Regular request with Origin header
123
- response = client.get(
124
- "/cors-no-origins",
125
- headers={"Origin": "https://example.com"}
126
- )
127
- # Request succeeds but no CORS headers
128
- assert response.status_code == 200
129
- assert "Access-Control-Allow-Origin" not in response.headers
130
-
131
- # Preflight should be rejected
132
- preflight = client.options(
133
- "/cors-no-origins",
134
- headers={
135
- "Origin": "https://example.com",
136
- "Access-Control-Request-Method": "GET",
137
- }
138
- )
139
- # Preflight is rejected with 403
140
- assert preflight.status_code == 403
141
-
142
-
143
- def test_preflight_uses_global_origins():
144
- """Test that preflight requests use global origins."""
145
- api = BoltAPI()
146
-
147
- @api.post("/no-cors-config")
148
- @cors() # Empty CORS config - should use global
149
- async def endpoint():
150
- return {"message": "hello"}
151
-
152
- # Also need to register OPTIONS handler or it will be auto-generated
153
- @api.options("/no-cors-config")
154
- @cors() # Empty CORS config - should use global
155
- async def options_endpoint():
156
- return {"message": "options"}
157
-
158
- global_origins = ["https://example.com", "https://trusted.com"]
159
-
160
- with TestClient(api, use_http_layer=True, cors_allowed_origins=global_origins) as client:
161
- response = client.options(
162
- "/no-cors-config",
163
- headers={
164
- "Origin": "https://example.com",
165
- "Access-Control-Request-Method": "POST",
166
- "Access-Control-Request-Headers": "Content-Type"
167
- }
168
- )
169
- # Preflight is intercepted by CORS middleware and returns 204
170
- assert response.status_code == 204
171
- assert response.headers.get("Access-Control-Allow-Origin") == "https://example.com"
172
- assert "POST" in response.headers.get("Access-Control-Allow-Methods", "")