Enforce RegistryEntryHider in entity registry (#73219)

This commit is contained in:
Erik Montnemery 2022-06-08 21:36:43 +02:00 committed by GitHub
parent 6bf219550e
commit 4435c641de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 60 additions and 17 deletions

View File

@ -369,6 +369,8 @@ class EntityRegistry:
if disabled_by and not isinstance(disabled_by, RegistryEntryDisabler): if disabled_by and not isinstance(disabled_by, RegistryEntryDisabler):
raise ValueError("disabled_by must be a RegistryEntryDisabler value") raise ValueError("disabled_by must be a RegistryEntryDisabler value")
if hidden_by and not isinstance(hidden_by, RegistryEntryHider):
raise ValueError("hidden_by must be a RegistryEntryHider value")
if ( if (
disabled_by is None disabled_by is None
@ -520,6 +522,12 @@ class EntityRegistry:
and not isinstance(disabled_by, RegistryEntryDisabler) and not isinstance(disabled_by, RegistryEntryDisabler)
): ):
raise ValueError("disabled_by must be a RegistryEntryDisabler value") raise ValueError("disabled_by must be a RegistryEntryDisabler value")
if (
hidden_by
and hidden_by is not UNDEFINED
and not isinstance(hidden_by, RegistryEntryHider)
):
raise ValueError("hidden_by must be a RegistryEntryHider value")
from .entity import EntityCategory # pylint: disable=import-outside-toplevel from .entity import EntityCategory # pylint: disable=import-outside-toplevel
@ -729,7 +737,9 @@ class EntityRegistry:
if entity["entity_category"] if entity["entity_category"]
else None, else None,
entity_id=entity["entity_id"], entity_id=entity["entity_id"],
hidden_by=entity["hidden_by"], hidden_by=RegistryEntryHider(entity["hidden_by"])
if entity["hidden_by"]
else None,
icon=entity["icon"], icon=entity["icon"],
id=entity["id"], id=entity["id"],
name=entity["name"], name=entity["name"],

View File

@ -348,7 +348,10 @@ async def test_all_options(
@pytest.mark.parametrize( @pytest.mark.parametrize(
"hide_members,hidden_by_initial,hidden_by", "hide_members,hidden_by_initial,hidden_by",
((False, "integration", None), (True, None, "integration")), (
(False, er.RegistryEntryHider.INTEGRATION, None),
(True, None, er.RegistryEntryHider.INTEGRATION),
),
) )
@pytest.mark.parametrize( @pytest.mark.parametrize(
"group_type,extra_input", "group_type,extra_input",

View File

@ -1421,12 +1421,12 @@ async def test_setup_and_remove_config_entry(
@pytest.mark.parametrize( @pytest.mark.parametrize(
"hide_members,hidden_by_initial,hidden_by", "hide_members,hidden_by_initial,hidden_by",
( (
(False, "integration", "integration"), (False, er.RegistryEntryHider.INTEGRATION, er.RegistryEntryHider.INTEGRATION),
(False, None, None), (False, None, None),
(False, "user", "user"), (False, er.RegistryEntryHider.USER, er.RegistryEntryHider.USER),
(True, "integration", None), (True, er.RegistryEntryHider.INTEGRATION, None),
(True, None, None), (True, None, None),
(True, "user", "user"), (True, er.RegistryEntryHider.USER, er.RegistryEntryHider.USER),
), ),
) )
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -1444,7 +1444,7 @@ async def test_unhide_members_on_remove(
group_type: str, group_type: str,
extra_options: dict[str, Any], extra_options: dict[str, Any],
hide_members: bool, hide_members: bool,
hidden_by_initial: str, hidden_by_initial: er.RegistryEntryHider,
hidden_by: str, hidden_by: str,
) -> None: ) -> None:
"""Test removing a config entry.""" """Test removing a config entry."""

View File

@ -65,8 +65,8 @@ async def test_config_flow(
@pytest.mark.parametrize( @pytest.mark.parametrize(
"hidden_by_before,hidden_by_after", "hidden_by_before,hidden_by_after",
( (
(er.RegistryEntryHider.USER.value, er.RegistryEntryHider.USER.value), (er.RegistryEntryHider.USER, er.RegistryEntryHider.USER),
(None, er.RegistryEntryHider.INTEGRATION.value), (None, er.RegistryEntryHider.INTEGRATION),
), ),
) )
@pytest.mark.parametrize("target_domain", PLATFORMS_TO_TEST) @pytest.mark.parametrize("target_domain", PLATFORMS_TO_TEST)

View File

@ -365,8 +365,8 @@ async def test_setup_and_remove_config_entry(
@pytest.mark.parametrize( @pytest.mark.parametrize(
"hidden_by_before,hidden_by_after", "hidden_by_before,hidden_by_after",
( (
(er.RegistryEntryHider.USER.value, er.RegistryEntryHider.USER.value), (er.RegistryEntryHider.USER, er.RegistryEntryHider.USER),
(er.RegistryEntryHider.INTEGRATION.value, None), (er.RegistryEntryHider.INTEGRATION, None),
), ),
) )
@pytest.mark.parametrize("target_domain", PLATFORMS_TO_TEST) @pytest.mark.parametrize("target_domain", PLATFORMS_TO_TEST)

View File

@ -79,6 +79,7 @@ def test_get_or_create_updates_data(registry):
device_id="mock-dev-id", device_id="mock-dev-id",
disabled_by=er.RegistryEntryDisabler.HASS, disabled_by=er.RegistryEntryDisabler.HASS,
entity_category=EntityCategory.CONFIG, entity_category=EntityCategory.CONFIG,
hidden_by=er.RegistryEntryHider.INTEGRATION,
original_device_class="mock-device-class", original_device_class="mock-device-class",
original_icon="initial-original_icon", original_icon="initial-original_icon",
original_name="initial-original_name", original_name="initial-original_name",
@ -97,6 +98,7 @@ def test_get_or_create_updates_data(registry):
device_id="mock-dev-id", device_id="mock-dev-id",
disabled_by=er.RegistryEntryDisabler.HASS, disabled_by=er.RegistryEntryDisabler.HASS,
entity_category=EntityCategory.CONFIG, entity_category=EntityCategory.CONFIG,
hidden_by=er.RegistryEntryHider.INTEGRATION,
icon=None, icon=None,
id=orig_entry.id, id=orig_entry.id,
name=None, name=None,
@ -119,6 +121,7 @@ def test_get_or_create_updates_data(registry):
device_id="new-mock-dev-id", device_id="new-mock-dev-id",
disabled_by=er.RegistryEntryDisabler.USER, disabled_by=er.RegistryEntryDisabler.USER,
entity_category=None, entity_category=None,
hidden_by=er.RegistryEntryHider.USER,
original_device_class="new-mock-device-class", original_device_class="new-mock-device-class",
original_icon="updated-original_icon", original_icon="updated-original_icon",
original_name="updated-original_name", original_name="updated-original_name",
@ -137,6 +140,7 @@ def test_get_or_create_updates_data(registry):
device_id="new-mock-dev-id", device_id="new-mock-dev-id",
disabled_by=er.RegistryEntryDisabler.HASS, # Should not be updated disabled_by=er.RegistryEntryDisabler.HASS, # Should not be updated
entity_category=EntityCategory.CONFIG, entity_category=EntityCategory.CONFIG,
hidden_by=er.RegistryEntryHider.INTEGRATION, # Should not be updated
icon=None, icon=None,
id=orig_entry.id, id=orig_entry.id,
name=None, name=None,
@ -191,6 +195,7 @@ async def test_loading_saving_data(hass, registry):
device_id="mock-dev-id", device_id="mock-dev-id",
disabled_by=er.RegistryEntryDisabler.HASS, disabled_by=er.RegistryEntryDisabler.HASS,
entity_category=EntityCategory.CONFIG, entity_category=EntityCategory.CONFIG,
hidden_by=er.RegistryEntryHider.INTEGRATION,
original_device_class="mock-device-class", original_device_class="mock-device-class",
original_icon="hass:original-icon", original_icon="hass:original-icon",
original_name="Original Name", original_name="Original Name",
@ -231,6 +236,7 @@ async def test_loading_saving_data(hass, registry):
assert new_entry2.disabled_by is er.RegistryEntryDisabler.HASS assert new_entry2.disabled_by is er.RegistryEntryDisabler.HASS
assert new_entry2.entity_category == "config" assert new_entry2.entity_category == "config"
assert new_entry2.icon == "hass:user-icon" assert new_entry2.icon == "hass:user-icon"
assert new_entry2.hidden_by == er.RegistryEntryHider.INTEGRATION
assert new_entry2.name == "User Name" assert new_entry2.name == "User Name"
assert new_entry2.options == {"light": {"minimum_brightness": 20}} assert new_entry2.options == {"light": {"minimum_brightness": 20}}
assert new_entry2.original_device_class == "mock-device-class" assert new_entry2.original_device_class == "mock-device-class"
@ -261,8 +267,8 @@ def test_is_registered(registry):
@pytest.mark.parametrize("load_registries", [False]) @pytest.mark.parametrize("load_registries", [False])
async def test_loading_extra_values(hass, hass_storage): async def test_filter_on_load(hass, hass_storage):
"""Test we load extra data from the registry.""" """Test we transform some data when loading from storage."""
hass_storage[er.STORAGE_KEY] = { hass_storage[er.STORAGE_KEY] = {
"version": er.STORAGE_VERSION_MAJOR, "version": er.STORAGE_VERSION_MAJOR,
"minor_version": 1, "minor_version": 1,
@ -274,6 +280,7 @@ async def test_loading_extra_values(hass, hass_storage):
"unique_id": "with-name", "unique_id": "with-name",
"name": "registry override", "name": "registry override",
}, },
# This entity's name should be None
{ {
"entity_id": "test.no_name", "entity_id": "test.no_name",
"platform": "super_platform", "platform": "super_platform",
@ -283,20 +290,22 @@ async def test_loading_extra_values(hass, hass_storage):
"entity_id": "test.disabled_user", "entity_id": "test.disabled_user",
"platform": "super_platform", "platform": "super_platform",
"unique_id": "disabled-user", "unique_id": "disabled-user",
"disabled_by": er.RegistryEntryDisabler.USER, "disabled_by": "user", # We store the string representation
}, },
{ {
"entity_id": "test.disabled_hass", "entity_id": "test.disabled_hass",
"platform": "super_platform", "platform": "super_platform",
"unique_id": "disabled-hass", "unique_id": "disabled-hass",
"disabled_by": er.RegistryEntryDisabler.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", "entity_id": "test.invalid__entity",
"platform": "super_platform", "platform": "super_platform",
"unique_id": "invalid-hass", "unique_id": "invalid-hass",
"disabled_by": er.RegistryEntryDisabler.HASS, "disabled_by": "hass", # We store the string representation
}, },
# This entry should have the entity_category reset to None
{ {
"entity_id": "test.system_entity", "entity_id": "test.system_entity",
"platform": "super_platform", "platform": "super_platform",
@ -311,6 +320,13 @@ async def test_loading_extra_values(hass, hass_storage):
registry = er.async_get(hass) registry = er.async_get(hass)
assert len(registry.entities) == 5 assert len(registry.entities) == 5
assert set(registry.entities.keys()) == {
"test.disabled_hass",
"test.disabled_user",
"test.named",
"test.no_name",
"test.system_entity",
}
entry_with_name = registry.async_get_or_create( entry_with_name = registry.async_get_or_create(
"test", "super_platform", "with-name" "test", "super_platform", "with-name"
@ -1221,7 +1237,7 @@ def test_entity_registry_items():
async def test_disabled_by_str_not_allowed(hass): async def test_disabled_by_str_not_allowed(hass):
"""Test we need to pass entity category type.""" """Test we need to pass disabled by type."""
reg = er.async_get(hass) reg = er.async_get(hass)
with pytest.raises(ValueError): with pytest.raises(ValueError):
@ -1252,6 +1268,20 @@ async def test_entity_category_str_not_allowed(hass):
) )
async def test_hidden_by_str_not_allowed(hass):
"""Test we need to pass hidden by type."""
reg = er.async_get(hass)
with pytest.raises(ValueError):
reg.async_get_or_create(
"light", "hue", "1234", hidden_by=er.RegistryEntryHider.USER.value
)
entity_id = reg.async_get_or_create("light", "hue", "1234").entity_id
with pytest.raises(ValueError):
reg.async_update_entity(entity_id, hidden_by=er.RegistryEntryHider.USER.value)
def test_migrate_entity_to_new_platform(hass, registry): def test_migrate_entity_to_new_platform(hass, registry):
"""Test migrate_entity_to_new_platform.""" """Test migrate_entity_to_new_platform."""
orig_config_entry = MockConfigEntry(domain="light") orig_config_entry = MockConfigEntry(domain="light")