mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Enforce RegistryEntryHider in entity registry (#73219)
This commit is contained in:
parent
6bf219550e
commit
4435c641de
@ -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"],
|
||||||
|
@ -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",
|
||||||
|
@ -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."""
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user