py.lib
39:b8d559c989d6
Go to Latest
py.lib/type_utils/dataclass_utils.py
+ Возможность воссоздавать объекты классов из кортежей и словарей
3 Наполнение заданного класса данных из предоставленного словаря или объекта.
5 НЕ РАБОТАЕТ БЕЗ ОСТАЛЬНОГО МОДУЛЯ type_utils
8 from dataclasses import fields, is_dataclass, asdict
9 from typing import Union, Dict, Any, Iterable
10 from .type_descriptor import get_type_describer
13 def _dict_has(obj: Dict[str, Any], key: str) -> bool:
17 def _dict_get(obj: Dict[str, Any], key: str) -> Any:
21 def _obj_has(obj: object, key: str) -> bool:
22 return hasattr(obj, key)
25 def _obj_get(obj: object, key: str) -> Any:
26 return getattr(obj, key)
29 def dataobj_extract(obj: Union[object, Dict[str, Any]], dataclass_type: type, type_convert: bool = False) -> object:
31 Извлекает объект данных из предоставленного объекта, путём получения из него
32 указанных в классе данных аттрибутов и поиска их в данном объекте.
33 :param obj: Объект, из которого берутся данные для класса данных
34 :param dataclass_type: Класс данных, наполняемый из ``obj``
35 :param type_convert: Признак конвертирования данных. Если задан, выполняет попытку сконвертировать имеющееся
36 в параметре значение в тип, указанных в классе данных. Чудес не бывает, и процесс может
37 ошибиться особенно с Union
42 if isinstance(obj, dict):
50 if not is_dataclass(dataclass_type):
51 raise ValueError(f'Не относится к классам данных: {dataclass_type.__name__}')
53 for fld in fields(dataclass_type):
54 if _has(obj, fld.name):
55 val = _get(obj, fld.name)
56 type_desc = get_type_describer(fld.type)
58 if not type_desc.check(val):
60 raise ValueError(f'Аттрибут {fld.name} не может быть получен из значения "{val}"'
61 f' с типом {type(val).__name__} поскольку не может быть преобразован в'
62 f' тип {type_desc}, заданный в классе данных: {type_desc.event_description}')
67 except (ValueError, TypeError) as e:
68 raise ValueError(f'Аттрибут {fld.name} не может быть получен из значения "{val}"'
69 f' с типом {type(val).__name__} поскольку не может быть преобразован в'
70 f' тип {type_desc}, заданный в классе данных: {e}')
72 elif not (type_desc.is_nullable or type_convert):
73 raise ValueError(f'Передан "None" в поле "{fld.name}", хотя он не ожидался')
75 params[fld.name] = val
78 res = dataclass_type(**params)
80 except (ValueError, TypeError) as e:
81 _params = ', '.join(map(lambda x: f'{x[0]}="{x[1]}"', params.items()))
82 raise ValueError(f'Не удалось получить объект'
83 f' класс {dataclass_type.__name__}'
84 f' из параметров: {_params}'