Beispiel #1
0
def from_dict(data_class: Type[T],
              data: Data,
              config: Optional[Config] = None) -> T:
    """Create a data class instance from a dictionary.

    :param data_class: a data class type
    :param data: a dictionary of a input data
    :param config: a configuration of the creation process
    :return: an instance of a data class
    """
    init_values: Data = {}
    post_init_values: Data = {}
    config = config or Config()
    try:
        data_class_hints = get_type_hints(data_class,
                                          globalns=config.forward_references)
    except NameError as error:
        raise ForwardReferenceError(str(error))
    data_class_fields = get_fields(data_class)
    if config.strict:
        extra_fields = set(data.keys()) - {f.name for f in data_class_fields}
        if extra_fields:
            raise UnexpectedDataError(keys=extra_fields)
    for field in data_class_fields:
        field = copy.copy(field)
        field.type = data_class_hints[field.name]
        try:
            try:
                field_data = data[field.name]
                transformed_value = transform_value(
                    type_hooks=config.type_hooks,
                    cast=config.cast,
                    target_type=field.type,
                    value=field_data)
                value = _build_value(type_=field.type,
                                     data=transformed_value,
                                     config=config)
            except DaciteFieldError as error:
                error.update_path(field.name)
                raise
            if config.check_types and not is_instance(value, field.type):
                raise WrongTypeError(field_path=field.name,
                                     field_type=field.type,
                                     value=value)
        except KeyError:
            try:
                value = get_default_value_for_field(field)
            except DefaultValueNotFoundError:
                if not field.init:
                    continue
                raise MissingValueError(field.name)
        if field.init:
            init_values[field.name] = value
        else:
            post_init_values[field.name] = value

    return create_instance(data_class=data_class,
                           init_values=init_values,
                           post_init_values=post_init_values)
Beispiel #2
0
 def _validate_data_key(self,
                        data_class: Type,
                        data: Data,
                        parameter: str,
                        validator=lambda v, c: v in c) -> None:
     input_data_keys = set(data.keys())
     data_class_fields = {field.name: field for field in fields(data_class)}
     for field_name, input_data_field in getattr(self, parameter).items():
         if "." not in field_name:
             field = data_class_fields[field_name]
             if not validator(input_data_field, input_data_keys
                              ) and not has_field_default_value(field):
                 raise InvalidConfigurationError(
                     parameter=parameter,
                     available_choices=input_data_keys,
                     value=input_data_field)