From 4026e8a80c90daa99800e837c0b05bbc7b429811 Mon Sep 17 00:00:00 2001 From: "Teemu R." Date: Thu, 7 Nov 2024 20:09:51 +0100 Subject: [PATCH] Make __repr__ work on discovery info (#1233) This PR will make `__repr__` also work on smartdevices where only discovery data is available by modifying the `model` property to fallback to the data found in the discovery payloads. --- kasa/device.py | 8 +++++--- kasa/smart/smartdevice.py | 4 +++- kasa/tests/test_discovery.py | 24 ++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/kasa/device.py b/kasa/device.py index 08dcf2a1..fb9b9f0c 100644 --- a/kasa/device.py +++ b/kasa/device.py @@ -469,9 +469,11 @@ class Device(ABC): """ def __repr__(self): - if self._last_update is None: - return f"<{self.device_type} at {self.host} - update() needed>" - return f"<{self.device_type} at {self.host} - {self.alias} ({self.model})>" + update_needed = " - update() needed" if not self._last_update else "" + return ( + f"<{self.device_type} at {self.host} -" + f" {self.alias} ({self.model}){update_needed}>" + ) _deprecated_device_type_attributes = { # is_type diff --git a/kasa/smart/smartdevice.py b/kasa/smart/smartdevice.py index f4012b68..17386e07 100644 --- a/kasa/smart/smartdevice.py +++ b/kasa/smart/smartdevice.py @@ -732,8 +732,10 @@ class SmartDevice(Device): if self._device_type is not DeviceType.Unknown: return self._device_type + # Fallback to device_type (from disco info) + type_str = self._info.get("type", self._info.get("device_type")) self._device_type = self._get_device_type_from_components( - list(self._components.keys()), self._info["type"] + list(self._components.keys()), type_str ) return self._device_type diff --git a/kasa/tests/test_discovery.py b/kasa/tests/test_discovery.py index 0dc4e0d7..0318de35 100644 --- a/kasa/tests/test_discovery.py +++ b/kasa/tests/test_discovery.py @@ -706,3 +706,27 @@ async def test_discover_try_connect_all(discovery_mock, mocker): assert dev.config.uses_http is (transport_class != XorTransport) if transport_class != XorTransport: assert dev.protocol._transport._http_client.client == session + + +async def test_discovery_device_repr(discovery_mock, mocker): + """Test that repr works when only discovery data is available.""" + host = "foobar" + ip = "127.0.0.1" + + discovery_mock.ip = ip + device_class = Discover._get_device_class(discovery_mock.discovery_data) + update_mock = mocker.patch.object(device_class, "update") + + dev = await Discover.discover_single(host, credentials=Credentials()) + assert update_mock.call_count == 0 + + repr_ = repr(dev) + assert dev.host in repr_ + assert str(dev.device_type) in repr_ + assert dev.model in repr_ + + # For IOT devices, _last_update is filled from the discovery data + if dev._last_update: + assert "update() needed" not in repr_ + else: + assert "update() needed" in repr_