2020from cattr import UnstructureStrategy
2121from cattr ._compat import is_py39_plus , is_py310_plus
2222from cattr .gen import make_dict_structure_fn , override
23- from cattrs .errors import ForbiddenExtraKeysError
23+ from cattrs .errors import ClassValidationError , ForbiddenExtraKeysError
2424
2525from . import (
2626 nested_typed_classes ,
@@ -88,11 +88,13 @@ def test_forbid_extra_keys(cls_and_vals):
8888 while bad_key in unstructured :
8989 bad_key += "A"
9090 unstructured [bad_key ] = 1
91- with pytest .raises (ForbiddenExtraKeysError ) as feke :
91+ with pytest .raises (ClassValidationError ) as cve :
9292 converter .structure (unstructured , cl )
9393
94- assert feke .value .cl is cl
95- assert feke .value .extra_fields == {bad_key }
94+ assert len (cve .value .exceptions ) == 1
95+ assert isinstance (cve .value .exceptions [0 ], ForbiddenExtraKeysError )
96+ assert cve .value .exceptions [0 ].cl is cl
97+ assert cve .value .exceptions [0 ].extra_fields == {bad_key }
9698
9799
98100@given (simple_typed_attrs (defaults = True ))
@@ -106,11 +108,13 @@ def test_forbid_extra_keys_defaults(attr_and_vals):
106108 inst = cl ()
107109 unstructured = converter .unstructure (inst )
108110 unstructured ["aa" ] = unstructured .pop ("a" )
109- with pytest .raises (ForbiddenExtraKeysError ) as feke :
111+ with pytest .raises (ClassValidationError ) as cve :
110112 converter .structure (unstructured , cl )
111113
112- assert feke .value .cl is cl
113- assert feke .value .extra_fields == {"aa" }
114+ assert len (cve .value .exceptions ) == 1
115+ assert isinstance (cve .value .exceptions [0 ], ForbiddenExtraKeysError )
116+ assert cve .value .exceptions [0 ].cl is cl
117+ assert cve .value .exceptions [0 ].extra_fields == {"aa" }
114118
115119
116120def test_forbid_extra_keys_nested_override ():
@@ -129,17 +133,30 @@ class A:
129133 converter .structure (unstructured , A )
130134 # if we break it in the subclass, we need it to raise
131135 unstructured ["c" ]["aa" ] = 5
132- with pytest .raises (ForbiddenExtraKeysError ) :
136+ with pytest .raises (ClassValidationError ) as cve :
133137 converter .structure (unstructured , A )
138+
139+ assert len (cve .value .exceptions ) == 1
140+ assert isinstance (cve .value .exceptions [0 ], ClassValidationError )
141+ assert len (cve .value .exceptions [0 ].exceptions ) == 1
142+ assert isinstance (cve .value .exceptions [0 ].exceptions [0 ], ForbiddenExtraKeysError )
143+ assert cve .value .exceptions [0 ].exceptions [0 ].cl is C
144+ assert cve .value .exceptions [0 ].exceptions [0 ].extra_fields == {"aa" }
145+
134146 # we can "fix" that by disabling forbid_extra_keys on the subclass
135147 hook = make_dict_structure_fn (C , converter , _cattrs_forbid_extra_keys = False )
136148 converter .register_structure_hook (C , hook )
137149 converter .structure (unstructured , A )
138150 # but we should still raise at the top level
139151 unstructured ["b" ] = 6
140- with pytest .raises (ForbiddenExtraKeysError ) :
152+ with pytest .raises (ClassValidationError ) as cve :
141153 converter .structure (unstructured , A )
142154
155+ assert len (cve .value .exceptions ) == 1
156+ assert isinstance (cve .value .exceptions [0 ], ForbiddenExtraKeysError )
157+ assert cve .value .exceptions [0 ].cl is A
158+ assert cve .value .exceptions [0 ].extra_fields == {"b" }
159+
143160
144161@given (nested_typed_classes (defaults = True , min_attrs = 1 ), unstructure_strats , booleans ())
145162def test_nested_roundtrip (cls_and_vals , strat , omit_if_default ):
0 commit comments