Example #1
0
def get_declared_error_types(response_type):
    # When there is only one error type, reqrep.make_annotations
    # would not generate Optional[T].
    fields = dataclasses.fields(response_type.Error)
    if len(fields) == 1:
        return {ASSERT.issubclass(fields[0].type, Exception): fields[0].name}
    else:
        return {
            ASSERT(
                typings.is_recursive_type(field.type)
                and typings.is_union_type(field.type)
                and typings.match_optional_type(field.type),
                'expect typing.Optional[T]: {!r}',
                field,
            ): field.name
            for field in fields
        }
Example #2
0
    def _encode_value(self, value_type, value):
        """Encode a value into a raw value.

        This and ``_decode_raw_value`` complement each other.
        """

        if typings.is_recursive_type(value_type):

            if value_type.__origin__ in (list, set, frozenset):
                element_type = value_type.__args__[0]
                return [
                    self._encode_value(element_type, element)
                    for element in value
                ]

            elif value_type.__origin__ is tuple:
                ASSERT.equal(len(value), len(value_type.__args__))
                return tuple(
                    self._encode_value(element_type, element)
                    for element_type, element in zip(
                        value_type.__args__,
                        value,
                    ))

            elif typings.is_union_type(value_type):

                # Make a special case for ``None``.
                if value is None:
                    ASSERT.in_(NoneType, value_type.__args__)
                    return None

                # Make a special case for ``Optional[T]``.
                type_ = typings.match_optional_type(value_type)
                if type_:
                    return self._encode_value(type_, value)

                for type_ in value_type.__args__:
                    if typings.is_recursive_type(type_):
                        if _match_recursive_type(type_, value):
                            return {
                                str(type_): self._encode_value(type_, value)
                            }
                    elif isinstance(value, type_):
                        return {
                            type_.__name__: self._encode_value(type_, value)
                        }

                return ASSERT.unreachable(
                    'value is not any union element type: {!r} {!r}',
                    value_type,
                    value,
                )

            else:
                return ASSERT.unreachable('unsupported generic: {!r}',
                                          value_type)

        elif wiredata.is_message(value):
            ASSERT.predicate(value_type, wiredata.is_message_type)
            return {
                f.name: self._encode_value(f.type, getattr(value, f.name))
                for f in dataclasses.fields(value)
            }

        elif isinstance(value, datetime.datetime):
            ASSERT.issubclass(value_type, datetime.datetime)
            return value.isoformat()

        elif isinstance(value, enum.Enum):
            ASSERT.issubclass(value_type, enum.Enum)
            return value.name

        # JSON does not support binary type; so it has to be encoded.
        elif isinstance(value, bytes):
            ASSERT.issubclass(value_type, bytes)
            return base64.standard_b64encode(value).decode('ascii')

        elif isinstance(value, Exception):
            ASSERT.issubclass(value_type, Exception)
            return {
                type(value).__name__: [
                    ASSERT.isinstance(arg, _DIRECTLY_SERIALIZABLE_TYPES)
                    for arg in value.args
                ]
            }

        elif isinstance(value, _DIRECTLY_SERIALIZABLE_TYPES):
            ASSERT.issubclass(value_type, _DIRECTLY_SERIALIZABLE_TYPES)
            return value

        else:
            return ASSERT.unreachable('unsupported value type: {!r} {!r}',
                                      value_type, value)