py.lib
py.lib/dataclass_utils.py
+ Поддержали наборы объектов концигурации в библиотеке помощника разбора конфигурации + Позволяем в помощнике получить секции конфигурации.
| 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 |