Skip to content

Support __post_init__ for Struct types - #470

Merged
jcrist merged 1 commit into
mainfrom
struct-post-init
Jul 6, 2023
Merged

jcrist merged 1 commit into
mainfrom
struct-post-init

Conversation

@jcrist

@jcrist jcrist commented Jul 6, 2023

Copy link
Copy Markdown
Member

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

jcrist commented Jul 6, 2023

Copy link
Copy Markdown
Member Author

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 force-pushed the struct-post-init branch from 9fbe7a0 to 7aa137c Compare July 6, 2023 01:39
@jcrist
jcrist merged commit 3dee8f1 into main Jul 6, 2023
@jcrist
jcrist deleted the struct-post-init branch July 6, 2023 01:49
@akotlar

akotlar commented Jul 6, 2023

Copy link
Copy Markdown

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