def _get_value_for_attr(
        obj,
        cls,
        orig_cls,
        sig_key,
        sig,
        meta_hints,
        attr_getters,
        **kwargs):
    # Find a value for the attribute (with signature sig_key).
    if obj and sig_key in obj:
        # This argument is in obj.
        result = sig_key, _get_value_from_obj(obj, cls, sig, sig_key,
                                              meta_hints, **kwargs)
    elif sig_key in attr_getters:
        # There exists an attr_getter for this argument.
        attr_getter = attr_getters.pop(sig_key)
        result = sig_key, attr_getter()
    elif sig.default != inspect.Parameter.empty:
        # There is a default value for this argument.
        result = sig_key, sig.default
    elif sig.kind in (inspect.Parameter.VAR_POSITIONAL,
                      inspect.Parameter.VAR_KEYWORD):
        # This argument is either *args or **kwargs.
        result = None, None
    elif can_match_with_none(cls):
        # It is fine that there is no value.
        result = sig_key, None
    else:
        raise UnfulfilledArgumentError(
            'No value found for "{}"'.format(sig_key), sig_key, obj, orig_cls)
    return result
def default_namedtuple_deserializer(obj: Union[list, dict], cls: type,
                                    **kwargs) -> object:
    """
    Deserialize a (JSON) list or dict into a named tuple by deserializing all
    items of that list/dict.
    :param obj: the tuple that needs deserializing.
    :param cls: the NamedTuple.
    :param kwargs: any keyword arguments.
    :return: a deserialized named tuple (i.e. an instance of a class).
    """
    is_dict = isinstance(obj, dict)
    args = []
    for index, field_name in enumerate(cls._fields):
        if index < len(obj):
            key = field_name if is_dict else index
            field = obj[key]
        else:
            field = cls._field_defaults.get(field_name, None)

        if field is None:
            hint = getattr(cls, '_field_types', {}).get(field_name)
            if type(None) not in (get_union_params(hint) or []):
                # The value 'None' is not permitted here.
                msg = ('No value present in {} for argument "{}"'.format(
                    obj, field_name))
                raise UnfulfilledArgumentError(msg, field_name, obj, cls)
        field_types = getattr(cls, '_field_types', None)
        cls_ = field_types.get(field_name) if field_types else None
        loaded_field = load(field, cls_, **kwargs)
        args.append(loaded_field)
    inst = cls(*args)
    return inst
Esempio n. 3
0
def default_namedtuple_deserializer(obj: Union[list, dict],
                                    cls: type,
                                    *,
                                    key_transformer: Optional[Callable[
                                        [str], str]] = None,
                                    **kwargs) -> object:
    """
    Deserialize a (JSON) list or dict into a named tuple by deserializing all
    items of that list/dict.
    :param obj: the tuple that needs deserializing.
    :param cls: the NamedTuple.
    :param kwargs: any keyword arguments.
    :return: a deserialized named tuple (i.e. an instance of a class).
    """
    is_dict = isinstance(obj, dict)
    key_tfr = key_transformer or (lambda key: key)

    if is_dict:
        tfm_obj = {key_tfr(k): v for k, v in obj.items()}

    args = []
    for index, field_name in enumerate(cls._fields):
        if index < len(obj):
            if is_dict:
                field = tfm_obj[field_name]
            else:
                field = obj[index]
        else:
            field = cls._field_defaults.get(field_name, None)

        # _field_types has been deprecated in favor of __annotations__ in Python 3.8
        if hasattr(cls, '__annotations__'):
            field_types = getattr(cls, '__annotations__', {})
        else:
            field_types = getattr(cls, '_field_types', {})

        if field is None:
            hint = field_types.get(field_name)
            if NoneType not in (get_union_params(hint) or []):
                # The value 'None' is not permitted here.
                msg = ('No value present in {} for argument "{}"'.format(
                    obj, field_name))
                raise UnfulfilledArgumentError(msg, field_name, obj, cls)
        cls_ = field_types.get(field_name) if field_types else None
        loaded_field = load(field,
                            cls_,
                            key_transformer=key_transformer,
                            **kwargs)
        args.append(loaded_field)
    inst = cls(*args)
    return inst
Esempio n. 4
0
def _get_value_for_attr(obj, cls, sig_key, sig, attr_getters, **kwargs):
    result = None, None
    if obj and sig_key in obj:
        # This argument is in obj.
        arg_cls = None
        if sig.annotation != inspect.Parameter.empty:
            arg_cls = sig.annotation
        value = load(obj[sig_key], arg_cls, **kwargs)
        result = sig_key, value
    elif sig_key in attr_getters:
        # There exists an attr_getter for this argument.
        attr_getter = attr_getters.pop(sig_key)
        result = sig_key, attr_getter()
    elif sig.default != inspect.Parameter.empty:
        # There is a default value for this argument.
        result = sig_key, sig.default
    elif sig.kind not in (inspect.Parameter.VAR_POSITIONAL,
                          inspect.Parameter.VAR_KEYWORD):
        # This argument is no *args or **kwargs and has no value.
        raise UnfulfilledArgumentError(
            'No value found for "{}"'.format(sig_key), sig_key, obj, cls)
    return result
Esempio n. 5
0
def default_namedtuple_deserializer(obj: list, cls: type, **kwargs) -> object:
    """
    Deserialize a (JSON) list into a named tuple by deserializing all items of
    that list.
    :param obj: the tuple that needs deserializing.
    :param cls: the NamedTuple.
    :param kwargs: any keyword arguments.
    :return: a deserialized named tuple (i.e. an instance of a class).
    """
    args = []
    for index, field_name in enumerate(cls._fields):
        if index < len(obj):
            field = obj[index]
        else:
            field = cls._field_defaults.get(field_name, None)
        if not field:
            msg = ('No value present in {} for argument "{}"'
                   .format(obj, field_name))
            raise UnfulfilledArgumentError(msg, field_name, obj, cls)
        cls_ = cls._field_types.get(field_name, None)
        loaded_field = load(field, cls_, **kwargs)
        args.append(loaded_field)
    inst = cls(*args)
    return inst