20
20
from cattr import UnstructureStrategy
21
21
from cattr ._compat import is_py39_plus , is_py310_plus
22
22
from cattr .gen import make_dict_structure_fn , override
23
- from cattrs .errors import ForbiddenExtraKeysError
23
+ from cattrs .errors import ClassValidationError , ForbiddenExtraKeysError
24
24
25
25
from . import (
26
26
nested_typed_classes ,
@@ -88,11 +88,13 @@ def test_forbid_extra_keys(cls_and_vals):
88
88
while bad_key in unstructured :
89
89
bad_key += "A"
90
90
unstructured [bad_key ] = 1
91
- with pytest .raises (ForbiddenExtraKeysError ) as feke :
91
+ with pytest .raises (ClassValidationError ) as cve :
92
92
converter .structure (unstructured , cl )
93
93
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 }
96
98
97
99
98
100
@given (simple_typed_attrs (defaults = True ))
@@ -106,11 +108,13 @@ def test_forbid_extra_keys_defaults(attr_and_vals):
106
108
inst = cl ()
107
109
unstructured = converter .unstructure (inst )
108
110
unstructured ["aa" ] = unstructured .pop ("a" )
109
- with pytest .raises (ForbiddenExtraKeysError ) as feke :
111
+ with pytest .raises (ClassValidationError ) as cve :
110
112
converter .structure (unstructured , cl )
111
113
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" }
114
118
115
119
116
120
def test_forbid_extra_keys_nested_override ():
@@ -129,17 +133,30 @@ class A:
129
133
converter .structure (unstructured , A )
130
134
# if we break it in the subclass, we need it to raise
131
135
unstructured ["c" ]["aa" ] = 5
132
- with pytest .raises (ForbiddenExtraKeysError ) :
136
+ with pytest .raises (ClassValidationError ) as cve :
133
137
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
+
134
146
# we can "fix" that by disabling forbid_extra_keys on the subclass
135
147
hook = make_dict_structure_fn (C , converter , _cattrs_forbid_extra_keys = False )
136
148
converter .register_structure_hook (C , hook )
137
149
converter .structure (unstructured , A )
138
150
# but we should still raise at the top level
139
151
unstructured ["b" ] = 6
140
- with pytest .raises (ForbiddenExtraKeysError ) :
152
+ with pytest .raises (ClassValidationError ) as cve :
141
153
converter .structure (unstructured , A )
142
154
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
+
143
160
144
161
@given (nested_typed_classes (defaults = True , min_attrs = 1 ), unstructure_strats , booleans ())
145
162
def test_nested_roundtrip (cls_and_vals , strat , omit_if_default ):
0 commit comments