rb-commons 0.1.24__tar.gz → 0.2.3__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 (28) hide show
  1. {rb-commons-0.1.24 → rb_commons-0.2.3}/PKG-INFO +12 -2
  2. rb_commons-0.2.3/rb_commons/broker/consumer.py +29 -0
  3. {rb-commons-0.1.24 → rb_commons-0.2.3}/rb_commons/configs/config.py +4 -0
  4. rb_commons-0.2.3/rb_commons/configs/rabbitmq.py +26 -0
  5. rb_commons-0.2.3/rb_commons/http/base_api.py +91 -0
  6. rb_commons-0.2.3/rb_commons/utils/__init__.py +0 -0
  7. {rb-commons-0.1.24 → rb_commons-0.2.3}/rb_commons.egg-info/PKG-INFO +12 -2
  8. {rb-commons-0.1.24 → rb_commons-0.2.3}/rb_commons.egg-info/SOURCES.txt +4 -0
  9. {rb-commons-0.1.24 → rb_commons-0.2.3}/rb_commons.egg-info/requires.txt +1 -0
  10. {rb-commons-0.1.24 → rb_commons-0.2.3}/setup.py +3 -2
  11. {rb-commons-0.1.24 → rb_commons-0.2.3}/README.md +0 -0
  12. {rb-commons-0.1.24 → rb_commons-0.2.3}/rb_commons/__init__.py +0 -0
  13. {rb-commons-0.1.24/rb_commons/configs → rb_commons-0.2.3/rb_commons/broker}/__init__.py +0 -0
  14. {rb-commons-0.1.24/rb_commons/http → rb_commons-0.2.3/rb_commons/configs}/__init__.py +0 -0
  15. {rb-commons-0.1.24 → rb_commons-0.2.3}/rb_commons/configs/injections.py +0 -0
  16. {rb-commons-0.1.24/rb_commons/orm → rb_commons-0.2.3/rb_commons/http}/__init__.py +0 -0
  17. {rb-commons-0.1.24 → rb_commons-0.2.3}/rb_commons/http/exceptions.py +0 -0
  18. {rb-commons-0.1.24/rb_commons/permissions → rb_commons-0.2.3/rb_commons/orm}/__init__.py +0 -0
  19. {rb-commons-0.1.24 → rb_commons-0.2.3}/rb_commons/orm/exceptions.py +0 -0
  20. {rb-commons-0.1.24 → rb_commons-0.2.3}/rb_commons/orm/managers.py +0 -0
  21. {rb-commons-0.1.24/rb_commons/schemes → rb_commons-0.2.3/rb_commons/permissions}/__init__.py +0 -0
  22. {rb-commons-0.1.24 → rb_commons-0.2.3}/rb_commons/permissions/role_permissions.py +0 -0
  23. {rb-commons-0.1.24/rb_commons/utils → rb_commons-0.2.3/rb_commons/schemes}/__init__.py +0 -0
  24. {rb-commons-0.1.24 → rb_commons-0.2.3}/rb_commons/schemes/jwt.py +0 -0
  25. {rb-commons-0.1.24 → rb_commons-0.2.3}/rb_commons/utils/media.py +0 -0
  26. {rb-commons-0.1.24 → rb_commons-0.2.3}/rb_commons.egg-info/dependency_links.txt +0 -0
  27. {rb-commons-0.1.24 → rb_commons-0.2.3}/rb_commons.egg-info/top_level.txt +0 -0
  28. {rb-commons-0.1.24 → rb_commons-0.2.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: rb-commons
3
- Version: 0.1.24
3
+ Version: 0.2.3
4
4
  Summary: Commons of project and simplified orm based on sqlalchemy.
5
5
  Home-page: https://github.com/RoboSell-organization/rb-commons
6
6
  Author: Abdulvoris
@@ -17,6 +17,16 @@ Requires-Dist: PyJWT==2.10.1
17
17
  Requires-Dist: python-dotenv==1.0.1
18
18
  Requires-Dist: SQLAlchemy==2.0.36
19
19
  Requires-Dist: fastapi<0.120.0,>=0.115.6
20
+ Requires-Dist: aio-pika==9.5.5
21
+ Dynamic: author
22
+ Dynamic: author-email
23
+ Dynamic: classifier
24
+ Dynamic: description
25
+ Dynamic: description-content-type
26
+ Dynamic: home-page
27
+ Dynamic: requires-dist
28
+ Dynamic: requires-python
29
+ Dynamic: summary
20
30
 
21
31
  # RB-Commons
22
32
 
@@ -0,0 +1,29 @@
1
+ from aio_pika import ExchangeType, IncomingMessage
2
+ from rb_commons.configs.rabbitmq import RabbitMQConnection
3
+
4
+
5
+ class BaseRabbitMQConsumer:
6
+ def __init__(self, exchange_name: str, queue_name: str, routing_key: str):
7
+ self.exchange_name = exchange_name
8
+ self.queue_name = queue_name
9
+ self.routing_key = routing_key
10
+
11
+ async def setup(self, channel):
12
+ exchange = await channel.declare_exchange(self.exchange_name, ExchangeType.DIRECT, durable=True)
13
+ queue = await channel.declare_queue(self.queue_name, durable=True)
14
+ await queue.bind(exchange, routing_key=self.routing_key)
15
+ return queue
16
+
17
+ async def consume(self):
18
+ async with RabbitMQConnection.get_channel() as channel:
19
+ queue = await self.setup(channel)
20
+ async with queue.iterator() as queue_iter:
21
+ async for message in queue_iter:
22
+ await self.process_message(message)
23
+
24
+ async def process_message(self, message: IncomingMessage):
25
+ async with message.process():
26
+ await self.handle_message(message.body.decode())
27
+
28
+ async def handle_message(self, body: str):
29
+ raise NotImplementedError("This method should be overridden by subclasses.")
@@ -20,6 +20,10 @@ class CommonConfigs(BaseSettings):
20
20
  POSTGRES_DB: Optional[str] = None
21
21
  DB_ALEMBIC_URL: Optional[str] = None
22
22
 
23
+ # Broker
24
+
25
+ RABBITMQ_URL: Optional[str] = None
26
+
23
27
  DIGITALOCEAN_STORAGE_BUCKET_NAME: Optional[str] = None
24
28
  DIGITALOCEAN_S3_ENDPOINT_URL: Optional[str] = None
25
29
 
@@ -0,0 +1,26 @@
1
+ from contextlib import asynccontextmanager
2
+ from aio_pika import connect_robust, Message, ExchangeType
3
+ from rb_commons.configs.config import configs
4
+
5
+ class RabbitMQConnection:
6
+ _connection = None
7
+ _channel = None
8
+
9
+ @classmethod
10
+ @asynccontextmanager
11
+ async def get_channel(cls):
12
+ if not cls._connection:
13
+ cls._connection = await connect_robust(configs.RABBITMQ_URL)
14
+ cls._channel = await cls._connection.channel()
15
+
16
+ try:
17
+ yield cls._channel
18
+ finally:
19
+ pass
20
+
21
+ @classmethod
22
+ async def close(cls):
23
+ if cls._connection:
24
+ await cls._connection.close()
25
+ cls._connection = None
26
+ cls._channel = None
@@ -0,0 +1,91 @@
1
+ import json
2
+ import requests
3
+ from rb_commons.http.exceptions import BadRequestException, InternalException
4
+ from requests import RequestException
5
+
6
+ class BaseAPI:
7
+ def __init__(self, base_url: str):
8
+ self.BASE_URL = base_url
9
+
10
+ def _make_request(self, method: str, path: str, data: dict = None,
11
+ params: dict = None, headers: dict = None, reset_base_url: bool = False, form_encoded: bool = False) -> requests.Response:
12
+ """
13
+ A general method to make HTTP requests (GET, POST, etc.)
14
+
15
+ This method abstracts the process of making HTTP requests, allowing for
16
+ different types of requests (GET, POST, PUT, DELETE) to be easily performed
17
+ by specifying the method and other parameters. This adheres to the DRY
18
+ (Don't Repeat Yourself) principle by centralizing request handling.
19
+
20
+ :param method: HTTP method to use for the request (e.g., 'GET', 'POST', 'PUT', 'DELETE').
21
+ :param path: The API endpoint path to which the request is made. This should be
22
+ relative to the base URL defined in the class.
23
+ :param data: Optional dictionary containing the data to be sent in the body of
24
+ the request (used for POST and PUT requests). Default is None.
25
+ :param params: Optional dictionary containing query parameters to be included
26
+ in the request URL. Default is None.
27
+ :param headers: Optional dictionary containing any custom headers to be sent
28
+ with the request. Default is None.
29
+ :return: Response object containing the server's response to the HTTP request.
30
+ :raises HttpException: Raises a custom HttpException if the request fails for
31
+ any reason, including invalid HTTP methods, network issues,
32
+ or JSON parsing errors.
33
+
34
+ The method constructs the full URL from the base URL and the provided path.
35
+ It uses a dictionary to map HTTP methods to their respective request functions
36
+ from the requests library. After making the request, it checks the response
37
+ status and attempts to parse the response as JSON.
38
+ """
39
+ url = self.BASE_URL + path
40
+
41
+ if reset_base_url:
42
+ url = path
43
+
44
+ try:
45
+ request_methods = {
46
+ 'POST': requests.post,
47
+ 'GET': requests.get,
48
+ 'PUT': requests.put,
49
+ 'DELETE': requests.delete
50
+ }
51
+
52
+ if method not in request_methods:
53
+ raise BadRequestException(f"Unsupported HTTP method: {method}")
54
+
55
+ kwargs = {
56
+ 'params': params,
57
+ 'headers': headers,
58
+ 'data' if form_encoded else 'json': data
59
+ }
60
+
61
+ response = request_methods[method](url, **kwargs)
62
+
63
+ data = response.json()
64
+
65
+ if not (200 <= response.status_code < 300):
66
+ error_message = data.get("message")
67
+ if error_message is not None:
68
+ raise BadRequestException(error_message)
69
+
70
+ raise BadRequestException(f"Unexpected error occured: {response.text}")
71
+
72
+ return response
73
+
74
+ except RequestException as e:
75
+ raise BadRequestException(f"Request failed: {e}")
76
+ except (json.JSONDecodeError, ValueError) as e:
77
+ raise InternalException(f"Failed to parse JSON: {e}")
78
+ except Exception as e:
79
+ raise InternalException("Something went wrong")
80
+
81
+ def _post(self, path: str, data: dict, headers: dict = None, params: dict = None, reset_base_url: bool = False, form_encoded: bool = False) -> requests.Response:
82
+ return self._make_request('POST', path, data=data, headers=headers, params=params, reset_base_url=reset_base_url, form_encoded=form_encoded)
83
+
84
+ def _get(self, path: str, params: dict = None, headers: dict = None, reset_base_url: bool = False, form_encoded: bool = False) -> requests.Response:
85
+ return self._make_request('GET', path, params=params, headers=headers, reset_base_url=reset_base_url, form_encoded=form_encoded)
86
+
87
+ def _put(self, path: str, params: dict = None, data: dict = None, headers: dict = None, reset_base_url: bool = False, form_encoded: bool = False) -> requests.Response:
88
+ return self._make_request('PUT', path, params=params, data=data, headers=headers, reset_base_url=reset_base_url, form_encoded=form_encoded)
89
+
90
+ def _delete(self, path: str, headers: dict = None, reset_base_url: bool = False, form_encoded: bool = False) -> requests.Response:
91
+ return self._make_request('DELETE', path, headers=headers, reset_base_url=reset_base_url, form_encoded=form_encoded)
File without changes
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: rb-commons
3
- Version: 0.1.24
3
+ Version: 0.2.3
4
4
  Summary: Commons of project and simplified orm based on sqlalchemy.
5
5
  Home-page: https://github.com/RoboSell-organization/rb-commons
6
6
  Author: Abdulvoris
@@ -17,6 +17,16 @@ Requires-Dist: PyJWT==2.10.1
17
17
  Requires-Dist: python-dotenv==1.0.1
18
18
  Requires-Dist: SQLAlchemy==2.0.36
19
19
  Requires-Dist: fastapi<0.120.0,>=0.115.6
20
+ Requires-Dist: aio-pika==9.5.5
21
+ Dynamic: author
22
+ Dynamic: author-email
23
+ Dynamic: classifier
24
+ Dynamic: description
25
+ Dynamic: description-content-type
26
+ Dynamic: home-page
27
+ Dynamic: requires-dist
28
+ Dynamic: requires-python
29
+ Dynamic: summary
20
30
 
21
31
  # RB-Commons
22
32
 
@@ -6,10 +6,14 @@ rb_commons.egg-info/SOURCES.txt
6
6
  rb_commons.egg-info/dependency_links.txt
7
7
  rb_commons.egg-info/requires.txt
8
8
  rb_commons.egg-info/top_level.txt
9
+ rb_commons/broker/__init__.py
10
+ rb_commons/broker/consumer.py
9
11
  rb_commons/configs/__init__.py
10
12
  rb_commons/configs/config.py
11
13
  rb_commons/configs/injections.py
14
+ rb_commons/configs/rabbitmq.py
12
15
  rb_commons/http/__init__.py
16
+ rb_commons/http/base_api.py
13
17
  rb_commons/http/exceptions.py
14
18
  rb_commons/orm/__init__.py
15
19
  rb_commons/orm/exceptions.py
@@ -5,3 +5,4 @@ PyJWT==2.10.1
5
5
  python-dotenv==1.0.1
6
6
  SQLAlchemy==2.0.36
7
7
  fastapi<0.120.0,>=0.115.6
8
+ aio-pika==9.5.5
@@ -5,7 +5,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
5
5
 
6
6
  setup(
7
7
  name="rb-commons",
8
- version="0.1.24",
8
+ version="0.2.3",
9
9
  author="Abdulvoris",
10
10
  author_email="erkinovabdulvoris101@gmail.com",
11
11
  description="Commons of project and simplified orm based on sqlalchemy.",
@@ -26,6 +26,7 @@ setup(
26
26
  "PyJWT==2.10.1",
27
27
  "python-dotenv==1.0.1",
28
28
  "SQLAlchemy==2.0.36",
29
- "fastapi>=0.115.6,<0.120.0"
29
+ "fastapi>=0.115.6,<0.120.0",
30
+ "aio-pika==9.5.5"
30
31
  ],
31
32
  )
File without changes
File without changes