def validate_colander_schema(schema, request): """Validates that the request is conform to the given schema""" from colander import Invalid, Sequence, drop def _validate_fields(location, data): for attr in schema.get_attributes(location=location, request=request): if attr.required and not attr.name in data: # missing request.errors.add(location, attr.name, "%s is missing" % attr.name) else: try: if not attr.name in data: deserialized = attr.deserialize() else: if (location == 'querystring' and isinstance(attr.typ, Sequence)): serialized = data.getall(attr.name) else: serialized = data[attr.name] deserialized = attr.deserialize(serialized) except Invalid as e: # the struct is invalid try: request.errors.add(location, attr.name, e.asdict()[attr.name]) except KeyError: for k, v in e.asdict().items(): if k.startswith(attr.name): request.errors.add(location, k, v) else: if deserialized is not drop: request.validated[attr.name] = deserialized qs, headers, body, path = extract_request_data(request) _validate_fields('path', path) _validate_fields('header', headers) _validate_fields('body', body) _validate_fields('querystring', qs) # These taken from colander's _SchemaNode::deserialize # to apply preparer/validator on the root node from colander.compat import is_nonstr_iter c_schema = schema._schema_inst if c_schema.preparer is not None: # if the preparer is a function, call a single preparer if hasattr(c_schema.preparer, '__call__'): request.validated = c_schema.preparer(request.validated) # if the preparer is a list, call each separate preparer elif is_nonstr_iter(c_schema.preparer): for preparer in c_schema.preparer: request.validated = preparer(request.validated) from colander import deferred if c_schema.validator is not None: if not isinstance(c_schema.validator, deferred): # unbound c_schema.validator(c_schema, request.validated)
def deserialize(self, node, cstruct): if cstruct is colander.null: return colander.null if not is_nonstr_iter(cstruct): raise colander.Invalid(node, '{} is not iterable'.format(cstruct)) return self.deserialize_set_to_models(node, cstruct)
def add_sequence_nodes(schema, *sequence_nodes, **kwargs): for sequence_node in sequence_nodes: if isinstance(sequence_node, dict): sequence_node.update(kwargs) add_sequence_node(schema, **sequence_node) elif is_nonstr_iter(sequence_node): add_sequence_node(schema, *sequence_node, **kwargs) else: add_sequence_node(schema, sequence_node, sequence_node.name, **kwargs)
def create_filter_by(self, node, json_value, filter_type=None): if isinstance(json_value, dict): queries = [] for value_filter_type, value in json_value.items(): if not filter_type and value_filter_type.lower() in ('and', 'or'): filter_type = value_filter_type if isinstance(value, dict): query = self.create_filter_by(node, value, value_filter_type) if isinstance(query, FilterBy): queries.append(query) elif not is_nonstr_iter(value): query = self.create_filter_by(node, value, value_filter_type) if isinstance(query, FilterBy): queries.append(query) else: for deep_value in value: query = self.create_filter_by(node, deep_value, value_filter_type) if isinstance(query, FilterBy): queries.append(query) filter_type = (filter_type or 'and').lower() if filter_type not in ('and', 'or'): message = 'Invalid filter type %s for %s' % (filter_type, json_value) raise Invalid('filter_type', message) else: return FilterBy(filter_type, queries) elif is_nonstr_iter(json_value): filter_type = filter_type or 'or' return self.create_filter_by(node, {filter_type: json_value}, filter_type) else: value = super(FilterByType, self).deserialize(node, json_value) if value is not null: return FilterBy(filter_type, value) else: return null
def create_filter_by(self, node, json_value, filter_type=None): if isinstance(json_value, dict): queries = [] for value_filter_type, value in json_value.items(): if not filter_type and value_filter_type.lower() in ('and', 'or'): filter_type = value_filter_type if isinstance(value, dict): query = self.create_filter_by(node, value, value_filter_type) if isinstance(query, FilterBy): queries.append(query) elif not is_nonstr_iter(value): query = self.create_filter_by(node, value, value_filter_type) if isinstance(query, FilterBy): queries.append(query) else: for deep_value in value: query = self.create_filter_by(node, deep_value, value_filter_type) if isinstance(query, FilterBy): queries.append(query) filter_type = (filter_type or 'and').lower() if filter_type not in ('and', 'or'): message = u'Invalid filter type %s for %s' % (value_filter_type, json_value) raise Invalid('filter_type', message) else: return FilterBy(filter_type, queries) elif is_nonstr_iter(json_value): filter_type = filter_type or 'or' return self.create_filter_by(node, {filter_type: json_value}, filter_type) else: value = super(FilterByType, self).deserialize(node, json_value) if value is not null: return FilterBy(filter_type or '==', value) else: return value
def OrderFinisher(node, appstruct): if appstruct and appstruct.get('order_by'): order_by = appstruct['order_by'] if not is_nonstr_iter(order_by): order_by = [order_by] appstruct['order_by'] = [] for ob in order_by: ob = ob.split(' ', 1) descendant = bool(len(ob) == 2 and ob[1].lower() in ('desc', 'd')) appstruct['order_by'].append(OrderBy(ob[0], descendant)) return appstruct
def PaginationOrderFinisher(node, appstruct): if appstruct and appstruct.get('order_by'): order_by = appstruct['order_by'] if not is_nonstr_iter(order_by): order_by = [order_by] appstruct['order_by'] = [] output_node = getattr(node, '__output_node__') for ob in order_by: ob = ob.split(' ', 1) if output_node: breadcrumbs = ob[0].split('.') if len(breadcrumbs) == 2: table_name, column_name = breadcrumbs table_name = uncamelcase(table_name) elif len(breadcrumbs) == 1: column_name = breadcrumbs[0] table_name = None else: continue column_name = uncamelcase(column_name) for schema in output_node.__class_schema_nodes__: if not table_name or schema.name == table_name: if isinstance(schema, SequenceSchema): schema = schema.__class_schema_nodes__[0] nodes = schema.__class_schema_nodes__ nodes.extend(schema.__all_schema_nodes__) for schema_node in nodes: if isinstance(schema_node, SchemaNode) and schema_node.name == column_name: break else: # Nothing found! dont add order by continue # Break this FOR to add order by break else: # Nothing found! dont add order by continue descendant = bool(len(ob) == 2 and ob[1].lower() in ('desc', 'd')) appstruct['order_by'].append(OrderBy(ob[0], descendant)) return appstruct
def my_deserialize(self, cstruct=null): # Return None, only if request and cstruct is empty if self.return_none_if_defined and cstruct == '': return None appstruct = super(SchemaNode, self).deserialize(cstruct) # Propose this! if hasattr(self, 'finisher'): # if the finisher is a function, call a single preparer if callable(self.finisher): appstruct = self.finisher(appstruct) # if the finisher is a list, call each separate preparer elif is_nonstr_iter(self.finisher): for preparer in self.finisher: appstruct = preparer(self, appstruct) return appstruct
def add_sequence_node(schema, sequence_node, single_key, plural_key=None, with_filter_by=False): if not sequence_node.name: sequence_node = sequence_node.clone(name=single_key) if with_filter_by: sequence_node = set_node_with_filter_by(sequence_node) single_node = SequenceSchema(Sequence(), sequence_node, missing=drop, name=single_key) schema.__class_schema_nodes__.append(single_node) schema.__all_schema_nodes__.append(single_node) if plural_key: if not sequence_node.name: sequence_node = sequence_node.clone(name=plural_key) plural_node = SequenceSchema( Sequence(), sequence_node, missing=drop, preparer=split_values, name=plural_key) schema.__class_schema_nodes__.append(plural_node) schema.__all_schema_nodes__.append(plural_node) sequence_finisher = SequenceFinisher(single_key, plural_key) if hasattr(schema, 'finisher'): if not is_nonstr_iter(schema.finisher): previous_finisher = schema.finisher def decorator(cls, appstruct): appstruct = sequence_finisher(cls, appstruct) return previous_finisher(cls, appstruct) schema.finisher = decorator else: schema.finisher.append(sequence_finisher) else: schema.finisher = [sequence_finisher]
def __unicode__(self): if not is_nonstr_iter(self.value): return force_unicode(self.value) else: return self.value
def __str__(self): if not is_nonstr_iter(self.value): return force_string(self.value) else: return self.value