mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
Adjust thread safety check messages to point to developer docs (#117392)
This commit is contained in:
parent
77de1b2331
commit
7871e9279b
@ -1955,7 +1955,7 @@ class ConfigEntries:
|
||||
if entry.entry_id not in self._entries:
|
||||
raise UnknownEntry(entry.entry_id)
|
||||
|
||||
self.hass.verify_event_loop_thread("async_update_entry")
|
||||
self.hass.verify_event_loop_thread("hass.config_entries.async_update_entry")
|
||||
changed = False
|
||||
_setter = object.__setattr__
|
||||
|
||||
|
@ -439,7 +439,10 @@ class HomeAssistant:
|
||||
|
||||
# frame is a circular import, so we import it here
|
||||
frame.report(
|
||||
f"calls {what} from a thread",
|
||||
f"calls {what} from a thread. "
|
||||
"For more information, see "
|
||||
"https://developers.home-assistant.io/docs/asyncio_thread_safety/"
|
||||
f"#{what.replace('.', '')}",
|
||||
error_if_core=True,
|
||||
error_if_integration=True,
|
||||
)
|
||||
@ -802,7 +805,7 @@ class HomeAssistant:
|
||||
# check with a check for the `hass.config.debug` flag being set as
|
||||
# long term we don't want to be checking this in production
|
||||
# environments since it is a performance hit.
|
||||
self.verify_event_loop_thread("async_create_task")
|
||||
self.verify_event_loop_thread("hass.async_create_task")
|
||||
return self.async_create_task_internal(target, name, eager_start)
|
||||
|
||||
@callback
|
||||
@ -1493,7 +1496,7 @@ class EventBus:
|
||||
This method must be run in the event loop.
|
||||
"""
|
||||
_verify_event_type_length_or_raise(event_type)
|
||||
self._hass.verify_event_loop_thread("async_fire")
|
||||
self._hass.verify_event_loop_thread("hass.bus.async_fire")
|
||||
return self.async_fire_internal(
|
||||
event_type, event_data, origin, context, time_fired
|
||||
)
|
||||
@ -2506,7 +2509,7 @@ class ServiceRegistry:
|
||||
|
||||
This method must be run in the event loop.
|
||||
"""
|
||||
self._hass.verify_event_loop_thread("async_register")
|
||||
self._hass.verify_event_loop_thread("hass.services.async_register")
|
||||
self._async_register(
|
||||
domain, service, service_func, schema, supports_response, job_type
|
||||
)
|
||||
@ -2565,7 +2568,7 @@ class ServiceRegistry:
|
||||
|
||||
This method must be run in the event loop.
|
||||
"""
|
||||
self._hass.verify_event_loop_thread("async_remove")
|
||||
self._hass.verify_event_loop_thread("hass.services.async_remove")
|
||||
self._async_remove(domain, service)
|
||||
|
||||
@callback
|
||||
|
@ -204,7 +204,7 @@ class AreaRegistry(BaseRegistry[AreasRegistryStoreData]):
|
||||
picture: str | None = None,
|
||||
) -> AreaEntry:
|
||||
"""Create a new area."""
|
||||
self.hass.verify_event_loop_thread("async_create")
|
||||
self.hass.verify_event_loop_thread("area_registry.async_create")
|
||||
normalized_name = normalize_name(name)
|
||||
|
||||
if self.async_get_area_by_name(name):
|
||||
@ -233,7 +233,7 @@ class AreaRegistry(BaseRegistry[AreasRegistryStoreData]):
|
||||
@callback
|
||||
def async_delete(self, area_id: str) -> None:
|
||||
"""Delete area."""
|
||||
self.hass.verify_event_loop_thread("async_delete")
|
||||
self.hass.verify_event_loop_thread("area_registry.async_delete")
|
||||
device_registry = dr.async_get(self.hass)
|
||||
entity_registry = er.async_get(self.hass)
|
||||
device_registry.async_clear_area_id(area_id)
|
||||
@ -314,7 +314,7 @@ class AreaRegistry(BaseRegistry[AreasRegistryStoreData]):
|
||||
if not new_values:
|
||||
return old
|
||||
|
||||
self.hass.verify_event_loop_thread("_async_update")
|
||||
self.hass.verify_event_loop_thread("area_registry.async_update")
|
||||
new = self.areas[area_id] = dataclasses.replace(old, **new_values) # type: ignore[arg-type]
|
||||
|
||||
self.async_schedule_save()
|
||||
|
@ -98,7 +98,7 @@ class CategoryRegistry(BaseRegistry[CategoryRegistryStoreData]):
|
||||
icon: str | None = None,
|
||||
) -> CategoryEntry:
|
||||
"""Create a new category."""
|
||||
self.hass.verify_event_loop_thread("async_create")
|
||||
self.hass.verify_event_loop_thread("category_registry.async_create")
|
||||
self._async_ensure_name_is_available(scope, name)
|
||||
category = CategoryEntry(
|
||||
icon=icon,
|
||||
@ -122,7 +122,7 @@ class CategoryRegistry(BaseRegistry[CategoryRegistryStoreData]):
|
||||
@callback
|
||||
def async_delete(self, *, scope: str, category_id: str) -> None:
|
||||
"""Delete category."""
|
||||
self.hass.verify_event_loop_thread("async_delete")
|
||||
self.hass.verify_event_loop_thread("category_registry.async_delete")
|
||||
del self.categories[scope][category_id]
|
||||
self.hass.bus.async_fire_internal(
|
||||
EVENT_CATEGORY_REGISTRY_UPDATED,
|
||||
@ -157,7 +157,7 @@ class CategoryRegistry(BaseRegistry[CategoryRegistryStoreData]):
|
||||
if not changes:
|
||||
return old
|
||||
|
||||
self.hass.verify_event_loop_thread("async_update")
|
||||
self.hass.verify_event_loop_thread("category_registry.async_update")
|
||||
new = self.categories[scope][category_id] = dataclasses.replace(old, **changes) # type: ignore[arg-type]
|
||||
|
||||
self.async_schedule_save()
|
||||
|
@ -906,7 +906,7 @@ class DeviceRegistry(BaseRegistry[dict[str, list[dict[str, Any]]]]):
|
||||
if not new_values:
|
||||
return old
|
||||
|
||||
self.hass.verify_event_loop_thread("async_update_device")
|
||||
self.hass.verify_event_loop_thread("device_registry.async_update_device")
|
||||
new = attr.evolve(old, **new_values)
|
||||
self.devices[device_id] = new
|
||||
|
||||
@ -933,7 +933,7 @@ class DeviceRegistry(BaseRegistry[dict[str, list[dict[str, Any]]]]):
|
||||
@callback
|
||||
def async_remove_device(self, device_id: str) -> None:
|
||||
"""Remove a device from the device registry."""
|
||||
self.hass.verify_event_loop_thread("async_remove_device")
|
||||
self.hass.verify_event_loop_thread("device_registry.async_remove_device")
|
||||
device = self.devices.pop(device_id)
|
||||
self.deleted_devices[device_id] = DeletedDeviceEntry(
|
||||
config_entries=device.config_entries,
|
||||
|
@ -821,7 +821,7 @@ class EntityRegistry(BaseRegistry):
|
||||
unit_of_measurement=unit_of_measurement,
|
||||
)
|
||||
|
||||
self.hass.verify_event_loop_thread("async_get_or_create")
|
||||
self.hass.verify_event_loop_thread("entity_registry.async_get_or_create")
|
||||
_validate_item(
|
||||
self.hass,
|
||||
domain,
|
||||
@ -894,7 +894,7 @@ class EntityRegistry(BaseRegistry):
|
||||
@callback
|
||||
def async_remove(self, entity_id: str) -> None:
|
||||
"""Remove an entity from registry."""
|
||||
self.hass.verify_event_loop_thread("async_remove")
|
||||
self.hass.verify_event_loop_thread("entity_registry.async_remove")
|
||||
entity = self.entities.pop(entity_id)
|
||||
config_entry_id = entity.config_entry_id
|
||||
key = (entity.domain, entity.platform, entity.unique_id)
|
||||
@ -1089,7 +1089,7 @@ class EntityRegistry(BaseRegistry):
|
||||
if not new_values:
|
||||
return old
|
||||
|
||||
self.hass.verify_event_loop_thread("_async_update_entity")
|
||||
self.hass.verify_event_loop_thread("entity_registry.async_update_entity")
|
||||
|
||||
new = self.entities[entity_id] = attr.evolve(old, **new_values)
|
||||
|
||||
|
@ -121,7 +121,7 @@ class FloorRegistry(BaseRegistry[FloorRegistryStoreData]):
|
||||
level: int | None = None,
|
||||
) -> FloorEntry:
|
||||
"""Create a new floor."""
|
||||
self.hass.verify_event_loop_thread("async_create")
|
||||
self.hass.verify_event_loop_thread("floor_registry.async_create")
|
||||
if floor := self.async_get_floor_by_name(name):
|
||||
raise ValueError(
|
||||
f"The name {name} ({floor.normalized_name}) is already in use"
|
||||
@ -152,7 +152,7 @@ class FloorRegistry(BaseRegistry[FloorRegistryStoreData]):
|
||||
@callback
|
||||
def async_delete(self, floor_id: str) -> None:
|
||||
"""Delete floor."""
|
||||
self.hass.verify_event_loop_thread("async_delete")
|
||||
self.hass.verify_event_loop_thread("floor_registry.async_delete")
|
||||
del self.floors[floor_id]
|
||||
self.hass.bus.async_fire_internal(
|
||||
EVENT_FLOOR_REGISTRY_UPDATED,
|
||||
@ -191,7 +191,7 @@ class FloorRegistry(BaseRegistry[FloorRegistryStoreData]):
|
||||
if not changes:
|
||||
return old
|
||||
|
||||
self.hass.verify_event_loop_thread("async_update")
|
||||
self.hass.verify_event_loop_thread("floor_registry.async_update")
|
||||
new = self.floors[floor_id] = dataclasses.replace(old, **changes) # type: ignore[arg-type]
|
||||
|
||||
self.async_schedule_save()
|
||||
|
@ -144,7 +144,7 @@ class IssueRegistry(BaseRegistry):
|
||||
translation_placeholders: dict[str, str] | None = None,
|
||||
) -> IssueEntry:
|
||||
"""Get issue. Create if it doesn't exist."""
|
||||
self.hass.verify_event_loop_thread("async_get_or_create")
|
||||
self.hass.verify_event_loop_thread("issue_registry.async_get_or_create")
|
||||
if (issue := self.async_get_issue(domain, issue_id)) is None:
|
||||
issue = IssueEntry(
|
||||
active=True,
|
||||
@ -204,7 +204,7 @@ class IssueRegistry(BaseRegistry):
|
||||
@callback
|
||||
def async_delete(self, domain: str, issue_id: str) -> None:
|
||||
"""Delete issue."""
|
||||
self.hass.verify_event_loop_thread("async_delete")
|
||||
self.hass.verify_event_loop_thread("issue_registry.async_delete")
|
||||
if self.issues.pop((domain, issue_id), None) is None:
|
||||
return
|
||||
|
||||
@ -221,7 +221,7 @@ class IssueRegistry(BaseRegistry):
|
||||
@callback
|
||||
def async_ignore(self, domain: str, issue_id: str, ignore: bool) -> IssueEntry:
|
||||
"""Ignore issue."""
|
||||
self.hass.verify_event_loop_thread("async_ignore")
|
||||
self.hass.verify_event_loop_thread("issue_registry.async_ignore")
|
||||
old = self.issues[(domain, issue_id)]
|
||||
dismissed_version = ha_version if ignore else None
|
||||
if old.dismissed_version == dismissed_version:
|
||||
|
@ -121,7 +121,7 @@ class LabelRegistry(BaseRegistry[LabelRegistryStoreData]):
|
||||
description: str | None = None,
|
||||
) -> LabelEntry:
|
||||
"""Create a new label."""
|
||||
self.hass.verify_event_loop_thread("async_create")
|
||||
self.hass.verify_event_loop_thread("label_registry.async_create")
|
||||
if label := self.async_get_label_by_name(name):
|
||||
raise ValueError(
|
||||
f"The name {name} ({label.normalized_name}) is already in use"
|
||||
@ -152,7 +152,7 @@ class LabelRegistry(BaseRegistry[LabelRegistryStoreData]):
|
||||
@callback
|
||||
def async_delete(self, label_id: str) -> None:
|
||||
"""Delete label."""
|
||||
self.hass.verify_event_loop_thread("async_delete")
|
||||
self.hass.verify_event_loop_thread("label_registry.async_delete")
|
||||
del self.labels[label_id]
|
||||
self.hass.bus.async_fire_internal(
|
||||
EVENT_LABEL_REGISTRY_UPDATED,
|
||||
@ -192,7 +192,7 @@ class LabelRegistry(BaseRegistry[LabelRegistryStoreData]):
|
||||
if not changes:
|
||||
return old
|
||||
|
||||
self.hass.verify_event_loop_thread("async_update")
|
||||
self.hass.verify_event_loop_thread("label_registry.async_update")
|
||||
new = self.labels[label_id] = dataclasses.replace(old, **changes) # type: ignore[arg-type]
|
||||
|
||||
self.async_schedule_save()
|
||||
|
@ -500,7 +500,7 @@ async def test_async_get_or_create_thread_checks(
|
||||
"""We raise when trying to create in the wrong thread."""
|
||||
with pytest.raises(
|
||||
RuntimeError,
|
||||
match="Detected code that calls async_create from a thread. Please report this issue.",
|
||||
match="Detected code that calls area_registry.async_create from a thread.",
|
||||
):
|
||||
await hass.async_add_executor_job(area_registry.async_create, "Mock1")
|
||||
|
||||
@ -512,7 +512,7 @@ async def test_async_update_thread_checks(
|
||||
area = area_registry.async_create("Mock1")
|
||||
with pytest.raises(
|
||||
RuntimeError,
|
||||
match="Detected code that calls _async_update from a thread. Please report this issue.",
|
||||
match="Detected code that calls area_registry.async_update from a thread.",
|
||||
):
|
||||
await hass.async_add_executor_job(
|
||||
partial(area_registry.async_update, area.id, name="Mock2")
|
||||
@ -526,6 +526,6 @@ async def test_async_delete_thread_checks(
|
||||
area = area_registry.async_create("Mock1")
|
||||
with pytest.raises(
|
||||
RuntimeError,
|
||||
match="Detected code that calls async_delete from a thread. Please report this issue.",
|
||||
match="Detected code that calls area_registry.async_delete from a thread.",
|
||||
):
|
||||
await hass.async_add_executor_job(area_registry.async_delete, area.id)
|
||||
|
@ -403,7 +403,7 @@ async def test_async_create_thread_safety(
|
||||
"""Test async_create raises when called from wrong thread."""
|
||||
with pytest.raises(
|
||||
RuntimeError,
|
||||
match="Detected code that calls async_create from a thread. Please report this issue.",
|
||||
match="Detected code that calls category_registry.async_create from a thread.",
|
||||
):
|
||||
await hass.async_add_executor_job(
|
||||
partial(category_registry.async_create, name="any", scope="any")
|
||||
@ -418,7 +418,7 @@ async def test_async_delete_thread_safety(
|
||||
|
||||
with pytest.raises(
|
||||
RuntimeError,
|
||||
match="Detected code that calls async_delete from a thread. Please report this issue.",
|
||||
match="Detected code that calls category_registry.async_delete from a thread.",
|
||||
):
|
||||
await hass.async_add_executor_job(
|
||||
partial(
|
||||
@ -437,7 +437,7 @@ async def test_async_update_thread_safety(
|
||||
|
||||
with pytest.raises(
|
||||
RuntimeError,
|
||||
match="Detected code that calls async_update from a thread. Please report this issue.",
|
||||
match="Detected code that calls category_registry.async_update from a thread.",
|
||||
):
|
||||
await hass.async_add_executor_job(
|
||||
partial(
|
||||
|
@ -2485,7 +2485,7 @@ async def test_async_get_or_create_thread_safety(
|
||||
|
||||
with pytest.raises(
|
||||
RuntimeError,
|
||||
match="Detected code that calls async_update_device from a thread. Please report this issue.",
|
||||
match="Detected code that calls device_registry.async_update_device from a thread.",
|
||||
):
|
||||
await hass.async_add_executor_job(
|
||||
partial(
|
||||
@ -2515,7 +2515,7 @@ async def test_async_remove_device_thread_safety(
|
||||
|
||||
with pytest.raises(
|
||||
RuntimeError,
|
||||
match="Detected code that calls async_remove_device from a thread. Please report this issue.",
|
||||
match="Detected code that calls device_registry.async_remove_device from a thread.",
|
||||
):
|
||||
await hass.async_add_executor_job(
|
||||
device_registry.async_remove_device, device.id
|
||||
|
@ -1984,7 +1984,7 @@ async def test_get_or_create_thread_safety(
|
||||
"""Test call async_get_or_create_from a thread."""
|
||||
with pytest.raises(
|
||||
RuntimeError,
|
||||
match="Detected code that calls async_get_or_create from a thread. Please report this issue.",
|
||||
match="Detected code that calls entity_registry.async_get_or_create from a thread.",
|
||||
):
|
||||
await hass.async_add_executor_job(
|
||||
entity_registry.async_get_or_create, "light", "hue", "1234"
|
||||
@ -1998,7 +1998,7 @@ async def test_async_update_entity_thread_safety(
|
||||
entry = entity_registry.async_get_or_create("light", "hue", "1234")
|
||||
with pytest.raises(
|
||||
RuntimeError,
|
||||
match="Detected code that calls _async_update_entity from a thread. Please report this issue.",
|
||||
match="Detected code that calls entity_registry.async_update_entity from a thread.",
|
||||
):
|
||||
await hass.async_add_executor_job(
|
||||
partial(
|
||||
@ -2016,6 +2016,6 @@ async def test_async_remove_thread_safety(
|
||||
entry = entity_registry.async_get_or_create("light", "hue", "1234")
|
||||
with pytest.raises(
|
||||
RuntimeError,
|
||||
match="Detected code that calls async_remove from a thread. Please report this issue.",
|
||||
match="Detected code that calls entity_registry.async_remove from a thread.",
|
||||
):
|
||||
await hass.async_add_executor_job(entity_registry.async_remove, entry.entity_id)
|
||||
|
@ -367,7 +367,7 @@ async def test_async_create_thread_safety(
|
||||
"""Test async_create raises when called from wrong thread."""
|
||||
with pytest.raises(
|
||||
RuntimeError,
|
||||
match="Detected code that calls async_create from a thread. Please report this issue.",
|
||||
match="Detected code that calls floor_registry.async_create from a thread.",
|
||||
):
|
||||
await hass.async_add_executor_job(floor_registry.async_create, "any")
|
||||
|
||||
@ -381,7 +381,7 @@ async def test_async_delete_thread_safety(
|
||||
|
||||
with pytest.raises(
|
||||
RuntimeError,
|
||||
match="Detected code that calls async_delete from a thread. Please report this issue.",
|
||||
match="Detected code that calls floor_registry.async_delete from a thread.",
|
||||
):
|
||||
await hass.async_add_executor_job(floor_registry.async_delete, any_floor)
|
||||
|
||||
@ -395,7 +395,7 @@ async def test_async_update_thread_safety(
|
||||
|
||||
with pytest.raises(
|
||||
RuntimeError,
|
||||
match="Detected code that calls async_update from a thread. Please report this issue.",
|
||||
match="Detected code that calls floor_registry.async_update from a thread.",
|
||||
):
|
||||
await hass.async_add_executor_job(
|
||||
partial(floor_registry.async_update, any_floor.floor_id, name="new name")
|
||||
|
@ -367,7 +367,7 @@ async def test_get_or_create_thread_safety(
|
||||
"""Test call async_get_or_create_from a thread."""
|
||||
with pytest.raises(
|
||||
RuntimeError,
|
||||
match="Detected code that calls async_get_or_create from a thread. Please report this issue.",
|
||||
match="Detected code that calls issue_registry.async_get_or_create from a thread.",
|
||||
):
|
||||
await hass.async_add_executor_job(
|
||||
partial(
|
||||
@ -397,7 +397,7 @@ async def test_async_delete_issue_thread_safety(
|
||||
|
||||
with pytest.raises(
|
||||
RuntimeError,
|
||||
match="Detected code that calls async_delete from a thread. Please report this issue.",
|
||||
match="Detected code that calls issue_registry.async_delete from a thread.",
|
||||
):
|
||||
await hass.async_add_executor_job(
|
||||
ir.async_delete_issue,
|
||||
@ -422,7 +422,7 @@ async def test_async_ignore_issue_thread_safety(
|
||||
|
||||
with pytest.raises(
|
||||
RuntimeError,
|
||||
match="Detected code that calls async_ignore from a thread. Please report this issue.",
|
||||
match="Detected code that calls issue_registry.async_ignore from a thread.",
|
||||
):
|
||||
await hass.async_add_executor_job(
|
||||
ir.async_ignore_issue, hass, "any", "any", True
|
||||
|
@ -464,7 +464,7 @@ async def test_async_create_thread_safety(
|
||||
"""Test async_create raises when called from wrong thread."""
|
||||
with pytest.raises(
|
||||
RuntimeError,
|
||||
match="Detected code that calls async_create from a thread. Please report this issue.",
|
||||
match="Detected code that calls label_registry.async_create from a thread.",
|
||||
):
|
||||
await hass.async_add_executor_job(label_registry.async_create, "any")
|
||||
|
||||
@ -478,7 +478,7 @@ async def test_async_delete_thread_safety(
|
||||
|
||||
with pytest.raises(
|
||||
RuntimeError,
|
||||
match="Detected code that calls async_delete from a thread. Please report this issue.",
|
||||
match="Detected code that calls label_registry.async_delete from a thread.",
|
||||
):
|
||||
await hass.async_add_executor_job(label_registry.async_delete, any_label)
|
||||
|
||||
@ -492,7 +492,7 @@ async def test_async_update_thread_safety(
|
||||
|
||||
with pytest.raises(
|
||||
RuntimeError,
|
||||
match="Detected code that calls async_update from a thread. Please report this issue.",
|
||||
match="Detected code that calls label_registry.async_update from a thread.",
|
||||
):
|
||||
await hass.async_add_executor_job(
|
||||
partial(label_registry.async_update, any_label.label_id, name="new name")
|
||||
|
@ -3442,7 +3442,8 @@ async def test_async_fire_thread_safety(hass: HomeAssistant) -> None:
|
||||
events = async_capture_events(hass, "test_event")
|
||||
hass.bus.async_fire("test_event")
|
||||
with pytest.raises(
|
||||
RuntimeError, match="Detected code that calls async_fire from a thread."
|
||||
RuntimeError,
|
||||
match="Detected code that calls hass.bus.async_fire from a thread.",
|
||||
):
|
||||
await hass.async_add_executor_job(hass.bus.async_fire, "test_event")
|
||||
|
||||
@ -3452,7 +3453,8 @@ async def test_async_fire_thread_safety(hass: HomeAssistant) -> None:
|
||||
async def test_async_register_thread_safety(hass: HomeAssistant) -> None:
|
||||
"""Test async_register thread safety."""
|
||||
with pytest.raises(
|
||||
RuntimeError, match="Detected code that calls async_register from a thread."
|
||||
RuntimeError,
|
||||
match="Detected code that calls hass.services.async_register from a thread.",
|
||||
):
|
||||
await hass.async_add_executor_job(
|
||||
hass.services.async_register,
|
||||
@ -3465,7 +3467,8 @@ async def test_async_register_thread_safety(hass: HomeAssistant) -> None:
|
||||
async def test_async_remove_thread_safety(hass: HomeAssistant) -> None:
|
||||
"""Test async_remove thread safety."""
|
||||
with pytest.raises(
|
||||
RuntimeError, match="Detected code that calls async_remove from a thread."
|
||||
RuntimeError,
|
||||
match="Detected code that calls hass.services.async_remove from a thread.",
|
||||
):
|
||||
await hass.async_add_executor_job(
|
||||
hass.services.async_remove, "test_domain", "test_service"
|
||||
@ -3479,6 +3482,7 @@ async def test_async_create_task_thread_safety(hass: HomeAssistant) -> None:
|
||||
pass
|
||||
|
||||
with pytest.raises(
|
||||
RuntimeError, match="Detected code that calls async_create_task from a thread."
|
||||
RuntimeError,
|
||||
match="Detected code that calls hass.async_create_task from a thread.",
|
||||
):
|
||||
await hass.async_add_executor_job(hass.async_create_task, _any_coro)
|
||||
|
Loading…
x
Reference in New Issue
Block a user