Skip to content

Commit b27ff08

Browse files
Refactor RendezqueueClient callbacks to be optional and use logging
- Change `on_data` and `on_error` parameters in `RendezqueueClient.__init__` to be optional (default `None`). - Change `on_error` default behavior from `print(e)` to `logging.error`. - Add type hints to `RendezqueueClient.__init__`. - Add test case `test_defaults` in `test/client_test.py` to verify safe instantiation without callbacks. - Ensure backwards compatibility (explicitly passed callbacks still work). - Ensure thread safety and no crashes when callbacks are `None`. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
1 parent d4e7140 commit b27ff08

2 files changed

Lines changed: 36 additions & 2 deletions

File tree

src/rendezqueue/client.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,23 @@
11
import base64
22
import json
3+
import logging
34
import random
45
import string
56
import threading
67
import time
78
import urllib.request
89
import urllib.error
10+
from typing import Callable, Optional, List
11+
12+
logger = logging.getLogger(__name__)
913

1014
class RendezqueueClient:
11-
def __init__(self, url, key, hue, on_data, on_error=None, poll_interval_ms=2000):
15+
def __init__(self, url: str, key: str, hue: str, on_data: Optional[Callable[[List[bytes]], None]] = None, on_error: Optional[Callable[[Exception], None]] = None, poll_interval_ms: int = 2000):
1216
self.url = url
1317
self.key = key
1418
self.hue = hue
1519
self.on_data = on_data
16-
self.on_error = on_error or (lambda e: print(e))
20+
self.on_error = on_error or (lambda e: logger.error(f"Rendezqueue error: {e}"))
1721
self.poll_interval_ms = poll_interval_ms
1822

1923
self.sid_counter = 1

test/client_test.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,5 +114,35 @@ def test_decode_padding(self):
114114
decoded = self.client._decode_response(msg)
115115
self.assertEqual(decoded['values'][0], b"test padding")
116116

117+
@patch("urllib.request.urlopen")
118+
def test_defaults(self, mock_urlopen):
119+
# Initialize client without callbacks
120+
client = RendezqueueClient(
121+
url=self.url,
122+
key=self.key,
123+
hue=self.hue
124+
)
125+
self.assertIsNone(client.on_data)
126+
self.assertIsNotNone(client.on_error) # Should be default logger lambda
127+
128+
# Simulate receiving data
129+
resp_values = [base64.b64encode(b"response").decode('ascii')]
130+
resp_data = {
131+
"offset": 1,
132+
"values": resp_values,
133+
"b64": 1
134+
}
135+
mock_resp = MagicMock()
136+
mock_resp.status = 200
137+
mock_resp.read.return_value = json.dumps(resp_data).encode('utf-8')
138+
mock_resp.__enter__.return_value = mock_resp
139+
mock_urlopen.return_value = mock_resp
140+
141+
# Trigger poll - should not crash
142+
try:
143+
client._poll()
144+
except Exception as e:
145+
self.fail(f"_poll raised exception unexpectedly: {e}")
146+
117147
if __name__ == "__main__":
118148
unittest.main()

0 commit comments

Comments
 (0)