mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 12:47:08 +00:00
Drop old migration code from entity registry (#78278)
This commit is contained in:
parent
13f250319d
commit
4e32bf2ac9
@ -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."""
|
||||
|
@ -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")
|
||||
|
Loading…
x
Reference in New Issue
Block a user