Beispiel #1
0
    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
Beispiel #2
0
    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')
Beispiel #3
0
    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)
Beispiel #4
0
    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)
Beispiel #5
0
    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
Beispiel #6
0
    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