|
16 | 16 | )
|
17 | 17 |
|
18 | 18 | import pytest
|
19 |
| -from attrs import Factory, define, fields, has, make_class |
| 19 | +from attrs import Factory, define, field, fields, has, make_class |
20 | 20 | from hypothesis import HealthCheck, assume, given, settings
|
21 | 21 | from hypothesis.strategies import booleans, just, lists, one_of, sampled_from
|
22 | 22 |
|
|
27 | 27 | ForbiddenExtraKeysError,
|
28 | 28 | StructureHandlerNotFoundError,
|
29 | 29 | )
|
| 30 | +from cattrs.fns import raise_error |
30 | 31 | from cattrs.gen import make_dict_structure_fn, override
|
31 | 32 |
|
32 | 33 | from ._compat import is_py310_plus
|
@@ -423,9 +424,9 @@ def test_type_overrides(cl_and_vals):
|
423 | 424 | inst = cl(*vals, **kwargs)
|
424 | 425 | unstructured = converter.unstructure(inst)
|
425 | 426 |
|
426 |
| - for field, val in zip(fields(cl), vals): |
427 |
| - if field.type is int and field.default is not None and field.default == val: |
428 |
| - assert field.name not in unstructured |
| 427 | + for attr, val in zip(fields(cl), vals): |
| 428 | + if attr.type is int and attr.default is not None and attr.default == val: |
| 429 | + assert attr.name not in unstructured |
429 | 430 |
|
430 | 431 |
|
431 | 432 | def test_calling_back():
|
@@ -744,6 +745,35 @@ class Test:
|
744 | 745 | assert isinstance(c.structure({}, Test), Test)
|
745 | 746 |
|
746 | 747 |
|
| 748 | +def test_legacy_structure_fallbacks(converter_cls: Type[BaseConverter]): |
| 749 | + """Restoring legacy behavior works.""" |
| 750 | + |
| 751 | + class Test: |
| 752 | + """Unsupported by default.""" |
| 753 | + |
| 754 | + def __init__(self, a): |
| 755 | + self.a = a |
| 756 | + |
| 757 | + c = converter_cls( |
| 758 | + structure_fallback_factory=lambda _: raise_error, detailed_validation=False |
| 759 | + ) |
| 760 | + |
| 761 | + # We can get the hook, but... |
| 762 | + hook = c.get_structure_hook(Test) |
| 763 | + |
| 764 | + # it won't work. |
| 765 | + with pytest.raises(StructureHandlerNotFoundError): |
| 766 | + hook({}, Test) |
| 767 | + |
| 768 | + # If a field has a converter, we honor that instead. |
| 769 | + @define |
| 770 | + class Container: |
| 771 | + a: Test = field(converter=Test) |
| 772 | + |
| 773 | + hook = c.get_structure_hook(Container) |
| 774 | + hook({"a": 1}, Container) |
| 775 | + |
| 776 | + |
747 | 777 | def test_fallback_chaining(converter_cls: Type[BaseConverter]):
|
748 | 778 | """Converters can be chained using fallback hooks."""
|
749 | 779 |
|
|
0 commit comments