Skip to content

Commit 3dcd6fe

Browse files
raabfTinche
authored andcommitted
For forbid_extra_keys raise custom ForbiddenExtraKeyError instead of generic Exception.
1 parent 5675952 commit 3dcd6fe

File tree

6 files changed

+15
-8
lines changed

6 files changed

+15
-8
lines changed

HISTORY.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ History
1818
(`#231 <https://github.com/python-attrs/cattrs/pull/231>`_)
1919
* Fix unstructuring all tuples - unannotated, variable-length, homogenous and heterogenous - to `list`.
2020
(`#226 <https://github.com/python-attrs/cattrs/issues/226>`_)
21-
21+
* For ``forbid_extra_keys`` raise custom ``ForbiddenExtraKeyError`` instead of generic ``Exception``.
22+
(`#255 <https://github.com/python-attrs/cattrs/pull/225>`_)
2223

2324
1.10.0 (2022-01-04)
2425
-------------------

docs/customizing.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ creating structure hooks with ``make_dict_structure_fn``.
108108
>>> c.structure({"nummber": 2}, TestClass)
109109
Traceback (most recent call last):
110110
...
111-
Exception: Extra fields in constructor for TestClass: nummber
111+
ForbiddenExtraKeyError: Extra fields in constructor for TestClass: nummber
112112
>>> hook = make_dict_structure_fn(TestClass, c, _cattrs_forbid_extra_keys=False)
113113
>>> c.register_structure_hook(TestClass, hook)
114114
>>> c.structure({"nummber": 2}, TestClass)

docs/structuring.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ Here's a small example showing how to use factory hooks to apply the `forbid_ext
473473
>>> c.structure({"an_int": 1, "else": 2}, E)
474474
Traceback (most recent call last):
475475
...
476-
Exception: Extra fields in constructor for E: else
476+
ForbiddenExtraKeyError: Extra fields in constructor for E: else
477477
478478
479479
A complex use case for hook factories is described over at :ref:`Using factory hooks`.

src/cattrs/errors.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,7 @@ class ClassValidationError(BaseValidationError):
3333
"""Raised when validating a class if any attributes are invalid."""
3434

3535
pass
36+
37+
38+
class ForbiddenExtraKeyError(Exception):
39+
"""Raised when `forbid_extra_keys` is activated and such an extra key is detected during structuring."""

src/cattrs/gen.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,10 +447,11 @@ def make_dict_structure_fn(
447447

448448
if _cattrs_forbid_extra_keys:
449449
globs["__c_a"] = allowed_fields
450+
globs["ForbiddenExtraKeyError"] = ForbiddenExtraKeyError
450451
post_lines += [
451452
" unknown_fields = set(o.keys()) - __c_a",
452453
" if unknown_fields:",
453-
" raise Exception(",
454+
" raise ForbiddenExtraKeyError(",
454455
f" 'Extra fields in constructor for {cl_name}: ' + ', '.join(unknown_fields)"
455456
" )",
456457
]

tests/metadata/test_genconverter.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from cattr import GenConverter as Converter
2020
from cattr import UnstructureStrategy
2121
from cattr._compat import is_py39_plus, is_py310_plus
22+
from cattrs.errors import ForbiddenExtraKeyError
2223
from cattr.gen import make_dict_structure_fn, override
2324

2425
from . import (
@@ -87,7 +88,7 @@ def test_forbid_extra_keys(cls_and_vals):
8788
while bad_key in unstructured:
8889
bad_key += "A"
8990
unstructured[bad_key] = 1
90-
with pytest.raises(Exception):
91+
with pytest.raises(ForbiddenExtraKeyError):
9192
converter.structure(unstructured, cl)
9293

9394

@@ -102,7 +103,7 @@ def test_forbid_extra_keys_defaults(attr_and_vals):
102103
inst = cl()
103104
unstructured = converter.unstructure(inst)
104105
unstructured["aa"] = unstructured.pop("a")
105-
with pytest.raises(Exception):
106+
with pytest.raises(ForbiddenExtraKeyError):
106107
converter.structure(unstructured, cl)
107108

108109

@@ -122,15 +123,15 @@ class A:
122123
converter.structure(unstructured, A)
123124
# if we break it in the subclass, we need it to raise
124125
unstructured["c"]["aa"] = 5
125-
with pytest.raises(Exception):
126+
with pytest.raises(ForbiddenExtraKeyError):
126127
converter.structure(unstructured, A)
127128
# we can "fix" that by disabling forbid_extra_keys on the subclass
128129
hook = make_dict_structure_fn(C, converter, _cattrs_forbid_extra_keys=False)
129130
converter.register_structure_hook(C, hook)
130131
converter.structure(unstructured, A)
131132
# but we should still raise at the top level
132133
unstructured["b"] = 6
133-
with pytest.raises(Exception):
134+
with pytest.raises(ForbiddenExtraKeyError):
134135
converter.structure(unstructured, A)
135136

136137

0 commit comments

Comments
 (0)