mirror of
https://github.com/home-assistant/core.git
synced 2026-04-18 23:49:03 +02:00
Compare commits
11 Commits
2026.2.2
...
gj-2025100
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6af30fb8f5 | ||
|
|
0ffb5fcfac | ||
|
|
a51fba80cc | ||
|
|
fe39037477 | ||
|
|
d860c13559 | ||
|
|
9f41cc0024 | ||
|
|
659846548b | ||
|
|
cdf781dc01 | ||
|
|
c78570558d | ||
|
|
b5d1becb3b | ||
|
|
0656642efb |
@@ -35,7 +35,7 @@ class ArveConfigFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||
except ArveConnectionError:
|
||||
errors["base"] = "cannot_connect"
|
||||
else:
|
||||
await self.async_set_unique_id(customer.customerId)
|
||||
await self.async_set_unique_id(str(customer.customerId))
|
||||
self._abort_if_unique_id_configured()
|
||||
return self.async_create_entry(
|
||||
title="Arve",
|
||||
|
||||
@@ -54,13 +54,9 @@ async def async_migrate_entry(hass: HomeAssistant, entry: LaundrifyConfigEntry)
|
||||
|
||||
_LOGGER.debug("Migrating from version %s", entry.version)
|
||||
|
||||
if entry.version == 1:
|
||||
# 1 -> 2: Unique ID from integer to string
|
||||
if entry.minor_version == 1:
|
||||
minor_version = 2
|
||||
hass.config_entries.async_update_entry(
|
||||
entry, unique_id=str(entry.unique_id), minor_version=minor_version
|
||||
)
|
||||
if entry.version == 1 and entry.minor_version == 1:
|
||||
# Migration of unique id was removed in #153369
|
||||
hass.config_entries.async_update_entry(entry, minor_version=2)
|
||||
|
||||
_LOGGER.debug("Migration successful")
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ class OAuth2FlowHandler(
|
||||
self.logger.exception("Unexpected error")
|
||||
return self.async_abort(reason="unknown")
|
||||
|
||||
await self.async_set_unique_id(current_user.id)
|
||||
await self.async_set_unique_id(str(current_user.id))
|
||||
if self.source != SOURCE_REAUTH:
|
||||
self._abort_if_unique_id_configured()
|
||||
return self.async_create_entry(
|
||||
|
||||
@@ -51,7 +51,7 @@ class MonzoFlowHandler(
|
||||
"""Create an entry for the flow."""
|
||||
self.oauth_data = data
|
||||
user_id = data[CONF_TOKEN]["user_id"]
|
||||
await self.async_set_unique_id(user_id)
|
||||
await self.async_set_unique_id(str(user_id))
|
||||
if self.source != SOURCE_REAUTH:
|
||||
self._abort_if_unique_id_configured()
|
||||
else:
|
||||
|
||||
@@ -93,13 +93,9 @@ async def async_migrate_entry(hass: HomeAssistant, entry: NexiaConfigEntry) -> b
|
||||
|
||||
_LOGGER.debug("Migrating from version %s", entry.version)
|
||||
|
||||
if entry.version == 1:
|
||||
# 1 -> 2: Unique ID from integer to string
|
||||
if entry.minor_version == 1:
|
||||
minor_version = 2
|
||||
hass.config_entries.async_update_entry(
|
||||
entry, unique_id=str(entry.unique_id), minor_version=minor_version
|
||||
)
|
||||
if entry.version == 1 and entry.minor_version == 1:
|
||||
# Migration of unique id was removed in #153369
|
||||
hass.config_entries.async_update_entry(entry, minor_version=2)
|
||||
|
||||
_LOGGER.debug("Migration successful")
|
||||
|
||||
|
||||
@@ -71,12 +71,9 @@ async def async_migrate_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
|
||||
_LOGGER.debug("Migrating from version %s", entry.version)
|
||||
|
||||
if entry.version == 1:
|
||||
if entry.minor_version == 1:
|
||||
minor_version = 2
|
||||
hass.config_entries.async_update_entry(
|
||||
entry, unique_id=str(entry.unique_id), minor_version=minor_version
|
||||
)
|
||||
if entry.version == 1 and entry.minor_version == 1:
|
||||
# Migration of unique id was removed in #153369
|
||||
hass.config_entries.async_update_entry(entry, minor_version=2)
|
||||
|
||||
_LOGGER.debug("Migration successful")
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ class ToonFlowHandler(AbstractOAuth2FlowHandler, domain=DOMAIN):
|
||||
if self.migrate_entry:
|
||||
await self.hass.config_entries.async_remove(self.migrate_entry)
|
||||
|
||||
await self.async_set_unique_id(agreement.agreement_id)
|
||||
await self.async_set_unique_id(str(agreement.agreement_id))
|
||||
self._abort_if_unique_id_configured()
|
||||
|
||||
self.data[CONF_AGREEMENT_ID] = agreement.agreement_id
|
||||
|
||||
@@ -74,13 +74,9 @@ async def async_migrate_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
|
||||
_LOGGER.debug("Migrating from version %s", entry.version)
|
||||
|
||||
if entry.version == 1:
|
||||
# 1 -> 2: Unique ID from integer to string
|
||||
if entry.minor_version == 1:
|
||||
minor_version = 2
|
||||
hass.config_entries.async_update_entry(
|
||||
entry, unique_id=str(entry.unique_id), minor_version=minor_version
|
||||
)
|
||||
if entry.version == 1 and entry.minor_version == 1:
|
||||
# Migration of unique id was removed in #153369
|
||||
hass.config_entries.async_update_entry(entry, minor_version=2)
|
||||
|
||||
_LOGGER.debug("Migration successful")
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
from homeassistant.helpers.httpx_client import create_async_httpx_client
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||
|
||||
@@ -132,23 +131,7 @@ async def async_migrate_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Migrate old entry."""
|
||||
# convert unique_id to string
|
||||
if entry.version == 1 and entry.minor_version == 1:
|
||||
if isinstance(entry.unique_id, int):
|
||||
hass.config_entries.async_update_entry(
|
||||
entry, unique_id=str(entry.unique_id)
|
||||
)
|
||||
device_registry = dr.async_get(hass)
|
||||
for device in dr.async_entries_for_config_entry(
|
||||
device_registry, entry.entry_id
|
||||
):
|
||||
new_identifiers = set()
|
||||
for identifier in device.identifiers:
|
||||
if identifier[0] == DOMAIN:
|
||||
new_identifiers.add((DOMAIN, str(identifier[1])))
|
||||
else:
|
||||
new_identifiers.add(identifier)
|
||||
device_registry.async_update_device(
|
||||
device.id, new_identifiers=new_identifiers
|
||||
)
|
||||
# Migration of unique id was removed in #153369
|
||||
hass.config_entries.async_update_entry(entry, minor_version=2)
|
||||
|
||||
return True
|
||||
|
||||
@@ -8,7 +8,6 @@ from collections.abc import (
|
||||
Callable,
|
||||
Coroutine,
|
||||
Generator,
|
||||
Hashable,
|
||||
Iterable,
|
||||
Mapping,
|
||||
ValuesView,
|
||||
@@ -1833,7 +1832,14 @@ class ConfigEntryItems(UserDict[str, ConfigEntry]):
|
||||
def __setitem__(self, entry_id: str, entry: ConfigEntry) -> None:
|
||||
"""Add an item."""
|
||||
data = self.data
|
||||
self.check_unique_id(entry)
|
||||
if not self.check_unique_id(entry):
|
||||
# If unique id not valid, don't save entry.
|
||||
_LOGGER.error(
|
||||
"The entry %s unique id %s is not a string and will not be added",
|
||||
entry.title,
|
||||
entry.unique_id,
|
||||
)
|
||||
return
|
||||
if entry_id in data:
|
||||
# This is likely a bug in a test that is adding the same entry twice.
|
||||
# In the future, once we have fixed the tests, this will raise HomeAssistantError.
|
||||
@@ -1842,45 +1848,27 @@ class ConfigEntryItems(UserDict[str, ConfigEntry]):
|
||||
data[entry_id] = entry
|
||||
self._index_entry(entry)
|
||||
|
||||
def check_unique_id(self, entry: ConfigEntry) -> None:
|
||||
"""Check config entry unique id.
|
||||
def check_unique_id(self, entry: ConfigEntry) -> bool:
|
||||
"""Check if config entry unique id is valid and log if not.
|
||||
|
||||
For a string unique id (this is the correct case): return
|
||||
For a hashable non string unique id: log warning
|
||||
For a non-hashable unique id: raise error
|
||||
Args:
|
||||
entry: Config entry.
|
||||
|
||||
Returns:
|
||||
True if the unique id is a string.
|
||||
"""
|
||||
if (unique_id := entry.unique_id) is None:
|
||||
return
|
||||
if isinstance(unique_id, str):
|
||||
# Unique id should be a string
|
||||
return
|
||||
if isinstance(unique_id, Hashable): # type: ignore[unreachable]
|
||||
# Checks for other non-string was added in HA Core 2024.10
|
||||
# In HA Core 2025.10, we should remove the error and instead fail
|
||||
report_issue = async_suggest_report_issue(
|
||||
self._hass, integration_domain=entry.domain
|
||||
)
|
||||
_LOGGER.error(
|
||||
(
|
||||
"Config entry '%s' from integration %s has an invalid unique_id"
|
||||
" '%s' of type %s when a string is expected, please %s"
|
||||
),
|
||||
entry.title,
|
||||
entry.domain,
|
||||
entry.unique_id,
|
||||
type(entry.unique_id).__name__,
|
||||
report_issue,
|
||||
)
|
||||
else:
|
||||
# Guard against integrations using unhashable unique_id
|
||||
# In HA Core 2024.11, the guard was changed from warning to failing
|
||||
raise HomeAssistantError(
|
||||
f"The entry unique id {unique_id} is not a string."
|
||||
)
|
||||
return True
|
||||
if not isinstance(unique_id, str):
|
||||
return False # type: ignore[unreachable]
|
||||
return True
|
||||
|
||||
def _index_entry(self, entry: ConfigEntry) -> None:
|
||||
"""Index an entry."""
|
||||
self.check_unique_id(entry)
|
||||
if not self.check_unique_id(entry):
|
||||
raise HomeAssistantError(
|
||||
f"Cannot update unique id to {entry.unique_id} as it's not a string value."
|
||||
)
|
||||
self._domain_index.setdefault(entry.domain, []).append(entry)
|
||||
if entry.unique_id is not None:
|
||||
self._domain_unique_id_index.setdefault(entry.domain, {}).setdefault(
|
||||
@@ -1913,7 +1901,10 @@ class ConfigEntryItems(UserDict[str, ConfigEntry]):
|
||||
"""
|
||||
entry_id = entry.entry_id
|
||||
self._unindex_entry(entry_id)
|
||||
self.check_unique_id(entry)
|
||||
if not self.check_unique_id(entry):
|
||||
raise HomeAssistantError(
|
||||
f"Cannot update unique id to {new_unique_id} as it's not a string value."
|
||||
)
|
||||
object.__setattr__(entry, "unique_id", new_unique_id)
|
||||
self._index_entry(entry)
|
||||
entry.clear_state_cache()
|
||||
@@ -1929,7 +1920,7 @@ class ConfigEntryItems(UserDict[str, ConfigEntry]):
|
||||
"""Get entry by domain and unique id."""
|
||||
if unique_id is None:
|
||||
return None # type: ignore[unreachable]
|
||||
if not isinstance(unique_id, Hashable):
|
||||
if not isinstance(unique_id, str):
|
||||
raise HomeAssistantError(
|
||||
f"The entry unique id {unique_id} is not a string."
|
||||
)
|
||||
|
||||
@@ -27,7 +27,10 @@ def mock_setup_entry() -> Generator[AsyncMock]:
|
||||
def mock_config_entry(hass: HomeAssistant, mock_arve: MagicMock) -> MockConfigEntry:
|
||||
"""Return the default mocked config entry."""
|
||||
return MockConfigEntry(
|
||||
title="Arve", domain=DOMAIN, data=USER_INPUT, unique_id=mock_arve.customer_id
|
||||
title="Arve",
|
||||
domain=DOMAIN,
|
||||
data=USER_INPUT,
|
||||
unique_id=str(mock_arve.customer_id),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ async def test_correct_flow(
|
||||
assert result2["type"] is FlowResultType.CREATE_ENTRY
|
||||
assert result2["data"] == USER_INPUT
|
||||
assert len(mock_setup_entry.mock_calls) == 1
|
||||
assert result2["result"].unique_id == 12345
|
||||
assert result2["result"].unique_id == "12345"
|
||||
|
||||
|
||||
async def test_form_cannot_connect(
|
||||
|
||||
@@ -516,8 +516,8 @@ async def test_camera_content_type(
|
||||
"framerate": 2,
|
||||
"verify_ssl": True,
|
||||
}
|
||||
await help_setup_mock_config_entry(hass, cam_config_jpg, unique_id=12345)
|
||||
await help_setup_mock_config_entry(hass, cam_config_svg, unique_id=54321)
|
||||
await help_setup_mock_config_entry(hass, cam_config_jpg, unique_id="12345")
|
||||
await help_setup_mock_config_entry(hass, cam_config_svg, unique_id="54321")
|
||||
|
||||
client = await hass_client()
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ async def laundrify_setup_config_entry(
|
||||
"""Create laundrify entry in Home Assistant."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
unique_id=VALID_ACCOUNT_ID,
|
||||
unique_id=str(VALID_ACCOUNT_ID),
|
||||
data={CONF_ACCESS_TOKEN: access_token},
|
||||
minor_version=2,
|
||||
)
|
||||
|
||||
@@ -65,7 +65,7 @@ async def test_migrate_entry_minor_version_1_2(hass: HomeAssistant) -> None:
|
||||
data={CONF_ACCESS_TOKEN: VALID_ACCESS_TOKEN},
|
||||
version=1,
|
||||
minor_version=1,
|
||||
unique_id=123456,
|
||||
unique_id="123456",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
|
||||
@@ -59,7 +59,7 @@ def mock_config_entry(expires_at: int, scopes: list[str]) -> MockConfigEntry:
|
||||
return MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
title=TITLE,
|
||||
unique_id=54321,
|
||||
unique_id="54321",
|
||||
data={
|
||||
"auth_implementation": DOMAIN,
|
||||
"token": {
|
||||
|
||||
@@ -74,7 +74,7 @@ async def test_full_flow(
|
||||
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||
assert result["title"] == "test@microbees.com"
|
||||
assert "result" in result
|
||||
assert result["result"].unique_id == 54321
|
||||
assert result["result"].unique_id == "54321"
|
||||
assert "token" in result["result"].data
|
||||
assert result["result"].data["token"]["access_token"] == "mock-access-token"
|
||||
assert result["result"].data["token"]["refresh_token"] == "mock-refresh-token"
|
||||
|
||||
@@ -62,7 +62,7 @@ async def test_migrate_entry_minor_version_1_2(hass: HomeAssistant) -> None:
|
||||
data={CONF_USERNAME: "mock", CONF_PASSWORD: "mock"},
|
||||
version=1,
|
||||
minor_version=1,
|
||||
unique_id=123456,
|
||||
unique_id="123456",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
|
||||
@@ -20,7 +20,6 @@ from .conftest import (
|
||||
HOST,
|
||||
MAC_ADDRESS_UNIQUE_ID,
|
||||
PASSWORD,
|
||||
SERIAL_NUMBER,
|
||||
SERIAL_RESPONSE,
|
||||
URL,
|
||||
WIFI_PARAMS_RESPONSE,
|
||||
@@ -190,13 +189,6 @@ async def test_multiple_config_entries(
|
||||
],
|
||||
CONFIG_ENTRY_DATA,
|
||||
),
|
||||
# Old unique id with serial, but same host
|
||||
(
|
||||
SERIAL_NUMBER,
|
||||
CONFIG_ENTRY_DATA,
|
||||
[mock_response(SERIAL_RESPONSE), mock_json_response(WIFI_PARAMS_RESPONSE)],
|
||||
CONFIG_ENTRY_DATA,
|
||||
),
|
||||
# Old unique id with no serial, but same host
|
||||
(
|
||||
None,
|
||||
@@ -220,7 +212,6 @@ async def test_multiple_config_entries(
|
||||
],
|
||||
ids=[
|
||||
"duplicate-mac-unique-id",
|
||||
"duplicate-host-legacy-serial-number",
|
||||
"duplicate-host-port-no-serial",
|
||||
"duplicate-duplicate-hostname",
|
||||
],
|
||||
|
||||
@@ -238,30 +238,6 @@ async def test_fix_unique_id_duplicate(
|
||||
"expected_device_identifier",
|
||||
),
|
||||
[
|
||||
(
|
||||
SERIAL_NUMBER,
|
||||
SERIAL_NUMBER,
|
||||
SERIAL_NUMBER,
|
||||
str(SERIAL_NUMBER),
|
||||
MAC_ADDRESS_UNIQUE_ID,
|
||||
MAC_ADDRESS_UNIQUE_ID,
|
||||
),
|
||||
(
|
||||
SERIAL_NUMBER,
|
||||
SERIAL_NUMBER,
|
||||
f"{SERIAL_NUMBER}-rain-delay",
|
||||
f"{SERIAL_NUMBER}-1",
|
||||
f"{MAC_ADDRESS_UNIQUE_ID}-rain-delay",
|
||||
f"{MAC_ADDRESS_UNIQUE_ID}-1",
|
||||
),
|
||||
(
|
||||
SERIAL_NUMBER,
|
||||
SERIAL_NUMBER,
|
||||
SERIAL_NUMBER,
|
||||
SERIAL_NUMBER,
|
||||
MAC_ADDRESS_UNIQUE_ID,
|
||||
MAC_ADDRESS_UNIQUE_ID,
|
||||
),
|
||||
("0", 0, "0", "0", MAC_ADDRESS_UNIQUE_ID, MAC_ADDRESS_UNIQUE_ID),
|
||||
(
|
||||
"0",
|
||||
@@ -289,9 +265,6 @@ async def test_fix_unique_id_duplicate(
|
||||
),
|
||||
],
|
||||
ids=(
|
||||
"serial-number",
|
||||
"serial-number-with-suffix",
|
||||
"serial-number-int",
|
||||
"zero-serial",
|
||||
"zero-serial-suffix",
|
||||
"new-format",
|
||||
|
||||
@@ -213,7 +213,7 @@ async def test_agreement_already_set_up(
|
||||
) -> None:
|
||||
"""Test showing display form again if display already exists."""
|
||||
await setup_component(hass)
|
||||
MockConfigEntry(domain=DOMAIN, unique_id=123).add_to_hass(hass)
|
||||
MockConfigEntry(domain=DOMAIN, unique_id="123").add_to_hass(hass)
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_USER}
|
||||
)
|
||||
@@ -312,7 +312,7 @@ async def test_import_migration(
|
||||
aioclient_mock: AiohttpClientMocker,
|
||||
) -> None:
|
||||
"""Test if importing step with migration works."""
|
||||
old_entry = MockConfigEntry(domain=DOMAIN, unique_id=123, version=1)
|
||||
old_entry = MockConfigEntry(domain=DOMAIN, unique_id="123", version=1)
|
||||
old_entry.add_to_hass(hass)
|
||||
|
||||
await setup_component(hass)
|
||||
|
||||
@@ -5,7 +5,7 @@ from __future__ import annotations
|
||||
import copy
|
||||
from datetime import timedelta
|
||||
from typing import Any
|
||||
from unittest.mock import AsyncMock, MagicMock, PropertyMock, patch
|
||||
from unittest.mock import AsyncMock, PropertyMock, patch
|
||||
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
from kasa import (
|
||||
@@ -85,7 +85,7 @@ async def test_configuring_tplink_causes_discovery(
|
||||
patch("homeassistant.components.tplink.Discover.discover_single"),
|
||||
patch("homeassistant.components.tplink.Device.connect"),
|
||||
):
|
||||
discover.return_value = {MagicMock(): MagicMock()}
|
||||
discover.return_value = {}
|
||||
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
|
||||
await hass.async_block_till_done(wait_background_tasks=True)
|
||||
# call_count will differ based on number of broadcast addresses
|
||||
|
||||
@@ -121,7 +121,7 @@ async def test_max_regions(hass: HomeAssistant) -> None:
|
||||
for i in range(5):
|
||||
MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
unique_id=i,
|
||||
unique_id=str(i),
|
||||
).add_to_hass(hass)
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
|
||||
@@ -16,7 +16,7 @@ async def test_migrate_entry_minor_version_1_2(hass: HomeAssistant) -> None:
|
||||
data={"protocol": "TCP", "address": "1.2.3.4", "file_path": "upb.upe"},
|
||||
version=1,
|
||||
minor_version=1,
|
||||
unique_id=123456,
|
||||
unique_id="123456",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
|
||||
@@ -4,7 +4,7 @@ from unittest.mock import patch
|
||||
|
||||
from httpx import RequestError
|
||||
|
||||
from homeassistant.components.wolflink.const import DEVICE_ID, DOMAIN, MANUFACTURER
|
||||
from homeassistant.components.wolflink.const import DEVICE_ID, DOMAIN
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
|
||||
@@ -18,27 +18,10 @@ async def test_unique_id_migration(
|
||||
) -> None:
|
||||
"""Test already configured while creating entry."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN, unique_id=CONFIG[DEVICE_ID], data=CONFIG
|
||||
domain=DOMAIN, unique_id=str(CONFIG[DEVICE_ID]), data=CONFIG
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
device_id = device_registry.async_get_or_create(
|
||||
config_entry_id=config_entry.entry_id,
|
||||
identifiers={(DOMAIN, CONFIG[DEVICE_ID])},
|
||||
configuration_url="https://www.wolf-smartset.com/",
|
||||
manufacturer=MANUFACTURER,
|
||||
).id
|
||||
|
||||
assert config_entry.version == 1
|
||||
assert config_entry.minor_version == 1
|
||||
assert config_entry.unique_id == 1234
|
||||
assert (
|
||||
hass.config_entries.async_entry_for_domain_unique_id(DOMAIN, 1234)
|
||||
is config_entry
|
||||
)
|
||||
assert hass.config_entries.async_entry_for_domain_unique_id(DOMAIN, "1234") is None
|
||||
assert device_registry.async_get(device_id).identifiers == {(DOMAIN, 1234)}
|
||||
|
||||
with (
|
||||
patch(
|
||||
"homeassistant.components.wolflink.fetch_parameters",
|
||||
@@ -54,6 +37,3 @@ async def test_unique_id_migration(
|
||||
hass.config_entries.async_entry_for_domain_unique_id(DOMAIN, "1234")
|
||||
is config_entry
|
||||
)
|
||||
assert hass.config_entries.async_entry_for_domain_unique_id(DOMAIN, 1234) is None
|
||||
|
||||
assert device_registry.async_get(device_id).identifiers == {(DOMAIN, "1234")}
|
||||
|
||||
@@ -2195,7 +2195,7 @@ async def test_addon_running_already_configured(
|
||||
"lr_s2_authenticated_key": "old321",
|
||||
},
|
||||
title=TITLE,
|
||||
unique_id=1234, # Unique ID is purposely set to int to test migration logic
|
||||
unique_id="1234",
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
|
||||
@@ -41,7 +41,7 @@ async def test_remove_stale_devices(
|
||||
"""Test removing devices with old-format ids."""
|
||||
|
||||
config_entry = MockConfigEntry(
|
||||
unique_id=uuid.uuid4(),
|
||||
unique_id=str(uuid.uuid4()),
|
||||
domain="zwave_me",
|
||||
data={CONF_TOKEN: "test_token", CONF_URL: "http://test_test"},
|
||||
)
|
||||
|
||||
@@ -7172,11 +7172,11 @@ async def test_reconfigure_subentry_create_subentry(hass: HomeAssistant) -> None
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize("unique_id", [["blah", "bleh"], {"key": "value"}])
|
||||
async def test_unhashable_unique_id_fails(
|
||||
@pytest.mark.parametrize("unique_id", [["blah", "bleh"], {"key": "value"}, 123, 2.3])
|
||||
async def test_non_string_unique_id_fails(
|
||||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture, unique_id: Any
|
||||
) -> None:
|
||||
"""Test the ConfigEntryItems user dict fails unhashable unique_id."""
|
||||
"""Test the ConfigEntryItems user dict fails non string unique_id."""
|
||||
entries = config_entries.ConfigEntryItems(hass)
|
||||
entry = config_entries.ConfigEntry(
|
||||
data={},
|
||||
@@ -7193,11 +7193,8 @@ async def test_unhashable_unique_id_fails(
|
||||
)
|
||||
|
||||
unique_id_string = re.escape(str(unique_id))
|
||||
with pytest.raises(
|
||||
HomeAssistantError,
|
||||
match=f"The entry unique id {unique_id_string} is not a string.",
|
||||
):
|
||||
entries[entry.entry_id] = entry
|
||||
entries[entry.entry_id] = entry
|
||||
assert f"The entry title unique id {unique_id} is not a string" in caplog.text
|
||||
|
||||
assert entry.entry_id not in entries
|
||||
|
||||
@@ -7208,11 +7205,11 @@ async def test_unhashable_unique_id_fails(
|
||||
entries.get_entry_by_domain_and_unique_id("test", unique_id)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("unique_id", [["blah", "bleh"], {"key": "value"}])
|
||||
async def test_unhashable_unique_id_fails_on_update(
|
||||
@pytest.mark.parametrize("unique_id", [["blah", "bleh"], {"key": "value"}, 123, 2.3])
|
||||
async def test_non_string_unique_id_fails_on_update(
|
||||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture, unique_id: Any
|
||||
) -> None:
|
||||
"""Test the ConfigEntryItems user dict fails non-hashable unique_id on update."""
|
||||
"""Test the ConfigEntryItems user dict fails non-string unique_id on update."""
|
||||
entries = config_entries.ConfigEntryItems(hass)
|
||||
entry = config_entries.ConfigEntry(
|
||||
data={},
|
||||
@@ -7234,7 +7231,7 @@ async def test_unhashable_unique_id_fails_on_update(
|
||||
unique_id_string = re.escape(str(unique_id))
|
||||
with pytest.raises(
|
||||
HomeAssistantError,
|
||||
match=f"The entry unique id {unique_id_string} is not a string.",
|
||||
match=f"Cannot update unique id to {unique_id_string} as it's not a string value.",
|
||||
):
|
||||
entries.update_unique_id(entry, unique_id)
|
||||
|
||||
@@ -7273,48 +7270,33 @@ async def test_string_unique_id_no_warning(
|
||||
assert entries.get_entry_by_domain_and_unique_id("test", "123") is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("unique_id", "type_name"),
|
||||
[
|
||||
(123, "int"),
|
||||
(2.3, "float"),
|
||||
],
|
||||
)
|
||||
async def test_hashable_unique_id(
|
||||
hass: HomeAssistant,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
unique_id: Any,
|
||||
type_name: str,
|
||||
async def test_loading_incorrect_unique_silently_ignored(
|
||||
hass: HomeAssistant, hass_storage: dict[str, Any], caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
"""Test the ConfigEntryItems user dict handles hashable non string unique_id."""
|
||||
entries = config_entries.ConfigEntryItems(hass)
|
||||
entry = config_entries.ConfigEntry(
|
||||
data={},
|
||||
discovery_keys={},
|
||||
domain="test",
|
||||
entry_id="mock_id",
|
||||
minor_version=1,
|
||||
options={},
|
||||
source="test",
|
||||
subentries_data=(),
|
||||
title="title",
|
||||
unique_id=unique_id,
|
||||
version=1,
|
||||
)
|
||||
"""Test entry with incorrect unique id silently is ignored."""
|
||||
hass_storage[config_entries.STORAGE_KEY] = {
|
||||
"version": 1,
|
||||
"data": {
|
||||
"entries": [
|
||||
{
|
||||
"version": 5,
|
||||
"domain": "my_domain",
|
||||
"entry_id": "mock-id",
|
||||
"data": {"my": "data"},
|
||||
"source": "user",
|
||||
"title": "Mock title",
|
||||
"unique_id": 123,
|
||||
"system_options": {"disable_new_entities": True},
|
||||
}
|
||||
]
|
||||
},
|
||||
}
|
||||
manager = config_entries.ConfigEntries(hass, {})
|
||||
await manager.async_initialize()
|
||||
|
||||
entries[entry.entry_id] = entry
|
||||
|
||||
assert (
|
||||
"Config entry 'title' from integration test has an invalid unique_id"
|
||||
f" '{unique_id}' of type {type_name} when a string is expected"
|
||||
) in caplog.text
|
||||
|
||||
assert entry.entry_id in entries
|
||||
assert entries[entry.entry_id] is entry
|
||||
assert entries.get_entry_by_domain_and_unique_id("test", unique_id) == entry
|
||||
del entries[entry.entry_id]
|
||||
assert not entries
|
||||
assert entries.get_entry_by_domain_and_unique_id("test", unique_id) is None
|
||||
entries = manager.async_entries()
|
||||
assert len(entries) == 0
|
||||
assert "The entry unique id 123 is not a string" not in caplog.text
|
||||
|
||||
|
||||
async def test_no_unique_id_no_warning(
|
||||
|
||||
Reference in New Issue
Block a user