Move issue_registry to homeassistant.helpers (#77299)

* Move issue_registry to homeassistant.helpers

* Add backwards compatibility
This commit is contained in:
Erik Montnemery 2022-08-25 11:32:06 +02:00 committed by GitHub
parent 79ab794e6a
commit dfed3ba75e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 174 additions and 159 deletions

View file

@ -24,7 +24,13 @@ from .const import (
SIGNAL_BOOTSTRAP_INTEGRATONS,
)
from .exceptions import HomeAssistantError
from .helpers import area_registry, device_registry, entity_registry, recorder
from .helpers import (
area_registry,
device_registry,
entity_registry,
issue_registry,
recorder,
)
from .helpers.dispatcher import async_dispatcher_send
from .helpers.typing import ConfigType
from .setup import (
@ -521,9 +527,10 @@ async def _async_set_up_integrations(
# Load the registries and cache the result of platform.uname().processor
await asyncio.gather(
area_registry.async_load(hass),
device_registry.async_load(hass),
entity_registry.async_load(hass),
area_registry.async_load(hass),
issue_registry.async_load(hass),
hass.async_add_executor_job(_cache_uname_processor),
)

View file

@ -2,19 +2,19 @@
from __future__ import annotations
from homeassistant.core import HomeAssistant
from homeassistant.helpers.typing import ConfigType
from . import issue_handler, websocket_api
from .const import DOMAIN
from .issue_handler import (
ConfirmRepairFlow,
from homeassistant.helpers.issue_registry import (
IssueSeverity,
async_create_issue,
async_delete_issue,
create_issue,
delete_issue,
)
from .issue_registry import async_load as async_load_issue_registry
from .models import IssueSeverity, RepairsFlow
from homeassistant.helpers.typing import ConfigType
from . import issue_handler, websocket_api
from .const import DOMAIN
from .issue_handler import ConfirmRepairFlow
from .models import RepairsFlow
__all__ = [
"async_create_issue",
@ -34,6 +34,5 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
issue_handler.async_setup(hass)
websocket_api.async_setup(hass)
await async_load_issue_registry(hass)
return True

View file

@ -1,10 +1,8 @@
"""The repairs integration."""
from __future__ import annotations
import functools as ft
from typing import Any
from awesomeversion import AwesomeVersion, AwesomeVersionStrategy
import voluptuous as vol
from homeassistant import data_entry_flow
@ -13,11 +11,16 @@ from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.integration_platform import (
async_process_integration_platforms,
)
from homeassistant.util.async_ import run_callback_threadsafe
# pylint: disable-next=unused-import
from homeassistant.helpers.issue_registry import ( # noqa: F401; Remove when integrations have been updated
async_create_issue,
async_delete_issue,
async_get as async_get_issue_registry,
)
from .const import DOMAIN
from .issue_registry import async_get as async_get_issue_registry
from .models import IssueSeverity, RepairsFlow, RepairsProtocol
from .models import RepairsFlow, RepairsProtocol
class ConfirmRepairFlow(RepairsFlow):
@ -111,112 +114,3 @@ async def _register_repairs_platform(
if not hasattr(platform, "async_create_fix_flow"):
raise HomeAssistantError(f"Invalid repairs platform {platform}")
hass.data[DOMAIN]["platforms"][integration_domain] = platform
@callback
def async_create_issue(
hass: HomeAssistant,
domain: str,
issue_id: str,
*,
breaks_in_ha_version: str | None = None,
data: dict[str, str | int | float | None] | None = None,
is_fixable: bool,
is_persistent: bool = False,
issue_domain: str | None = None,
learn_more_url: str | None = None,
severity: IssueSeverity,
translation_key: str,
translation_placeholders: dict[str, str] | None = None,
) -> None:
"""Create an issue, or replace an existing one."""
# Verify the breaks_in_ha_version is a valid version string
if breaks_in_ha_version:
AwesomeVersion(
breaks_in_ha_version,
ensure_strategy=AwesomeVersionStrategy.CALVER,
find_first_match=False,
)
issue_registry = async_get_issue_registry(hass)
issue_registry.async_get_or_create(
domain,
issue_id,
breaks_in_ha_version=breaks_in_ha_version,
data=data,
is_fixable=is_fixable,
is_persistent=is_persistent,
issue_domain=issue_domain,
learn_more_url=learn_more_url,
severity=severity,
translation_key=translation_key,
translation_placeholders=translation_placeholders,
)
def create_issue(
hass: HomeAssistant,
domain: str,
issue_id: str,
*,
breaks_in_ha_version: str | None = None,
data: dict[str, str | int | float | None] | None = None,
is_fixable: bool,
is_persistent: bool = False,
issue_domain: str | None = None,
learn_more_url: str | None = None,
severity: IssueSeverity,
translation_key: str,
translation_placeholders: dict[str, str] | None = None,
) -> None:
"""Create an issue, or replace an existing one."""
return run_callback_threadsafe(
hass.loop,
ft.partial(
async_create_issue,
hass,
domain,
issue_id,
breaks_in_ha_version=breaks_in_ha_version,
data=data,
is_fixable=is_fixable,
is_persistent=is_persistent,
issue_domain=issue_domain,
learn_more_url=learn_more_url,
severity=severity,
translation_key=translation_key,
translation_placeholders=translation_placeholders,
),
).result()
@callback
def async_delete_issue(hass: HomeAssistant, domain: str, issue_id: str) -> None:
"""Delete an issue.
It is not an error to delete an issue that does not exist.
"""
issue_registry = async_get_issue_registry(hass)
issue_registry.async_delete(domain, issue_id)
def delete_issue(hass: HomeAssistant, domain: str, issue_id: str) -> None:
"""Delete an issue.
It is not an error to delete an issue that does not exist.
"""
return run_callback_threadsafe(
hass.loop, async_delete_issue, hass, domain, issue_id
).result()
@callback
def async_ignore_issue(
hass: HomeAssistant, domain: str, issue_id: str, ignore: bool
) -> None:
"""Ignore an issue.
Will raise if the issue does not exist.
"""
issue_registry = async_get_issue_registry(hass)
issue_registry.async_ignore(domain, issue_id, ignore)

View file

@ -4,16 +4,12 @@ from __future__ import annotations
from typing import Protocol
from homeassistant import data_entry_flow
from homeassistant.backports.enum import StrEnum
from homeassistant.core import HomeAssistant
class IssueSeverity(StrEnum):
"""Issue severity."""
CRITICAL = "critical"
ERROR = "error"
WARNING = "warning"
# pylint: disable-next=unused-import
from homeassistant.helpers.issue_registry import ( # noqa: F401; Remove when integrations have been updated
IssueSeverity,
)
class RepairsFlow(data_entry_flow.FlowHandler):

View file

@ -18,10 +18,12 @@ from homeassistant.helpers.data_entry_flow import (
FlowManagerIndexView,
FlowManagerResourceView,
)
from homeassistant.helpers.issue_registry import (
async_get as async_get_issue_registry,
async_ignore_issue,
)
from .const import DOMAIN
from .issue_handler import async_ignore_issue
from .issue_registry import async_get as async_get_issue_registry
@callback

View file

@ -3,14 +3,18 @@ from __future__ import annotations
import dataclasses
from datetime import datetime
import functools as ft
from typing import Any, cast
from awesomeversion import AwesomeVersion, AwesomeVersionStrategy
from homeassistant.backports.enum import StrEnum
from homeassistant.const import __version__ as ha_version
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.storage import Store
from homeassistant.util.async_ import run_callback_threadsafe
import homeassistant.util.dt as dt_util
from .models import IssueSeverity
from .storage import Store
DATA_REGISTRY = "issue_registry"
EVENT_REPAIRS_ISSUE_REGISTRY_UPDATED = "repairs_issue_registry_updated"
@ -20,6 +24,14 @@ STORAGE_VERSION_MINOR = 2
SAVE_DELAY = 10
class IssueSeverity(StrEnum):
"""Issue severity."""
CRITICAL = "critical"
ERROR = "error"
WARNING = "warning"
@dataclasses.dataclass(frozen=True)
class IssueEntry:
"""Issue Registry Entry."""
@ -267,3 +279,112 @@ async def async_load(hass: HomeAssistant) -> None:
assert DATA_REGISTRY not in hass.data
hass.data[DATA_REGISTRY] = IssueRegistry(hass)
await hass.data[DATA_REGISTRY].async_load()
@callback
def async_create_issue(
hass: HomeAssistant,
domain: str,
issue_id: str,
*,
breaks_in_ha_version: str | None = None,
data: dict[str, str | int | float | None] | None = None,
is_fixable: bool,
is_persistent: bool = False,
issue_domain: str | None = None,
learn_more_url: str | None = None,
severity: IssueSeverity,
translation_key: str,
translation_placeholders: dict[str, str] | None = None,
) -> None:
"""Create an issue, or replace an existing one."""
# Verify the breaks_in_ha_version is a valid version string
if breaks_in_ha_version:
AwesomeVersion(
breaks_in_ha_version,
ensure_strategy=AwesomeVersionStrategy.CALVER,
find_first_match=False,
)
issue_registry = async_get(hass)
issue_registry.async_get_or_create(
domain,
issue_id,
breaks_in_ha_version=breaks_in_ha_version,
data=data,
is_fixable=is_fixable,
is_persistent=is_persistent,
issue_domain=issue_domain,
learn_more_url=learn_more_url,
severity=severity,
translation_key=translation_key,
translation_placeholders=translation_placeholders,
)
def create_issue(
hass: HomeAssistant,
domain: str,
issue_id: str,
*,
breaks_in_ha_version: str | None = None,
data: dict[str, str | int | float | None] | None = None,
is_fixable: bool,
is_persistent: bool = False,
issue_domain: str | None = None,
learn_more_url: str | None = None,
severity: IssueSeverity,
translation_key: str,
translation_placeholders: dict[str, str] | None = None,
) -> None:
"""Create an issue, or replace an existing one."""
return run_callback_threadsafe(
hass.loop,
ft.partial(
async_create_issue,
hass,
domain,
issue_id,
breaks_in_ha_version=breaks_in_ha_version,
data=data,
is_fixable=is_fixable,
is_persistent=is_persistent,
issue_domain=issue_domain,
learn_more_url=learn_more_url,
severity=severity,
translation_key=translation_key,
translation_placeholders=translation_placeholders,
),
).result()
@callback
def async_delete_issue(hass: HomeAssistant, domain: str, issue_id: str) -> None:
"""Delete an issue.
It is not an error to delete an issue that does not exist.
"""
issue_registry = async_get(hass)
issue_registry.async_delete(domain, issue_id)
def delete_issue(hass: HomeAssistant, domain: str, issue_id: str) -> None:
"""Delete an issue.
It is not an error to delete an issue that does not exist.
"""
return run_callback_threadsafe(
hass.loop, async_delete_issue, hass, domain, issue_id
).result()
@callback
def async_ignore_issue(
hass: HomeAssistant, domain: str, issue_id: str, ignore: bool
) -> None:
"""Ignore an issue.
Will raise if the issue does not exist.
"""
issue_registry = async_get(hass)
issue_registry.async_ignore(domain, issue_id, ignore)

View file

@ -50,6 +50,7 @@ from homeassistant.helpers import (
entity_platform,
entity_registry,
intent,
issue_registry,
recorder as recorder_helper,
restore_state,
storage,
@ -297,9 +298,10 @@ async def async_test_home_assistant(loop, load_registries=True):
# Load the registries
if load_registries:
await asyncio.gather(
area_registry.async_load(hass),
device_registry.async_load(hass),
entity_registry.async_load(hass),
area_registry.async_load(hass),
issue_registry.async_load(hass),
)
await hass.async_block_till_done()

View file

@ -14,12 +14,11 @@ from homeassistant.components.repairs import (
)
from homeassistant.components.repairs.const import DOMAIN
from homeassistant.components.repairs.issue_handler import (
async_ignore_issue,
async_process_repairs_platforms,
)
from homeassistant.components.repairs.models import IssueSeverity
from homeassistant.const import __version__ as ha_version
from homeassistant.core import HomeAssistant
from homeassistant.helpers.issue_registry import IssueSeverity, async_ignore_issue
from homeassistant.setup import async_setup_component
from tests.common import mock_platform

View file

@ -9,14 +9,11 @@ import pytest
import voluptuous as vol
from homeassistant import data_entry_flow
from homeassistant.components.repairs import (
RepairsFlow,
async_create_issue,
issue_registry,
)
from homeassistant.components.repairs import RepairsFlow, async_create_issue
from homeassistant.components.repairs.const import DOMAIN
from homeassistant.const import __version__ as ha_version
from homeassistant.core import HomeAssistant
from homeassistant.helpers import issue_registry
from homeassistant.setup import async_setup_component
from tests.common import mock_platform

View file

@ -1,20 +1,14 @@
"""Test the repairs websocket API."""
from homeassistant.components.repairs import async_create_issue, issue_registry
from homeassistant.components.repairs.const import DOMAIN
from homeassistant.components.repairs.issue_handler import (
async_delete_issue,
async_ignore_issue,
)
import pytest
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
from homeassistant.helpers import issue_registry
from tests.common import async_capture_events, flush_store
async def test_load_issues(hass: HomeAssistant) -> None:
"""Make sure that we can load/save data correctly."""
assert await async_setup_component(hass, DOMAIN, {})
issues = [
{
"breaks_in_ha_version": "2022.9",
@ -68,7 +62,7 @@ async def test_load_issues(hass: HomeAssistant) -> None:
)
for issue in issues:
async_create_issue(
issue_registry.async_create_issue(
hass,
issue["domain"],
issue["issue_id"],
@ -105,7 +99,9 @@ async def test_load_issues(hass: HomeAssistant) -> None:
"issue_id": "issue_4",
}
async_ignore_issue(hass, issues[0]["domain"], issues[0]["issue_id"], True)
issue_registry.async_ignore_issue(
hass, issues[0]["domain"], issues[0]["issue_id"], True
)
await hass.async_block_till_done()
assert len(events) == 5
@ -115,7 +111,7 @@ async def test_load_issues(hass: HomeAssistant) -> None:
"issue_id": "issue_1",
}
async_delete_issue(hass, issues[2]["domain"], issues[2]["issue_id"])
issue_registry.async_delete_issue(hass, issues[2]["domain"], issues[2]["issue_id"])
await hass.async_block_till_done()
assert len(events) == 6
@ -175,6 +171,7 @@ async def test_load_issues(hass: HomeAssistant) -> None:
assert issue4_registry2 == issue4
@pytest.mark.parametrize("load_registries", [False])
async def test_loading_issues_from_storage(hass: HomeAssistant, hass_storage) -> None:
"""Test loading stored issues on start."""
hass_storage[issue_registry.STORAGE_KEY] = {
@ -215,12 +212,13 @@ async def test_loading_issues_from_storage(hass: HomeAssistant, hass_storage) ->
},
}
assert await async_setup_component(hass, DOMAIN, {})
await issue_registry.async_load(hass)
registry: issue_registry.IssueRegistry = hass.data[issue_registry.DATA_REGISTRY]
assert len(registry.issues) == 3
@pytest.mark.parametrize("load_registries", [False])
async def test_migration_1_1(hass: HomeAssistant, hass_storage) -> None:
"""Test migration from version 1.1."""
hass_storage[issue_registry.STORAGE_KEY] = {
@ -244,7 +242,7 @@ async def test_migration_1_1(hass: HomeAssistant, hass_storage) -> None:
},
}
assert await async_setup_component(hass, DOMAIN, {})
await issue_registry.async_load(hass)
registry: issue_registry.IssueRegistry = hass.data[issue_registry.DATA_REGISTRY]
assert len(registry.issues) == 2