Drop old migration code from entity registry (#78278)

This commit is contained in:
Erik Montnemery 2022-09-13 04:28:05 +02:00 committed by GitHub
parent 13f250319d
commit 4e32bf2ac9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 61 additions and 196 deletions

View File

@ -42,7 +42,6 @@ from homeassistant.core import (
from homeassistant.exceptions import MaxLengthExceeded
from homeassistant.loader import bind_hass
from homeassistant.util import slugify, uuid as uuid_util
from homeassistant.util.yaml import load_yaml
from . import device_registry as dr, storage
from .device_registry import EVENT_DEVICE_REGISTRY_UPDATED
@ -56,7 +55,6 @@ if TYPE_CHECKING:
T = TypeVar("T")
PATH_REGISTRY = "entity_registry.yaml"
DATA_REGISTRY = "entity_registry"
EVENT_ENTITY_REGISTRY_UPDATED = "entity_registry_updated"
SAVE_DELAY = 10
@ -177,7 +175,65 @@ class EntityRegistryStore(storage.Store):
self, old_major_version: int, old_minor_version: int, old_data: dict
) -> dict:
"""Migrate to the new version."""
return await _async_migrate(old_major_version, old_minor_version, old_data)
data = old_data
if old_major_version == 1 and old_minor_version < 2:
# From version 1.1
for entity in data["entities"]:
# Populate all keys
entity["area_id"] = entity.get("area_id")
entity["capabilities"] = entity.get("capabilities") or {}
entity["config_entry_id"] = entity.get("config_entry_id")
entity["device_class"] = entity.get("device_class")
entity["device_id"] = entity.get("device_id")
entity["disabled_by"] = entity.get("disabled_by")
entity["entity_category"] = entity.get("entity_category")
entity["icon"] = entity.get("icon")
entity["name"] = entity.get("name")
entity["original_icon"] = entity.get("original_icon")
entity["original_name"] = entity.get("original_name")
entity["platform"] = entity["platform"]
entity["supported_features"] = entity.get("supported_features", 0)
entity["unit_of_measurement"] = entity.get("unit_of_measurement")
if old_major_version == 1 and old_minor_version < 3:
# Version 1.3 adds original_device_class
for entity in data["entities"]:
# Move device_class to original_device_class
entity["original_device_class"] = entity["device_class"]
entity["device_class"] = None
if old_major_version == 1 and old_minor_version < 4:
# Version 1.4 adds id
for entity in data["entities"]:
entity["id"] = uuid_util.random_uuid_hex()
if old_major_version == 1 and old_minor_version < 5:
# Version 1.5 adds entity options
for entity in data["entities"]:
entity["options"] = {}
if old_major_version == 1 and old_minor_version < 6:
# Version 1.6 adds hidden_by
for entity in data["entities"]:
entity["hidden_by"] = None
if old_major_version == 1 and old_minor_version < 7:
# Version 1.7 adds has_entity_name
for entity in data["entities"]:
entity["has_entity_name"] = False
if old_major_version == 1 and old_minor_version < 8:
# Cleanup after frontend bug which incorrectly updated device_class
# Fixed by frontend PR #13551
for entity in data["entities"]:
domain = split_entity_id(entity["entity_id"])[0]
if domain in [Platform.BINARY_SENSOR, Platform.COVER]:
continue
entity["device_class"] = None
if old_major_version > 1:
raise NotImplementedError
return data
class EntityRegistryItems(UserDict[str, "RegistryEntry"]):
@ -362,13 +418,6 @@ class EntityRegistry:
original_name=original_name,
supported_features=supported_features,
unit_of_measurement=unit_of_measurement,
# When we changed our slugify algorithm, we invalidated some
# stored entity IDs with either a __ or ending in _.
# Fix introduced in 0.86 (Jan 23, 2019). Next line can be
# removed when we release 1.0 or in 2020.
new_entity_id=".".join(
slugify(part) for part in entity_id.split(".", 1)
),
)
entity_id = self.async_generate_entity_id(
@ -722,25 +771,13 @@ class EntityRegistry:
"""Load the entity registry."""
async_setup_entity_restore(self.hass, self)
data = await storage.async_migrator(
self.hass,
self.hass.config.path(PATH_REGISTRY),
self._store,
old_conf_load_func=load_yaml,
old_conf_migrate_func=_async_migrate_yaml_to_json,
)
data = await self._store.async_load()
entities = EntityRegistryItems()
from .entity import EntityCategory # pylint: disable=import-outside-toplevel
if data is not None:
for entity in data["entities"]:
# Some old installations can have some bad entities.
# Filter them out as they cause errors down the line.
# Can be removed in Jan 2021
if not valid_entity_id(entity["entity_id"]):
continue
# We removed this in 2022.5. Remove this check in 2023.1.
if entity["entity_category"] == "system":
entity["entity_category"] = None
@ -922,82 +959,6 @@ def async_config_entry_disabled_by_changed(
)
async def _async_migrate(
old_major_version: int, old_minor_version: int, data: dict
) -> dict:
"""Migrate to the new version."""
if old_major_version == 1 and old_minor_version < 2:
# From version 1.1
for entity in data["entities"]:
# Populate all keys
entity["area_id"] = entity.get("area_id")
entity["capabilities"] = entity.get("capabilities") or {}
entity["config_entry_id"] = entity.get("config_entry_id")
entity["device_class"] = entity.get("device_class")
entity["device_id"] = entity.get("device_id")
entity["disabled_by"] = entity.get("disabled_by")
entity["entity_category"] = entity.get("entity_category")
entity["icon"] = entity.get("icon")
entity["name"] = entity.get("name")
entity["original_icon"] = entity.get("original_icon")
entity["original_name"] = entity.get("original_name")
entity["platform"] = entity["platform"]
entity["supported_features"] = entity.get("supported_features", 0)
entity["unit_of_measurement"] = entity.get("unit_of_measurement")
if old_major_version == 1 and old_minor_version < 3:
# Version 1.3 adds original_device_class
for entity in data["entities"]:
# Move device_class to original_device_class
entity["original_device_class"] = entity["device_class"]
entity["device_class"] = None
if old_major_version == 1 and old_minor_version < 4:
# Version 1.4 adds id
for entity in data["entities"]:
entity["id"] = uuid_util.random_uuid_hex()
if old_major_version == 1 and old_minor_version < 5:
# Version 1.5 adds entity options
for entity in data["entities"]:
entity["options"] = {}
if old_major_version == 1 and old_minor_version < 6:
# Version 1.6 adds hidden_by
for entity in data["entities"]:
entity["hidden_by"] = None
if old_major_version == 1 and old_minor_version < 7:
# Version 1.7 adds has_entity_name
for entity in data["entities"]:
entity["has_entity_name"] = False
if old_major_version == 1 and old_minor_version < 8:
# Cleanup after frontend bug which incorrectly updated device_class
# Fixed by frontend PR #13551
for entity in data["entities"]:
domain = split_entity_id(entity["entity_id"])[0]
if domain in [Platform.BINARY_SENSOR, Platform.COVER]:
continue
entity["device_class"] = None
if old_major_version > 1:
raise NotImplementedError
return data
async def _async_migrate_yaml_to_json(
entities: dict[str, Any]
) -> dict[str, list[dict[str, Any]]]:
"""Migrate the YAML config file to storage helper format."""
entities_1_1 = {
"entities": [
{"entity_id": entity_id, **info} for entity_id, info in entities.items()
]
}
return await _async_migrate(1, 1, entities_1_1)
@callback
def async_setup_entity_restore(hass: HomeAssistant, registry: EntityRegistry) -> None:
"""Set up the entity restore mechanism."""

View File

@ -6,7 +6,7 @@ import voluptuous as vol
from homeassistant import config_entries
from homeassistant.const import EVENT_HOMEASSISTANT_START, STATE_UNAVAILABLE
from homeassistant.core import CoreState, callback, valid_entity_id
from homeassistant.core import CoreState, callback
from homeassistant.exceptions import MaxLengthExceeded
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.helpers.entity import EntityCategory
@ -342,13 +342,6 @@ async def test_filter_on_load(hass, hass_storage):
"unique_id": "disabled-hass",
"disabled_by": "hass", # We store the string representation
},
# This entry should not be loaded because the entity_id is invalid
{
"entity_id": "test.invalid__entity",
"platform": "super_platform",
"unique_id": "invalid-hass",
"disabled_by": "hass", # We store the string representation
},
# This entry should have the entity_category reset to None
{
"entity_id": "test.system_entity",
@ -465,38 +458,6 @@ async def test_removing_area_id(registry):
assert entry_w_area != entry_wo_area
@pytest.mark.parametrize("load_registries", [False])
async def test_migration_yaml_to_json(hass):
"""Test migration from old (yaml) data to new."""
mock_config = MockConfigEntry(domain="test-platform", entry_id="test-config-id")
old_conf = {
"light.kitchen": {
"config_entry_id": "test-config-id",
"unique_id": "test-unique",
"platform": "test-platform",
"name": "Test Name",
"disabled_by": er.RegistryEntryDisabler.HASS,
}
}
with patch("os.path.isfile", return_value=True), patch("os.remove"), patch(
"homeassistant.helpers.entity_registry.load_yaml", return_value=old_conf
):
await er.async_load(hass)
registry = er.async_get(hass)
assert registry.async_is_registered("light.kitchen")
entry = registry.async_get_or_create(
domain="light",
platform="test-platform",
unique_id="test-unique",
config_entry=mock_config,
)
assert entry.name == "Test Name"
assert entry.disabled_by is er.RegistryEntryDisabler.HASS
assert entry.config_entry_id == "test-config-id"
@pytest.mark.parametrize("load_registries", [False])
async def test_migration_1_1(hass, hass_storage):
"""Test migration from version 1.1."""
@ -596,63 +557,6 @@ async def test_migration_1_7(hass, hass_storage):
assert entry.original_device_class == "class_by_integration"
@pytest.mark.parametrize("load_registries", [False])
async def test_loading_invalid_entity_id(hass, hass_storage):
"""Test we skip entities with invalid entity IDs."""
hass_storage[er.STORAGE_KEY] = {
"version": er.STORAGE_VERSION_MAJOR,
"minor_version": er.STORAGE_VERSION_MINOR,
"data": {
"entities": [
{
"entity_id": "test.invalid__middle",
"platform": "super_platform",
"unique_id": "id-invalid-middle",
"name": "registry override 1",
},
{
"entity_id": "test.invalid_end_",
"platform": "super_platform",
"unique_id": "id-invalid-end",
"name": "registry override 2",
},
{
"entity_id": "test._invalid_start",
"platform": "super_platform",
"unique_id": "id-invalid-start",
"name": "registry override 3",
},
]
},
}
await er.async_load(hass)
registry = er.async_get(hass)
assert len(registry.entities) == 0
entity_invalid_middle = registry.async_get_or_create(
"test", "super_platform", "id-invalid-middle"
)
assert valid_entity_id(entity_invalid_middle.entity_id)
# Check name to make sure we created a new entity
assert entity_invalid_middle.name is None
entity_invalid_end = registry.async_get_or_create(
"test", "super_platform", "id-invalid-end"
)
assert valid_entity_id(entity_invalid_end.entity_id)
assert entity_invalid_end.name is None
entity_invalid_start = registry.async_get_or_create(
"test", "super_platform", "id-invalid-start"
)
assert valid_entity_id(entity_invalid_start.entity_id)
assert entity_invalid_start.name is None
async def test_update_entity_unique_id(registry):
"""Test entity's unique_id is updated."""
mock_config = MockConfigEntry(domain="light", entry_id="mock-id-1")