qena-shared-lib 0.1.7__py3-none-any.whl → 0.1.8__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.
@@ -27,17 +27,18 @@ from punq import Container, Scope
27
27
  from pydantic import ValidationError
28
28
 
29
29
  from ..dependencies.miscellaneous import validate_annotation
30
- from ..exceptions import ServiceException
30
+ from ..exceptions import (
31
+ RabbitMQConnectionUnhealthyError,
32
+ ServiceException,
33
+ )
31
34
  from ..logging import LoggerProvider
32
35
  from ..logstash import BaseLogstashSender
33
36
  from ..utils import AsyncEventLoopMixin
34
37
  from ._exception_handlers import (
35
38
  handle_general_mq_exception,
36
- handle_microservice_exception,
37
- handle_rabbitmq_exception,
39
+ handle_rabbit_mq_service_exception,
38
40
  handle_validation_error,
39
41
  )
40
- from ._exceptions import RabbitMQException
41
42
  from ._listener import (
42
43
  LISTENER_ATTRIBUTE,
43
44
  Listener,
@@ -121,9 +122,10 @@ class RabbitMqManager(AsyncEventLoopMixin):
121
122
  type[Exception], ExceptionHandlerContainer
122
123
  ] = {}
123
124
 
124
- self.exception_handler(RabbitMQException)(handle_rabbitmq_exception)
125
+ self.exception_handler(ServiceException)(
126
+ handle_rabbit_mq_service_exception
127
+ )
125
128
  self.exception_handler(ValidationError)(handle_validation_error)
126
- self.exception_handler(ServiceException)(handle_microservice_exception)
127
129
  self.exception_handler(Exception)(handle_general_mq_exception)
128
130
 
129
131
  self._channel_pool = ChannelPool()
@@ -288,7 +290,7 @@ class RabbitMqManager(AsyncEventLoopMixin):
288
290
  @property
289
291
  def connection(self) -> AsyncioConnection:
290
292
  if not self._is_connection_healthy():
291
- raise RuntimeError("connection not ready yet")
293
+ raise RabbitMQConnectionUnhealthyError("connection not ready yet")
292
294
 
293
295
  assert self._connection is not None
294
296
 
@@ -302,7 +304,9 @@ class RabbitMqManager(AsyncEventLoopMixin):
302
304
  headers: dict[str, str] | None = None,
303
305
  ) -> Publisher:
304
306
  if not self._is_connection_healthy():
305
- raise RuntimeError("rabbitmq connection is not healthy")
307
+ raise RabbitMQConnectionUnhealthyError(
308
+ "rabbitmq connection is not healthy"
309
+ )
306
310
 
307
311
  return Publisher(
308
312
  routing_key=routing_key,
@@ -322,16 +326,15 @@ class RabbitMqManager(AsyncEventLoopMixin):
322
326
  return_type: type | None = None,
323
327
  timeout: float = 0,
324
328
  ) -> RpcClient:
325
- if timeout < 0:
326
- raise ValueError(f"timeout cannot below 0, got {timeout} seconds")
327
-
328
329
  if timeout == 0:
329
330
  self._logger.warning(
330
331
  "rpc call with 0 seconds timeout may never return back"
331
332
  )
332
333
 
333
334
  if not self._is_connection_healthy():
334
- raise RuntimeError("rabbitmq connection is not healthy")
335
+ raise RabbitMQConnectionUnhealthyError(
336
+ "rabbitmq connection is not healthy"
337
+ )
335
338
 
336
339
  return RpcClient(
337
340
  routing_key=routing_key,
@@ -341,7 +344,7 @@ class RabbitMqManager(AsyncEventLoopMixin):
341
344
  procedure=procedure,
342
345
  headers=headers,
343
346
  return_type=return_type,
344
- timeout=timeout,
347
+ timeout=abs(timeout),
345
348
  )
346
349
 
347
350
  def _is_connection_healthy(self) -> bool:
@@ -359,7 +362,7 @@ class RabbitMqManager(AsyncEventLoopMixin):
359
362
  self._disconnected = True
360
363
 
361
364
  if self._connection is None:
362
- raise RuntimeError("connection not ready yet")
365
+ raise RabbitMQConnectionUnhealthyError("connection not ready yet")
363
366
 
364
367
  if self._connection.is_closing or self._connection.is_closed:
365
368
  self._logger.info("already disconnected from rabbitmq")
@@ -411,7 +414,7 @@ class RabbitMqManager(AsyncEventLoopMixin):
411
414
  return
412
415
 
413
416
  if self._connection is None:
414
- raise RuntimeError("connection not ready yet")
417
+ raise RabbitMQConnectionUnhealthyError("connection not ready yet")
415
418
 
416
419
  self.loop.create_task(
417
420
  self._channel_pool.fill(self._connection)
@@ -464,7 +467,7 @@ class RabbitMqManager(AsyncEventLoopMixin):
464
467
  return
465
468
 
466
469
  if self._connection is None:
467
- raise RuntimeError("connection not ready yet")
470
+ raise RabbitMQConnectionUnhealthyError("connection not ready yet")
468
471
 
469
472
  channel_count = len(self._channel_pool)
470
473
 
@@ -537,7 +540,7 @@ class RabbitMqManager(AsyncEventLoopMixin):
537
540
  self._connected = True
538
541
 
539
542
  if self._connection is None:
540
- raise RuntimeError("connection not ready yet")
543
+ raise RabbitMQConnectionUnhealthyError("connection not ready yet")
541
544
 
542
545
  params = self._connection.params
543
546
  listener_count = len(self._listeners)
@@ -3,80 +3,26 @@ from typing import Annotated
3
3
  from pydantic import ValidationError
4
4
 
5
5
  from ..dependencies.miscellaneous import DependsOn
6
- from ..exceptions import ServiceException, Severity
6
+ from ..exceptions import (
7
+ HTTPServiceError,
8
+ RabbitMQServiceException,
9
+ ServiceException,
10
+ Severity,
11
+ )
7
12
  from ..logging import LoggerProvider
8
13
  from ..logstash._base import BaseLogstashSender
9
- from ._exceptions import RabbitMQException
10
14
  from ._listener import ListenerContext
11
15
 
12
16
  __all__ = [
13
17
  "handle_general_mq_exception",
14
- "handle_microservice_exception",
15
- "handle_rabbitmq_exception",
18
+ "handle_rabbit_mq_service_exception",
16
19
  "handle_validation_error",
17
20
  ]
18
21
 
19
22
  RABBITMQ_EXCEPTION_HANDLER_LOGGER_NAME = "rabbitmq.exception_handler"
20
23
 
21
24
 
22
- def handle_rabbitmq_exception(
23
- context: ListenerContext,
24
- exception: RabbitMQException,
25
- logstash: Annotated[BaseLogstashSender, DependsOn(BaseLogstashSender)],
26
- logger_provider: Annotated[LoggerProvider, DependsOn(LoggerProvider)],
27
- ):
28
- logger = logger_provider.get_logger(RABBITMQ_EXCEPTION_HANDLER_LOGGER_NAME)
29
-
30
- if not exception.logstash_logging:
31
- logger.warning("%r", exception)
32
-
33
- return
34
-
35
- logstash.warning(
36
- message=exception.message,
37
- tags=exception.tags
38
- or [
39
- "RabbitMQ",
40
- "RabbitMQException",
41
- str(exception.code),
42
- context.queue,
43
- context.listener_name or "__default__",
44
- ],
45
- extra=exception.extra
46
- or {
47
- "serviceType": "RabbitMQ",
48
- "queue": context.queue,
49
- "listenerName": context.listener_name,
50
- "exception": "RabbitMQException",
51
- },
52
- exception=exception,
53
- )
54
-
55
-
56
- def handle_validation_error(
57
- context: ListenerContext,
58
- exception: ValidationError,
59
- logstash: Annotated[BaseLogstashSender, DependsOn(BaseLogstashSender)],
60
- ):
61
- logstash.error(
62
- message=f"invalid rabbitmq request data at queue `{context.queue}` and listener `{context.listener_name}`",
63
- tags=[
64
- "RabbitMQ",
65
- "ValidationError",
66
- context.queue,
67
- context.listener_name or "__default__",
68
- ],
69
- extra={
70
- "serviceType": "RabbitMQ",
71
- "queue": context.queue,
72
- "listenerName": context.listener_name,
73
- "exception": "ValidationError",
74
- },
75
- exception=exception,
76
- )
77
-
78
-
79
- def handle_microservice_exception(
25
+ def handle_rabbit_mq_service_exception(
80
26
  context: ListenerContext,
81
27
  exception: ServiceException,
82
28
  logstash: Annotated[BaseLogstashSender, DependsOn(BaseLogstashSender)],
@@ -85,14 +31,10 @@ def handle_microservice_exception(
85
31
  logger = logger_provider.get_logger(RABBITMQ_EXCEPTION_HANDLER_LOGGER_NAME)
86
32
  tags = [
87
33
  "RabbitMQ",
88
- type(exception).__name__,
89
34
  context.queue,
90
35
  context.listener_name or "__default__",
36
+ exception.__class__.__name__,
91
37
  ]
92
-
93
- if exception.tags:
94
- exception.tags.extend(tags)
95
-
96
38
  extra = {
97
39
  "serviceType": "RabbitMQ",
98
40
  "queue": context.queue,
@@ -100,8 +42,30 @@ def handle_microservice_exception(
100
42
  "exception": exception.__class__.__name__,
101
43
  }
102
44
 
45
+ match exception:
46
+ case HTTPServiceError() as http_service_error:
47
+ if http_service_error.status_code is not None:
48
+ str_status_code = str(http_service_error.status_code)
49
+ extra["statusCode"] = str_status_code
50
+
51
+ tags.append(str_status_code)
52
+
53
+ if http_service_error.response_code is not None:
54
+ str_response_code = str(http_service_error.response_code)
55
+ extra["responseCode"] = str_response_code
56
+
57
+ tags.append(str_response_code)
58
+ case RabbitMQServiceException() as rabbitmq_service_exception:
59
+ str_error_code = str(rabbitmq_service_exception.code)
60
+ extra["code"] = str_error_code
61
+
62
+ tags.append(str_error_code)
63
+
64
+ if exception.tags:
65
+ tags.extend(exception.tags)
66
+
103
67
  if exception.extra:
104
- exception.extra.update(extra)
68
+ extra.update(exception.extra)
105
69
 
106
70
  exc_info = (
107
71
  (type(exception), exception, exception.__traceback__)
@@ -137,6 +101,29 @@ def handle_microservice_exception(
137
101
  )
138
102
 
139
103
 
104
+ def handle_validation_error(
105
+ context: ListenerContext,
106
+ exception: ValidationError,
107
+ logstash: Annotated[BaseLogstashSender, DependsOn(BaseLogstashSender)],
108
+ ):
109
+ logstash.error(
110
+ message=f"invalid rabbitmq request data at queue `{context.queue}` and listener `{context.listener_name}`",
111
+ tags=[
112
+ "RabbitMQ",
113
+ context.queue,
114
+ context.listener_name or "__default__",
115
+ "ValidationError",
116
+ ],
117
+ extra={
118
+ "serviceType": "RabbitMQ",
119
+ "queue": context.queue,
120
+ "listenerName": context.listener_name,
121
+ "exception": "ValidationError",
122
+ },
123
+ exception=exception,
124
+ )
125
+
126
+
140
127
  def handle_general_mq_exception(
141
128
  context: ListenerContext,
142
129
  exception: Exception,
@@ -146,9 +133,9 @@ def handle_general_mq_exception(
146
133
  message=f"something went wrong while consuming message on queue `{context.queue}` and listener `{context.listener_name}`",
147
134
  tags=[
148
135
  "RabbitMQ",
149
- exception.__class__.__name__,
150
136
  context.queue,
151
137
  context.listener_name or "__default__",
138
+ exception.__class__.__name__,
152
139
  ],
153
140
  extra={
154
141
  "serviceType": "RabbitMQ",
@@ -19,11 +19,11 @@ from pydantic import ValidationError
19
19
  from pydantic_core import from_json, to_json
20
20
 
21
21
  from ..dependencies.miscellaneous import validate_annotation
22
+ from ..exceptions import RabbitMQServiceException
22
23
  from ..logging import LoggerProvider
23
24
  from ..logstash import BaseLogstashSender
24
25
  from ..utils import AsyncEventLoopMixin, TypeAdapterCache
25
26
  from ._channel import BaseChannel
26
- from ._exceptions import RabbitMQException
27
27
  from ._pool import ChannelPool
28
28
 
29
29
  __all__ = [
@@ -184,6 +184,7 @@ class RetryPolicy:
184
184
  max_retry: int
185
185
  retry_delay_strategy: RetryDelayStrategy
186
186
  retry_delay_jitter: RetryDelayJitter | None = None
187
+ match_by_cause: bool = False
187
188
 
188
189
  def can_retry(self, times_rejected: int) -> bool:
189
190
  return times_rejected < self.max_retry
@@ -756,9 +757,18 @@ class Listener(AsyncEventLoopMixin):
756
757
  or self._global_retry_policy
757
758
  )
758
759
 
759
- if retry_policy is not None and any(
760
- exception_type in retry_policy.exceptions
761
- for exception_type in type(exception).mro()
760
+ if retry_policy is not None and (
761
+ self._is_recoverable_exception(
762
+ exception=exception,
763
+ retry_policy_exceptions=retry_policy.exceptions,
764
+ )
765
+ or (
766
+ retry_policy.match_by_cause
767
+ and self._has_recoverable_cause(
768
+ exception=exception,
769
+ retry_policy_exceptions=retry_policy.exceptions,
770
+ )
771
+ )
762
772
  ):
763
773
  times_rejected = None
764
774
 
@@ -824,6 +834,43 @@ class Listener(AsyncEventLoopMixin):
824
834
  queue=self._queue, listener_name=listener_message_meta.listener_name
825
835
  ).observe(listener_message_meta.listener_start_time - time())
826
836
 
837
+ def _is_recoverable_exception(
838
+ self,
839
+ exception: BaseException,
840
+ retry_policy_exceptions: Collection[type[Exception]],
841
+ ) -> bool:
842
+ return self._in_retry_policy_exceptions(
843
+ exception=exception, retry_policy_exceptions=retry_policy_exceptions
844
+ )
845
+
846
+ def _has_recoverable_cause(
847
+ self,
848
+ exception: BaseException,
849
+ retry_policy_exceptions: Collection[type[Exception]],
850
+ ) -> bool:
851
+ cause = exception.__cause__ or exception.__context__
852
+
853
+ while cause is not None:
854
+ if self._in_retry_policy_exceptions(
855
+ exception=cause,
856
+ retry_policy_exceptions=retry_policy_exceptions,
857
+ ):
858
+ return True
859
+
860
+ cause = cause.__cause__ or exception.__context__
861
+
862
+ return False
863
+
864
+ def _in_retry_policy_exceptions(
865
+ self,
866
+ exception: BaseException,
867
+ retry_policy_exceptions: Collection[type[Exception]],
868
+ ) -> bool:
869
+ return any(
870
+ exception_type in retry_policy_exceptions
871
+ for exception_type in type(exception).mro()
872
+ )
873
+
827
874
  def _call_exception_callback(
828
875
  self,
829
876
  exception: BaseException,
@@ -1035,20 +1082,24 @@ class Listener(AsyncEventLoopMixin):
1035
1082
 
1036
1083
  def _reponse_from_exception(self, exception: BaseException) -> dict:
1037
1084
  match exception:
1038
- case RabbitMQException() as rabbitmq_exception:
1085
+ case RabbitMQServiceException() as rabbitmq_exception:
1039
1086
  code = rabbitmq_exception.code
1040
1087
  message = rabbitmq_exception.message
1088
+ data = rabbitmq_exception.data
1041
1089
  case ValidationError() as validation_error:
1042
1090
  code = 0
1043
- message = validation_error.json()
1091
+ message = validation_error.title
1092
+ data = validation_error.json()
1044
1093
  case unknown_execption:
1045
1094
  code = 0
1046
1095
  message = str(unknown_execption)
1096
+ data = None
1047
1097
 
1048
1098
  return {
1049
1099
  "exception": True,
1050
1100
  "code": code,
1051
1101
  "message": message,
1102
+ "data": data,
1052
1103
  }
1053
1104
 
1054
1105
  def _on_reply_channel_found(
@@ -1137,6 +1188,38 @@ class Consumer(Listener):
1137
1188
  return wrapper
1138
1189
 
1139
1190
 
1191
+ def consumer(
1192
+ queue: str,
1193
+ prefetch_count: int = 250,
1194
+ retry_policy: RetryPolicy | None = None,
1195
+ ) -> Consumer:
1196
+ return Consumer(
1197
+ queue=queue,
1198
+ prefetch_count=prefetch_count,
1199
+ retry_policy=retry_policy,
1200
+ )
1201
+
1202
+
1203
+ def consume(
1204
+ target: str | None = None, retry_policy: RetryPolicy | None = None
1205
+ ) -> Callable[[Callable], Callable]:
1206
+ def wrapper(consumer_method: Callable) -> Callable:
1207
+ if not callable(consumer_method):
1208
+ raise TypeError(
1209
+ f"consumer method argument not a callable, got {type(consumer_method)}"
1210
+ )
1211
+
1212
+ setattr(
1213
+ consumer_method,
1214
+ CONSUMER_ATTRIBUTE,
1215
+ ListenerMethodMeta(listener_name=target, retry_policy=retry_policy),
1216
+ )
1217
+
1218
+ return consumer_method
1219
+
1220
+ return wrapper
1221
+
1222
+
1140
1223
  class RpcWorker(Listener):
1141
1224
  def __init__(self, queue: str, prefetch_count: int = 250):
1142
1225
  super().__init__(
@@ -1166,6 +1249,26 @@ class RpcWorker(Listener):
1166
1249
  return wrapper
1167
1250
 
1168
1251
 
1252
+ def rpc_worker(queue: str, prefetch_count: int = 250) -> RpcWorker:
1253
+ return RpcWorker(queue=queue, prefetch_count=prefetch_count)
1254
+
1255
+
1256
+ def execute(procedure: str | None = None) -> Callable[[Callable], Callable]:
1257
+ def wrapper(worker_method: Callable) -> Callable:
1258
+ if not callable(worker_method):
1259
+ raise TypeError(
1260
+ f"worker method argument not a callable, got {type(worker_method)}"
1261
+ )
1262
+
1263
+ setattr(
1264
+ worker_method, RPC_WORKER_ATTRIBUTE, ListenerMethodMeta(procedure)
1265
+ )
1266
+
1267
+ return worker_method
1268
+
1269
+ return wrapper
1270
+
1271
+
1169
1272
  @dataclass
1170
1273
  class ListenerMethodMeta:
1171
1274
  listener_name: str | None = None
@@ -1253,39 +1356,3 @@ class ListenerBase:
1253
1356
  )
1254
1357
 
1255
1358
  return listener_method_attribute, attribute, listener_method_meta
1256
-
1257
-
1258
- def consume(
1259
- target: str | None = None, retry_policy: RetryPolicy | None = None
1260
- ) -> Callable[[Callable], Callable]:
1261
- def wrapper(consumer_method: Callable) -> Callable:
1262
- if not callable(consumer_method):
1263
- raise TypeError(
1264
- f"consumer method argument not a callable, got {type(consumer_method)}"
1265
- )
1266
-
1267
- setattr(
1268
- consumer_method,
1269
- CONSUMER_ATTRIBUTE,
1270
- ListenerMethodMeta(listener_name=target, retry_policy=retry_policy),
1271
- )
1272
-
1273
- return consumer_method
1274
-
1275
- return wrapper
1276
-
1277
-
1278
- def execute(procedure: str | None = None) -> Callable[[Callable], Callable]:
1279
- def wrapper(worker_method: Callable) -> Callable:
1280
- if not callable(worker_method):
1281
- raise TypeError(
1282
- f"worker method argument not a callable, got {type(worker_method)}"
1283
- )
1284
-
1285
- setattr(
1286
- worker_method, RPC_WORKER_ATTRIBUTE, ListenerMethodMeta(procedure)
1287
- )
1288
-
1289
- return worker_method
1290
-
1291
- return wrapper
@@ -4,6 +4,7 @@ from pika import BasicProperties
4
4
  from prometheus_client import Counter
5
5
  from pydantic_core import to_json
6
6
 
7
+ from ..exceptions import RabbitMQBlockedError
7
8
  from ..logging import LoggerProvider
8
9
  from ._pool import ChannelPool
9
10
 
@@ -47,7 +48,7 @@ class Publisher:
47
48
 
48
49
  async def _get_channel_and_publish(self, message: Any):
49
50
  if self._blocked_connection_check_callback():
50
- raise RuntimeError(
51
+ raise RabbitMQBlockedError(
51
52
  "rabbitmq broker is not able to accept message right now"
52
53
  )
53
54
 
@@ -12,9 +12,14 @@ from pika.spec import Basic
12
12
  from prometheus_client import Counter, Summary
13
13
  from pydantic_core import from_json, to_json
14
14
 
15
+ from ..exceptions import (
16
+ RabbitMQBlockedError,
17
+ RabbitMQRpcRequestPendingError,
18
+ RabbitMQRpcRequestTimeoutError,
19
+ RabbitMQServiceException,
20
+ )
15
21
  from ..logging import LoggerProvider
16
22
  from ..utils import AsyncEventLoopMixin, TypeAdapterCache
17
- from ._exceptions import RabbitMQException
18
23
  from ._pool import ChannelPool
19
24
 
20
25
  __all__ = ["RpcClient"]
@@ -97,7 +102,7 @@ class RpcClient(AsyncEventLoopMixin):
97
102
  procedure: str | None = None,
98
103
  headers: dict[str, str] | None = None,
99
104
  return_type: type | None = None,
100
- timeout: float = 0,
105
+ timeout: float = 15,
101
106
  ):
102
107
  self._routing_key = routing_key
103
108
  self._exchange = exchange or ""
@@ -130,13 +135,15 @@ class RpcClient(AsyncEventLoopMixin):
130
135
 
131
136
  async def _get_channel_and_call(self, message: Any) -> Any:
132
137
  if self._blocked_connection_check_callback():
133
- raise RuntimeError(
138
+ raise RabbitMQBlockedError(
134
139
  "rabbitmq broker is not able to accept message right now"
135
140
  )
136
141
 
137
142
  async with self._rpc_call_lock:
138
143
  if self._rpc_call_pending:
139
- raise RuntimeError("previous rpc request not done yet")
144
+ raise RabbitMQRpcRequestPendingError(
145
+ "previous rpc request not done yet"
146
+ )
140
147
 
141
148
  self._rpc_call_pending = True
142
149
 
@@ -200,7 +207,7 @@ class RpcClient(AsyncEventLoopMixin):
200
207
 
201
208
  def _on_timeout(self):
202
209
  self._finalize_call(
203
- exception=TimeoutError(
210
+ exception=RabbitMQRpcRequestTimeoutError(
204
211
  f"rpc worker didn't responed in a timely manner within `{self._timeout}` seconds"
205
212
  )
206
213
  )
@@ -232,7 +239,7 @@ class RpcClient(AsyncEventLoopMixin):
232
239
 
233
240
  if isinstance(response, dict) and "exception" in response:
234
241
  self._finalize_call(
235
- exception=RabbitMQException(
242
+ exception=RabbitMQServiceException(
236
243
  code=response.get("code") or 0,
237
244
  message=response.get("message")
238
245
  or "unknown error occured from the rpc worker side",
@@ -20,6 +20,7 @@ from .utils import AsyncEventLoopMixin
20
20
  __all__ = [
21
21
  "schedule",
22
22
  "ScheduleManager",
23
+ "scheduler",
23
24
  "Scheduler",
24
25
  "SchedulerBase",
25
26
  ]
@@ -108,6 +109,10 @@ class Scheduler:
108
109
  return self._scheduled_tasks
109
110
 
110
111
 
112
+ def scheduler() -> Scheduler:
113
+ return Scheduler()
114
+
115
+
111
116
  @dataclass
112
117
  class ScheduledTaskMeta:
113
118
  cron_expression: str
@@ -15,7 +15,7 @@ from .exceptions import Unauthorized
15
15
  from .utils import AsyncEventLoopMixin
16
16
 
17
17
  __all__ = [
18
- "EndpointACL",
18
+ "Authorization",
19
19
  "get_int_from_datetime",
20
20
  "get_time_from_int",
21
21
  "jwk_from_dict",
@@ -137,7 +137,7 @@ class PermissionMatch(Enum):
137
137
  ALL = 1
138
138
 
139
139
 
140
- def EndpointACL(
140
+ def Authorization(
141
141
  user_type: str | None = None,
142
142
  permissions: list[str] | None = None,
143
143
  permission_match_strategy: PermissionMatch | None = None,
@@ -186,7 +186,7 @@ class EndpointAclValidator:
186
186
  tags=[user_info.user_id],
187
187
  extra={
188
188
  "userId": user_info.user_id,
189
- "userYype": user_info.user_type,
189
+ "userType": user_info.user_type,
190
190
  "userPermissions": str(user_info.user_permissions or []),
191
191
  "requiredUserType": self._user_type or "None",
192
192
  "requiredPermissions": str(self._permissions or []),
@@ -1,18 +1,17 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qena-shared-lib
3
- Version: 0.1.7
3
+ Version: 0.1.8
4
4
  Summary: A shared tools for other services
5
5
  Requires-Python: >=3.10
6
- Requires-Dist: cronsim~=2.0
7
- Requires-Dist: fastapi[all]~=0.115.0
8
- Requires-Dist: httpx~=0.27.0
9
- Requires-Dist: jwt~=1.3.0
10
- Requires-Dist: passlib[bcrypt]~=1.7.0
11
- Requires-Dist: pika~=1.3.0
12
- Requires-Dist: prometheus-client~=0.21.0
13
- Requires-Dist: prometheus-fastapi-instrumentator~=7.0.0
14
- Requires-Dist: punq~=0.7.0
15
- Requires-Dist: pydantic~=2.10.0
6
+ Requires-Dist: cronsim==2.6
7
+ Requires-Dist: fastapi[all]==0.115.6
8
+ Requires-Dist: httpx==0.27.2
9
+ Requires-Dist: jwt==1.3.1
10
+ Requires-Dist: passlib[bcrypt]==1.7.4
11
+ Requires-Dist: pika==1.3.2
12
+ Requires-Dist: prometheus-client==0.21.1
13
+ Requires-Dist: prometheus-fastapi-instrumentator==7.0.2
14
+ Requires-Dist: punq==0.7.0
16
15
  Description-Content-Type: text/markdown
17
16
 
18
17
  # Qena shared lib