qena-shared-lib 0.1.14__py3-none-any.whl → 0.1.16__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,3 +1,7 @@
1
+ try:
2
+ from . import rabbitmq, scheduler, security
3
+ except NameError:
4
+ pass
1
5
  from . import (
2
6
  application,
3
7
  background,
@@ -5,10 +9,7 @@ from . import (
5
9
  exceptions,
6
10
  http,
7
11
  logging,
8
- rabbitmq,
9
12
  remotelogging,
10
- scheduler,
11
- security,
12
13
  utils,
13
14
  )
14
15
 
@@ -1,6 +1,5 @@
1
1
  from functools import lru_cache
2
2
  from logging import (
3
- INFO,
4
3
  Formatter,
5
4
  Handler,
6
5
  Logger,
@@ -14,15 +13,12 @@ __all__ = [
14
13
  "LoggerProvider",
15
14
  ]
16
15
 
17
- ROOT_LOGGER_NAME = environ.get("LOGGER_NAME") or "qena_shared_lib"
16
+ ROOT_LOGGER_NAME = (
17
+ environ.get("QENA_SHARED_LIB_LOGGING_LOGGER_NAME") or "qena_shared_lib"
18
+ )
18
19
 
19
20
 
20
21
  class LoggerProvider:
21
- def __init__(self) -> None:
22
- logger = self.get_logger()
23
-
24
- logger.setLevel(INFO)
25
-
26
22
  @lru_cache
27
23
  @staticmethod
28
24
  def default() -> "LoggerProvider":
@@ -14,10 +14,13 @@ from typing import (
14
14
  cast,
15
15
  )
16
16
 
17
- from pika.adapters.asyncio_connection import AsyncioConnection
18
- from pika.connection import Parameters, URLParameters
19
- from pika.exceptions import ChannelClosedByClient, ConnectionClosedByClient
20
- from pika.frame import Method
17
+ try:
18
+ from pika.adapters.asyncio_connection import AsyncioConnection
19
+ from pika.connection import Parameters, URLParameters
20
+ from pika.exceptions import ChannelClosedByClient, ConnectionClosedByClient
21
+ from pika.frame import Method
22
+ except ImportError:
23
+ pass
21
24
  from prometheus_client import Counter
22
25
  from prometheus_client import Enum as PrometheusEnum
23
26
  from punq import Container, Scope
@@ -451,10 +454,12 @@ class RabbitMqManager(AsyncEventLoopMixin):
451
454
  ).add_done_callback(self._listener_and_service_config_and_init_done)
452
455
 
453
456
  def _configure_listeners(self) -> list[Awaitable[Any]]:
454
- try:
455
- assert self._connection is not None
457
+ assert self._connection is not None
458
+
459
+ listeners_configured_coroutines: list[Awaitable[Any]] = []
456
460
 
457
- return [
461
+ try:
462
+ listeners_configured_coroutines.extend(
458
463
  listener.configure(
459
464
  connection=self._connection,
460
465
  channel_pool=self._channel_pool,
@@ -464,28 +469,36 @@ class RabbitMqManager(AsyncEventLoopMixin):
464
469
  global_retry_policy=self._listener_global_retry_policy,
465
470
  )
466
471
  for listener in self._listeners
467
- ]
472
+ )
468
473
  except Exception as e:
469
474
  listener_configuration_error_future = self.loop.create_future()
470
475
 
471
476
  listener_configuration_error_future.set_exception(e)
477
+ listeners_configured_coroutines.append(
478
+ listener_configuration_error_future
479
+ )
472
480
 
473
- return [listener_configuration_error_future]
481
+ return listeners_configured_coroutines
474
482
 
475
483
  def _initialize_services(self) -> list[Future[Any]]:
476
484
  assert self._connection is not None
477
485
 
486
+ service_initialization_futures: list[Future[Any]] = []
487
+
478
488
  try:
479
- return [
489
+ service_initialization_futures.extend(
480
490
  service.initialize(self._connection, self._channel_pool)
481
491
  for service in self._services
482
- ]
492
+ )
483
493
  except Exception as e:
484
494
  service_initialization_error_future = self.loop.create_future()
485
495
 
486
496
  service_initialization_error_future.set_exception(e)
497
+ service_initialization_futures.append(
498
+ service_initialization_error_future
499
+ )
487
500
 
488
- return [service_initialization_error_future]
501
+ return service_initialization_futures
489
502
 
490
503
  def _listener_and_service_config_and_init_done(
491
504
  self, future: Future[list[Any]]
@@ -521,7 +534,7 @@ class RabbitMqManager(AsyncEventLoopMixin):
521
534
  service_count = len(self._services)
522
535
 
523
536
  self._logger.info(
524
- "connect to rabbitmq, `%s:%s%s` with `%d` %s and `%d` %s.",
537
+ "connected to rabbitmq, `%s:%s%s` with `%d` %s and `%d` %s.",
525
538
  params.host,
526
539
  params.port,
527
540
  params.virtual_host,
@@ -4,10 +4,13 @@ from random import uniform
4
4
  from typing import cast
5
5
  from uuid import UUID, uuid4
6
6
 
7
- from pika.adapters.asyncio_connection import AsyncioConnection
8
- from pika.channel import Channel
9
- from pika.exceptions import ChannelClosedByClient
10
- from pika.spec import Basic
7
+ try:
8
+ from pika.adapters.asyncio_connection import AsyncioConnection
9
+ from pika.channel import Channel
10
+ from pika.exceptions import ChannelClosedByClient
11
+ from pika.spec import Basic
12
+ except ImportError:
13
+ pass
11
14
 
12
15
  from ..logging import LoggerProvider
13
16
  from ..utils import AsyncEventLoopMixin
@@ -16,11 +16,14 @@ from time import time
16
16
  from types import MappingProxyType
17
17
  from typing import Any, Callable, Collection, TypeVar, cast
18
18
 
19
- from pika import BasicProperties
20
- from pika.adapters.asyncio_connection import AsyncioConnection
21
- from pika.channel import Channel
22
- from pika.frame import Method
23
- from pika.spec import Basic
19
+ try:
20
+ from pika import BasicProperties
21
+ from pika.adapters.asyncio_connection import AsyncioConnection
22
+ from pika.channel import Channel
23
+ from pika.frame import Method
24
+ from pika.spec import Basic
25
+ except ImportError:
26
+ pass
24
27
  from prometheus_client import Counter, Summary
25
28
  from punq import Container
26
29
  from pydantic import ValidationError
@@ -1,7 +1,10 @@
1
1
  from asyncio import Lock
2
2
  from uuid import UUID
3
3
 
4
- from pika.adapters.asyncio_connection import AsyncioConnection
4
+ try:
5
+ from pika.adapters.asyncio_connection import AsyncioConnection
6
+ except ImportError:
7
+ pass
5
8
 
6
9
  from ..utils import AsyncEventLoopMixin
7
10
  from ._channel import BaseChannel
@@ -1,6 +1,9 @@
1
1
  from typing import Any, Callable
2
2
 
3
- from pika import BasicProperties
3
+ try:
4
+ from pika import BasicProperties
5
+ except ImportError:
6
+ pass
4
7
  from prometheus_client import Counter
5
8
  from pydantic_core import to_json
6
9
 
@@ -5,10 +5,13 @@ from time import time
5
5
  from typing import Any, Callable, Generic, TypeVar
6
6
  from uuid import uuid4
7
7
 
8
- from pika import BasicProperties
9
- from pika.channel import Channel
10
- from pika.frame import Method
11
- from pika.spec import Basic
8
+ try:
9
+ from pika import BasicProperties
10
+ from pika.channel import Channel
11
+ from pika.frame import Method
12
+ from pika.spec import Basic
13
+ except ImportError:
14
+ pass
12
15
  from prometheus_client import Counter, Summary
13
16
  from pydantic_core import from_json, to_json
14
17
 
@@ -166,9 +169,11 @@ class RpcClient(Generic[R], AsyncEventLoopMixin):
166
169
  return await self._rpc_future
167
170
 
168
171
  def _on_queue_declared(self, message: Any, method: Method) -> None:
172
+ queue = getattr(method.method, "queue")
173
+
169
174
  try:
170
175
  self._rpc_reply_consumer_tag = self._channel.basic_consume(
171
- queue=method.method.queue,
176
+ queue=queue,
172
177
  on_message_callback=self._on_reply_message,
173
178
  auto_ack=True,
174
179
  )
@@ -185,7 +190,7 @@ class RpcClient(Generic[R], AsyncEventLoopMixin):
185
190
  routing_key=self._routing_key,
186
191
  properties=BasicProperties(
187
192
  content_type="application/json",
188
- reply_to=method.method.queue,
193
+ reply_to=queue,
189
194
  correlation_id=self._correlation_id,
190
195
  headers=self._headers,
191
196
  ),
@@ -8,7 +8,10 @@ from os import name as osname
8
8
  from typing import Any, Callable, TypeVar, cast
9
9
  from zoneinfo import ZoneInfo
10
10
 
11
- from cronsim import CronSim
11
+ try:
12
+ from cronsim import CronSim
13
+ except ImportError:
14
+ pass
12
15
  from prometheus_client import Enum as PrometheusEnum
13
16
  from punq import Container, Scope
14
17
 
@@ -3,11 +3,14 @@ from enum import Enum
3
3
  from os import environ
4
4
  from typing import AbstractSet, Annotated, Any, cast
5
5
 
6
+ try:
7
+ from jwt import JWT, AbstractJWKBase, jwk_from_dict
8
+ from jwt.exceptions import JWTDecodeError
9
+ from jwt.utils import get_int_from_datetime, get_time_from_int
10
+ from passlib.context import CryptContext
11
+ except ImportError:
12
+ pass
6
13
  from fastapi import Depends, Header
7
- from jwt import JWT, AbstractJWKBase, jwk_from_dict
8
- from jwt.exceptions import JWTDecodeError
9
- from jwt.utils import get_int_from_datetime, get_time_from_int
10
- from passlib.context import CryptContext
11
14
  from pydantic import BaseModel, Field, ValidationError
12
15
 
13
16
  from .dependencies.http import DependsOn
@@ -27,7 +30,9 @@ __all__ = [
27
30
 
28
31
 
29
32
  MESSAGE = "you are not authorized to access requested resource"
30
- RESPONSE_CODE = int(environ.get("UNAUTHORIZED_RESPONSE_CODE") or 0)
33
+ RESPONSE_CODE = int(
34
+ environ.get("QENA_SHARED_LIB_SECURITY_UNAUTHORIZED_RESPONSE_CODE") or 0
35
+ )
31
36
 
32
37
 
33
38
  class PasswordHasher(AsyncEventLoopMixin):
@@ -92,7 +97,11 @@ class UserInfo(BaseModel):
92
97
  async def extract_user_info(
93
98
  jwt_adapter: Annotated[JwtAdapter, DependsOn(JwtAdapter)],
94
99
  token: Annotated[
95
- str | None, Header(alias=environ.get("TOKEN_HEADER") or "authorization")
100
+ str | None,
101
+ Header(
102
+ alias=environ.get("QENA_SHARED_LIB_SECURITY_TOKEN_HEADER")
103
+ or "authorization"
104
+ ),
96
105
  ] = None,
97
106
  user_agent: Annotated[
98
107
  str | None, Header(alias="user-agent", include_in_schema=False)
qena_shared_lib/utils.py CHANGED
@@ -1,4 +1,5 @@
1
1
  from asyncio import AbstractEventLoop, get_running_loop
2
+ from typing import Generator
2
3
 
3
4
  from pydantic import TypeAdapter
4
5
 
@@ -32,3 +33,12 @@ class TypeAdapterCache:
32
33
  cls.cache_annotation(annotation)
33
34
 
34
35
  return cls._cache[annotation]
36
+
37
+
38
+ class YieldOnce:
39
+ def __await__(self) -> Generator[None, None, None]:
40
+ return (yield)
41
+
42
+
43
+ def yield_now() -> YieldOnce:
44
+ return YieldOnce()
@@ -1,17 +1,23 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qena-shared-lib
3
- Version: 0.1.14
3
+ Version: 0.1.16
4
4
  Summary: A shared tools for other services
5
5
  Requires-Python: >=3.10
6
- Requires-Dist: cronsim==2.6
7
6
  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
7
  Requires-Dist: prometheus-client==0.21.1
13
8
  Requires-Dist: prometheus-fastapi-instrumentator==7.0.2
14
9
  Requires-Dist: punq==0.7.0
10
+ Requires-Dist: pydantic-core==2.27.1
11
+ Requires-Dist: pydantic==2.10.3
12
+ Requires-Dist: starlette==0.41.3
13
+ Requires-Dist: typing-extensions==4.12.2
14
+ Provides-Extra: rabbitmq
15
+ Requires-Dist: pika==1.3.2; extra == 'rabbitmq'
16
+ Provides-Extra: scheduler
17
+ Requires-Dist: cronsim==2.6; extra == 'scheduler'
18
+ Provides-Extra: security
19
+ Requires-Dist: jwt==1.3.1; extra == 'security'
20
+ Requires-Dist: passlib[bcrypt]==1.7.4; extra == 'security'
15
21
  Description-Content-Type: text/markdown
16
22
 
17
23
  # Qena shared lib
@@ -32,9 +38,9 @@ A shared tools for other services. It includes.
32
38
 
33
39
  ## Environment variables
34
40
 
35
- - `LOGGER_NAME` root logger name.
36
- - `UNAUTHORIZED_RESPONSE_CODE` an integer response on an authorized access of resource.
37
- - `TOKEN_HEADER` to header key for jwt token.
41
+ - `QENA_SHARED_LIB_LOGGING_LOGGER_NAME` root logger name.
42
+ - `QENA_SHARED_LIB_SECURITY_UNAUTHORIZED_RESPONSE_CODE` an integer response on an authorized access of resource.
43
+ - `QENA_SHARED_LIB_SECURITY_TOKEN_HEADER` to header key for jwt token.
38
44
 
39
45
  ## Http
40
46
 
@@ -51,6 +57,7 @@ def main() -> FastAPI:
51
57
  .with_description("A shared tools for other services.")
52
58
  .with_version("0.1.0")
53
59
  .with_environment(Environment.PRODUCTION)
60
+ .with_default_exception_handlers()
54
61
  )
55
62
 
56
63
  app = builder.build()
@@ -131,9 +138,7 @@ class UserController(ControllerBase):
131
138
  def main() -> FastAPI:
132
139
  ...
133
140
 
134
- builder.with_controllers([
135
- UserController
136
- ])
141
+ builder.with_controllers(UserController)
137
142
 
138
143
  ...
139
144
  ```
@@ -161,9 +166,7 @@ async def login(
161
166
  def main() -> FastAPI:
162
167
  ...
163
168
 
164
- builder.with_routers([
165
- router
166
- ])
169
+ builder.with_routers(router)
167
170
 
168
171
  ...
169
172
  ```
@@ -270,6 +273,7 @@ def main() -> FastAPI:
270
273
  container=builder.container,
271
274
  )
272
275
 
276
+ rabbitmq.init_default_exception_handlers()
273
277
  rabbitmq.include_listener(UserConsumer)
274
278
  builder.add_singleton(
275
279
  service=RabbitMqManager,
@@ -293,7 +297,7 @@ async def store_user(
293
297
  publisher = rabbitmq.publisher("UserQueue")
294
298
 
295
299
  await publisher.publish(user)
296
- # await publisher.publish_with_arguments(user)
300
+ # await publisher.publish_as_arguments(user)
297
301
  ```
298
302
 
299
303
  ### RPC client
@@ -625,7 +629,7 @@ class UserController(ControllerBase):
625
629
  UserInfo,
626
630
  Authorization(
627
631
  user_type="ADMIN",
628
- persmission=[
632
+ persmissions=[
629
633
  "READ"
630
634
  ],
631
635
  )
@@ -1,31 +1,31 @@
1
- qena_shared_lib/__init__.py,sha256=oyuCR9Pca8aiRka0CXxV2JqO9FWANapkT2NU3VWBrIE,381
1
+ qena_shared_lib/__init__.py,sha256=gYwkSbX7aC96BKp7FysOBDOsbli527haUQpaFtSpF7c,418
2
2
  qena_shared_lib/application.py,sha256=4a1RfI9ZqM5iVHCykjQ_zeDfb7lwqqP5uThS1wYWOAU,7111
3
3
  qena_shared_lib/background.py,sha256=A6ohscchVpBzT2igDnAV6WgbJoQtmjqJYLxZBl6HiNE,3323
4
4
  qena_shared_lib/exception_handlers.py,sha256=wEnmWyLZZBnl1zJpkRNr_m_VNdGr85IBWZxhGdlHe-E,7715
5
5
  qena_shared_lib/exceptions.py,sha256=D9Vs2q03VW_Eo7pD_8RYsZGNkVOOQ4Aq9HpUcnxeRlA,11031
6
6
  qena_shared_lib/http.py,sha256=2u5T9aXmUrg5WoRb3uaKUqG_m_mWey_O-KXi_ANVfz4,25047
7
- qena_shared_lib/logging.py,sha256=NyaKgbaBknti9aYxqrhGhIBuAbybCTmYXrRZtI-Mils,1625
7
+ qena_shared_lib/logging.py,sha256=dEDkhBjU5LY7TspdsylO0hCcrPQz-7xiJx6RWKo4otk,1548
8
8
  qena_shared_lib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- qena_shared_lib/scheduler.py,sha256=_qQ7ugxZi_KBAzdKv6bwxJ_5z7dSsfNxmjk0Y7SO7wo,13111
10
- qena_shared_lib/security.py,sha256=ZWs_XXkLAk6dvToC8pDyEUareb8mScvPbbHN3SPlZio,6128
11
- qena_shared_lib/utils.py,sha256=BGlQjozpR72WuF7wdeim8LjG2j6gSOrmXbcxNPvydN8,850
9
+ qena_shared_lib/scheduler.py,sha256=XNXHrUPkYMfV26DQyFJrMJvjXZhFqMoVaknHrE5E_So,13149
10
+ qena_shared_lib/security.py,sha256=iVk-TUtm9Zl8BZlV51iSyTQOibIiCoHIgVFnXNItrqk,6277
11
+ qena_shared_lib/utils.py,sha256=yoDbtEAhqa30Fubh6h5w919Vuybq23M8yWG-YOa3Cqc,1032
12
12
  qena_shared_lib/dependencies/__init__.py,sha256=W12RgJbhqZ9GiSV1nLlHmpwPzvQv8t7f4JEoazM_WYg,350
13
13
  qena_shared_lib/dependencies/http.py,sha256=IBsMnRr8Jh8ixf2IcU6n1aYRMazI3fF9GLZxHM2dsXk,1492
14
14
  qena_shared_lib/dependencies/miscellaneous.py,sha256=iGwAjatXb_JVSF13n1vdTRAgSKv19VtHo9ZbjjbkIco,753
15
15
  qena_shared_lib/rabbitmq/__init__.py,sha256=1Rw7OP-A9UacuQWHzKbSOa9zFHa4FsEyFTVgAps01tw,1267
16
- qena_shared_lib/rabbitmq/_base.py,sha256=JYdW-gchL82wGCaRR3mjSAXPUUYd8CAxioZqIBhMc6I,22670
17
- qena_shared_lib/rabbitmq/_channel.py,sha256=yb3pCv6i7D5zXAvusOM3aSw-MWy-wfbEym4mOlKZV9E,5882
16
+ qena_shared_lib/rabbitmq/_base.py,sha256=k1RFyMo5zCyUZo7Bn8PPkuCx2pVW9Gb0O08q0WbMFoQ,23125
17
+ qena_shared_lib/rabbitmq/_channel.py,sha256=IitD3OPgg4dkGq5voSr4U5UOuHmCRGMTi4Gi83_zODk,5932
18
18
  qena_shared_lib/rabbitmq/_exception_handlers.py,sha256=Gc8IXWLddl0qr7KHXWjyq_Rl52zMlb8iQiLO-2zwvlk,5757
19
- qena_shared_lib/rabbitmq/_listener.py,sha256=i3Y8pqUuVl_I5Fxt8o-KFEPIbZSL9_oj8pFhUCwOcgo,48346
20
- qena_shared_lib/rabbitmq/_pool.py,sha256=GZcJJygMfXEo5LLxaPB_qCDtgEElPCovHWTvY1VYfIM,1968
21
- qena_shared_lib/rabbitmq/_publisher.py,sha256=vAWLrR4rS6aL2C4iHEk2jG69imoNuzbtzIW4zydqO2U,2468
22
- qena_shared_lib/rabbitmq/_rpc_client.py,sha256=PvEnd-Lr1pDaEFC_eqhF9RIaTp_IjbCRa1uS2bGPTAE,9257
19
+ qena_shared_lib/rabbitmq/_listener.py,sha256=C5J8RqiLCC_ZUMTySqJc3B7fW9_N9cCs2AxsjDeCFyM,48400
20
+ qena_shared_lib/rabbitmq/_pool.py,sha256=eEJswSoWoWzjh290doFYccn1cwQW6DgbdpHeU-7nZSg,2006
21
+ qena_shared_lib/rabbitmq/_publisher.py,sha256=aTasICX_XBuq2FEud3luuaLseCkALb8zUt_ht9EjjKs,2506
22
+ qena_shared_lib/rabbitmq/_rpc_client.py,sha256=BdfsUWRjkmFwD8HLg5Lnrwao98M4Zwj8vS3-Ybk5MmA,9328
23
23
  qena_shared_lib/remotelogging/__init__.py,sha256=DEmzWGadTT9-utyEAAmyVDkWFhsonY4wbWIy1J34C14,245
24
24
  qena_shared_lib/remotelogging/_base.py,sha256=XYd_4iGkXJNT5HC_vLoj5wP4QQp6PCJreVnFv8rQHps,15394
25
25
  qena_shared_lib/remotelogging/logstash/__init__.py,sha256=-sg2V8gYuAKtnHSXfLorpdu_LUB_Gpldw0pCuWIsSc0,186
26
26
  qena_shared_lib/remotelogging/logstash/_base.py,sha256=ZNxE9SjZJW3sWKUUn3i52__X0mZuykaZLL3mp-52EOQ,961
27
27
  qena_shared_lib/remotelogging/logstash/_http_sender.py,sha256=kTUdHE1OOSI72tDbIxmwv1-g8shHldfZ0-nBoSu8TyU,1810
28
28
  qena_shared_lib/remotelogging/logstash/_tcp_sender.py,sha256=hIxDW2zEM07rr7BtgmJ5gR9Cs-MXiPD9qtQoVnrmNJ8,2467
29
- qena_shared_lib-0.1.14.dist-info/METADATA,sha256=GWGe51QzF_Jixj796LMl2DUSqlV6ERObFO4YERFaEzY,11413
30
- qena_shared_lib-0.1.14.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
31
- qena_shared_lib-0.1.14.dist-info/RECORD,,
29
+ qena_shared_lib-0.1.16.dist-info/METADATA,sha256=OgRzBYcHpZnknzpnDXbRRSP7AScsVGvF-rQRV9nUfAc,11819
30
+ qena_shared_lib-0.1.16.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
31
+ qena_shared_lib-0.1.16.dist-info/RECORD,,