Source code for zsl.utils.dict_to_object_conversion

from datetime import date, datetime
from typing import Any, Dict, Union

from zsl.utils.date_helper import format_date_portable, format_datetime_portable

DATE_DATA = 'date_data'
DATETIME_DATA = 'datetime_data'
RELATED_FIELDS = 'related_fields'
RELATED_FIELDS_CLASS = 'cls'
RELATED_FIELDS_HINTS = 'hints'


[docs] def extend_object_by_dict(target, dict_data, hints=None): """ Extends the target object with data from the provided dictionary, using hints to handle specific data types and related objects. :param target: The object to extend with data from the dictionary. :type target: object :param dict_data: The dictionary containing data to extend the target object with. :type dict_data: dict :param hints: A dictionary containing hints on how to handle specific fields. The hints should be organized in the following way:: { 'date_data': { 'field_name': 'date_format', ... }, 'datetime_data': { 'field_name': 'datetime_format', ... }, 'related_fields': { 'field_name': { 'cls': RelatedClass, 'hints': { 'date_data': {...}, 'datetime_data': {...}, 'related_fields': {...} } }, ... } } The 'date_data' and 'datetime_data' keys contain dictionaries with field names as keys and date or datetime formats as values. This helps to correctly parse date and datetime strings in the provided dictionary. The 'related_fields' key contains a dictionary with field names as keys and dictionaries as values. Each dictionary should have a 'cls' key, which should be a related class, and an optional 'hints' key containing another hints dictionary, used for nested related objects. :type hints: dict, optional :return: None. The function modifies the target object in-place. """ hints = _get_hints(hints) for field_name, field_value in dict_data.items(): if isinstance(field_value, (type(None), str, int, float, bool)): if field_name in hints[DATE_DATA] and field_value is not None: d = datetime.strptime(field_value, hints[DATE_DATA][field_name]).date() setattr(target, field_name, format_date_portable(d)) elif field_name in hints[DATETIME_DATA] and \ field_value is not None: d = datetime.strptime(field_value, hints[DATETIME_DATA][field_name]) setattr(target, field_name, format_datetime_portable(d)) else: setattr(target, field_name, field_value) elif isinstance(field_value, datetime): setattr(target, field_name, format_datetime_portable(field_value)) elif isinstance(field_value, date): setattr(target, field_name, format_date_portable(field_value)) elif field_name in hints[RELATED_FIELDS]: related_cls = hints[RELATED_FIELDS][field_name][ RELATED_FIELDS_CLASS] related_hints = hints[RELATED_FIELDS][field_name].get( RELATED_FIELDS_HINTS) if isinstance(field_value, (list, tuple)): setattr( target, field_name, [ related_cls(_to_dict(x), 'id', related_hints) for x in field_value ] ) else: setattr( target, field_name, related_cls(_to_dict(field_value), 'id', related_hints) ) elif isinstance(field_value, (list, tuple)): setattr(target, field_name, [x for x in field_value])
def _to_dict(val): # type: (Union[Dict[str, Any], object]) -> Dict[str, Any] return val if isinstance(val, dict) else val.__dict__ def _get_hints(original_hints): if original_hints is None: correct_hints = {DATE_DATA: {}, DATETIME_DATA: {}, RELATED_FIELDS: {}} else: correct_hints = original_hints if DATE_DATA not in correct_hints: correct_hints[DATE_DATA] = {} if DATETIME_DATA not in correct_hints: correct_hints[DATETIME_DATA] = {} if RELATED_FIELDS not in correct_hints: correct_hints[RELATED_FIELDS] = {} return correct_hints