attrs
attrs copied to clipboard
Validation happens only after the creation of all fields, which can be too late
Setup
from attrs import (
Factory,
field,
frozen,
validators,
)
Simple validation, all good:
@frozen
class Foo:
text: str = field(validator=validators.instance_of(str))
Foo(1)
# TypeError: ("'text' must be <class 'str'> (got 1 that is a <class 'int'>).", Attribute(name='text', ...
A more nuanced case:
class Bar:
def __init__(self, text: str):
"""
The input type will always be validated by the client code,
so no need to worry, right?
"""
if not isinstance(text, str):
raise Exception("Something terrible happens")
bar_factory = Factory(
lambda self: Bar(self.text),
takes_self=True
)
@frozen
class Foo:
text: str = field(validator=validators.instance_of(str))
_bar: Bar = field(default=bar_factory)
Foo(1)
# Exception: Something terrible happens
Same thing with:
@frozen
class Foo:
text: str = field(validator=validators.instance_of(str))
_bar: Bar = field(init=False)
@_bar.default
def _(self):
return Bar(self.text)
Foo(1)
# Exception: Something terrible happens
Yes, but this is on purpose. It's a trade-off between your use-cases and ppl wanting to valid the whole class once it's done.
That said, if you need more complex validation/conversion, we've got our sibling project cattrs for that: https://github.com/python-attrs/cattrs