diff --git a/HISTORY.md b/HISTORY.md index e76cff20..a6c70b79 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -17,6 +17,8 @@ Our backwards-compatibility policy can be found [here](https://github.com/python ([#473](https://github.com/python-attrs/cattrs/pull/473)) - **Minor change**: Heterogeneous tuples are now unstructured into tuples instead of lists by default; this is significantly faster and widely supported by serialization libraries. ([#486](https://github.com/python-attrs/cattrs/pull/486)) +- **Minor change**: {py:func}`cattrs.gen.make_dict_structure_fn` will use the value for the `prefer_attrib_converters` parameter from the given converter by default now. + If you're using this function directly, the old behavior can be restored by passing in the desired values explicitly. - Introduce {meth}`BaseConverter.get_structure_hook` and {meth}`BaseConverter.get_unstructure_hook` methods. ([#432](https://github.com/python-attrs/cattrs/issues/432) [#472](https://github.com/python-attrs/cattrs/pull/472)) - {meth}`BaseConverter.register_structure_hook`, {meth}`BaseConverter.register_unstructure_hook`, diff --git a/src/cattrs/gen/__init__.py b/src/cattrs/gen/__init__.py index e7a93fd7..e8b40cf8 100644 --- a/src/cattrs/gen/__init__.py +++ b/src/cattrs/gen/__init__.py @@ -258,7 +258,9 @@ def make_dict_structure_fn( converter: BaseConverter, _cattrs_forbid_extra_keys: bool | Literal["from_converter"] = "from_converter", _cattrs_use_linecache: bool = True, - _cattrs_prefer_attrib_converters: bool = False, + _cattrs_prefer_attrib_converters: ( + bool | Literal["from_converter"] + ) = "from_converter", _cattrs_detailed_validation: bool | Literal["from_converter"] = "from_converter", _cattrs_use_alias: bool = False, _cattrs_include_init_false: bool = False, @@ -289,6 +291,9 @@ def make_dict_structure_fn( .. versionchanged:: 23.2.0 The `_cattrs_forbid_extra_keys` and `_cattrs_detailed_validation` parameters take their values from the given converter by default. + .. versionchanged:: 24.1.0 + The `_cattrs_prefer_attrib_converters` parameter takes its value from the given + converter by default. """ mapping = {} @@ -344,6 +349,8 @@ def make_dict_structure_fn( _cattrs_forbid_extra_keys = getattr(converter, "forbid_extra_keys", False) if _cattrs_detailed_validation == "from_converter": _cattrs_detailed_validation = converter.detailed_validation + if _cattrs_prefer_attrib_converters == "from_converter": + _cattrs_prefer_attrib_converters = converter._prefer_attrib_converters if _cattrs_forbid_extra_keys: globs["__c_a"] = allowed_fields diff --git a/tests/test_gen_dict.py b/tests/test_gen_dict.py index 5e5f5720..fe274503 100644 --- a/tests/test_gen_dict.py +++ b/tests/test_gen_dict.py @@ -633,6 +633,26 @@ class A: converter.structure({"a": "a"}, A) +@given(prefer=...) +def test_prefer_converters_from_converter(prefer: bool): + """ + `prefer_attrs_converters` is taken from the converter by default. + """ + + @define + class A: + a: int = field(converter=lambda x: x + 1) + + converter = BaseConverter(prefer_attrib_converters=prefer) + converter.register_structure_hook(int, lambda x, _: x + 1) + converter.register_structure_hook(A, make_dict_structure_fn(A, converter)) + + if prefer: + assert converter.structure({"a": 1}, A).a == 2 + else: + assert converter.structure({"a": 1}, A).a == 3 + + def test_fields_exception(): """fields() raises on a non-attrs, non-dataclass class.""" with pytest.raises(Exception): # noqa: B017