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 test_iteritems(self): assert sorted(iteritems(OpenStruct())) == [] o = OpenStruct({'foo': 'hello'}) assert sorted(iteritems(o)) == sorted(o.items()) o['bar'] = 123 assert sorted(iteritems(o)) == sorted(o.items())
def __repr__(self): return '<{klass} {properties}>'.format( klass= self.__class__.__name__, properties=' '.join(['%s=%s' % (k, repr(v)) for k, v in iteritems({'min': self.min, 'max': self.max}) if v is not None]) )
def __repr__(self): return '<{klass} {properties}>'.format( klass=self.__class__.__name__, properties=' '.join([ '%s=%s' % (k, repr(v)) for k, v in iteritems({ 'min': self.min, 'max': self.max }) if v is not None ]))
def merge_errors(errors1, errors2): """Deeply merges two error messages. Error messages can be string, list of strings or dict of error messages (recursively). Format is the same as accepted by :exc:`ValidationError`. Returns new error messages. """ if errors1 is None: return errors2 elif errors2 is None: return errors1 if isinstance(errors1, list): if not errors1: return errors2 if isinstance(errors2, list): return errors1 + errors2 elif isinstance(errors2, dict): return dict( errors2, **{SCHEMA: merge_errors(errors1, errors2.get(SCHEMA))} ) else: return errors1 + [errors2] elif isinstance(errors1, dict): if isinstance(errors2, list): return dict( errors1, **{SCHEMA: merge_errors(errors1.get(SCHEMA), errors2)} ) elif isinstance(errors2, dict): errors = dict(errors1) for k, v in iteritems(errors2): if k in errors: errors[k] = merge_errors(errors[k], v) else: errors[k] = v return errors else: return dict( errors1, **{SCHEMA: merge_errors(errors1.get(SCHEMA), errors2)} ) else: if isinstance(errors2, list): return [errors1] + errors2 if errors2 else errors1 elif isinstance(errors2, dict): return dict( errors2, **{SCHEMA: merge_errors(errors1, errors2.get(SCHEMA))} ) else: return [errors1, errors2]
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 dump(self, obj, *args, **kwargs): if obj is MISSING or obj is None: self._fail('required') errors_builder = ValidationErrorBuilder() result = OrderedDict() if self.ordered else {} for name, field in iteritems(self.fields): try: dumped = field.dump(name, obj, *args, **kwargs) if dumped != MISSING: result[name] = dumped except ValidationError as ve: errors_builder.add_error(name, ve.messages) errors_builder.raise_errors() return super(Object, self).dump(result, *args, **kwargs)
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 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