qena-shared-lib 0.1.17__py3-none-any.whl → 0.1.18__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 +3 -2
- qena_shared_lib/application.py +4 -4
- qena_shared_lib/background.py +9 -7
- qena_shared_lib/exception_handling.py +409 -0
- qena_shared_lib/exceptions.py +170 -57
- qena_shared_lib/http/__init__.py +90 -0
- qena_shared_lib/{http.py → http/_base.py} +36 -36
- qena_shared_lib/http/_exception_handlers.py +202 -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/rabbitmq/__init__.py +4 -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 +246 -157
- qena_shared_lib/rabbitmq/_publisher.py +5 -5
- qena_shared_lib/rabbitmq/_rpc_client.py +21 -22
- qena_shared_lib/remotelogging/_base.py +20 -20
- qena_shared_lib/remotelogging/logstash/_base.py +2 -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/utils.py +13 -11
- {qena_shared_lib-0.1.17.dist-info → qena_shared_lib-0.1.18.dist-info}/METADATA +4 -1
- qena_shared_lib-0.1.18.dist-info/RECORD +38 -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 → qena_shared_lib-0.1.18.dist-info}/WHEEL +0 -0
qena_shared_lib/exceptions.py
CHANGED
@@ -2,6 +2,7 @@ from enum import Enum
|
|
2
2
|
from typing import Any
|
3
3
|
|
4
4
|
from fastapi import status
|
5
|
+
from typing_extensions import Self
|
5
6
|
|
6
7
|
__all__ = [
|
7
8
|
"BadGateway",
|
@@ -18,6 +19,7 @@ __all__ = [
|
|
18
19
|
"IAmATeapot",
|
19
20
|
"InsufficientStorage",
|
20
21
|
"InternalServerError",
|
22
|
+
"KafkaDisconnectedError",
|
21
23
|
"LengthRequired",
|
22
24
|
"Locked",
|
23
25
|
"LoopDetected",
|
@@ -64,8 +66,8 @@ class Severity(Enum):
|
|
64
66
|
|
65
67
|
|
66
68
|
class ServiceException(Exception):
|
67
|
-
|
68
|
-
|
69
|
+
GENERAL_SEVERITY: Severity | None = None
|
70
|
+
GENERAL_EXTRACT_EXC_INFO: bool | None = None
|
69
71
|
|
70
72
|
def __init__(
|
71
73
|
self,
|
@@ -80,8 +82,8 @@ class ServiceException(Exception):
|
|
80
82
|
|
81
83
|
if severity is not None:
|
82
84
|
self._severity = severity
|
83
|
-
elif self.
|
84
|
-
self._severity = self.
|
85
|
+
elif self.GENERAL_SEVERITY is not None:
|
86
|
+
self._severity = self.GENERAL_SEVERITY
|
85
87
|
else:
|
86
88
|
self._severity = Severity.LOW
|
87
89
|
|
@@ -95,8 +97,8 @@ class ServiceException(Exception):
|
|
95
97
|
|
96
98
|
if extract_exc_info is not None:
|
97
99
|
self._extract_exc_info = extract_exc_info
|
98
|
-
elif self.
|
99
|
-
self._extract_exc_info = self.
|
100
|
+
elif self.GENERAL_EXTRACT_EXC_INFO is not None:
|
101
|
+
self._extract_exc_info = self.GENERAL_EXTRACT_EXC_INFO
|
100
102
|
else:
|
101
103
|
self._extract_exc_info = False
|
102
104
|
|
@@ -132,7 +134,7 @@ class ServiceException(Exception):
|
|
132
134
|
|
133
135
|
|
134
136
|
class HTTPServiceError(ServiceException):
|
135
|
-
|
137
|
+
GENERAL_STATUS_CODE: int | None = None
|
136
138
|
|
137
139
|
def __init__(
|
138
140
|
self,
|
@@ -163,7 +165,7 @@ class HTTPServiceError(ServiceException):
|
|
163
165
|
if status_code is not None:
|
164
166
|
self._status_code = status_code
|
165
167
|
else:
|
166
|
-
self._status_code = self.
|
168
|
+
self._status_code = self.GENERAL_STATUS_CODE
|
167
169
|
|
168
170
|
self._headers = headers
|
169
171
|
self._response_code = response_code
|
@@ -197,179 +199,179 @@ class HTTPServiceError(ServiceException):
|
|
197
199
|
|
198
200
|
|
199
201
|
class ClientError(HTTPServiceError):
|
200
|
-
|
201
|
-
|
202
|
+
GENERAL_SEVERITY = Severity.MEDIUM
|
203
|
+
GENERAL_EXTRACT_EXC_INFO = False
|
202
204
|
|
203
205
|
|
204
206
|
class BadRequest(ClientError):
|
205
|
-
|
207
|
+
GENERAL_STATUS_CODE = status.HTTP_400_BAD_REQUEST
|
206
208
|
|
207
209
|
|
208
210
|
class Unauthorized(ClientError):
|
209
|
-
|
211
|
+
GENERAL_STATUS_CODE = status.HTTP_401_UNAUTHORIZED
|
210
212
|
|
211
213
|
|
212
214
|
class PaymentRequired(ClientError):
|
213
|
-
|
215
|
+
GENERAL_STATUS_CODE = status.HTTP_402_PAYMENT_REQUIRED
|
214
216
|
|
215
217
|
|
216
218
|
class Forbidden(ClientError):
|
217
|
-
|
219
|
+
GENERAL_STATUS_CODE = status.HTTP_403_FORBIDDEN
|
218
220
|
|
219
221
|
|
220
222
|
class NotFound(ClientError):
|
221
|
-
|
223
|
+
GENERAL_STATUS_CODE = status.HTTP_404_NOT_FOUND
|
222
224
|
|
223
225
|
|
224
226
|
class MethodNotAllowed(ClientError):
|
225
|
-
|
227
|
+
GENERAL_STATUS_CODE = status.HTTP_405_METHOD_NOT_ALLOWED
|
226
228
|
|
227
229
|
|
228
230
|
class NotAcceptable(ClientError):
|
229
|
-
|
231
|
+
GENERAL_STATUS_CODE = status.HTTP_406_NOT_ACCEPTABLE
|
230
232
|
|
231
233
|
|
232
234
|
class ProxyAuthenticationRequired(ClientError):
|
233
|
-
|
235
|
+
GENERAL_STATUS_CODE = status.HTTP_407_PROXY_AUTHENTICATION_REQUIRED
|
234
236
|
|
235
237
|
|
236
238
|
class RequestTimeout(ClientError):
|
237
|
-
|
239
|
+
GENERAL_STATUS_CODE = status.HTTP_408_REQUEST_TIMEOUT
|
238
240
|
|
239
241
|
|
240
242
|
class Conflict(ClientError):
|
241
|
-
|
243
|
+
GENERAL_STATUS_CODE = status.HTTP_409_CONFLICT
|
242
244
|
|
243
245
|
|
244
246
|
class Gone(ClientError):
|
245
|
-
|
247
|
+
GENERAL_STATUS_CODE = status.HTTP_410_GONE
|
246
248
|
|
247
249
|
|
248
250
|
class LengthRequired(ClientError):
|
249
|
-
|
251
|
+
GENERAL_STATUS_CODE = status.HTTP_411_LENGTH_REQUIRED
|
250
252
|
|
251
253
|
|
252
254
|
class PreconditionFailed(ClientError):
|
253
|
-
|
255
|
+
GENERAL_STATUS_CODE = status.HTTP_412_PRECONDITION_FAILED
|
254
256
|
|
255
257
|
|
256
258
|
class PayloadTooLarge(ClientError):
|
257
|
-
|
259
|
+
GENERAL_STATUS_CODE = status.HTTP_413_REQUEST_ENTITY_TOO_LARGE
|
258
260
|
|
259
261
|
|
260
262
|
class URITooLong(ClientError):
|
261
|
-
|
263
|
+
GENERAL_STATUS_CODE = status.HTTP_414_REQUEST_URI_TOO_LONG
|
262
264
|
|
263
265
|
|
264
266
|
class UnsupportedMediaType(ClientError):
|
265
|
-
|
267
|
+
GENERAL_STATUS_CODE = status.HTTP_415_UNSUPPORTED_MEDIA_TYPE
|
266
268
|
|
267
269
|
|
268
270
|
class RangeNotSatisfiable(ClientError):
|
269
|
-
|
271
|
+
GENERAL_STATUS_CODE = status.HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE
|
270
272
|
|
271
273
|
|
272
274
|
class ExpectationFailed(ClientError):
|
273
|
-
|
275
|
+
GENERAL_STATUS_CODE = status.HTTP_417_EXPECTATION_FAILED
|
274
276
|
|
275
277
|
|
276
278
|
class IAmATeapot(ClientError):
|
277
|
-
|
279
|
+
GENERAL_STATUS_CODE = status.HTTP_418_IM_A_TEAPOT
|
278
280
|
|
279
281
|
|
280
282
|
class MisdirectedRequest(ClientError):
|
281
|
-
|
283
|
+
GENERAL_STATUS_CODE = status.HTTP_421_MISDIRECTED_REQUEST
|
282
284
|
|
283
285
|
|
284
286
|
class UnprocessableEntity(ClientError):
|
285
|
-
|
287
|
+
GENERAL_STATUS_CODE = status.HTTP_422_UNPROCESSABLE_ENTITY
|
286
288
|
|
287
289
|
|
288
290
|
class Locked(ClientError):
|
289
|
-
|
291
|
+
GENERAL_STATUS_CODE = status.HTTP_423_LOCKED
|
290
292
|
|
291
293
|
|
292
294
|
class FailedDependency(ClientError):
|
293
|
-
|
295
|
+
GENERAL_STATUS_CODE = status.HTTP_424_FAILED_DEPENDENCY
|
294
296
|
|
295
297
|
|
296
298
|
class TooEarly(ClientError):
|
297
|
-
|
299
|
+
GENERAL_STATUS_CODE = status.HTTP_425_TOO_EARLY
|
298
300
|
|
299
301
|
|
300
302
|
class UpgradeRequired(ClientError):
|
301
|
-
|
303
|
+
GENERAL_STATUS_CODE = status.HTTP_426_UPGRADE_REQUIRED
|
302
304
|
|
303
305
|
|
304
306
|
class PreconditionRequired(ClientError):
|
305
|
-
|
307
|
+
GENERAL_STATUS_CODE = status.HTTP_428_PRECONDITION_REQUIRED
|
306
308
|
|
307
309
|
|
308
310
|
class TooManyRequests(ClientError):
|
309
|
-
|
311
|
+
GENERAL_STATUS_CODE = status.HTTP_429_TOO_MANY_REQUESTS
|
310
312
|
|
311
313
|
|
312
314
|
class RequestHeaderFieldsTooLarge(ClientError):
|
313
|
-
|
315
|
+
GENERAL_STATUS_CODE = status.HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE
|
314
316
|
|
315
317
|
|
316
318
|
class UnavailableForLegalReasons(ClientError):
|
317
|
-
|
319
|
+
GENERAL_STATUS_CODE = status.HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS
|
318
320
|
|
319
321
|
|
320
322
|
class ServerError(HTTPServiceError):
|
321
|
-
|
322
|
-
|
323
|
+
GENERAL_SEVERITY = Severity.HIGH
|
324
|
+
GENERAL_EXTRACT_EXC_INFO = True
|
323
325
|
|
324
326
|
|
325
327
|
class InternalServerError(ServerError):
|
326
|
-
|
328
|
+
GENERAL_STATUS_CODE = status.HTTP_500_INTERNAL_SERVER_ERROR
|
327
329
|
|
328
330
|
|
329
331
|
class NotImplemented(ServerError):
|
330
|
-
|
332
|
+
GENERAL_STATUS_CODE = status.HTTP_501_NOT_IMPLEMENTED
|
331
333
|
|
332
334
|
|
333
335
|
class BadGateway(ServerError):
|
334
|
-
|
336
|
+
GENERAL_STATUS_CODE = status.HTTP_502_BAD_GATEWAY
|
335
337
|
|
336
338
|
|
337
339
|
class ServiceUnavailable(ServerError):
|
338
|
-
|
340
|
+
GENERAL_STATUS_CODE = status.HTTP_503_SERVICE_UNAVAILABLE
|
339
341
|
|
340
342
|
|
341
343
|
class GatewayTimeout(ServerError):
|
342
|
-
|
344
|
+
GENERAL_STATUS_CODE = status.HTTP_504_GATEWAY_TIMEOUT
|
343
345
|
|
344
346
|
|
345
347
|
class HTTPVersionNotSupported(ServerError):
|
346
|
-
|
348
|
+
GENERAL_STATUS_CODE = status.HTTP_505_HTTP_VERSION_NOT_SUPPORTED
|
347
349
|
|
348
350
|
|
349
351
|
class VariantAlsoNegotiates(ServerError):
|
350
|
-
|
352
|
+
GENERAL_STATUS_CODE = status.HTTP_506_VARIANT_ALSO_NEGOTIATES
|
351
353
|
|
352
354
|
|
353
355
|
class InsufficientStorage(ServerError):
|
354
|
-
|
356
|
+
GENERAL_STATUS_CODE = status.HTTP_507_INSUFFICIENT_STORAGE
|
355
357
|
|
356
358
|
|
357
359
|
class LoopDetected(ServerError):
|
358
|
-
|
360
|
+
GENERAL_STATUS_CODE = status.HTTP_508_LOOP_DETECTED
|
359
361
|
|
360
362
|
|
361
363
|
class NotExtended(ServerError):
|
362
|
-
|
364
|
+
GENERAL_STATUS_CODE = status.HTTP_510_NOT_EXTENDED
|
363
365
|
|
364
366
|
|
365
367
|
class NetworkAuthenticationRequired(ServerError):
|
366
|
-
|
368
|
+
GENERAL_STATUS_CODE = status.HTTP_511_NETWORK_AUTHENTICATION_REQUIRED
|
367
369
|
|
368
370
|
|
369
371
|
class RabbitMQServiceException(ServiceException):
|
370
|
-
|
371
|
-
|
372
|
-
|
372
|
+
GENERAL_SEVERITY = Severity.HIGH
|
373
|
+
GENERAL_EXTRACT_EXC_INFO = True
|
374
|
+
GENERAL_CODE: int | None = None
|
373
375
|
|
374
376
|
def __init__(
|
375
377
|
self,
|
@@ -393,8 +395,8 @@ class RabbitMQServiceException(ServiceException):
|
|
393
395
|
|
394
396
|
if code is not None:
|
395
397
|
self._code = code
|
396
|
-
elif self.
|
397
|
-
self._code = self.
|
398
|
+
elif self.GENERAL_CODE is not None:
|
399
|
+
self._code = self.GENERAL_CODE
|
398
400
|
else:
|
399
401
|
self._code = 0
|
400
402
|
|
@@ -429,3 +431,114 @@ class RabbitMQRpcRequestPendingError(Exception):
|
|
429
431
|
|
430
432
|
class RabbitMQConnectionUnhealthyError(Exception):
|
431
433
|
pass
|
434
|
+
|
435
|
+
|
436
|
+
class KafkaDisconnectedError(Exception):
|
437
|
+
pass
|
438
|
+
|
439
|
+
|
440
|
+
class ServiceType(Enum):
|
441
|
+
HTTP = 0
|
442
|
+
RABBIT_MQ = 1
|
443
|
+
|
444
|
+
|
445
|
+
class GenericServiceExceptionFactory:
|
446
|
+
def __init__(
|
447
|
+
self,
|
448
|
+
message: str,
|
449
|
+
severity: Severity | None = None,
|
450
|
+
tags: list[str] | None = None,
|
451
|
+
extra: dict[str, str] | None = None,
|
452
|
+
remote_logging: bool = True,
|
453
|
+
extract_exc_info: bool = True,
|
454
|
+
):
|
455
|
+
self._message = message
|
456
|
+
self._severity = severity
|
457
|
+
self._tags = tags
|
458
|
+
self._extra = extra
|
459
|
+
self._remote_logging = remote_logging
|
460
|
+
self._extract_exc_info = extract_exc_info
|
461
|
+
|
462
|
+
self._http_service_error: type[HTTPServiceError] = InternalServerError
|
463
|
+
self._rabbitmq_service_exception: type[RabbitMQServiceException] = (
|
464
|
+
RabbitMQServiceException
|
465
|
+
)
|
466
|
+
|
467
|
+
self._body: Any | None = None
|
468
|
+
self._status_code: int | None = None
|
469
|
+
self._headers: dict[str, str] | None = None
|
470
|
+
self._response_code: int | None = None
|
471
|
+
self._corrective_action: str | None = None
|
472
|
+
self._code: int | None = None
|
473
|
+
self._data: Any | None = None
|
474
|
+
|
475
|
+
def for_http_service_error(
|
476
|
+
self, http_service_error: type[HTTPServiceError]
|
477
|
+
) -> Self:
|
478
|
+
self._http_service_error = http_service_error
|
479
|
+
|
480
|
+
return self
|
481
|
+
|
482
|
+
def for_rabbitmq_service_exception(
|
483
|
+
self, rabbitmq_service_exception: type[RabbitMQServiceException]
|
484
|
+
) -> Self:
|
485
|
+
self._rabbitmq_service_exception = rabbitmq_service_exception
|
486
|
+
|
487
|
+
return self
|
488
|
+
|
489
|
+
def with_http_service_error(
|
490
|
+
self,
|
491
|
+
body: Any | None = None,
|
492
|
+
status_code: int | None = None,
|
493
|
+
headers: dict[str, str] | None = None,
|
494
|
+
response_code: int | None = None,
|
495
|
+
corrective_action: str | None = None,
|
496
|
+
) -> Self:
|
497
|
+
self._body = body
|
498
|
+
self._status_code = status_code
|
499
|
+
self._headers = headers
|
500
|
+
self._response_code = response_code
|
501
|
+
self._corrective_action = corrective_action
|
502
|
+
|
503
|
+
return self
|
504
|
+
|
505
|
+
def with_rabbitmq_service_exception(
|
506
|
+
self,
|
507
|
+
code: int | None = None,
|
508
|
+
data: Any | None = None,
|
509
|
+
) -> Self:
|
510
|
+
self._code = code
|
511
|
+
self._data = data
|
512
|
+
|
513
|
+
return self
|
514
|
+
|
515
|
+
def create(self, service_type: ServiceType) -> ServiceException:
|
516
|
+
assert self._http_service_error is not None
|
517
|
+
assert self._rabbitmq_service_exception is not None
|
518
|
+
|
519
|
+
match service_type:
|
520
|
+
case ServiceType.HTTP:
|
521
|
+
return self._http_service_error(
|
522
|
+
message=self._message,
|
523
|
+
body=self._body,
|
524
|
+
status_code=self._status_code,
|
525
|
+
headers=self._headers,
|
526
|
+
response_code=self._response_code,
|
527
|
+
corrective_action=self._corrective_action,
|
528
|
+
severity=self._severity,
|
529
|
+
tags=self._tags,
|
530
|
+
extra=self._extra,
|
531
|
+
remote_logging=self._remote_logging,
|
532
|
+
extract_exc_info=self._extract_exc_info,
|
533
|
+
)
|
534
|
+
case ServiceType.RABBIT_MQ:
|
535
|
+
return self._rabbitmq_service_exception(
|
536
|
+
message=self._message,
|
537
|
+
code=self._code,
|
538
|
+
data=self._data,
|
539
|
+
severity=self._severity,
|
540
|
+
tags=self._tags,
|
541
|
+
extra=self._extra,
|
542
|
+
remote_logging=self._remote_logging,
|
543
|
+
extract_exc_info=self._extract_exc_info,
|
544
|
+
)
|
@@ -0,0 +1,90 @@
|
|
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
|
+
|
47
|
+
__all__ = [
|
48
|
+
"AbstractHttpExceptionHandler",
|
49
|
+
"api_controller",
|
50
|
+
"APIRouter",
|
51
|
+
"BackgroundTasks",
|
52
|
+
"Body",
|
53
|
+
"ControllerBase",
|
54
|
+
"Cookie",
|
55
|
+
"delete",
|
56
|
+
"Depends",
|
57
|
+
"File",
|
58
|
+
"FileResponse",
|
59
|
+
"Form",
|
60
|
+
"get",
|
61
|
+
"head",
|
62
|
+
"Header",
|
63
|
+
"HTMLResponse",
|
64
|
+
"HTTPException",
|
65
|
+
"HttpGeneralExceptionHandler",
|
66
|
+
"HTTPServiceExceptionHandler",
|
67
|
+
"JSONResponse",
|
68
|
+
"options",
|
69
|
+
"patch",
|
70
|
+
"Path",
|
71
|
+
"PlainTextResponse",
|
72
|
+
"post",
|
73
|
+
"put",
|
74
|
+
"Query",
|
75
|
+
"RedirectResponse",
|
76
|
+
"Request",
|
77
|
+
"RequestValidationErrorHandler",
|
78
|
+
"Response",
|
79
|
+
"Response",
|
80
|
+
"ROUTE_HANDLER_ATTRIBUTE",
|
81
|
+
"RouteHandlerMetadata",
|
82
|
+
"Security",
|
83
|
+
"status",
|
84
|
+
"StreamingResponse",
|
85
|
+
"trace",
|
86
|
+
"UploadFile",
|
87
|
+
"WebSocket",
|
88
|
+
"WebSocketDisconnect",
|
89
|
+
"WebSocketException",
|
90
|
+
]
|
@@ -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
|