Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support __post_init__ for Struct types #470

Merged
merged 1 commit into from Jul 6, 2023
Merged

Support __post_init__ for Struct types #470

merged 1 commit into from Jul 6, 2023

Conversation

jcrist
Copy link
Owner

@jcrist jcrist commented Jul 6, 2023

This adds support for an optional __post_init__ hook method on msgspec.Struct types. If defined, this method is called at the end of the generated __init__ method. It can be used to customize the builtin __init__ as needed, as well as provides a spot to do some additional validation.

As with dec_hook errors, any ValueError or TypeError raised in __post_init__ will be wrapped in a ValidationError when decoding. In the long run I plan to add support for more granular (and obviously named) custom validator support, but for now doing some validation in __post_init__ is a fine and simple solution. There are other use cases for __post_init__ besides validation, so we'd want to add this ability either way.

Fixes #442.

@jcrist
Copy link
Owner Author

jcrist commented Jul 6, 2023

A quick example:

>>> import msgspec

>>> class Interval(msgspec.Struct):
...     low: float
...     high: float
...
...     def __post_init__(self):
...         if self.low > self.high:
...             raise ValueError("`low` may not be greater than `high`")

>>> Interval(1, 2)  # valid interval
Interval(low=1, high=2)

>>> Interval(2, 1)  # invalid interval
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in __post_init__
ValueError: `low` may not be greater than `high`

>>> msgspec.json.decode(b'{"low": 2, "high": 1}', type=Interval)  # invalid interval from JSON
Traceback (most recent call last):
  File "<stdin>", line 6, in __post_init__
ValueError: `low` may not be greater than `high`

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
msgspec.ValidationError: `low` may not be greater than `high`

This adds support for an optional `__post_init__` hook method on
`msgspec.Struct` types. If defined, this method is called at the end of
the generated `__init__` method. It can be used to customize the builtin
`__init__` as needed, as well as provides a spot to do some additional
validation.

As with `dec_hook` errors, any `ValueError` or `TypeError` raised in
`__post_init__` will be wrapped in a `ValidationError` when decoding.
@jcrist jcrist merged commit 3dee8f1 into main Jul 6, 2023
8 checks passed
@jcrist jcrist deleted the struct-post-init branch July 6, 2023 01:49
@akotlar
Copy link

akotlar commented Jul 6, 2023

Amazing, thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Post-init hook
2 participants