Migrate bracketed IP addresses in ZHA config entry (#95917)

* Automatically correct IP addresses surrounded by brackets

* Simplify regex

* Move pattern inline

* Maintain old behavior of stripping whitespace
This commit is contained in:
puddly 2023-07-06 11:47:51 -04:00 committed by GitHub
parent 59645344e7
commit ecc0917e8f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 6 deletions

View File

@ -3,6 +3,7 @@ import asyncio
import copy import copy
import logging import logging
import os import os
import re
import voluptuous as vol import voluptuous as vol
from zhaquirks import setup as setup_quirks from zhaquirks import setup as setup_quirks
@ -85,19 +86,34 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
return True return True
def _clean_serial_port_path(path: str) -> str:
"""Clean the serial port path, applying corrections where necessary."""
if path.startswith("socket://"):
path = path.strip()
# Removes extraneous brackets from IP addresses (they don't parse in CPython 3.11.4)
if re.match(r"^socket://\[\d+\.\d+\.\d+\.\d+\]:\d+$", path):
path = path.replace("[", "").replace("]", "")
return path
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool: async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
"""Set up ZHA. """Set up ZHA.
Will automatically load components to support devices found on the network. Will automatically load components to support devices found on the network.
""" """
# Strip whitespace around `socket://` URIs, this is no longer accepted by zigpy # Remove brackets around IP addresses, this no longer works in CPython 3.11.4
# This will be removed in 2023.7.0 # This will be removed in 2023.11.0
path = config_entry.data[CONF_DEVICE][CONF_DEVICE_PATH] path = config_entry.data[CONF_DEVICE][CONF_DEVICE_PATH]
cleaned_path = _clean_serial_port_path(path)
data = copy.deepcopy(dict(config_entry.data)) data = copy.deepcopy(dict(config_entry.data))
if path.startswith("socket://") and path != path.strip(): if path != cleaned_path:
data[CONF_DEVICE][CONF_DEVICE_PATH] = path.strip() _LOGGER.debug("Cleaned serial port path %r -> %r", path, cleaned_path)
data[CONF_DEVICE][CONF_DEVICE_PATH] = cleaned_path
hass.config_entries.async_update_entry(config_entry, data=data) hass.config_entries.async_update_entry(config_entry, data=data)
zha_data = hass.data.setdefault(DATA_ZHA, {}) zha_data = hass.data.setdefault(DATA_ZHA, {})

View File

@ -114,19 +114,27 @@ async def test_config_depreciation(hass: HomeAssistant, zha_config) -> None:
@pytest.mark.parametrize( @pytest.mark.parametrize(
("path", "cleaned_path"), ("path", "cleaned_path"),
[ [
# No corrections
("/dev/path1", "/dev/path1"), ("/dev/path1", "/dev/path1"),
("/dev/path1[asd]", "/dev/path1[asd]"),
("/dev/path1 ", "/dev/path1 "), ("/dev/path1 ", "/dev/path1 "),
("socket://1.2.3.4:5678", "socket://1.2.3.4:5678"),
# Brackets around URI
("socket://[1.2.3.4]:5678", "socket://1.2.3.4:5678"),
# Spaces
("socket://dev/path1 ", "socket://dev/path1"), ("socket://dev/path1 ", "socket://dev/path1"),
# Both
("socket://[1.2.3.4]:5678 ", "socket://1.2.3.4:5678"),
], ],
) )
@patch("homeassistant.components.zha.setup_quirks", Mock(return_value=True)) @patch("homeassistant.components.zha.setup_quirks", Mock(return_value=True))
@patch( @patch(
"homeassistant.components.zha.websocket_api.async_load_api", Mock(return_value=True) "homeassistant.components.zha.websocket_api.async_load_api", Mock(return_value=True)
) )
async def test_setup_with_v3_spaces_in_uri( async def test_setup_with_v3_cleaning_uri(
hass: HomeAssistant, path: str, cleaned_path: str hass: HomeAssistant, path: str, cleaned_path: str
) -> None: ) -> None:
"""Test migration of config entry from v3 with spaces after `socket://` URI.""" """Test migration of config entry from v3, applying corrections to the port path."""
config_entry_v3 = MockConfigEntry( config_entry_v3 = MockConfigEntry(
domain=DOMAIN, domain=DOMAIN,
data={ data={