Skip to content

Commit 433f18a

Browse files
committed
Allow decoding of XML Enums via P2P
1 parent 7ca3829 commit 433f18a

4 files changed

Lines changed: 59 additions & 8 deletions

File tree

deebot_client/command.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,9 @@ def _create_from_mqtt(cls, data: dict[str, Any]) -> CommandMqttP2P:
307307
data.pop(name, None)
308308
else:
309309
try:
310-
values[param.name or name] = _pop_or_raise(name, param.type_, data)
310+
values[param.name or name] = cls._pop_or_raise(
311+
name, param.type_, data
312+
)
311313
except KeyError as err:
312314
if not param.optional:
313315
msg = f'"{name}" is missing in {data}'
@@ -318,14 +320,18 @@ def _create_from_mqtt(cls, data: dict[str, Any]) -> CommandMqttP2P:
318320

319321
return cls(**values)
320322

323+
@classmethod
324+
def _pop_or_raise(cls, name: str, type_: type, data: dict[str, Any]) -> Any:
325+
value = data.pop(name)
326+
try:
327+
return cls._decode(type_, value)
328+
except ValueError as err:
329+
msg = f'Could not convert "{value}" of {name} into {type_}'
330+
raise DeebotError(msg) from err
321331

322-
def _pop_or_raise(name: str, type_: type, data: dict[str, Any]) -> Any:
323-
value = data.pop(name)
324-
try:
332+
@classmethod
333+
def _decode(cls, type_: type, value: Any) -> Any:
325334
return type_(value)
326-
except ValueError as err:
327-
msg = f'Could not convert "{value}" of {name} into {type_}'
328-
raise DeebotError(msg) from err
329335

330336

331337
class GetCommand(CommandWithMessageHandling, ABC):

deebot_client/commands/xml/common.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,12 @@ def handle_mqtt_p2p(
116116

117117
self._handle_mqtt_p2p(event_bus, data)
118118

119+
@classmethod
120+
def _decode(cls, type_: type, value: Any) -> Any:
121+
if hasattr(type_, "from_xml"):
122+
return type_.from_xml(value)
123+
return type_(value)
124+
119125
@abstractmethod
120126
def _handle_mqtt_p2p(
121127
self, event_bus: EventBus, response: dict[str, Any] | str

deebot_client/commands/xml/life_span.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class ResetLifeSpan(ExecuteCommand, XmlCommandMqttP2P):
5858
"""ResetLifeSpan command."""
5959

6060
NAME = "ResetLifeSpan"
61-
_mqtt_params = MappingProxyType({"type": InitParam(str, "life_span")})
61+
_mqtt_params = MappingProxyType({"type": InitParam(LifeSpan, "life_span")})
6262

6363
def __init__(self, life_span: LifeSpan | str) -> None:
6464
xml_value = (

tests/commands/xml/test_common.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
from __future__ import annotations
22

3+
from types import MappingProxyType
4+
from typing import Any
35
from unittest.mock import Mock, patch
46

57
import pytest
68

9+
from deebot_client.command import CommandResult, InitParam
710
from deebot_client.commands.xml.common import XmlCommandMqttP2P
811
from deebot_client.event_bus import EventBus
12+
from deebot_client.events import LifeSpan
913

1014

1115
@pytest.mark.parametrize(
@@ -38,3 +42,38 @@ def test_XmlCommandMqttP2P_invalid_decoding() -> None:
3842
pytest.raises(TypeError),
3943
):
4044
command.handle_mqtt_p2p(event_bus, {}) # type: ignore[arg-type]
45+
46+
47+
@pytest.mark.parametrize(
48+
("command_payload", "payload_type", "expected_argument"),
49+
[
50+
("test", str, "test"),
51+
(LifeSpan.BRUSH.xml_value, LifeSpan, LifeSpan.BRUSH),
52+
],
53+
ids=["native", "with xml_value"],
54+
)
55+
def test_XmlCommandMqttP2P_create_from_mqtt(
56+
command_payload: str, payload_type: type, expected_argument: type
57+
) -> None:
58+
class Sut(XmlCommandMqttP2P):
59+
_mqtt_params = MappingProxyType({"payload": InitParam(payload_type)})
60+
NAME = "Sut"
61+
62+
def __init__(self, payload: Any) -> None:
63+
super().__init__(args={"payload": payload})
64+
65+
def _handle_mqtt_p2p(
66+
self, _event_bus: EventBus, _response: dict[str, Any] | str
67+
) -> None:
68+
pass
69+
70+
def _handle_response(
71+
self, _event_bus: EventBus, _response: dict[str, Any]
72+
) -> CommandResult:
73+
return CommandResult.analyse()
74+
75+
xml_message = f"<ctl ret='ok' payload='{command_payload}'/>"
76+
77+
sut = Sut.create_from_mqtt(xml_message)
78+
79+
assert sut._args == {"payload": expected_argument}

0 commit comments

Comments
 (0)