qena-shared-lib 0.1.8__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.
- qena_shared_lib/exception_handlers.py +2 -2
- qena_shared_lib/http.py +16 -40
- qena_shared_lib/rabbitmq/_exception_handlers.py +2 -2
- {qena_shared_lib-0.1.8.dist-info → qena_shared_lib-0.1.9.dist-info}/METADATA +146 -12
- {qena_shared_lib-0.1.8.dist-info → qena_shared_lib-0.1.9.dist-info}/RECORD +6 -6
- {qena_shared_lib-0.1.8.dist-info → qena_shared_lib-0.1.9.dist-info}/WHEEL +0 -0
@@ -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=
|
125
|
-
extra=
|
124
|
+
tags=tags,
|
125
|
+
extra=extra,
|
126
126
|
exception=exception if exception.extract_exc_info else None,
|
127
127
|
)
|
128
128
|
else:
|
qena_shared_lib/http.py
CHANGED
@@ -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
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
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
|
-
|
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
|
-
|
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=
|
91
|
-
extra=
|
90
|
+
tags=tags,
|
91
|
+
extra=extra,
|
92
92
|
exception=exception if exception.extract_exc_info else None,
|
93
93
|
)
|
94
94
|
else:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: qena-shared-lib
|
3
|
-
Version: 0.1.
|
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
|
-
|
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
|
-
@
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
@
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
638
|
+
Authorization("ADMIN")
|
505
639
|
]
|
506
640
|
)
|
507
641
|
...
|
@@ -1,9 +1,9 @@
|
|
1
1
|
qena_shared_lib/__init__.py,sha256=WokKEFaMNow6h2ZY_fyB-tiYnic-Ed6K6kyzKgg3Rlw,371
|
2
2
|
qena_shared_lib/application.py,sha256=LyMgCrp1wqUfHsQktybWW-fZG-XugxZ6_Bafhp3gRls,5472
|
3
3
|
qena_shared_lib/background.py,sha256=upWeJ747-4S4xsBOR-P2_oNar1YiaxCpnLhEDvnArmQ,3097
|
4
|
-
qena_shared_lib/exception_handlers.py,sha256=
|
4
|
+
qena_shared_lib/exception_handlers.py,sha256=qAXb8yE06yJRO2Qe9tfTu9D2DJhqgvX5wsc1_OPOjX4,6188
|
5
5
|
qena_shared_lib/exceptions.py,sha256=GEGcSNaNMhFCdgCl6crNrrw-tmzPD-2Jz6MnpMvqXIU,9419
|
6
|
-
qena_shared_lib/http.py,sha256=
|
6
|
+
qena_shared_lib/http.py,sha256=ZWbCV0C4SOKasfGhMLDcqZpZgIUUA_rEPAooeBkKieo,23846
|
7
7
|
qena_shared_lib/logging.py,sha256=JL6bAmkK1BJA84rZNpvDEmrec3dogQRpSug4fj1Omkw,1618
|
8
8
|
qena_shared_lib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
9
|
qena_shared_lib/scheduler.py,sha256=wVLgHM0cCBZhqSmOAgEa5McEJSSTHfoMAEIrFGI0tT0,11946
|
@@ -19,11 +19,11 @@ qena_shared_lib/logstash/_tcp_sender.py,sha256=ncvc3wYxOJPkB7c_0W8vboaxMRJ_1UYGd
|
|
19
19
|
qena_shared_lib/rabbitmq/__init__.py,sha256=HKGd-CfbqNkTMDzF9dd-ZQlj5fQfnO5S9qzMcILy8xk,1151
|
20
20
|
qena_shared_lib/rabbitmq/_base.py,sha256=S7jo4NbtAO8rzr7mBwhxRJrSmzrypOalrJChfrQ6-6I,23098
|
21
21
|
qena_shared_lib/rabbitmq/_channel.py,sha256=R0xzZvLkeE4YWsyLhx8bPDramsTFDZIcCgfsDyFmSB4,5429
|
22
|
-
qena_shared_lib/rabbitmq/_exception_handlers.py,sha256=
|
22
|
+
qena_shared_lib/rabbitmq/_exception_handlers.py,sha256=gLkPFxQUW9faL8RApPT-Bqmn-fQ134q1ZvKInfRKjuo,4529
|
23
23
|
qena_shared_lib/rabbitmq/_listener.py,sha256=1w5JAgwYy0xIU4kEZwL_KHyudfUWeqMWSXX5UdZ-p7M,46210
|
24
24
|
qena_shared_lib/rabbitmq/_pool.py,sha256=MGubA-nYxxjgsZRF1yK4UBkzUy65t-suh0W1jZDk5q8,1952
|
25
25
|
qena_shared_lib/rabbitmq/_publisher.py,sha256=Dr2u1IELCboCbozjTRsRtyQh7TRaJvujPsp74TF7utA,2434
|
26
26
|
qena_shared_lib/rabbitmq/_rpc_client.py,sha256=eNzKpU_BvfDTR3udiSNtjJ4MaJqHrIOxMItKHA8aJbo,8909
|
27
|
-
qena_shared_lib-0.1.
|
28
|
-
qena_shared_lib-0.1.
|
29
|
-
qena_shared_lib-0.1.
|
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,,
|
File without changes
|