def traverser(self, data, schema, tree): """ Traverses the dictionary, recursing onto itself if it sees appropriate key/value pairs that indicate that there is a need for more validation in a branch below us. """ if hasattr(schema, '__validator_leaf__'): return schema(data, tree) if hasattr(schema, 'must_validate'): # cherry picking? if not len(schema.must_validate): reason = "must_validate attribute must not be empty" raise SchemaError(data, tree, reason=reason) data = sift(data, schema.must_validate) schema = self.sanitize_optionals(data, schema, tree) for index in range(len(data)): self.length_equality(data, schema, index, tree) key, value = data[index] skey, svalue = schema[index] tree.append(key) # Validate the key before anything, to prevent recursing self.key_leaf(data[index], schema[index], tree) # If a dict is a value we need to recurse. # XXX Should we check isinstance(value, ndict) ? if isinstance(value, dict) and len(value): self.traverser(value, svalue, tree) else: self.value_leaf(data[index], schema[index], tree) if tree: tree.pop()
def enforce(self, data, schema, item_index, tree): # yo dawg, a recursive validator within a recursive validator anyone? if is_callable(schema) and hasattr(schema, '__validator_leaf__'): return schema(data[item_index], tree) if isinstance(data[item_index], dict) and isinstance(schema, tuple): try: _validator = Validator(data[item_index], schema) _validator.validate() except Invalid: e = sys.exc_info()[1] tree.append('list[%s]' % item_index) tree.extend(e.path) raise Invalid(e.schema_item, tree, reason=e._reason, pair='value') # FIXME this is utterly redundant, and also happens in # RecursiveValidator except SchemaError: e = sys.exc_info()[1] tree.extend(e.path) raise SchemaError('', tree, reason=e._reason, pair='value') elif isinstance(schema, tuple) and not isinstance(data[item_index], (tuple, dict)): raise SchemaError( data, tree, reason='iterable contains single items, schema does not') else: try: if is_callable(schema): schema(data[item_index]) else: ensure(data[item_index] == schema) except AssertionError: reason = sys.exc_info()[1] tree.append('list[%s]' % item_index) raise Invalid(schema, tree, reason=reason, pair='item')
def length_equality(self, data, schema, index, tree): try: data = data[index] try: schema = schema[index] except KeyError: if not hasattr(schema, 'must_validate'): reason = 'has unexpected item in data: %s' % data_item( data) raise Invalid(None, tree, msg=reason, reason=reason, pair='value') except (KeyError, TypeError): if not hasattr(schema, 'must_validate'): reason = "has less items in schema than in data" raise SchemaError(data, tree, reason=reason) if hasattr(schema, '__validator_leaf__'): return if len(data) != len(schema): raise SchemaError(data, tree, reason='length did not match schema')
def is_alpha_ordered(self, data, normalized_schema, tree): keys = [] indexes = normalized_schema.keys() for index in indexes: key = normalized_schema[index][0] if isinstance(key, str): keys.append(key) elif hasattr(key, '_object'): if isinstance(key._object, str): keys.append(key._object) sorted_keys = sorted(keys) if keys != sorted_keys: for index, key in enumerate(keys): if key != sorted_keys[index]: raise SchemaError( keys, [key], reason='schema item is not alphabetically ordered')
def enforce(self, data, schema, item_index, tree): # yo dawg, a recursive validator within a recursive validator anyone? if is_callable(schema) and hasattr(schema, '__validator_leaf__'): return schema(data, tree) try: _validate = Validator({}, self.schema) _validate.data = {0: data[item_index]} _validate.validate() except Invalid: e = sys.exc_info()[1] tree.extend(e.path) raise Invalid(e.schema_item, tree, pair='value', msg=e._msg, reason=e._reason) except SchemaError: e = sys.exc_info()[1] tree.extend(e.path) raise SchemaError('', tree, reason=e._reason, pair='value')
def traverser(self, data, schema, tree): if len(data) < self.index: reason = "has not enough items to select from" raise SchemaError(data, tree, reason=reason) self.leaves(data, schema, tree)
def traverser(self, data, schema, tree): """ Traverses the dictionary, recursing onto itself if it sees appropriate key/value pairs that indicate that there is a need for more validation in a branch below us. """ if hasattr(schema, '__validator_leaf__'): return schema(data, tree) if hasattr(schema, 'must_validate'): # cherry picking? if not len(schema.must_validate): reason = "must_validate attribute must not be empty" raise SchemaError(data, tree, reason=reason) data = sift(data, schema.must_validate) schema = self.sanitize_optionals(data, schema, tree) validated_indexes = [] skip_missing_indexes = getattr(schema, 'must_validate', False) if len(data) < len(schema): # we have missing required items in data, but we don't know # which ones so find what may fail: data_keys = [v[1] for v in data.values()] schema_keys = [v[1] for v in schema.values()] def enforce_once(data_keys, schema_key): # XXX Go through all the data keys and try and see if they pass # validation against the schema. At this point it is impossible # to know which data key corresponds to what schema key # (because schema keys can be a function/callable) so it is # a *very* naive way to try and detect which one might be # missing for data_key in data_keys: failed = None try: enforce(data_key, schema_key, tree, pair='key') return except Invalid: failed = data_key, schema_key if failed: return failed for schema_key in schema_keys: failure = enforce_once(data_keys, schema_key) if failure: _, failed_schema_key = failure msg = "required key in data is missing: %s" % str( failed_schema_key) raise Invalid(None, tree, reason=msg, pair='key') for index in range(len(data)): self.length_equality(data, schema, index, tree) key, value = data[index] skey, svalue = schema[index] tree.append(key) # Validate the key before anything, to prevent recursing self.key_leaf(data[index], schema[index], tree) # If a dict is a value we need to recurse. # XXX Should we check isinstance(value, ndict) ? if isinstance(value, dict) and len(value): self.traverser(value, svalue, tree) else: self.value_leaf(data[index], schema[index], tree) if tree: tree.pop() validated_indexes.append(index) # XXX There is a chance we might have missing items from # the incoming data that are labeled as required from the schema # we should make sure *here* that we account for that and raise # the appropriate exception. Since the loop finished and everything # seems to have passed, this lack of check will give false positives. missing_indexes = set(schema.keys()).difference(validated_indexes) if missing_indexes: if skip_missing_indexes: return for i in missing_indexes: if not hasattr(schema[i], 'is_optional'): required_key = schema[i][0] tree.append('item[%s]' % i) msg = "required item in schema is missing: %s" % str( required_key) raise Invalid(required_key, tree, reason=msg, pair='key')