Skip to content

Commit 90c8a90

Browse files
committed
Generate rename metadata for aliases in generated hooks
Add changelog entry for #710 Reformat
1 parent 08bd8d9 commit 90c8a90

File tree

3 files changed

+35
-1
lines changed

3 files changed

+35
-1
lines changed

HISTORY.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ Our backwards-compatibility policy can be found [here](https://github.com/python
1313

1414
## 25.4.0 (UNRELEASED)
1515

16+
- Aliases (from `use_alias=True` or `attrs` field aliases) now generate rename metadata in generated hooks.
17+
([#706](https://github.com/python-attrs/cattrs/issues/706) [#710](https://github.com/python-attrs/cattrs/pull/710))
1618
- Fix structuring of nested generic classes with stringified annotations.
1719
([#688](https://github.com/python-attrs/cattrs/pull/688))
1820
- Python 3.9 is no longer supported, as it is end-of-life. Use previous versions on this Python version.

src/cattrs/gen/__init__.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from collections.abc import Callable, Iterable, Mapping
55
from typing import TYPE_CHECKING, Any, Final, Literal, TypeVar
66

7-
from attrs import NOTHING, Attribute, Converter, Factory
7+
from attrs import NOTHING, Attribute, Converter, Factory, evolve
88
from typing_extensions import NoDefault
99

1010
from .._compat import (
@@ -124,6 +124,8 @@ def make_dict_unstructure_fn_from_attrs(
124124
continue
125125
if override.rename is None:
126126
kn = attr_name if not _cattrs_use_alias else a.alias
127+
if kn != attr_name:
128+
kwargs[attr_name] = evolve(override, rename=kn)
127129
else:
128130
kn = override.rename
129131
d = a.default
@@ -435,6 +437,8 @@ def make_dict_structure_fn_from_attrs(
435437
ian = a.alias
436438
if override.rename is None:
437439
kn = an if not _cattrs_use_alias else a.alias
440+
if kn != an:
441+
kwargs[an] = evolve(override, rename=kn)
438442
else:
439443
kn = override.rename
440444

@@ -562,6 +566,8 @@ def make_dict_structure_fn_from_attrs(
562566

563567
if override.rename is None:
564568
kn = an if not _cattrs_use_alias else a.alias
569+
if kn != an:
570+
kwargs[an] = evolve(override, rename=kn)
565571
else:
566572
kn = override.rename
567573
allowed_fields.add(kn)
@@ -631,6 +637,8 @@ def make_dict_structure_fn_from_attrs(
631637

632638
if override.rename is None:
633639
kn = an if not _cattrs_use_alias else a.alias
640+
if kn != an:
641+
kwargs[an] = evolve(override, rename=kn)
634642
else:
635643
kn = override.rename
636644
allowed_fields.add(kn)

tests/test_gen_dict.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,30 @@ class A:
419419
)
420420

421421

422+
def test_alias_implicit_rename(converter: BaseConverter) -> None:
423+
"""Attributes with aliases generate rename metadata."""
424+
425+
@define
426+
class A:
427+
a: int = field(alias="b")
428+
c: int = field(alias="d", default=1)
429+
430+
u_fn = make_dict_unstructure_fn(A, converter, _cattrs_use_alias=True)
431+
s_fn = make_dict_structure_fn(A, converter, _cattrs_use_alias=True)
432+
433+
assert u_fn.overrides["a"].rename == "b"
434+
assert s_fn.overrides["a"].rename == "b"
435+
assert u_fn.overrides["c"].rename == "d"
436+
assert s_fn.overrides["c"].rename == "d"
437+
438+
converter.register_unstructure_hook(A, u_fn)
439+
converter.register_structure_hook(A, s_fn)
440+
441+
assert converter.unstructure(A(1)) == {"b": 1, "d": 1}
442+
assert converter.structure({"b": 1}, A) == A(1)
443+
assert converter.structure({"b": 1, "d": 2}, A) == A(1, 2)
444+
445+
422446
def test_init_false(converter: BaseConverter) -> None:
423447
"""By default init=False keys are ignored."""
424448

0 commit comments

Comments
 (0)