-
-
Notifications
You must be signed in to change notification settings - Fork 114
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
64 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
"""The list-from-dict implementation.""" | ||
|
||
from collections.abc import Mapping | ||
from typing import Any, TypeVar, get_args | ||
|
||
from .. import BaseConverter, SimpleStructureHook | ||
from ..dispatch import UnstructureHook | ||
|
||
T = TypeVar("T") | ||
|
||
|
||
def configure_list_from_dict( | ||
seq_type: list[T], field: str, converter: BaseConverter | ||
) -> tuple[SimpleStructureHook[Mapping, T], UnstructureHook]: | ||
""" | ||
Configure a list subtype to be structured and unstructured using a dictionary. | ||
List elements have to be an attrs class or a dataclass. One field of the element | ||
type is extracted into a dictionary key; the rest of the data is stored under that | ||
key. | ||
""" | ||
arg_type = get_args(seq_type)[0] | ||
|
||
arg_structure_hook = converter.get_structure_hook(arg_type, cache_result=False) | ||
|
||
def structure_hook( | ||
value: Mapping, type: Any = seq_type, _arg_type=arg_type | ||
) -> list[T]: | ||
return [arg_structure_hook(v | {field: k}, _arg_type) for k, v in value.items()] | ||
|
||
arg_unstructure_hook = converter.get_unstructure_hook(arg_type, cache_result=False) | ||
|
||
def unstructure_hook(val: list[T]) -> dict: | ||
return { | ||
(unstructured := arg_unstructure_hook(v)).pop(field): unstructured | ||
for v in val | ||
} | ||
|
||
return structure_hook, unstructure_hook |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
"""Tests for the list-from-dict strategy.""" | ||
|
||
from attrs import define | ||
|
||
from cattrs import BaseConverter | ||
from cattrs.strategies import configure_list_from_dict | ||
|
||
|
||
@define | ||
class A: | ||
a: int | ||
b: str | ||
|
||
|
||
def test_simple_roundtrip(converter: BaseConverter): | ||
hook, hook2 = configure_list_from_dict(list[A], "a", converter) | ||
|
||
structured = [A(1, "2"), A(3, "4")] | ||
unstructured = hook2(structured) | ||
assert unstructured == {1: {"b": "2"}, 3: {"b": "4"}} | ||
|
||
assert hook(unstructured) == structured |