py.lib

Yohn Y. 2022-08-27 Parent:366c9fe26d76

41:483727ff89c4 Go to Latest

py.lib/type_utils/dataclass_utils.py

+ Возможность удалить cookie при формировании штатного ответа.

History
1 # coding: utf-8
2 """\
3 Наполнение заданного класса данных из предоставленного словаря или объекта.
5 НЕ РАБОТАЕТ БЕЗ ОСТАЛЬНОГО МОДУЛЯ type_utils
6 """
8 from dataclasses import fields, is_dataclass
9 from typing import Union, Dict, Any
10 from .type_descriptor import get_type_describer
13 def _dict_has(obj: Dict[str, Any], key: str) -> bool:
14 return key in obj
17 def _dict_get(obj: Dict[str, Any], key: str) -> Any:
18 return obj[key]
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:
30 """\
31 Извлекает объект данных из предоставленного объекта, путём получения из него
32 указанных в классе данных аттрибутов и поиска их в данном объекте.
33 :param obj: Объект, из которого берутся данные для класса данных
34 :param dataclass_type: Класс данных, наполняемый из ``obj``
35 :param type_convert: Признак конвертирования данных. Если задан, выполняет попытку сконвертировать имеющееся
36 в параметре значение в тип, указанных в классе данных. Чудес не бывает, и процесс может
37 ошибиться особенно с Union
38 """
40 params = {}
42 if isinstance(obj, dict):
43 _has = _dict_has
44 _get = _dict_get
46 else:
47 _has = _obj_has
48 _get = _obj_get
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)
57 if val is not None:
58 if not type_desc.check(val):
59 if not type_convert:
60 raise ValueError(f'Аттрибут {fld.name} не может быть получен из значения "{val}"'
61 f' с типом {type(val).__name__} поскольку не может быть преобразован в'
62 f' тип {type_desc}, заданный в классе данных: {type_desc.event_description}')
64 try:
65 val = type_desc(val)
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
77 try:
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}'
85 f' ошибка: {e}')
87 return res