def test_get_cls_from_str(self): self.assertEqual(str, get_cls_from_str('str', {}, None)) self.assertEqual(int, get_cls_from_str('int', {}, None)) self.assertEqual(list, get_cls_from_str('list', {}, None)) class C: pass jsons.announce_class(C, 'NonExisting') self.assertEqual(C, get_cls_from_str('NonExisting', {}, StateHolder))
def _get_cls_and_meta( json_obj: object, fork_inst: type) -> Tuple[Optional[type], Optional[dict]]: if isinstance(json_obj, dict) and META_ATTR in json_obj: cls_str = json_obj[META_ATTR]['classes']['/'] cls = get_cls_from_str(cls_str, json_obj, fork_inst) return cls, json_obj[META_ATTR] return None, None
def _get_value_from_obj(obj, sig, sig_key, meta_hints, **kwargs): # Obtain the value for the attribute with the given signature from the # given obj. Try to obtain the class of this attribute from the meta info # or from type hints. cls_key = '/{}'.format(sig_key) cls_from_meta = meta_hints.get(cls_key, None) new_hints = meta_hints arg_cls = None if cls_from_meta: arg_cls = get_cls_from_str(cls_from_meta, obj, kwargs['fork_inst']) # Rebuild the class hints: cls_key becomes the new root. new_hints = { key.replace(cls_key, '/'): meta_hints[key] for key in meta_hints if key != '/' } elif sig.annotation != inspect.Parameter.empty: arg_cls = sig.annotation value = load(obj[sig_key], arg_cls, meta_hints=new_hints, **kwargs) return value
def _get_value_from_obj(obj, cls, sig, sig_key, meta_hints, **kwargs): # Obtain the value for the attribute with the given signature from the # given obj. Try to obtain the class of this attribute from the meta info # or from type hints. cls_key = '/{}'.format(sig_key) cls_str_from_meta = meta_hints.get(cls_key, None) new_hints = meta_hints cls_from_meta = None if cls_str_from_meta: cls_from_meta = get_cls_from_str( cls_str_from_meta, obj, kwargs['fork_inst']) # Rebuild the class hints: cls_key becomes the new root. new_hints = { _remove_prefix(cls_key, key): meta_hints[key] for key in meta_hints } cls_ = determine_precedence(cls=cls, cls_from_meta=cls_from_meta, cls_from_type=None, inferred_cls=True) value = load(obj[sig_key], cls_, meta_hints=new_hints, **kwargs) return value
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)
def test_get_cls_from_str(self): self.assertEqual(str, get_cls_from_str('str', {}, None)) self.assertEqual(int, get_cls_from_str('int', {}, None)) self.assertEqual(list, get_cls_from_str('list', {}, None))