anzu 0.1.4__py3-none-any.whl → 0.1.5__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.
- anzu/__init__.py +5 -1
- anzu/__main__.py +0 -0
- anzu/logger/__init__.py +1 -0
- anzu/logger/logger.py +45 -0
- anzu/websocket/__init__.py +1 -0
- anzu/websocket/sockets.py +14 -0
- anzu/worker/__init__.py +2 -0
- anzu/worker/client.py +112 -0
- anzu/worker/constants.py +4 -0
- anzu/worker/exceptions.py +14 -0
- anzu/worker/utils.py +25 -0
- {anzu-0.1.4.dist-info → anzu-0.1.5.dist-info}/METADATA +8 -24
- anzu-0.1.5.dist-info/RECORD +16 -0
- {anzu-0.1.4.dist-info → anzu-0.1.5.dist-info}/WHEEL +1 -2
- anzu-0.1.5.dist-info/entry_points.txt +2 -0
- anzu-0.1.4.dist-info/RECORD +0 -6
- anzu-0.1.4.dist-info/top_level.txt +0 -1
- {anzu-0.1.4.dist-info → anzu-0.1.5.dist-info}/licenses/LICENSE +0 -0
anzu/__init__.py
CHANGED
anzu/__main__.py
ADDED
File without changes
|
anzu/logger/__init__.py
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
from .logger import redis_logger, logger, AnzuLogger
|
anzu/logger/logger.py
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
import logging
|
2
|
+
|
3
|
+
|
4
|
+
class AnzuLogger:
|
5
|
+
_instance = None
|
6
|
+
|
7
|
+
def __new__(cls, level: str = logging.INFO, name: str = __name__):
|
8
|
+
# Ensures that only one instance of the logger is created
|
9
|
+
if cls._instance is None:
|
10
|
+
cls._instance = super(AnzuLogger, cls).__new__(cls)
|
11
|
+
cls._instance._logger = logging.getLogger(name)
|
12
|
+
cls._instance._logger.setLevel(logging.INFO) # Default log level
|
13
|
+
handler = logging.StreamHandler() # You can also use FileHandler
|
14
|
+
formatter = logging.Formatter(
|
15
|
+
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
16
|
+
)
|
17
|
+
handler.setFormatter(formatter)
|
18
|
+
cls._instance._logger.addHandler(handler)
|
19
|
+
|
20
|
+
return cls._instance._logger
|
21
|
+
|
22
|
+
def get_logger(self):
|
23
|
+
"""Returns the logger instance."""
|
24
|
+
return self._instance._logger
|
25
|
+
|
26
|
+
def set_name(self, name: str):
|
27
|
+
"""Sets the name of the logger."""
|
28
|
+
self._instance._logger = logging.getLogger(name)
|
29
|
+
|
30
|
+
def add_file_handler(self, file_name: str):
|
31
|
+
"""Adds a file handler to the logger."""
|
32
|
+
handler = logging.FileHandler(file_name)
|
33
|
+
formatter = logging.Formatter(
|
34
|
+
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
35
|
+
)
|
36
|
+
handler.setFormatter(formatter)
|
37
|
+
self._instance._logger.addHandler(handler)
|
38
|
+
|
39
|
+
def remove_handler(self, handler):
|
40
|
+
"""Removes a handler from the logger."""
|
41
|
+
self._instance._logger.removeHandler(handler)
|
42
|
+
|
43
|
+
|
44
|
+
logger = AnzuLogger()
|
45
|
+
redis_logger = AnzuLogger(name="redis_logger")
|
@@ -0,0 +1 @@
|
|
1
|
+
from .sockets import send_socket_response, emit_socket_event
|
@@ -0,0 +1,14 @@
|
|
1
|
+
import socketio
|
2
|
+
|
3
|
+
# Create client
|
4
|
+
sio = socketio.Client(ssl_verify=False)
|
5
|
+
sio_server = 'https://django:9500'
|
6
|
+
|
7
|
+
def emit_socket_event(event, data):
|
8
|
+
if sio.connected is False:
|
9
|
+
sio.connect(sio_server)
|
10
|
+
|
11
|
+
sio.emit(event, data)
|
12
|
+
|
13
|
+
def send_socket_response(event, data):
|
14
|
+
emit_socket_event(event, data)
|
anzu/worker/__init__.py
ADDED
anzu/worker/client.py
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
import json
|
2
|
+
import requests
|
3
|
+
from requests.auth import HTTPBasicAuth
|
4
|
+
from .exceptions import QueueUpdateError
|
5
|
+
from .utils import get_env_var, setup_logger
|
6
|
+
|
7
|
+
logger = setup_logger()
|
8
|
+
|
9
|
+
|
10
|
+
class QueueClient:
|
11
|
+
"""Client for updating queue items in a Django service."""
|
12
|
+
|
13
|
+
def __init__(self, django_url=None, username=None, password=None, service_endpoint=None, verify_ssl=None):
|
14
|
+
"""
|
15
|
+
Initialize the queue client with connection parameters.
|
16
|
+
|
17
|
+
Args:
|
18
|
+
django_url (str, optional): URL of the Django service. Defaults to DJANGO_URL env var.
|
19
|
+
username (str, optional): Django superuser username. Defaults to DJANGO_SUPERUSER_USERNAME env var.
|
20
|
+
password (str, optional): Django superuser password. Defaults to DJANGO_SUPERUSER_PASSWORD env var.
|
21
|
+
service_endpoint (str, optional): Service endpoint. Defaults to SERVICE_ENDPOINT env var or '/'.
|
22
|
+
verify_ssl (bool, optional): Whether to verify SSL certificates. Defaults to True unless URL contains 'https'.
|
23
|
+
"""
|
24
|
+
self.django_url = django_url or get_env_var('DJANGO_URL', required=True)
|
25
|
+
self.username = username or get_env_var('DJANGO_SUPERUSER_USERNAME', required=True)
|
26
|
+
self.password = password or get_env_var('DJANGO_SUPERUSER_PASSWORD', required=True)
|
27
|
+
self.service_endpoint = service_endpoint or get_env_var('SERVICE_ENDPOINT', '/')
|
28
|
+
|
29
|
+
# Handle the verify_ssl parameter
|
30
|
+
if verify_ssl is None:
|
31
|
+
self.verify_ssl = False if 'https' in self.django_url else True
|
32
|
+
else:
|
33
|
+
self.verify_ssl = verify_ssl
|
34
|
+
|
35
|
+
self.headers = {
|
36
|
+
'Content-Type': 'application/json'
|
37
|
+
}
|
38
|
+
|
39
|
+
def update_queue_item(self, qi_hash, status, data=None, error=None, timeout=10):
|
40
|
+
"""
|
41
|
+
Update a queue item with the given status and optional data or error.
|
42
|
+
|
43
|
+
Args:
|
44
|
+
qi_hash (str): Hash of the queue item to update.
|
45
|
+
status (str): New status for the queue item.
|
46
|
+
data (dict, optional): Additional data to update. Defaults to None.
|
47
|
+
error (str, optional): Error message if applicable. Defaults to None.
|
48
|
+
timeout (int, optional): Request timeout in seconds. Defaults to 10.
|
49
|
+
|
50
|
+
Returns:
|
51
|
+
dict: Response data from the API
|
52
|
+
|
53
|
+
Raises:
|
54
|
+
TypeError: If data is not a dictionary.
|
55
|
+
QueueUpdateError: If the update request fails.
|
56
|
+
"""
|
57
|
+
if not qi_hash:
|
58
|
+
logger.warning("No queue item to update")
|
59
|
+
return
|
60
|
+
|
61
|
+
payload = {
|
62
|
+
"status": status
|
63
|
+
}
|
64
|
+
|
65
|
+
if data is not None:
|
66
|
+
if not isinstance(data, dict):
|
67
|
+
raise TypeError(f"Expected dict, got {type(data)} with value: {data}")
|
68
|
+
payload.update(data)
|
69
|
+
|
70
|
+
if error is not None:
|
71
|
+
payload['error'] = error
|
72
|
+
|
73
|
+
url = f'{self.django_url}{self.service_endpoint}{qi_hash}/'
|
74
|
+
|
75
|
+
response = requests.request(
|
76
|
+
"PATCH",
|
77
|
+
url,
|
78
|
+
headers=self.headers,
|
79
|
+
data=json.dumps(payload),
|
80
|
+
auth=HTTPBasicAuth(self.username, self.password),
|
81
|
+
verify=self.verify_ssl,
|
82
|
+
timeout=timeout
|
83
|
+
)
|
84
|
+
|
85
|
+
if response.status_code not in [200, 204]:
|
86
|
+
response_text = None
|
87
|
+
if 'text/html' in response.headers.get('Content-Type', ''):
|
88
|
+
logger.error(f"Failed to update queue item. Status Code: {response.status_code}")
|
89
|
+
else:
|
90
|
+
response_text = response.text
|
91
|
+
logger.error(
|
92
|
+
f"Failed to update queue item. Status Code: {response.status_code}, Response: {response_text}")
|
93
|
+
|
94
|
+
raise QueueUpdateError(response.status_code, response_text)
|
95
|
+
|
96
|
+
try:
|
97
|
+
return response.json()
|
98
|
+
except (ValueError, json.JSONDecodeError):
|
99
|
+
# Return empty dict if no JSON in response
|
100
|
+
return {}
|
101
|
+
|
102
|
+
|
103
|
+
# For backwards compatibility
|
104
|
+
def update_queue_item(qi_hash, status, data=None, error=None):
|
105
|
+
"""
|
106
|
+
Legacy function to update a queue item. Uses environment variables for connection details.
|
107
|
+
|
108
|
+
This function exists for backwards compatibility with the original code.
|
109
|
+
New code should use the QueueClient class instead.
|
110
|
+
"""
|
111
|
+
client = QueueClient()
|
112
|
+
return client.update_queue_item(qi_hash, status, data, error)
|
anzu/worker/constants.py
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
class QueueUpdaterError(Exception):
|
2
|
+
"""Base exception for queue updater."""
|
3
|
+
pass
|
4
|
+
|
5
|
+
|
6
|
+
class QueueUpdateError(QueueUpdaterError):
|
7
|
+
"""Exception raised when updating a queue item fails."""
|
8
|
+
def __init__(self, status_code, response_text=None):
|
9
|
+
self.status_code = status_code
|
10
|
+
self.response_text = response_text
|
11
|
+
message = f"Failed to update queue item. Status Code: {status_code}"
|
12
|
+
if response_text:
|
13
|
+
message += f", Response: {response_text}"
|
14
|
+
super().__init__(message)
|
anzu/worker/utils.py
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
import logging
|
2
|
+
import os
|
3
|
+
|
4
|
+
|
5
|
+
def get_env_var(name, default=None, required=False):
|
6
|
+
"""Get environment variable with proper error handling."""
|
7
|
+
value = os.environ.get(name, default)
|
8
|
+
if required and value is None:
|
9
|
+
raise ValueError(f"Required environment variable '{name}' is not set")
|
10
|
+
return value
|
11
|
+
|
12
|
+
|
13
|
+
def setup_logger(name='queue_updater', level=logging.INFO):
|
14
|
+
"""Setup and return a logger with the given name and level."""
|
15
|
+
logger = logging.getLogger(name)
|
16
|
+
|
17
|
+
# Only add handler if not already added to avoid duplicate logs
|
18
|
+
if not logger.handlers:
|
19
|
+
handler = logging.StreamHandler()
|
20
|
+
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
21
|
+
handler.setFormatter(formatter)
|
22
|
+
logger.addHandler(handler)
|
23
|
+
|
24
|
+
logger.setLevel(level)
|
25
|
+
return logger
|
@@ -1,35 +1,19 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: anzu
|
3
|
-
Version: 0.1.
|
4
|
-
Summary:
|
5
|
-
Home-page: https://github.com/yourusername/queue_updater
|
6
|
-
Author: Your Name
|
3
|
+
Version: 0.1.5
|
4
|
+
Summary: Anzu package for workers
|
7
5
|
Author-email: Your Name <your.email@example.com>
|
8
6
|
License: MIT
|
9
|
-
|
10
|
-
Project-URL: Bug Tracker, https://github.com/yourusername/queue_updater/issues
|
7
|
+
License-File: LICENSE
|
11
8
|
Keywords: django,queue,update
|
12
|
-
Classifier: Programming Language :: Python :: 3
|
13
9
|
Classifier: License :: OSI Approved :: MIT License
|
14
10
|
Classifier: Operating System :: OS Independent
|
15
|
-
|
16
|
-
|
17
|
-
License-File: LICENSE
|
18
|
-
Requires-Dist: requests>=2.25.0
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
12
|
+
Requires-Python: >=3.8
|
19
13
|
Requires-Dist: aiohttp>=3.7.3
|
20
14
|
Requires-Dist: python-socketio>=5.12.1
|
21
|
-
|
22
|
-
|
23
|
-
Provides-Extra: dev
|
24
|
-
Requires-Dist: pytest>=6.0.0; extra == "dev"
|
25
|
-
Requires-Dist: black>=22.0.0; extra == "dev"
|
26
|
-
Requires-Dist: isort>=5.0.0; extra == "dev"
|
27
|
-
Requires-Dist: mypy>=0.900; extra == "dev"
|
28
|
-
Requires-Dist: flake8>=4.0.0; extra == "dev"
|
29
|
-
Dynamic: author
|
30
|
-
Dynamic: home-page
|
31
|
-
Dynamic: license-file
|
32
|
-
Dynamic: requires-python
|
15
|
+
Requires-Dist: requests>=2.25.0
|
16
|
+
Description-Content-Type: text/markdown
|
33
17
|
|
34
18
|
# Queue Updater
|
35
19
|
|
@@ -104,4 +88,4 @@ update_queue_item(
|
|
104
88
|
|
105
89
|
## License
|
106
90
|
|
107
|
-
MIT
|
91
|
+
MIT
|
@@ -0,0 +1,16 @@
|
|
1
|
+
anzu/__init__.py,sha256=rNEjTqQzvpIw6-SKRv1Vy68XnX99GUoSYSKqCCFEHXM,83
|
2
|
+
anzu/__main__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
|
+
anzu/logger/__init__.py,sha256=kb2kDG1QFvRU48_Seod3RHVCrpq1udgzACOdmy7-Rg8,52
|
4
|
+
anzu/logger/logger.py,sha256=M6oVFVUFD053BXWKEkj0Mz--d3FbvFGcKWFexsYsbco,1584
|
5
|
+
anzu/websocket/__init__.py,sha256=vJVQgpYZZeJtIt9KrlhP049l_Xx_eFpSQrZlLxyluuQ,60
|
6
|
+
anzu/websocket/sockets.py,sha256=VOGePsUkBMvP-54gabY6nPW5zAWMOujPoBenbIwiPPE,309
|
7
|
+
anzu/worker/__init__.py,sha256=6SGGl1IOaSfJP0lOHEYI-8ENv_Ed8FvpNzCc0UMYkGw,98
|
8
|
+
anzu/worker/client.py,sha256=SBBPAxJu9n1vfoqTSLu-SvjsARx0JvB4NhHEJ4bTLks,4347
|
9
|
+
anzu/worker/constants.py,sha256=Z_w0Hr-PtZ9mLDJwEkrfMKebCdm7GJidNXtjnJwQzkc,59
|
10
|
+
anzu/worker/exceptions.py,sha256=At2boea4ABjyph9b59pAyUIaSF5C0zl8Scqjxmjr-R8,524
|
11
|
+
anzu/worker/utils.py,sha256=mcUMb3J4MhsLrJnL57_ULRd4END2_MYXZ-6lIwZJjzE,835
|
12
|
+
anzu-0.1.5.dist-info/METADATA,sha256=Z8C3LKs5mwtVDjFLRiryghRzEFIbXXnB1lW_acjl-kU,2150
|
13
|
+
anzu-0.1.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
14
|
+
anzu-0.1.5.dist-info/entry_points.txt,sha256=ZzQxwCwDcp-JpCDaU6LiacEGNk7MhbeQgE1xhQqBUsQ,35
|
15
|
+
anzu-0.1.5.dist-info/licenses/LICENSE,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
16
|
+
anzu-0.1.5.dist-info/RECORD,,
|
anzu-0.1.4.dist-info/RECORD
DELETED
@@ -1,6 +0,0 @@
|
|
1
|
-
anzu/__init__.py,sha256=yapPQwS18DmiLOYcWJc2tK5KUTVs5lrsW_zmwUcb9zo,43
|
2
|
-
anzu-0.1.4.dist-info/licenses/LICENSE,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
|
-
anzu-0.1.4.dist-info/METADATA,sha256=nRyxc6NCUk0g-LWouq22y_KfRK2vj9NlBiVujheN0DI,2805
|
4
|
-
anzu-0.1.4.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
5
|
-
anzu-0.1.4.dist-info/top_level.txt,sha256=ScsUMREYhumuqwuPGmSlaT4aifa-g8khMiFr7-h-xQ0,5
|
6
|
-
anzu-0.1.4.dist-info/RECORD,,
|
@@ -1 +0,0 @@
|
|
1
|
-
anzu
|
File without changes
|