attrs icon indicating copy to clipboard operation
attrs copied to clipboard

on_setattr doesn't apply during init

Open liveFreeOrCode opened this issue 5 years ago • 3 comments

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

liveFreeOrCode avatar Aug 21 '20 16:08 liveFreeOrCode

Yes that’s on purpose. Your use-case is a bit specific but there has been calls for whole-class validators lately.

hynek avatar Aug 21 '20 17:08 hynek

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.

wsanchez avatar Aug 26 '20 01:08 wsanchez

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).

hynek avatar Aug 30 '20 08:08 hynek