py.lib

Yohn Y. 2022-08-13 Parent:4186c3b229fa Child:57f63bf31fd8

32:eb41cc498ddb Go to Latest

py.lib/dataclass_utils.py

+ Поддержали наборы объектов концигурации в библиотеке помощника разбора конфигурации + Позволяем в помощнике получить секции конфигурации.

History
awgur@31 1 # coding: utf-8
awgur@31 2
awgur@31 3 from dataclasses import fields, dataclass, is_dataclass
awgur@31 4 from typing import Union, Dict, Any
awgur@31 5
awgur@31 6
awgur@31 7 def _dict_has(obj: Dict[str, Any], key: str) -> bool:
awgur@31 8 return key in obj
awgur@31 9
awgur@31 10
awgur@31 11 def _dict_get(obj: Dict[str, Any], key: str) -> Any:
awgur@31 12 return obj[key]
awgur@31 13
awgur@31 14
awgur@31 15 def _obj_has(obj: object, key: str) -> bool:
awgur@31 16 return hasattr(obj, key)
awgur@31 17
awgur@31 18
awgur@31 19 def _obj_get(obj: object, key: str) -> Any:
awgur@31 20 return getattr(obj, key)
awgur@31 21
awgur@31 22
awgur@31 23 def dataobj_extract(obj: Union[object, Dict[str, Any]], dataclass_type: type) -> dataclass:
awgur@31 24 """\
awgur@31 25 Извлекает объект данных из предоставленного объекта, путём получения из него
awgur@31 26 указанных в классе данных аттрибутов и поиска их в данном объекте.
awgur@31 27 """
awgur@31 28
awgur@31 29 params = {}
awgur@31 30
awgur@31 31 if isinstance(obj, dict):
awgur@31 32 _has = _dict_has
awgur@31 33 _get = _dict_get
awgur@31 34
awgur@31 35 else:
awgur@31 36 _has = _obj_has
awgur@31 37 _get = _obj_get
awgur@31 38
awgur@31 39 if not is_dataclass(dataclass_type):
awgur@31 40 raise ValueError(f'Не относится к классам данных: {dataclass_type.__name__}')
awgur@31 41
awgur@31 42 for fld in fields(dataclass_type):
awgur@31 43 if _has(obj, fld.name):
awgur@31 44 val = _get(obj, fld.name)
awgur@31 45 if val is not None and not isinstance(val, fld.type):
awgur@31 46 try:
awgur@31 47 val = fld.type(val)
awgur@31 48
awgur@31 49 except (ValueError, TypeError) as e:
awgur@31 50 raise ValueError(f'Аттрибут {fld.name} не может быть получен из значения "{val}"'
awgur@31 51 f' с типом {type(val).__name__} поскольку не может быть преобразован в'
awgur@31 52 f' тип {fld.type.__name__}, заданный в классе данных: {e}')
awgur@31 53
awgur@31 54 params[fld.name] = val
awgur@31 55
awgur@31 56 try:
awgur@31 57 res = dataclass_type(**params)
awgur@31 58
awgur@31 59 except (ValueError, TypeError) as e:
awgur@31 60 _params = ', '.join(map(lambda x: f'{x[0]}="{x[1]}"', params.items()))
awgur@31 61 raise ValueError(f'Не удалось получить объект'
awgur@31 62 f' класс {dataclass_type.__name__}'
awgur@31 63 f' из параметров: {_params}'
awgur@31 64 f' ошибка: {e}')
awgur@31 65
awgur@31 66 return res