Package: python3-hbmqtt
Version: 0.9.6-1.1
Severity: grave
Justification: hbmqtt.client.MQTTClient.connect never works
Tags: patch upstream

The MQTTClient is not useable at all at present. Trying to connect to
any broker results in the following:

| Unhandled exception: 'Lock' object is not iterable
| Connection failed: TypeError("'Lock' object is not iterable")
| Unhandled exception: 'Lock' object is not iterable
| Reconnection attempt failed: TypeError("'Lock' object is not iterable")
| Unhandled exception: 'Lock' object is not iterable
| Reconnection attempt failed: TypeError("'Lock' object is not iterable")
| Unhandled exception: 'Lock' object is not iterable
| Reconnection attempt failed: TypeError("'Lock' object is not iterable")
| Maximum number of connection attempts reached. Reconnection aborted
| Traceback (most recent call last):
|   File "/usr/lib/python3/dist-packages/hbmqtt/client.py", line 149, in connect
|     return (yield from self._do_connect())
|   File "/usr/lib/python3/dist-packages/hbmqtt/client.py", line 234, in 
_do_connect
|     return_code = yield from self._connect_coro()
|   File "/usr/lib/python3/dist-packages/hbmqtt/client.py", line 423, in 
_connect_coro
|     return_code = yield from self._handler.mqtt_connect()
|   File 
"/usr/lib/python3/dist-packages/hbmqtt/mqtt/protocol/client_handler.py", line 
83, in mqtt_connect
|     yield from self._send_packet(connect_packet)
|   File "/usr/lib/python3/dist-packages/hbmqtt/mqtt/protocol/handler.py", line 
445, in _send_packet
|     with (yield from self._write_lock):
| TypeError: 'Lock' object is not iterable
| 
| During handling of the above exception, another exception occurred:
| 
| Traceback (most recent call last):
|   File "/usr/lib/python3/dist-packages/hbmqtt/client.py", line 220, in 
reconnect
|     return (yield from self._do_connect())
|   File "/usr/lib/python3/dist-packages/hbmqtt/client.py", line 234, in 
_do_connect
|     return_code = yield from self._connect_coro()
|   File "/usr/lib/python3/dist-packages/hbmqtt/client.py", line 423, in 
_connect_coro
|     return_code = yield from self._handler.mqtt_connect()
|   File 
"/usr/lib/python3/dist-packages/hbmqtt/mqtt/protocol/client_handler.py", line 
83, in mqtt_connect
|     yield from self._send_packet(connect_packet)
|   File "/usr/lib/python3/dist-packages/hbmqtt/mqtt/protocol/handler.py", line 
445, in _send_packet
|     with (yield from self._write_lock):
| TypeError: 'Lock' object is not iterable
| 
| During handling of the above exception, another exception occurred:
| 
| Traceback (most recent call last):
|   File "<string>", line 1, in <module>
|   File "/usr/lib/python3.9/asyncio/base_events.py", line 642, in 
run_until_complete
|     return future.result()
|   File "/usr/lib/python3/dist-packages/hbmqtt/client.py", line 156, in connect
|     return (yield from self.reconnect())
|   File "/usr/lib/python3/dist-packages/hbmqtt/client.py", line 225, in 
reconnect
|     raise ConnectException("Too many connection attempts failed")
| hbmqtt.client.ConnectException: Too many connection attempts failed

The cause for this is a change in how asyncio Locks work. Their support
for the pre-async API based on iterators has ceased, but hbmqtt attempts
to do so. Avoiding the context manager does the trick here. Please find
a minimal patch fixing the problem attached.

In any case, hbmqtt looks quite dead upstream. Maybe replacing it with
https://github.com/sbtinstruments/asyncio-mqtt would be better.

Helmut
--- a/hbmqtt/mqtt/protocol/handler.py
+++ b/hbmqtt/mqtt/protocol/handler.py
@@ -442,8 +442,11 @@ class ProtocolHandler:
     @asyncio.coroutine
     def _send_packet(self, packet):
         try:
-            with (yield from self._write_lock):
+            yield from self._write_lock.acquire()
+            try:
                 yield from packet.to_stream(self.writer)
+            finally:
+                self._write_lock.release()
             if self._keepalive_task:
                 self._keepalive_task.cancel()
                 self._keepalive_task = self._loop.call_later(self.keepalive_timeout, self.handle_write_timeout)

Reply via email to