diff --git a/src/attr/_make.py b/src/attr/_make.py index 7439dc2ad..e84d9792a 100644 --- a/src/attr/_make.py +++ b/src/attr/_make.py @@ -448,7 +448,7 @@ def _transform_attrs( attrs = base_attrs + own_attrs if field_transformer is not None: - attrs = field_transformer(cls, attrs) + attrs = tuple(field_transformer(cls, attrs)) # Check attr order after executing the field_transformer. # Mandatory vs non-mandatory attr order only matters when they are part of diff --git a/tests/test_hooks.py b/tests/test_hooks.py index 6b3420639..4dcd35240 100644 --- a/tests/test_hooks.py +++ b/tests/test_hooks.py @@ -217,6 +217,22 @@ class C: assert "CAttributes" == fields_type.__name__ assert issubclass(fields_type, tuple) + def test_hook_generator(self): + """ + Ensure that `attrs.fields` are correctly recorded when field_transformer is a generator + + Regression test for #1417 + """ + + def hook(cls, attribs): + yield from attribs + + @attr.s(auto_attribs=True, field_transformer=hook) + class Base: + x: int + + assert ["x"] == [a.name for a in attr.fields(Base)] + class TestAsDictHook: def test_asdict(self):