qena-shared-lib 0.1.17__py3-none-any.whl → 0.1.19__py3-none-any.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.
- qena_shared_lib/__init__.py +20 -2
- qena_shared_lib/alias.py +27 -0
- qena_shared_lib/application.py +4 -4
- qena_shared_lib/background.py +9 -7
- qena_shared_lib/cache.py +61 -0
- qena_shared_lib/enums.py +8 -0
- qena_shared_lib/eventbus.py +373 -0
- qena_shared_lib/exception_handling.py +409 -0
- qena_shared_lib/exceptions.py +167 -57
- qena_shared_lib/http/__init__.py +110 -0
- qena_shared_lib/{http.py → http/_base.py} +36 -36
- qena_shared_lib/http/_exception_handlers.py +202 -0
- qena_shared_lib/http/_request.py +24 -0
- qena_shared_lib/http/_response.py +24 -0
- qena_shared_lib/kafka/__init__.py +21 -0
- qena_shared_lib/kafka/_base.py +233 -0
- qena_shared_lib/kafka/_consumer.py +597 -0
- qena_shared_lib/kafka/_exception_handlers.py +124 -0
- qena_shared_lib/kafka/_producer.py +133 -0
- qena_shared_lib/logging.py +17 -13
- qena_shared_lib/mongodb.py +575 -0
- qena_shared_lib/rabbitmq/__init__.py +6 -6
- qena_shared_lib/rabbitmq/_base.py +68 -132
- qena_shared_lib/rabbitmq/_channel.py +2 -4
- qena_shared_lib/rabbitmq/_exception_handlers.py +69 -142
- qena_shared_lib/rabbitmq/_listener.py +245 -180
- qena_shared_lib/rabbitmq/_publisher.py +5 -5
- qena_shared_lib/rabbitmq/_rpc_client.py +21 -22
- qena_shared_lib/rabbitmq/message/__init__.py +19 -0
- qena_shared_lib/rabbitmq/message/_inbound.py +13 -0
- qena_shared_lib/rabbitmq/message/_outbound.py +13 -0
- qena_shared_lib/redis.py +47 -0
- qena_shared_lib/remotelogging/_base.py +34 -28
- qena_shared_lib/remotelogging/logstash/_base.py +3 -2
- qena_shared_lib/remotelogging/logstash/_http_sender.py +2 -4
- qena_shared_lib/remotelogging/logstash/_tcp_sender.py +2 -2
- qena_shared_lib/scheduler.py +24 -15
- qena_shared_lib/security.py +39 -32
- qena_shared_lib/sync.py +91 -0
- qena_shared_lib/utils.py +13 -11
- {qena_shared_lib-0.1.17.dist-info → qena_shared_lib-0.1.19.dist-info}/METADATA +395 -32
- qena_shared_lib-0.1.19.dist-info/RECORD +50 -0
- qena_shared_lib-0.1.19.dist-info/WHEEL +4 -0
- qena_shared_lib/exception_handlers.py +0 -235
- qena_shared_lib-0.1.17.dist-info/RECORD +0 -31
- qena_shared_lib-0.1.17.dist-info/WHEEL +0 -4
qena_shared_lib/exceptions.py
CHANGED
|
@@ -2,6 +2,9 @@ from enum import Enum
|
|
|
2
2
|
from typing import Any
|
|
3
3
|
|
|
4
4
|
from fastapi import status
|
|
5
|
+
from typing_extensions import Self
|
|
6
|
+
|
|
7
|
+
from .enums import ServiceType
|
|
5
8
|
|
|
6
9
|
__all__ = [
|
|
7
10
|
"BadGateway",
|
|
@@ -18,6 +21,7 @@ __all__ = [
|
|
|
18
21
|
"IAmATeapot",
|
|
19
22
|
"InsufficientStorage",
|
|
20
23
|
"InternalServerError",
|
|
24
|
+
"KafkaDisconnectedError",
|
|
21
25
|
"LengthRequired",
|
|
22
26
|
"Locked",
|
|
23
27
|
"LoopDetected",
|
|
@@ -64,8 +68,8 @@ class Severity(Enum):
|
|
|
64
68
|
|
|
65
69
|
|
|
66
70
|
class ServiceException(Exception):
|
|
67
|
-
|
|
68
|
-
|
|
71
|
+
GENERAL_SEVERITY: Severity | None = None
|
|
72
|
+
GENERAL_EXTRACT_EXC_INFO: bool | None = None
|
|
69
73
|
|
|
70
74
|
def __init__(
|
|
71
75
|
self,
|
|
@@ -80,8 +84,8 @@ class ServiceException(Exception):
|
|
|
80
84
|
|
|
81
85
|
if severity is not None:
|
|
82
86
|
self._severity = severity
|
|
83
|
-
elif self.
|
|
84
|
-
self._severity = self.
|
|
87
|
+
elif self.GENERAL_SEVERITY is not None:
|
|
88
|
+
self._severity = self.GENERAL_SEVERITY
|
|
85
89
|
else:
|
|
86
90
|
self._severity = Severity.LOW
|
|
87
91
|
|
|
@@ -95,8 +99,8 @@ class ServiceException(Exception):
|
|
|
95
99
|
|
|
96
100
|
if extract_exc_info is not None:
|
|
97
101
|
self._extract_exc_info = extract_exc_info
|
|
98
|
-
elif self.
|
|
99
|
-
self._extract_exc_info = self.
|
|
102
|
+
elif self.GENERAL_EXTRACT_EXC_INFO is not None:
|
|
103
|
+
self._extract_exc_info = self.GENERAL_EXTRACT_EXC_INFO
|
|
100
104
|
else:
|
|
101
105
|
self._extract_exc_info = False
|
|
102
106
|
|
|
@@ -132,7 +136,7 @@ class ServiceException(Exception):
|
|
|
132
136
|
|
|
133
137
|
|
|
134
138
|
class HTTPServiceError(ServiceException):
|
|
135
|
-
|
|
139
|
+
GENERAL_STATUS_CODE: int | None = None
|
|
136
140
|
|
|
137
141
|
def __init__(
|
|
138
142
|
self,
|
|
@@ -163,7 +167,7 @@ class HTTPServiceError(ServiceException):
|
|
|
163
167
|
if status_code is not None:
|
|
164
168
|
self._status_code = status_code
|
|
165
169
|
else:
|
|
166
|
-
self._status_code = self.
|
|
170
|
+
self._status_code = self.GENERAL_STATUS_CODE
|
|
167
171
|
|
|
168
172
|
self._headers = headers
|
|
169
173
|
self._response_code = response_code
|
|
@@ -197,179 +201,179 @@ class HTTPServiceError(ServiceException):
|
|
|
197
201
|
|
|
198
202
|
|
|
199
203
|
class ClientError(HTTPServiceError):
|
|
200
|
-
|
|
201
|
-
|
|
204
|
+
GENERAL_SEVERITY = Severity.MEDIUM
|
|
205
|
+
GENERAL_EXTRACT_EXC_INFO = False
|
|
202
206
|
|
|
203
207
|
|
|
204
208
|
class BadRequest(ClientError):
|
|
205
|
-
|
|
209
|
+
GENERAL_STATUS_CODE = status.HTTP_400_BAD_REQUEST
|
|
206
210
|
|
|
207
211
|
|
|
208
212
|
class Unauthorized(ClientError):
|
|
209
|
-
|
|
213
|
+
GENERAL_STATUS_CODE = status.HTTP_401_UNAUTHORIZED
|
|
210
214
|
|
|
211
215
|
|
|
212
216
|
class PaymentRequired(ClientError):
|
|
213
|
-
|
|
217
|
+
GENERAL_STATUS_CODE = status.HTTP_402_PAYMENT_REQUIRED
|
|
214
218
|
|
|
215
219
|
|
|
216
220
|
class Forbidden(ClientError):
|
|
217
|
-
|
|
221
|
+
GENERAL_STATUS_CODE = status.HTTP_403_FORBIDDEN
|
|
218
222
|
|
|
219
223
|
|
|
220
224
|
class NotFound(ClientError):
|
|
221
|
-
|
|
225
|
+
GENERAL_STATUS_CODE = status.HTTP_404_NOT_FOUND
|
|
222
226
|
|
|
223
227
|
|
|
224
228
|
class MethodNotAllowed(ClientError):
|
|
225
|
-
|
|
229
|
+
GENERAL_STATUS_CODE = status.HTTP_405_METHOD_NOT_ALLOWED
|
|
226
230
|
|
|
227
231
|
|
|
228
232
|
class NotAcceptable(ClientError):
|
|
229
|
-
|
|
233
|
+
GENERAL_STATUS_CODE = status.HTTP_406_NOT_ACCEPTABLE
|
|
230
234
|
|
|
231
235
|
|
|
232
236
|
class ProxyAuthenticationRequired(ClientError):
|
|
233
|
-
|
|
237
|
+
GENERAL_STATUS_CODE = status.HTTP_407_PROXY_AUTHENTICATION_REQUIRED
|
|
234
238
|
|
|
235
239
|
|
|
236
240
|
class RequestTimeout(ClientError):
|
|
237
|
-
|
|
241
|
+
GENERAL_STATUS_CODE = status.HTTP_408_REQUEST_TIMEOUT
|
|
238
242
|
|
|
239
243
|
|
|
240
244
|
class Conflict(ClientError):
|
|
241
|
-
|
|
245
|
+
GENERAL_STATUS_CODE = status.HTTP_409_CONFLICT
|
|
242
246
|
|
|
243
247
|
|
|
244
248
|
class Gone(ClientError):
|
|
245
|
-
|
|
249
|
+
GENERAL_STATUS_CODE = status.HTTP_410_GONE
|
|
246
250
|
|
|
247
251
|
|
|
248
252
|
class LengthRequired(ClientError):
|
|
249
|
-
|
|
253
|
+
GENERAL_STATUS_CODE = status.HTTP_411_LENGTH_REQUIRED
|
|
250
254
|
|
|
251
255
|
|
|
252
256
|
class PreconditionFailed(ClientError):
|
|
253
|
-
|
|
257
|
+
GENERAL_STATUS_CODE = status.HTTP_412_PRECONDITION_FAILED
|
|
254
258
|
|
|
255
259
|
|
|
256
260
|
class PayloadTooLarge(ClientError):
|
|
257
|
-
|
|
261
|
+
GENERAL_STATUS_CODE = status.HTTP_413_REQUEST_ENTITY_TOO_LARGE
|
|
258
262
|
|
|
259
263
|
|
|
260
264
|
class URITooLong(ClientError):
|
|
261
|
-
|
|
265
|
+
GENERAL_STATUS_CODE = status.HTTP_414_REQUEST_URI_TOO_LONG
|
|
262
266
|
|
|
263
267
|
|
|
264
268
|
class UnsupportedMediaType(ClientError):
|
|
265
|
-
|
|
269
|
+
GENERAL_STATUS_CODE = status.HTTP_415_UNSUPPORTED_MEDIA_TYPE
|
|
266
270
|
|
|
267
271
|
|
|
268
272
|
class RangeNotSatisfiable(ClientError):
|
|
269
|
-
|
|
273
|
+
GENERAL_STATUS_CODE = status.HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE
|
|
270
274
|
|
|
271
275
|
|
|
272
276
|
class ExpectationFailed(ClientError):
|
|
273
|
-
|
|
277
|
+
GENERAL_STATUS_CODE = status.HTTP_417_EXPECTATION_FAILED
|
|
274
278
|
|
|
275
279
|
|
|
276
280
|
class IAmATeapot(ClientError):
|
|
277
|
-
|
|
281
|
+
GENERAL_STATUS_CODE = status.HTTP_418_IM_A_TEAPOT
|
|
278
282
|
|
|
279
283
|
|
|
280
284
|
class MisdirectedRequest(ClientError):
|
|
281
|
-
|
|
285
|
+
GENERAL_STATUS_CODE = status.HTTP_421_MISDIRECTED_REQUEST
|
|
282
286
|
|
|
283
287
|
|
|
284
288
|
class UnprocessableEntity(ClientError):
|
|
285
|
-
|
|
289
|
+
GENERAL_STATUS_CODE = status.HTTP_422_UNPROCESSABLE_ENTITY
|
|
286
290
|
|
|
287
291
|
|
|
288
292
|
class Locked(ClientError):
|
|
289
|
-
|
|
293
|
+
GENERAL_STATUS_CODE = status.HTTP_423_LOCKED
|
|
290
294
|
|
|
291
295
|
|
|
292
296
|
class FailedDependency(ClientError):
|
|
293
|
-
|
|
297
|
+
GENERAL_STATUS_CODE = status.HTTP_424_FAILED_DEPENDENCY
|
|
294
298
|
|
|
295
299
|
|
|
296
300
|
class TooEarly(ClientError):
|
|
297
|
-
|
|
301
|
+
GENERAL_STATUS_CODE = status.HTTP_425_TOO_EARLY
|
|
298
302
|
|
|
299
303
|
|
|
300
304
|
class UpgradeRequired(ClientError):
|
|
301
|
-
|
|
305
|
+
GENERAL_STATUS_CODE = status.HTTP_426_UPGRADE_REQUIRED
|
|
302
306
|
|
|
303
307
|
|
|
304
308
|
class PreconditionRequired(ClientError):
|
|
305
|
-
|
|
309
|
+
GENERAL_STATUS_CODE = status.HTTP_428_PRECONDITION_REQUIRED
|
|
306
310
|
|
|
307
311
|
|
|
308
312
|
class TooManyRequests(ClientError):
|
|
309
|
-
|
|
313
|
+
GENERAL_STATUS_CODE = status.HTTP_429_TOO_MANY_REQUESTS
|
|
310
314
|
|
|
311
315
|
|
|
312
316
|
class RequestHeaderFieldsTooLarge(ClientError):
|
|
313
|
-
|
|
317
|
+
GENERAL_STATUS_CODE = status.HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE
|
|
314
318
|
|
|
315
319
|
|
|
316
320
|
class UnavailableForLegalReasons(ClientError):
|
|
317
|
-
|
|
321
|
+
GENERAL_STATUS_CODE = status.HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS
|
|
318
322
|
|
|
319
323
|
|
|
320
324
|
class ServerError(HTTPServiceError):
|
|
321
|
-
|
|
322
|
-
|
|
325
|
+
GENERAL_SEVERITY = Severity.HIGH
|
|
326
|
+
GENERAL_EXTRACT_EXC_INFO = True
|
|
323
327
|
|
|
324
328
|
|
|
325
329
|
class InternalServerError(ServerError):
|
|
326
|
-
|
|
330
|
+
GENERAL_STATUS_CODE = status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
327
331
|
|
|
328
332
|
|
|
329
333
|
class NotImplemented(ServerError):
|
|
330
|
-
|
|
334
|
+
GENERAL_STATUS_CODE = status.HTTP_501_NOT_IMPLEMENTED
|
|
331
335
|
|
|
332
336
|
|
|
333
337
|
class BadGateway(ServerError):
|
|
334
|
-
|
|
338
|
+
GENERAL_STATUS_CODE = status.HTTP_502_BAD_GATEWAY
|
|
335
339
|
|
|
336
340
|
|
|
337
341
|
class ServiceUnavailable(ServerError):
|
|
338
|
-
|
|
342
|
+
GENERAL_STATUS_CODE = status.HTTP_503_SERVICE_UNAVAILABLE
|
|
339
343
|
|
|
340
344
|
|
|
341
345
|
class GatewayTimeout(ServerError):
|
|
342
|
-
|
|
346
|
+
GENERAL_STATUS_CODE = status.HTTP_504_GATEWAY_TIMEOUT
|
|
343
347
|
|
|
344
348
|
|
|
345
349
|
class HTTPVersionNotSupported(ServerError):
|
|
346
|
-
|
|
350
|
+
GENERAL_STATUS_CODE = status.HTTP_505_HTTP_VERSION_NOT_SUPPORTED
|
|
347
351
|
|
|
348
352
|
|
|
349
353
|
class VariantAlsoNegotiates(ServerError):
|
|
350
|
-
|
|
354
|
+
GENERAL_STATUS_CODE = status.HTTP_506_VARIANT_ALSO_NEGOTIATES
|
|
351
355
|
|
|
352
356
|
|
|
353
357
|
class InsufficientStorage(ServerError):
|
|
354
|
-
|
|
358
|
+
GENERAL_STATUS_CODE = status.HTTP_507_INSUFFICIENT_STORAGE
|
|
355
359
|
|
|
356
360
|
|
|
357
361
|
class LoopDetected(ServerError):
|
|
358
|
-
|
|
362
|
+
GENERAL_STATUS_CODE = status.HTTP_508_LOOP_DETECTED
|
|
359
363
|
|
|
360
364
|
|
|
361
365
|
class NotExtended(ServerError):
|
|
362
|
-
|
|
366
|
+
GENERAL_STATUS_CODE = status.HTTP_510_NOT_EXTENDED
|
|
363
367
|
|
|
364
368
|
|
|
365
369
|
class NetworkAuthenticationRequired(ServerError):
|
|
366
|
-
|
|
370
|
+
GENERAL_STATUS_CODE = status.HTTP_511_NETWORK_AUTHENTICATION_REQUIRED
|
|
367
371
|
|
|
368
372
|
|
|
369
373
|
class RabbitMQServiceException(ServiceException):
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
374
|
+
GENERAL_SEVERITY = Severity.HIGH
|
|
375
|
+
GENERAL_EXTRACT_EXC_INFO = True
|
|
376
|
+
GENERAL_CODE: int | None = None
|
|
373
377
|
|
|
374
378
|
def __init__(
|
|
375
379
|
self,
|
|
@@ -393,8 +397,8 @@ class RabbitMQServiceException(ServiceException):
|
|
|
393
397
|
|
|
394
398
|
if code is not None:
|
|
395
399
|
self._code = code
|
|
396
|
-
elif self.
|
|
397
|
-
self._code = self.
|
|
400
|
+
elif self.GENERAL_CODE is not None:
|
|
401
|
+
self._code = self.GENERAL_CODE
|
|
398
402
|
else:
|
|
399
403
|
self._code = 0
|
|
400
404
|
|
|
@@ -429,3 +433,109 @@ class RabbitMQRpcRequestPendingError(Exception):
|
|
|
429
433
|
|
|
430
434
|
class RabbitMQConnectionUnhealthyError(Exception):
|
|
431
435
|
pass
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
class KafkaDisconnectedError(Exception):
|
|
439
|
+
pass
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
class GenericServiceExceptionFactory:
|
|
443
|
+
def __init__(
|
|
444
|
+
self,
|
|
445
|
+
message: str,
|
|
446
|
+
severity: Severity | None = None,
|
|
447
|
+
tags: list[str] | None = None,
|
|
448
|
+
extra: dict[str, str] | None = None,
|
|
449
|
+
remote_logging: bool = True,
|
|
450
|
+
extract_exc_info: bool = True,
|
|
451
|
+
):
|
|
452
|
+
self._message = message
|
|
453
|
+
self._severity = severity
|
|
454
|
+
self._tags = tags
|
|
455
|
+
self._extra = extra
|
|
456
|
+
self._remote_logging = remote_logging
|
|
457
|
+
self._extract_exc_info = extract_exc_info
|
|
458
|
+
|
|
459
|
+
self._http_service_error: type[HTTPServiceError] = InternalServerError
|
|
460
|
+
self._rabbitmq_service_exception: type[RabbitMQServiceException] = (
|
|
461
|
+
RabbitMQServiceException
|
|
462
|
+
)
|
|
463
|
+
|
|
464
|
+
self._body: Any | None = None
|
|
465
|
+
self._status_code: int | None = None
|
|
466
|
+
self._headers: dict[str, str] | None = None
|
|
467
|
+
self._response_code: int | None = None
|
|
468
|
+
self._corrective_action: str | None = None
|
|
469
|
+
self._code: int | None = None
|
|
470
|
+
self._data: Any | None = None
|
|
471
|
+
|
|
472
|
+
def for_http_service_error(
|
|
473
|
+
self, http_service_error: type[HTTPServiceError]
|
|
474
|
+
) -> Self:
|
|
475
|
+
self._http_service_error = http_service_error
|
|
476
|
+
|
|
477
|
+
return self
|
|
478
|
+
|
|
479
|
+
def for_rabbitmq_service_exception(
|
|
480
|
+
self, rabbitmq_service_exception: type[RabbitMQServiceException]
|
|
481
|
+
) -> Self:
|
|
482
|
+
self._rabbitmq_service_exception = rabbitmq_service_exception
|
|
483
|
+
|
|
484
|
+
return self
|
|
485
|
+
|
|
486
|
+
def with_http_service_error(
|
|
487
|
+
self,
|
|
488
|
+
body: Any | None = None,
|
|
489
|
+
status_code: int | None = None,
|
|
490
|
+
headers: dict[str, str] | None = None,
|
|
491
|
+
response_code: int | None = None,
|
|
492
|
+
corrective_action: str | None = None,
|
|
493
|
+
) -> Self:
|
|
494
|
+
self._body = body
|
|
495
|
+
self._status_code = status_code
|
|
496
|
+
self._headers = headers
|
|
497
|
+
self._response_code = response_code
|
|
498
|
+
self._corrective_action = corrective_action
|
|
499
|
+
|
|
500
|
+
return self
|
|
501
|
+
|
|
502
|
+
def with_rabbitmq_service_exception(
|
|
503
|
+
self,
|
|
504
|
+
code: int | None = None,
|
|
505
|
+
data: Any | None = None,
|
|
506
|
+
) -> Self:
|
|
507
|
+
self._code = code
|
|
508
|
+
self._data = data
|
|
509
|
+
|
|
510
|
+
return self
|
|
511
|
+
|
|
512
|
+
def create(self, service_type: ServiceType) -> ServiceException:
|
|
513
|
+
assert self._http_service_error is not None
|
|
514
|
+
assert self._rabbitmq_service_exception is not None
|
|
515
|
+
|
|
516
|
+
match service_type:
|
|
517
|
+
case ServiceType.HTTP:
|
|
518
|
+
return self._http_service_error(
|
|
519
|
+
message=self._message,
|
|
520
|
+
body=self._body,
|
|
521
|
+
status_code=self._status_code,
|
|
522
|
+
headers=self._headers,
|
|
523
|
+
response_code=self._response_code,
|
|
524
|
+
corrective_action=self._corrective_action,
|
|
525
|
+
severity=self._severity,
|
|
526
|
+
tags=self._tags,
|
|
527
|
+
extra=self._extra,
|
|
528
|
+
remote_logging=self._remote_logging,
|
|
529
|
+
extract_exc_info=self._extract_exc_info,
|
|
530
|
+
)
|
|
531
|
+
case ServiceType.RABBIT_MQ:
|
|
532
|
+
return self._rabbitmq_service_exception(
|
|
533
|
+
message=self._message,
|
|
534
|
+
code=self._code,
|
|
535
|
+
data=self._data,
|
|
536
|
+
severity=self._severity,
|
|
537
|
+
tags=self._tags,
|
|
538
|
+
extra=self._extra,
|
|
539
|
+
remote_logging=self._remote_logging,
|
|
540
|
+
extract_exc_info=self._extract_exc_info,
|
|
541
|
+
)
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
from ._base import (
|
|
2
|
+
ROUTE_HANDLER_ATTRIBUTE,
|
|
3
|
+
APIRouter,
|
|
4
|
+
BackgroundTasks,
|
|
5
|
+
Body,
|
|
6
|
+
ControllerBase,
|
|
7
|
+
Cookie,
|
|
8
|
+
Depends,
|
|
9
|
+
File,
|
|
10
|
+
FileResponse,
|
|
11
|
+
Form,
|
|
12
|
+
Header,
|
|
13
|
+
HTMLResponse,
|
|
14
|
+
HTTPException,
|
|
15
|
+
JSONResponse,
|
|
16
|
+
Path,
|
|
17
|
+
PlainTextResponse,
|
|
18
|
+
Query,
|
|
19
|
+
RedirectResponse,
|
|
20
|
+
Request,
|
|
21
|
+
Response,
|
|
22
|
+
RouteHandlerMetadata,
|
|
23
|
+
Security,
|
|
24
|
+
StreamingResponse,
|
|
25
|
+
UploadFile,
|
|
26
|
+
WebSocket,
|
|
27
|
+
WebSocketDisconnect,
|
|
28
|
+
WebSocketException,
|
|
29
|
+
api_controller,
|
|
30
|
+
delete,
|
|
31
|
+
get,
|
|
32
|
+
head,
|
|
33
|
+
options,
|
|
34
|
+
patch,
|
|
35
|
+
post,
|
|
36
|
+
put,
|
|
37
|
+
status,
|
|
38
|
+
trace,
|
|
39
|
+
)
|
|
40
|
+
from ._exception_handlers import (
|
|
41
|
+
AbstractHttpExceptionHandler,
|
|
42
|
+
HttpGeneralExceptionHandler,
|
|
43
|
+
HTTPServiceExceptionHandler,
|
|
44
|
+
RequestValidationErrorHandler,
|
|
45
|
+
)
|
|
46
|
+
from ._request import (
|
|
47
|
+
CamelCaseRequest,
|
|
48
|
+
InboundRequest,
|
|
49
|
+
OutboundRequest,
|
|
50
|
+
SnakeCaseRequest,
|
|
51
|
+
)
|
|
52
|
+
from ._response import (
|
|
53
|
+
CamelCaseResponse,
|
|
54
|
+
InboundResponse,
|
|
55
|
+
OutboundResponse,
|
|
56
|
+
SnakeCaseRespose,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
__all__ = [
|
|
60
|
+
"AbstractHttpExceptionHandler",
|
|
61
|
+
"api_controller",
|
|
62
|
+
"APIRouter",
|
|
63
|
+
"BackgroundTasks",
|
|
64
|
+
"Body",
|
|
65
|
+
"CamelCaseRequest",
|
|
66
|
+
"CamelCaseResponse",
|
|
67
|
+
"ControllerBase",
|
|
68
|
+
"Cookie",
|
|
69
|
+
"delete",
|
|
70
|
+
"Depends",
|
|
71
|
+
"File",
|
|
72
|
+
"FileResponse",
|
|
73
|
+
"Form",
|
|
74
|
+
"get",
|
|
75
|
+
"head",
|
|
76
|
+
"Header",
|
|
77
|
+
"HTMLResponse",
|
|
78
|
+
"HTTPException",
|
|
79
|
+
"HttpGeneralExceptionHandler",
|
|
80
|
+
"HTTPServiceExceptionHandler",
|
|
81
|
+
"InboundRequest",
|
|
82
|
+
"InboundResponse",
|
|
83
|
+
"JSONResponse",
|
|
84
|
+
"options",
|
|
85
|
+
"OutboundRequest",
|
|
86
|
+
"OutboundResponse",
|
|
87
|
+
"patch",
|
|
88
|
+
"Path",
|
|
89
|
+
"PlainTextResponse",
|
|
90
|
+
"post",
|
|
91
|
+
"put",
|
|
92
|
+
"Query",
|
|
93
|
+
"RedirectResponse",
|
|
94
|
+
"Request",
|
|
95
|
+
"RequestValidationErrorHandler",
|
|
96
|
+
"Response",
|
|
97
|
+
"Response",
|
|
98
|
+
"ROUTE_HANDLER_ATTRIBUTE",
|
|
99
|
+
"RouteHandlerMetadata",
|
|
100
|
+
"Security",
|
|
101
|
+
"SnakeCaseRequest",
|
|
102
|
+
"SnakeCaseRespose",
|
|
103
|
+
"status",
|
|
104
|
+
"StreamingResponse",
|
|
105
|
+
"trace",
|
|
106
|
+
"UploadFile",
|
|
107
|
+
"WebSocket",
|
|
108
|
+
"WebSocketDisconnect",
|
|
109
|
+
"WebSocketException",
|
|
110
|
+
]
|
|
@@ -75,7 +75,7 @@ __all__ = [
|
|
|
75
75
|
|
|
76
76
|
AC = TypeVar("AC")
|
|
77
77
|
API_CONTROLLER_ATTRIBUTE = "__api_controller_router__"
|
|
78
|
-
ROUTE_HANDLER_ATTRIBUTE = "
|
|
78
|
+
ROUTE_HANDLER_ATTRIBUTE = "__route_handler_metadata__"
|
|
79
79
|
|
|
80
80
|
|
|
81
81
|
class HTTPMethods(Enum):
|
|
@@ -90,7 +90,7 @@ class HTTPMethods(Enum):
|
|
|
90
90
|
|
|
91
91
|
|
|
92
92
|
@dataclass
|
|
93
|
-
class
|
|
93
|
+
class RouteHandlerMetadata:
|
|
94
94
|
method: HTTPMethods
|
|
95
95
|
path: str | None = None
|
|
96
96
|
response_model: Any | None = None
|
|
@@ -173,7 +173,7 @@ def get(
|
|
|
173
173
|
setattr(
|
|
174
174
|
route_handler,
|
|
175
175
|
ROUTE_HANDLER_ATTRIBUTE,
|
|
176
|
-
|
|
176
|
+
RouteHandlerMetadata(
|
|
177
177
|
method=HTTPMethods.GET,
|
|
178
178
|
path=path,
|
|
179
179
|
response_model=response_model,
|
|
@@ -230,7 +230,7 @@ def put(
|
|
|
230
230
|
setattr(
|
|
231
231
|
route_handler,
|
|
232
232
|
ROUTE_HANDLER_ATTRIBUTE,
|
|
233
|
-
|
|
233
|
+
RouteHandlerMetadata(
|
|
234
234
|
method=HTTPMethods.PUT,
|
|
235
235
|
path=path,
|
|
236
236
|
response_model=response_model,
|
|
@@ -287,7 +287,7 @@ def post(
|
|
|
287
287
|
setattr(
|
|
288
288
|
route_handler,
|
|
289
289
|
ROUTE_HANDLER_ATTRIBUTE,
|
|
290
|
-
|
|
290
|
+
RouteHandlerMetadata(
|
|
291
291
|
method=HTTPMethods.POST,
|
|
292
292
|
path=path,
|
|
293
293
|
response_model=response_model,
|
|
@@ -344,7 +344,7 @@ def delete(
|
|
|
344
344
|
setattr(
|
|
345
345
|
route_handler,
|
|
346
346
|
ROUTE_HANDLER_ATTRIBUTE,
|
|
347
|
-
|
|
347
|
+
RouteHandlerMetadata(
|
|
348
348
|
method=HTTPMethods.DELETE,
|
|
349
349
|
path=path,
|
|
350
350
|
response_model=response_model,
|
|
@@ -401,7 +401,7 @@ def options(
|
|
|
401
401
|
setattr(
|
|
402
402
|
route_handler,
|
|
403
403
|
ROUTE_HANDLER_ATTRIBUTE,
|
|
404
|
-
|
|
404
|
+
RouteHandlerMetadata(
|
|
405
405
|
method=HTTPMethods.OPTIONS,
|
|
406
406
|
path=path,
|
|
407
407
|
response_model=response_model,
|
|
@@ -458,7 +458,7 @@ def head(
|
|
|
458
458
|
setattr(
|
|
459
459
|
route_handler,
|
|
460
460
|
ROUTE_HANDLER_ATTRIBUTE,
|
|
461
|
-
|
|
461
|
+
RouteHandlerMetadata(
|
|
462
462
|
method=HTTPMethods.HEAD,
|
|
463
463
|
path=path,
|
|
464
464
|
response_model=response_model,
|
|
@@ -515,7 +515,7 @@ def patch(
|
|
|
515
515
|
setattr(
|
|
516
516
|
route_handler,
|
|
517
517
|
ROUTE_HANDLER_ATTRIBUTE,
|
|
518
|
-
|
|
518
|
+
RouteHandlerMetadata(
|
|
519
519
|
method=HTTPMethods.PATCH,
|
|
520
520
|
path=path,
|
|
521
521
|
response_model=response_model,
|
|
@@ -572,7 +572,7 @@ def trace(
|
|
|
572
572
|
setattr(
|
|
573
573
|
route_handler,
|
|
574
574
|
ROUTE_HANDLER_ATTRIBUTE,
|
|
575
|
-
|
|
575
|
+
RouteHandlerMetadata(
|
|
576
576
|
method=HTTPMethods.TRACE,
|
|
577
577
|
path=path,
|
|
578
578
|
response_model=response_model,
|
|
@@ -622,21 +622,21 @@ class ControllerBase:
|
|
|
622
622
|
if attribute is None:
|
|
623
623
|
continue
|
|
624
624
|
|
|
625
|
-
|
|
625
|
+
route_handler_metadata = getattr(
|
|
626
626
|
attribute, ROUTE_HANDLER_ATTRIBUTE, None
|
|
627
627
|
)
|
|
628
628
|
|
|
629
|
-
if
|
|
629
|
+
if route_handler_metadata is None:
|
|
630
630
|
continue
|
|
631
631
|
|
|
632
|
-
if not isinstance(
|
|
632
|
+
if not isinstance(route_handler_metadata, RouteHandlerMetadata):
|
|
633
633
|
raise TypeError(
|
|
634
|
-
f"expected `{ROUTE_HANDLER_ATTRIBUTE}` to be of type `
|
|
634
|
+
f"expected `{ROUTE_HANDLER_ATTRIBUTE}` to be of type `RouteHandlerMetadata`, got {type(route_handler_metadata)}"
|
|
635
635
|
)
|
|
636
636
|
|
|
637
637
|
api_router_method = None
|
|
638
638
|
|
|
639
|
-
match
|
|
639
|
+
match route_handler_metadata.method:
|
|
640
640
|
case HTTPMethods.GET:
|
|
641
641
|
api_router_method = api_router.get
|
|
642
642
|
case HTTPMethods.PUT:
|
|
@@ -656,30 +656,30 @@ class ControllerBase:
|
|
|
656
656
|
|
|
657
657
|
if api_router_method is None:
|
|
658
658
|
raise ValueError(
|
|
659
|
-
f"api router method {
|
|
659
|
+
f"api router method {route_handler_metadata.method} not supported"
|
|
660
660
|
)
|
|
661
661
|
|
|
662
662
|
api_router_method(
|
|
663
|
-
path=
|
|
664
|
-
response_model=
|
|
665
|
-
status_code=
|
|
666
|
-
tags=
|
|
667
|
-
dependencies=
|
|
668
|
-
summary=
|
|
669
|
-
description=
|
|
670
|
-
response_description=
|
|
671
|
-
responses=
|
|
672
|
-
deprecated=
|
|
673
|
-
response_model_include=
|
|
674
|
-
response_model_exclude=
|
|
675
|
-
response_model_by_alias=
|
|
676
|
-
response_model_exclude_unset=
|
|
677
|
-
response_model_exclude_defaults=
|
|
678
|
-
response_model_exclude_none=
|
|
679
|
-
include_in_schema=
|
|
680
|
-
response_class=
|
|
681
|
-
name=
|
|
682
|
-
openapi_extra=
|
|
663
|
+
path=route_handler_metadata.path or "",
|
|
664
|
+
response_model=route_handler_metadata.response_model,
|
|
665
|
+
status_code=route_handler_metadata.status_code,
|
|
666
|
+
tags=route_handler_metadata.tags,
|
|
667
|
+
dependencies=route_handler_metadata.dependencies,
|
|
668
|
+
summary=route_handler_metadata.summary,
|
|
669
|
+
description=route_handler_metadata.description,
|
|
670
|
+
response_description=route_handler_metadata.response_description,
|
|
671
|
+
responses=route_handler_metadata.responses,
|
|
672
|
+
deprecated=route_handler_metadata.deprecated,
|
|
673
|
+
response_model_include=route_handler_metadata.response_model_include,
|
|
674
|
+
response_model_exclude=route_handler_metadata.response_model_exclude,
|
|
675
|
+
response_model_by_alias=route_handler_metadata.response_model_by_alias,
|
|
676
|
+
response_model_exclude_unset=route_handler_metadata.response_model_exclude_unset,
|
|
677
|
+
response_model_exclude_defaults=route_handler_metadata.response_model_exclude_defaults,
|
|
678
|
+
response_model_exclude_none=route_handler_metadata.response_model_exclude_none,
|
|
679
|
+
include_in_schema=route_handler_metadata.include_in_schema,
|
|
680
|
+
response_class=route_handler_metadata.response_class,
|
|
681
|
+
name=route_handler_metadata.name,
|
|
682
|
+
openapi_extra=route_handler_metadata.openapi_extra,
|
|
683
683
|
)(attribute)
|
|
684
684
|
|
|
685
685
|
return api_router
|