attrs
attrs copied to clipboard
on_setattr doesn't apply during init
This may be by design, but I was hopeful it would work. When an attribute is set during init, on_setattr does not seem to apply, but it does after instantiation. What's the best way to hook in so I can add a validator to all Attributes? Looking to essentially create a class that enforces all values are set to valid types, without adding the same validator to each attribute when I can have some classes with dozens of attributes.
import attr
def raise_value_error(instance, attribute, value):
raise ValueError
@attr.define(on_setattr=raise_value_error)
class Test:
a: int
test = Test("a string") # fine
test.a = "another string" # fails
Yes that’s on purpose. Your use-case is a bit specific but there has been calls for whole-class validators lately.
For what it's worth, I think I'd find that a bit surprising also if I were coming in new.
A single validator (for either the class, or for individual attributes) that gets call at the end of initialization and after every attribute change would seem an obvious design to me; not doing the same in both cases seems inconsistent, though perhaps a reasonable exception.
I agree that the thought process around it is a tad convoluted by its history and we probably should do a better job at explaining why things work as they do in the docs.
However I feel like the naming makes it IMHO quite unequivocal once you grok the way it works.
Also please note that OP didn’t use validators really. They just wanted something to happen on every __setattr__ which is technically impossible to implement well (cf freezing etc).