def _decode_generic(type_, value, infer_missing): if value is None: res = value elif _is_collection(type_): if _is_mapping(type_): k_type, v_type = type_.__args__ # a mapping type has `.keys()` and `.values()` (see collections.abc) ks = _decode_dict_keys(k_type, value.keys(), infer_missing) vs = _decode_items(v_type, value.values(), infer_missing) xs = zip(ks, vs) else: xs = _decode_items(type_.__args__[0], value, infer_missing) # get the constructor if using corresponding generic type in `typing` # otherwise fallback on constructing using type_ itself try: res = _get_type_cons(type_)(xs) except TypeError: res = type_(xs) elif _issubclass_safe(type_, Enum): # Convert to an Enum using the type as a constructor. Assumes a direct match is found. res = type_(value) else: # Optional type_arg = type_.__args__[0] if is_dataclass(type_arg) or is_dataclass(value): res = _decode_dataclass(type_arg, value, infer_missing) elif _is_supported_generic(type_arg): res = _decode_generic(type_arg, value, infer_missing) else: res = value return res
def _decode_generic(type_, value, infer_missing): if value is None: res = value elif _issubclass_safe(type_, Enum): # Convert to an Enum using the type as a constructor. Assumes a direct match is found. res = type_(value) # FIXME this is a hack to fix a deeper underlying issue. A refactor is due. elif _is_collection(type_): if _is_mapping(type_): k_type, v_type = type_.__args__ # a mapping type has `.keys()` and `.values()` (see collections.abc) ks = _decode_dict_keys(k_type, value.keys(), infer_missing) vs = _decode_items(v_type, value.values(), infer_missing) xs = zip(ks, vs) else: xs = _decode_items(type_.__args__[0], value, infer_missing) # get the constructor if using corresponding generic type in `typing` # otherwise fallback on constructing using type_ itself try: res = _get_type_cons(type_)(xs) except TypeError: res = type_(xs) else: # Optional or Union if _is_optional(type_) and len(type_.__args__) == 2: # Optional type_arg = type_.__args__[0] if is_dataclass(type_arg) or is_dataclass(value): res = _decode_dataclass(type_arg, value, infer_missing) elif _is_supported_generic(type_arg): res = _decode_generic(type_arg, value, infer_missing) else: res = _support_extended_types(type_arg, value) else: # Union (already decoded or unsupported 'from_json' used) res = value return res
def _make_default_field(type_, default, cls): cons_type = type_ cons_type = (list if _is_nonstr_collection(cons_type) else cons_type) cons_type = (dict if _is_mapping(cons_type) else cons_type) cons_type = (type_.__args__[0] if _is_optional(cons_type) else cons_type) cons = _type_to_cons[cons_type] if cons is fields.List: type_arg = type_.___args__[0] if type_arg not in _type_to_cons: raise TypeError(f"Unsupported {type_arg} detected. Is it " f"a supported JSON type or dataclass_json " f"instance?") arg_cons = _type_to_cons[type_arg] return cons(cls, arg_cons, missing=default) return cons(cls, missing=default)