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/router.py ADDED
@@ -0,0 +1,48 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Callable, Dict, List, Optional, Tuple
4
+
5
+
6
+ class APIRouter:
7
+ def __init__(self, prefix: str = "", tags: Optional[List[str]] = None, dependencies: Optional[List[Any]] = None):
8
+ self.prefix = prefix.rstrip("/")
9
+ self.tags = tags or []
10
+ self.dependencies = dependencies or []
11
+ self._routes: List[Tuple[str, str, Callable, Dict[str, Any]]] = []
12
+
13
+ def _add(self, method: str, path: str, handler: Callable, **meta: Any) -> None:
14
+ full = (self.prefix + path) if self.prefix else path
15
+ self._routes.append((method, full, handler, meta))
16
+
17
+ def get(self, path: str, **kwargs: Any):
18
+ def dec(fn: Callable):
19
+ self._add("GET", path, fn, **kwargs)
20
+ return fn
21
+ return dec
22
+
23
+ def post(self, path: str, **kwargs: Any):
24
+ def dec(fn: Callable):
25
+ self._add("POST", path, fn, **kwargs)
26
+ return fn
27
+ return dec
28
+
29
+ def put(self, path: str, **kwargs: Any):
30
+ def dec(fn: Callable):
31
+ self._add("PUT", path, fn, **kwargs)
32
+ return fn
33
+ return dec
34
+
35
+ def patch(self, path: str, **kwargs: Any):
36
+ def dec(fn: Callable):
37
+ self._add("PATCH", path, fn, **kwargs)
38
+ return fn
39
+ return dec
40
+
41
+ def delete(self, path: str, **kwargs: Any):
42
+ def dec(fn: Callable):
43
+ self._add("DELETE", path, fn, **kwargs)
44
+ return fn
45
+ return dec
46
+
47
+
48
+
@@ -0,0 +1,193 @@
1
+ """Response serialization utilities."""
2
+ import mimetypes
3
+ import msgspec
4
+ from typing import Any, Dict, List, Optional, Tuple
5
+ from .responses import Response as ResponseClass, JSON, PlainText, HTML, Redirect, File, FileResponse, StreamingResponse
6
+ from .binding import coerce_to_response_type_async
7
+
8
+ ResponseTuple = Tuple[int, List[Tuple[str, str]], bytes]
9
+
10
+
11
+ async def serialize_response(result: Any, meta: Dict[str, Any]) -> ResponseTuple:
12
+ """Serialize handler result to HTTP response."""
13
+ response_tp = meta.get("response_type")
14
+
15
+ # Check if result is already a raw response tuple (status, headers, body)
16
+ # This is used by ASGI bridge and other low-level handlers
17
+ if isinstance(result, tuple) and len(result) == 3:
18
+ status, headers, body = result
19
+ # Validate it looks like a response tuple
20
+ if isinstance(status, int) and isinstance(headers, list) and isinstance(body, (bytes, bytearray)):
21
+ return status, headers, bytes(body)
22
+
23
+ # Handle different response types (ordered by frequency for performance)
24
+ # Most common: plain dict/list JSON responses
25
+ if isinstance(result, (dict, list)):
26
+ return await serialize_json_data(result, response_tp, meta)
27
+ # Common: JSON wrapper
28
+ elif isinstance(result, JSON):
29
+ return await serialize_json_response(result, response_tp)
30
+ # Common: Streaming responses
31
+ elif isinstance(result, StreamingResponse):
32
+ return result
33
+ # Less common: Other response types
34
+ elif isinstance(result, PlainText):
35
+ return serialize_plaintext_response(result)
36
+ elif isinstance(result, HTML):
37
+ return serialize_html_response(result)
38
+ elif isinstance(result, (bytes, bytearray)):
39
+ status = int(meta.get("default_status_code", 200))
40
+ return status, [("content-type", "application/octet-stream")], bytes(result)
41
+ elif isinstance(result, str):
42
+ status = int(meta.get("default_status_code", 200))
43
+ return status, [("content-type", "text/plain; charset=utf-8")], result.encode()
44
+ elif isinstance(result, Redirect):
45
+ return serialize_redirect_response(result)
46
+ elif isinstance(result, File):
47
+ return serialize_file_response(result)
48
+ elif isinstance(result, FileResponse):
49
+ return serialize_file_streaming_response(result)
50
+ elif isinstance(result, ResponseClass):
51
+ return await serialize_generic_response(result, response_tp)
52
+ else:
53
+ # Fallback to msgspec encoding
54
+ return await serialize_json_data(result, response_tp, meta)
55
+
56
+
57
+ async def serialize_generic_response(result: ResponseClass, response_tp: Optional[Any]) -> ResponseTuple:
58
+ """Serialize generic Response object with custom headers."""
59
+ # Check if content-type is already provided in custom headers
60
+ has_custom_content_type = result.headers and any(k.lower() == "content-type" for k in result.headers.keys())
61
+
62
+ if has_custom_content_type:
63
+ # Use only custom headers (including custom content-type)
64
+ headers = [(k.lower(), v) for k, v in result.headers.items()]
65
+ else:
66
+ # Use media_type as content-type and extend with custom headers
67
+ headers = [("content-type", result.media_type)]
68
+ if result.headers:
69
+ headers.extend([(k.lower(), v) for k, v in result.headers.items()])
70
+
71
+ if response_tp is not None:
72
+ try:
73
+ validated = await coerce_to_response_type_async(result.content, response_tp)
74
+ data_bytes = msgspec.json.encode(validated) if result.media_type == "application/json" else result.to_bytes()
75
+ except Exception as e:
76
+ err = f"Response validation error: {e}"
77
+ return 500, [("content-type", "text/plain; charset=utf-8")], err.encode()
78
+ else:
79
+ data_bytes = result.to_bytes()
80
+
81
+ return int(result.status_code), headers, data_bytes
82
+
83
+
84
+ async def serialize_json_response(result: JSON, response_tp: Optional[Any]) -> ResponseTuple:
85
+ """Serialize JSON response object."""
86
+ # Check if content-type is already provided in custom headers
87
+ has_custom_content_type = result.headers and any(k.lower() == "content-type" for k in result.headers.keys())
88
+
89
+ if has_custom_content_type:
90
+ # Use only custom headers (including custom content-type)
91
+ headers = [(k.lower(), v) for k, v in result.headers.items()]
92
+ else:
93
+ # Use default content-type and extend with custom headers
94
+ headers = [("content-type", "application/json")]
95
+ if result.headers:
96
+ headers.extend([(k.lower(), v) for k, v in result.headers.items()])
97
+
98
+ if response_tp is not None:
99
+ try:
100
+ validated = await coerce_to_response_type_async(result.data, response_tp)
101
+ data_bytes = msgspec.json.encode(validated)
102
+ except Exception as e:
103
+ err = f"Response validation error: {e}"
104
+ return 500, [("content-type", "text/plain; charset=utf-8")], err.encode()
105
+ else:
106
+ data_bytes = result.to_bytes()
107
+
108
+ return int(result.status_code), headers, data_bytes
109
+
110
+
111
+ def serialize_plaintext_response(result: PlainText) -> ResponseTuple:
112
+ """Serialize plain text response."""
113
+ # Check if content-type is already provided in custom headers
114
+ has_custom_content_type = result.headers and any(k.lower() == "content-type" for k in result.headers.keys())
115
+
116
+ if has_custom_content_type:
117
+ # Use only custom headers (including custom content-type)
118
+ headers = [(k.lower(), v) for k, v in result.headers.items()]
119
+ else:
120
+ # Use default content-type and extend with custom headers
121
+ headers = [("content-type", "text/plain; charset=utf-8")]
122
+ if result.headers:
123
+ headers.extend([(k.lower(), v) for k, v in result.headers.items()])
124
+
125
+ return int(result.status_code), headers, result.to_bytes()
126
+
127
+
128
+ def serialize_html_response(result: HTML) -> ResponseTuple:
129
+ """Serialize HTML response."""
130
+ # Check if content-type is already provided in custom headers
131
+ has_custom_content_type = result.headers and any(k.lower() == "content-type" for k in result.headers.keys())
132
+
133
+ if has_custom_content_type:
134
+ # Use only custom headers (including custom content-type)
135
+ headers = [(k.lower(), v) for k, v in result.headers.items()]
136
+ else:
137
+ # Use default content-type and extend with custom headers
138
+ headers = [("content-type", "text/html; charset=utf-8")]
139
+ if result.headers:
140
+ headers.extend([(k.lower(), v) for k, v in result.headers.items()])
141
+
142
+ return int(result.status_code), headers, result.to_bytes()
143
+
144
+
145
+ def serialize_redirect_response(result: Redirect) -> ResponseTuple:
146
+ """Serialize redirect response."""
147
+ headers = [("location", result.url)]
148
+ if result.headers:
149
+ headers.extend([(k.lower(), v) for k, v in result.headers.items()])
150
+ return int(result.status_code), headers, b""
151
+
152
+
153
+ def serialize_file_response(result: File) -> ResponseTuple:
154
+ """Serialize file response."""
155
+ data = result.read_bytes()
156
+ ctype = result.media_type or mimetypes.guess_type(result.path)[0] or "application/octet-stream"
157
+ headers = [("content-type", ctype)]
158
+
159
+ if result.filename:
160
+ headers.append(("content-disposition", f"attachment; filename=\"{result.filename}\""))
161
+ if result.headers:
162
+ headers.extend([(k.lower(), v) for k, v in result.headers.items()])
163
+
164
+ return int(result.status_code), headers, data
165
+
166
+
167
+ def serialize_file_streaming_response(result: FileResponse) -> ResponseTuple:
168
+ """Serialize file streaming response."""
169
+ ctype = result.media_type or mimetypes.guess_type(result.path)[0] or "application/octet-stream"
170
+ headers = [("x-bolt-file-path", result.path), ("content-type", ctype)]
171
+
172
+ if result.filename:
173
+ headers.append(("content-disposition", f"attachment; filename=\"{result.filename}\""))
174
+ if result.headers:
175
+ headers.extend([(k.lower(), v) for k, v in result.headers.items()])
176
+
177
+ return int(result.status_code), headers, b""
178
+
179
+
180
+ async def serialize_json_data(result: Any, response_tp: Optional[Any], meta: Dict[str, Any]) -> ResponseTuple:
181
+ """Serialize dict/list/other data as JSON."""
182
+ if response_tp is not None:
183
+ try:
184
+ validated = await coerce_to_response_type_async(result, response_tp)
185
+ data = msgspec.json.encode(validated)
186
+ except Exception as e:
187
+ err = f"Response validation error: {e}"
188
+ return 500, [("content-type", "text/plain; charset=utf-8")], err.encode()
189
+ else:
190
+ data = msgspec.json.encode(result)
191
+
192
+ status = int(meta.get("default_status_code", 200))
193
+ return status, [("content-type", "application/json")], data
@@ -0,0 +1,321 @@
1
+ from typing import Final
2
+
3
+ # HTTP Status Codes
4
+
5
+ HTTP_100_CONTINUE: Final = 100
6
+ """HTTP status code 'Continue'"""
7
+
8
+ HTTP_101_SWITCHING_PROTOCOLS: Final = 101
9
+ """HTTP status code 'Switching Protocols'"""
10
+
11
+ HTTP_102_PROCESSING: Final = 102
12
+ """HTTP status code 'Processing'"""
13
+
14
+ HTTP_103_EARLY_HINTS: Final = 103
15
+ """HTTP status code 'Early Hints'"""
16
+
17
+ HTTP_200_OK: Final = 200
18
+ """HTTP status code 'OK'"""
19
+
20
+ HTTP_201_CREATED: Final = 201
21
+ """HTTP status code 'Created'"""
22
+
23
+ HTTP_202_ACCEPTED: Final = 202
24
+ """HTTP status code 'Accepted'"""
25
+
26
+ HTTP_203_NON_AUTHORITATIVE_INFORMATION: Final = 203
27
+ """HTTP status code 'Non Authoritative Information'"""
28
+
29
+ HTTP_204_NO_CONTENT: Final = 204
30
+ """HTTP status code 'No Content'"""
31
+
32
+ HTTP_205_RESET_CONTENT: Final = 205
33
+ """HTTP status code 'Reset Content'"""
34
+
35
+ HTTP_206_PARTIAL_CONTENT: Final = 206
36
+ """HTTP status code 'Partial Content'"""
37
+
38
+ HTTP_207_MULTI_STATUS: Final = 207
39
+ """HTTP status code 'Multi Status'"""
40
+
41
+ HTTP_208_ALREADY_REPORTED: Final = 208
42
+ """HTTP status code 'Already Reported'"""
43
+
44
+ HTTP_226_IM_USED: Final = 226
45
+ """HTTP status code 'I'm Used'"""
46
+
47
+ HTTP_300_MULTIPLE_CHOICES: Final = 300
48
+ """HTTP status code 'Multiple Choices'"""
49
+
50
+ HTTP_301_MOVED_PERMANENTLY: Final = 301
51
+ """HTTP status code 'Moved Permanently'"""
52
+
53
+ HTTP_302_FOUND: Final = 302
54
+ """HTTP status code 'Found'"""
55
+
56
+ HTTP_303_SEE_OTHER: Final = 303
57
+ """HTTP status code 'See Other'"""
58
+
59
+ HTTP_304_NOT_MODIFIED: Final = 304
60
+ """HTTP status code 'Not Modified'"""
61
+
62
+ HTTP_305_USE_PROXY: Final = 305
63
+ """HTTP status code 'Use Proxy'"""
64
+
65
+ HTTP_306_RESERVED: Final = 306
66
+ """HTTP status code 'Reserved'"""
67
+
68
+ HTTP_307_TEMPORARY_REDIRECT: Final = 307
69
+ """HTTP status code 'Temporary Redirect'"""
70
+
71
+ HTTP_308_PERMANENT_REDIRECT: Final = 308
72
+ """HTTP status code 'Permanent Redirect'"""
73
+
74
+ HTTP_400_BAD_REQUEST: Final = 400
75
+ """HTTP status code 'Bad Request'"""
76
+
77
+ HTTP_401_UNAUTHORIZED: Final = 401
78
+ """HTTP status code 'Unauthorized'"""
79
+
80
+ HTTP_402_PAYMENT_REQUIRED: Final = 402
81
+ """HTTP status code 'Payment Required'"""
82
+
83
+ HTTP_403_FORBIDDEN: Final = 403
84
+ """HTTP status code 'Forbidden'"""
85
+
86
+ HTTP_404_NOT_FOUND: Final = 404
87
+ """HTTP status code 'Not Found'"""
88
+
89
+ HTTP_405_METHOD_NOT_ALLOWED: Final = 405
90
+ """HTTP status code 'Method Not Allowed'"""
91
+
92
+ HTTP_406_NOT_ACCEPTABLE: Final = 406
93
+ """HTTP status code 'Not Acceptable'"""
94
+
95
+ HTTP_407_PROXY_AUTHENTICATION_REQUIRED: Final = 407
96
+ """HTTP status code 'Proxy Authentication Required'"""
97
+
98
+ HTTP_408_REQUEST_TIMEOUT: Final = 408
99
+ """HTTP status code 'Request Timeout'"""
100
+
101
+ HTTP_409_CONFLICT: Final = 409
102
+ """HTTP status code 'Conflict'"""
103
+
104
+ HTTP_410_GONE: Final = 410
105
+ """HTTP status code 'Gone'"""
106
+
107
+ HTTP_411_LENGTH_REQUIRED: Final = 411
108
+ """HTTP status code 'Length Required'"""
109
+
110
+ HTTP_412_PRECONDITION_FAILED: Final = 412
111
+ """HTTP status code 'Precondition Failed'"""
112
+
113
+ HTTP_413_REQUEST_ENTITY_TOO_LARGE: Final = 413
114
+ """HTTP status code 'Request Entity Too Large'"""
115
+
116
+ HTTP_414_REQUEST_URI_TOO_LONG: Final = 414
117
+ """HTTP status code 'Request URI Too Long'"""
118
+
119
+ HTTP_415_UNSUPPORTED_MEDIA_TYPE: Final = 415
120
+ """HTTP status code 'Unsupported Media Type'"""
121
+
122
+ HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE: Final = 416
123
+ """HTTP status code 'Requested Range Not Satisfiable'"""
124
+
125
+ HTTP_417_EXPECTATION_FAILED: Final = 417
126
+ """HTTP status code 'Expectation Failed'"""
127
+
128
+ HTTP_418_IM_A_TEAPOT: Final = 418
129
+ """HTTP status code 'I'm A Teapot'"""
130
+
131
+ HTTP_421_MISDIRECTED_REQUEST: Final = 421
132
+ """HTTP status code 'Misdirected Request'"""
133
+
134
+ HTTP_422_UNPROCESSABLE_ENTITY: Final = 422
135
+ """HTTP status code 'Unprocessable Entity'"""
136
+
137
+ HTTP_423_LOCKED: Final = 423
138
+ """HTTP status code 'Locked'"""
139
+
140
+ HTTP_424_FAILED_DEPENDENCY: Final = 424
141
+ """HTTP status code 'Failed Dependency'"""
142
+
143
+ HTTP_425_TOO_EARLY: Final = 425
144
+ """HTTP status code 'Too Early'"""
145
+
146
+ HTTP_426_UPGRADE_REQUIRED: Final = 426
147
+ """HTTP status code 'Upgrade Required'"""
148
+
149
+ HTTP_428_PRECONDITION_REQUIRED: Final = 428
150
+ """HTTP status code 'Precondition Required'"""
151
+
152
+ HTTP_429_TOO_MANY_REQUESTS: Final = 429
153
+ """HTTP status code 'Too Many Requests'"""
154
+
155
+ HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE: Final = 431
156
+ """HTTP status code 'Request Header Fields Too Large'"""
157
+
158
+ HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS: Final = 451
159
+ """HTTP status code 'Unavailable For Legal Reasons'"""
160
+
161
+ HTTP_500_INTERNAL_SERVER_ERROR: Final = 500
162
+ """HTTP status code 'Internal Server Error'"""
163
+
164
+ HTTP_501_NOT_IMPLEMENTED: Final = 501
165
+ """HTTP status code 'Not Implemented'"""
166
+
167
+ HTTP_502_BAD_GATEWAY: Final = 502
168
+ """HTTP status code 'Bad Gateway'"""
169
+
170
+ HTTP_503_SERVICE_UNAVAILABLE: Final = 503
171
+ """HTTP status code 'Service Unavailable'"""
172
+
173
+ HTTP_504_GATEWAY_TIMEOUT: Final = 504
174
+ """HTTP status code 'Gateway Timeout'"""
175
+
176
+ HTTP_505_HTTP_VERSION_NOT_SUPPORTED: Final = 505
177
+ """HTTP status code 'Http Version Not Supported'"""
178
+
179
+ HTTP_506_VARIANT_ALSO_NEGOTIATES: Final = 506
180
+ """HTTP status code 'Variant Also Negotiates'"""
181
+
182
+ HTTP_507_INSUFFICIENT_STORAGE: Final = 507
183
+ """HTTP status code 'Insufficient Storage'"""
184
+
185
+ HTTP_508_LOOP_DETECTED: Final = 508
186
+ """HTTP status code 'Loop Detected'"""
187
+
188
+ HTTP_510_NOT_EXTENDED: Final = 510
189
+ """HTTP status code 'Not Extended'"""
190
+
191
+ HTTP_511_NETWORK_AUTHENTICATION_REQUIRED: Final = 511
192
+ """HTTP status code 'Network Authentication Required'"""
193
+
194
+
195
+ # # Websocket Codes
196
+ # WS_1000_NORMAL_CLOSURE: Final = 1000
197
+ # """WebSocket status code 'Normal Closure'"""
198
+
199
+ # WS_1001_GOING_AWAY: Final = 1001
200
+ # """WebSocket status code 'Going Away'"""
201
+
202
+ # WS_1002_PROTOCOL_ERROR: Final = 1002
203
+ # """WebSocket status code 'Protocol Error'"""
204
+
205
+ # WS_1003_UNSUPPORTED_DATA: Final = 1003
206
+ # """WebSocket status code 'Unsupported Data'"""
207
+
208
+ # WS_1005_NO_STATUS_RECEIVED: Final = 1005
209
+ # """WebSocket status code 'No Status Received'"""
210
+
211
+ # WS_1006_ABNORMAL_CLOSURE: Final = 1006
212
+ # """WebSocket status code 'Abnormal Closure'"""
213
+
214
+ # WS_1007_INVALID_FRAME_PAYLOAD_DATA: Final = 1007
215
+ # """WebSocket status code 'Invalid Frame Payload Data'"""
216
+
217
+ # WS_1008_POLICY_VIOLATION: Final = 1008
218
+ # """WebSocket status code 'Policy Violation'"""
219
+
220
+ # WS_1009_MESSAGE_TOO_BIG: Final = 1009
221
+ # """WebSocket status code 'Message Too Big'"""
222
+
223
+ # WS_1010_MANDATORY_EXT: Final = 1010
224
+ # """WebSocket status code 'Mandatory Ext.'"""
225
+
226
+ # WS_1011_INTERNAL_ERROR: Final = 1011
227
+ # """WebSocket status code 'Internal Error'"""
228
+
229
+ # WS_1012_SERVICE_RESTART: Final = 1012
230
+ # """WebSocket status code 'Service Restart'"""
231
+
232
+ # WS_1013_TRY_AGAIN_LATER: Final = 1013
233
+ # """WebSocket status code 'Try Again Later'"""
234
+
235
+ # WS_1014_BAD_GATEWAY: Final = 1014
236
+ # """WebSocket status code 'Bad Gateway'"""
237
+
238
+ # WS_1015_TLS_HANDSHAKE: Final = 1015
239
+ # """WebSocket status code 'TLS Handshake'"""
240
+
241
+
242
+ __all__ = (
243
+ "HTTP_100_CONTINUE",
244
+ "HTTP_101_SWITCHING_PROTOCOLS",
245
+ "HTTP_102_PROCESSING",
246
+ "HTTP_103_EARLY_HINTS",
247
+ "HTTP_200_OK",
248
+ "HTTP_201_CREATED",
249
+ "HTTP_202_ACCEPTED",
250
+ "HTTP_203_NON_AUTHORITATIVE_INFORMATION",
251
+ "HTTP_204_NO_CONTENT",
252
+ "HTTP_205_RESET_CONTENT",
253
+ "HTTP_206_PARTIAL_CONTENT",
254
+ "HTTP_207_MULTI_STATUS",
255
+ "HTTP_208_ALREADY_REPORTED",
256
+ "HTTP_226_IM_USED",
257
+ "HTTP_300_MULTIPLE_CHOICES",
258
+ "HTTP_301_MOVED_PERMANENTLY",
259
+ "HTTP_302_FOUND",
260
+ "HTTP_303_SEE_OTHER",
261
+ "HTTP_304_NOT_MODIFIED",
262
+ "HTTP_305_USE_PROXY",
263
+ "HTTP_306_RESERVED",
264
+ "HTTP_307_TEMPORARY_REDIRECT",
265
+ "HTTP_308_PERMANENT_REDIRECT",
266
+ "HTTP_400_BAD_REQUEST",
267
+ "HTTP_401_UNAUTHORIZED",
268
+ "HTTP_402_PAYMENT_REQUIRED",
269
+ "HTTP_403_FORBIDDEN",
270
+ "HTTP_404_NOT_FOUND",
271
+ "HTTP_405_METHOD_NOT_ALLOWED",
272
+ "HTTP_406_NOT_ACCEPTABLE",
273
+ "HTTP_407_PROXY_AUTHENTICATION_REQUIRED",
274
+ "HTTP_408_REQUEST_TIMEOUT",
275
+ "HTTP_409_CONFLICT",
276
+ "HTTP_410_GONE",
277
+ "HTTP_411_LENGTH_REQUIRED",
278
+ "HTTP_412_PRECONDITION_FAILED",
279
+ "HTTP_413_REQUEST_ENTITY_TOO_LARGE",
280
+ "HTTP_414_REQUEST_URI_TOO_LONG",
281
+ "HTTP_415_UNSUPPORTED_MEDIA_TYPE",
282
+ "HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE",
283
+ "HTTP_417_EXPECTATION_FAILED",
284
+ "HTTP_418_IM_A_TEAPOT",
285
+ "HTTP_421_MISDIRECTED_REQUEST",
286
+ "HTTP_422_UNPROCESSABLE_ENTITY",
287
+ "HTTP_423_LOCKED",
288
+ "HTTP_424_FAILED_DEPENDENCY",
289
+ "HTTP_425_TOO_EARLY",
290
+ "HTTP_426_UPGRADE_REQUIRED",
291
+ "HTTP_428_PRECONDITION_REQUIRED",
292
+ "HTTP_429_TOO_MANY_REQUESTS",
293
+ "HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE",
294
+ "HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS",
295
+ "HTTP_500_INTERNAL_SERVER_ERROR",
296
+ "HTTP_501_NOT_IMPLEMENTED",
297
+ "HTTP_502_BAD_GATEWAY",
298
+ "HTTP_503_SERVICE_UNAVAILABLE",
299
+ "HTTP_504_GATEWAY_TIMEOUT",
300
+ "HTTP_505_HTTP_VERSION_NOT_SUPPORTED",
301
+ "HTTP_506_VARIANT_ALSO_NEGOTIATES",
302
+ "HTTP_507_INSUFFICIENT_STORAGE",
303
+ "HTTP_508_LOOP_DETECTED",
304
+ "HTTP_510_NOT_EXTENDED",
305
+ "HTTP_511_NETWORK_AUTHENTICATION_REQUIRED",
306
+ # "WS_1000_NORMAL_CLOSURE",
307
+ # "WS_1001_GOING_AWAY",
308
+ # "WS_1002_PROTOCOL_ERROR",
309
+ # "WS_1003_UNSUPPORTED_DATA",
310
+ # "WS_1005_NO_STATUS_RECEIVED",
311
+ # "WS_1006_ABNORMAL_CLOSURE",
312
+ # "WS_1007_INVALID_FRAME_PAYLOAD_DATA",
313
+ # "WS_1008_POLICY_VIOLATION",
314
+ # "WS_1009_MESSAGE_TOO_BIG",
315
+ # "WS_1010_MANDATORY_EXT",
316
+ # "WS_1011_INTERNAL_ERROR",
317
+ # "WS_1012_SERVICE_RESTART",
318
+ # "WS_1013_TRY_AGAIN_LATER",
319
+ # "WS_1014_BAD_GATEWAY",
320
+ # "WS_1015_TLS_HANDSHAKE",
321
+ )
@@ -0,0 +1,10 @@
1
+ """Testing utilities for django-bolt.
2
+
3
+ Provides test clients for in-memory testing without subprocess/network overhead.
4
+ """
5
+ from django_bolt.testing.client import TestClient, AsyncTestClient
6
+
7
+ __all__ = [
8
+ "TestClient",
9
+ "AsyncTestClient",
10
+ ]