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
django_bolt/typing.py ADDED
@@ -0,0 +1,273 @@
1
+ """
2
+ Type introspection and field definition system for parameter binding.
3
+
4
+ Inspired by Litestar's architecture but built from scratch for Django-Bolt's
5
+ msgspec-first, async-only design with focus on performance.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import inspect
10
+ import msgspec
11
+ from dataclasses import dataclass
12
+ from typing import Any, get_origin, get_args, Union, Optional, List, Dict, Annotated
13
+
14
+ __all__ = [
15
+ "FieldDefinition",
16
+ "is_msgspec_struct",
17
+ "is_simple_type",
18
+ "is_sequence_type",
19
+ "is_optional",
20
+ "unwrap_optional",
21
+ "infer_param_source",
22
+ ]
23
+
24
+
25
+ # Simple scalar types that map to query parameters
26
+ SIMPLE_TYPES = (str, int, float, bool, bytes)
27
+
28
+
29
+ def is_msgspec_struct(annotation: Any) -> bool:
30
+ """Check if type is a msgspec.Struct."""
31
+ try:
32
+ return isinstance(annotation, type) and issubclass(annotation, msgspec.Struct)
33
+ except (TypeError, AttributeError):
34
+ return False
35
+
36
+
37
+ def is_simple_type(annotation: Any) -> bool:
38
+ """Check if annotation is a simple scalar type (str, int, float, bool, bytes)."""
39
+ origin = get_origin(annotation)
40
+ if origin is not None:
41
+ # Unwrap Optional, List, etc.
42
+ return False
43
+ return annotation in SIMPLE_TYPES or annotation is Any
44
+
45
+
46
+ def is_sequence_type(annotation: Any) -> bool:
47
+ """Check if annotation is a sequence type like List[T]."""
48
+ origin = get_origin(annotation)
49
+ return origin in (list, List, tuple, set, frozenset)
50
+
51
+
52
+ def is_optional(annotation: Any) -> bool:
53
+ """Check if annotation is Optional[T] or T | None."""
54
+ origin = get_origin(annotation)
55
+ if origin is Union:
56
+ args = get_args(annotation)
57
+ return type(None) in args
58
+ return False
59
+
60
+
61
+ def unwrap_optional(annotation: Any) -> Any:
62
+ """Unwrap Optional[T] to get T."""
63
+ origin = get_origin(annotation)
64
+ if origin is Union:
65
+ args = tuple(a for a in get_args(annotation) if a is not type(None))
66
+ return args[0] if len(args) == 1 else Union[args] # type: ignore
67
+ return annotation
68
+
69
+
70
+ def is_dataclass_type(annotation: Any) -> bool:
71
+ """Check if annotation is a dataclass."""
72
+ try:
73
+ from dataclasses import is_dataclass
74
+ return is_dataclass(annotation)
75
+ except (TypeError, AttributeError):
76
+ return False
77
+
78
+
79
+ def infer_param_source(
80
+ name: str,
81
+ annotation: Any,
82
+ path_params: set[str],
83
+ http_method: str
84
+ ) -> str:
85
+ """
86
+ Infer parameter source based on type and context.
87
+
88
+ Inference rules (in priority order):
89
+ 1. If name matches path parameter -> "path"
90
+ 2. If special name (request, req) -> "request"
91
+ 3. If simple type (str, int, float, bool) -> "query"
92
+ 4. If msgspec.Struct or dataclass -> "body" (if method allows body)
93
+ 5. Default -> "query"
94
+
95
+ Args:
96
+ name: Parameter name
97
+ annotation: Type annotation
98
+ path_params: Set of path parameter names from route pattern
99
+ http_method: HTTP method (GET, POST, etc.)
100
+
101
+ Returns:
102
+ Source string: "path", "query", "body", "request", etc.
103
+ """
104
+ # 1. Path parameters
105
+ if name in path_params:
106
+ return "path"
107
+
108
+ # 2. Special request parameter
109
+ if name in {"request", "req"}:
110
+ return "request"
111
+
112
+ # Unwrap Optional if present
113
+ unwrapped = unwrap_optional(annotation)
114
+
115
+ # 3. Simple types -> query params
116
+ if is_simple_type(unwrapped):
117
+ return "query"
118
+
119
+ # 4. Sequence of simple types -> query (for list params)
120
+ if is_sequence_type(unwrapped):
121
+ args = get_args(unwrapped)
122
+ if args and is_simple_type(args[0]):
123
+ return "query"
124
+
125
+ # 5. Complex types (msgspec.Struct, dataclass) -> body (if allowed)
126
+ if is_msgspec_struct(unwrapped) or is_dataclass_type(unwrapped):
127
+ if http_method in {"POST", "PUT", "PATCH"}:
128
+ return "body"
129
+ # For GET/DELETE/HEAD, this will trigger validation error later
130
+ return "body"
131
+
132
+ # 6. Default to query
133
+ return "query"
134
+
135
+
136
+ @dataclass(frozen=True)
137
+ class FieldDefinition:
138
+ """
139
+ Represents a parsed function parameter with type metadata.
140
+
141
+ This is the core data structure for parameter binding, containing
142
+ all information needed to extract and validate a parameter value
143
+ from an HTTP request.
144
+ """
145
+
146
+ name: str
147
+ """Parameter name"""
148
+
149
+ annotation: Any
150
+ """Raw type annotation"""
151
+
152
+ default: Any
153
+ """Default value (inspect.Parameter.empty if required)"""
154
+
155
+ source: str
156
+ """Parameter source: 'path', 'query', 'body', 'header', 'cookie', 'form', 'file', 'request', 'dependency'"""
157
+
158
+ alias: Optional[str] = None
159
+ """Alternative name for the parameter (e.g., 'user-id' for 'user_id')"""
160
+
161
+ embed: Optional[bool] = None
162
+ """For body params: whether to embed in a wrapper object"""
163
+
164
+ dependency: Any = None
165
+ """Depends marker for dependency injection"""
166
+
167
+ kind: inspect._ParameterKind = inspect.Parameter.POSITIONAL_OR_KEYWORD
168
+ """Parameter kind (positional, keyword-only, etc.)"""
169
+
170
+ # Cached type properties for performance
171
+ _is_optional: Optional[bool] = None
172
+ _is_simple: Optional[bool] = None
173
+ _is_struct: Optional[bool] = None
174
+ _unwrapped: Optional[Any] = None
175
+
176
+ @property
177
+ def is_optional(self) -> bool:
178
+ """Check if parameter is optional (has default or Optional type)."""
179
+ if self._is_optional is None:
180
+ object.__setattr__(
181
+ self,
182
+ "_is_optional",
183
+ self.default is not inspect.Parameter.empty or is_optional(self.annotation)
184
+ )
185
+ return self._is_optional # type: ignore
186
+
187
+ @property
188
+ def is_required(self) -> bool:
189
+ """Check if parameter is required."""
190
+ return not self.is_optional
191
+
192
+ @property
193
+ def is_simple_type(self) -> bool:
194
+ """Check if parameter type is simple (str, int, etc.)."""
195
+ if self._is_simple is None:
196
+ unwrapped = self.unwrapped_annotation
197
+ object.__setattr__(self, "_is_simple", is_simple_type(unwrapped))
198
+ return self._is_simple # type: ignore
199
+
200
+ @property
201
+ def is_msgspec_struct(self) -> bool:
202
+ """Check if parameter type is a msgspec.Struct."""
203
+ if self._is_struct is None:
204
+ unwrapped = self.unwrapped_annotation
205
+ object.__setattr__(self, "_is_struct", is_msgspec_struct(unwrapped))
206
+ return self._is_struct # type: ignore
207
+
208
+ @property
209
+ def unwrapped_annotation(self) -> Any:
210
+ """Get annotation with Optional unwrapped."""
211
+ if self._unwrapped is None:
212
+ object.__setattr__(self, "_unwrapped", unwrap_optional(self.annotation))
213
+ return self._unwrapped
214
+
215
+ @property
216
+ def field_alias(self) -> str:
217
+ """Get the alias or name."""
218
+ return self.alias or self.name
219
+
220
+ @classmethod
221
+ def from_parameter(
222
+ cls,
223
+ parameter: inspect.Parameter,
224
+ annotation: Any,
225
+ path_params: set[str],
226
+ http_method: str,
227
+ explicit_marker: Any = None
228
+ ) -> "FieldDefinition":
229
+ """
230
+ Create FieldDefinition from inspect.Parameter.
231
+
232
+ Args:
233
+ parameter: The inspect.Parameter object
234
+ annotation: Type annotation from type hints
235
+ path_params: Set of path parameter names
236
+ http_method: HTTP method for inference
237
+ explicit_marker: Explicit Param or Depends marker if present
238
+
239
+ Returns:
240
+ FieldDefinition instance
241
+ """
242
+ from .params import Param, Depends as DependsMarker
243
+
244
+ name = parameter.name
245
+ default = parameter.default
246
+
247
+ # Handle explicit markers
248
+ source: str
249
+ alias: Optional[str] = None
250
+ embed: Optional[bool] = None
251
+ dependency: Any = None
252
+
253
+ if isinstance(explicit_marker, Param):
254
+ source = explicit_marker.source
255
+ alias = explicit_marker.alias
256
+ embed = explicit_marker.embed
257
+ elif isinstance(explicit_marker, DependsMarker):
258
+ source = "dependency"
259
+ dependency = explicit_marker
260
+ else:
261
+ # Infer source from type and context
262
+ source = infer_param_source(name, annotation, path_params, http_method)
263
+
264
+ return cls(
265
+ name=name,
266
+ annotation=annotation,
267
+ default=default,
268
+ source=source,
269
+ alias=alias,
270
+ embed=embed,
271
+ dependency=dependency,
272
+ kind=parameter.kind,
273
+ )