diff --git a/napalm_sonos/sonos_driver.py b/napalm_sonos/sonos_driver.py index 160e09f..dbf7992 100644 --- a/napalm_sonos/sonos_driver.py +++ b/napalm_sonos/sonos_driver.py @@ -1,5 +1,6 @@ from __future__ import annotations +import logging import socket from typing import Any @@ -13,6 +14,8 @@ SoCo library, exposing NAPALM standard methods alongside Sonos-specific media-playback controls. """ +logger = logging.getLogger(__name__) + class SonosDriver(MediaDriver): """NAPALM driver for controlling Sonos speakers. @@ -33,7 +36,9 @@ class SonosDriver(MediaDriver): FingerprintRule("rincon", weight=5.0), ] - def __init__( + # A Sonos speaker takes no login: username and password exist only for NAPALM's + # constructor signature, and the empty default is no credential. + def __init__( # nosec B107 self, hostname: str, username: str = "", @@ -60,7 +65,7 @@ class SonosDriver(MediaDriver): self._speaker_info = self._device.get_speaker_info() except Exception as e: # Broad catch: SoCo can raise a variety of transport/XML errors - raise ConnectionException(f"Cannot connect to Sonos at {self.hostname}: {e}") + raise ConnectionException(f"Cannot connect to Sonos at {self.hostname}: {e}") from e def close(self) -> None: """Close the connection to the Sonos speaker.""" @@ -112,7 +117,7 @@ class SonosDriver(MediaDriver): return wifimode in ("0", "", None) except Exception: # Broad catch: SoCo device_properties may fail for many reasons - pass + logger.debug("Sonos device properties: ignored", exc_info=True) return False def get_interfaces(self) -> dict[str, dict[str, Any]]: diff --git a/tests/test_sonos.py b/tests/test_sonos.py index f3106b8..35ba906 100644 --- a/tests/test_sonos.py +++ b/tests/test_sonos.py @@ -52,7 +52,7 @@ class TestSonosDriver: mock_soco.side_effect = Exception("Connection refused") try: driver.open() - assert False, "Expected ConnectionException" + raise AssertionError("Expected ConnectionException") except ConnectionException: pass