diff --git a/CHANGELOG.md b/CHANGELOG.md index 07afd4f..b97a9cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added + +- If Pydantic is installed, parameter data classes automatically have Pydantic type + validation enabled. + ### Changed - All `ParamData` objects now internally track the latest time that they or any of their diff --git a/docs/parameter-data.md b/docs/parameter-data.md index 9f5fd53..47a93c5 100644 --- a/docs/parameter-data.md +++ b/docs/parameter-data.md @@ -68,8 +68,8 @@ when building up dataclasses through inheritance. from dataclasses import field class KeywordOnlyParam(ParamDataclass, kw_only=True): - values: list[int] = field(default_factory=list) count: int + values: list[int] = field(default_factory=list) keyword_only_param = KeywordOnlyParam(count=123) keyword_only_param @@ -162,6 +162,34 @@ nested_param.child_param.root is nested_param See [Type Mixins](#type-mixins) for information on how to get the parent and root properties to work better with static type checkers. +### Type Validation + +If [Pydantic] is installed, parameter data classes will automatically be converted to +[Pydantic data classes], enabling runtime type validation. Some [Pydantic configuration] +have modified defaults; see {py:class}`ParamDataclass` for more information. + +Pydantic type validation will enforce type hints at runtime by raising an exception. For +example: + +```{jupyter-execute} +import pydantic + +try: + CustomParam(value="123") +except pydantic.ValidationError as exception: + print(exception) +``` + +Type validation can be disabled for a particular parameter data class (and its subclasses) +using the class keyword argument `type_validation`: + +```{jupyter-execute} +class NoTypeValidationParam(CustomParam, type_validation=False): + pass + +NoTypeValidationParam(value="123") +``` + ## Collections Ordinary lists and dictionaries can be used within parameter data; however, any @@ -265,5 +293,7 @@ This does nothing to the functionality, but static type checkers will now know t [mutable default values]: https://docs.python.org/3/library/dataclasses.html#mutable-default-values [`@property`]: https://docs.python.org/3/library/functions.html#property [`__post_init__`]: https://docs.python.org/3/library/dataclasses.html#post-init-processing -[`abc.abc`]: https://docs.python.org/3/library/abc.html#abc.ABC +[Pydantic]: https://docs.pydantic.dev/latest/ +[Pydantic data classes]: https://docs.pydantic.dev/latest/concepts/dataclasses/ +[Pydantic configuration]: https://docs.pydantic.dev/latest/api/config/ [`collections.abc`]: https://docs.python.org/3/library/collections.abc.html diff --git a/paramdb/_param_data/_dataclasses.py b/paramdb/_param_data/_dataclasses.py index 73925e4..3dd248d 100644 --- a/paramdb/_param_data/_dataclasses.py +++ b/paramdb/_param_data/_dataclasses.py @@ -43,6 +43,7 @@ class CustomParam(ParamDataclass): Pydantic configuration options can be updated using the class keyword argument ``pydantic_config``, which will merge new options with the existing configuration. + See https://docs.pydantic.dev/latest/api/config for full configuration options. """ __field_names: set[str] # Data class field names