diff --git a/CHANGELOG.md b/CHANGELOG.md index 2695747..de4038b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] +### Added +- Added an optional `client` argument to `IdasenDesk.__init__` for + injecting a pre-configured `BleakClient`. Useful for downstream + wrappers that manage their own connection lifecycle (e.g. via + `bleak-retry-connector`). When provided, `disconnected_callback` + is ignored. + ## [0.13.0] - 2026-05-25 ### Fixed - Fixed the CLI ignoring the `XDG_CONFIG_HOME` environment variable. diff --git a/idasen/__init__.py b/idasen/__init__.py index a6308c9..bc5cb9f 100644 --- a/idasen/__init__.py +++ b/idasen/__init__.py @@ -94,7 +94,15 @@ class IdasenDesk: disconnected_callback: Callback that will be scheduled in the event loop when the client is disconnected. The callable must take one argument, which will be - this client object. + this client object. Ignored when ``client`` is provided; in that + case the caller is responsible for configuring the disconnected + callback on the injected client. + client: + Optional pre-configured :class:`bleak.BleakClient` to use instead + of letting :class:`IdasenDesk` create one internally. Useful for + downstream wrappers that manage their own connection lifecycle + (e.g. via ``bleak-retry-connector``). When provided, + ``disconnected_callback`` is ignored. Note: There is no locking to prevent you from running multiple movement @@ -124,12 +132,16 @@ def __init__( mac: Union[BLEDevice, str], exit_on_fail: bool = False, disconnected_callback: Optional[Callable[[BleakClient], None]] = None, + client: Optional[BleakClient] = None, ): self._exit_on_fail = exit_on_fail - self._client = BleakClient( - address_or_ble_device=mac, - disconnected_callback=disconnected_callback, - ) + if client is None: + self._client = BleakClient( + address_or_ble_device=mac, + disconnected_callback=disconnected_callback, + ) + else: + self._client = client self._mac = mac.address if isinstance(mac, BLEDevice) else mac self._logger = _DeskLoggingAdapter( logger=logging.getLogger(__name__), extra={"mac": self.mac} diff --git a/tests/test_idasen.py b/tests/test_idasen.py index 4599ece..84aa839 100644 --- a/tests/test_idasen.py +++ b/tests/test_idasen.py @@ -107,6 +107,35 @@ def test_mac(desk: IdasenDesk): assert desk.mac == desk_mac +def test_init_creates_default_client(): + """Without ``client``, ``__init__`` creates its own ``BleakClient``.""" + desk = IdasenDesk(mac=desk_mac) + assert isinstance(desk._client, bleak.BleakClient) + + +def test_init_uses_injected_client(): + """An injected ``client`` is used as-is, with no replacement.""" + injected = MockBleakClient() + desk = IdasenDesk(mac=desk_mac, client=injected) # type: ignore[arg-type] + assert desk._client is injected + + +def test_init_ignores_disconnected_callback_when_client_provided(): + """``disconnected_callback`` is ignored when ``client`` is provided. + + The caller is expected to configure the disconnected callback on the + client they pass in. + """ + injected = MockBleakClient() + callback = mock.Mock() + desk = IdasenDesk( + mac=desk_mac, + client=injected, # type: ignore[arg-type] + disconnected_callback=callback, + ) + assert desk._client is injected + + async def test_pair(desk: IdasenDesk): if desk_mac != "AA:AA:AA:AA:AA:AA": return