Reputation: 963
I just discovered attrs
and it's actually great for my upcoming project. While playing around I recognized some behaviour which I can't explain to myself.
I have this piece of code:
from attr import attrs, attrib, Factory
def validate_dict(instance, attribute, value):
if not isinstance(value, dict):
raise ValueError(f"Attribute `{attribute.name}` has to be of type dict(), not {type(value)}!")
@attrs(kw_only=True, on_setattr=validate_dict)
class FooBar:
defaults = attrib(default=Factory(dict), validator=validate_dict)
config = attrib(default=Factory(dict), validator=validate_dict)
source = attrib(default=Factory(dict), validator=validate_dict)
target = attrib(default=Factory(dict), validator=validate_dict)
>>> foobar = FooBar()
>>> foobar
FooBar(defaults={}, config={}, source={}, target={})
>>> foobar.defaults = {'firstname':'Thomas'}
>>> foobar
FooBar(defaults=None, config={}, source={}, target={})
Using foobar.defaults.update(firstname='Thomas')
works, also foobar = FooBar(defaults={'firstname':'Thomas'})
, but shouldn't work direct assigning as well? Or is the way I use on_setattr
and validator
wrong?
When I try to set an attribute with an int, i.e. foobar.defaults = 1
the ValueError is correctly raised.
Any hints appreciated. Regards, Thomas
Upvotes: 0
Views: 866
Reputation: 251365
According to the documentation for on_setattr
:
If no exception is raised, the attribute is set to the return value of the callable.
Your validate_dict
returns None, so that is what is being set as the value. If you want to set the value to the dict passed in, you need to do return value
in validate_dict
. (Presumably the API was set up this way so that such a handler can modify the passed-in value rather than simply accepting or rejecting it.)
Upvotes: 1