Skip to content

Commit 71d4d72

Browse files
committed
rename prevent_additional_properties to reject_unknown_fields
1 parent 91cf1dd commit 71d4d72

7 files changed

Lines changed: 66 additions & 66 deletions

File tree

docs/05-dataclasses.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -297,28 +297,28 @@ It is also worth noting that you can use the `@validataclass` decorator with opt
297297
being applied to the class.
298298

299299

300-
## Prevent additional properties
300+
## Reject unknown fields
301301

302-
Per default, validataclass just ignores any additional properties in the input dictionary when validating an object.
303-
This makes sense for normal APIs, as additional fields are just filtered out, and it makes validataclass more robust to
304-
changes in the API. There might be situations where one needs to have a strict validation of additional parameters,
305-
for example, to match an OpenAPI validation.
302+
Per default, validataclass just ignores any unknown fields in the input dictionary when validating an object.
303+
This makes sense for normal APIs, as additional fields are just filtered out, and it makes validataclass more robust to
304+
changes in the API. There might be situations where one needs to have a strict validation of additional fields,
305+
for example, to match an OpenAPI validation.
306306

307-
You can prevent additional properties by setting `prevent_additional_properties` at the `@validataclass` to `True`,
307+
You can reject unknown fields by setting `reject_unknown_fields` at the `@validataclass` to `True`,
308308
like this:
309309

310310
```python
311311
from validataclass.dataclasses import validataclass
312312
from validataclass.validators import DataclassValidator, StringValidator
313313

314-
@validataclass(prevent_additional_properties=True)
314+
@validataclass(reject_unknown_fields=True)
315315
class MyModel:
316316
name: str = StringValidator()
317317

318318
my_validator = DataclassValidator(MyModel)
319319

320320
my_validator.validate({'name': 'test'}) # would work fine
321-
my_validator.validate({'name': 'test', 'more': 'stuff'}) # would throw an AdditionalPropertiesError
321+
my_validator.validate({'name': 'test', 'more': 'stuff'}) # would throw an UnknownFieldsError
322322
```
323323

324324

src/validataclass/dataclasses/validataclass.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ class ExampleDataclass:
9090

9191
def decorator(_cls: type[_T]) -> type[_T]:
9292
# Pop validataclass-specific options before passing kwargs to @dataclass
93-
prevent_additional_properties = kwargs.pop('prevent_additional_properties', False)
93+
reject_unknown_fields = kwargs.pop('reject_unknown_fields', False)
9494

9595
# Set kw_only=True as the default to allow required and optional fields in any order
9696
kwargs.setdefault('kw_only', True)
@@ -102,7 +102,7 @@ def decorator(_cls: type[_T]) -> type[_T]:
102102
_cls = dataclasses.dataclass(**kwargs)(_cls)
103103

104104
# Store validataclass-specific settings on the class
105-
_cls.__prevent_additional_properties__ = prevent_additional_properties # type: ignore[attr-defined]
105+
_cls.__reject_unknown_fields__ = reject_unknown_fields # type: ignore[attr-defined]
106106

107107
return _cls
108108

src/validataclass/exceptions/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
InvalidTypeError,
1111
RequiredValueError,
1212
)
13-
from .dataclass_exceptions import AdditionalPropertiesError, DataclassPostValidationError
13+
from .dataclass_exceptions import UnknownFieldsError, DataclassPostValidationError
1414
from .datetime_exceptions import (
1515
DateTimeRangeError,
1616
InvalidDateError,
@@ -50,7 +50,7 @@
5050
from .url_exceptions import InvalidUrlError
5151

5252
__all__ = [
53-
'AdditionalPropertiesError',
53+
'UnknownFieldsError',
5454
'DataclassInvalidPreValidateSignatureException',
5555
'DataclassPostValidationError',
5656
'DataclassValidatorFieldException',

src/validataclass/exceptions/dataclass_exceptions.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,31 +11,31 @@
1111
from .base_exceptions import ValidationError
1212

1313
__all__ = [
14-
'AdditionalPropertiesError',
14+
'UnknownFieldsError',
1515
'DataclassPostValidationError',
1616
]
1717

1818

19-
class AdditionalPropertiesError(ValidationError):
19+
class UnknownFieldsError(ValidationError):
2020
"""
2121
Validation error raised by `DataclassValidator` when the input dictionary contains keys that do not correspond to
22-
any field in the dataclass, and `prevent_additional_properties` is set to `True`.
22+
any field in the dataclass, and `reject_unknown_fields` is set to `True`.
2323
24-
The `additional_properties` attribute contains a sorted list of the extra field names.
24+
The `unknown_fields` attribute contains a sorted list of the extra field names.
2525
2626
Example as dictionary:
2727
2828
```
2929
{
30-
'code': 'additional_properties',
31-
'additional_properties': ['unknown1', 'unknown2'],
30+
'code': 'unknown_fields',
31+
'unknown_fields': ['unknown1', 'unknown2'],
3232
}
3333
```
3434
"""
35-
code = 'additional_properties'
35+
code = 'unknown_fields'
3636

37-
def __init__(self, *, additional_properties: list[str], **kwargs: Any):
38-
super().__init__(additional_properties=sorted(additional_properties), **kwargs)
37+
def __init__(self, *, unknown_fields: list[str], **kwargs: Any):
38+
super().__init__(unknown_fields=sorted(unknown_fields), **kwargs)
3939

4040

4141
class DataclassPostValidationError(ValidationError):

src/validataclass/validators/dataclass_validator.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
from validataclass.dataclasses import BaseDefault, NoDefault
1515
from validataclass.exceptions import (
16-
AdditionalPropertiesError,
16+
UnknownFieldsError,
1717
DataclassInvalidPreValidateSignatureException,
1818
DataclassPostValidationError,
1919
DataclassValidatorFieldException,
@@ -115,8 +115,8 @@ def __post_validate__(self, *, require_optional_field: bool = False):
115115
# Dataclass type that the validated dictionary will be converted to
116116
dataclass_cls: type[T_Dataclass]
117117

118-
# Whether to prevent additional properties in the input dictionary
119-
prevent_additional_properties: bool
118+
# Whether to reject unknown fields in the input dictionary
119+
reject_unknown_fields: bool
120120

121121
# Field default values
122122
field_defaults: dict[str, BaseDefault[Any]]
@@ -138,7 +138,7 @@ def __init__(self, dataclass_cls: type[T_Dataclass] | None = None) -> None:
138138
raise InvalidValidatorOptionException('Parameter "dataclass_cls" must be a dataclass type.')
139139

140140
self.dataclass_cls = dataclass_cls
141-
self.prevent_additional_properties = getattr(dataclass_cls, '__prevent_additional_properties__', False)
141+
self.reject_unknown_fields = getattr(dataclass_cls, '__reject_unknown_fields__', False)
142142
self.field_defaults = {}
143143

144144
# Collect field validators and required fields for the DictValidator by examining the dataclass fields
@@ -233,12 +233,12 @@ def _pre_validate(self, input_data: Any, **kwargs: Any) -> dict[str, Any]:
233233
# Filter input dictionary through __pre_validate__()
234234
input_data = pre_validate_func(input_data, **context_kwargs)
235235

236-
# Check for additional properties if not allowed
237-
if self.prevent_additional_properties:
236+
# Check for unknown fields if not allowed
237+
if self.reject_unknown_fields:
238238
self._ensure_type(input_data, dict)
239-
additional = sorted(set(input_data.keys()) - set(self.field_validators.keys()))
240-
if additional:
241-
raise AdditionalPropertiesError(additional_properties=additional)
239+
unknown = sorted(set(input_data.keys()) - set(self.field_validators.keys()))
240+
if unknown:
241+
raise UnknownFieldsError(unknown_fields=unknown)
242242

243243
# Validate raw dictionary using underlying DictValidator
244244
validated_dict = self.dict_validator.validate(input_data, **kwargs)

tests/unit/exceptions/dataclass_exceptions_test.py

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,48 +5,48 @@
55
"""
66

77
from validataclass.exceptions import (
8-
AdditionalPropertiesError,
8+
UnknownFieldsError,
99
DataclassPostValidationError,
1010
DictRequiredFieldError,
1111
InvalidTypeError,
1212
ValidationError,
1313
)
1414

1515

16-
class AdditionalPropertiesErrorTest:
16+
class UnknownFieldsErrorTest:
1717
"""
18-
Tests for the AdditionalPropertiesError exception class.
18+
Tests for the UnknownFieldsError exception class.
1919
"""
2020

2121
@staticmethod
22-
def test_additional_properties_error_single_property():
23-
""" Tests AdditionalPropertiesError with a single additional property. """
24-
error = AdditionalPropertiesError(additional_properties=['unknown_field'])
22+
def test_unknown_fields_error_single_property():
23+
""" Tests UnknownFieldsError with a single additional property. """
24+
error = UnknownFieldsError(unknown_fields=['unknown_field'])
2525

2626
assert error.to_dict() == {
27-
'code': 'additional_properties',
28-
'additional_properties': ['unknown_field'],
27+
'code': 'unknown_fields',
28+
'unknown_fields': ['unknown_field'],
2929
}
3030

3131
@staticmethod
32-
def test_additional_properties_error_multiple_properties():
33-
""" Tests AdditionalPropertiesError with multiple additional properties (sorted). """
34-
error = AdditionalPropertiesError(additional_properties=['watermelon', 'apple', 'mango'])
32+
def test_unknown_fields_error_multiple_fields():
33+
""" Tests UnknownFieldsError with multiple additional fields (sorted). """
34+
error = UnknownFieldsError(unknown_fields=['watermelon', 'apple', 'mango'])
3535

3636
assert error.to_dict() == {
37-
'code': 'additional_properties',
38-
'additional_properties': ['apple', 'mango', 'watermelon'],
37+
'code': 'unknown_fields',
38+
'unknown_fields': ['apple', 'mango', 'watermelon'],
3939
}
4040

4141
@staticmethod
42-
def test_additional_properties_error_repr():
43-
""" Tests repr of AdditionalPropertiesError. """
44-
error = AdditionalPropertiesError(additional_properties=['unknown1', 'unknown2'])
42+
def test_unknown_fields_error_repr():
43+
""" Tests repr of UnknownFieldsError. """
44+
error = UnknownFieldsError(unknown_fields=['unknown1', 'unknown2'])
4545

4646
assert (
4747
repr(error)
48-
== "AdditionalPropertiesError(code='additional_properties', "
49-
"additional_properties=['unknown1', 'unknown2'])"
48+
== "UnknownFieldsError(code='unknown_fields', "
49+
"unknown_fields=['unknown1', 'unknown2'])"
5050
)
5151
assert str(error) == repr(error)
5252

tests/unit/validators/dataclass_validator_test.py

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from tests.test_utils import UnitTestContextValidator
1515
from validataclass.dataclasses import Default, DefaultFactory, DefaultUnset, validataclass, validataclass_field
1616
from validataclass.exceptions import (
17-
AdditionalPropertiesError,
17+
UnknownFieldsError,
1818
DataclassInvalidPreValidateSignatureException,
1919
DataclassPostValidationError,
2020
DataclassValidatorFieldException,
@@ -60,9 +60,9 @@ class UnitTestNestedDataclass:
6060
validataclass_field(DataclassValidator(UnitTestDataclass), default=Default(None))
6161

6262

63-
# Dataclass with prevent_additional_properties=True
63+
# Dataclass with reject_unknown_fields=True
6464

65-
@validataclass(prevent_additional_properties=True)
65+
@validataclass(reject_unknown_fields=True)
6666
class UnitTestStrictDataclass:
6767
"""
6868
Dataclass that does not allow additional properties in the input dictionary.
@@ -1151,8 +1151,8 @@ class IncompatibleDataclass:
11511151
str(exception_info.value)
11521152
== 'Default specified for dataclass field "foo" is not an instance of "BaseDefault".'
11531153
)
1154-
# Tests for prevent_additional_properties option
11551154

1155+
# Tests for reject_unknown_fields option
11561156
@staticmethod
11571157
def test_strict_dataclass_valid():
11581158
""" Validate a strict dataclass with no extra keys. """
@@ -1180,26 +1180,26 @@ def test_strict_dataclass_valid_with_optional_field_omitted():
11801180

11811181
@staticmethod
11821182
def test_strict_dataclass_with_additional_properties():
1183-
""" Test that a strict dataclass raises AdditionalPropertiesError for unknown keys. """
1183+
""" Test that a strict dataclass raises UnknownFieldsError for unknown keys. """
11841184
validator = DataclassValidator(UnitTestStrictDataclass)
11851185

1186-
with pytest.raises(AdditionalPropertiesError) as exception_info:
1186+
with pytest.raises(UnknownFieldsError) as exception_info:
11871187
validator.validate({
11881188
'name': 'banana',
11891189
'unknown_field': 'unknown_value',
11901190
})
11911191

11921192
assert exception_info.value.to_dict() == {
1193-
'code': 'additional_properties',
1194-
'additional_properties': ['unknown_field'],
1193+
'code': 'unknown_fields',
1194+
'unknown_fields': ['unknown_field'],
11951195
}
11961196

11971197
@staticmethod
1198-
def test_strict_dataclass_with_multiple_additional_properties():
1199-
""" Test that additional properties are sorted in the error. """
1198+
def test_strict_dataclass_with_multiple_additional_fields():
1199+
""" Test that additional fields are sorted in the error. """
12001200
validator = DataclassValidator(UnitTestStrictDataclass)
12011201

1202-
with pytest.raises(AdditionalPropertiesError) as exception_info:
1202+
with pytest.raises(UnknownFieldsError) as exception_info:
12031203
validator.validate({
12041204
'name': 'banana',
12051205
'zebra': 1,
@@ -1208,13 +1208,13 @@ def test_strict_dataclass_with_multiple_additional_properties():
12081208
})
12091209

12101210
assert exception_info.value.to_dict() == {
1211-
'code': 'additional_properties',
1212-
'additional_properties': ['alpha', 'mango', 'zebra'],
1211+
'code': 'unknown_fields',
1212+
'unknown_fields': ['alpha', 'mango', 'zebra'],
12131213
}
12141214

12151215
@staticmethod
1216-
def test_default_allows_additional_properties():
1217-
""" Test that by default (prevent_additional_properties=False), unknown keys are silently ignored. """
1216+
def test_default_allows_additional_fields():
1217+
""" Test that by default (reject_unknown_fields=False), unknown keys are silently ignored. """
12181218
validator = DataclassValidator(UnitTestDataclass)
12191219
validated_data = validator.validate({
12201220
'name': 'banana',
@@ -1228,10 +1228,10 @@ def test_default_allows_additional_properties():
12281228
assert validated_data.name == 'banana'
12291229

12301230
@staticmethod
1231-
def test_explicit_prevent_additional_properties_false():
1232-
""" Test that prevent_additional_properties=False explicitly allows unknown keys. """
1231+
def test_explicit_reject_unknown_fields_false():
1232+
""" Test that reject_unknown_fields=False explicitly allows unknown keys. """
12331233

1234-
@validataclass(prevent_additional_properties=False)
1234+
@validataclass(reject_unknown_fields=False)
12351235
class ExplicitAllowDataclass:
12361236
name: str = StringValidator()
12371237

0 commit comments

Comments
 (0)