py.lib
2022-08-19
Parent:f1a05e880961
py.lib/dataclass_utils.py
. Исправление ошибок и рефакторинг
1.1 --- a/dataclass_utils.py Fri Aug 19 00:07:55 2022 +0300 1.2 +++ b/dataclass_utils.py Fri Aug 19 02:36:30 2022 +0300 1.3 @@ -30,12 +30,12 @@ 1.4 self.like = like 1.5 self.is_complex = is_complex 1.6 1.7 - def __instancecheck__(self, instance): 1.8 + def check(self, instance): 1.9 if self.like is None: 1.10 return False 1.11 1.12 else: 1.13 - return isinstance(instance, self.like) 1.14 + return check_instance(instance, self.like) 1.15 1.16 def __repr__(self): 1.17 return f'<TypeDescriber({self.__name__}, {self.like})>' 1.18 @@ -44,8 +44,31 @@ 1.19 if val is None: 1.20 return None 1.21 1.22 + elif not self.is_complex and check_instance(val, self.like): 1.23 + return val 1.24 + 1.25 else: 1.26 - return self.cast(val) 1.27 + return self.cast(val) 1.28 + 1.29 + 1.30 +def check_instance(obj, types): 1.31 + if types is None: 1.32 + return False 1.33 + 1.34 + elif isinstance(types, (tuple, list)): 1.35 + _flag = False 1.36 + for t in types: 1.37 + if check_instance(obj, t): 1.38 + _flag = True 1.39 + break 1.40 + 1.41 + return _flag 1.42 + 1.43 + elif isinstance(types, TypeDescriber): 1.44 + return types.check(obj) 1.45 + 1.46 + else: 1.47 + return isinstance(obj, types) 1.48 1.49 1.50 def cast_iterator(t: Union[type, TypeDescriber], lst: Iterable): 1.51 @@ -53,14 +76,16 @@ 1.52 Обрабатывает последовательности единого типа. 1.53 """ 1.54 for i in lst: 1.55 - if isinstance(i, t): 1.56 + if check_instance(i, t): 1.57 yield i 1.58 1.59 - try: 1.60 - yield t(i) 1.61 + else: 1.62 + try: 1.63 + yield t(i) 1.64 1.65 - except (TypeError, ValueError) as e: 1.66 - raise ValueError(f'Не удалось привести значение к нужному типу: тип={t.__name__}; знач={i}') 1.67 + except (TypeError, ValueError) as e: 1.68 + raise ValueError(f'Не удалось привести значение к нужному типу: ' 1.69 + f'тип={t.__name__}; знач={i}') 1.70 1.71 1.72 def multi_item_tuple(tt, val): 1.73 @@ -80,14 +105,16 @@ 1.74 res = [] 1.75 1.76 for i in range(t_len): 1.77 - if isinstance(val[i], tt[i]): 1.78 - yield val[i] 1.79 + if check_instance(val[i], tt[i]): 1.80 + res.append(val[i]) 1.81 1.82 - try: 1.83 - res.append(tt[i](val[i])) 1.84 + else: 1.85 + try: 1.86 + res.append(tt[i](val[i])) 1.87 1.88 - except (TypeError, ValueError) as e: 1.89 - raise ValueError(f'Не удалось привести значение к нужному типу: тип={tt[i].__name__}; знач={val[i]}') 1.90 + except (TypeError, ValueError) as e: 1.91 + raise ValueError(f'Не удалось привести значение к нужному типу: ' 1.92 + f'тип={tt[i].__name__}; знач={val[i]}') 1.93 1.94 return tuple(res) 1.95 1.96 @@ -107,9 +134,14 @@ 1.97 if len(tt) == 0: 1.98 raise ValueError('Не указан ни один тип в составном типе Union') 1.99 1.100 - for t in tt: 1.101 + sorted_types_begin = [ t for t in tt if t in (int, float, bool)] 1.102 + sorted_types_body = [ t for t in tt if t not in (int, float, bool, str)] 1.103 + sorted_types_end = [ t for t in tt if t == str] 1.104 + 1.105 + for t in sorted_types_begin + sorted_types_body + sorted_types_end: 1.106 + _t = get_type_describer(t) 1.107 try: 1.108 - res = t(val) 1.109 + res = _t(val) 1.110 break 1.111 1.112 except (TypeError, ValueError) as e: 1.113 @@ -134,9 +166,11 @@ 1.114 1.115 _p = [] 1.116 1.117 + tt_cast = [get_type_describer(t) for t in tt] 1.118 + 1.119 for k, v in _d.items(): 1.120 try: 1.121 - _p.append((tt[0](k), tt[1](v))) 1.122 + _p.append((tt_cast[0](k), tt_cast[1](v))) 1.123 1.124 except (TypeError, ValueError) as e: 1.125 raise ValueError(f'Не удалось привести значения элемента словаря к требуемому типу: ' 1.126 @@ -224,7 +258,7 @@ 1.127 if len(_args) == 0: 1.128 raise ValueError('Не указан ни один тип в конструкции Union') 1.129 1.130 - _cast_args = tuple(map(get_type_describer, _args)) 1.131 + _cast_args = tuple(map(get_type_describer, [ i for i in _args if i is not None])) 1.132 _args_name = ', '.join(map(lambda x: x.__name__, _args)) 1.133 1.134 return TypeDescriber( 1.135 @@ -264,7 +298,7 @@ 1.136 if _has(obj, fld.name): 1.137 val = _get(obj, fld.name) 1.138 type_desc = get_type_describer(fld.type) 1.139 - if val is not None and not isinstance(val, type_desc): 1.140 + if val is not None: 1.141 try: 1.142 val = type_desc(val) 1.143