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..61aab60c 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[Union[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))