Coverage for /pythoncovmergedfiles/medio/medio/src/pydantic/pydantic/deprecated/copy_internals.py: 17%

87 statements  

« prev     ^ index     » next       coverage.py v7.2.3, created at 2023-04-27 07:38 +0000

1from __future__ import annotations as _annotations 

2 

3import typing 

4from copy import deepcopy 

5from enum import Enum 

6from typing import Any, Tuple 

7 

8import typing_extensions 

9 

10from .._internal import ( 

11 _model_construction, 

12 _typing_extra, 

13 _utils, 

14) 

15from .._internal._fields import Undefined 

16 

17if typing.TYPE_CHECKING: 

18 from .. import BaseModel 

19 from .._internal._utils import AbstractSetIntStr, MappingIntStrAny 

20 

21 AnyClassMethod = classmethod[Any, Any, Any] 

22 TupleGenerator = typing.Generator[Tuple[str, Any], None, None] 

23 Model = typing.TypeVar('Model', bound='BaseModel') 

24 # should be `set[int] | set[str] | dict[int, IncEx] | dict[str, IncEx] | None`, but mypy can't cope 

25 IncEx: typing_extensions.TypeAlias = 'set[int] | set[str] | dict[int, Any] | dict[str, Any] | None' 

26 

27_object_setattr = _model_construction.object_setattr 

28 

29 

30def _iter( 

31 self: BaseModel, 

32 to_dict: bool = False, 

33 by_alias: bool = False, 

34 include: AbstractSetIntStr | MappingIntStrAny | None = None, 

35 exclude: AbstractSetIntStr | MappingIntStrAny | None = None, 

36 exclude_unset: bool = False, 

37 exclude_defaults: bool = False, 

38 exclude_none: bool = False, 

39) -> TupleGenerator: 

40 # Merge field set excludes with explicit exclude parameter with explicit overriding field set options. 

41 # The extra "is not None" guards are not logically necessary but optimizes performance for the simple case. 

42 if exclude is not None: 

43 exclude = _utils.ValueItems.merge( 

44 {k: v.exclude for k, v in self.model_fields.items() if v.exclude is not None}, exclude 

45 ) 

46 

47 if include is not None: 

48 include = _utils.ValueItems.merge({k: v.include for k, v in self.model_fields.items()}, include, intersect=True) 

49 

50 allowed_keys = _calculate_keys(self, include=include, exclude=exclude, exclude_unset=exclude_unset) # type: ignore 

51 if allowed_keys is None and not (to_dict or by_alias or exclude_unset or exclude_defaults or exclude_none): 

52 # huge boost for plain _iter() 

53 yield from self.__dict__.items() 

54 return 

55 

56 value_exclude = _utils.ValueItems(self, exclude) if exclude is not None else None 

57 value_include = _utils.ValueItems(self, include) if include is not None else None 

58 

59 for field_key, v in self.__dict__.items(): 

60 if (allowed_keys is not None and field_key not in allowed_keys) or (exclude_none and v is None): 

61 continue 

62 

63 if exclude_defaults: 

64 try: 

65 field = self.model_fields[field_key] 

66 except KeyError: 

67 pass 

68 else: 

69 if not field.is_required() and field.default == v: 

70 continue 

71 

72 if by_alias and field_key in self.model_fields: 

73 dict_key = self.model_fields[field_key].alias or field_key 

74 else: 

75 dict_key = field_key 

76 

77 if to_dict or value_include or value_exclude: 

78 v = _get_value( # type: ignore[no-untyped-call] 

79 type(self), 

80 v, 

81 to_dict=to_dict, 

82 by_alias=by_alias, 

83 include=value_include and value_include.for_element(field_key), 

84 exclude=value_exclude and value_exclude.for_element(field_key), 

85 exclude_unset=exclude_unset, 

86 exclude_defaults=exclude_defaults, 

87 exclude_none=exclude_none, 

88 ) 

89 yield dict_key, v 

90 

91 

92def _copy_and_set_values( 

93 self: Model, values: typing.Dict[str, Any], fields_set: set[str], *, deep: bool # noqa UP006 

94) -> Model: 

95 if deep: 

96 # chances of having empty dict here are quite low for using smart_deepcopy 

97 values = deepcopy(values) 

98 

99 cls = self.__class__ 

100 m = cls.__new__(cls) 

101 _object_setattr(m, '__dict__', values) 

102 _object_setattr(m, '__pydantic_fields_set__', fields_set) 

103 for name in self.__private_attributes__: 

104 value = getattr(self, name, Undefined) 

105 if value is not Undefined: 

106 if deep: 

107 value = deepcopy(value) 

108 _object_setattr(m, name, value) 

109 

110 return m 

111 

112 

113@typing.no_type_check 

114def _get_value( 

115 cls: type[BaseModel], 

116 v: Any, 

117 to_dict: bool, 

118 by_alias: bool, 

119 include: AbstractSetIntStr | MappingIntStrAny | None, 

120 exclude: AbstractSetIntStr | MappingIntStrAny | None, 

121 exclude_unset: bool, 

122 exclude_defaults: bool, 

123 exclude_none: bool, 

124) -> Any: 

125 from .. import BaseModel 

126 

127 if isinstance(v, BaseModel): 

128 if to_dict: 

129 return v.model_dump( 

130 by_alias=by_alias, 

131 exclude_unset=exclude_unset, 

132 exclude_defaults=exclude_defaults, 

133 include=include, # type: ignore 

134 exclude=exclude, # type: ignore 

135 exclude_none=exclude_none, 

136 ) 

137 else: 

138 return v.copy(include=include, exclude=exclude) 

139 

140 value_exclude = _utils.ValueItems(v, exclude) if exclude else None 

141 value_include = _utils.ValueItems(v, include) if include else None 

142 

143 if isinstance(v, dict): 

144 return { 

145 k_: _get_value( 

146 cls, 

147 v_, 

148 to_dict=to_dict, 

149 by_alias=by_alias, 

150 exclude_unset=exclude_unset, 

151 exclude_defaults=exclude_defaults, 

152 include=value_include and value_include.for_element(k_), 

153 exclude=value_exclude and value_exclude.for_element(k_), 

154 exclude_none=exclude_none, 

155 ) 

156 for k_, v_ in v.items() 

157 if (not value_exclude or not value_exclude.is_excluded(k_)) 

158 and (not value_include or value_include.is_included(k_)) 

159 } 

160 

161 elif _utils.sequence_like(v): 

162 seq_args = ( 

163 _get_value( 

164 cls, 

165 v_, 

166 to_dict=to_dict, 

167 by_alias=by_alias, 

168 exclude_unset=exclude_unset, 

169 exclude_defaults=exclude_defaults, 

170 include=value_include and value_include.for_element(i), 

171 exclude=value_exclude and value_exclude.for_element(i), 

172 exclude_none=exclude_none, 

173 ) 

174 for i, v_ in enumerate(v) 

175 if (not value_exclude or not value_exclude.is_excluded(i)) 

176 and (not value_include or value_include.is_included(i)) 

177 ) 

178 

179 return v.__class__(*seq_args) if _typing_extra.is_namedtuple(v.__class__) else v.__class__(seq_args) 

180 

181 elif isinstance(v, Enum) and getattr(cls.model_config, 'use_enum_values', False): 

182 return v.value 

183 

184 else: 

185 return v 

186 

187 

188def _calculate_keys( 

189 self: BaseModel, 

190 include: MappingIntStrAny | None, 

191 exclude: MappingIntStrAny | None, 

192 exclude_unset: bool, 

193 update: typing.Dict[str, Any] | None = None, # noqa UP006 

194) -> typing.AbstractSet[str] | None: 

195 if include is None and exclude is None and exclude_unset is False: 

196 return None 

197 

198 keys: typing.AbstractSet[str] 

199 if exclude_unset: 

200 keys = self.__pydantic_fields_set__.copy() 

201 else: 

202 keys = self.__dict__.keys() 

203 

204 if include is not None: 

205 keys &= include.keys() 

206 

207 if update: 

208 keys -= update.keys() 

209 

210 if exclude: 

211 keys -= {k for k, v in exclude.items() if _utils.ValueItems.is_true(v)} 

212 

213 return keys