django-bolt 0.1.0__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 (128) hide show
  1. django_bolt/__init__.py +147 -0
  2. django_bolt/_core.pyd +0 -0
  3. django_bolt/admin/__init__.py +25 -0
  4. django_bolt/admin/admin_detection.py +179 -0
  5. django_bolt/admin/asgi_bridge.py +267 -0
  6. django_bolt/admin/routes.py +91 -0
  7. django_bolt/admin/static.py +155 -0
  8. django_bolt/admin/static_routes.py +111 -0
  9. django_bolt/api.py +1011 -0
  10. django_bolt/apps.py +7 -0
  11. django_bolt/async_collector.py +228 -0
  12. django_bolt/auth/README.md +464 -0
  13. django_bolt/auth/REVOCATION_EXAMPLE.md +391 -0
  14. django_bolt/auth/__init__.py +84 -0
  15. django_bolt/auth/backends.py +236 -0
  16. django_bolt/auth/guards.py +224 -0
  17. django_bolt/auth/jwt_utils.py +212 -0
  18. django_bolt/auth/revocation.py +286 -0
  19. django_bolt/auth/token.py +335 -0
  20. django_bolt/binding.py +363 -0
  21. django_bolt/bootstrap.py +77 -0
  22. django_bolt/cli.py +133 -0
  23. django_bolt/compression.py +104 -0
  24. django_bolt/decorators.py +159 -0
  25. django_bolt/dependencies.py +128 -0
  26. django_bolt/error_handlers.py +305 -0
  27. django_bolt/exceptions.py +294 -0
  28. django_bolt/health.py +129 -0
  29. django_bolt/logging/__init__.py +6 -0
  30. django_bolt/logging/config.py +357 -0
  31. django_bolt/logging/middleware.py +296 -0
  32. django_bolt/management/__init__.py +1 -0
  33. django_bolt/management/commands/__init__.py +0 -0
  34. django_bolt/management/commands/runbolt.py +427 -0
  35. django_bolt/middleware/__init__.py +32 -0
  36. django_bolt/middleware/compiler.py +131 -0
  37. django_bolt/middleware/middleware.py +247 -0
  38. django_bolt/openapi/__init__.py +23 -0
  39. django_bolt/openapi/config.py +196 -0
  40. django_bolt/openapi/plugins.py +439 -0
  41. django_bolt/openapi/routes.py +152 -0
  42. django_bolt/openapi/schema_generator.py +581 -0
  43. django_bolt/openapi/spec/__init__.py +68 -0
  44. django_bolt/openapi/spec/base.py +74 -0
  45. django_bolt/openapi/spec/callback.py +24 -0
  46. django_bolt/openapi/spec/components.py +72 -0
  47. django_bolt/openapi/spec/contact.py +21 -0
  48. django_bolt/openapi/spec/discriminator.py +25 -0
  49. django_bolt/openapi/spec/encoding.py +67 -0
  50. django_bolt/openapi/spec/enums.py +41 -0
  51. django_bolt/openapi/spec/example.py +36 -0
  52. django_bolt/openapi/spec/external_documentation.py +21 -0
  53. django_bolt/openapi/spec/header.py +132 -0
  54. django_bolt/openapi/spec/info.py +50 -0
  55. django_bolt/openapi/spec/license.py +28 -0
  56. django_bolt/openapi/spec/link.py +66 -0
  57. django_bolt/openapi/spec/media_type.py +51 -0
  58. django_bolt/openapi/spec/oauth_flow.py +36 -0
  59. django_bolt/openapi/spec/oauth_flows.py +28 -0
  60. django_bolt/openapi/spec/open_api.py +87 -0
  61. django_bolt/openapi/spec/operation.py +105 -0
  62. django_bolt/openapi/spec/parameter.py +147 -0
  63. django_bolt/openapi/spec/path_item.py +78 -0
  64. django_bolt/openapi/spec/paths.py +27 -0
  65. django_bolt/openapi/spec/reference.py +38 -0
  66. django_bolt/openapi/spec/request_body.py +38 -0
  67. django_bolt/openapi/spec/response.py +48 -0
  68. django_bolt/openapi/spec/responses.py +44 -0
  69. django_bolt/openapi/spec/schema.py +678 -0
  70. django_bolt/openapi/spec/security_requirement.py +28 -0
  71. django_bolt/openapi/spec/security_scheme.py +69 -0
  72. django_bolt/openapi/spec/server.py +34 -0
  73. django_bolt/openapi/spec/server_variable.py +32 -0
  74. django_bolt/openapi/spec/tag.py +32 -0
  75. django_bolt/openapi/spec/xml.py +44 -0
  76. django_bolt/pagination.py +669 -0
  77. django_bolt/param_functions.py +49 -0
  78. django_bolt/params.py +337 -0
  79. django_bolt/request_parsing.py +128 -0
  80. django_bolt/responses.py +214 -0
  81. django_bolt/router.py +48 -0
  82. django_bolt/serialization.py +193 -0
  83. django_bolt/status_codes.py +321 -0
  84. django_bolt/testing/__init__.py +10 -0
  85. django_bolt/testing/client.py +274 -0
  86. django_bolt/testing/helpers.py +93 -0
  87. django_bolt/tests/__init__.py +0 -0
  88. django_bolt/tests/admin_tests/__init__.py +1 -0
  89. django_bolt/tests/admin_tests/conftest.py +6 -0
  90. django_bolt/tests/admin_tests/test_admin_with_django.py +278 -0
  91. django_bolt/tests/admin_tests/urls.py +9 -0
  92. django_bolt/tests/cbv/__init__.py +0 -0
  93. django_bolt/tests/cbv/test_class_views.py +570 -0
  94. django_bolt/tests/cbv/test_class_views_django_orm.py +703 -0
  95. django_bolt/tests/cbv/test_class_views_features.py +1173 -0
  96. django_bolt/tests/cbv/test_class_views_with_client.py +622 -0
  97. django_bolt/tests/conftest.py +165 -0
  98. django_bolt/tests/test_action_decorator.py +399 -0
  99. django_bolt/tests/test_auth_secret_key.py +83 -0
  100. django_bolt/tests/test_decorator_syntax.py +159 -0
  101. django_bolt/tests/test_error_handling.py +481 -0
  102. django_bolt/tests/test_file_response.py +192 -0
  103. django_bolt/tests/test_global_cors.py +172 -0
  104. django_bolt/tests/test_guards_auth.py +441 -0
  105. django_bolt/tests/test_guards_integration.py +303 -0
  106. django_bolt/tests/test_health.py +283 -0
  107. django_bolt/tests/test_integration_validation.py +400 -0
  108. django_bolt/tests/test_json_validation.py +536 -0
  109. django_bolt/tests/test_jwt_auth.py +327 -0
  110. django_bolt/tests/test_jwt_token.py +458 -0
  111. django_bolt/tests/test_logging.py +837 -0
  112. django_bolt/tests/test_logging_merge.py +419 -0
  113. django_bolt/tests/test_middleware.py +492 -0
  114. django_bolt/tests/test_middleware_server.py +230 -0
  115. django_bolt/tests/test_model_viewset.py +323 -0
  116. django_bolt/tests/test_models.py +24 -0
  117. django_bolt/tests/test_pagination.py +1258 -0
  118. django_bolt/tests/test_parameter_validation.py +178 -0
  119. django_bolt/tests/test_syntax.py +626 -0
  120. django_bolt/tests/test_testing_utilities.py +163 -0
  121. django_bolt/tests/test_testing_utilities_simple.py +123 -0
  122. django_bolt/tests/test_viewset_unified.py +346 -0
  123. django_bolt/typing.py +273 -0
  124. django_bolt/views.py +1110 -0
  125. django_bolt-0.1.0.dist-info/METADATA +629 -0
  126. django_bolt-0.1.0.dist-info/RECORD +128 -0
  127. django_bolt-0.1.0.dist-info/WHEEL +4 -0
  128. django_bolt-0.1.0.dist-info/entry_points.txt +2 -0
@@ -0,0 +1,91 @@
1
+ """
2
+ Django admin route registration for BoltAPI.
3
+
4
+ This module handles the registration of Django admin routes via ASGI bridge,
5
+ keeping the BoltAPI class lean and focused.
6
+ """
7
+ from typing import TYPE_CHECKING
8
+
9
+ if TYPE_CHECKING:
10
+ from django_bolt.api import BoltAPI
11
+
12
+
13
+ class AdminRouteRegistrar:
14
+ """Handles registration of Django admin routes via ASGI bridge."""
15
+
16
+ def __init__(self, api: 'BoltAPI'):
17
+ """Initialize the registrar with a BoltAPI instance.
18
+
19
+ Args:
20
+ api: The BoltAPI instance to register routes on
21
+ """
22
+ self.api = api
23
+
24
+ def register_routes(self, host: str = "localhost", port: int = 8000) -> None:
25
+ """Register Django admin routes via ASGI bridge.
26
+
27
+ This method auto-registers routes for Django admin if it's installed
28
+ and enabled. The routes use an ASGI bridge to handle Django's middleware
29
+ stack (sessions, CSRF, auth, etc.).
30
+
31
+ Args:
32
+ host: Server hostname for ASGI scope
33
+ port: Server port for ASGI scope
34
+ """
35
+ if self.api._admin_routes_registered:
36
+ return
37
+
38
+ # Check if admin should be enabled
39
+ from django_bolt.admin.admin_detection import should_enable_admin, get_admin_route_patterns
40
+
41
+ if not should_enable_admin():
42
+ return
43
+
44
+ # Get admin route patterns
45
+ route_patterns = get_admin_route_patterns()
46
+ if not route_patterns:
47
+ return
48
+
49
+ # Lazy-load ASGI handler
50
+ if self.api._asgi_handler is None:
51
+ from django_bolt.admin.asgi_bridge import ASGIFallbackHandler
52
+ self.api._asgi_handler = ASGIFallbackHandler(host, port)
53
+
54
+ # Register admin routes for each method
55
+ for path_pattern, methods in route_patterns:
56
+ for method in methods:
57
+ self._register_admin_route(method, path_pattern)
58
+
59
+ self.api._admin_routes_registered = True
60
+
61
+ def _register_admin_route(self, method: str, path_pattern: str) -> None:
62
+ """Register a single admin route.
63
+
64
+ Args:
65
+ method: HTTP method (GET, POST, etc.)
66
+ path_pattern: URL path pattern
67
+ """
68
+ # Create handler that delegates to ASGI bridge
69
+ # NOTE: We need to create a new function for each route to avoid closure issues
70
+ def make_admin_handler(asgi_handler):
71
+ async def admin_handler(request):
72
+ return await asgi_handler.handle_request(request)
73
+ return admin_handler
74
+
75
+ admin_handler = make_admin_handler(self.api._asgi_handler)
76
+
77
+ # Register the route using internal route registration
78
+ # This bypasses the decorator to avoid async enforcement issues
79
+ handler_id = self.api._next_handler_id
80
+ self.api._next_handler_id += 1
81
+
82
+ self.api._routes.append((method, path_pattern, handler_id, admin_handler))
83
+ self.api._handlers[handler_id] = admin_handler
84
+
85
+ # Create minimal metadata for admin handlers
86
+ meta = {
87
+ "mode": "request_only",
88
+ "sig": None,
89
+ "fields": [],
90
+ }
91
+ self.api._handler_meta[admin_handler] = meta
@@ -0,0 +1,155 @@
1
+ """
2
+ Static file serving utilities for Django-Bolt.
3
+
4
+ Provides static file serving for Django admin and other static assets.
5
+ """
6
+
7
+ import os
8
+ from pathlib import Path
9
+ from typing import Optional, Tuple, List, Dict, Any
10
+
11
+
12
+ def find_static_file(path: str) -> Optional[str]:
13
+ """
14
+ Find a static file using Django's static file finders.
15
+
16
+ Args:
17
+ path: Relative path to static file (e.g., 'admin/css/base.css')
18
+
19
+ Returns:
20
+ Absolute path to file if found, None otherwise
21
+ """
22
+ try:
23
+ from django.conf import settings
24
+
25
+ # First try STATIC_ROOT (collected static files in production)
26
+ if hasattr(settings, 'STATIC_ROOT') and settings.STATIC_ROOT:
27
+ static_root = Path(settings.STATIC_ROOT)
28
+ file_path = static_root / path
29
+ if file_path.exists() and file_path.is_file():
30
+ return str(file_path)
31
+
32
+ # Try using Django's static file finders (development mode)
33
+ try:
34
+ from django.contrib.staticfiles.finders import find
35
+ found_path = find(path)
36
+ if found_path:
37
+ return found_path
38
+ except ImportError:
39
+ # staticfiles not installed
40
+ pass
41
+
42
+ # Fallback: check STATICFILES_DIRS
43
+ if hasattr(settings, 'STATICFILES_DIRS'):
44
+ for static_dir in settings.STATICFILES_DIRS:
45
+ if isinstance(static_dir, tuple):
46
+ static_dir = static_dir[1] # (prefix, path) tuple
47
+ file_path = Path(static_dir) / path
48
+ if file_path.exists() and file_path.is_file():
49
+ return str(file_path)
50
+
51
+ except Exception as e:
52
+ import sys
53
+ print(f"[django-bolt] Warning: Error finding static file {path}: {e}", file=sys.stderr)
54
+
55
+ return None
56
+
57
+
58
+ def guess_content_type(file_path: str) -> str:
59
+ """
60
+ Guess content type from file extension.
61
+
62
+ Args:
63
+ file_path: Path to file
64
+
65
+ Returns:
66
+ MIME type string
67
+ """
68
+ import mimetypes
69
+
70
+ content_type, _ = mimetypes.guess_type(file_path)
71
+ if content_type:
72
+ return content_type
73
+
74
+ # Fallback for common static file types
75
+ ext = os.path.splitext(file_path)[1].lower()
76
+ type_map = {
77
+ '.css': 'text/css',
78
+ '.js': 'application/javascript',
79
+ '.json': 'application/json',
80
+ '.png': 'image/png',
81
+ '.jpg': 'image/jpeg',
82
+ '.jpeg': 'image/jpeg',
83
+ '.gif': 'image/gif',
84
+ '.svg': 'image/svg+xml',
85
+ '.ico': 'image/x-icon',
86
+ '.woff': 'font/woff',
87
+ '.woff2': 'font/woff2',
88
+ '.ttf': 'font/ttf',
89
+ '.eot': 'application/vnd.ms-fontobject',
90
+ }
91
+
92
+ return type_map.get(ext, 'application/octet-stream')
93
+
94
+
95
+ async def serve_static_file(path: str) -> Tuple[int, List[Tuple[str, str]], bytes]:
96
+ """
97
+ Serve a static file using Django's static file system.
98
+
99
+ Args:
100
+ path: Relative path to static file
101
+
102
+ Returns:
103
+ Response tuple: (status_code, headers, body)
104
+ """
105
+ from ..exceptions import HTTPException
106
+
107
+ # Security: prevent directory traversal
108
+ if '..' in path or path.startswith('/'):
109
+ raise HTTPException(400, "Invalid static file path")
110
+
111
+ # Find the static file
112
+ file_path = find_static_file(path)
113
+
114
+ if not file_path:
115
+ raise HTTPException(404, f"Static file not found: {path}")
116
+
117
+ # Return FileResponse (Rust will handle streaming)
118
+ from ..responses import FileResponse
119
+ content_type = guess_content_type(file_path)
120
+
121
+ # Use FileResponse which returns the special file response format
122
+ return FileResponse(
123
+ file_path,
124
+ headers={"content-type": content_type}
125
+ )
126
+
127
+
128
+ def register_static_routes(api, static_url: Optional[str] = None):
129
+ """
130
+ Register static file serving routes on a BoltAPI instance.
131
+
132
+ Args:
133
+ api: BoltAPI instance
134
+ static_url: Static URL prefix (default: from settings.STATIC_URL)
135
+ """
136
+ from django.conf import settings
137
+
138
+ if static_url is None:
139
+ if not hasattr(settings, 'STATIC_URL') or not settings.STATIC_URL:
140
+ # Static files not configured
141
+ return
142
+ static_url = settings.STATIC_URL.strip('/')
143
+
144
+ if not static_url:
145
+ static_url = 'static'
146
+
147
+ # Register catch-all route for static files
148
+ route_pattern = f'/{static_url}/{{path:path}}'
149
+
150
+ @api.get(route_pattern)
151
+ async def serve_static(path: str):
152
+ """Serve static files for Django admin and other apps."""
153
+ return await serve_static_file(path)
154
+
155
+ return serve_static
@@ -0,0 +1,111 @@
1
+ """
2
+ Static file route registration for Django admin.
3
+
4
+ This module handles the registration of static file serving routes
5
+ needed by Django admin and other Django apps.
6
+ """
7
+ import inspect
8
+ from typing import TYPE_CHECKING
9
+
10
+ if TYPE_CHECKING:
11
+ from django_bolt.api import BoltAPI
12
+
13
+
14
+ class StaticRouteRegistrar:
15
+ """Handles registration of static file serving routes."""
16
+
17
+ def __init__(self, api: 'BoltAPI'):
18
+ """Initialize the registrar with a BoltAPI instance.
19
+
20
+ Args:
21
+ api: The BoltAPI instance to register routes on
22
+ """
23
+ self.api = api
24
+
25
+ def register_routes(self) -> None:
26
+ """Register static file serving routes for Django admin.
27
+
28
+ This enables serving of CSS, JS, and other static assets needed
29
+ by Django admin and other Django apps.
30
+ """
31
+ if self.api._static_routes_registered:
32
+ return
33
+
34
+ # Only register static routes if admin routes were registered
35
+ # (admin needs static files for CSS/JS)
36
+ if not self.api._admin_routes_registered:
37
+ return
38
+
39
+ try:
40
+ from django.conf import settings
41
+
42
+ # Check if static files are configured
43
+ if not hasattr(settings, 'STATIC_URL') or not settings.STATIC_URL:
44
+ return
45
+
46
+ static_url = settings.STATIC_URL.strip('/')
47
+ if not static_url:
48
+ static_url = 'static'
49
+
50
+ # Register catch-all route for static files
51
+ route_pattern = f'/{static_url}/{{path:path}}'
52
+
53
+ # Import here to avoid circular dependency
54
+ from django_bolt.admin.static import serve_static_file
55
+
56
+ # Create static file handler
57
+ async def static_handler(path: str):
58
+ """Serve static files for Django admin and other apps."""
59
+ return await serve_static_file(path)
60
+
61
+ # Register the route
62
+ self._register_static_route(route_pattern, static_handler)
63
+
64
+ self.api._static_routes_registered = True
65
+
66
+ except Exception as e:
67
+ import sys
68
+ print(f"[django-bolt] Warning: Failed to register static routes: {e}", file=sys.stderr)
69
+
70
+ def _register_static_route(self, route_pattern: str, handler) -> None:
71
+ """Register a static file serving route.
72
+
73
+ Args:
74
+ route_pattern: URL path pattern (e.g., /static/{path:path})
75
+ handler: Async handler function for serving static files
76
+ """
77
+ handler_id = self.api._next_handler_id
78
+ self.api._next_handler_id += 1
79
+
80
+ self.api._routes.append(("GET", route_pattern, handler_id, handler))
81
+ self.api._handlers[handler_id] = handler
82
+
83
+ # Create metadata for static handler
84
+ # Extract path parameter metadata
85
+ sig = inspect.signature(handler)
86
+ meta = {
87
+ "mode": "mixed",
88
+ "sig": sig,
89
+ "fields": [{
90
+ "name": "path",
91
+ "annotation": str,
92
+ "default": inspect.Parameter.empty,
93
+ "kind": inspect.Parameter.POSITIONAL_OR_KEYWORD,
94
+ "source": "path",
95
+ "alias": None,
96
+ "embed": False,
97
+ "dependency": None,
98
+ }],
99
+ "path_params": {"path"},
100
+ "params": [{
101
+ "name": "path",
102
+ "annotation": str,
103
+ "default": inspect.Parameter.empty,
104
+ "kind": inspect.Parameter.POSITIONAL_OR_KEYWORD,
105
+ "source": "path",
106
+ "alias": None,
107
+ "embed": False,
108
+ "dependency": None,
109
+ }],
110
+ }
111
+ self.api._handler_meta[handler] = meta