qena-shared-lib 0.1.7__py3-none-any.whl → 0.1.9__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.
@@ -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.9
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
@@ -41,6 +40,9 @@ A shared tools for other services. It includes.
41
40
  To create fastapi app.
42
41
 
43
42
  ``` py
43
+ from qena_shared_lib.application import Builder, Environment
44
+
45
+
44
46
  def main() -> FastAPI:
45
47
  builder = (
46
48
  Builder()
@@ -64,6 +66,11 @@ $ uvicorn --factory main:main
64
66
  ### Lifespan
65
67
 
66
68
  ``` py
69
+ from contextlib import asynccontextmanager
70
+
71
+ from fastapi import FastAPI
72
+
73
+
67
74
  @asynccontextmanager
68
75
  def lifespan(app: FastAPI):
69
76
  ...
@@ -84,6 +91,16 @@ def main() -> FastAPI:
84
91
  ### Dependencies
85
92
 
86
93
  ``` py
94
+ class EmailService:
95
+ def __init__(self):
96
+ ...
97
+
98
+
99
+ class Database:
100
+ def __init__(self):
101
+ ...
102
+
103
+
87
104
  def main() -> FastAPI:
88
105
  ...
89
106
 
@@ -96,7 +113,10 @@ def main() -> FastAPI:
96
113
  ### Controllers
97
114
 
98
115
  ``` py
99
- @ApiController("/users")
116
+ from qena_shared_lib.http import ControllerBase, api_controller, post
117
+
118
+
119
+ @api_controller("/users")
100
120
  class UserController(ControllerBase):
101
121
 
102
122
  def __init__(self, email_service: EmailService):
@@ -113,11 +133,18 @@ def main() -> FastAPI:
113
133
  builder.with_controllers([
114
134
  UserController
115
135
  ])
136
+
137
+ ...
116
138
  ```
117
139
 
118
140
  ### Routers
119
141
 
120
142
  ``` py
143
+ from fastapi import APIRouter
144
+
145
+ from qena_shared_lib.dependencies.http import DependsOn
146
+
147
+
121
148
  router = APIRouter(prefix="/auth")
122
149
 
123
150
 
@@ -154,6 +181,9 @@ def main() -> FastAPI:
154
181
  ## Logstash
155
182
 
156
183
  ``` py
184
+ from qena_shared_lib.logstash import BaseLogstashSender, HTTPSender, # TCPSender
185
+
186
+
157
187
  @asynccontextmanager
158
188
  async def lifespan(app: FastAPI):
159
189
  logstash = get_service(BaseLogstashSender)
@@ -204,6 +234,9 @@ def log_message(
204
234
  To create rabbitmq connection manager.
205
235
 
206
236
  ``` py
237
+ from qena_shared_lib.rabbitmq import ListenerBase, consume, consumer
238
+
239
+
207
240
  @asynccontextmanager
208
241
  async def lifespan(app: FastAPI):
209
242
  rabbitmq = get_service(RabbitMqManager)
@@ -215,7 +248,7 @@ async def lifespan(app: FastAPI):
215
248
  rabbitmq.disconnect()
216
249
 
217
250
 
218
- @Consumer("UserQueue")
251
+ @consumer("UserQueue")
219
252
  class UserConsumer(ListenerBase):
220
253
 
221
254
  def __init__(self, db: Database):
@@ -250,7 +283,7 @@ def main() -> FastAPI:
250
283
  async def store_user(
251
284
  rabbitmq: Annotated[
252
285
  RabbitMqManager,
253
- DependsOne(RabbitMqManager)
286
+ DependsOn(RabbitMqManager)
254
287
  ],
255
288
  user: User,
256
289
  )
@@ -267,7 +300,7 @@ async def store_user(
267
300
  async def get_user(
268
301
  rabbitmq: Annotated[
269
302
  RabbitMqManager,
270
- DependsOne(RabbitMqManager)
303
+ DependsOn(RabbitMqManager)
271
304
  ],
272
305
  user_id: str,
273
306
  )
@@ -282,7 +315,10 @@ async def get_user(
282
315
  ### Flow control
283
316
 
284
317
  ``` py
285
- @Consumer("UserQueue")
318
+ from qena_shared_lib.rabbitmq import ... , ListenerContext
319
+
320
+
321
+ @consumer("UserQueue")
286
322
  class UserConsumer(ListenerBase):
287
323
 
288
324
  @consume()
@@ -300,7 +336,10 @@ class UserConsumer(ListenerBase):
300
336
  Optionally it is possible to reply to rpc calls, through.
301
337
 
302
338
  ``` py
303
- @RpcWorker("UserQueue")
339
+ from qena_shared_lib.rabbitmq import ... , rpc_worker
340
+
341
+
342
+ @rpc_worker("UserQueue")
304
343
  class UserWorker(ListenerBase):
305
344
 
306
345
  @execute()
@@ -312,10 +351,92 @@ class UserWorker(ListenerBase):
312
351
  ...
313
352
  ```
314
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
+
315
427
 
316
428
  ## Scheduler
317
429
 
318
430
  ``` py
431
+ from qena_shared_lib.scheduler import (
432
+ ScheduleManager,
433
+ # Scheduler,
434
+ SchedulerBase,
435
+ schedule,
436
+ scheduler,
437
+ )
438
+
439
+
319
440
  @asynccontextmanager
320
441
  async def lifespan(app: FastAPI):
321
442
  schedule_manager = get_service(ScheduleManager)
@@ -327,7 +448,7 @@ async def lifespan(app: FastAPI):
327
448
  schedule_manager.stop()
328
449
 
329
450
 
330
- @Scheduler()
451
+ @scheduler()
331
452
  class TaskScheduler(SchedulerBase):
332
453
 
333
454
  def __init__(self, db: Database)
@@ -368,6 +489,9 @@ def main() -> FastAPI:
368
489
  ## Background
369
490
 
370
491
  ``` py
492
+ from qena_shared_lib.background import Background
493
+
494
+
371
495
  @asynccontextmanager
372
496
  async def lifespan(app: FastAPI):
373
497
  background = get_service(Background)
@@ -411,7 +535,10 @@ async def process_data(
411
535
  ### Password hasher
412
536
 
413
537
  ``` py
414
- @ApiController("/users")
538
+ from qena_shared_lib.security import PasswordHasher
539
+
540
+
541
+ @api_controller("/users")
415
542
  class UserController(ControllerBase):
416
543
 
417
544
  def __init__(self, password_hasher: PasswordHasher):
@@ -440,6 +567,9 @@ def main() -> FastAPI:
440
567
  ### JWT
441
568
 
442
569
  ``` py
570
+ from qena_shared_lib.security import JwtAdapter
571
+
572
+
443
573
  @ApiController("/users")
444
574
  class UserController(ControllerBase):
445
575
 
@@ -479,7 +609,10 @@ def main() -> FastAPI:
479
609
  ### ACL
480
610
 
481
611
  ``` py
482
- @ApiController("/users")
612
+ from qena_shared_lib.security import Authorization
613
+
614
+
615
+ @api_controller("/users")
483
616
  class UserController(ControllerBase):
484
617
 
485
618
  @post()
@@ -487,7 +620,7 @@ class UserController(ControllerBase):
487
620
  self,
488
621
  user: Annotated[
489
622
  UserInfo,
490
- EndpointACL(
623
+ Authorization(
491
624
  user_type="ADMIN",
492
625
  persmission=[
493
626
  "READ"
@@ -502,7 +635,7 @@ class UserController(ControllerBase):
502
635
  async def get_users(
503
636
  user: Annotated[
504
637
  UserInfo,
505
- EndpointACL("ADMIN")
638
+ Authorization("ADMIN")
506
639
  ]
507
640
  )
508
641
  ...
@@ -0,0 +1,29 @@
1
+ qena_shared_lib/__init__.py,sha256=WokKEFaMNow6h2ZY_fyB-tiYnic-Ed6K6kyzKgg3Rlw,371
2
+ qena_shared_lib/application.py,sha256=LyMgCrp1wqUfHsQktybWW-fZG-XugxZ6_Bafhp3gRls,5472
3
+ qena_shared_lib/background.py,sha256=upWeJ747-4S4xsBOR-P2_oNar1YiaxCpnLhEDvnArmQ,3097
4
+ qena_shared_lib/exception_handlers.py,sha256=qAXb8yE06yJRO2Qe9tfTu9D2DJhqgvX5wsc1_OPOjX4,6188
5
+ qena_shared_lib/exceptions.py,sha256=GEGcSNaNMhFCdgCl6crNrrw-tmzPD-2Jz6MnpMvqXIU,9419
6
+ qena_shared_lib/http.py,sha256=ZWbCV0C4SOKasfGhMLDcqZpZgIUUA_rEPAooeBkKieo,23846
7
+ qena_shared_lib/logging.py,sha256=JL6bAmkK1BJA84rZNpvDEmrec3dogQRpSug4fj1Omkw,1618
8
+ qena_shared_lib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ qena_shared_lib/scheduler.py,sha256=wVLgHM0cCBZhqSmOAgEa5McEJSSTHfoMAEIrFGI0tT0,11946
10
+ qena_shared_lib/security.py,sha256=MAq2Qf8FVYiUp8Iht82cVIPlyJGHReZC4LYKBF6N6cw,6076
11
+ qena_shared_lib/utils.py,sha256=y60AKFknK-vus4i-nesgL00BWuAXJyd8Qx79Gi7lRq4,1272
12
+ qena_shared_lib/dependencies/__init__.py,sha256=W12RgJbhqZ9GiSV1nLlHmpwPzvQv8t7f4JEoazM_WYg,350
13
+ qena_shared_lib/dependencies/http.py,sha256=3KopQjq05qbYROMPZjji2Zz7qQLU6_2u3qKisLrjLks,1469
14
+ qena_shared_lib/dependencies/miscellaneous.py,sha256=iGwAjatXb_JVSF13n1vdTRAgSKv19VtHo9ZbjjbkIco,753
15
+ qena_shared_lib/logstash/__init__.py,sha256=KlWFXqwPGwKM3yWnz0lTmeZymkobxFPPNeOgyfdGu4g,315
16
+ qena_shared_lib/logstash/_base.py,sha256=SRTcAwMOWk-sDxuu12-VGgbBts5HBmL3f6OJtQBvr18,15768
17
+ qena_shared_lib/logstash/_http_sender.py,sha256=Sq3bJOXuOafqloROGblnmyUd0RuU3zF0QLpQDYjiy-g,1765
18
+ qena_shared_lib/logstash/_tcp_sender.py,sha256=ncvc3wYxOJPkB7c_0W8vboaxMRJ_1UYGdA8LN2NXUpo,2306
19
+ qena_shared_lib/rabbitmq/__init__.py,sha256=HKGd-CfbqNkTMDzF9dd-ZQlj5fQfnO5S9qzMcILy8xk,1151
20
+ qena_shared_lib/rabbitmq/_base.py,sha256=S7jo4NbtAO8rzr7mBwhxRJrSmzrypOalrJChfrQ6-6I,23098
21
+ qena_shared_lib/rabbitmq/_channel.py,sha256=R0xzZvLkeE4YWsyLhx8bPDramsTFDZIcCgfsDyFmSB4,5429
22
+ qena_shared_lib/rabbitmq/_exception_handlers.py,sha256=gLkPFxQUW9faL8RApPT-Bqmn-fQ134q1ZvKInfRKjuo,4529
23
+ qena_shared_lib/rabbitmq/_listener.py,sha256=1w5JAgwYy0xIU4kEZwL_KHyudfUWeqMWSXX5UdZ-p7M,46210
24
+ qena_shared_lib/rabbitmq/_pool.py,sha256=MGubA-nYxxjgsZRF1yK4UBkzUy65t-suh0W1jZDk5q8,1952
25
+ qena_shared_lib/rabbitmq/_publisher.py,sha256=Dr2u1IELCboCbozjTRsRtyQh7TRaJvujPsp74TF7utA,2434
26
+ qena_shared_lib/rabbitmq/_rpc_client.py,sha256=eNzKpU_BvfDTR3udiSNtjJ4MaJqHrIOxMItKHA8aJbo,8909
27
+ qena_shared_lib-0.1.9.dist-info/METADATA,sha256=DJuWOWR6IvgDxREbIXdIK3TQJUNfcAtFPOmQdooaZO4,11232
28
+ qena_shared_lib-0.1.9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
29
+ qena_shared_lib-0.1.9.dist-info/RECORD,,
@@ -1,46 +0,0 @@
1
- class RabbitMQException(Exception):
2
- def __init__(
3
- self,
4
- code: int,
5
- message: str,
6
- tags: list[str] | None = None,
7
- extra: dict[str, str] | None = None,
8
- logstash_logging: bool = True,
9
- extract_exc_info: bool = True,
10
- ):
11
- self._code = code
12
- self._message = message
13
- self._tags = tags
14
- self._extra = extra
15
- self._logstash_logging = logstash_logging
16
- self._extract_exc_info = extract_exc_info
17
-
18
- @property
19
- def code(self) -> int:
20
- return self._code
21
-
22
- @property
23
- def message(self) -> str:
24
- return self._message
25
-
26
- @property
27
- def tags(self) -> list[str] | None:
28
- return self._tags
29
-
30
- @property
31
- def extra(self) -> dict[str, str] | None:
32
- return self._extra
33
-
34
- @property
35
- def logstash_logging(self) -> bool:
36
- return self._logstash_logging
37
-
38
- @property
39
- def extract_exc_info(self) -> bool:
40
- return self._extract_exc_info
41
-
42
- def __str__(self) -> str:
43
- return f"message `{self.message}`, code `{self.code}`"
44
-
45
- def __repr__(self) -> str:
46
- return f"{self.__class__.__name__} ( message: `{self._message}`, code: {self._code} )"
@@ -1,30 +0,0 @@
1
- qena_shared_lib/__init__.py,sha256=WokKEFaMNow6h2ZY_fyB-tiYnic-Ed6K6kyzKgg3Rlw,371
2
- qena_shared_lib/application.py,sha256=2bpoEHW9FXRjNgBUuij2djfTLbhk01zymqp6kwasRq0,5470
3
- qena_shared_lib/background.py,sha256=upWeJ747-4S4xsBOR-P2_oNar1YiaxCpnLhEDvnArmQ,3097
4
- qena_shared_lib/exception_handlers.py,sha256=GclZUv8_QuJtbVSkzux8hxNbZNG7DWI2u0oGXgaEMD4,5143
5
- qena_shared_lib/exceptions.py,sha256=cNeksC8ZavKgoqKLBik1NR-lCcdLZzITHMXww5deY5Y,6789
6
- qena_shared_lib/http.py,sha256=90bmDfs522KxKBj2o0vO-MgmDqa3EZOfaNUFp1DuUdQ,23864
7
- qena_shared_lib/logging.py,sha256=JL6bAmkK1BJA84rZNpvDEmrec3dogQRpSug4fj1Omkw,1618
8
- qena_shared_lib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- qena_shared_lib/scheduler.py,sha256=qxM3zdKJnAKUWw8i_I2M5o3uL_fEOTaBzYUBL-HvUzg,11874
10
- qena_shared_lib/security.py,sha256=n872UE3eQfezo1lkHwz5hcAngO0VekA_qDQ9LsZ8JZ8,6072
11
- qena_shared_lib/utils.py,sha256=y60AKFknK-vus4i-nesgL00BWuAXJyd8Qx79Gi7lRq4,1272
12
- qena_shared_lib/dependencies/__init__.py,sha256=W12RgJbhqZ9GiSV1nLlHmpwPzvQv8t7f4JEoazM_WYg,350
13
- qena_shared_lib/dependencies/http.py,sha256=3KopQjq05qbYROMPZjji2Zz7qQLU6_2u3qKisLrjLks,1469
14
- qena_shared_lib/dependencies/miscellaneous.py,sha256=iGwAjatXb_JVSF13n1vdTRAgSKv19VtHo9ZbjjbkIco,753
15
- qena_shared_lib/logstash/__init__.py,sha256=KlWFXqwPGwKM3yWnz0lTmeZymkobxFPPNeOgyfdGu4g,315
16
- qena_shared_lib/logstash/_base.py,sha256=sX0FLr9R4mkYL3KJO6ADlZaqjn3KbGOLyVTfK_ZTbSo,15722
17
- qena_shared_lib/logstash/_http_sender.py,sha256=Sq3bJOXuOafqloROGblnmyUd0RuU3zF0QLpQDYjiy-g,1765
18
- qena_shared_lib/logstash/_tcp_sender.py,sha256=ncvc3wYxOJPkB7c_0W8vboaxMRJ_1UYGdA8LN2NXUpo,2306
19
- qena_shared_lib/rabbitmq/__init__.py,sha256=WKAcKpRXXX9kqfHVEkyX6p2yIWzB07TMsBBWbV8nrKA,1209
20
- qena_shared_lib/rabbitmq/_base.py,sha256=IKWwi7B82dhkIPwvY12l4ko1cjdmedklBxYkUQVQVL0,23069
21
- qena_shared_lib/rabbitmq/_channel.py,sha256=R0xzZvLkeE4YWsyLhx8bPDramsTFDZIcCgfsDyFmSB4,5429
22
- qena_shared_lib/rabbitmq/_exception_handlers.py,sha256=7-WguEUqUSIdbvCIWn10f2CRaWPCM3MDZ6sxSATCCYA,4762
23
- qena_shared_lib/rabbitmq/_exceptions.py,sha256=Mg56Uk4eBEwTnWC91_WPS3_8d-yaqNkbb_32IpX_R-c,1208
24
- qena_shared_lib/rabbitmq/_listener.py,sha256=eYrlaptPoc72y7UMRyo_Lnn_OE0HGVlBJIh5UEptnww,44134
25
- qena_shared_lib/rabbitmq/_pool.py,sha256=MGubA-nYxxjgsZRF1yK4UBkzUy65t-suh0W1jZDk5q8,1952
26
- qena_shared_lib/rabbitmq/_publisher.py,sha256=48JdpvNzFaw3Bw5LhunFxcjm3qNWz3AXKyXtcpzcohQ,2380
27
- qena_shared_lib/rabbitmq/_rpc_client.py,sha256=5hA8IWvydRufYdv0zViIsi6_W2tWkHcmZotgCV2yjfc,8705
28
- qena_shared_lib-0.1.7.dist-info/METADATA,sha256=f6AHqMQrm79vJ1H0n_O5t14CnKvFec8zq1xJZi54H-Q,8520
29
- qena_shared_lib-0.1.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
30
- qena_shared_lib-0.1.7.dist-info/RECORD,,