Releases: binary-butterfly/validataclass
0.11.0
This release makes the library PEP 561 compatible by adding a py.typed file. It also fixes some mypy issues that were previously ignored.
While there is still some work necessary to make the library fully compatible with mypy (see #116), this release enables mypy to detect the type annotations in the library without the need for stub files.
Important note / breaking changes
This update was originally released as patch version 0.10.1, but was then yanked and later re-released as a new minor version instead.
The update does not introduce any breaking changes in the code. However, it may result in mypy errors in your project which have previously not been discovered by mypy, thus leading to failing CI pipelines. Keep this in mind when updating the library.
Some of the issues found by mypy currently need to be ignored using # type: ignore comments, until the library is fully compatible with mypy (#116). Examples:
Return type "X" of "validate" incompatible with return type "Y" in supertype "SomeBaseValidator" [override]:
This can happen when you subclass a validator and change the return type of thevalidatemethod, which technically violates the Liskov substitution principle. However, in the case of validators, that's intentional.Item "UnsetValueType" of "X | UnsetValueType" has no attribute "Y":
This can happen despite of conditions likeif some_field is not UnsetValue:, because mypy doesn't know thatUnsetValueis a sentinel object, thus not being able to narrow down the type. A possible workaround that doesn't require# type: ignorewould be to define a Type Guard](https://mypy.readthedocs.io/en/stable/type_narrowing.html#user-defined-type-guards) and use that instead of the bare condition.
We will hopefully find better solutions for these problems in the future.
Added
- Add
py.typedfile to make the package PEP 561 compatible. #125
Fixed
- Explicitly re-export imports in
__init__.pyby defining__all__to fix mypy issues. #125
0.10.0
This release features custom pre-validation in dataclasses using the __pre_validate__() method and a change to the accepted format of datetimes in the DateTimeValidator to accept arbitrary decimal places after seconds.
This also is a "spring cleaning" release that contains a lot of miscellaneous refactorings and code cleanup, as well as some preparation for full mypy support (#116).
It also drops support for Python 3.7 and adds support for Python 3.12.
Added
- Official support for Python 3.12. #112
- Custom pre-validation in dataclasses using the
__pre_validate__class method. #115
Changed
DateTimeValidator: Accept datetimes with arbitrary precision (by @flauschzelle). #111, #113- This is not a breaking change, unless you specifically want to restrict datetime input strings to exactly 0, 3 or 6 decimal places after the seconds. It does not really matter for the result.
- Move
ValidationErrorbase class to separate modulevalidataclass.exceptions.base_exceptions. #117- This should not break any code as long as you import
ValidationErrorfrom thevalidataclass.exceptionspackage instead of thevalidataclass.exceptions.common_exceptionsmodule. If you do import it from the module, it should still work because the class is imported there as well, but you might get linter warnings.
- This should not break any code as long as you import
DataclassValidator: Simplify check and error handling for when the specified dataclass is not a dataclass. #120
Removed
- Breaking change: Drop support for Python 3.7. #118
- Remove
python-dateutilfrom install requirements. #122- This library was previously a dependency of validataclass. However, it was only needed in the unit tests, so it has been moved to the
testingextra requirements.
- This library was previously a dependency of validataclass. However, it was only needed in the unit tests, so it has been moved to the
Fixed
- Fix style of type comparisons in some unit tests (by @flauschzelle). #110
- Fix various typing issues reported by mypy, add missing type annotations and other related changes. #120, #121
Testing / CI
Miscellaneous
DateTimeValidator: Unify class docstring with Markdown documentation. #113- Miscellaneous code reformatting, more consistent docstrings, unit test refactoring. #119
New contributors
- @flauschzelle made her first contributions in #110 and #111.
0.9.0
This release adds official support for Python for Workgroups 3.11, as well as some minor changes.
Added
EmailValidator: Add parameterto_lowercase. #106
Changed
- Allow defining
__post_validate__()with specific context arguments without**kwargs. #105
Fixed
- Fix Python 3.11 incompatibilities due to
UnsetValuenot being hashable. #102 - Also fix missing
__hash__methods in theDefaultclasses (for completeness). #102
Testing / CI
0.8.1
Fixed
AnyOfValidatorandEnumValidator: Fixed wrong default value. Now the validators are really case-insensitive by default.
0.8.0
This release adds two new validators and a handful of new parameters to existing validators.
It also introduces two breaking changes, which in practice shouldn't really affect anyone negatively, and one deprecation of an existing validator parameter. See the changes below.
Added
AllowEmptyString: New wrapper validator that accepts empty strings (by @TomasHalgas). #91DiscardValidator: New validator that discards any input and always returns a predefined value. #94EmailValidatorandRegexValidator: Add parameterallow_emptyto allow empty strings (by @TomasHalgas). #89EmailValidator: Add parametermax_length. #97DecimalValidator: Add parameterroundingto specify rounding mode (with a new default, see "Changed"). #99
Changed
- Breaking change:
AnyOfValidatorandEnumValidatorare now case-sensitive by default. #98- The parameter
case_insensitiveis replaced with a new parametercase_sensitivewhich defaults to True. - The old parameter is still supported for compatibility, but is now deprecated and will be removed in a future version.
- If you have set
case_insensitive=Truebefore, you can simply remove this parameter now as this is the default now.
- The parameter
- Breaking change:
DecimalValidator(and all subclasses) now usesdecimal.ROUND_HALF_UPas default rounding mode. #99- Until now, the rounding mode of the current decimal context was used, which defaults to
decimal.ROUND_HALF_EVEN. - Use the
roundingparameter to change this. To restore the old behavior and use the decimal context, setrounding=None.
- Until now, the rounding mode of the current decimal context was used, which defaults to
Deprecated
AnyOfValidatorandEnumValidator: The parametercase_insensitiveis now deprecated and will be removed in a future version. (See "Changed" above.) #98
Testing
- Fix version incompatibility in test suite. #95
AnyOfValidator: Add unit tests with an empty list for allowed values. #96
New contributors
- @TomasHalgas made their first contributions in #89 and #91.
0.7.2
0.7.1
This small patch release improves type hinting for the @validataclass decorator and the DataclassValidation.
Changed
DataclassValidator: The exact type of the validator (e.g.DataclassValidator[MyDataclass]) and thus the return type ofvalidate()is now auto-deduced from the constructor arguments without an explicit type annotation. #84- The
@validataclassdecorator has (hopefully correct) type annotations now. #84
0.7.0 - Context-sensitive validation
This release mainly introduces context-sensitive (post-)validation. There are some more additions planned for this feature (e.g. dependencies between dataclass fields), but for now we have a solid base.
It also features a handful of smaller additions and changes, see below.
There is a potential breaking change (which probably won't affect anybody), and a sort of deprecation that will affect most custom validators in the future, so make sure to upgrade your validators as explained below.
Added
- Basic support for context-sensitive validation. #77
- All built-in validators now support arbitrary keyword arguments (so called context arguments) in the
validate()method. These can be used to change the behavior of a validator at validation time based on some kind of application context. Most validators don't do anything with them except passing them down to child validators (e.g. to the item validators in aListValidator, etc.), but you can implement custom validators that use them. - To keep compatibility with custom validators that do not accept context arguments yet, a provisional helper method
validate_with_context()was added to the baseValidatorclass. This method simply calls thevalidate()method, but checks whether it supports context arguments. If yes, context arguments are passed tovalidate(), elsevalidate()is called without any extra arguments. This method will become obsolete and eventually removed in the future, and should only be used in cases where it is unsure whether a validator supports context arguments.
- All built-in validators now support arbitrary keyword arguments (so called context arguments) in the
- Context-sensitive post-validation in dataclasses. #77
- The
DataclassValidatorwill now call the method__post_validate__()on your dataclass instances if you have defined this method. Additionally, if the method accepts arbitrary keyword arguments (i.e.**kwargs, although the name of this parameter doesn't matter), all context arguments will be passed to it. - You can use this to implement context-sensitive post-validation. For example, if you implement a
PATCHendpoint in a REST API, you could have fields that are sometimes optional and sometimes required, depending on a property of the object the user wants to update. You can now fetch the object before callingvalidate(), then pass the object (or just the property) as a context argument tovalidate(), and then access it in__post_validate__()to implement a context-sensitive field requirement check. - The
__post_init__()method of regular dataclasses can still be used for post-validation as before. It cannot be used context-sensitively, though, because we cannot pass arbitrary keyword arguments to it.
- The
DateTimeValidator: Add parameterdiscard_millisecondsto discard the milli- and microseconds of datetimes. #79AnyOfValidatorandEnumValidator: Add parametercase_insensitivefor case-insensitive string matching. #81- New helper function
unset_to_none()(returnsNoneif value isUnsetValue). #76
Changed
- All built-in validators now support context arguments in the
validate()method. See above. #77 - The
validate()method of theDataclassValidatorwas restructured a bit for easier extendability. (This may be subject of additional changes in the future, though.) #77 - The
@validataclassdecorator is now marked as a "data class transform" using the@dataclass_transformdecorator as specified in PEP 681. #78- Since this decorator was only introduced in Python 3.11, we use the typing-extensions library which backports new typing features like this.
ListValidatorandEnumValidatorare now defined as generic classes for better type hinting. #80AnyOfValidatorandEnumValidatornow acceptallowed_valuesandallowed_typesas any iterable. #80AnyOfValidatorandEnumValidator: TheValueNotAllowedErrornow lists all allowed values (unless they are more than 20). #81
Deprecated
- Validator classes that do not accept context arguments are now deprecated. #77
- When defining a
Validatorsubclass, the__init_subclass__()method will check whether yourvalidate()method accepts arbitrary keyword arguments. If not, aDeprecationWarningwill be issued. - Existing custom validators will keep working for now, but this compatibility will be removed in version 1.0.
- To update your custom validators, simply add
**kwargsto the parameter list ofvalidate(). If your validator class is based on an existing validator, make sure to pass the context arguments down to thevalidate()of your base class as well, i.e.super().validate(input_data, **kwargs).
- When defining a
Removed
- Breaking change: The
post_validate()method of theDataclassValidatorwas removed. #77- (This should not to be confused with the new
__post_validate__(), however, which is a method of dataclasses, not of the validator itself.) - This method was removed because a) post-validation using either
__post_init__()or the new__post_validate__()method in the dataclass should be preferred, b) the validator was restructured in a way that makes this method redundant, and c) it was probably never used anyway. - If you do need post-validation as part of a subclassed
DataclassValidator, you can extend eithervalidate()or the new_post_validate()private method (but make sure to extend, not override it, since it also handles the call of the dataclass's__post_validate__()method).
- (This should not to be confused with the new
0.6.2 - Fix bug with multiple inheritance
This release fixes a bug with multiple inheritance in validataclasses.
Fixed
- Fix overriding of existing field properties in validataclasses with multiple inheritance. #71