qena-shared-lib 0.1.7__tar.gz → 0.1.9__tar.gz

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.
Files changed (44) hide show
  1. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/.pre-commit-config.yaml +9 -1
  2. qena_shared_lib-0.1.7/README.md → qena_shared_lib-0.1.9/PKG-INFO +161 -11
  3. qena_shared_lib-0.1.7/PKG-INFO → qena_shared_lib-0.1.9/README.md +145 -28
  4. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/pyproject.toml +15 -16
  5. qena_shared_lib-0.1.9/requirements.txt +55 -0
  6. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/src/qena_shared_lib/application.py +2 -2
  7. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/src/qena_shared_lib/exception_handlers.py +69 -44
  8. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/src/qena_shared_lib/exceptions.py +187 -85
  9. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/src/qena_shared_lib/http.py +20 -20
  10. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/src/qena_shared_lib/logstash/_base.py +2 -2
  11. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/src/qena_shared_lib/rabbitmq/__init__.py +6 -6
  12. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/src/qena_shared_lib/rabbitmq/_base.py +20 -17
  13. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/src/qena_shared_lib/rabbitmq/_exception_handlers.py +58 -71
  14. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/src/qena_shared_lib/rabbitmq/_listener.py +109 -42
  15. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/src/qena_shared_lib/rabbitmq/_publisher.py +2 -1
  16. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/src/qena_shared_lib/rabbitmq/_rpc_client.py +13 -6
  17. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/src/qena_shared_lib/scheduler.py +5 -0
  18. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/src/qena_shared_lib/security.py +3 -3
  19. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/tests/test_application.py +13 -13
  20. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/tests/test_logstash.py +50 -16
  21. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/tests/test_rabbitmq.py +109 -32
  22. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/tests/test_scheduler.py +3 -2
  23. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/tests/test_security.py +20 -18
  24. qena_shared_lib-0.1.9/tests/utils.py +5 -0
  25. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/uv.lock +16 -18
  26. qena_shared_lib-0.1.7/requirements.txt +0 -18
  27. qena_shared_lib-0.1.7/src/qena_shared_lib/rabbitmq/_exceptions.py +0 -46
  28. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/.gitignore +0 -0
  29. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/src/qena_shared_lib/__init__.py +0 -0
  30. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/src/qena_shared_lib/background.py +0 -0
  31. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/src/qena_shared_lib/dependencies/__init__.py +0 -0
  32. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/src/qena_shared_lib/dependencies/http.py +0 -0
  33. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/src/qena_shared_lib/dependencies/miscellaneous.py +0 -0
  34. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/src/qena_shared_lib/logging.py +0 -0
  35. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/src/qena_shared_lib/logstash/__init__.py +0 -0
  36. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/src/qena_shared_lib/logstash/_http_sender.py +0 -0
  37. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/src/qena_shared_lib/logstash/_tcp_sender.py +0 -0
  38. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/src/qena_shared_lib/py.typed +0 -0
  39. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/src/qena_shared_lib/rabbitmq/_channel.py +0 -0
  40. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/src/qena_shared_lib/rabbitmq/_pool.py +0 -0
  41. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/src/qena_shared_lib/utils.py +0 -0
  42. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/tests/conftest.py +0 -0
  43. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/tests/test_background.py +0 -0
  44. {qena_shared_lib-0.1.7 → qena_shared_lib-0.1.9}/tests/test_dependencies.py +0 -0
@@ -5,9 +5,17 @@ repos:
5
5
  - id: check-yaml
6
6
  - id: end-of-file-fixer
7
7
  - id: trailing-whitespace
8
+ - id: check-toml
9
+ - id: name-tests-test
10
+ args: [ --pytest-test-first ]
11
+ - id: check-added-large-files
8
12
  - repo: https://github.com/astral-sh/ruff-pre-commit
9
- rev: v0.9.2
13
+ rev: v0.9.9
10
14
  hooks:
11
15
  - id: ruff
12
16
  args: [ --fix ]
13
17
  - id: ruff-format
18
+ - repo: https://github.com/pre-commit/mirrors-mypy
19
+ rev: v1.15.0
20
+ hooks:
21
+ - id: mypy
@@ -1,3 +1,19 @@
1
+ Metadata-Version: 2.4
2
+ Name: qena-shared-lib
3
+ Version: 0.1.9
4
+ Summary: A shared tools for other services
5
+ Requires-Python: >=3.10
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
15
+ Description-Content-Type: text/markdown
16
+
1
17
  # Qena shared lib
2
18
 
3
19
  A shared tools for other services. It includes.
@@ -24,6 +40,9 @@ A shared tools for other services. It includes.
24
40
  To create fastapi app.
25
41
 
26
42
  ``` py
43
+ from qena_shared_lib.application import Builder, Environment
44
+
45
+
27
46
  def main() -> FastAPI:
28
47
  builder = (
29
48
  Builder()
@@ -47,6 +66,11 @@ $ uvicorn --factory main:main
47
66
  ### Lifespan
48
67
 
49
68
  ``` py
69
+ from contextlib import asynccontextmanager
70
+
71
+ from fastapi import FastAPI
72
+
73
+
50
74
  @asynccontextmanager
51
75
  def lifespan(app: FastAPI):
52
76
  ...
@@ -67,6 +91,16 @@ def main() -> FastAPI:
67
91
  ### Dependencies
68
92
 
69
93
  ``` py
94
+ class EmailService:
95
+ def __init__(self):
96
+ ...
97
+
98
+
99
+ class Database:
100
+ def __init__(self):
101
+ ...
102
+
103
+
70
104
  def main() -> FastAPI:
71
105
  ...
72
106
 
@@ -79,7 +113,10 @@ def main() -> FastAPI:
79
113
  ### Controllers
80
114
 
81
115
  ``` py
82
- @ApiController("/users")
116
+ from qena_shared_lib.http import ControllerBase, api_controller, post
117
+
118
+
119
+ @api_controller("/users")
83
120
  class UserController(ControllerBase):
84
121
 
85
122
  def __init__(self, email_service: EmailService):
@@ -96,11 +133,18 @@ def main() -> FastAPI:
96
133
  builder.with_controllers([
97
134
  UserController
98
135
  ])
136
+
137
+ ...
99
138
  ```
100
139
 
101
140
  ### Routers
102
141
 
103
142
  ``` py
143
+ from fastapi import APIRouter
144
+
145
+ from qena_shared_lib.dependencies.http import DependsOn
146
+
147
+
104
148
  router = APIRouter(prefix="/auth")
105
149
 
106
150
 
@@ -137,6 +181,9 @@ def main() -> FastAPI:
137
181
  ## Logstash
138
182
 
139
183
  ``` py
184
+ from qena_shared_lib.logstash import BaseLogstashSender, HTTPSender, # TCPSender
185
+
186
+
140
187
  @asynccontextmanager
141
188
  async def lifespan(app: FastAPI):
142
189
  logstash = get_service(BaseLogstashSender)
@@ -187,6 +234,9 @@ def log_message(
187
234
  To create rabbitmq connection manager.
188
235
 
189
236
  ``` py
237
+ from qena_shared_lib.rabbitmq import ListenerBase, consume, consumer
238
+
239
+
190
240
  @asynccontextmanager
191
241
  async def lifespan(app: FastAPI):
192
242
  rabbitmq = get_service(RabbitMqManager)
@@ -198,7 +248,7 @@ async def lifespan(app: FastAPI):
198
248
  rabbitmq.disconnect()
199
249
 
200
250
 
201
- @Consumer("UserQueue")
251
+ @consumer("UserQueue")
202
252
  class UserConsumer(ListenerBase):
203
253
 
204
254
  def __init__(self, db: Database):
@@ -233,7 +283,7 @@ def main() -> FastAPI:
233
283
  async def store_user(
234
284
  rabbitmq: Annotated[
235
285
  RabbitMqManager,
236
- DependsOne(RabbitMqManager)
286
+ DependsOn(RabbitMqManager)
237
287
  ],
238
288
  user: User,
239
289
  )
@@ -250,7 +300,7 @@ async def store_user(
250
300
  async def get_user(
251
301
  rabbitmq: Annotated[
252
302
  RabbitMqManager,
253
- DependsOne(RabbitMqManager)
303
+ DependsOn(RabbitMqManager)
254
304
  ],
255
305
  user_id: str,
256
306
  )
@@ -265,7 +315,10 @@ async def get_user(
265
315
  ### Flow control
266
316
 
267
317
  ``` py
268
- @Consumer("UserQueue")
318
+ from qena_shared_lib.rabbitmq import ... , ListenerContext
319
+
320
+
321
+ @consumer("UserQueue")
269
322
  class UserConsumer(ListenerBase):
270
323
 
271
324
  @consume()
@@ -283,7 +336,10 @@ class UserConsumer(ListenerBase):
283
336
  Optionally it is possible to reply to rpc calls, through.
284
337
 
285
338
  ``` py
286
- @RpcWorker("UserQueue")
339
+ from qena_shared_lib.rabbitmq import ... , rpc_worker
340
+
341
+
342
+ @rpc_worker("UserQueue")
287
343
  class UserWorker(ListenerBase):
288
344
 
289
345
  @execute()
@@ -295,10 +351,92 @@ class UserWorker(ListenerBase):
295
351
  ...
296
352
  ```
297
353
 
354
+ ### Retry consumer
355
+
356
+ Consumer can retry to consumer a message in an event of failure.
357
+
358
+ ``` py
359
+ from qena_shared_lib.rabbitmq import (
360
+ BackoffRetryDelay,
361
+ FixedRetryDelay,
362
+ RabbitMqManager,
363
+ RetryDelayJitter,
364
+ RetryPolicy,
365
+ )
366
+
367
+
368
+ @consumer(
369
+ queue="UserQueue",
370
+ # can be defined for consumer of specific queue
371
+ retry_policy=RetryPolicy(
372
+ exceptions=(AMQPError,),
373
+ max_retry=5,
374
+ retry_delay_strategy=FixedRetryDelay(
375
+ retry_delay=2
376
+ ),
377
+ retry_delay_jitter=RetryDelayJitter(min=0.5, max=5.0),
378
+ )
379
+ )
380
+ class UserConsumer(ListenerBase):
381
+
382
+ @consume(
383
+ # for specific target
384
+ retry_policy=RetryPolicy(
385
+ exceptions=(AMQPError,),
386
+ max_retry=5,
387
+ retry_delay_strategy=FixedRetryDelay(
388
+ retry_delay=2
389
+ ),
390
+ retry_delay_jitter=RetryDelayJitter(min=0.5, max=5.0),
391
+ )
392
+ )
393
+ async def store_user(self, ctx: ListenerContext, user: User):
394
+ ...
395
+
396
+ await ctx.flow_control.request(10)
397
+
398
+ ...
399
+
400
+
401
+ def main() -> FastAPI:
402
+ ...
403
+
404
+ rabbitmq = RabbitMqManager(
405
+ logstash=logstash,
406
+ container=builder.container,
407
+ # or globally for all consumers
408
+ listener_global_retry_policy=RetryPolicy(
409
+ exceptions=(AMQPError,),
410
+ max_retry=10,
411
+ retry_delay_strategy=BackoffRetryDelay(
412
+ multiplier=1.5, min=2, max=10
413
+ ),
414
+ retry_delay_jitter=RetryDelayJitter(min=0.5, max=5.0),
415
+ match_by_cause=True,
416
+ ),
417
+ )
418
+
419
+ rabbitmq.include_listener(UserConsumer)
420
+ builder.add_singleton(
421
+ service=RabbitMqManager,
422
+ instance=rabbitmq,
423
+ )
424
+ ```
425
+
426
+
298
427
 
299
428
  ## Scheduler
300
429
 
301
430
  ``` py
431
+ from qena_shared_lib.scheduler import (
432
+ ScheduleManager,
433
+ # Scheduler,
434
+ SchedulerBase,
435
+ schedule,
436
+ scheduler,
437
+ )
438
+
439
+
302
440
  @asynccontextmanager
303
441
  async def lifespan(app: FastAPI):
304
442
  schedule_manager = get_service(ScheduleManager)
@@ -310,7 +448,7 @@ async def lifespan(app: FastAPI):
310
448
  schedule_manager.stop()
311
449
 
312
450
 
313
- @Scheduler()
451
+ @scheduler()
314
452
  class TaskScheduler(SchedulerBase):
315
453
 
316
454
  def __init__(self, db: Database)
@@ -351,6 +489,9 @@ def main() -> FastAPI:
351
489
  ## Background
352
490
 
353
491
  ``` py
492
+ from qena_shared_lib.background import Background
493
+
494
+
354
495
  @asynccontextmanager
355
496
  async def lifespan(app: FastAPI):
356
497
  background = get_service(Background)
@@ -394,7 +535,10 @@ async def process_data(
394
535
  ### Password hasher
395
536
 
396
537
  ``` py
397
- @ApiController("/users")
538
+ from qena_shared_lib.security import PasswordHasher
539
+
540
+
541
+ @api_controller("/users")
398
542
  class UserController(ControllerBase):
399
543
 
400
544
  def __init__(self, password_hasher: PasswordHasher):
@@ -423,6 +567,9 @@ def main() -> FastAPI:
423
567
  ### JWT
424
568
 
425
569
  ``` py
570
+ from qena_shared_lib.security import JwtAdapter
571
+
572
+
426
573
  @ApiController("/users")
427
574
  class UserController(ControllerBase):
428
575
 
@@ -462,7 +609,10 @@ def main() -> FastAPI:
462
609
  ### ACL
463
610
 
464
611
  ``` py
465
- @ApiController("/users")
612
+ from qena_shared_lib.security import Authorization
613
+
614
+
615
+ @api_controller("/users")
466
616
  class UserController(ControllerBase):
467
617
 
468
618
  @post()
@@ -470,7 +620,7 @@ class UserController(ControllerBase):
470
620
  self,
471
621
  user: Annotated[
472
622
  UserInfo,
473
- EndpointACL(
623
+ Authorization(
474
624
  user_type="ADMIN",
475
625
  persmission=[
476
626
  "READ"
@@ -485,7 +635,7 @@ class UserController(ControllerBase):
485
635
  async def get_users(
486
636
  user: Annotated[
487
637
  UserInfo,
488
- EndpointACL("ADMIN")
638
+ Authorization("ADMIN")
489
639
  ]
490
640
  )
491
641
  ...
@@ -1,20 +1,3 @@
1
- Metadata-Version: 2.4
2
- Name: qena-shared-lib
3
- Version: 0.1.7
4
- Summary: A shared tools for other services
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
16
- Description-Content-Type: text/markdown
17
-
18
1
  # Qena shared lib
19
2
 
20
3
  A shared tools for other services. It includes.
@@ -41,6 +24,9 @@ A shared tools for other services. It includes.
41
24
  To create fastapi app.
42
25
 
43
26
  ``` py
27
+ from qena_shared_lib.application import Builder, Environment
28
+
29
+
44
30
  def main() -> FastAPI:
45
31
  builder = (
46
32
  Builder()
@@ -64,6 +50,11 @@ $ uvicorn --factory main:main
64
50
  ### Lifespan
65
51
 
66
52
  ``` py
53
+ from contextlib import asynccontextmanager
54
+
55
+ from fastapi import FastAPI
56
+
57
+
67
58
  @asynccontextmanager
68
59
  def lifespan(app: FastAPI):
69
60
  ...
@@ -84,6 +75,16 @@ def main() -> FastAPI:
84
75
  ### Dependencies
85
76
 
86
77
  ``` py
78
+ class EmailService:
79
+ def __init__(self):
80
+ ...
81
+
82
+
83
+ class Database:
84
+ def __init__(self):
85
+ ...
86
+
87
+
87
88
  def main() -> FastAPI:
88
89
  ...
89
90
 
@@ -96,7 +97,10 @@ def main() -> FastAPI:
96
97
  ### Controllers
97
98
 
98
99
  ``` py
99
- @ApiController("/users")
100
+ from qena_shared_lib.http import ControllerBase, api_controller, post
101
+
102
+
103
+ @api_controller("/users")
100
104
  class UserController(ControllerBase):
101
105
 
102
106
  def __init__(self, email_service: EmailService):
@@ -113,11 +117,18 @@ def main() -> FastAPI:
113
117
  builder.with_controllers([
114
118
  UserController
115
119
  ])
120
+
121
+ ...
116
122
  ```
117
123
 
118
124
  ### Routers
119
125
 
120
126
  ``` py
127
+ from fastapi import APIRouter
128
+
129
+ from qena_shared_lib.dependencies.http import DependsOn
130
+
131
+
121
132
  router = APIRouter(prefix="/auth")
122
133
 
123
134
 
@@ -154,6 +165,9 @@ def main() -> FastAPI:
154
165
  ## Logstash
155
166
 
156
167
  ``` py
168
+ from qena_shared_lib.logstash import BaseLogstashSender, HTTPSender, # TCPSender
169
+
170
+
157
171
  @asynccontextmanager
158
172
  async def lifespan(app: FastAPI):
159
173
  logstash = get_service(BaseLogstashSender)
@@ -204,6 +218,9 @@ def log_message(
204
218
  To create rabbitmq connection manager.
205
219
 
206
220
  ``` py
221
+ from qena_shared_lib.rabbitmq import ListenerBase, consume, consumer
222
+
223
+
207
224
  @asynccontextmanager
208
225
  async def lifespan(app: FastAPI):
209
226
  rabbitmq = get_service(RabbitMqManager)
@@ -215,7 +232,7 @@ async def lifespan(app: FastAPI):
215
232
  rabbitmq.disconnect()
216
233
 
217
234
 
218
- @Consumer("UserQueue")
235
+ @consumer("UserQueue")
219
236
  class UserConsumer(ListenerBase):
220
237
 
221
238
  def __init__(self, db: Database):
@@ -250,7 +267,7 @@ def main() -> FastAPI:
250
267
  async def store_user(
251
268
  rabbitmq: Annotated[
252
269
  RabbitMqManager,
253
- DependsOne(RabbitMqManager)
270
+ DependsOn(RabbitMqManager)
254
271
  ],
255
272
  user: User,
256
273
  )
@@ -267,7 +284,7 @@ async def store_user(
267
284
  async def get_user(
268
285
  rabbitmq: Annotated[
269
286
  RabbitMqManager,
270
- DependsOne(RabbitMqManager)
287
+ DependsOn(RabbitMqManager)
271
288
  ],
272
289
  user_id: str,
273
290
  )
@@ -282,7 +299,10 @@ async def get_user(
282
299
  ### Flow control
283
300
 
284
301
  ``` py
285
- @Consumer("UserQueue")
302
+ from qena_shared_lib.rabbitmq import ... , ListenerContext
303
+
304
+
305
+ @consumer("UserQueue")
286
306
  class UserConsumer(ListenerBase):
287
307
 
288
308
  @consume()
@@ -300,7 +320,10 @@ class UserConsumer(ListenerBase):
300
320
  Optionally it is possible to reply to rpc calls, through.
301
321
 
302
322
  ``` py
303
- @RpcWorker("UserQueue")
323
+ from qena_shared_lib.rabbitmq import ... , rpc_worker
324
+
325
+
326
+ @rpc_worker("UserQueue")
304
327
  class UserWorker(ListenerBase):
305
328
 
306
329
  @execute()
@@ -312,10 +335,92 @@ class UserWorker(ListenerBase):
312
335
  ...
313
336
  ```
314
337
 
338
+ ### Retry consumer
339
+
340
+ Consumer can retry to consumer a message in an event of failure.
341
+
342
+ ``` py
343
+ from qena_shared_lib.rabbitmq import (
344
+ BackoffRetryDelay,
345
+ FixedRetryDelay,
346
+ RabbitMqManager,
347
+ RetryDelayJitter,
348
+ RetryPolicy,
349
+ )
350
+
351
+
352
+ @consumer(
353
+ queue="UserQueue",
354
+ # can be defined for consumer of specific queue
355
+ retry_policy=RetryPolicy(
356
+ exceptions=(AMQPError,),
357
+ max_retry=5,
358
+ retry_delay_strategy=FixedRetryDelay(
359
+ retry_delay=2
360
+ ),
361
+ retry_delay_jitter=RetryDelayJitter(min=0.5, max=5.0),
362
+ )
363
+ )
364
+ class UserConsumer(ListenerBase):
365
+
366
+ @consume(
367
+ # for specific target
368
+ retry_policy=RetryPolicy(
369
+ exceptions=(AMQPError,),
370
+ max_retry=5,
371
+ retry_delay_strategy=FixedRetryDelay(
372
+ retry_delay=2
373
+ ),
374
+ retry_delay_jitter=RetryDelayJitter(min=0.5, max=5.0),
375
+ )
376
+ )
377
+ async def store_user(self, ctx: ListenerContext, user: User):
378
+ ...
379
+
380
+ await ctx.flow_control.request(10)
381
+
382
+ ...
383
+
384
+
385
+ def main() -> FastAPI:
386
+ ...
387
+
388
+ rabbitmq = RabbitMqManager(
389
+ logstash=logstash,
390
+ container=builder.container,
391
+ # or globally for all consumers
392
+ listener_global_retry_policy=RetryPolicy(
393
+ exceptions=(AMQPError,),
394
+ max_retry=10,
395
+ retry_delay_strategy=BackoffRetryDelay(
396
+ multiplier=1.5, min=2, max=10
397
+ ),
398
+ retry_delay_jitter=RetryDelayJitter(min=0.5, max=5.0),
399
+ match_by_cause=True,
400
+ ),
401
+ )
402
+
403
+ rabbitmq.include_listener(UserConsumer)
404
+ builder.add_singleton(
405
+ service=RabbitMqManager,
406
+ instance=rabbitmq,
407
+ )
408
+ ```
409
+
410
+
315
411
 
316
412
  ## Scheduler
317
413
 
318
414
  ``` py
415
+ from qena_shared_lib.scheduler import (
416
+ ScheduleManager,
417
+ # Scheduler,
418
+ SchedulerBase,
419
+ schedule,
420
+ scheduler,
421
+ )
422
+
423
+
319
424
  @asynccontextmanager
320
425
  async def lifespan(app: FastAPI):
321
426
  schedule_manager = get_service(ScheduleManager)
@@ -327,7 +432,7 @@ async def lifespan(app: FastAPI):
327
432
  schedule_manager.stop()
328
433
 
329
434
 
330
- @Scheduler()
435
+ @scheduler()
331
436
  class TaskScheduler(SchedulerBase):
332
437
 
333
438
  def __init__(self, db: Database)
@@ -368,6 +473,9 @@ def main() -> FastAPI:
368
473
  ## Background
369
474
 
370
475
  ``` py
476
+ from qena_shared_lib.background import Background
477
+
478
+
371
479
  @asynccontextmanager
372
480
  async def lifespan(app: FastAPI):
373
481
  background = get_service(Background)
@@ -411,7 +519,10 @@ async def process_data(
411
519
  ### Password hasher
412
520
 
413
521
  ``` py
414
- @ApiController("/users")
522
+ from qena_shared_lib.security import PasswordHasher
523
+
524
+
525
+ @api_controller("/users")
415
526
  class UserController(ControllerBase):
416
527
 
417
528
  def __init__(self, password_hasher: PasswordHasher):
@@ -440,6 +551,9 @@ def main() -> FastAPI:
440
551
  ### JWT
441
552
 
442
553
  ``` py
554
+ from qena_shared_lib.security import JwtAdapter
555
+
556
+
443
557
  @ApiController("/users")
444
558
  class UserController(ControllerBase):
445
559
 
@@ -479,7 +593,10 @@ def main() -> FastAPI:
479
593
  ### ACL
480
594
 
481
595
  ``` py
482
- @ApiController("/users")
596
+ from qena_shared_lib.security import Authorization
597
+
598
+
599
+ @api_controller("/users")
483
600
  class UserController(ControllerBase):
484
601
 
485
602
  @post()
@@ -487,7 +604,7 @@ class UserController(ControllerBase):
487
604
  self,
488
605
  user: Annotated[
489
606
  UserInfo,
490
- EndpointACL(
607
+ Authorization(
491
608
  user_type="ADMIN",
492
609
  persmission=[
493
610
  "READ"
@@ -502,7 +619,7 @@ class UserController(ControllerBase):
502
619
  async def get_users(
503
620
  user: Annotated[
504
621
  UserInfo,
505
- EndpointACL("ADMIN")
622
+ Authorization("ADMIN")
506
623
  ]
507
624
  )
508
625
  ...
@@ -1,20 +1,19 @@
1
1
  [project]
2
2
  name = "qena-shared-lib"
3
- version = "0.1.7"
3
+ version = "0.1.9"
4
4
  description = "A shared tools for other services"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
7
7
  dependencies = [
8
- "cronsim~=2.0",
9
- "fastapi[all]~=0.115.0",
10
- "httpx~=0.27.0",
11
- "jwt~=1.3.0",
12
- "passlib[bcrypt]~=1.7.0",
13
- "pika~=1.3.0",
14
- "prometheus-client~=0.21.0",
15
- "prometheus-fastapi-instrumentator~=7.0.0",
16
- "punq~=0.7.0",
17
- "pydantic~=2.10.0",
8
+ "cronsim==2.6",
9
+ "fastapi[all]==0.115.6",
10
+ "httpx==0.27.2",
11
+ "jwt==1.3.1",
12
+ "passlib[bcrypt]==1.7.4",
13
+ "pika==1.3.2",
14
+ "prometheus-client==0.21.1",
15
+ "prometheus-fastapi-instrumentator==7.0.2",
16
+ "punq==0.7.0",
18
17
  ]
19
18
 
20
19
  [build-system]
@@ -23,11 +22,11 @@ build-backend = "hatchling.build"
23
22
 
24
23
  [tool.uv]
25
24
  dev-dependencies = [
26
- "pre-commit~=4.0.0",
27
- "pytest-asyncio~=0.24.0",
28
- "pytest~=8.3.0",
29
- "testcontainers~=4.8.0",
30
- "pytest-cov~=6.0.0",
25
+ "pre-commit==4.0.1",
26
+ "pytest-asyncio==0.24.0",
27
+ "pytest==8.3.3",
28
+ "testcontainers==4.8.2",
29
+ "pytest-cov==6.0.0",
31
30
  ]
32
31
 
33
32
  [tool.ruff]