def load(self, data, *args, **kwargs): if data is MISSING or data is None: self._fail('required') if not is_dict(data): self._fail('invalid') errors_builder = ValidationErrorBuilder() result = {} for name, field in iteritems(self.fields): try: loaded = field.load(name, data, *args, **kwargs) if loaded != MISSING: result[name] = loaded except ValidationError as ve: errors_builder.add_error(name, ve.messages) if self.allow_extra_fields is False: field_names = [name for name, _ in iteritems(self.fields)] for name in data: if name not in field_names: errors_builder.add_error(name, self._error_messages['unknown']) errors_builder.raise_errors() result = super(Object, self).load(result, *args, **kwargs) if self.constructor: result = self.constructor(**result) return result
def dump(self, data, *args, **kwargs): if data is MISSING or data is None: self._fail('required') if is_dict(self.types) and self.dump_hint: type_id = self.dump_hint(data) if type_id not in self.types: self._fail('unknown_type_id', type_id=type_id) item_type = self.types[type_id] result = item_type.dump(data, *args, **kwargs) return super(OneOf, self).dump(result, *args, **kwargs) else: for item_type in (self.types.values() if is_dict(self.types) else self.types): try: result = item_type.dump(data, *args, **kwargs) return super(OneOf, self).dump(result, *args, **kwargs) except ValidationError as ve: pass self._fail('no_type_matched')
def dump(self, value, *args, **kwargs): if value is MISSING or value is None: self._fail('required') if not is_dict(value): self._fail('invalid') errors_builder = ValidationErrorBuilder() result = {} for k, v in iteritems(value): value_type = self.value_types.get(k) if value_type is None: continue try: result[k] = value_type.dump(v, *args, **kwargs) except ValidationError as ve: errors_builder.add_error(k, ve.messages) errors_builder.raise_errors() return super(Dict, self).dump(result, *args, **kwargs)
def _resolve_fields(self, bases, fields, only=None, exclude=None): all_fields = [] if bases is not None: for base in bases: all_fields += list(iteritems(base.fields)) if only is not None: all_fields = [(name, field) for name, field in all_fields if name in only] if exclude is not None: all_fields = [(name, field) for name, field in all_fields if name not in exclude] if fields is not None: all_fields += [ (name, self._normalize_field(field)) for name, field in (iteritems(fields) if is_dict(fields) else fields) ] return OrderedDict(all_fields)
def __init__(self, bases_or_fields=None, fields=None, constructor=None, default_field_type=None, allow_extra_fields=None, only=None, exclude=None, immutable=None, ordered=None, **kwargs): super(Object, self).__init__(**kwargs) if bases_or_fields is None and fields is None: raise ValueError('No base and/or fields are specified') if isinstance(bases_or_fields, Type): bases = [bases_or_fields] if is_list(bases_or_fields) and \ all([isinstance(base, Type) for base in bases_or_fields]): bases = bases_or_fields elif is_list(bases_or_fields) or is_dict(bases_or_fields): if fields is None: bases = [] fields = bases_or_fields else: raise ValueError('Unknown base object type: %r' % bases_or_fields) self.bases = bases self._default_field_type = default_field_type self._constructor = constructor self._allow_extra_fields = allow_extra_fields self._immutable = immutable self._ordered = ordered if only is not None and not is_list(only): only = [only] if exclude is not None and not is_list(exclude): exclude = [exclude] self._only = only self._exclude = exclude self._fields = fields
def load_into(self, obj, data, inplace=True, *args, **kwargs): """Load data and update existing object. :param obj: Object to update with deserialized data. :param data: Raw data to get value to deserialize from. :param bool inplace: If True update data inplace; otherwise - create new data. :param kwargs: Same keyword arguments as for :meth:`Type.load`. :returns: Updated object. :raises: :exc:`~lollipop.errors.ValidationError` """ if obj is None: raise ValueError('Load target should not be None') if data is MISSING: return if data is None: self._fail('required') if not is_dict(data): self._fail('invalid') errors_builder = ValidationErrorBuilder() data1 = {} for name, field in iteritems(self.fields): try: if name in data: # Load new data value = field.load_into(obj, name, data, inplace=not self.immutable and inplace) else: # Retrive data from existing object value = field.get_value(name, obj, *args, **kwargs) if value is not MISSING: data1[name] = value except ValidationError as ve: errors_builder.add_error(name, ve.messages) if self.allow_extra_fields is False: field_names = [name for name, _ in iteritems(self.fields)] for name in data: if name not in field_names: errors_builder.add_error(name, self._error_messages['unknown']) errors_builder.raise_errors() data2 = super(Object, self).load(data1, *args, **kwargs) if self.immutable or not inplace: result = data2 if self.constructor: result = self.constructor(**result) else: for name, field in iteritems(self.fields): if name not in data: continue try: field.set_value(name, obj, data2.get(name, MISSING)) except ValidationError as ve: raise ValidationError({name: ve.messages}) result = obj return result