コード例 #1
0
ファイル: objects.py プロジェクト: clchiou/garage
 def __init__(self, schema, exc_type):
     if (
         schema.name != exc_type.__name__
         and schema.name != cases.upper_to_lower_camel(exc_type.__name__)
     ):
         LOG.warning(
             'expect exc_type.__name__ == %r, not %r',
             schema.name,
             exc_type.__name__,
         )
     args_annotation = (
         exc_type.__dict__.get('__annotations__', {}).get('args')
     )
     if args_annotation is None:
         element_types = [
             TYPE_ASSERT.getitem(self._SIMPLE_TYPE_MAP, sf.type.which)
             for sf in _fields_by_code_order(schema)
         ]
     else:
         TYPE_ASSERT(
             typings.is_recursive_type(args_annotation)
             and args_annotation.__origin__ is tuple,
             'expect typing.Tuple, not {!r}',
             args_annotation,
         )
         element_types = args_annotation.__args__
     self._converter = _TupleConverter(schema, element_types)
     self._exc_type = exc_type
コード例 #2
0
ファイル: utils.py プロジェクト: clchiou/garage
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
        }
コード例 #3
0
ファイル: objects.py プロジェクト: clchiou/garage
def _make_optional_field_converter(sf_type, df_type):
    """Make a converter for a union member.

    * ``sf_type`` should be type of a member field of a union.
    * ``df_type`` should be a typing.Optional annotation.
    """
    if typings.type_is_subclass(df_type, NoneType):
        # Handle typing.Optional[NoneType], which is simply NoneType.
        return _make_union_member_converter(sf_type, df_type)
    else:
        return _make_union_member_converter(
            sf_type,
            TYPE_ASSERT(
                typings.is_recursive_type(df_type)
                and typings.is_union_type(df_type)
                and typings.match_optional_type(df_type),
                'expect typing.Optional, not {!r}',
                df_type,
            ),
        )
コード例 #4
0
def _match_recursive_type(type_, value):

    if not typings.is_recursive_type(type_):
        # Base case of the recursive type.
        return isinstance(value, type_)

    elif type_.__origin__ in (list, set, frozenset):
        return (isinstance(value, type_.__origin__) and all(
            _match_recursive_type(type_.__args__[0], v) for v in value))

    elif type_.__origin__ is tuple:
        return (
            isinstance(value, tuple) and \
            len(value) == len(type_.__args__) and
            all(_match_recursive_type(t, v)
                for t, v in zip(type_.__args__, value))
        )

    elif typings.is_union_type(type_):
        return any(_match_recursive_type(t, value) for t in type_.__args__)

    else:
        return False
コード例 #5
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)
コード例 #6
0
    def _decode_raw_value(self, value_type, raw_value):
        """Decode a raw value into ``value_type``-typed value.

        This and ``_encode_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 value_type.__origin__(
                    self._decode_raw_value(element_type, raw_element)
                    for raw_element in raw_value)

            elif value_type.__origin__ is tuple:
                ASSERT.equal(len(raw_value), len(value_type.__args__))
                return tuple(
                    self._decode_raw_value(element_type, raw_element)
                    for element_type, raw_element in zip(
                        value_type.__args__,
                        raw_value,
                    ))

            elif typings.is_union_type(value_type):

                # Handle ``None`` special case.
                if raw_value is None:
                    ASSERT.in_(NoneType, value_type.__args__)
                    return None

                # Handle ``Optional[T]`` special case.
                type_ = typings.match_optional_type(value_type)
                if type_:
                    return self._decode_raw_value(type_, raw_value)

                ASSERT.equal(len(raw_value), 1)
                type_name, raw_element = next(iter(raw_value.items()))
                for type_ in value_type.__args__:
                    if typings.is_recursive_type(type_):
                        candidate = str(type_)
                    else:
                        candidate = type_.__name__
                    if type_name == candidate:
                        return self._decode_raw_value(type_, raw_element)

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

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

        elif wiredata.is_message_type(value_type):
            return value_type(
                **{
                    f.name: self._decode_raw_value(f.type, raw_value[f.name])
                    for f in dataclasses.fields(value_type)
                    if f.name in raw_value
                })

        elif not isinstance(value_type, type):
            # Non-``type`` instance cannot be passed to ``issubclass``.
            return ASSERT.unreachable('unsupported value type: {!r}',
                                      value_type)

        elif issubclass(value_type, datetime.datetime):
            return value_type.fromisoformat(raw_value)

        elif issubclass(value_type, enum.Enum):
            return value_type[raw_value]

        elif issubclass(value_type, bytes):
            return base64.standard_b64decode(raw_value.encode('ascii'))

        elif issubclass(value_type, Exception):
            ASSERT.equal(len(raw_value), 1)
            return value_type(
                *(ASSERT.isinstance(raw_arg, _DIRECTLY_SERIALIZABLE_TYPES)
                  for raw_arg in raw_value[value_type.__name__]))

        elif issubclass(value_type, _DIRECTLY_SERIALIZABLE_TYPES):
            if value_type in _DIRECTLY_SERIALIZABLE_TYPES:
                return ASSERT.isinstance(raw_value, value_type)
            else:
                # Support sub-type of int, etc.
                return value_type(raw_value)

        else:
            return ASSERT.unreachable('unsupported value type: {!r}',
                                      value_type)
コード例 #7
0
ファイル: objects.py プロジェクト: clchiou/garage
def _make_union_member_converter(sf_type, df_type):

    if typings.is_recursive_type(df_type):

        if df_type.__origin__ is list:
            TYPE_ASSERT.equal(len(df_type.__args__), 1)
            TYPE_ASSERT.true(sf_type.is_list())
            return _CollectionTypedFieldConverter.make_union_list_accessors(
                _ListConverter(sf_type.as_list(), df_type.__args__[0])
            )

        elif df_type.__origin__ is tuple:
            TYPE_ASSERT.true(sf_type.is_struct())
            return _CollectionTypedFieldConverter.make_union_accessors(
                _TupleConverter(sf_type.as_struct(), df_type.__args__)
            )

        else:
            return TYPE_ASSERT.unreachable(
                'unsupported generic type for union: {!r}', df_type
            )

    elif is_dataclass(df_type):
        TYPE_ASSERT.true(sf_type.is_struct())
        return _CollectionTypedFieldConverter.make_union_accessors(
            _StructConverter.get(sf_type.as_struct(), df_type)
        )

    elif issubclass(df_type, Exception):
        TYPE_ASSERT.true(sf_type.is_struct())
        return _CollectionTypedFieldConverter.make_union_accessors(
            _ExceptionConverter(sf_type.as_struct(), df_type)
        )

    elif issubclass(df_type, datetime.datetime):
        if sf_type.which is _DATETIME_FLOAT_TYPE:
            return _union_datetime_getter, _union_datetime_setter_float
        else:
            TYPE_ASSERT.in_(sf_type.which, _DATETIME_INT_TYPES)
            return _union_datetime_getter, _union_datetime_setter_int

    elif issubclass(df_type, enum.Enum):
        TYPE_ASSERT.true(sf_type.is_enum())
        return functools.partial(_union_enum_getter, df_type), _union_setter

    elif issubclass(df_type, NoneType):
        TYPE_ASSERT.true(sf_type.is_void())
        return _union_none_getter, _union_setter

    elif issubclass(df_type, _capnp.VoidType):
        TYPE_ASSERT.true(sf_type.is_void())
        return operator.getitem, _union_setter

    elif issubclass(df_type, bool):
        TYPE_ASSERT.true(sf_type.is_bool())
        return operator.getitem, _union_setter

    elif issubclass(df_type, int):
        # NOTE: For now we only support sub-types of int.  If there are
        # use cases of sub-types other types, we will add support to
        # them as well.
        TYPE_ASSERT.in_(sf_type.which, _INT_TYPES)
        if df_type is int:
            getter = operator.getitem
        else:
            getter = functools.partial(_union_int_subtype_getter, df_type)
        return getter, _union_setter

    elif issubclass(df_type, float):
        TYPE_ASSERT.in_(sf_type.which, _FLOAT_TYPES)
        return operator.getitem, _union_setter

    elif issubclass(df_type, bytes):
        TYPE_ASSERT.true(sf_type.is_data())
        return _bytes_getter, _union_setter

    elif issubclass(df_type, str):
        TYPE_ASSERT.true(sf_type.is_text())
        return operator.getitem, _union_setter

    else:
        return TYPE_ASSERT.unreachable(
            'unsupported union member type: {!r}, {!r}', sf_type, df_type
        )