def _dependencies(self, data, schema): # TODO: ensure the logic in this function is solid. # Write more detailed tests to ensure code handles corner cases. for key, value in schema.get('dependencies', {}).items(): if key in data: if type(value) == list: for dependency in value: if dependency not in data: # TODO: This makes no sense! What about dependencies that don't validate?! yield ValidationError( ValidationError.Type.DEPENDENCIES, dependency, data) else: yield self.errors(data, dependency) else: errors = ParserIterator(self._properties(data, value)) error = errors.lookahead() if error: # TODO: I disagree with this now. It's not that the dependency is missing, but # that the schema of the dependency didn't validate. So just yield the subschema's # errors and remove this dependency error. yield ValidationError( ValidationError.Type.DEPENDENCIES, error.schema, error.data, errors=errors)
def _format(self, data, schema): format_ = schema.get('format') validator = self.formats.get(format_) if validator: if not validator(data): yield ValidationError(ValidationError.Type.FORMAT, format_, data) else: # TODO: this should be moved to schema validation! yield ValidationError(ValidationError.Type.FORMAT, format_, data)
def test_validation_error(self): v = ValidationError(ValidationError.Type.ENUM, ['a', 'b', 'c'], 'd', misc='something') t = (ValidationError.Type.ENUM.name, ['a', 'b', 'c'], 'd', None) self.assertEqual(v.__str__(), validation_pattern % t) self.assertEqual(v.__unicode__(), validation_pattern % t) self.assertEqual(v.__repr__(), validation_pattern % t) self.assertEqual(v.error, ValidationError.Type.ENUM) self.assertEqual(v.schema, ['a', 'b', 'c']) self.assertEqual(v.data, 'd')
def _type(self, data, schema): type_ = schema.get('type') if array(type_): validates = False for t in type_: validator = self._types[t] if validator(data): validates = True break if not validates: yield ValidationError(ValidationError.Type.TYPE, t, data) else: validator = self._types[type_] if not validator(data): yield ValidationError(ValidationError.Type.TYPE, type_, data)
def _unique_items(self, data, schema): if schema.get('uniqueItems', False): for i, x in enumerate(data[0:-1]): for y in data[i + 1:]: if (x == y and type(x) == type(y)): yield ValidationError( ValidationError.Type.UNIQUE_ITEMS, True, data)
def _maximum(self, data, schema): max_value = schema.get('maximum') exclusive = schema.get('exclusiveMaximum', False) if max_value is not None and not maximum(data, max_value, exclusive): yield ValidationError(ValidationError.Type.MAXIMUM, max_value, data, exclusive=exclusive)
def _minimum(self, data, schema): min_value = schema.get('minimum') exclusive = schema.get('exclusiveMinimum', False) if min_value is not None and not minimum(data, min_value, exclusive): yield ValidationError(ValidationError.Type.MINIMUM, min_value, data, exclusive=exclusive)
def _any_of(self, data, schema): any_of_schema = schema.get('anyOf') error_count = 0 for subschema in any_of_schema: subschema_errors = self.errors(data, subschema) if subschema_errors.lookahead(): error_count += 1 if error_count == len(any_of_schema): yield ValidationError(ValidationError.Type.ANY_OF, any_of_schema, data)
def _pattern(self, data, schema): regex = schema.get('pattern') try: r = self._regex_cache(regex) except: r = re.compile(regex) self._regex_cache[regex] = r if not r.search(data): yield ValidationError(ValidationError.Type.PATTERN, regex, data)
def _items(self, data, schema): items = schema.get('items') if type(items) == dict: for item in data: yield self.errors(item, items) else: additional = schema.get('additionalItems', True) if len(items) > len(data): yield ValidationError(ValidationError.Type.ITEMS, items, data) else: for x, y in zip(data, items): yield self.errors(x, y) len_data = len(data) len_items = len(items) if len_data > len_items: if additional == False: yield ValidationError( ValidationError.Type.ADDITIONAL_ITEMS, False, data[len_items:]) elif type(additional) == dict: for x in data[len_items:]: yield self.errors(x, additional)
def _errors(self, data, schema): try: processed_properties = False for key in self._keys[type(data)] + self._all_keys: if key in schema: if key not in self._properties_keys: yield self._validators[key](data, schema) elif not processed_properties: processed_properties = True yield self._validators[key](data, schema) except KeyError as e: yield ValidationError(ValidationError.Type.TYPE, self._types.keys(), data)
def _one_of(self, data, schema): one_of_schema = schema.get('oneOf') validate_count = 0 validated_subschemas = [] for subschema in one_of_schema: subschema_errors = self.errors(data, subschema) if not subschema_errors.lookahead(): validate_count += 1 validated_subschemas.append(subschema) if validate_count != 1: yield ValidationError(ValidationError.Type.ONE_OF, schema, data, validated=validated_subschemas)
def _all_of(self, data, schema): all_of_schema = schema.get('allOf') invalid_schemas = [] errors = [] for subschema in all_of_schema: subschema_errors = self.errors(data, subschema) if subschema_errors.lookahead(): invalid_schemas.append(subschema) errors.append(subschema_errors) if len(errors): yield ValidationError(ValidationError.Type.ALL_OF, invalid_schemas, data, errors=errors)
def _properties(self, data, schema): properties = schema.get('properties', {}) patterns = schema.get('patternProperties', {}) additional = schema.get('additionalProperties', True) for key in data: if key in properties: yield self.errors(data[key], properties[key]) subschemas = self._regex_keys(key, patterns) if len(subschemas) > 0: for subschema in subschemas: yield self.errors(data[key], subschema) elif key not in properties: if type(additional) == bool: if not additional: yield ValidationError( ValidationError.Type.ADDITIONAL_PROPERTIES, False, key) else: yield self.errors(data[key], additional)
def _max_properties(self, data, schema): maxProperties = schema.get('maxProperties', None) len_data = len(data) if maxProperties != None and len_data > maxProperties: yield ValidationError(ValidationError.Type.MAX_PROPERTIES, maxProperties, len_data)
def _min_items(self, data, schema): num_items = schema.get('minItems') if num_items is not None and not min_items(data, num_items): yield ValidationError(ValidationError.Type.MIN_ITEMS, num_items, data)
def _required(self, data, schema): for key in schema.get('required', {}): if key not in data: yield ValidationError(ValidationError.Type.REQUIRED, key, data)
def _min_length(self, data, schema): length = schema.get('minLength') if length is not None and not min_length(data, length): yield ValidationError(ValidationError.Type.MIN_LENGTH, length, data)
def _multiple_of(self, data, schema): multiple = schema.get('multipleOf') if multiple is not None and not multiple_of(data, multiple): yield ValidationError(ValidationError.Type.MULTIPLE_OF, multiple, data)
def _min_properties(self, data, schema): minProperties = schema.get('minProperties', None) len_data = len(data) if minProperties != None and len_data < minProperties: yield ValidationError(ValidationError.Type.MIN_PROPERTIES, minProperties, len_data)
def _not(self, data, schema): not_schema = schema.get('not') if not self.errors(data, not_schema).lookahead(): yield ValidationError(ValidationError.Type.NOT, not_schema, data)
def _enum(self, data, schema): enums = schema.get('enum') if enums and not enum(data, enums): yield ValidationError(ValidationError.Type.ENUM, enums, data)