Class for more convenient calculation of excluded or included fields on values.
| 171 | |
| 172 | |
| 173 | class ValueItems(_repr.Representation): |
| 174 | """Class for more convenient calculation of excluded or included fields on values.""" |
| 175 | |
| 176 | __slots__ = ('_items', '_type') |
| 177 | |
| 178 | def __init__(self, value: Any, items: AbstractSetIntStr | MappingIntStrAny) -> None: |
| 179 | items = self._coerce_items(items) |
| 180 | |
| 181 | if isinstance(value, (list, tuple)): |
| 182 | items = self._normalize_indexes(items, len(value)) # type: ignore |
| 183 | |
| 184 | self._items: MappingIntStrAny = items # type: ignore |
| 185 | |
| 186 | def is_excluded(self, item: Any) -> bool: |
| 187 | """Check if item is fully excluded. |
| 188 | |
| 189 | :param item: key or index of a value |
| 190 | """ |
| 191 | return self.is_true(self._items.get(item)) |
| 192 | |
| 193 | def is_included(self, item: Any) -> bool: |
| 194 | """Check if value is contained in self._items. |
| 195 | |
| 196 | :param item: key or index of value |
| 197 | """ |
| 198 | return item in self._items |
| 199 | |
| 200 | def for_element(self, e: int | str) -> AbstractSetIntStr | MappingIntStrAny | None: |
| 201 | """:param e: key or index of element on value |
| 202 | :return: raw values for element if self._items is dict and contain needed element |
| 203 | """ |
| 204 | item = self._items.get(e) # type: ignore |
| 205 | return item if not self.is_true(item) else None |
| 206 | |
| 207 | def _normalize_indexes(self, items: MappingIntStrAny, v_length: int) -> dict[int | str, Any]: |
| 208 | """:param items: dict or set of indexes which will be normalized |
| 209 | :param v_length: length of sequence indexes of which will be |
| 210 | |
| 211 | >>> self._normalize_indexes({0: True, -2: True, -1: True}, 4) |
| 212 | {0: True, 2: True, 3: True} |
| 213 | >>> self._normalize_indexes({'__all__': True}, 4) |
| 214 | {0: True, 1: True, 2: True, 3: True} |
| 215 | """ |
| 216 | normalized_items: dict[int | str, Any] = {} |
| 217 | all_items = None |
| 218 | for i, v in items.items(): |
| 219 | if not (isinstance(v, Mapping) or isinstance(v, AbstractSet) or self.is_true(v)): |
| 220 | raise TypeError(f'Unexpected type of exclude value for index "{i}" {v.__class__}') |
| 221 | if i == '__all__': |
| 222 | all_items = self._coerce_value(v) |
| 223 | continue |
| 224 | if not isinstance(i, int): |
| 225 | raise TypeError( |
| 226 | 'Excluding fields from a sequence of sub-models or dicts must be performed index-wise: ' |
| 227 | 'expected integer keys or keyword "__all__"' |
| 228 | ) |
| 229 | normalized_i = v_length + i if i < 0 else i |
| 230 | normalized_items[normalized_i] = self.merge(v, normalized_items.get(normalized_i)) |
no outgoing calls