def validate_configuration(configuration): """Get the schema for validating the configuration.""" valid_gpio_pin = ValidateGPIOPin() valid_numeric_position = ValidateNumericPosition() config = vol.Schema( { vol.Required(CONF_API): vol.Or(MQTT_CONFIGURATION_SCHEMA, HASS_CONFIGURATION_SCHEMA, NULL_CONFIGURATION_SCHEMA), vol.Inclusive(CONF_OPEN_GARAGE_PIN, 'control'): valid_gpio_pin, vol.Inclusive(CONF_CLOSE_GARAGE_PIN, 'control'): valid_gpio_pin, vol.Optional(CONF_TOGGLE_GARAGE_PIN): valid_gpio_pin, vol.Optional(CONF_INVERT_RELAY, default=False): vol.Coerce(bool), vol.Required(CONF_POSITIONS): keys_with_schema(valid_numeric_position, VALID_GPIO_PINS), vol.Required(CONF_ENTITY_ID): entity_id }, extra=vol.ALLOW_EXTRA)(configuration) if not config.get(CONF_OPEN_GARAGE_PIN) and not config.get( CONF_TOGGLE_GARAGE_PIN): raise vol.MultipleInvalid('({} and {}) or {}'.format( CONF_OPEN_GARAGE_PIN, CONF_CLOSE_GARAGE_PIN, CONF_TOGGLE_GARAGE_PIN)) return config
def validator(value): is_list = isinstance(value, list) if not is_list: value = [value] names = set() ret = [] errors = [] for i, effect in enumerate(value): path = [i] if is_list else [] if not isinstance(effect, dict): errors.append( vol.Invalid( "Each effect must be a dictionary, not {}".format( type(value)), path)) continue if len(effect) > 1: errors.append( vol.Invalid( "Each entry in the 'effects:' option must be a single effect.", path)) continue if not effect: errors.append( vol.Invalid( "Found no effect for the {}th entry in 'effects:'!". format(i), path)) continue key = next(iter(effect.keys())) if key.startswith('fastled'): errors.append( vol.Invalid( "FastLED effects have been renamed to addressable effects. " "Please use '{}'".format( key.replace('fastled', 'addressable')), path)) continue if key not in allowed_effects: errors.append( vol.Invalid( "The effect '{}' does not exist or is not allowed for this " "light type".format(key), path)) continue effect[key] = effect[key] or {} try: conf = EFFECTS_SCHEMA(effect) except vol.Invalid as err: err.prepend(path) errors.append(err) continue name = conf[key][CONF_NAME] if name in names: errors.append( vol.Invalid( u"Found the effect name '{}' twice. All effects must have " u"unique names".format(name), [i])) continue names.add(name) ret.append(conf) if errors: raise vol.MultipleInvalid(errors) return ret
def valid_preset_mode_configuration(config): """Validate that the preset mode reset payload is not one of the preset modes.""" if PRESET_NONE in config.get(CONF_PRESET_MODES_LIST): raise ValueError("preset_modes must not include preset mode 'none'") if config.get(CONF_PRESET_MODE_COMMAND_TOPIC): for config_parameter in DEPRECATED_INVALID: if config.get(config_parameter): raise vol.MultipleInvalid( "preset_modes cannot be used with deprecated away or hold mode config options" ) return config
def indications_validator(indications: Any): if isinstance(indications, Mapping): temp_indications = {**indications} dict_indications = {} for key in indications.keys(): key_str = str(key) match = RE_INDICATIONS_KEY.search(key_str) if match: value = cv.positive_float(indications[key]) idx = cv.positive_int(match.group(3)) if idx in dict_indications and dict_indications[idx] != value: raise vol.Invalid( 'altering indication value for same index: %s' % (idx, ), path=[key_str]) dict_indications[idx] = value del temp_indications[key] if temp_indications: errors = [ vol.Invalid('extra keys not allowed', path=[key]) for key in temp_indications.keys() ] if len(errors) == 1: raise errors[0] raise vol.MultipleInvalid(errors) list_indications = [] for key in sorted(dict_indications.keys()): if len(list_indications) < key - 1: raise vol.Invalid('missing indication index: %d' % (key - 1, )) list_indications.append(dict_indications[key]) else: try: indications = map(str.strip, cv.string(indications).split(',')) except (vol.Invalid, vol.MultipleInvalid): indications = cv.ensure_list(indications) list_indications = list(map(cv.positive_float, indications)) if len(list_indications) < 1: raise vol.Invalid('empty set of indications provided') return list_indications
def _unique_username_validator( configs: List[Mapping[str, Any]]) -> List[Mapping[str, Any]]: existing_usernames = set() exceptions = [] for i, config in enumerate(configs): if config[CONF_USERNAME] in existing_usernames: exceptions.append( vol.Invalid('duplicate username entry detected', [i])) else: existing_usernames.add(config[CONF_USERNAME]) if len(exceptions) > 1: raise vol.MultipleInvalid(exceptions) elif len(exceptions) == 1: raise exceptions[0] return configs
def validator_(value): if isinstance(value, list): try: # First try as a sequence of actions return [schema({CONF_THEN: value})] except vol.Invalid as err: # Next try as a sequence of automations try: return vol.Schema([schema])(value) except vol.Invalid as err2: raise vol.MultipleInvalid([err, err2]) elif isinstance(value, dict): if CONF_THEN in value: return [schema(value)] return [schema({CONF_THEN: value})] # This should only happen with invalid configs, but let's have a nice error message. return [schema(value)]
def validate_event_data(obj: dict) -> dict: """Validate that a trigger has a valid event data.""" # Return if there's no event data to validate if ATTR_EVENT_DATA not in obj: return obj event_source = obj[ATTR_EVENT_SOURCE] event_name = obj[ATTR_EVENT] event_data = obj[ATTR_EVENT_DATA] try: EVENT_MODEL_MAP[event_source][event_name](**event_data) except ValidationError as exc: # Filter out required field errors if keys can be missing, and if there are # still errors, raise an exception if errors := [ error for error in exc.errors() if error["type"] != "value_error.missing" ]: raise vol.MultipleInvalid(errors) from exc
def validator_(value): if isinstance(value, list): try: # First try as a sequence of actions return [schema({CONF_THEN: value})] except vol.Invalid as err: if err.path and err.path[0] == CONF_THEN: err.path.pop(0) # Next try as a sequence of automations try: return cv.Schema([schema])(value) except vol.Invalid as err2: if 'Unable to find action' in str(err): raise err2 raise vol.MultipleInvalid([err, err2]) elif isinstance(value, dict): if CONF_THEN in value: return [schema(value)] return [schema({CONF_THEN: value})] # This should only happen with invalid configs, but let's have a nice error message. return [schema(value)]
def ensure_multiple_invalid(err): if isinstance(err, vol.MultipleInvalid): return err return vol.MultipleInvalid(err)
def validate_mapping(path, iterable, out): required_keys = all_required_keys.copy() # Build a map of all provided key-value pairs. # The type(out) is used to retain ordering in case a ordered # map type is provided as input. key_value_map = type(out)() for key, value in iterable: key_value_map[key] = value # Insert default values for non-existing keys. for key in all_default_keys: if ( not isinstance(key.default, vol.Undefined) and key.schema not in key_value_map ): # A default value has been specified for this missing key, insert it. key_value_map[key.schema] = key.default() error = None errors = [] for key, value in key_value_map.items(): key_path = path + [key] # Optimization. Validate against the matching key first, then fallback to the rest relevant_candidates = itertools.chain( candidates_by_key.get(key, []), additional_candidates ) # compare each given key/value against all compiled key/values # schema key, (compiled key, compiled value) for skey, (ckey, cvalue) in relevant_candidates: try: new_key = ckey(key_path, key) except vol.Invalid as e: if len(e.path) > len(key_path): raise if not error or len(e.path) > len(error.path): error = e continue # Backtracking is not performed once a key is selected, so if # the value is invalid we immediately throw an exception. exception_errors = [] try: cval = cvalue(key_path, value) out[new_key] = cval except vol.MultipleInvalid as e: exception_errors.extend(e.errors) except vol.Invalid as e: exception_errors.append(e) if exception_errors: for err in exception_errors: if len(err.path) <= len(key_path): err.error_type = invalid_msg errors.append(err) # If there is a validation error for a required # key, this means that the key was provided. # Discard the required key so it does not # create an additional, noisy exception. required_keys.discard(skey) break # Key and value okay, mark as found in case it was # a Required() field. required_keys.discard(skey) break else: if self.extra == vol.ALLOW_EXTRA: out[key] = value elif self.extra != vol.REMOVE_EXTRA: if isinstance(key, str) and key_names: matches = difflib.get_close_matches(key, key_names) errors.append( ExtraKeysInvalid( "extra keys not allowed", key_path, candidates=matches, ) ) else: errors.append( vol.Invalid("extra keys not allowed", key_path) ) # for any required keys left that weren't found and don't have defaults: for key in required_keys: msg = getattr(key, "msg", None) or "required key not provided" errors.append(vol.RequiredFieldInvalid(msg, path + [key])) if errors: raise vol.MultipleInvalid(errors) return out