commit
c78d3b6154
5 changed files with 94 additions and 2 deletions
|
@ -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.package import async_get_user_site, is_virtual_env
|
||||||
from homeassistant.util.yaml import clear_secret_cache
|
from homeassistant.util.yaml import clear_secret_cache
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
|
from homeassistant.helpers import config_validation as cv
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -153,6 +154,34 @@ async def async_from_config_dict(config: Dict[str, Any],
|
||||||
stop = time()
|
stop = time()
|
||||||
_LOGGER.info("Home Assistant initialized in %.2fs", stop-start)
|
_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
|
return hass
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -228,6 +228,7 @@ class HueLight(Light):
|
||||||
self.is_philips = light.manufacturername == 'Philips'
|
self.is_philips = light.manufacturername == 'Philips'
|
||||||
self.gamut_typ = self.light.colorgamuttype
|
self.gamut_typ = self.light.colorgamuttype
|
||||||
self.gamut = self.light.colorgamut
|
self.gamut = self.light.colorgamut
|
||||||
|
_LOGGER.debug("Color gamut of %s: %s", self.name, str(self.gamut))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def unique_id(self):
|
def unique_id(self):
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"""Constants used by Home Assistant components."""
|
"""Constants used by Home Assistant components."""
|
||||||
MAJOR_VERSION = 0
|
MAJOR_VERSION = 0
|
||||||
MINOR_VERSION = 86
|
MINOR_VERSION = 86
|
||||||
PATCH_VERSION = '2'
|
PATCH_VERSION = '3'
|
||||||
__short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION)
|
__short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION)
|
||||||
__version__ = '{}.{}'.format(__short_version__, PATCH_VERSION)
|
__version__ = '{}.{}'.format(__short_version__, PATCH_VERSION)
|
||||||
REQUIRED_PYTHON_VER = (3, 5, 3)
|
REQUIRED_PYTHON_VER = (3, 5, 3)
|
||||||
|
|
|
@ -26,6 +26,13 @@ from homeassistant.helpers import template as template_helper
|
||||||
# pylint: disable=invalid-name
|
# pylint: disable=invalid-name
|
||||||
|
|
||||||
TIME_PERIOD_ERROR = "offset {} should be format 'HH:MM' or 'HH:MM:SS'"
|
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
|
# Home Assistant types
|
||||||
byte = vol.All(vol.Coerce(int), vol.Range(min=0, max=255))
|
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()
|
value = string(value).lower()
|
||||||
if valid_entity_id(value):
|
if valid_entity_id(value):
|
||||||
return 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))
|
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')
|
raise vol.Invalid('expected dictionary')
|
||||||
|
|
||||||
for key in value.keys():
|
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 schema(value)
|
||||||
return verify
|
return verify
|
||||||
|
|
||||||
|
|
|
@ -602,3 +602,31 @@ def test_comp_entity_ids():
|
||||||
for invalid in (['light.kitchen', 'not-entity-id'], '*', ''):
|
for invalid in (['light.kitchen', 'not-entity-id'], '*', ''):
|
||||||
with pytest.raises(vol.Invalid):
|
with pytest.raises(vol.Invalid):
|
||||||
schema(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…
Add table
Reference in a new issue