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)
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))
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))
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)
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