Esempio n. 1
0
    def convert(self, ctx: Context) -> t.Any:
        preconditions.check_instance_of(ctx.type, ConcreteType)
        preconditions.check_argument(
            t.cast(ConcreteType, ctx.type).type is decimal.Decimal,
            'must be Decimal')
        context = Optional(ctx.get_annotation(A.precision))\
          .map(lambda b: b.to_context()).or_else(None)
        fieldinfo = ctx.get_annotation(A.fieldinfo) or A.fieldinfo()

        if ctx.direction == Direction.deserialize:
            if (not fieldinfo.strict
                    and isinstance(ctx.value, (int, float))) or isinstance(
                        ctx.value, str):
                return decimal.Decimal(ctx.value, context)
            raise ctx.type_error(expected='str')

        else:
            if not isinstance(ctx.value, decimal.Decimal):
                raise ctx.type_error(expected=decimal.Decimal)
            return str(ctx.value)
Esempio n. 2
0
    def _deserialize(self, ctx: Context, type_: ObjectType) -> t.Any:
        enable_unknowns = ctx.settings.get(A.enable_unknowns)
        typeinfo = ctx.get_annotation(A.typeinfo)

        if not isinstance(ctx.value, t.Mapping):
            raise ctx.type_error(expected=t.Mapping)

        groups: t.Dict[str, t.Dict[str, t.Any]] = {'$': {}}

        # Collect keys into groups.
        used_keys: t.Set[str] = set()
        flattened = type_.schema.flattened()
        for name, flat_field in flattened.fields.items():
            aliases = flat_field.field.aliases or [name]
            for alias in aliases:
                if alias in ctx.value:
                    value = ctx.value[alias]
                    groups.setdefault(flat_field.group or '$', {})[name] = \
                      ctx.push(flat_field.field.type, value, name, flat_field.field).convert()
                    used_keys.add(alias)
                    break

        # Move captured groups into the root group ($).
        for group, values in groups.items():
            if group == '$': continue
            field = type_.schema.fields[group]
            groups['$'][group] = ctx.push(field.type, values, group,
                                          field).convert()

        # Collect unknown fields into the remainder field if there is one.
        if flattened.remainder_field:
            assert isinstance(flattened.remainder_field.type, MapType)
            remanants = {k: ctx.value[k] for k in ctx.value.keys() - used_keys}
            groups['$'][flattened.remainder_field.name] = ctx.push(
                flattened.remainder_field.type, remanants, None,
                flattened.remainder_field).convert()
            used_keys.update(ctx.value.keys())

        if not enable_unknowns or (enable_unknowns
                                   and enable_unknowns.callback):
            unused_keys = ctx.value.keys() - used_keys
            if unused_keys and not enable_unknowns:
                raise ConversionError(
                    f'unknown keys found while deserializing {ctx.type}: {unused_keys}',
                    ctx.location)
            elif unused_keys and enable_unknowns and enable_unknowns.callback:
                enable_unknowns.callback(ctx, set(unused_keys))

        try:
            return ((typeinfo.deserialize_as if typeinfo else None)
                    or type_.schema.python_type)(**groups['$'])
        except TypeError as exc:
            raise ctx.error(str(exc))
Esempio n. 3
0
 def convert(self, ctx: Context) -> t.Any:
     source_type = type(ctx.value)
     target_type = preconditions.check_instance_of(ctx.location.type,
                                                   ConcreteType).type
     fieldinfo = ctx.get_annotation(A.fieldinfo) or A.fieldinfo()
     strict = ctx.direction == Direction.serialize or fieldinfo.strict
     func = (self._strict_adapters if strict else self._nonstrict_adapters)\
         .get((source_type, target_type))
     if func is None:
         raise ctx.error(
             f'unable to {ctx.direction.name} {source_type.__name__} -> {target_type.__name__}'
         )
     try:
         return func(ctx.value)
     except ValueError as exc:
         raise ctx.error(str(exc))
Esempio n. 4
0
    def convert(self, ctx: Context) -> t.Any:
        preconditions.check_instance_of(ctx.type, ConcreteType)
        type_ = t.cast(ConcreteType, ctx.type).type
        datefmt = ctx.get_annotation(A.datefmt) or (
            self.DEFAULT_DATE_FMT if type_ == datetime.date else
            self.DEFAULT_TIME_FMT if type_ == datetime.time else
            self.DEFAULT_DATETIME_FMT if type_ == datetime.datetime else None)
        assert datefmt is not None

        if ctx.direction == Direction.deserialize:
            if isinstance(ctx.value, type_):
                return ctx.value
            elif isinstance(ctx.value, str):
                dt = datefmt.parse(
                    type_, ctx.value
                )  # TODO(NiklasRosenstein): Rethrow as ConversionError
                assert isinstance(dt, type_)
                return dt
            raise ctx.type_error(expected=f'str|{type_.__name__}')

        else:
            if not isinstance(ctx.value, type_):
                raise ctx.type_error(expected=type_)
            return datefmt.format(ctx.value)
Esempio n. 5
0
    def convert(self, ctx: Context) -> t.Any:
        assert isinstance(ctx.type, UnionType)

        fallback = ctx.get_annotation(A.union) or A.union()
        style = ctx.type.style or fallback.style or UnionType.DEFAULT_STYLE
        discriminator_key = ctx.type.discriminator_key or fallback.discriminator_key or UnionType.DEFAULT_DISCRIMINATOR_KEY
        is_deserialize = ctx.direction == Direction.deserialize

        if is_deserialize:
            if not isinstance(ctx.value, t.Mapping):
                raise ctx.type_error(expected=t.Mapping)
            member_name = self._get_deserialize_member_name(
                ctx.value, style, discriminator_key, ctx.location)
            member_type = ctx.type.subtypes.get_type_by_name(
                member_name, ctx.type_hint_adapter)
            assert isinstance(member_type, BaseType), f'"{type(ctx.type.subtypes).__name__}" returned member_type must '\
                f'be BaseType, got "{type(member_type).__name__}"'
        else:
            member_type = ctx.type_hint_adapter.adapt_type_hint(type(
                ctx.value))
            member_name = ctx.type.subtypes.get_type_name(
                member_type, ctx.type_hint_adapter)

        type_hint = member_type

        if is_deserialize:
            if style == A.union.Style.nested:
                if member_name not in ctx.value:
                    raise ConversionError(
                        f'missing union value key {member_name!r}',
                        ctx.location)
                child_context = ctx.push(type_hint, ctx.value[member_name],
                                         member_name, ctx.field)
            elif style == A.union.Style.flat:
                child_context = ctx.push(type_hint, dict(ctx.value), None,
                                         ctx.field)
                t.cast(t.Dict, child_context.value).pop(discriminator_key)
            elif style == A.union.Style.keyed:
                child_context = ctx.push(type_hint, ctx.value[member_name],
                                         member_name, ctx.field)
            else:
                raise RuntimeError(f'bad style: {style!r}')
        else:
            child_context = ctx.push(type_hint, ctx.value, None, ctx.field)

        result = child_context.convert()

        if is_deserialize:
            return result
        else:
            if style == A.union.Style.nested:
                result = {discriminator_key: member_name, member_name: result}
            elif style == A.union.Style.flat:
                if not isinstance(result, t.MutableMapping):
                    raise RuntimeError(
                        f'union.Style.flat is not supported for non-object member types'
                    )
                result[discriminator_key] = member_name
            elif style == A.union.Style.keyed:
                if not isinstance(result, t.MutableMapping):
                    raise RuntimeError(
                        f'union.Style.keyed is not supported for non-object member types'
                    )
                result = {member_name: result}
            else:
                raise RuntimeError(f'bda style: {style!r}')

        return result