mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 03:07:37 +00:00
Make dispatcher setup lazy (#74374)
This commit is contained in:
parent
dd57d7d77f
commit
6c3baf03aa
@ -41,26 +41,13 @@ def async_dispatcher_connect(
|
|||||||
"""
|
"""
|
||||||
if DATA_DISPATCHER not in hass.data:
|
if DATA_DISPATCHER not in hass.data:
|
||||||
hass.data[DATA_DISPATCHER] = {}
|
hass.data[DATA_DISPATCHER] = {}
|
||||||
|
hass.data[DATA_DISPATCHER].setdefault(signal, {})[target] = None
|
||||||
job = HassJob(
|
|
||||||
catch_log_exception(
|
|
||||||
target,
|
|
||||||
lambda *args: "Exception in {} when dispatching '{}': {}".format(
|
|
||||||
# Functions wrapped in partial do not have a __name__
|
|
||||||
getattr(target, "__name__", None) or str(target),
|
|
||||||
signal,
|
|
||||||
args,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
hass.data[DATA_DISPATCHER].setdefault(signal, []).append(job)
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_remove_dispatcher() -> None:
|
def async_remove_dispatcher() -> None:
|
||||||
"""Remove signal listener."""
|
"""Remove signal listener."""
|
||||||
try:
|
try:
|
||||||
hass.data[DATA_DISPATCHER][signal].remove(job)
|
del hass.data[DATA_DISPATCHER][signal][target]
|
||||||
except (KeyError, ValueError):
|
except (KeyError, ValueError):
|
||||||
# KeyError is key target listener did not exist
|
# KeyError is key target listener did not exist
|
||||||
# ValueError if listener did not exist within signal
|
# ValueError if listener did not exist within signal
|
||||||
@ -75,6 +62,21 @@ def dispatcher_send(hass: HomeAssistant, signal: str, *args: Any) -> None:
|
|||||||
hass.loop.call_soon_threadsafe(async_dispatcher_send, hass, signal, *args)
|
hass.loop.call_soon_threadsafe(async_dispatcher_send, hass, signal, *args)
|
||||||
|
|
||||||
|
|
||||||
|
def _generate_job(signal: str, target: Callable[..., Any]) -> HassJob:
|
||||||
|
"""Generate a HassJob for a signal and target."""
|
||||||
|
return HassJob(
|
||||||
|
catch_log_exception(
|
||||||
|
target,
|
||||||
|
lambda *args: "Exception in {} when dispatching '{}': {}".format(
|
||||||
|
# Functions wrapped in partial do not have a __name__
|
||||||
|
getattr(target, "__name__", None) or str(target),
|
||||||
|
signal,
|
||||||
|
args,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
@bind_hass
|
@bind_hass
|
||||||
def async_dispatcher_send(hass: HomeAssistant, signal: str, *args: Any) -> None:
|
def async_dispatcher_send(hass: HomeAssistant, signal: str, *args: Any) -> None:
|
||||||
@ -82,7 +84,9 @@ def async_dispatcher_send(hass: HomeAssistant, signal: str, *args: Any) -> None:
|
|||||||
|
|
||||||
This method must be run in the event loop.
|
This method must be run in the event loop.
|
||||||
"""
|
"""
|
||||||
target_list = hass.data.get(DATA_DISPATCHER, {}).get(signal, [])
|
target_list = hass.data.get(DATA_DISPATCHER, {}).get(signal, {})
|
||||||
|
for target, job in target_list.items():
|
||||||
for job in target_list:
|
if job is None:
|
||||||
|
job = _generate_job(signal, target)
|
||||||
|
target_list[target] = job
|
||||||
hass.async_add_hass_job(job, *args)
|
hass.async_add_hass_job(job, *args)
|
||||||
|
@ -311,7 +311,7 @@ async def test_internal_discovery_callback_fill_out_group_fail(
|
|||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
# when called with incomplete info, it should use HTTP to get missing
|
# when called with incomplete info, it should use HTTP to get missing
|
||||||
discover = signal.mock_calls[0][1][0]
|
discover = signal.mock_calls[-1][1][0]
|
||||||
assert discover == full_info
|
assert discover == full_info
|
||||||
get_multizone_status_mock.assert_called_once()
|
get_multizone_status_mock.assert_called_once()
|
||||||
|
|
||||||
@ -352,7 +352,7 @@ async def test_internal_discovery_callback_fill_out_group(
|
|||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
# when called with incomplete info, it should use HTTP to get missing
|
# when called with incomplete info, it should use HTTP to get missing
|
||||||
discover = signal.mock_calls[0][1][0]
|
discover = signal.mock_calls[-1][1][0]
|
||||||
assert discover == full_info
|
assert discover == full_info
|
||||||
get_multizone_status_mock.assert_called_once()
|
get_multizone_status_mock.assert_called_once()
|
||||||
|
|
||||||
@ -423,23 +423,25 @@ async def test_internal_discovery_callback_fill_out_cast_type_manufacturer(
|
|||||||
# when called with incomplete info, it should use HTTP to get missing
|
# when called with incomplete info, it should use HTTP to get missing
|
||||||
get_cast_type_mock.assert_called_once()
|
get_cast_type_mock.assert_called_once()
|
||||||
assert get_cast_type_mock.call_count == 1
|
assert get_cast_type_mock.call_count == 1
|
||||||
discover = signal.mock_calls[0][1][0]
|
discover = signal.mock_calls[2][1][0]
|
||||||
assert discover == full_info
|
assert discover == full_info
|
||||||
assert "Fetched cast details for unknown model 'Chromecast'" in caplog.text
|
assert "Fetched cast details for unknown model 'Chromecast'" in caplog.text
|
||||||
|
|
||||||
|
signal.reset_mock()
|
||||||
# Call again, the model name should be fetched from cache
|
# Call again, the model name should be fetched from cache
|
||||||
discover_cast(FAKE_MDNS_SERVICE, info)
|
discover_cast(FAKE_MDNS_SERVICE, info)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert get_cast_type_mock.call_count == 1 # No additional calls
|
assert get_cast_type_mock.call_count == 1 # No additional calls
|
||||||
discover = signal.mock_calls[1][1][0]
|
discover = signal.mock_calls[0][1][0]
|
||||||
assert discover == full_info
|
assert discover == full_info
|
||||||
|
|
||||||
|
signal.reset_mock()
|
||||||
# Call for another model, need to call HTTP again
|
# Call for another model, need to call HTTP again
|
||||||
get_cast_type_mock.return_value = full_info2.cast_info
|
get_cast_type_mock.return_value = full_info2.cast_info
|
||||||
discover_cast(FAKE_MDNS_SERVICE, info2)
|
discover_cast(FAKE_MDNS_SERVICE, info2)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert get_cast_type_mock.call_count == 2
|
assert get_cast_type_mock.call_count == 2
|
||||||
discover = signal.mock_calls[2][1][0]
|
discover = signal.mock_calls[0][1][0]
|
||||||
assert discover == full_info2
|
assert discover == full_info2
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user