Warn for old slugs/entity ids (#20478)
* Warn for old slugs/entity ids * add comments * Lint * LInt * Lint * Lintpull/20488/head
parent
38b1ce3fe0
commit
87316c4e83
|
@ -18,6 +18,7 @@ from homeassistant.util.logging import AsyncHandler
|
|||
from homeassistant.util.package import async_get_user_site, is_virtual_env
|
||||
from homeassistant.util.yaml import clear_secret_cache
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -153,6 +154,34 @@ async def async_from_config_dict(config: Dict[str, Any],
|
|||
stop = time()
|
||||
_LOGGER.info("Home Assistant initialized in %.2fs", stop-start)
|
||||
|
||||
# TEMP: warn users for invalid slugs
|
||||
# Remove after 0.94 or 1.0
|
||||
if cv.INVALID_SLUGS_FOUND or cv.INVALID_ENTITY_IDS_FOUND:
|
||||
msg = []
|
||||
|
||||
if cv.INVALID_ENTITY_IDS_FOUND:
|
||||
msg.append(
|
||||
"Your configuration contains invalid entity ID references. "
|
||||
"Please find and update the following. "
|
||||
"This will become a breaking change."
|
||||
)
|
||||
msg.append('\n'.join('- {} -> {}'.format(*item)
|
||||
for item
|
||||
in cv.INVALID_ENTITY_IDS_FOUND.items()))
|
||||
|
||||
if cv.INVALID_SLUGS_FOUND:
|
||||
msg.append(
|
||||
"Your configuration contains invalid slugs. "
|
||||
"Please find and update the following. "
|
||||
"This will become a breaking change."
|
||||
)
|
||||
msg.append('\n'.join('- {} -> {}'.format(*item)
|
||||
for item in cv.INVALID_SLUGS_FOUND.items()))
|
||||
|
||||
hass.components.persistent_notification.async_create(
|
||||
'\n\n'.join(msg), "Config Warning", "config_warning"
|
||||
)
|
||||
|
||||
return hass
|
||||
|
||||
|
||||
|
|
|
@ -26,6 +26,13 @@ from homeassistant.helpers import template as template_helper
|
|||
# pylint: disable=invalid-name
|
||||
|
||||
TIME_PERIOD_ERROR = "offset {} should be format 'HH:MM' or 'HH:MM:SS'"
|
||||
OLD_SLUG_VALIDATION = r'^[a-z0-9_]+$'
|
||||
OLD_ENTITY_ID_VALIDATION = r"^(\w+)\.(\w+)$"
|
||||
# Keep track of invalid slugs and entity ids found so we can create a
|
||||
# persistent notification. Rare temporary exception to use a global.
|
||||
INVALID_SLUGS_FOUND = {}
|
||||
INVALID_ENTITY_IDS_FOUND = {}
|
||||
|
||||
|
||||
# Home Assistant types
|
||||
byte = vol.All(vol.Coerce(int), vol.Range(min=0, max=255))
|
||||
|
@ -149,6 +156,18 @@ def entity_id(value: Any) -> str:
|
|||
value = string(value).lower()
|
||||
if valid_entity_id(value):
|
||||
return value
|
||||
elif re.match(OLD_ENTITY_ID_VALIDATION, value):
|
||||
# To ease the breaking change, we allow old slugs for now
|
||||
# Remove after 0.94 or 1.0
|
||||
fixed = '.'.join(util_slugify(part) for part in value.split('.', 1))
|
||||
INVALID_ENTITY_IDS_FOUND[value] = fixed
|
||||
logging.getLogger(__name__).warning(
|
||||
"Found invalid entity_id %s, please update with %s. This "
|
||||
"will become a breaking change.",
|
||||
value, fixed
|
||||
)
|
||||
return value
|
||||
|
||||
raise vol.Invalid('Entity ID {} is an invalid entity id'.format(value))
|
||||
|
||||
|
||||
|
@ -333,7 +352,22 @@ def schema_with_slug_keys(value_schema: Union[T, Callable]) -> Callable:
|
|||
raise vol.Invalid('expected dictionary')
|
||||
|
||||
for key in value.keys():
|
||||
slug(key)
|
||||
try:
|
||||
slug(key)
|
||||
except vol.Invalid:
|
||||
# To ease the breaking change, we allow old slugs for now
|
||||
# Remove after 0.94 or 1.0
|
||||
if re.match(OLD_SLUG_VALIDATION, key):
|
||||
fixed = util_slugify(key)
|
||||
INVALID_SLUGS_FOUND[key] = fixed
|
||||
logging.getLogger(__name__).warning(
|
||||
"Found invalid slug %s, please update with %s. This "
|
||||
"will be come a breaking change.",
|
||||
key, fixed
|
||||
)
|
||||
else:
|
||||
raise
|
||||
|
||||
return schema(value)
|
||||
return verify
|
||||
|
||||
|
|
|
@ -602,3 +602,31 @@ def test_comp_entity_ids():
|
|||
for invalid in (['light.kitchen', 'not-entity-id'], '*', ''):
|
||||
with pytest.raises(vol.Invalid):
|
||||
schema(invalid)
|
||||
|
||||
|
||||
def test_schema_with_slug_keys_allows_old_slugs(caplog):
|
||||
"""Test schema with slug keys allowing old slugs."""
|
||||
schema = cv.schema_with_slug_keys(str)
|
||||
|
||||
with patch.dict(cv.INVALID_SLUGS_FOUND, clear=True):
|
||||
for value in ('_world', 'wow__yeah'):
|
||||
caplog.clear()
|
||||
# Will raise if not allowing old slugs
|
||||
schema({value: 'yo'})
|
||||
assert "Found invalid slug {}".format(value) in caplog.text
|
||||
|
||||
assert len(cv.INVALID_SLUGS_FOUND) == 2
|
||||
|
||||
|
||||
def test_entity_id_allow_old_validation(caplog):
|
||||
"""Test schema allowing old entity_ids."""
|
||||
schema = vol.Schema(cv.entity_id)
|
||||
|
||||
with patch.dict(cv.INVALID_ENTITY_IDS_FOUND, clear=True):
|
||||
for value in ('hello.__world', 'great.wow__yeah'):
|
||||
caplog.clear()
|
||||
# Will raise if not allowing old entity ID
|
||||
schema(value)
|
||||
assert "Found invalid entity_id {}".format(value) in caplog.text
|
||||
|
||||
assert len(cv.INVALID_ENTITY_IDS_FOUND) == 2
|
||||
|
|
Loading…
Reference in New Issue