From a0d1b7fe918bf0c609d5e8cd9f791652779896ef Mon Sep 17 00:00:00 2001 From: Tin Tvrtkovic Date: Fri, 18 Aug 2023 17:00:23 +0200 Subject: [PATCH 1/2] Fix annotated --- HISTORY.md | 2 ++ src/cattrs/converters.py | 6 ++++-- tests/test_converter.py | 13 +++++++------ 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 50b7f1f8..18da3bd5 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -34,6 +34,8 @@ ([#408](https://github.com/python-attrs/cattrs/pull/408)) - Fix structuring `Final` lists. ([#412](https://github.com/python-attrs/cattrs/issues/412)) +- Fix certain cases of structuring `Annotated` types. + ([#418](https://github.com/python-attrs/cattrs/issues/418)) ## 23.1.2 (2023-06-02) diff --git a/src/cattrs/converters.py b/src/cattrs/converters.py index 253355f4..e0320c28 100644 --- a/src/cattrs/converters.py +++ b/src/cattrs/converters.py @@ -917,9 +917,11 @@ def gen_unstructure_annotated(self, type): origin = type.__origin__ return self._unstructure_func.dispatch(origin) - def gen_structure_annotated(self, type): + def gen_structure_annotated(self, type) -> Callable: + """A hook factory for annotated types.""" origin = type.__origin__ - return self._structure_func.dispatch(origin) + hook = self._structure_func.dispatch(origin) + return lambda v, _: hook(v, origin) def gen_unstructure_typeddict(self, cl: Any) -> Callable[[Dict], Dict]: """Generate a TypedDict unstructure function. diff --git a/tests/test_converter.py b/tests/test_converter.py index ffbec1cd..f3b747a4 100644 --- a/tests/test_converter.py +++ b/tests/test_converter.py @@ -671,21 +671,22 @@ class Inner: class Outer: i: Annotated[Inner, "test"] j: List[Annotated[Inner, "test"]] + k: Annotated[Inner | None, "test"] - orig = Outer(Inner(1), [Inner(1)]) + orig = Outer(Inner(1), [Inner(1)], Inner(1)) raw = converter.unstructure(orig) - assert raw == {"i": {"a": 1}, "j": [{"a": 1}]} + assert raw == {"i": {"a": 1}, "j": [{"a": 1}], "k": {"a": 1}} structured = converter.structure(raw, Outer) assert structured == orig # Now register a hook and rerun the test. - converter.register_unstructure_hook(Inner, lambda v: {"a": 2}) + converter.register_unstructure_hook(Inner, lambda _: {"a": 2}) - raw = converter.unstructure(Outer(Inner(1), [Inner(1)])) + raw = converter.unstructure(Outer(Inner(1), [Inner(1)], Inner(1))) - assert raw == {"i": {"a": 2}, "j": [{"a": 2}]} + assert raw == {"i": {"a": 2}, "j": [{"a": 2}], "k": {"a": 2}} structured = converter.structure(raw, Outer) - assert structured == Outer(Inner(2), [Inner(2)]) + assert structured == Outer(Inner(2), [Inner(2)], Inner(2)) From 6d4f77914c73bb2d451fa33fa25ccb3204965ee5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tin=20Tvrtkovi=C4=87?= Date: Fri, 18 Aug 2023 17:16:44 +0200 Subject: [PATCH 2/2] Fix for 3.8 --- tests/test_converter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_converter.py b/tests/test_converter.py index f3b747a4..61aab60c 100644 --- a/tests/test_converter.py +++ b/tests/test_converter.py @@ -671,7 +671,7 @@ class Inner: class Outer: i: Annotated[Inner, "test"] j: List[Annotated[Inner, "test"]] - k: Annotated[Inner | None, "test"] + k: Annotated[Union[Inner, None], "test"] orig = Outer(Inner(1), [Inner(1)], Inner(1)) raw = converter.unstructure(orig)