def _do_load(json_obj: object, deserializer: callable, cls: type, initial: bool, **kwargs): try: result = deserializer(json_obj, cls, **kwargs) validate(result, cls, kwargs['fork_inst']) except Exception as err: clear() if isinstance(err, JsonsError): raise raise DeserializationError(str(err), json_obj, cls) else: if initial: # Clear all lru caches right before returning the initial call. clear() return result
def _do_load(json_obj: object, deserializer: callable, cls: type, initial: bool, **kwargs): cls_name = get_class_name(cls, fully_qualified=True) if deserializer is None: raise DeserializationError( 'No deserializer for type "{}"'.format(cls_name), json_obj, cls) try: result = deserializer(json_obj, cls, **kwargs) validate(result, cls, kwargs['fork_inst']) except Exception as err: clear() if isinstance(err, JsonsError): raise message = 'Could not deserialize value "{}" into "{}". {}'.format( json_obj, cls_name, err) raise DeserializationError(message, json_obj, cls) else: if initial: # Clear all lru caches right before returning the initial call. clear() return result
def load(json_obj: object, cls: Optional[Type[T]] = None, strict: bool = False, fork_inst: Optional[type] = StateHolder, attr_getters: Optional[Dict[str, Callable[[], object]]] = None, **kwargs) -> T: """ Deserialize the given ``json_obj`` to an object of type ``cls``. If the contents of ``json_obj`` do not match the interface of ``cls``, a DeserializationError is raised. If ``json_obj`` contains a value that belongs to a custom class, there must be a type hint present for that value in ``cls`` to let this function know what type it should deserialize that value to. **Example**: >>> from typing import List >>> import jsons >>> class Person: ... # No type hint required for name ... def __init__(self, name): ... self.name = name >>> class Family: ... # Person is a custom class, use a type hint ... def __init__(self, persons: List[Person]): ... self.persons = persons >>> loaded = jsons.load({'persons': [{'name': 'John'}]}, Family) >>> loaded.persons[0].name 'John' If no ``cls`` is given, a dict is simply returned, but contained values (e.g. serialized ``datetime`` values) are still deserialized. If `strict` mode is off and the type of `json_obj` exactly matches `cls` then `json_obj` is simply returned. :param json_obj: the dict that is to be deserialized. :param cls: a matching class of which an instance should be returned. :param strict: a bool to determine if the deserializer should be strict (i.e. fail on a partially deserialized `json_obj` or on `None`). :param fork_inst: if given, it uses this fork of ``JsonSerializable``. :param attr_getters: a ``dict`` that may hold callables that return values for certain attributes. :param kwargs: the keyword args are passed on to the deserializer function. :return: an instance of ``cls`` if given, a dict otherwise. """ _check_for_none(json_obj, cls) if _should_skip(json_obj, cls, strict): validate(json_obj, cls, fork_inst) return json_obj if isinstance(cls, str): cls = get_cls_from_str(cls, json_obj, fork_inst) cls, meta_hints = _check_and_get_cls_and_meta_hints( json_obj, cls, fork_inst, kwargs.get('_inferred_cls', False)) deserializer = get_deserializer(cls, fork_inst) # Is this the initial call or a nested? initial = kwargs.get('_initial', True) kwargs_ = { 'strict': strict, 'fork_inst': fork_inst, 'attr_getters': attr_getters, 'meta_hints': meta_hints, '_initial': False, **kwargs } try: result = deserializer(json_obj, cls, **kwargs_) validate(result, cls, fork_inst) if initial: # Clear all lru caches right before returning the initial call. clear() return result except Exception as err: clear() if isinstance(err, JsonsError): raise raise DeserializationError(str(err), json_obj, cls)