Make config entry disabled_by an enum (#60445)

* Make config entry disabled_by an enum

* Update homeassistant/config_entries.py

Co-authored-by: Erik Montnemery <erik@montnemery.com>
This commit is contained in:
Ville Skyttä 2021-12-15 21:53:21 +02:00 committed by GitHub
parent aa83b0388a
commit 7db3246de4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 78 additions and 22 deletions

View file

@ -304,7 +304,8 @@ async def config_entry_update(hass, connection, msg):
"type": "config_entries/disable",
"entry_id": str,
# We only allow setting disabled_by user via API.
"disabled_by": vol.Any(config_entries.DISABLED_USER, None),
# No Enum support like this in voluptuous, use .value
"disabled_by": vol.Any(config_entries.ConfigEntryDisabler.USER.value, None),
}
)
async def config_entry_disable(hass, connection, msg):

View file

@ -13,6 +13,7 @@ from typing import TYPE_CHECKING, Any, Callable, Optional, cast
import weakref
from homeassistant import data_entry_flow, loader
from homeassistant.backports.enum import StrEnum
from homeassistant.const import EVENT_HOMEASSISTANT_STARTED, EVENT_HOMEASSISTANT_STOP
from homeassistant.core import CALLBACK_TYPE, CoreState, HomeAssistant, callback
from homeassistant.exceptions import (
@ -22,6 +23,7 @@ from homeassistant.exceptions import (
)
from homeassistant.helpers import device_registry, entity_registry
from homeassistant.helpers.event import Event
from homeassistant.helpers.frame import report
from homeassistant.helpers.typing import (
UNDEFINED,
ConfigType,
@ -128,7 +130,15 @@ RECONFIGURE_NOTIFICATION_ID = "config_entry_reconfigure"
EVENT_FLOW_DISCOVERED = "config_entry_discovered"
DISABLED_USER = "user"
class ConfigEntryDisabler(StrEnum):
"""What disabled a config entry."""
USER = "user"
# DISABLED_* is deprecated, to be removed in 2022.3
DISABLED_USER = ConfigEntryDisabler.USER.value
RELOAD_AFTER_UPDATE_DELAY = 30
@ -195,7 +205,7 @@ class ConfigEntry:
unique_id: str | None = None,
entry_id: str | None = None,
state: ConfigEntryState = ConfigEntryState.NOT_LOADED,
disabled_by: str | None = None,
disabled_by: ConfigEntryDisabler | None = None,
) -> None:
"""Initialize a config entry."""
# Unique id of the config entry
@ -237,6 +247,16 @@ class ConfigEntry:
self.unique_id = unique_id
# Config entry is disabled
if isinstance(disabled_by, str) and not isinstance(
disabled_by, ConfigEntryDisabler
):
report( # type: ignore[unreachable]
"uses str for config entry disabled_by. This is deprecated and will "
"stop working in Home Assistant 2022.3, it should be updated to use "
"ConfigEntryDisabler instead",
error_if_core=False,
)
disabled_by = ConfigEntryDisabler(disabled_by)
self.disabled_by = disabled_by
# Supports unload
@ -924,7 +944,9 @@ class ConfigEntries:
# New in 0.104
unique_id=entry.get("unique_id"),
# New in 2021.3
disabled_by=entry.get("disabled_by"),
disabled_by=ConfigEntryDisabler(entry["disabled_by"])
if entry.get("disabled_by")
else None,
# New in 2021.6
pref_disable_new_entities=pref_disable_new_entities,
pref_disable_polling=entry.get("pref_disable_polling"),
@ -985,7 +1007,7 @@ class ConfigEntries:
return await self.async_setup(entry_id)
async def async_set_disabled_by(
self, entry_id: str, disabled_by: str | None
self, entry_id: str, disabled_by: ConfigEntryDisabler | None
) -> bool:
"""Disable an entry.
@ -994,7 +1016,18 @@ class ConfigEntries:
if (entry := self.async_get_entry(entry_id)) is None:
raise UnknownEntry
if entry.disabled_by == disabled_by:
if isinstance(disabled_by, str) and not isinstance(
disabled_by, ConfigEntryDisabler
):
report( # type: ignore[unreachable]
"uses str for config entry disabled_by. This is deprecated and will "
"stop working in Home Assistant 2022.3, it should be updated to use "
"ConfigEntryDisabler instead",
error_if_core=False,
)
disabled_by = ConfigEntryDisabler(disabled_by)
if entry.disabled_by is disabled_by:
return True
entry.disabled_by = disabled_by

View file

@ -79,7 +79,7 @@ async def test_get_entries(hass, client):
domain="comp3",
title="Test 3",
source="bla3",
disabled_by=core_ce.DISABLED_USER,
disabled_by=core_ce.ConfigEntryDisabler.USER,
).add_to_hass(hass)
resp = await client.get("/api/config/config_entries/entry")
@ -121,7 +121,7 @@ async def test_get_entries(hass, client):
"supports_unload": False,
"pref_disable_new_entities": False,
"pref_disable_polling": False,
"disabled_by": core_ce.DISABLED_USER,
"disabled_by": core_ce.ConfigEntryDisabler.USER,
"reason": None,
},
]
@ -877,14 +877,14 @@ async def test_disable_entry(hass, hass_ws_client):
"id": 5,
"type": "config_entries/disable",
"entry_id": entry.entry_id,
"disabled_by": core_ce.DISABLED_USER,
"disabled_by": core_ce.ConfigEntryDisabler.USER,
}
)
response = await ws_client.receive_json()
assert response["success"]
assert response["result"] == {"require_restart": True}
assert entry.disabled_by == core_ce.DISABLED_USER
assert entry.disabled_by is core_ce.ConfigEntryDisabler.USER
assert entry.state is core_ce.ConfigEntryState.FAILED_UNLOAD
# Enable
@ -930,7 +930,7 @@ async def test_disable_entry_nonexisting(hass, hass_ws_client):
"id": 5,
"type": "config_entries/disable",
"entry_id": "non_existing",
"disabled_by": core_ce.DISABLED_USER,
"disabled_by": core_ce.ConfigEntryDisabler.USER,
}
)
response = await ws_client.receive_json()

View file

@ -10,7 +10,7 @@ from zwave_js_server.model.node import Node
from homeassistant.components.hassio.handler import HassioAPIError
from homeassistant.components.zwave_js.const import DOMAIN
from homeassistant.components.zwave_js.helpers import get_device_id
from homeassistant.config_entries import DISABLED_USER, ConfigEntryState
from homeassistant.config_entries import ConfigEntryDisabler, ConfigEntryState
from homeassistant.const import STATE_UNAVAILABLE
from homeassistant.helpers import device_registry as dr, entity_registry as er
@ -554,7 +554,9 @@ async def test_stop_addon(
assert entry.state is ConfigEntryState.LOADED
await hass.config_entries.async_set_disabled_by(entry.entry_id, DISABLED_USER)
await hass.config_entries.async_set_disabled_by(
entry.entry_id, ConfigEntryDisabler.USER
)
await hass.async_block_till_done()
assert entry.state == entry_state

View file

@ -1342,7 +1342,7 @@ async def test_disable_config_entry_disables_devices(hass, registry):
assert entry2.disabled
await hass.config_entries.async_set_disabled_by(
config_entry.entry_id, config_entries.DISABLED_USER
config_entry.entry_id, config_entries.ConfigEntryDisabler.USER
)
await hass.async_block_till_done()
@ -1382,7 +1382,7 @@ async def test_only_disable_device_if_all_config_entries_are_disabled(hass, regi
assert not entry1.disabled
await hass.config_entries.async_set_disabled_by(
config_entry1.entry_id, config_entries.DISABLED_USER
config_entry1.entry_id, config_entries.ConfigEntryDisabler.USER
)
await hass.async_block_till_done()
@ -1390,7 +1390,7 @@ async def test_only_disable_device_if_all_config_entries_are_disabled(hass, regi
assert not entry1.disabled
await hass.config_entries.async_set_disabled_by(
config_entry2.entry_id, config_entries.DISABLED_USER
config_entry2.entry_id, config_entries.ConfigEntryDisabler.USER
)
await hass.async_block_till_done()

View file

@ -919,7 +919,7 @@ async def test_disable_config_entry_disables_entities(hass, registry):
assert entry3.disabled
await hass.config_entries.async_set_disabled_by(
config_entry.entry_id, config_entries.DISABLED_USER
config_entry.entry_id, config_entries.ConfigEntryDisabler.USER
)
await hass.async_block_till_done()

View file

@ -529,7 +529,7 @@ async def test_domains_gets_domains_excludes_ignore_and_disabled(manager):
).add_to_manager(manager)
MockConfigEntry(domain="test3").add_to_manager(manager)
MockConfigEntry(
domain="disabled", disabled_by=config_entries.DISABLED_USER
domain="disabled", disabled_by=config_entries.ConfigEntryDisabler.USER
).add_to_manager(manager)
assert manager.async_domains() == ["test", "test2", "test3"]
assert manager.async_domains(include_ignore=False) == ["test", "test2", "test3"]
@ -1323,7 +1323,7 @@ async def test_entry_disable_succeed(hass, manager):
# Disable
assert await manager.async_set_disabled_by(
entry.entry_id, config_entries.DISABLED_USER
entry.entry_id, config_entries.ConfigEntryDisabler.USER
)
assert len(async_unload_entry.mock_calls) == 1
assert len(async_setup.mock_calls) == 0
@ -1358,7 +1358,7 @@ async def test_entry_disable_without_reload_support(hass, manager):
# Disable
assert not await manager.async_set_disabled_by(
entry.entry_id, config_entries.DISABLED_USER
entry.entry_id, config_entries.ConfigEntryDisabler.USER
)
assert len(async_setup.mock_calls) == 0
assert len(async_setup_entry.mock_calls) == 0
@ -1374,7 +1374,9 @@ async def test_entry_disable_without_reload_support(hass, manager):
async def test_entry_enable_without_reload_support(hass, manager):
"""Test that we can disable an entry without reload support."""
entry = MockConfigEntry(domain="comp", disabled_by=config_entries.DISABLED_USER)
entry = MockConfigEntry(
domain="comp", disabled_by=config_entries.ConfigEntryDisabler.USER
)
entry.add_to_hass(hass)
async_setup = AsyncMock(return_value=True)
@ -1398,7 +1400,7 @@ async def test_entry_enable_without_reload_support(hass, manager):
# Disable
assert not await manager.async_set_disabled_by(
entry.entry_id, config_entries.DISABLED_USER
entry.entry_id, config_entries.ConfigEntryDisabler.USER
)
assert len(async_setup.mock_calls) == 1
assert len(async_setup_entry.mock_calls) == 1
@ -2966,3 +2968,21 @@ async def test_loading_old_data(hass, hass_storage):
assert entry.title == "Mock title"
assert entry.data == {"my": "data"}
assert entry.pref_disable_new_entities is True
async def test_deprecated_disabled_by_str_ctor(hass, caplog):
"""Test deprecated str disabled_by constructor enumizes and logs a warning."""
entry = MockConfigEntry(disabled_by=config_entries.ConfigEntryDisabler.USER.value)
assert entry.disabled_by is config_entries.ConfigEntryDisabler.USER
assert " str for config entry disabled_by. This is deprecated " in caplog.text
async def test_deprecated_disabled_by_str_set(hass, manager, caplog):
"""Test deprecated str set disabled_by enumizes and logs a warning."""
entry = MockConfigEntry()
entry.add_to_manager(manager)
assert await manager.async_set_disabled_by(
entry.entry_id, config_entries.ConfigEntryDisabler.USER.value
)
assert entry.disabled_by is config_entries.ConfigEntryDisabler.USER
assert " str for config entry disabled_by. This is deprecated " in caplog.text