|
1 |
| -from collections import Counter |
| 1 | +from collections import Counter, deque |
2 | 2 | from collections.abc import MutableSet as AbcMutableSet
|
3 | 3 | from dataclasses import Field
|
4 | 4 | from enum import Enum
|
|
7 | 7 | from typing import (
|
8 | 8 | Any,
|
9 | 9 | Callable,
|
| 10 | + Deque, |
10 | 11 | Dict,
|
11 | 12 | Iterable,
|
12 | 13 | List,
|
|
46 | 47 | is_annotated,
|
47 | 48 | is_bare,
|
48 | 49 | is_counter,
|
| 50 | + is_deque, |
49 | 51 | is_frozenset,
|
50 | 52 | is_generic,
|
51 | 53 | is_generic_attrs,
|
@@ -193,6 +195,7 @@ def __init__(
|
193 | 195 | (is_literal, self._structure_simple_literal),
|
194 | 196 | (is_literal_containing_enums, self._structure_enum_literal),
|
195 | 197 | (is_sequence, self._structure_list),
|
| 198 | + (is_deque, self._structure_deque), |
196 | 199 | (is_mutable_set, self._structure_set),
|
197 | 200 | (is_frozenset, self._structure_frozenset),
|
198 | 201 | (is_tuple, self._structure_tuple),
|
@@ -326,7 +329,6 @@ def register_structure_hook_factory(
|
326 | 329 |
|
327 | 330 | def structure(self, obj: Any, cl: Type[T]) -> T:
|
328 | 331 | """Convert unstructured Python data structures to structured data."""
|
329 |
| - |
330 | 332 | return self._structure_func.dispatch(cl)(obj, cl)
|
331 | 333 |
|
332 | 334 | # Classes to Python primitives.
|
@@ -545,6 +547,36 @@ def _structure_list(self, obj: Iterable[T], cl: Any) -> List[T]:
|
545 | 547 | res = [handler(e, elem_type) for e in obj]
|
546 | 548 | return res
|
547 | 549 |
|
| 550 | + def _structure_deque(self, obj: Iterable[T], cl: Any) -> Deque[T]: |
| 551 | + """Convert an iterable to a potentially generic deque.""" |
| 552 | + if is_bare(cl) or cl.__args__[0] is Any: |
| 553 | + res = deque(e for e in obj) |
| 554 | + else: |
| 555 | + elem_type = cl.__args__[0] |
| 556 | + handler = self._structure_func.dispatch(elem_type) |
| 557 | + if self.detailed_validation: |
| 558 | + errors = [] |
| 559 | + res = deque() |
| 560 | + ix = 0 # Avoid `enumerate` for performance. |
| 561 | + for e in obj: |
| 562 | + try: |
| 563 | + res.append(handler(e, elem_type)) |
| 564 | + except Exception as e: |
| 565 | + msg = IterableValidationNote( |
| 566 | + f"Structuring {cl} @ index {ix}", ix, elem_type |
| 567 | + ) |
| 568 | + e.__notes__ = getattr(e, "__notes__", []) + [msg] |
| 569 | + errors.append(e) |
| 570 | + finally: |
| 571 | + ix += 1 |
| 572 | + if errors: |
| 573 | + raise IterableValidationError( |
| 574 | + f"While structuring {cl!r}", errors, cl |
| 575 | + ) |
| 576 | + else: |
| 577 | + res = deque(handler(e, elem_type) for e in obj) |
| 578 | + return res |
| 579 | + |
548 | 580 | def _structure_set(
|
549 | 581 | self, obj: Iterable[T], cl: Any, structure_to: type = set
|
550 | 582 | ) -> Set[T]:
|
@@ -823,6 +855,8 @@ def __init__(
|
823 | 855 | if MutableSequence in co:
|
824 | 856 | if list not in co:
|
825 | 857 | co[list] = co[MutableSequence]
|
| 858 | + if deque not in co: |
| 859 | + co[deque] = co[MutableSequence] |
826 | 860 |
|
827 | 861 | # abc.Mapping overrides, if defined, can apply to MutableMappings
|
828 | 862 | if Mapping in co:
|
|
0 commit comments