mirror of
https://github.com/home-assistant/core.git
synced 2025-07-27 23:27:37 +00:00
Move thread safety check in issue_registry sooner (#116899)
This commit is contained in:
parent
2a4686e1b7
commit
5d5f311898
@ -132,7 +132,7 @@ class IssueRegistry(BaseRegistry):
|
|||||||
translation_placeholders: dict[str, str] | None = None,
|
translation_placeholders: dict[str, str] | None = None,
|
||||||
) -> IssueEntry:
|
) -> IssueEntry:
|
||||||
"""Get issue. Create if it doesn't exist."""
|
"""Get issue. Create if it doesn't exist."""
|
||||||
|
self.hass.verify_event_loop_thread("async_get_or_create")
|
||||||
if (issue := self.async_get_issue(domain, issue_id)) is None:
|
if (issue := self.async_get_issue(domain, issue_id)) is None:
|
||||||
issue = IssueEntry(
|
issue = IssueEntry(
|
||||||
active=True,
|
active=True,
|
||||||
@ -152,7 +152,7 @@ class IssueRegistry(BaseRegistry):
|
|||||||
)
|
)
|
||||||
self.issues[(domain, issue_id)] = issue
|
self.issues[(domain, issue_id)] = issue
|
||||||
self.async_schedule_save()
|
self.async_schedule_save()
|
||||||
self.hass.bus.async_fire(
|
self.hass.bus.async_fire_internal(
|
||||||
EVENT_REPAIRS_ISSUE_REGISTRY_UPDATED,
|
EVENT_REPAIRS_ISSUE_REGISTRY_UPDATED,
|
||||||
{"action": "create", "domain": domain, "issue_id": issue_id},
|
{"action": "create", "domain": domain, "issue_id": issue_id},
|
||||||
)
|
)
|
||||||
@ -174,7 +174,7 @@ class IssueRegistry(BaseRegistry):
|
|||||||
if replacement != issue:
|
if replacement != issue:
|
||||||
issue = self.issues[(domain, issue_id)] = replacement
|
issue = self.issues[(domain, issue_id)] = replacement
|
||||||
self.async_schedule_save()
|
self.async_schedule_save()
|
||||||
self.hass.bus.async_fire(
|
self.hass.bus.async_fire_internal(
|
||||||
EVENT_REPAIRS_ISSUE_REGISTRY_UPDATED,
|
EVENT_REPAIRS_ISSUE_REGISTRY_UPDATED,
|
||||||
{"action": "update", "domain": domain, "issue_id": issue_id},
|
{"action": "update", "domain": domain, "issue_id": issue_id},
|
||||||
)
|
)
|
||||||
@ -184,11 +184,12 @@ class IssueRegistry(BaseRegistry):
|
|||||||
@callback
|
@callback
|
||||||
def async_delete(self, domain: str, issue_id: str) -> None:
|
def async_delete(self, domain: str, issue_id: str) -> None:
|
||||||
"""Delete issue."""
|
"""Delete issue."""
|
||||||
|
self.hass.verify_event_loop_thread("async_delete")
|
||||||
if self.issues.pop((domain, issue_id), None) is None:
|
if self.issues.pop((domain, issue_id), None) is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
self.async_schedule_save()
|
self.async_schedule_save()
|
||||||
self.hass.bus.async_fire(
|
self.hass.bus.async_fire_internal(
|
||||||
EVENT_REPAIRS_ISSUE_REGISTRY_UPDATED,
|
EVENT_REPAIRS_ISSUE_REGISTRY_UPDATED,
|
||||||
{"action": "remove", "domain": domain, "issue_id": issue_id},
|
{"action": "remove", "domain": domain, "issue_id": issue_id},
|
||||||
)
|
)
|
||||||
@ -196,6 +197,7 @@ class IssueRegistry(BaseRegistry):
|
|||||||
@callback
|
@callback
|
||||||
def async_ignore(self, domain: str, issue_id: str, ignore: bool) -> IssueEntry:
|
def async_ignore(self, domain: str, issue_id: str, ignore: bool) -> IssueEntry:
|
||||||
"""Ignore issue."""
|
"""Ignore issue."""
|
||||||
|
self.hass.verify_event_loop_thread("async_ignore")
|
||||||
old = self.issues[(domain, issue_id)]
|
old = self.issues[(domain, issue_id)]
|
||||||
dismissed_version = ha_version if ignore else None
|
dismissed_version = ha_version if ignore else None
|
||||||
if old.dismissed_version == dismissed_version:
|
if old.dismissed_version == dismissed_version:
|
||||||
@ -207,7 +209,7 @@ class IssueRegistry(BaseRegistry):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.async_schedule_save()
|
self.async_schedule_save()
|
||||||
self.hass.bus.async_fire(
|
self.hass.bus.async_fire_internal(
|
||||||
EVENT_REPAIRS_ISSUE_REGISTRY_UPDATED,
|
EVENT_REPAIRS_ISSUE_REGISTRY_UPDATED,
|
||||||
{"action": "update", "domain": domain, "issue_id": issue_id},
|
{"action": "update", "domain": domain, "issue_id": issue_id},
|
||||||
)
|
)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
"""Test the repairs websocket API."""
|
"""Test the repairs websocket API."""
|
||||||
|
|
||||||
|
from functools import partial
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@ -358,3 +359,71 @@ async def test_migration_1_1(hass: HomeAssistant, hass_storage: dict[str, Any])
|
|||||||
|
|
||||||
registry: ir.IssueRegistry = hass.data[ir.DATA_REGISTRY]
|
registry: ir.IssueRegistry = hass.data[ir.DATA_REGISTRY]
|
||||||
assert len(registry.issues) == 2
|
assert len(registry.issues) == 2
|
||||||
|
|
||||||
|
|
||||||
|
async def test_get_or_create_thread_safety(
|
||||||
|
hass: HomeAssistant, issue_registry: ir.IssueRegistry
|
||||||
|
) -> None:
|
||||||
|
"""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.",
|
||||||
|
):
|
||||||
|
await hass.async_add_executor_job(
|
||||||
|
partial(
|
||||||
|
ir.async_create_issue,
|
||||||
|
hass,
|
||||||
|
"any",
|
||||||
|
"any",
|
||||||
|
is_fixable=True,
|
||||||
|
severity="error",
|
||||||
|
translation_key="any",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_async_delete_issue_thread_safety(
|
||||||
|
hass: HomeAssistant, issue_registry: ir.IssueRegistry
|
||||||
|
) -> None:
|
||||||
|
"""Test call async_delete_issue from a thread."""
|
||||||
|
ir.async_create_issue(
|
||||||
|
hass,
|
||||||
|
"any",
|
||||||
|
"any",
|
||||||
|
is_fixable=True,
|
||||||
|
severity="error",
|
||||||
|
translation_key="any",
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(
|
||||||
|
RuntimeError,
|
||||||
|
match="Detected code that calls async_delete from a thread. Please report this issue.",
|
||||||
|
):
|
||||||
|
await hass.async_add_executor_job(
|
||||||
|
ir.async_delete_issue,
|
||||||
|
hass,
|
||||||
|
"any",
|
||||||
|
"any",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_async_ignore_issue_thread_safety(
|
||||||
|
hass: HomeAssistant, issue_registry: ir.IssueRegistry
|
||||||
|
) -> None:
|
||||||
|
"""Test call async_ignore_issue from a thread."""
|
||||||
|
ir.async_create_issue(
|
||||||
|
hass,
|
||||||
|
"any",
|
||||||
|
"any",
|
||||||
|
is_fixable=True,
|
||||||
|
severity="error",
|
||||||
|
translation_key="any",
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(
|
||||||
|
RuntimeError,
|
||||||
|
match="Detected code that calls async_ignore from a thread. Please report this issue.",
|
||||||
|
):
|
||||||
|
await hass.async_add_executor_job(
|
||||||
|
ir.async_ignore_issue, hass, "any", "any", True
|
||||||
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user