Skip to content

Commit 45782ff

Browse files
authored
Merge pull request #82 from binary-butterfly/release-0.7.0
Prepare release of 0.7.0
2 parents f357fda + 94a431c commit 45782ff

File tree

8 files changed

+120
-26
lines changed

8 files changed

+120
-26
lines changed

.github/workflows/tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ jobs:
4343
uses: actions/upload-artifact@v3
4444
if: success() || failure()
4545
with:
46-
# This will add every pytest_VERSION.yml to the same artifact file
46+
# This will add every pytest_VERSION.xml to the same artifact file
4747
name: pytest-results
4848
path: reports/pytest_${{ matrix.python-version }}.xml
4949

CHANGELOG.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,88 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

88

9+
## [0.7.0](https://github.com/binary-butterfly/validataclass/releases/tag/0.7.0) - 2022-09-22
10+
11+
[Full changelog](https://github.com/binary-butterfly/validataclass/compare/0.6.2...0.7.0)
12+
13+
This release mainly introduces **context-sensitive (post-)validation**. There are some more additions planned for this
14+
feature (e.g. dependencies between dataclass fields), but for now we have a solid base.
15+
16+
It also features a handful of smaller additions and changes, see below.
17+
18+
There is a potential **breaking change** (which probably won't affect anybody), and a sort of **deprecation** that
19+
**will** affect most custom validators in the future, so make sure to upgrade your validators as explained below.
20+
21+
### Added
22+
23+
- Basic support for **context-sensitive validation**. [#77]
24+
- All built-in validators now support arbitrary keyword arguments (so called **context arguments**) in the `validate()`
25+
method. These can be used to change the behavior of a validator at validation time based on some kind of application
26+
context. Most validators don't do anything with them except passing them down to child validators (e.g. to the item
27+
validators in a `ListValidator`, etc.), but you can implement custom validators that use them.
28+
- To keep compatibility with custom validators that do not accept context arguments yet, a **provisional** helper
29+
method `validate_with_context()` was added to the base `Validator` class. This method simply calls the `validate()`
30+
method, but checks whether it supports context arguments. If yes, context arguments are passed to `validate()`,
31+
else `validate()` is called without any extra arguments. This method will become obsolete and eventually removed in
32+
the future, and should only be used in cases where it is unsure whether a validator supports context arguments.
33+
- Context-sensitive **post-validation in dataclasses**. [#77]
34+
- The `DataclassValidator` will now call the method `__post_validate__()` on your dataclass instances if you have
35+
defined this method. Additionally, if the method accepts arbitrary keyword arguments (i.e. `**kwargs`, although the
36+
name of this parameter doesn't matter), all context arguments will be passed to it.
37+
- You can use this to implement context-sensitive post-validation. For example, if you implement a `PATCH` endpoint in
38+
a REST API, you could have fields that are sometimes optional and sometimes required, depending on a property of the
39+
object the user wants to update. You can now fetch the object before calling `validate()`, then pass the object (or
40+
just the property) as a context argument to `validate()`, and then access it in `__post_validate__()` to implement a
41+
context-sensitive field requirement check.
42+
- The `__post_init__()` method of regular dataclasses can still be used for post-validation as before. It cannot be
43+
used context-sensitively, though, because we cannot pass arbitrary keyword arguments to it.
44+
- `DateTimeValidator`: Add parameter `discard_milliseconds` to discard the milli- and microseconds of datetimes. [#79]
45+
- `AnyOfValidator` and `EnumValidator`: Add parameter `case_insensitive` for case-insensitive string matching. [#81]
46+
- New helper function `unset_to_none()` (returns `None` if value is `UnsetValue`). [#76]
47+
48+
### Changed
49+
50+
- All built-in validators now support context arguments in the `validate()` method. See above. [#77]
51+
- The `validate()` method of the `DataclassValidator` was restructured a bit for easier extendability. (This may be
52+
subject of additional changes in the future, though.) [#77]
53+
- The `@validataclass` decorator is now marked as a "data class transform" using the `@dataclass_transform` decorator
54+
as specified in [PEP 681](https://peps.python.org/pep-0681/). [#78]
55+
- Since this decorator was only introduced in Python 3.11, we use the [typing-extensions](https://pypi.org/project/typing-extensions/)
56+
library which backports new typing features like this.
57+
- `ListValidator` and `EnumValidator` are now defined as generic classes for better type hinting. [#80]
58+
- `AnyOfValidator` and `EnumValidator` now accept `allowed_values` and `allowed_types` as any iterable. [#80]
59+
- `AnyOfValidator` and `EnumValidator`: The `ValueNotAllowedError` now lists all allowed values (unless they are more than 20). [#81]
60+
61+
### Deprecated
62+
63+
- Validator classes that do not accept context arguments are now deprecated. [#77]
64+
- When defining a `Validator` subclass, the `__init_subclass__()` method will check whether your `validate()` method
65+
accepts arbitrary keyword arguments. If not, a `DeprecationWarning` will be issued.
66+
- Existing custom validators will keep working for now, but this compatibility will be removed in version 1.0.
67+
- To update your custom validators, simply add `**kwargs` to the parameter list of `validate()`. If your validator
68+
class is based on an existing validator, make sure to pass the context arguments down to the `validate()` of your
69+
base class as well, i.e. `super().validate(input_data, **kwargs)`.
70+
71+
### Removed
72+
73+
- **Breaking change:** The `post_validate()` method of the `DataclassValidator` was **removed**. [#77]
74+
- (This should not to be confused with the new `__post_validate__()`, however, which is a method of dataclasses, not
75+
of the validator itself.)
76+
- This method was removed because a) post-validation using either `__post_init__()` or the new `__post_validate__()`
77+
method in the dataclass should be preferred, b) the validator was restructured in a way that makes this method
78+
redundant, and c) it was probably never used anyway.
79+
- If you do need post-validation as part of a subclassed `DataclassValidator`, you can extend either `validate()` or
80+
the new `_post_validate()` private method (but make sure to extend, not override it, since it also handles the call
81+
of the dataclass's `__post_validate__()` method).
82+
83+
[#76]: https://github.com/binary-butterfly/validataclass/pull/76
84+
[#77]: https://github.com/binary-butterfly/validataclass/pull/77
85+
[#78]: https://github.com/binary-butterfly/validataclass/pull/78
86+
[#79]: https://github.com/binary-butterfly/validataclass/pull/79
87+
[#80]: https://github.com/binary-butterfly/validataclass/pull/80
88+
[#81]: https://github.com/binary-butterfly/validataclass/pull/81
89+
90+
991
## [0.6.2](https://github.com/binary-butterfly/validataclass/releases/tag/0.6.2) - 2022-07-11
1092

1193
[Full changelog](https://github.com/binary-butterfly/validataclass/compare/0.6.1...0.6.2)

Makefile

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,21 @@
33
DOCKER_MULTI_PYTHON_IMAGE = gnufede/multi-python:focal
44
DOCKER_USER = "$(shell id -u):$(shell id -g)"
55

6-
.PHONY: all venv build \
7-
tox test flake8 open-coverage \
8-
docker-tox docker-tox-py37 docker-tox-py38 docker-tox-py39 docker-tox-py310 docker-tox-all docker-pull \
9-
clean clean-dist clean-all
10-
116
# Default target
12-
all: tox
7+
.DEFAULT_GOAL := tox
138

149

1510
# Development environment
1611
# -----------------------
1712

1813
# Install a virtualenv
14+
.PHONY: venv
1915
venv:
2016
virtualenv venv
21-
. venv/bin/activate && pip install -r requirements.txt && pip install -e .
17+
. venv/bin/activate && pip install --upgrade pip tox build && pip install -e ".[testing]"
2218

2319
# Build distribution package
20+
.PHONY: build
2421
build:
2522
. venv/bin/activate && python -m build
2623

@@ -29,22 +26,32 @@ build:
2926
# ----------
3027

3128
# Run complete tox suite
29+
.PHONY: tox
3230
tox:
3331
tox
3432

33+
# Run tox in venv (needs to be installed with `make venv` first)
34+
.PHONY: venv-tox
35+
venv-tox:
36+
. venv/bin/activate && tox
37+
3538
# Only run pytest
39+
.PHONY: test
3640
test:
37-
tox -e 'clean,py{310,39,38,37,py3},report'
41+
tox -e 'clean,py{310,39,38,37},report'
3842

3943
# Only run flake8 linter
44+
.PHONY: flake8
4045
flake8:
4146
tox -e flake8
4247

4348
# Open HTML coverage report in browser
49+
.PHONY: open-coverage
4450
open-coverage:
4551
$(or $(BROWSER),firefox) ./reports/coverage_html/index.html
4652

4753
# Run complete tox test suite in a multi-python Docker container
54+
.PHONY: docker-tox
4855
docker-tox:
4956
docker run --rm --tty \
5057
--user $(DOCKER_USER) \
@@ -55,6 +62,7 @@ docker-tox:
5562
tox --workdir .tox_docker $(TOX_ARGS)
5663

5764
# Run partial tox test suites in Docker
65+
.PHONY: docker-tox-py310 docker-tox-py39 docker-tox-py38 docker-tox-py37
5866
docker-tox-py310: TOX_ARGS="-e clean,py310,py310-report"
5967
docker-tox-py310: docker-tox
6068
docker-tox-py39: TOX_ARGS="-e clean,py39,py39-report"
@@ -65,24 +73,29 @@ docker-tox-py37: TOX_ARGS="-e clean,py37,py37-report"
6573
docker-tox-py37: docker-tox
6674

6775
# Run all tox test suites, but separately to check code coverage individually
76+
.PHONY: docker-tox-all
6877
docker-tox-all:
6978
make docker-tox-py37
7079
make docker-tox-py38
7180
make docker-tox-py39
7281
make docker-tox-py310
7382

7483
# Pull the latest image of the multi-python Docker image
84+
.PHONY: docker-pull
7585
docker-pull:
7686
docker pull $(DOCKER_MULTI_PYTHON_IMAGE)
7787

7888

7989
# Cleanup
8090
# -------
91+
.PHONY: clean
8192
clean:
8293
rm -rf .coverage .pytest_cache reports src/validataclass/_version.py
8394

95+
.PHONY: clean-dist
8496
clean-dist:
8597
rm -rf dist/
8698

99+
.PHONY: clean-all
87100
clean-all: clean clean-dist
88101
rm -rf .tox .tox_docker .eggs src/*.egg-info venv

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,17 @@ To install it using [pip](https://pip.pypa.io/en/stable/getting-started/), just
1717
pip install validataclass
1818
```
1919

20-
If you add the package to your `requirements.txt`, it is recommended to use [compatible release](https://www.python.org/dev/peps/pep-0440/#compatible-release)
20+
If you add the package to your dependencies, it is recommended to use [compatible release](https://www.python.org/dev/peps/pep-0440/#compatible-release)
2121
version specifiers to make sure you always get the latest version of the library but without running into breaking changes:
2222

2323
```shell
24-
pip install validataclass~=0.6
24+
pip install validataclass~=0.7
2525
```
2626

27+
However, keep in mind that the library still is in its beta phase (as indicated by the major version of 0). There can
28+
and will be smaller breaking changes between 0.x minor versions, but we will try to keep them at a minimum and save them
29+
for the release of version 1.0.0.
30+
2731

2832
## Usage
2933

pyproject.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
[build-system]
22
requires = [
3-
"setuptools>=42",
4-
"setuptools_scm>=6.2",
3+
"setuptools",
4+
"setuptools_scm",
55
"wheel",
6-
"python-dateutil"
76
]
87
build-backend = "setuptools.build_meta"
98

requirements.txt

Lines changed: 0 additions & 8 deletions
This file was deleted.

setup.cfg

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,10 @@ install_requires =
3636

3737
[options.packages.find]
3838
where = src
39+
40+
[options.extras_require]
41+
testing =
42+
pytest ~= 7.1
43+
pytest-cov ~= 3.0
44+
coverage ~= 6.4
45+
coverage-conditional-plugin ~= 0.5

tox.ini

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,8 @@ per-file-ignores =
1212
__init__.py: F401
1313

1414
[testenv]
15+
extras = testing
1516
commands = python -m pytest --cov --cov-append {posargs}
16-
deps =
17-
pytest
18-
pytest-cov
19-
{[testenv:report]deps}
2017

2118
[testenv:flake8]
2219
skip_install = true

0 commit comments

Comments
 (0)