def default_list_deserializer(obj: list, cls: type = None, *, warn_on_fail: bool = False, tasks: int = 1, task_type: type = Process, fork_inst: Type[StateHolder] = StateHolder, **kwargs) -> list: """ Deserialize a list by deserializing all items of that list. :param obj: the list that needs deserializing. :param cls: the type optionally with a generic (e.g. List[str]). :param warn_on_fail: if ``True``, will warn upon any failure and continue. :param tasks: the allowed number of tasks (threads or processes). :param task_type: the type that is used for multitasking. :param fork_inst: if given, it uses this fork of ``JsonSerializable``. :param kwargs: any keyword arguments. :return: a deserialized list instance. """ cls_ = None kwargs_ = {**kwargs} cls_args = get_args(cls) if cls_args: cls_ = cls_args[0] # Mark the cls as 'inferred' so that later it is known where cls came # from and the precedence of classes can be determined. kwargs_['_inferred_cls'] = True if tasks == 1: result = _do_load(obj, cls_, warn_on_fail, fork_inst, kwargs_) elif tasks > 1: result = multi_task(load, obj, tasks, task_type, cls_, **kwargs_) else: raise JsonsError('Invalid number of tasks: {}'.format(tasks)) return result
def default_dict_deserializer(obj: dict, cls: type, *, key_transformer: Optional[Callable[[str], str]] = None, **kwargs) -> dict: """ Deserialize a dict by deserializing all instances of that dict. :param obj: the dict that needs deserializing. :param key_transformer: a function that transforms the keys to a different style (e.g. PascalCase). :param cls: not used. :param kwargs: any keyword arguments. :return: a deserialized dict instance. """ key_tfr = key_transformer or (lambda key: key) cls_args = get_args(cls) kwargs_ = {**kwargs, 'key_transformer': key_transformer} if len(cls_args) == 2: cls_k, cls_v = cls_args kwargs_k = {**kwargs_, 'cls': cls_k} kwargs_v = {**kwargs_, 'cls': cls_v} res = { load(key_tfr(k), **kwargs_k): load(obj[k], **kwargs_v) for k in obj } else: res = {key_tfr(key): load(obj[key], **kwargs_) for key in obj} return res
def default_list_deserializer(obj: list, cls: type = None, *, tasks: int = 1, task_type: type = Process, **kwargs) -> list: """ Deserialize a list by deserializing all items of that list. :param obj: the list that needs deserializing. :param cls: the type optionally with a generic (e.g. List[str]). :param tasks: the allowed number of tasks (threads or processes). :param task_type: the type that is used for multitasking. :param kwargs: any keyword arguments. :return: a deserialized list instance. """ cls_ = None kwargs_ = {**kwargs} cls_args = get_args(cls) if cls_args: cls_ = cls_args[0] # Mark the cls as 'inferred' so that later it is known where cls came # from and the precedence of classes can be determined. kwargs_['_inferred_cls'] = True if tasks == 1: result = [load(elem, cls=cls_, tasks=1, **kwargs_) for elem in obj] elif tasks > 1: result = multi_task(load, obj, tasks, task_type, cls_, **kwargs_) else: raise JsonsError('Invalid number of tasks: {}'.format(tasks)) return result
def default_dict_deserializer(obj: dict, cls: type, *, key_transformer: Optional[Callable[[str], str]] = None, **kwargs) -> dict: """ Deserialize a dict by deserializing all instances of that dict. :param obj: the dict that needs deserializing. :param key_transformer: a function that transforms the keys to a different style (e.g. PascalCase). :param cls: not used. :param kwargs: any keyword arguments. :return: a deserialized dict instance. """ cls_args = get_args(cls) obj_, keys_were_hashed = _load_hashed_keys(obj, cls, cls_args, key_transformer=key_transformer, **kwargs) return _deserialize(obj_, cls_args, key_transformer, keys_were_hashed, kwargs)
def default_tuple_deserializer(obj: list, cls: type = None, *, key_transformer: Optional[Callable[[str], str]] = None, **kwargs) -> object: """ Deserialize a (JSON) list into a tuple by deserializing all items of that list. :param obj: the tuple that needs deserializing. :param cls: the type optionally with a generic (e.g. Tuple[str, int]). :param kwargs: any keyword arguments. :return: a deserialized tuple instance. """ if hasattr(cls, '_fields'): return default_namedtuple_deserializer(obj, cls, key_transformer=key_transformer, **kwargs) cls_args = get_args(cls) if cls_args: tuple_types = getattr(cls, '__tuple_params__', cls_args) if tuple_with_ellipsis(cls): tuple_types = [tuple_types[0]] * len(obj) list_ = [ load(value, tuple_types[i], **kwargs) for i, value in enumerate(obj) ] else: list_ = [load(value, **kwargs) for i, value in enumerate(obj)] return tuple(list_)
def default_defaultdict_deserializer(obj: dict, cls: type, *, key_transformer: Optional[Callable[ [str], str]] = None, **kwargs) -> dict: """ Deserialize a defaultdict. :param obj: the dict that needs deserializing. :param key_transformer: a function that transforms the keys to a different style (e.g. PascalCase). :param cls: not used. :param kwargs: any keyword arguments. :return: a deserialized defaultdict instance. """ args = get_args(cls) default_factory = None cls_ = Dict if args: key, value = get_args(cls) cls_ = Dict[key, value] default_factory = value loaded = load(obj, cls_, key_transformer=key_transformer, **kwargs) return defaultdict(default_factory, loaded)
def _get_subclasses(obj: Iterable, cls: type = None) -> Tuple[type, ...]: subclasses = (None, ) * len(obj) if cls: args = get_args(cls) if len(args) == 1: # E.g. List[int] subclasses = args * len(obj) elif len(args) > 1: # E.g. Tuple[int, str, str] subclasses = args if len(subclasses) != len(obj): msg = ('Not enough generic types ({}) in {}, expected {} to match ' 'the iterable of length {}'.format(len(subclasses), cls, len(obj), len(obj))) raise SerializationError(msg) return subclasses
def is_optional_type(cls: type) -> bool: """ Return True if the given class is an optional type. A type is considered to be optional if it allows ``None`` as value. Example: is_optional_type(Optional[str]) # True is_optional_type(Union[str, int, None]) # True is_optional_type(str) # False is_optional_type(Union[str, int]) # False :param cls: a type. :return: True if cls is an optional type. """ origin = get_origin(cls) args = get_args(cls) return origin == typing.Union and NoneType in args
def default_tuple_serializer(obj: tuple, cls: Optional[type] = None, **kwargs) -> Union[list, dict]: """ Serialize the given ``obj`` to a list of serialized objects. :param obj: the tuple that is to be serialized. :param cls: the type of the ``obj``. :param kwargs: any keyword arguments that may be given to the serialization process. :return: a list of which all elements are serialized. """ if hasattr(obj, '_fields'): return default_namedtuple_serializer(obj, **kwargs) cls_ = cls if cls and tuple_with_ellipsis(cls): cls_ = Tuple[(get_args(cls)[0], ) * len(obj)] return default_iterable_serializer(obj, cls_, **kwargs)
def default_mapping_deserializer(obj: dict, cls: type, **kwargs) -> Mapping: """ Deserialize a (JSON) dict into a mapping by deserializing all items of that dict. :param obj: the dict that needs deserializing. :param cls: the type, optionally with a generic (e.g. Set[str]). :param kwargs: any keyword arguments. :return: a deserialized set instance. """ cls_ = Mapping cls_args = get_args(cls) if cls_args: cls_ = MappingType[cls_args] dict_ = default_dict_deserializer(obj, cls_, **kwargs) result = dict_ # Strip any generics from cls to allow for an instance check. if not isinstance(result, get_origin(cls)): result = cls(dict_) return result
def default_list_serializer(obj: list, cls: type = None, *, strict: bool = False, fork_inst: Optional[type] = StateHolder, **kwargs) -> list: """ Serialize the given ``obj`` to a list of serialized objects. :param obj: the list that is to be serialized. :param cls: the (subscripted) type of the list. :param strict: a bool to determine if the serializer should be strict (i.e. only dumping stuff that is known to ``cls``). :param fork_inst: if given, it uses this fork of ``JsonSerializable``. :param kwargs: any keyword arguments that may be given to the serialization process. :return: a list of which all elements are serialized. """ if not obj: return [] kwargs_ = {**kwargs, 'strict': strict} # The meta kwarg store_cls is filtered out, because an iterable should have # its own -meta attribute. kwargs_.pop('_store_cls', None) inner_type = None serializer = dump cls_args = get_args(cls) if cls_args: inner_type = cls_args[0] serializer = get_serializer(inner_type, fork_inst) elif strict: inner_type = type(obj[0]) serializer = get_serializer(inner_type, fork_inst) return [ serializer(elem, cls=inner_type, fork_inst=fork_inst, **kwargs_) for elem in obj ]