Skip to content

Commit eb81a42

Browse files
authored
Allow string formatting for dispatcher SignalType (home-assistant#114174)
1 parent dd43947 commit eb81a42

File tree

5 files changed

+58
-8
lines changed

5 files changed

+58
-8
lines changed

homeassistant/components/mqtt/discovery.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from homeassistant.data_entry_flow import FlowResultType
1919
import homeassistant.helpers.config_validation as cv
2020
from homeassistant.helpers.dispatcher import (
21+
SignalTypeFormat,
2122
async_dispatcher_connect,
2223
async_dispatcher_send,
2324
)
@@ -79,10 +80,14 @@
7980
"water_heater",
8081
}
8182

82-
MQTT_DISCOVERY_UPDATED = "mqtt_discovery_updated_{}"
83-
MQTT_DISCOVERY_NEW = "mqtt_discovery_new_{}_{}"
83+
MQTT_DISCOVERY_UPDATED: SignalTypeFormat[MQTTDiscoveryPayload] = SignalTypeFormat(
84+
"mqtt_discovery_updated_{}"
85+
)
86+
MQTT_DISCOVERY_NEW: SignalTypeFormat[MQTTDiscoveryPayload] = SignalTypeFormat(
87+
"mqtt_discovery_new_{}_{}"
88+
)
8489
MQTT_DISCOVERY_NEW_COMPONENT = "mqtt_discovery_new_component"
85-
MQTT_DISCOVERY_DONE = "mqtt_discovery_done_{}"
90+
MQTT_DISCOVERY_DONE: SignalTypeFormat[Any] = SignalTypeFormat("mqtt_discovery_done_{}")
8691

8792
TOPIC_BASE = "~"
8893

homeassistant/helpers/discovery.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,16 @@
1515
from homeassistant.const import Platform
1616
from homeassistant.loader import bind_hass
1717

18-
from .dispatcher import async_dispatcher_connect, async_dispatcher_send
18+
from .dispatcher import (
19+
SignalTypeFormat,
20+
async_dispatcher_connect,
21+
async_dispatcher_send,
22+
)
1923
from .typing import ConfigType, DiscoveryInfoType
2024

21-
SIGNAL_PLATFORM_DISCOVERED = "discovery.platform_discovered_{}"
25+
SIGNAL_PLATFORM_DISCOVERED: SignalTypeFormat[DiscoveryDict] = SignalTypeFormat(
26+
"discovery.platform_discovered_{}"
27+
)
2228
EVENT_LOAD_PLATFORM = "load_platform.{}"
2329
ATTR_PLATFORM = "platform"
2430
ATTR_DISCOVERED = "discovered"

homeassistant/helpers/dispatcher.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020

2121

2222
@dataclass(frozen=True)
23-
class SignalType(Generic[*_Ts]):
24-
"""Generic string class for signal to improve typing."""
23+
class _SignalTypeBase(Generic[*_Ts]):
24+
"""Generic base class for SignalType."""
2525

2626
name: str
2727

@@ -40,6 +40,20 @@ def __eq__(self, other: Any) -> bool:
4040
return False
4141

4242

43+
@dataclass(frozen=True, eq=False)
44+
class SignalType(_SignalTypeBase[*_Ts]):
45+
"""Generic string class for signal to improve typing."""
46+
47+
48+
@dataclass(frozen=True, eq=False)
49+
class SignalTypeFormat(_SignalTypeBase[*_Ts]):
50+
"""Generic string class for signal. Requires call to 'format' before use."""
51+
52+
def format(self, *args: Any, **kwargs: Any) -> SignalType[*_Ts]:
53+
"""Format name and return new SignalType instance."""
54+
return SignalType(self.name.format(*args, **kwargs))
55+
56+
4357
_DispatcherDataType = dict[
4458
SignalType[*_Ts] | str,
4559
dict[

tests/common.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
translation,
7777
)
7878
from homeassistant.helpers.dispatcher import (
79+
SignalType,
7980
async_dispatcher_connect,
8081
async_dispatcher_send,
8182
)
@@ -1497,7 +1498,9 @@ def capture_events(event: Event) -> None:
14971498

14981499

14991500
@callback
1500-
def async_mock_signal(hass: HomeAssistant, signal: str) -> list[tuple[Any]]:
1501+
def async_mock_signal(
1502+
hass: HomeAssistant, signal: SignalType[Any] | str
1503+
) -> list[tuple[Any]]:
15011504
"""Catch all dispatches to a signal."""
15021505
calls = []
15031506

tests/helpers/test_dispatcher.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from homeassistant.core import HomeAssistant, callback
88
from homeassistant.helpers.dispatcher import (
99
SignalType,
10+
SignalTypeFormat,
1011
async_dispatcher_connect,
1112
async_dispatcher_send,
1213
)
@@ -58,6 +59,27 @@ def test_funct(data1: str, data2: int) -> None:
5859
assert calls == [("Hello", 2), ("World", 3), ("x", 4)]
5960

6061

62+
async def test_signal_type_format(hass: HomeAssistant) -> None:
63+
"""Test dispatcher with SignalType and format."""
64+
signal: SignalTypeFormat[str, int] = SignalTypeFormat("test-{}")
65+
calls: list[tuple[str, int]] = []
66+
67+
def test_funct(data1: str, data2: int) -> None:
68+
calls.append((data1, data2))
69+
70+
async_dispatcher_connect(hass, signal.format("unique-id"), test_funct)
71+
async_dispatcher_send(hass, signal.format("unique-id"), "Hello", 2)
72+
await hass.async_block_till_done()
73+
74+
assert calls == [("Hello", 2)]
75+
76+
# Test compatibility with string keys
77+
async_dispatcher_send(hass, "test-{}".format("unique-id"), "x", 4)
78+
await hass.async_block_till_done()
79+
80+
assert calls == [("Hello", 2), ("x", 4)]
81+
82+
6183
async def test_simple_function_unsub(hass: HomeAssistant) -> None:
6284
"""Test simple function (executor) and unsub."""
6385
calls1 = []

0 commit comments

Comments
 (0)