Esempio n. 1
0
    def decode(
        self, json: JsValue, ancestors: List[JsValue]
    ) -> TOrError[Optional[T]]:
        if json is None:
            return Boxed(None)

        result = self.inner_decoder.decode(json, ancestors)
        if isinstance(result, Boxed):
            return Boxed(result.t)
        else:
            return result
Esempio n. 2
0
    def extract_if_dataclass_type(t: type) -> Optional[Dict[str, FieldType]]:
        """
        :param t: Type that needs to be checked for being a dataclass.
        :return:
           If `t` is a dataclass, returns a mapping from `t`'s field names to their types and default values.
           Otherwise, returns None.
        """
        dataclass_fields: Dict[str, Field]
        if is_dataclass(t):
            dataclass_fields = cast(Dict[str, Field],
                                    t.__dataclass_fields__)  # type: ignore
        elif hasattr(t, "__origin__") and hasattr(
                t.__origin__, "__args__") and is_dataclass(t.__origin__):
            dataclass_fields = cast(
                Dict[str,
                     Field], t.__origin__.__dataclass_fields__)  # type: ignore
        else:
            return None

        fields: Dict[str, FieldType] = {}
        for (field_name, field_definition) in dataclass_fields.items():
            field_default: Union[None, Boxed[Any], Callable[[], Any]] = None
            if field_definition.default is not MISSING:
                field_default = Boxed(field_definition.default)
            elif field_definition.default_factory is not MISSING:  # type: ignore
                field_default = field_definition.default_factory  # type: ignore
            fields[field_name] = FieldType(field_definition.type,
                                           field_default)
        return fields
Esempio n. 3
0
    def decode(
        self, json: JsValue, ancestors: List[JsValue]
    ) -> TOrError[List[T]]:
        if not isinstance(json, list):
            return [
                JsDecodeErrorFinal(
                    "Expected a JSON array but received something else."
                )
            ]
        decoded_elements: List[Any] = []
        decoding_errors: List[JsDecodeError] = []
        for index, element_json in enumerate(json):
            element_json = cast(JsValue, element_json)
            parent: JsValue = json
            decoded_element = self.element_decoder.decode(
                element_json, [parent] + ancestors
            )
            if isinstance(decoded_element, Boxed):
                decoded_elements.append(decoded_element.t)
            else:
                for err in decoded_element:
                    decoding_errors.append(JsDecodeErrorInArray(index, err))

        if len(decoding_errors) > 0:
            return decoding_errors
        else:
            return Boxed(decoded_elements)
Esempio n. 4
0
    def decode(
        self, json: JsValue, ancestors: List[JsValue]
    ) -> TOrError[Dict[str, T]]:
        if not isinstance(json, dict):
            return [
                JsDecodeErrorFinal(
                    "Expected a JSON object but received something else."
                )
            ]
        decoded_elements: Dict[str, Any] = {}
        decoding_errors: List[JsDecodeError] = []
        for key, value_json in json.items():
            if type(key) is not str:
                decoding_errors.append(
                    JsDecodeErrorFinal("Found non-string key %s in a json object (type: %s)." % (str(key), type(key)))
                )
            else:
                value_json = cast(JsValue, value_json)
                parent: JsValue = json
                decoded_value = self.element_decoder.decode(
                    value_json, [parent] + ancestors
                )
                if isinstance(decoded_value, Boxed):
                    if key not in decoded_elements:
                        decoded_elements[key] = decoded_value.t
                    else:
                        decoding_errors.append(JsDecodeErrorFinal("Found key %s more than once." % key))
                else:
                    for err in decoded_value:
                        decoding_errors.append(JsDecodeErrorInField(key, err))

        if len(decoding_errors) > 0:
            return decoding_errors
        else:
            return Boxed(decoded_elements)
Esempio n. 5
0
    def decode(self, json: JsValue, ancestors: List[JsValue]) -> TOrError[Tuple[Any, ...]]:
        if not isinstance(json, list):
            return [
                JsDecodeErrorFinal(
                    "Expected a JSON array but received something else."
                )
            ]
        if len(json) != len(self.field_decoders):
            return [
                JsDecodeErrorFinal(
                    "Expected a JSON array of size %d but received one of size %d." % (len(self.field_decoders), len(json))
                )
            ]

        decoded_fields: List[Any] = []
        decoding_errors: List[JsDecodeError] = []
        for index, field_decoder in enumerate(self.field_decoders):
            # The field_name is a key and its associated value is not None. So, it should be decoded.
            field_json = cast(JsValue, json[index])
            decoded_field = field_decoder.decode(field_json, [cast(JsValue, json)] + ancestors)
            if isinstance(decoded_field, Boxed):
                decoded_fields.append(decoded_field.t)
            else:
                for err in decoded_field:
                    decoding_errors.append(
                        JsDecodeErrorInArray(index, err)
                    )

        if len(decoding_errors) > 0:
            return decoding_errors
        else:
            return Boxed(tuple(decoded_fields))
Esempio n. 6
0
 def decode(self, json: JsValue, ancestors: List[JsValue]) -> TOrError[T]:
     decoded_field = self.field_decoder.decode(json, ancestors)
     if isinstance(decoded_field, Boxed):
         return Boxed(
             self.get_constructor()({self.field_name: decoded_field.t})
         )
     else:
         return decoded_field
Esempio n. 7
0
    def _extract_unnamed_product_type(
            self, product_type: type) -> Optional[Boxed[T]]:
        maybe_fields = Extractor.extract_if_tuple_type(product_type)
        if maybe_fields is None:
            return None

        fields: List[T] = [self._make(t) for t in maybe_fields]
        return Boxed(self.unnamed_product_extractor(product_type, fields))
Esempio n. 8
0
 def decode(self, json: JsValue, ancestors: List[JsValue]) -> TOrError[str]:
     if not isinstance(json, str):
         return [
             JsDecodeErrorFinal(
                 "Expected a JSON string but received something else."
             )
         ]
     return Boxed(json)
Esempio n. 9
0
    def _extract_named_sum_type(self, sum_type: type) -> Optional[Boxed[T]]:
        maybe_named_sum_type = Extractor.extract_if_has_sub_classes(sum_type)
        if maybe_named_sum_type is None:
            return None

        extracted_branches: Dict[str, Tuple[type, T]] = {
            s: (t, self._make(t))
            for (s, t) in maybe_named_sum_type.branches.items()
        }
        return Boxed(self.named_sum_extractor(sum_type, extracted_branches))
Esempio n. 10
0
    def _extract_enum_type(self, enum_type: type) -> Optional[Boxed[T]]:
        try:
            if not issubclass(enum_type, Enum):
                return None
        except Exception:
            return None

        value_dict = cast(Dict[str, Any], enum_type._value2member_map_)
        value_list = cast(List[Tuple[str, Any]], list(value_dict.items()))
        return Boxed(self.enum_extractor(str(enum_type), value_list))
Esempio n. 11
0
    def _extract_list_type(self, list_type: type) -> Optional[Boxed[T]]:
        maybe_list_var_name = Extractor.extract_if_list_type(list_type)
        if maybe_list_var_name is None:
            return None

        list_inner_type: type
        if isinstance(maybe_list_var_name, str):
            list_inner_type = self._var_to_type(maybe_list_var_name)
        else:
            list_inner_type = maybe_list_var_name.t

        return Boxed(self.list_extractor(self._make(list_inner_type)))
Esempio n. 12
0
    def decode(
        self, json: JsValue, ancestors: List[JsValue]
    ) -> TOrError[Decimal]:
        if isinstance(json, Decimal):
            return Boxed(json)
        elif (
            isinstance(json, float)
            or isinstance(json, int)
            or isinstance(json, str)
        ):
            try:
                return Boxed(Decimal(json))
            except DecimalException:
                return [JsDecodeErrorFinal("Value not convertible to decimal: '%s'." % str(json))]

        return [
            JsDecodeErrorFinal(
                "Expected a JSON number or a JSON string encoding a number but received something of type %s."
                % type(json)
            )
        ]
Esempio n. 13
0
class AutoMetricExporter(Extractor[MetricsExporter[Any]]):
    _enum_exporter = EnumExporter()
    _basics: Dict[type, Boxed[MetricsExporter[Any]]] = {
        bool: Boxed(BooleanExporter()),
        int: Boxed(ValueExporter()),
        float: Boxed(ValueExporter()),
        Decimal: Boxed(ValueExporter()),
        str: Boxed(TagExporter()),
        date: Boxed(DateExporter()),
        datetime: Boxed(DateTimeExporter())
    }

    @property
    def basics(self) -> Dict[type, Boxed[MetricsExporter[Any]]]:
        return self._basics

    def named_product_extractor(
        self,
        t: type,
        fields: Dict[str, WithDefault[MetricsExporter[Any]]]
    ) -> MetricsExporter[Any]:
        return NamedProductExporter(field_exporters={f_name: f_exporter.t for f_name, f_exporter in fields.items()})

    def unnamed_product_extractor(self, t: type, fields: List[MetricsExporter[Any]]) -> MetricsExporter[Any]:
        return TupleExporter(fields)

    def named_sum_extractor(
        self,
        t: type,
        branches: Dict[str, Tuple[type, MetricsExporter[Any]]]
    ) -> MetricsExporter[Any]:
        return TaggedExporter(branches=branches, tag_tag=t.__name__)

    def unnamed_sum_extractor(self, t: type, branches: List[Tuple[type, MetricsExporter[Any]]]) -> MetricsExporter[Any]:
        return PriorityExporter(branches=branches)

    def optional_extractor(self, t: MetricsExporter[Any]) -> MetricsExporter[Any]:
        return OptionalExporter(t)

    def list_extractor(self, t: MetricsExporter[Any]) -> MetricsExporter[Any]:
        return ListExporter(t)

    def dictionary_extractor(
        self,
        key: type,
        value: type,
        key_ext: MetricsExporter[Any],
        val_ext: MetricsExporter[Any]
    ) -> MetricsExporter[Any]:
        if key is str:
            return StringDictionaryExporter(val_ext)
        raise NotImplementedError()

    def enum_extractor(self, enum_name: str, enum_values: List[Tuple[str, Any]]) -> MetricsExporter[Any]:
        return self._enum_exporter
Esempio n. 14
0
 def extract_if_list_type(t: type) -> Union[None, str, Boxed[type]]:
     """
     :param t: type that needs to be checked for being a list.
     :return: Returns `Boxed("X")` if `t` is the type `List[X]` with X being the type variable name used by `List`.
     """
     if not hasattr(t, "__origin__"):
         return None
     origin = cast(type, t.__origin__)  # type: ignore
     if origin is List:
         return origin.__parameters__[0].__name__  # type: ignore
     if origin is list:
         return Boxed(t.__args__[0])  # type: ignore
     return None
Esempio n. 15
0
        def to_enum_dict(d: Dict[str, Any]) -> TOrError[Dict[Any, Any]]:
            result: Dict[Any, Any] = {}
            errors: List[JsDecodeError] = []
            for k, v in d.items():
                try:
                    e = cast(Enum, key_ext.read(k))
                    result[e] = v
                except JsDecodeException as exception:
                    for err in exception.errors:
                        errors.append(err)

            if len(errors) > 0:
                return errors
            return Boxed(result)
Esempio n. 16
0
    def _extract_named_product_type(self,
                                    product_type: type) -> Optional[Boxed[T]]:
        maybe_fields = Extractor.extract_if_named_tuple_type(product_type)
        maybe_fields = Extractor.or_else(
            maybe_fields,
            lambda: Extractor.extract_if_dataclass_type(product_type))
        if maybe_fields is None:
            return None

        fields: Dict[str, WithDefault[T]] = {
            n: v.map(self._make)
            for (n, v) in maybe_fields.items()
        }
        return Boxed(self.named_product_extractor(product_type, fields))
Esempio n. 17
0
 def decode(self, json: JsValue, ancestors: List[JsValue]) -> TOrError[int]:
     decimal_or_error = json_number_decoder.decode(json, ancestors)
     if isinstance(decimal_or_error, Boxed):
         d = decimal_or_error.t
         if int(d) == d:
             return Boxed(int(d))
         else:
             return [
                 JsDecodeErrorFinal(
                     "Expected an integral number but received non-intgeral number."
                 )
             ]
     else:
         return decimal_or_error
Esempio n. 18
0
 def extract_if_dictionary_type(
         t: type) -> Union[None, Tuple[str, str], Boxed[Tuple[type, type]]]:
     """
     :param t: type that needs to be checked for being a dictionary.
     :return: Returns `Boxed(("X", "Y"))` if `t` is the type `Dict[X, Y]` and X and Y are type variable names
              for key and value types respectively.
     """
     if not hasattr(t, "__origin__"):
         return None
     origin = cast(type, t.__origin__)  # type: ignore
     if origin is Dict:
         return origin.__parameters__[0].__name__, origin.__parameters__[
             1].__name__  # type: ignore
     if origin is dict:
         return Boxed((t.__args__[0], t.__args__[1]))  # type: ignore
     return None
Esempio n. 19
0
 def decode(self, json: JsValue, ancestors: List[JsValue]) -> TOrError[T]:
     string_or_error = json_string_decoder.decode(json, ancestors)
     if isinstance(string_or_error, Boxed):
         s = string_or_error.t
         enum_value = self.enum_values.get(s)
         if enum_value is None:
             return [
                 JsDecodeErrorFinal(
                     "Unexpected value %s while deserializing enum %s."
                     % (s, self.enum_name)
                 )
             ]
         else:
             return Boxed(enum_value)
     else:
         return string_or_error
Esempio n. 20
0
    def _extract_unnamed_sum_type(self, sum_type: type) -> Optional[Boxed[T]]:
        maybe_unnamed_sum_type = Extractor.extract_if_union_type(sum_type)
        if maybe_unnamed_sum_type is None:
            return None

        extracted_branches: List[Tuple[type, T]] = [
            (t, self._make(t)) for t in maybe_unnamed_sum_type.branches
        ]
        extracted_union: T
        if len(extracted_branches) == 1:
            extracted_union = extracted_branches[0][1]
        else:
            extracted_union = self.unnamed_sum_extractor(
                sum_type, extracted_branches)
        if maybe_unnamed_sum_type.is_optional:
            extracted_union = self.optional_extractor(extracted_union)
        return Boxed(extracted_union)
Esempio n. 21
0
 def decode(
     self, json: JsValue, ancestors: List[JsValue]
 ) -> TOrError[datetime]:
     string_or_error = json_string_decoder.decode(json, ancestors)
     if isinstance(string_or_error, Boxed):
         s = string_or_error.t
         try:
             return Boxed(parser.isoparse(s))
         except ValueError:
             return [
                 JsDecodeErrorFinal(
                     "Expected a string representing a datetime but received '%s'."
                     % s
                 )
             ]
     else:
         return string_or_error
Esempio n. 22
0
    def _make(self, t: type) -> T:
        if isinstance(t, TypeVar):  # type: ignore
            t = self._var_to_type(t.__name__)

        t_origin, t_assignments, new_context = self.assignments(t)
        key = (t_origin, t_assignments)
        if key in self.memoized:
            result = self.memoized[key].t
            if isinstance(result, RecursiveTypeApplication):
                result.ref_count = result.ref_count + 1
            return result

        recursion_placeholder = RecursiveTypeApplication(
            0, t_origin, t_assignments)
        self.memoized[key] = Boxed(recursion_placeholder)

        old_context = self._context
        self._context = new_context

        result: Optional[Boxed[T]] = None
        result = Extractor.or_else(result,
                                   lambda: self._extract_basic_type(t_origin))
        result = Extractor.or_else(
            result, lambda: self._extract_unnamed_sum_type(t_origin))
        result = Extractor.or_else(
            result, lambda: self._extract_named_sum_type(t_origin))
        result = Extractor.or_else(result,
                                   lambda: self._extract_list_type(t_origin))
        result = Extractor.or_else(
            result, lambda: self._extract_dictionary_type(t_origin))
        result = Extractor.or_else(
            result, lambda: self._extract_unnamed_product_type(t_origin))
        result = Extractor.or_else(
            result, lambda: self._extract_named_product_type(t_origin))
        result = Extractor.or_else(result,
                                   lambda: self._extract_enum_type(t_origin))

        if result is None:
            raise UnknownExtractorException(t_origin)

        if recursion_placeholder.ref_count > 0:
            replace_all_refs(recursion_placeholder, result.t)
        self._context = old_context
        self.memoized[key] = result
        return result.t
Esempio n. 23
0
    def extract_if_named_tuple_type(t: type) -> Optional[Dict[str, FieldType]]:
        """
        :param t: Type that needs to be checked for being a named tuple.
        :return:
           If `t` is a NamedTuple, returns a mapping from `t`'s field names to their types and default values.
           Otherwise, returns None.
        """
        if not hasattr(t, "_field_types"):
            return None

        t = cast(Type[NamedTuple], t)
        fields: Dict[str, FieldType] = {}
        for (f_name, f_type) in t._field_types.items():
            f_default: Optional[Boxed[Any]] = None
            if f_name in t._field_defaults:
                f_default = Boxed(t._field_defaults[f_name])
            fields[f_name] = FieldType(f_type, f_default)
        return fields
Esempio n. 24
0
    def _extract_dictionary_type(self, dict_type: type) -> Optional[Boxed[T]]:
        maybe_dict_vars = Extractor.extract_if_dictionary_type(dict_type)
        if maybe_dict_vars is None:
            return None

        key_type: type
        value_type: type
        if isinstance(maybe_dict_vars, Boxed):
            key_type, value_type = maybe_dict_vars.t
        else:
            (key_var_name, value_var_name) = maybe_dict_vars
            key_type = self._var_to_type(key_var_name)
            value_type = self._var_to_type(value_var_name)

        key_extractor = self._make(key_type)
        value_extractor = self._make(value_type)
        return Boxed(
            self.dictionary_extractor(key_type, value_type, key_extractor,
                                      value_extractor))
Esempio n. 25
0
    def decode(self, json: JsValue, ancestors: List[JsValue]) -> TOrError[T]:
        if not isinstance(json, dict):
            return [
                JsDecodeErrorFinal(
                    "Expected a JSON object but received something else."
                )
            ]
        decoded_fields: Dict[str, Any] = {}
        decoding_errors: List[JsDecodeError] = []
        for field_name, field_decoder in self.field_decoders.items():
            if (field_name not in json) or (json[field_name] is None):
                if isinstance(field_decoder, JsonOptionalDecoder):
                    decoded_fields[field_name] = None
                elif field_name in self.field_defaults:
                    def_or_fac = self.field_defaults[field_name]
                    decoded_fields[field_name] = def_or_fac.t if isinstance(def_or_fac, Boxed) else def_or_fac()
                else:
                    decoding_errors.append(
                        JsDecodeErrorInField(
                            field_name,
                            JsDecodeErrorFinal(
                                "Non-optional field was not found"
                            ),
                        )
                    )
            else:
                # The field_name is a key and its associated value is not None. So, it should be decoded.
                field_json = cast(JsValue, json[field_name])
                decoded_field = field_decoder.decode(
                    field_json, [cast(JsValue, json)] + ancestors
                )
                if isinstance(decoded_field, Boxed):
                    decoded_fields[field_name] = decoded_field.t
                else:
                    for err in decoded_field:
                        decoding_errors.append(
                            JsDecodeErrorInField(field_name, err)
                        )

        if len(decoding_errors) > 0:
            return decoding_errors
        else:
            return Boxed(self.get_constructor()(decoded_fields))
Esempio n. 26
0
class AutoJsonDecoder(Extractor[JsonDecoder[Any]]):
    json_boolean_decoder = JsonBooleanDecoder()
    json_integer_decoder = JsonIntegerDecoder()
    json_date_decoder = JsonDateDecoder()
    json_datetime_decoder = JsonDatetimeDecoder()

    basic_json_decoders: Dict[type, Boxed[JsonDecoder[Any]]] = {
        bool: Boxed(json_boolean_decoder),
        str: Boxed(json_string_decoder),
        int: Boxed(json_integer_decoder),
        Decimal: Boxed(json_number_decoder),
        datetime: Boxed(json_datetime_decoder),
        date: Boxed(json_date_decoder),
        type(None): Boxed(cast(JsonDecoder[Any], JsonNoneDecoder))
    }

    def __init__(self) -> None:
        super().__init__()

    @property
    def basics(self) -> Dict[type, Boxed[JsonDecoder[Any]]]:
        return self.basic_json_decoders

    def named_product_extractor(self, t: type, fields: Dict[str, WithDefault[JsonDecoder[Any]]]) -> JsonDecoder[Any]:
        field_decoders: Dict[str, JsonDecoder[Any]] = {
            n: v.t for (n, v) in fields.items()
        }
        field_defaults: Dict[str, Union[Boxed[Any], Callable[[], Any]]] = {
            n: v.default for (n, v) in fields.items() if v.default is not None
        }

        return JsonObjectDecoder(
            field_decoders=field_decoders,
            field_defaults=field_defaults,
            constructor=lambda args: t(**args),
        )

    def unnamed_product_extractor(self, t: type, fields: List[JsonDecoder[Any]]) -> JsonDecoder[Tuple[Any, ...]]:
        return JsonTupleDecoder(fields)

    def named_sum_extractor(self, t: type, branches: Dict[str, Tuple[type, JsonDecoder[Any]]]) -> JsonDecoder[Any]:
        return JsonTaggedDecoder(
            branch_decoders={s: t for (s, (_, t)) in branches.items()},
            tag_field_name=t.__name__, value_field_name=None
        )

    def unnamed_sum_extractor(self, t: type, branches: List[Tuple[type, JsonDecoder[Any]]]) -> JsonDecoder[Any]:
        return JsonPriorityDecoder([d for (_, d) in branches])

    def optional_extractor(self, t: JsonDecoder[T]) -> JsonDecoder[Optional[T]]:
        return JsonOptionalDecoder(t)

    def list_extractor(self, t: JsonDecoder[T]) -> JsonDecoder[List[T]]:
        return JsonListDecoder(t)

    def dictionary_extractor(
        self,
        key: type,
        value: type,
        key_ext: JsonDecoder[Any],
        val_ext: JsonDecoder[Any]
    ) -> JsonDecoder[Dict[Any, Any]]:
        def to_enum_dict(d: Dict[str, Any]) -> TOrError[Dict[Any, Any]]:
            result: Dict[Any, Any] = {}
            errors: List[JsDecodeError] = []
            for k, v in d.items():
                try:
                    e = cast(Enum, key_ext.read(k))
                    result[e] = v
                except JsDecodeException as exception:
                    for err in exception.errors:
                        errors.append(err)

            if len(errors) > 0:
                return errors
            return Boxed(result)

        if key is str:
            return JsonStringDictionaryDecoder(val_ext)
        if issubclass(key, Enum):
            return JsonFlatMappedDecoder(JsonStringDictionaryDecoder(val_ext), to_enum_dict)
        raise NotImplementedError()

    def enum_extractor(self, enum_name: str, enum_values: List[Tuple[str, Any]]) -> JsonDecoder[Any]:
        return JsonEnumDecoder(enum_name, {n: v for (n, v) in enum_values})
Esempio n. 27
0
 def decode(
     self, json: JsValue, ancestors: List[JsValue]
 ) -> TOrError[None]:
     return Boxed(None)
Esempio n. 28
0
 def decode(self, json: JsValue, ancestors: List[JsValue]) -> TOrError[T]:
     result = self.u_decoder.decode(json, ancestors)
     if isinstance(result, Boxed):
         transformer = cast(Callable[[U], T], self.u_to_t)
         return Boxed(transformer(result.t))
     return result
Esempio n. 29
0
class AutoJsonEncoder(Extractor[JsonEncoder[Any]]):
    json_basic_encoder: JsonBasicEncoder = JsonBasicEncoder()
    json_decimal_encoder: JsonDecimalEncoder = JsonDecimalEncoder()
    json_date_encoder: JsonDateEncoder = JsonDateEncoder()
    json_enum_encoder: JsonEnumEncoder = JsonEnumEncoder()

    basic_encoders: Dict[type, Boxed[JsonEncoder[Any]]] = {
        bool: Boxed(json_basic_encoder),
        str: Boxed(json_basic_encoder),
        int: Boxed(json_basic_encoder),
        float: Boxed(json_basic_encoder),
        Decimal: Boxed(json_decimal_encoder),
        datetime: Boxed(json_date_encoder),
        date: Boxed(json_date_encoder),
        type(None): Boxed(JsonNoneEncoder())
    }

    def __init__(self) -> None:
        super().__init__()

    @property
    def basics(self) -> Dict[type, Boxed[JsonEncoder[Any]]]:
        return self.basic_encoders

    def named_product_extractor(
            self, t: type,
            fields: Dict[str,
                         WithDefault[JsonEncoder[Any]]]) -> JsonEncoder[Any]:
        field_encoders: Dict[str, JsonEncoder[Any]] = {
            n: v.t
            for (n, v) in fields.items()
        }
        return JsonObjectEncoder(field_encoders=field_encoders)

    def unnamed_product_extractor(
            self, t: type,
            fields: List[JsonEncoder[Any]]) -> JsonEncoder[Tuple[Any, ...]]:
        return JsonTupleEncoder(fields)

    def named_sum_extractor(
        self, t: type,
        branches: Dict[str, Tuple[type,
                                  JsonEncoder[Any]]]) -> JsonEncoder[Any]:
        return JsonTaggedEncoder(branches=branches,
                                 tag_field_name=t.__name__,
                                 value_field_name=None)

    def unnamed_sum_extractor(
            self, t: type,
            branches: List[Tuple[type, JsonEncoder[Any]]]) -> JsonEncoder[Any]:
        return JsonPriorityEncoder(branches)

    def optional_extractor(self,
                           t: JsonEncoder[T]) -> JsonEncoder[Optional[T]]:
        return JsonOptionalEncoder(t)

    def list_extractor(self, t: JsonEncoder[T]) -> JsonEncoder[List[T]]:
        return JsonListEncoder(t)

    def dictionary_extractor(
            self, key: type, value: type, key_ext: JsonEncoder[Any],
            val_ext: JsonEncoder[Any]) -> JsonEncoder[Dict[Any, Any]]:
        def to_str_dict(d: Dict[Enum, Any]) -> Dict[str, Any]:
            return {cast(str, k.value): v for k, v in d.items()}

        if key is str:
            return JsonStringDictionaryEncoder(val_ext)
        if issubclass(key, Enum):
            return JsonMappedEncoder(JsonStringDictionaryEncoder(val_ext),
                                     to_str_dict)
        raise NotImplementedError()

    def enum_extractor(self, enum_name: str,
                       enum_values: List[Tuple[str, Any]]) -> JsonEncoder[Any]:
        return self.json_enum_encoder
Esempio n. 30
0
 def decode(self, json: JsValue, ancestors: List[JsValue]) -> TOrError[T]:
     result = self.inner_decoder.decode(json, ancestors)
     if isinstance(result, Boxed):
         return result
     return Boxed(self.default)