diff --git a/HISTORY.md b/HISTORY.md index c62f0885..2a6727a0 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -26,6 +26,8 @@ ([#398](https://github.com/python-attrs/cattrs/issues/398) [#399](https://github.com/python-attrs/cattrs/pull/399)) - Broaden loads' type definition for the preconf orjson converter. ([#400](https://github.com/python-attrs/cattrs/pull/400)) +- `AttributeValidationNote` and `IterableValidationNote` are now pickable. + ([#408](https://github.com/python-attrs/cattrs/pull/408)) ## 23.1.2 (2023-06-02) diff --git a/src/cattrs/errors.py b/src/cattrs/errors.py index 20a5f5d0..9148bf10 100644 --- a/src/cattrs/errors.py +++ b/src/cattrs/errors.py @@ -40,6 +40,9 @@ def __new__( instance.type = type return instance + def __getnewargs__(self) -> Tuple[str, Union[int, str], Any]: + return (str(self), self.index, self.type) + class IterableValidationError(BaseValidationError): """Raised when structuring an iterable.""" @@ -76,6 +79,9 @@ def __new__(cls, string: str, name: str, type: Any) -> "AttributeValidationNote" instance.type = type return instance + def __getnewargs__(self) -> Tuple[str, str, Any]: + return (str(self), self.name, self.type) + class ClassValidationError(BaseValidationError): """Raised when validating a class if any attributes are invalid.""" diff --git a/tests/test_validation.py b/tests/test_validation.py index 9f371d12..d472bb15 100644 --- a/tests/test_validation.py +++ b/tests/test_validation.py @@ -2,13 +2,19 @@ from typing import Dict, FrozenSet, List, Set, Tuple import pytest +import pickle from attrs import define, field from attrs.validators import in_ from hypothesis import given from cattrs import Converter from cattrs._compat import Counter -from cattrs.errors import ClassValidationError, IterableValidationError +from cattrs.errors import ( + AttributeValidationNote, + ClassValidationError, + IterableValidationError, + IterableValidationNote, +) def test_class_validation(): @@ -178,3 +184,20 @@ def test_hetero_tuple_validation(): assert exc.value.exceptions[0].__notes__ == [ "Structuring typing.Tuple[int, int, int] @ index 2" ] + + +def test_notes_pickling(): + """Validation notes should be picklable""" + note = pickle.loads( # noqa: S301 + pickle.dumps(IterableValidationNote("foo", "key", str)) + ) + assert note == "foo" + assert note.index == "key" + assert note.type is str + + note = pickle.loads( # noqa: S301 + pickle.dumps(AttributeValidationNote("foo", "name", int)) + ) + assert note == "foo" + assert note.name == "name" + assert note.type is int