Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ Our backwards-compatibility policy can be found [here](https://github.com/python
and {func}`cattrs.gen.typeddicts.make_dict_structure_fn` will use the value for the `use_alias` parameter from the given converter by default now.
If you're using these functions directly, the old behavior can be restored by passing in the desired value directly.
([#596](https://github.com/python-attrs/cattrs/issues/596) [#660](https://github.com/python-attrs/cattrs/pull/660))
- Fix unstructuring of generic classes with stringified annotations.
([#661](https://github.com/python-attrs/cattrs/issues/661) [#662](https://github.com/python-attrs/cattrs/issues/662))

## 25.1.1 (2025-06-04)

Expand Down
2 changes: 1 addition & 1 deletion src/cattrs/converters.py
Original file line number Diff line number Diff line change
Expand Up @@ -1252,7 +1252,7 @@ def gen_unstructure_attrs_fromdict(
attribs = fields(origin or cl)
if attrs_has(cl) and any(isinstance(a.type, str) for a in attribs):
# PEP 563 annotations - need to be resolved.
resolve_types(cl)
resolve_types(origin or cl)
attrib_overrides = {
a.name: self.type_overrides[a.type]
for a in attribs
Expand Down
25 changes: 25 additions & 0 deletions tests/test_generics_649.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""Tests for PEP 649 (Deferred Evaluation Of Annotations Using Descriptors)."""

from __future__ import annotations

from typing import Generic, TypeVar

from attrs import define

from cattrs import Converter

T = TypeVar("T")


@define
class GenericClass(Generic[T]):
t: T


def test_generics_with_stringified_annotations():
"""Type resolution works with stringified annotations."""
converter = Converter()
inst = GenericClass(42)
dct = converter.unstructure(inst, unstructure_as=GenericClass[int])
assert dct == {"t": 42}
assert converter.structure(dct, GenericClass[int])