Config Validator: schema_with_slug_keys (#20298)

* schema_with_slug_keys

* Update config_validation.py

* Update config_validation.py
This commit is contained in:
Johann Kellerman 2019-01-22 02:36:04 +02:00 committed by Paulus Schoutsen
parent 4b3cdb9f4e
commit 6511e11ec9
38 changed files with 66 additions and 66 deletions

View file

@ -46,9 +46,7 @@ ALERT_SCHEMA = vol.Schema({
vol.Required(CONF_NOTIFIERS): cv.ensure_list}) vol.Required(CONF_NOTIFIERS): cv.ensure_list})
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({ DOMAIN: cv.schema_with_slug_keys(ALERT_SCHEMA),
cv.slug: ALERT_SCHEMA,
}),
}, extra=vol.ALLOW_EXTRA) }, extra=vol.ALLOW_EXTRA)

View file

@ -50,9 +50,7 @@ DEVICE_SCHEMA = vol.Schema({
}) })
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({ DOMAIN: cv.schema_with_slug_keys(DEVICE_SCHEMA),
cv.slug: DEVICE_SCHEMA,
}),
}, extra=vol.ALLOW_EXTRA) }, extra=vol.ALLOW_EXTRA)
SERVICE_VAPIX_CALL = 'vapix_call' SERVICE_VAPIX_CALL = 'vapix_call'

View file

@ -41,7 +41,7 @@ SENSOR_SCHEMA = vol.Schema({
}) })
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_SENSORS): vol.Schema({cv.slug: SENSOR_SCHEMA}), vol.Required(CONF_SENSORS): cv.schema_with_slug_keys(SENSOR_SCHEMA),
}) })

View file

@ -51,7 +51,7 @@ SENSOR_SCHEMA = vol.Schema({
}) })
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_SENSORS): vol.Schema({cv.slug: SENSOR_SCHEMA}), vol.Required(CONF_SENSORS): cv.schema_with_slug_keys(SENSOR_SCHEMA),
}) })

View file

@ -37,8 +37,8 @@ SERVICE_SCHEMA = vol.Schema({
}) })
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({ DOMAIN: cv.schema_with_slug_keys(
cv.slug: vol.Any({ vol.Any({
vol.Optional(CONF_ICON): cv.icon, vol.Optional(CONF_ICON): cv.icon,
vol.Optional(CONF_INITIAL, default=DEFAULT_INITIAL): vol.Optional(CONF_INITIAL, default=DEFAULT_INITIAL):
cv.positive_int, cv.positive_int,
@ -46,7 +46,7 @@ CONFIG_SCHEMA = vol.Schema({
vol.Optional(CONF_RESTORE, default=True): cv.boolean, vol.Optional(CONF_RESTORE, default=True): cv.boolean,
vol.Optional(CONF_STEP, default=DEFAULT_STEP): cv.positive_int, vol.Optional(CONF_STEP, default=DEFAULT_STEP): cv.positive_int,
}, None) }, None)
}) )
}, extra=vol.ALLOW_EXTRA) }, extra=vol.ALLOW_EXTRA)

View file

@ -27,7 +27,7 @@ COVER_SCHEMA = vol.Schema({
}) })
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_COVERS): vol.Schema({cv.slug: COVER_SCHEMA}), vol.Required(CONF_COVERS): cv.schema_with_slug_keys(COVER_SCHEMA),
}) })

View file

@ -47,7 +47,7 @@ COVER_SCHEMA = vol.Schema({
}) })
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_COVERS): vol.Schema({cv.slug: COVER_SCHEMA}), vol.Required(CONF_COVERS): cv.schema_with_slug_keys(COVER_SCHEMA),
}) })

View file

@ -46,7 +46,7 @@ COVER_SCHEMA = vol.Schema({
}) })
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_COVERS): vol.Schema({cv.slug: COVER_SCHEMA}), vol.Required(CONF_COVERS): cv.schema_with_slug_keys(COVER_SCHEMA),
}) })

View file

@ -18,7 +18,8 @@ _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['scsgate'] DEPENDENCIES = ['scsgate']
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_DEVICES): vol.Schema({cv.slug: scsgate.SCSGATE_SCHEMA}), vol.Required(CONF_DEVICES):
cv.schema_with_slug_keys(scsgate.SCSGATE_SCHEMA),
}) })

View file

@ -67,7 +67,7 @@ COVER_SCHEMA = vol.Schema({
}) })
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_COVERS): vol.Schema({cv.slug: COVER_SCHEMA}), vol.Required(CONF_COVERS): cv.schema_with_slug_keys(COVER_SCHEMA),
}) })

View file

@ -26,7 +26,7 @@ COVER_SCHEMA = vol.Schema({
}) })
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_COVERS): vol.Schema({cv.slug: COVER_SCHEMA}), vol.Required(CONF_COVERS): cv.schema_with_slug_keys(COVER_SCHEMA),
}) })
DEPENDENCIES = ['velbus'] DEPENDENCIES = ['velbus']

View file

@ -62,7 +62,7 @@ FAN_SCHEMA = vol.Schema({
}) })
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
vol.Required(CONF_FANS): vol.Schema({cv.slug: FAN_SCHEMA}), vol.Required(CONF_FANS): cv.schema_with_slug_keys(FAN_SCHEMA),
}) })

View file

@ -34,7 +34,7 @@ GRAPH_SCHEMA = vol.Schema({
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({cv.slug: GRAPH_SCHEMA}) DOMAIN: cv.schema_with_slug_keys(GRAPH_SCHEMA)
}, extra=vol.ALLOW_EXTRA) }, extra=vol.ALLOW_EXTRA)

View file

@ -30,13 +30,13 @@ SERVICE_SCHEMA = vol.Schema({
}) })
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({ DOMAIN: cv.schema_with_slug_keys(
cv.slug: vol.Any({ vol.Any({
vol.Optional(CONF_NAME): cv.string, vol.Optional(CONF_NAME): cv.string,
vol.Optional(CONF_INITIAL): cv.boolean, vol.Optional(CONF_INITIAL): cv.boolean,
vol.Optional(CONF_ICON): cv.icon, vol.Optional(CONF_ICON): cv.icon,
}, None) }, None)
}) )
}, extra=vol.ALLOW_EXTRA) }, extra=vol.ALLOW_EXTRA)

View file

@ -46,14 +46,15 @@ def has_date_or_time(conf):
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({ DOMAIN: cv.schema_with_slug_keys(
cv.slug: vol.All({ vol.All({
vol.Optional(CONF_NAME): cv.string, vol.Optional(CONF_NAME): cv.string,
vol.Optional(CONF_HAS_DATE, default=False): cv.boolean, vol.Optional(CONF_HAS_DATE, default=False): cv.boolean,
vol.Optional(CONF_HAS_TIME, default=False): cv.boolean, vol.Optional(CONF_HAS_TIME, default=False): cv.boolean,
vol.Optional(CONF_ICON): cv.icon, vol.Optional(CONF_ICON): cv.icon,
vol.Optional(CONF_INITIAL): cv.string, vol.Optional(CONF_INITIAL): cv.string,
}, has_date_or_time)}) }, has_date_or_time)
)
}, extra=vol.ALLOW_EXTRA) }, extra=vol.ALLOW_EXTRA)

View file

@ -63,8 +63,8 @@ def _cv_input_number(cfg):
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({ DOMAIN: cv.schema_with_slug_keys(
cv.slug: vol.All({ vol.All({
vol.Optional(CONF_NAME): cv.string, vol.Optional(CONF_NAME): cv.string,
vol.Required(CONF_MIN): vol.Coerce(float), vol.Required(CONF_MIN): vol.Coerce(float),
vol.Required(CONF_MAX): vol.Coerce(float), vol.Required(CONF_MAX): vol.Coerce(float),
@ -76,7 +76,7 @@ CONFIG_SCHEMA = vol.Schema({
vol.Optional(CONF_MODE, default=MODE_SLIDER): vol.Optional(CONF_MODE, default=MODE_SLIDER):
vol.In([MODE_BOX, MODE_SLIDER]), vol.In([MODE_BOX, MODE_SLIDER]),
}, _cv_input_number) }, _cv_input_number)
}) )
}, required=True, extra=vol.ALLOW_EXTRA) }, required=True, extra=vol.ALLOW_EXTRA)

View file

@ -64,14 +64,15 @@ def _cv_input_select(cfg):
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({ DOMAIN: cv.schema_with_slug_keys(
cv.slug: vol.All({ vol.All({
vol.Optional(CONF_NAME): cv.string, vol.Optional(CONF_NAME): cv.string,
vol.Required(CONF_OPTIONS): vol.Required(CONF_OPTIONS):
vol.All(cv.ensure_list, vol.Length(min=1), [cv.string]), vol.All(cv.ensure_list, vol.Length(min=1), [cv.string]),
vol.Optional(CONF_INITIAL): cv.string, vol.Optional(CONF_INITIAL): cv.string,
vol.Optional(CONF_ICON): cv.icon, vol.Optional(CONF_ICON): cv.icon,
}, _cv_input_select)}) }, _cv_input_select)
)
}, required=True, extra=vol.ALLOW_EXTRA) }, required=True, extra=vol.ALLOW_EXTRA)

View file

@ -55,8 +55,8 @@ def _cv_input_text(cfg):
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({ DOMAIN: cv.schema_with_slug_keys(
cv.slug: vol.All({ vol.All({
vol.Optional(CONF_NAME): cv.string, vol.Optional(CONF_NAME): cv.string,
vol.Optional(CONF_MIN, default=0): vol.Coerce(int), vol.Optional(CONF_MIN, default=0): vol.Coerce(int),
vol.Optional(CONF_MAX, default=100): vol.Coerce(int), vol.Optional(CONF_MAX, default=100): vol.Coerce(int),
@ -67,7 +67,7 @@ CONFIG_SCHEMA = vol.Schema({
vol.Optional(CONF_MODE, default=MODE_TEXT): vol.Optional(CONF_MODE, default=MODE_TEXT):
vol.In([MODE_TEXT, MODE_PASSWORD]), vol.In([MODE_TEXT, MODE_PASSWORD]),
}, _cv_input_text) }, _cv_input_text)
}) )
}, required=True, extra=vol.ALLOW_EXTRA) }, required=True, extra=vol.ALLOW_EXTRA)

View file

@ -19,7 +19,8 @@ _LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['scsgate'] DEPENDENCIES = ['scsgate']
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_DEVICES): vol.Schema({cv.slug: scsgate.SCSGATE_SCHEMA}), vol.Required(CONF_DEVICES):
cv.schema_with_slug_keys(scsgate.SCSGATE_SCHEMA),
}) })

View file

@ -44,7 +44,7 @@ LIGHT_SCHEMA = vol.Schema({
}) })
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_LIGHTS): vol.Schema({cv.slug: LIGHT_SCHEMA}), vol.Required(CONF_LIGHTS): cv.schema_with_slug_keys(LIGHT_SCHEMA),
}) })

View file

@ -47,8 +47,8 @@ CONF_SERVICE_DATA = 'service_data'
OFF_STATES = [STATE_IDLE, STATE_OFF, STATE_UNAVAILABLE] OFF_STATES = [STATE_IDLE, STATE_OFF, STATE_UNAVAILABLE]
ATTRS_SCHEMA = vol.Schema({cv.slug: cv.string}) ATTRS_SCHEMA = cv.schema_with_slug_keys(cv.string)
CMD_SCHEMA = vol.Schema({cv.slug: cv.SERVICE_SCHEMA}) CMD_SCHEMA = cv.schema_with_slug_keys(cv.SERVICE_SCHEMA)
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_NAME): cv.string, vol.Required(CONF_NAME): cv.string,

View file

@ -19,8 +19,8 @@ CONF_RELATIVE_URL_ERROR_MSG = "Invalid relative URL. Absolute path required."
CONF_RELATIVE_URL_REGEX = r'\A/' CONF_RELATIVE_URL_REGEX = r'\A/'
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({ DOMAIN: cv.schema_with_slug_keys(
cv.slug: { vol.Schema({
# pylint: disable=no-value-for-parameter # pylint: disable=no-value-for-parameter
vol.Optional(CONF_TITLE): cv.string, vol.Optional(CONF_TITLE): cv.string,
vol.Optional(CONF_ICON): cv.icon, vol.Optional(CONF_ICON): cv.icon,
@ -29,7 +29,9 @@ CONFIG_SCHEMA = vol.Schema({
CONF_RELATIVE_URL_REGEX, CONF_RELATIVE_URL_REGEX,
msg=CONF_RELATIVE_URL_ERROR_MSG), msg=CONF_RELATIVE_URL_ERROR_MSG),
vol.Url()), vol.Url()),
}})}, extra=vol.ALLOW_EXTRA) })
)
}, extra=vol.ALLOW_EXTRA)
async def async_setup(hass, config): async def async_setup(hass, config):

View file

@ -49,9 +49,7 @@ ZONE_SCHEMA = vol.Schema({
}) })
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({ DOMAIN: cv.schema_with_slug_keys(ZONE_SCHEMA),
cv.slug: ZONE_SCHEMA,
}),
}, extra=vol.ALLOW_EXTRA) }, extra=vol.ALLOW_EXTRA)

View file

@ -57,7 +57,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(ATTR_HIDDEN, default=True): cv.boolean, vol.Optional(ATTR_HIDDEN, default=True): cv.boolean,
vol.Required(CONF_TOKEN): vol.All(str, vol.Length(min=32, max=32)), vol.Required(CONF_TOKEN): vol.All(str, vol.Length(min=32, max=32)),
vol.Optional(CONF_COMMANDS, default={}): vol.Optional(CONF_COMMANDS, default={}):
vol.Schema({cv.slug: COMMAND_SCHEMA}), cv.schema_with_slug_keys(COMMAND_SCHEMA),
}, extra=vol.ALLOW_EXTRA) }, extra=vol.ALLOW_EXTRA)

View file

@ -49,9 +49,7 @@ COMMAND_SCHEMA = vol.Schema({
}) })
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({ DOMAIN: cv.schema_with_slug_keys(COMMAND_SCHEMA),
cv.slug: COMMAND_SCHEMA,
}),
}, extra=vol.ALLOW_EXTRA) }, extra=vol.ALLOW_EXTRA)

View file

@ -45,7 +45,7 @@ SENSOR_SCHEMA = vol.Schema({
}) })
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_SENSORS): vol.Schema({cv.slug: SENSOR_SCHEMA}), vol.Required(CONF_SENSORS): cv.schema_with_slug_keys(SENSOR_SCHEMA),
vol.Optional(CONF_BAUD, default=DEFAULT_BAUD): cv.string, vol.Optional(CONF_BAUD, default=DEFAULT_BAUD): cv.string,
vol.Optional(CONF_DATARATE): cv.positive_int, vol.Optional(CONF_DATARATE): cv.positive_int,
vol.Optional(CONF_DEVICE, default=DEFAULT_DEVICE): cv.string, vol.Optional(CONF_DEVICE, default=DEFAULT_DEVICE): cv.string,

View file

@ -68,9 +68,9 @@ PLATFORM_SCHEMA = vol.All(PLATFORM_SCHEMA.extend({
vol.Required(CONF_PASSWORD): cv.string, vol.Required(CONF_PASSWORD): cv.string,
vol.Optional(CONF_GROUP, default=GROUPS[0]): vol.In(GROUPS), vol.Optional(CONF_GROUP, default=GROUPS[0]): vol.In(GROUPS),
vol.Optional(CONF_SENSORS, default={}): vol.Optional(CONF_SENSORS, default={}):
vol.Schema({cv.slug: cv.ensure_list}), cv.schema_with_slug_keys(cv.ensure_list),
vol.Optional(CONF_CUSTOM, default={}): vol.Optional(CONF_CUSTOM, default={}):
vol.Schema({cv.slug: CUSTOM_SCHEMA}), cv.schema_with_slug_keys(CUSTOM_SCHEMA),
}, extra=vol.PREVENT_EXTRA), _check_sensor_schema) }, extra=vol.PREVENT_EXTRA), _check_sensor_schema)

View file

@ -36,7 +36,7 @@ SENSOR_SCHEMA = vol.Schema({
}) })
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_SENSORS): vol.Schema({cv.slug: SENSOR_SCHEMA}), vol.Required(CONF_SENSORS): cv.schema_with_slug_keys(SENSOR_SCHEMA),
}) })

View file

@ -21,9 +21,7 @@ DOMAIN = 'shell_command'
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({ DOMAIN: cv.schema_with_slug_keys(cv.string),
cv.slug: cv.string,
}),
}, extra=vol.ALLOW_EXTRA) }, extra=vol.ALLOW_EXTRA)

View file

@ -59,7 +59,7 @@ MP1_SWITCH_SLOT_SCHEMA = vol.Schema({
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_SWITCHES, default={}): vol.Optional(CONF_SWITCHES, default={}):
vol.Schema({cv.slug: SWITCH_SCHEMA}), cv.schema_with_slug_keys(SWITCH_SCHEMA),
vol.Optional(CONF_SLOTS, default={}): MP1_SWITCH_SLOT_SCHEMA, vol.Optional(CONF_SLOTS, default={}): MP1_SWITCH_SLOT_SCHEMA,
vol.Required(CONF_HOST): cv.string, vol.Required(CONF_HOST): cv.string,
vol.Required(CONF_MAC): cv.string, vol.Required(CONF_MAC): cv.string,

View file

@ -28,7 +28,7 @@ SWITCH_SCHEMA = vol.Schema({
}) })
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_SWITCHES): vol.Schema({cv.slug: SWITCH_SCHEMA}), vol.Required(CONF_SWITCHES): cv.schema_with_slug_keys(SWITCH_SCHEMA),
}) })

View file

@ -30,7 +30,7 @@ SWITCH_SCHEMA = vol.Schema({
}) })
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_SWITCHES): vol.Schema({cv.slug: SWITCH_SCHEMA}), vol.Required(CONF_SWITCHES): cv.schema_with_slug_keys(SWITCH_SCHEMA),
}) })

View file

@ -24,7 +24,8 @@ CONF_SCENARIO = 'scenario'
CONF_SCS_ID = 'scs_id' CONF_SCS_ID = 'scs_id'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_DEVICES): vol.Schema({cv.slug: scsgate.SCSGATE_SCHEMA}), vol.Required(CONF_DEVICES):
cv.schema_with_slug_keys(scsgate.SCSGATE_SCHEMA),
}) })

View file

@ -32,7 +32,7 @@ SWITCH_SCHEMA = vol.Schema({
}) })
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_SWITCHES): vol.Schema({cv.slug: SWITCH_SCHEMA}), vol.Required(CONF_SWITCHES): cv.schema_with_slug_keys(SWITCH_SCHEMA),
}) })
SCAN_INTERVAL = timedelta(seconds=10) SCAN_INTERVAL = timedelta(seconds=10)

View file

@ -38,7 +38,7 @@ SWITCH_SCHEMA = vol.Schema({
}) })
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_SWITCHES): vol.Schema({cv.slug: SWITCH_SCHEMA}), vol.Required(CONF_SWITCHES): cv.schema_with_slug_keys(SWITCH_SCHEMA),
}) })

View file

@ -53,14 +53,14 @@ SERVICE_SCHEMA_DURATION = vol.Schema({
}) })
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({ DOMAIN: cv.schema_with_slug_keys(
cv.slug: vol.Any({ vol.Any({
vol.Optional(CONF_NAME): cv.string, vol.Optional(CONF_NAME): cv.string,
vol.Optional(CONF_ICON): cv.icon, vol.Optional(CONF_ICON): cv.icon,
vol.Optional(CONF_DURATION, timedelta(DEFAULT_DURATION)): vol.Optional(CONF_DURATION, timedelta(DEFAULT_DURATION)):
cv.time_period, cv.time_period,
}, None) }, None)
}) )
}, extra=vol.ALLOW_EXTRA) }, extra=vol.ALLOW_EXTRA)

View file

@ -93,8 +93,8 @@ CONFIG_SCHEMA = vol.Schema({
vol.Required(CONF_PASSWORD): cv.string, vol.Required(CONF_PASSWORD): cv.string,
vol.Optional(CONF_UPDATE_INTERVAL, default=DEFAULT_UPDATE_INTERVAL): ( vol.Optional(CONF_UPDATE_INTERVAL, default=DEFAULT_UPDATE_INTERVAL): (
vol.All(cv.time_period, vol.Clamp(min=MIN_UPDATE_INTERVAL))), vol.All(cv.time_period, vol.Clamp(min=MIN_UPDATE_INTERVAL))),
vol.Optional(CONF_NAME, default={}): vol.Schema( vol.Optional(CONF_NAME, default={}):
{cv.slug: cv.string}), cv.schema_with_slug_keys(cv.string),
vol.Optional(CONF_RESOURCES): vol.All( vol.Optional(CONF_RESOURCES): vol.All(
cv.ensure_list, [vol.In(RESOURCES)]), cv.ensure_list, [vol.In(RESOURCES)]),
vol.Optional(CONF_REGION): cv.string, vol.Optional(CONF_REGION): cv.string,

View file

@ -329,6 +329,9 @@ def schema_with_slug_keys(value_schema: Union[T, Callable]) -> Callable:
def verify(value: Dict) -> Dict: def verify(value: Dict) -> Dict:
"""Validate all keys are slugs and then the value_schema.""" """Validate all keys are slugs and then the value_schema."""
if not isinstance(value, dict):
raise vol.Invalid('expected dictionary')
for key in value.keys(): for key in value.keys():
slug(key) slug(key)
return schema(value) return schema(value)