qena-shared-lib 0.1.15__tar.gz → 0.1.17__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.15 → qena_shared_lib-0.1.17}/CHANGELOG.md +17 -0
  2. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/PKG-INFO +20 -9
  3. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/README.md +3 -3
  4. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/pyproject.toml +23 -6
  5. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/src/qena_shared_lib/__init__.py +4 -3
  6. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/src/qena_shared_lib/logging.py +3 -1
  7. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/src/qena_shared_lib/rabbitmq/_base.py +7 -4
  8. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/src/qena_shared_lib/rabbitmq/_channel.py +7 -4
  9. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/src/qena_shared_lib/rabbitmq/_listener.py +8 -5
  10. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/src/qena_shared_lib/rabbitmq/_pool.py +4 -1
  11. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/src/qena_shared_lib/rabbitmq/_publisher.py +4 -1
  12. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/src/qena_shared_lib/rabbitmq/_rpc_client.py +11 -6
  13. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/src/qena_shared_lib/scheduler.py +4 -1
  14. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/src/qena_shared_lib/security.py +15 -6
  15. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/uv.lock +825 -810
  16. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/.gitignore +0 -0
  17. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/.pre-commit-config.yaml +0 -0
  18. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/src/qena_shared_lib/application.py +0 -0
  19. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/src/qena_shared_lib/background.py +0 -0
  20. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/src/qena_shared_lib/dependencies/__init__.py +0 -0
  21. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/src/qena_shared_lib/dependencies/http.py +0 -0
  22. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/src/qena_shared_lib/dependencies/miscellaneous.py +0 -0
  23. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/src/qena_shared_lib/exception_handlers.py +0 -0
  24. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/src/qena_shared_lib/exceptions.py +0 -0
  25. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/src/qena_shared_lib/http.py +0 -0
  26. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/src/qena_shared_lib/py.typed +0 -0
  27. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/src/qena_shared_lib/rabbitmq/__init__.py +0 -0
  28. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/src/qena_shared_lib/rabbitmq/_exception_handlers.py +0 -0
  29. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/src/qena_shared_lib/remotelogging/__init__.py +0 -0
  30. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/src/qena_shared_lib/remotelogging/_base.py +0 -0
  31. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/src/qena_shared_lib/remotelogging/logstash/__init__.py +0 -0
  32. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/src/qena_shared_lib/remotelogging/logstash/_base.py +0 -0
  33. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/src/qena_shared_lib/remotelogging/logstash/_http_sender.py +0 -0
  34. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/src/qena_shared_lib/remotelogging/logstash/_tcp_sender.py +0 -0
  35. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/src/qena_shared_lib/utils.py +0 -0
  36. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/tests/conftest.py +0 -0
  37. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/tests/test_application.py +0 -0
  38. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/tests/test_background.py +0 -0
  39. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/tests/test_dependencies.py +0 -0
  40. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/tests/test_logstash.py +0 -0
  41. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/tests/test_rabbitmq.py +0 -0
  42. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/tests/test_scheduler.py +0 -0
  43. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/tests/test_security.py +0 -0
  44. {qena_shared_lib-0.1.15 → qena_shared_lib-0.1.17}/tests/utils.py +0 -0
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.17] - 2025-07-16
4
+
5
+ ### Changed
6
+
7
+ - Added `all` extra dependecies
8
+
9
+
10
+ ## [0.1.16] - 2025-07-15
11
+
12
+ ### Changed
13
+
14
+ - Added a prefix for environment variables with `QENA_SHARED_LIB_{MODULE_NAME}`
15
+ - Added optional extra dependencies
16
+
17
+
3
18
  ## [0.1.15] - 2025-06-28
4
19
 
5
20
  ### Changed
@@ -37,6 +52,8 @@
37
52
  - Added a re-export for rabbitmq channel pool (ChannelPool) class.
38
53
 
39
54
 
55
+ [0.1.17]: https://github.com/Qena-Digital-Lending/qena-shared-kernel/compare/v0.1.16...v0.1.17
56
+ [0.1.16]: https://github.com/Qena-Digital-Lending/qena-shared-kernel/compare/v0.1.15...v0.1.16
40
57
  [0.1.15]: https://github.com/Qena-Digital-Lending/qena-shared-kernel/compare/v0.1.14...v0.1.15
41
58
  [0.1.14]: https://github.com/Qena-Digital-Lending/qena-shared-kernel/compare/v0.1.13...v0.1.14
42
59
  [0.1.13]: https://github.com/Qena-Digital-Lending/qena-shared-kernel/compare/v0.1.12...v0.1.13
@@ -1,17 +1,28 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qena-shared-lib
3
- Version: 0.1.15
3
+ Version: 0.1.17
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: all
15
+ Requires-Dist: cronsim==2.6; extra == 'all'
16
+ Requires-Dist: jwt==1.3.1; extra == 'all'
17
+ Requires-Dist: passlib[bcrypt]==1.7.4; extra == 'all'
18
+ Requires-Dist: pika==1.3.2; extra == 'all'
19
+ Provides-Extra: rabbitmq
20
+ Requires-Dist: pika==1.3.2; extra == 'rabbitmq'
21
+ Provides-Extra: scheduler
22
+ Requires-Dist: cronsim==2.6; extra == 'scheduler'
23
+ Provides-Extra: security
24
+ Requires-Dist: jwt==1.3.1; extra == 'security'
25
+ Requires-Dist: passlib[bcrypt]==1.7.4; extra == 'security'
15
26
  Description-Content-Type: text/markdown
16
27
 
17
28
  # Qena shared lib
@@ -32,9 +43,9 @@ A shared tools for other services. It includes.
32
43
 
33
44
  ## Environment variables
34
45
 
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.
46
+ - `QENA_SHARED_LIB_LOGGING_LOGGER_NAME` root logger name.
47
+ - `QENA_SHARED_LIB_SECURITY_UNAUTHORIZED_RESPONSE_CODE` an integer response on an authorized access of resource.
48
+ - `QENA_SHARED_LIB_SECURITY_TOKEN_HEADER` to header key for jwt token.
38
49
 
39
50
  ## Http
40
51
 
@@ -16,9 +16,9 @@ A shared tools for other services. It includes.
16
16
 
17
17
  ## Environment variables
18
18
 
19
- - `LOGGER_NAME` root logger name.
20
- - `UNAUTHORIZED_RESPONSE_CODE` an integer response on an authorized access of resource.
21
- - `TOKEN_HEADER` to header key for jwt token.
19
+ - `QENA_SHARED_LIB_LOGGING_LOGGER_NAME` root logger name.
20
+ - `QENA_SHARED_LIB_SECURITY_UNAUTHORIZED_RESPONSE_CODE` an integer response on an authorized access of resource.
21
+ - `QENA_SHARED_LIB_SECURITY_TOKEN_HEADER` to header key for jwt token.
22
22
 
23
23
  ## Http
24
24
 
@@ -1,19 +1,36 @@
1
1
  [project]
2
2
  name = "qena-shared-lib"
3
- version = "0.1.15"
3
+ version = "0.1.17"
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.6",
9
8
  "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
9
  "prometheus-client==0.21.1",
15
10
  "prometheus-fastapi-instrumentator==7.0.2",
16
11
  "punq==0.7.0",
12
+ "pydantic-core==2.27.1",
13
+ "pydantic==2.10.3",
14
+ "starlette==0.41.3",
15
+ "typing-extensions==4.12.2",
16
+ ]
17
+
18
+ [project.optional-dependencies]
19
+ rabbitmq = [
20
+ "pika==1.3.2",
21
+ ]
22
+ scheduler = [
23
+ "cronsim==2.6",
24
+ ]
25
+ security = [
26
+ "jwt==1.3.1",
27
+ "passlib[bcrypt]==1.7.4",
28
+ ]
29
+ all = [
30
+ "cronsim==2.6",
31
+ "jwt==1.3.1",
32
+ "passlib[bcrypt]==1.7.4",
33
+ "pika==1.3.2",
17
34
  ]
18
35
 
19
36
  [build-system]
@@ -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
 
@@ -13,7 +13,9 @@ __all__ = [
13
13
  "LoggerProvider",
14
14
  ]
15
15
 
16
- 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
+ )
17
19
 
18
20
 
19
21
  class 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
@@ -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)