py.lib
33:57f63bf31fd8
Go to Latest
py.lib/dataclass_utils.py
* С разбегу влетел в type hinting, пришлось обкладывать костылями. И этот процесс судя по всему длительный, и место больное будет долго...
3 from dataclasses import fields, dataclass, is_dataclass
4 from typing import Union, Dict, Any
7 def _dict_has(obj: Dict[str, Any], key: str) -> bool:
11 def _dict_get(obj: Dict[str, Any], key: str) -> Any:
15 def _obj_has(obj: object, key: str) -> bool:
16 return hasattr(obj, key)
19 def _obj_get(obj: object, key: str) -> Any:
20 return getattr(obj, key)
23 def difficult_type_recognizer(type_obj, value):
25 Магия борющаяся с костылями type hinting
27 if type(type_obj).__name__ == '_GenericAlias':
29 hasattr(type_obj, '__args__')
30 and type(type_obj.__args__) == tuple
33 if type_obj.__name__ == 'List':
34 return list(map(type_obj.__args__[0], value))
36 elif type_obj.__name__ == 'Tuple':
37 return tuple(map(type_obj.__args__[0], value))
40 raise ValueError('Неизвестный тип')
43 ValueError('Неизвестный тип')
45 elif type(type_obj).__name__ == '_UnionGenericAlias':
46 if type_obj.__name__ not in ('Union', 'Optional'):
47 raise TypeError(f'Неизвестный подтип _UnionGenericAlias: {type_obj.__name__}')
50 hasattr(type_obj, '__args__')
51 and type(type_obj.__args__) == tuple
54 raise TypeError(f'Не ясно как работать с типом не вижу аргументов: {type_obj.__name__}')
56 for _t in type_obj.__args__:
57 if _t.__name__ == 'NoneType':
63 except (TypeError, ValueError):
66 raise ValueError('Не удалось привести значение к типу')
69 def dataobj_extract(obj: Union[object, Dict[str, Any]], dataclass_type: type) -> dataclass:
71 Извлекает объект данных из предоставленного объекта, путём получения из него
72 указанных в классе данных аттрибутов и поиска их в данном объекте.
77 if isinstance(obj, dict):
85 if not is_dataclass(dataclass_type):
86 raise ValueError(f'Не относится к классам данных: {dataclass_type.__name__}')
88 for fld in fields(dataclass_type):
89 if _has(obj, fld.name):
90 val = _get(obj, fld.name)
91 if val is not None and not isinstance(val, fld.type):
95 except (ValueError, TypeError) as e:
97 val = difficult_type_recognizer(fld.type, val)
99 except (ValueError, TypeError):
100 raise ValueError(f'Аттрибут {fld.name} не может быть получен из значения "{val}"'
101 f' с типом {type(val).__name__} поскольку не может быть преобразован в'
102 f' тип {fld.type.__name__}, заданный в классе данных: {e}')
104 params[fld.name] = val
107 res = dataclass_type(**params)
109 except (ValueError, TypeError) as e:
110 _params = ', '.join(map(lambda x: f'{x[0]}="{x[1]}"', params.items()))
111 raise ValueError(f'Не удалось получить объект'
112 f' класс {dataclass_type.__name__}'
113 f' из параметров: {_params}'