qena-shared-lib 0.1.8__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 (42) hide show
  1. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/PKG-INFO +146 -12
  2. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/README.md +145 -11
  3. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/pyproject.toml +1 -1
  4. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/src/qena_shared_lib/exception_handlers.py +2 -2
  5. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/src/qena_shared_lib/http.py +16 -40
  6. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/src/qena_shared_lib/rabbitmq/_exception_handlers.py +2 -2
  7. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/.gitignore +0 -0
  8. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/.pre-commit-config.yaml +0 -0
  9. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/requirements.txt +0 -0
  10. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/src/qena_shared_lib/__init__.py +0 -0
  11. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/src/qena_shared_lib/application.py +0 -0
  12. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/src/qena_shared_lib/background.py +0 -0
  13. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/src/qena_shared_lib/dependencies/__init__.py +0 -0
  14. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/src/qena_shared_lib/dependencies/http.py +0 -0
  15. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/src/qena_shared_lib/dependencies/miscellaneous.py +0 -0
  16. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/src/qena_shared_lib/exceptions.py +0 -0
  17. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/src/qena_shared_lib/logging.py +0 -0
  18. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/src/qena_shared_lib/logstash/__init__.py +0 -0
  19. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/src/qena_shared_lib/logstash/_base.py +0 -0
  20. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/src/qena_shared_lib/logstash/_http_sender.py +0 -0
  21. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/src/qena_shared_lib/logstash/_tcp_sender.py +0 -0
  22. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/src/qena_shared_lib/py.typed +0 -0
  23. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/src/qena_shared_lib/rabbitmq/__init__.py +0 -0
  24. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/src/qena_shared_lib/rabbitmq/_base.py +0 -0
  25. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/src/qena_shared_lib/rabbitmq/_channel.py +0 -0
  26. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/src/qena_shared_lib/rabbitmq/_listener.py +0 -0
  27. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/src/qena_shared_lib/rabbitmq/_pool.py +0 -0
  28. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/src/qena_shared_lib/rabbitmq/_publisher.py +0 -0
  29. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/src/qena_shared_lib/rabbitmq/_rpc_client.py +0 -0
  30. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/src/qena_shared_lib/scheduler.py +0 -0
  31. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/src/qena_shared_lib/security.py +0 -0
  32. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/src/qena_shared_lib/utils.py +0 -0
  33. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/tests/conftest.py +0 -0
  34. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/tests/test_application.py +0 -0
  35. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/tests/test_background.py +0 -0
  36. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/tests/test_dependencies.py +0 -0
  37. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/tests/test_logstash.py +0 -0
  38. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/tests/test_rabbitmq.py +0 -0
  39. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/tests/test_scheduler.py +0 -0
  40. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/tests/test_security.py +0 -0
  41. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/tests/utils.py +0 -0
  42. {qena_shared_lib-0.1.8 → qena_shared_lib-0.1.9}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qena-shared-lib
3
- Version: 0.1.8
3
+ Version: 0.1.9
4
4
  Summary: A shared tools for other services
5
5
  Requires-Python: >=3.10
6
6
  Requires-Dist: cronsim==2.6
@@ -40,6 +40,9 @@ A shared tools for other services. It includes.
40
40
  To create fastapi app.
41
41
 
42
42
  ``` py
43
+ from qena_shared_lib.application import Builder, Environment
44
+
45
+
43
46
  def main() -> FastAPI:
44
47
  builder = (
45
48
  Builder()
@@ -63,6 +66,11 @@ $ uvicorn --factory main:main
63
66
  ### Lifespan
64
67
 
65
68
  ``` py
69
+ from contextlib import asynccontextmanager
70
+
71
+ from fastapi import FastAPI
72
+
73
+
66
74
  @asynccontextmanager
67
75
  def lifespan(app: FastAPI):
68
76
  ...
@@ -83,6 +91,16 @@ def main() -> FastAPI:
83
91
  ### Dependencies
84
92
 
85
93
  ``` py
94
+ class EmailService:
95
+ def __init__(self):
96
+ ...
97
+
98
+
99
+ class Database:
100
+ def __init__(self):
101
+ ...
102
+
103
+
86
104
  def main() -> FastAPI:
87
105
  ...
88
106
 
@@ -95,7 +113,10 @@ def main() -> FastAPI:
95
113
  ### Controllers
96
114
 
97
115
  ``` py
98
- @ApiController("/users")
116
+ from qena_shared_lib.http import ControllerBase, api_controller, post
117
+
118
+
119
+ @api_controller("/users")
99
120
  class UserController(ControllerBase):
100
121
 
101
122
  def __init__(self, email_service: EmailService):
@@ -112,11 +133,18 @@ def main() -> FastAPI:
112
133
  builder.with_controllers([
113
134
  UserController
114
135
  ])
136
+
137
+ ...
115
138
  ```
116
139
 
117
140
  ### Routers
118
141
 
119
142
  ``` py
143
+ from fastapi import APIRouter
144
+
145
+ from qena_shared_lib.dependencies.http import DependsOn
146
+
147
+
120
148
  router = APIRouter(prefix="/auth")
121
149
 
122
150
 
@@ -153,6 +181,9 @@ def main() -> FastAPI:
153
181
  ## Logstash
154
182
 
155
183
  ``` py
184
+ from qena_shared_lib.logstash import BaseLogstashSender, HTTPSender, # TCPSender
185
+
186
+
156
187
  @asynccontextmanager
157
188
  async def lifespan(app: FastAPI):
158
189
  logstash = get_service(BaseLogstashSender)
@@ -203,6 +234,9 @@ def log_message(
203
234
  To create rabbitmq connection manager.
204
235
 
205
236
  ``` py
237
+ from qena_shared_lib.rabbitmq import ListenerBase, consume, consumer
238
+
239
+
206
240
  @asynccontextmanager
207
241
  async def lifespan(app: FastAPI):
208
242
  rabbitmq = get_service(RabbitMqManager)
@@ -214,7 +248,7 @@ async def lifespan(app: FastAPI):
214
248
  rabbitmq.disconnect()
215
249
 
216
250
 
217
- @Consumer("UserQueue")
251
+ @consumer("UserQueue")
218
252
  class UserConsumer(ListenerBase):
219
253
 
220
254
  def __init__(self, db: Database):
@@ -249,7 +283,7 @@ def main() -> FastAPI:
249
283
  async def store_user(
250
284
  rabbitmq: Annotated[
251
285
  RabbitMqManager,
252
- DependsOne(RabbitMqManager)
286
+ DependsOn(RabbitMqManager)
253
287
  ],
254
288
  user: User,
255
289
  )
@@ -266,7 +300,7 @@ async def store_user(
266
300
  async def get_user(
267
301
  rabbitmq: Annotated[
268
302
  RabbitMqManager,
269
- DependsOne(RabbitMqManager)
303
+ DependsOn(RabbitMqManager)
270
304
  ],
271
305
  user_id: str,
272
306
  )
@@ -281,7 +315,10 @@ async def get_user(
281
315
  ### Flow control
282
316
 
283
317
  ``` py
284
- @Consumer("UserQueue")
318
+ from qena_shared_lib.rabbitmq import ... , ListenerContext
319
+
320
+
321
+ @consumer("UserQueue")
285
322
  class UserConsumer(ListenerBase):
286
323
 
287
324
  @consume()
@@ -299,7 +336,10 @@ class UserConsumer(ListenerBase):
299
336
  Optionally it is possible to reply to rpc calls, through.
300
337
 
301
338
  ``` py
302
- @RpcWorker("UserQueue")
339
+ from qena_shared_lib.rabbitmq import ... , rpc_worker
340
+
341
+
342
+ @rpc_worker("UserQueue")
303
343
  class UserWorker(ListenerBase):
304
344
 
305
345
  @execute()
@@ -311,10 +351,92 @@ class UserWorker(ListenerBase):
311
351
  ...
312
352
  ```
313
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
+
314
427
 
315
428
  ## Scheduler
316
429
 
317
430
  ``` py
431
+ from qena_shared_lib.scheduler import (
432
+ ScheduleManager,
433
+ # Scheduler,
434
+ SchedulerBase,
435
+ schedule,
436
+ scheduler,
437
+ )
438
+
439
+
318
440
  @asynccontextmanager
319
441
  async def lifespan(app: FastAPI):
320
442
  schedule_manager = get_service(ScheduleManager)
@@ -326,7 +448,7 @@ async def lifespan(app: FastAPI):
326
448
  schedule_manager.stop()
327
449
 
328
450
 
329
- @Scheduler()
451
+ @scheduler()
330
452
  class TaskScheduler(SchedulerBase):
331
453
 
332
454
  def __init__(self, db: Database)
@@ -367,6 +489,9 @@ def main() -> FastAPI:
367
489
  ## Background
368
490
 
369
491
  ``` py
492
+ from qena_shared_lib.background import Background
493
+
494
+
370
495
  @asynccontextmanager
371
496
  async def lifespan(app: FastAPI):
372
497
  background = get_service(Background)
@@ -410,7 +535,10 @@ async def process_data(
410
535
  ### Password hasher
411
536
 
412
537
  ``` py
413
- @ApiController("/users")
538
+ from qena_shared_lib.security import PasswordHasher
539
+
540
+
541
+ @api_controller("/users")
414
542
  class UserController(ControllerBase):
415
543
 
416
544
  def __init__(self, password_hasher: PasswordHasher):
@@ -439,6 +567,9 @@ def main() -> FastAPI:
439
567
  ### JWT
440
568
 
441
569
  ``` py
570
+ from qena_shared_lib.security import JwtAdapter
571
+
572
+
442
573
  @ApiController("/users")
443
574
  class UserController(ControllerBase):
444
575
 
@@ -478,7 +609,10 @@ def main() -> FastAPI:
478
609
  ### ACL
479
610
 
480
611
  ``` py
481
- @ApiController("/users")
612
+ from qena_shared_lib.security import Authorization
613
+
614
+
615
+ @api_controller("/users")
482
616
  class UserController(ControllerBase):
483
617
 
484
618
  @post()
@@ -486,7 +620,7 @@ class UserController(ControllerBase):
486
620
  self,
487
621
  user: Annotated[
488
622
  UserInfo,
489
- EndpointACL(
623
+ Authorization(
490
624
  user_type="ADMIN",
491
625
  persmission=[
492
626
  "READ"
@@ -501,7 +635,7 @@ class UserController(ControllerBase):
501
635
  async def get_users(
502
636
  user: Annotated[
503
637
  UserInfo,
504
- EndpointACL("ADMIN")
638
+ Authorization("ADMIN")
505
639
  ]
506
640
  )
507
641
  ...
@@ -24,6 +24,9 @@ A shared tools for other services. It includes.
24
24
  To create fastapi app.
25
25
 
26
26
  ``` py
27
+ from qena_shared_lib.application import Builder, Environment
28
+
29
+
27
30
  def main() -> FastAPI:
28
31
  builder = (
29
32
  Builder()
@@ -47,6 +50,11 @@ $ uvicorn --factory main:main
47
50
  ### Lifespan
48
51
 
49
52
  ``` py
53
+ from contextlib import asynccontextmanager
54
+
55
+ from fastapi import FastAPI
56
+
57
+
50
58
  @asynccontextmanager
51
59
  def lifespan(app: FastAPI):
52
60
  ...
@@ -67,6 +75,16 @@ def main() -> FastAPI:
67
75
  ### Dependencies
68
76
 
69
77
  ``` py
78
+ class EmailService:
79
+ def __init__(self):
80
+ ...
81
+
82
+
83
+ class Database:
84
+ def __init__(self):
85
+ ...
86
+
87
+
70
88
  def main() -> FastAPI:
71
89
  ...
72
90
 
@@ -79,7 +97,10 @@ def main() -> FastAPI:
79
97
  ### Controllers
80
98
 
81
99
  ``` py
82
- @ApiController("/users")
100
+ from qena_shared_lib.http import ControllerBase, api_controller, post
101
+
102
+
103
+ @api_controller("/users")
83
104
  class UserController(ControllerBase):
84
105
 
85
106
  def __init__(self, email_service: EmailService):
@@ -96,11 +117,18 @@ def main() -> FastAPI:
96
117
  builder.with_controllers([
97
118
  UserController
98
119
  ])
120
+
121
+ ...
99
122
  ```
100
123
 
101
124
  ### Routers
102
125
 
103
126
  ``` py
127
+ from fastapi import APIRouter
128
+
129
+ from qena_shared_lib.dependencies.http import DependsOn
130
+
131
+
104
132
  router = APIRouter(prefix="/auth")
105
133
 
106
134
 
@@ -137,6 +165,9 @@ def main() -> FastAPI:
137
165
  ## Logstash
138
166
 
139
167
  ``` py
168
+ from qena_shared_lib.logstash import BaseLogstashSender, HTTPSender, # TCPSender
169
+
170
+
140
171
  @asynccontextmanager
141
172
  async def lifespan(app: FastAPI):
142
173
  logstash = get_service(BaseLogstashSender)
@@ -187,6 +218,9 @@ def log_message(
187
218
  To create rabbitmq connection manager.
188
219
 
189
220
  ``` py
221
+ from qena_shared_lib.rabbitmq import ListenerBase, consume, consumer
222
+
223
+
190
224
  @asynccontextmanager
191
225
  async def lifespan(app: FastAPI):
192
226
  rabbitmq = get_service(RabbitMqManager)
@@ -198,7 +232,7 @@ async def lifespan(app: FastAPI):
198
232
  rabbitmq.disconnect()
199
233
 
200
234
 
201
- @Consumer("UserQueue")
235
+ @consumer("UserQueue")
202
236
  class UserConsumer(ListenerBase):
203
237
 
204
238
  def __init__(self, db: Database):
@@ -233,7 +267,7 @@ def main() -> FastAPI:
233
267
  async def store_user(
234
268
  rabbitmq: Annotated[
235
269
  RabbitMqManager,
236
- DependsOne(RabbitMqManager)
270
+ DependsOn(RabbitMqManager)
237
271
  ],
238
272
  user: User,
239
273
  )
@@ -250,7 +284,7 @@ async def store_user(
250
284
  async def get_user(
251
285
  rabbitmq: Annotated[
252
286
  RabbitMqManager,
253
- DependsOne(RabbitMqManager)
287
+ DependsOn(RabbitMqManager)
254
288
  ],
255
289
  user_id: str,
256
290
  )
@@ -265,7 +299,10 @@ async def get_user(
265
299
  ### Flow control
266
300
 
267
301
  ``` py
268
- @Consumer("UserQueue")
302
+ from qena_shared_lib.rabbitmq import ... , ListenerContext
303
+
304
+
305
+ @consumer("UserQueue")
269
306
  class UserConsumer(ListenerBase):
270
307
 
271
308
  @consume()
@@ -283,7 +320,10 @@ class UserConsumer(ListenerBase):
283
320
  Optionally it is possible to reply to rpc calls, through.
284
321
 
285
322
  ``` py
286
- @RpcWorker("UserQueue")
323
+ from qena_shared_lib.rabbitmq import ... , rpc_worker
324
+
325
+
326
+ @rpc_worker("UserQueue")
287
327
  class UserWorker(ListenerBase):
288
328
 
289
329
  @execute()
@@ -295,10 +335,92 @@ class UserWorker(ListenerBase):
295
335
  ...
296
336
  ```
297
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
+
298
411
 
299
412
  ## Scheduler
300
413
 
301
414
  ``` py
415
+ from qena_shared_lib.scheduler import (
416
+ ScheduleManager,
417
+ # Scheduler,
418
+ SchedulerBase,
419
+ schedule,
420
+ scheduler,
421
+ )
422
+
423
+
302
424
  @asynccontextmanager
303
425
  async def lifespan(app: FastAPI):
304
426
  schedule_manager = get_service(ScheduleManager)
@@ -310,7 +432,7 @@ async def lifespan(app: FastAPI):
310
432
  schedule_manager.stop()
311
433
 
312
434
 
313
- @Scheduler()
435
+ @scheduler()
314
436
  class TaskScheduler(SchedulerBase):
315
437
 
316
438
  def __init__(self, db: Database)
@@ -351,6 +473,9 @@ def main() -> FastAPI:
351
473
  ## Background
352
474
 
353
475
  ``` py
476
+ from qena_shared_lib.background import Background
477
+
478
+
354
479
  @asynccontextmanager
355
480
  async def lifespan(app: FastAPI):
356
481
  background = get_service(Background)
@@ -394,7 +519,10 @@ async def process_data(
394
519
  ### Password hasher
395
520
 
396
521
  ``` py
397
- @ApiController("/users")
522
+ from qena_shared_lib.security import PasswordHasher
523
+
524
+
525
+ @api_controller("/users")
398
526
  class UserController(ControllerBase):
399
527
 
400
528
  def __init__(self, password_hasher: PasswordHasher):
@@ -423,6 +551,9 @@ def main() -> FastAPI:
423
551
  ### JWT
424
552
 
425
553
  ``` py
554
+ from qena_shared_lib.security import JwtAdapter
555
+
556
+
426
557
  @ApiController("/users")
427
558
  class UserController(ControllerBase):
428
559
 
@@ -462,7 +593,10 @@ def main() -> FastAPI:
462
593
  ### ACL
463
594
 
464
595
  ``` py
465
- @ApiController("/users")
596
+ from qena_shared_lib.security import Authorization
597
+
598
+
599
+ @api_controller("/users")
466
600
  class UserController(ControllerBase):
467
601
 
468
602
  @post()
@@ -470,7 +604,7 @@ class UserController(ControllerBase):
470
604
  self,
471
605
  user: Annotated[
472
606
  UserInfo,
473
- EndpointACL(
607
+ Authorization(
474
608
  user_type="ADMIN",
475
609
  persmission=[
476
610
  "READ"
@@ -485,7 +619,7 @@ class UserController(ControllerBase):
485
619
  async def get_users(
486
620
  user: Annotated[
487
621
  UserInfo,
488
- EndpointACL("ADMIN")
622
+ Authorization("ADMIN")
489
623
  ]
490
624
  )
491
625
  ...
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "qena-shared-lib"
3
- version = "0.1.8"
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"
@@ -121,8 +121,8 @@ def handle_http_service_error(
121
121
  if exception.logstash_logging:
122
122
  logstash_logger_method(
123
123
  message=exception.message,
124
- tags=exception.tags or tags,
125
- extra=exception.extra or extra,
124
+ tags=tags,
125
+ extra=extra,
126
126
  exception=exception if exception.extract_exc_info else None,
127
127
  )
128
128
  else:
@@ -10,7 +10,6 @@ from fastapi.types import IncEx
10
10
 
11
11
  __all__ = [
12
12
  "api_controller",
13
- "ApiController",
14
13
  "ControllerBase",
15
14
  "delete",
16
15
  "get",
@@ -63,20 +62,19 @@ class RouteHandlerMeta:
63
62
  openapi_extra: dict[str, Any] | None = None
64
63
 
65
64
 
66
- class ApiController:
67
- def __init__(
68
- self,
69
- prefix: str | None = None,
70
- *,
71
- tags: list[str | Enum] | None = None,
72
- dependencies: Sequence[Depends] | None = None,
73
- default_response_class: type[Response] = JSONResponse,
74
- responses: dict[int | str, dict[str, Any]] | None = None,
75
- redirect_slashes: bool = True,
76
- deprecated: bool | None = None,
77
- include_in_schema: bool = True,
78
- ):
79
- self._api_router = APIRouter(
65
+ def api_controller(
66
+ prefix: str | None = None,
67
+ *,
68
+ tags: list[str | Enum] | None = None,
69
+ dependencies: Sequence[Depends] | None = None,
70
+ default_response_class: type[Response] = JSONResponse,
71
+ responses: dict[int | str, dict[str, Any]] | None = None,
72
+ redirect_slashes: bool = True,
73
+ deprecated: bool | None = None,
74
+ include_in_schema: bool = True,
75
+ ) -> Callable[["ControllerBase"], "ControllerBase"]:
76
+ def annotate_class(api_controller_class: ControllerBase):
77
+ router = APIRouter(
80
78
  prefix=prefix or "",
81
79
  tags=tags,
82
80
  dependencies=dependencies,
@@ -87,33 +85,11 @@ class ApiController:
87
85
  include_in_schema=include_in_schema,
88
86
  )
89
87
 
90
- def __call__(self, controller: type[AC]) -> type[AC]:
91
- setattr(controller, API_CONTROLLER_ATTRIBUTE, self._api_router)
92
-
93
- return controller
88
+ setattr(api_controller_class, API_CONTROLLER_ATTRIBUTE, router)
94
89
 
90
+ return api_controller_class
95
91
 
96
- def api_controller(
97
- prefix: str | None = None,
98
- *,
99
- tags: list[str | Enum] | None = None,
100
- dependencies: Sequence[Depends] | None = None,
101
- default_response_class: type[Response] = JSONResponse,
102
- responses: dict[int | str, dict[str, Any]] | None = None,
103
- redirect_slashes: bool = True,
104
- deprecated: bool | None = None,
105
- include_in_schema: bool = True,
106
- ) -> ApiController:
107
- return ApiController(
108
- prefix=prefix,
109
- tags=tags,
110
- dependencies=dependencies,
111
- default_response_class=default_response_class,
112
- responses=responses,
113
- redirect_slashes=redirect_slashes,
114
- deprecated=deprecated,
115
- include_in_schema=include_in_schema,
116
- )
92
+ return annotate_class
117
93
 
118
94
 
119
95
  def get(
@@ -87,8 +87,8 @@ def handle_rabbit_mq_service_exception(
87
87
  if exception.logstash_logging:
88
88
  logstash_logger_method(
89
89
  message=exception.message,
90
- tags=exception.tags or tags,
91
- extra=exception.extra or extra,
90
+ tags=tags,
91
+ extra=extra,
92
92
  exception=exception if exception.extract_exc_info else None,
93
93
  )
94
94
  else:
File without changes