def __call__(self, v): try: return self._schema(v) except er.Invalid as e: if not self.msg or len(e.path) > 1: raise raise er.Invalid(self.msg)
def validate_mapping(path, iterable, out): required_keys = all_required_keys.copy() # keeps track of all default keys that haven't been filled default_keys = all_default_keys.copy() error = None errors = [] for key, value in iterable: key_path = path + [key] remove_key = False # compare each given key/value against all compiled key/values # schema key, (compiled key, compiled value) for skey, (ckey, cvalue) in candidates: try: new_key = ckey(key_path, key) except er.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 = [] # check if the key is marked for removal is_remove = new_key is Remove try: cval = cvalue(key_path, value) # include if it's not marked for removal if not is_remove: out[new_key] = cval else: remove_key = True continue except er.MultipleInvalid as e: exception_errors.extend(e.errors) except er.Invalid as e: exception_errors.append(e) if exception_errors: if is_remove or remove_key: continue 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 any Required() fields as found. required_keys.discard(skey) # No need for a default if it was filled default_keys.discard(skey) break else: if remove_key: # remove key continue elif self.extra == ALLOW_EXTRA: out[key] = value elif self.extra != REMOVE_EXTRA: errors.append( er.Invalid('extra keys not allowed', key_path)) # else REMOVE_EXTRA: ignore the key so it's removed from output # set defaults for any that can have defaults for key in default_keys: if not isinstance( key.default, Undefined ): # if the user provides a default with the node out[key.schema] = key.default() if key in required_keys: required_keys.discard(key) # for any required keys left that weren't found and don't have defaults: for key in required_keys: msg = key.msg if hasattr( key, 'msg') and key.msg else 'required key not provided' errors.append(er.RequiredFieldInvalid(msg, path + [key])) if errors: raise er.MultipleInvalid(errors) return out