py.lib
2022-08-05
Child:57f63bf31fd8
py.lib/dataclass_utils.py
+ Модуль работы с датаклассами и их наполнения из ORM + Утилиты Bottle + Утилиты JWT + Помошник в парсинге конфигурационных файлов
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dataclass_utils.py Fri Aug 05 23:58:12 2022 +0300 1.3 @@ -0,0 +1,66 @@ 1.4 +# coding: utf-8 1.5 + 1.6 +from dataclasses import fields, dataclass, is_dataclass 1.7 +from typing import Union, Dict, Any 1.8 + 1.9 + 1.10 +def _dict_has(obj: Dict[str, Any], key: str) -> bool: 1.11 + return key in obj 1.12 + 1.13 + 1.14 +def _dict_get(obj: Dict[str, Any], key: str) -> Any: 1.15 + return obj[key] 1.16 + 1.17 + 1.18 +def _obj_has(obj: object, key: str) -> bool: 1.19 + return hasattr(obj, key) 1.20 + 1.21 + 1.22 +def _obj_get(obj: object, key: str) -> Any: 1.23 + return getattr(obj, key) 1.24 + 1.25 + 1.26 +def dataobj_extract(obj: Union[object, Dict[str, Any]], dataclass_type: type) -> dataclass: 1.27 + """\ 1.28 + Извлекает объект данных из предоставленного объекта, путём получения из него 1.29 + указанных в классе данных аттрибутов и поиска их в данном объекте. 1.30 + """ 1.31 + 1.32 + params = {} 1.33 + 1.34 + if isinstance(obj, dict): 1.35 + _has = _dict_has 1.36 + _get = _dict_get 1.37 + 1.38 + else: 1.39 + _has = _obj_has 1.40 + _get = _obj_get 1.41 + 1.42 + if not is_dataclass(dataclass_type): 1.43 + raise ValueError(f'Не относится к классам данных: {dataclass_type.__name__}') 1.44 + 1.45 + for fld in fields(dataclass_type): 1.46 + if _has(obj, fld.name): 1.47 + val = _get(obj, fld.name) 1.48 + if val is not None and not isinstance(val, fld.type): 1.49 + try: 1.50 + val = fld.type(val) 1.51 + 1.52 + except (ValueError, TypeError) as e: 1.53 + raise ValueError(f'Аттрибут {fld.name} не может быть получен из значения "{val}"' 1.54 + f' с типом {type(val).__name__} поскольку не может быть преобразован в' 1.55 + f' тип {fld.type.__name__}, заданный в классе данных: {e}') 1.56 + 1.57 + params[fld.name] = val 1.58 + 1.59 + try: 1.60 + res = dataclass_type(**params) 1.61 + 1.62 + except (ValueError, TypeError) as e: 1.63 + _params = ', '.join(map(lambda x: f'{x[0]}="{x[1]}"', params.items())) 1.64 + raise ValueError(f'Не удалось получить объект' 1.65 + f' класс {dataclass_type.__name__}' 1.66 + f' из параметров: {_params}' 1.67 + f' ошибка: {e}') 1.68 + 1.69 + return res