Skip to content

Commit 1d8ef3f

Browse files
authored
Merge pull request #240 from vladak/exceptions_tidy_up
reduce the use of MMQTTException
2 parents c413397 + fdd436e commit 1d8ef3f

File tree

2 files changed

+42
-29
lines changed

2 files changed

+42
-29
lines changed

adafruit_minimqtt/adafruit_minimqtt.py

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,26 @@
9595

9696

9797
class MMQTTException(Exception):
98-
"""MiniMQTT Exception class."""
98+
"""
99+
MiniMQTT Exception class.
100+
101+
Raised for various mostly protocol or network/system level errors.
102+
In general, the robust way to recover is to call reconnect().
103+
"""
99104

100105
def __init__(self, error, code=None):
101106
super().__init__(error, code)
102107
self.code = code
103108

104109

110+
class MMQTTStateError(MMQTTException):
111+
"""
112+
MiniMQTT invalid state error.
113+
114+
Raised e.g. if a function is called in unexpected state.
115+
"""
116+
117+
105118
class NullLogger:
106119
"""Fake logger class that does not do anything"""
107120

@@ -165,7 +178,7 @@ def __init__( # noqa: PLR0915, PLR0913, Too many statements, Too many arguments
165178
self._use_binary_mode = use_binary_mode
166179

167180
if recv_timeout <= socket_timeout:
168-
raise MMQTTException("recv_timeout must be strictly greater than socket_timeout")
181+
raise ValueError("recv_timeout must be strictly greater than socket_timeout")
169182
self._socket_timeout = socket_timeout
170183
self._recv_timeout = recv_timeout
171184

@@ -183,7 +196,7 @@ def __init__( # noqa: PLR0915, PLR0913, Too many statements, Too many arguments
183196
self._reconnect_timeout = float(0)
184197
self._reconnect_maximum_backoff = 32
185198
if connect_retries <= 0:
186-
raise MMQTTException("connect_retries must be positive")
199+
raise ValueError("connect_retries must be positive")
187200
self._reconnect_attempts_max = connect_retries
188201

189202
self.broker = broker
@@ -192,7 +205,7 @@ def __init__( # noqa: PLR0915, PLR0913, Too many statements, Too many arguments
192205
if (
193206
self._password and len(password.encode("utf-8")) > MQTT_TOPIC_LENGTH_LIMIT
194207
): # [MQTT-3.1.3.5]
195-
raise MMQTTException("Password length is too large.")
208+
raise ValueError("Password length is too large.")
196209

197210
# The connection will be insecure unless is_ssl is set to True.
198211
# If the port is not specified, the security will be set based on the is_ssl parameter.
@@ -288,28 +301,27 @@ def will_set(
288301
"""
289302
self.logger.debug("Setting last will properties")
290303
if self._is_connected:
291-
raise MMQTTException("Last Will should only be called before connect().")
304+
raise MMQTTStateError("Last Will should only be called before connect().")
292305

293306
# check topic/msg/qos kwargs
294307
self._valid_topic(topic)
295308
if "+" in topic or "#" in topic:
296-
raise MMQTTException("Publish topic can not contain wildcards.")
309+
raise ValueError("Publish topic can not contain wildcards.")
297310

298311
if msg is None:
299-
raise MMQTTException("Message can not be None.")
312+
raise ValueError("Message can not be None.")
300313
if isinstance(msg, (int, float)):
301314
msg = str(msg).encode("ascii")
302315
elif isinstance(msg, str):
303316
msg = str(msg).encode("utf-8")
304317
elif isinstance(msg, bytes):
305318
pass
306319
else:
307-
raise MMQTTException("Invalid message data type.")
320+
raise ValueError("Invalid message data type.")
308321
if len(msg) > MQTT_MSG_MAX_SZ:
309-
raise MMQTTException(f"Message size larger than {MQTT_MSG_MAX_SZ} bytes.")
322+
raise ValueError(f"Message size larger than {MQTT_MSG_MAX_SZ} bytes.")
310323

311324
self._valid_qos(qos)
312-
assert 0 <= qos <= 1, "Quality of Service Level 2 is unsupported by this library."
313325

314326
# fixed header. [3.3.1.2], [3.3.1.3]
315327
pub_hdr_fixed = bytearray([MQTT_PUBLISH | retain | qos << 1])
@@ -392,7 +404,7 @@ def username_pw_set(self, username: str, password: Optional[str] = None) -> None
392404
393405
"""
394406
if self._is_connected:
395-
raise MMQTTException("This method must be called before connect().")
407+
raise MMQTTStateError("This method must be called before connect().")
396408
self._username = username
397409
if password is not None:
398410
self._password = password
@@ -672,21 +684,22 @@ def publish( # noqa: PLR0912, Too many branches
672684
self._connected()
673685
self._valid_topic(topic)
674686
if "+" in topic or "#" in topic:
675-
raise MMQTTException("Publish topic can not contain wildcards.")
687+
raise ValueError("Publish topic can not contain wildcards.")
676688
# check msg/qos kwargs
677689
if msg is None:
678-
raise MMQTTException("Message can not be None.")
690+
raise ValueError("Message can not be None.")
679691
if isinstance(msg, (int, float)):
680692
msg = str(msg).encode("ascii")
681693
elif isinstance(msg, str):
682694
msg = str(msg).encode("utf-8")
683695
elif isinstance(msg, bytes):
684696
pass
685697
else:
686-
raise MMQTTException("Invalid message data type.")
698+
raise ValueError("Invalid message data type.")
687699
if len(msg) > MQTT_MSG_MAX_SZ:
688-
raise MMQTTException(f"Message size larger than {MQTT_MSG_MAX_SZ} bytes.")
689-
assert 0 <= qos <= 1, "Quality of Service Level 2 is unsupported by this library."
700+
raise ValueError(f"Message size larger than {MQTT_MSG_MAX_SZ} bytes.")
701+
702+
self._valid_qos(qos)
690703

691704
# fixed header. [3.3.1.2], [3.3.1.3]
692705
pub_hdr_fixed = bytearray([MQTT_PUBLISH | retain | qos << 1])
@@ -851,7 +864,7 @@ def unsubscribe( # noqa: PLR0912, Too many branches
851864
topics.append(t)
852865
for t in topics:
853866
if t not in self._subscribed_topics:
854-
raise MMQTTException("Topic must be subscribed to before attempting unsubscribe.")
867+
raise MMQTTStateError("Topic must be subscribed to before attempting unsubscribe.")
855868
# Assemble packet
856869
self.logger.debug("Sending UNSUBSCRIBE to broker...")
857870
fixed_header = bytearray([MQTT_UNSUB])
@@ -961,7 +974,7 @@ def loop(self, timeout: float = 1.0) -> Optional[list[int]]:
961974
962975
"""
963976
if timeout < self._socket_timeout:
964-
raise MMQTTException(
977+
raise ValueError(
965978
f"loop timeout ({timeout}) must be >= "
966979
+ f"socket timeout ({self._socket_timeout}))"
967980
)
@@ -1155,13 +1168,13 @@ def _valid_topic(topic: str) -> None:
11551168
11561169
"""
11571170
if topic is None:
1158-
raise MMQTTException("Topic may not be NoneType")
1171+
raise ValueError("Topic may not be NoneType")
11591172
# [MQTT-4.7.3-1]
11601173
if not topic:
1161-
raise MMQTTException("Topic may not be empty.")
1174+
raise ValueError("Topic may not be empty.")
11621175
# [MQTT-4.7.3-3]
11631176
if len(topic.encode("utf-8")) > MQTT_TOPIC_LENGTH_LIMIT:
1164-
raise MMQTTException("Topic length is too large.")
1177+
raise ValueError(f"Encoded topic length is larger than {MQTT_TOPIC_LENGTH_LIMIT}")
11651178

11661179
@staticmethod
11671180
def _valid_qos(qos_level: int) -> None:
@@ -1172,16 +1185,16 @@ def _valid_qos(qos_level: int) -> None:
11721185
"""
11731186
if isinstance(qos_level, int):
11741187
if qos_level < 0 or qos_level > 2:
1175-
raise MMQTTException("QoS must be between 1 and 2.")
1188+
raise NotImplementedError("QoS must be between 1 and 2.")
11761189
else:
1177-
raise MMQTTException("QoS must be an integer.")
1190+
raise ValueError("QoS must be an integer.")
11781191

11791192
def _connected(self) -> None:
11801193
"""Returns MQTT client session status as True if connected, raises
1181-
a `MMQTTException` if `False`.
1194+
a `MMQTTStateError exception` if `False`.
11821195
"""
11831196
if not self.is_connected():
1184-
raise MMQTTException("MiniMQTT is not connected")
1197+
raise MMQTTStateError("MiniMQTT is not connected")
11851198

11861199
def is_connected(self) -> bool:
11871200
"""Returns MQTT client session status as True if connected, False

tests/test_loop.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ def test_loop_basic(self) -> None:
157157

158158
def test_loop_timeout_vs_socket_timeout(self):
159159
"""
160-
loop() should throw MMQTTException if the timeout argument
160+
loop() should throw ValueError if the timeout argument
161161
is bigger than the socket timeout.
162162
"""
163163
mqtt_client = MQTT.MQTT(
@@ -169,14 +169,14 @@ def test_loop_timeout_vs_socket_timeout(self):
169169
)
170170

171171
mqtt_client.is_connected = lambda: True
172-
with pytest.raises(MQTT.MMQTTException) as context:
172+
with pytest.raises(ValueError) as context:
173173
mqtt_client.loop(timeout=0.5)
174174

175175
assert "loop timeout" in str(context)
176176

177177
def test_loop_is_connected(self):
178178
"""
179-
loop() should throw MMQTTException if not connected
179+
loop() should throw MMQTTStateError if not connected
180180
"""
181181
mqtt_client = MQTT.MQTT(
182182
broker="127.0.0.1",
@@ -185,7 +185,7 @@ def test_loop_is_connected(self):
185185
ssl_context=ssl.create_default_context(),
186186
)
187187

188-
with pytest.raises(MQTT.MMQTTException) as context:
188+
with pytest.raises(MQTT.MMQTTStateError) as context:
189189
mqtt_client.loop(timeout=1)
190190

191191
assert "not connected" in str(context)

0 commit comments

Comments
 (0)