I have several classes defined using attrs like this one:
from attr import attrs, attrib, validators
@attrs
class MyClass:
name = attrib(])
@name.validator
def check_length(self, attribute, value):
if not (3 <= len(value) <= 30):
raise ValueError("Name must be between 3 and 30 characters")
description = attrib()
@description.validator
def check_length(self, attribute, value):
if not (10 <= len(value) <= 400):
raise ValueError("Description must be between 10 and 400 characters")
For several attributes I need to create a validator to check wether the data it's in some range. I want to avoid repetition, so I can create a custom validator where I pass some extra arguments for min and max, like this one:
def range_validator(instance, attribute, value, min_value, max_value):
if min_value >= len(value) >= max_value:
raise ValueError("Must be between {} and {}".format(min_value, max_value))
But then I don't know how to call this validator from inside attrib() passing the extra args (min_value and max_value), I mean do something like:
name = attrib(validator=[range_validator(self, 10, 30)])
You could use functools.partial
:
def range_validator(instance, attribute, value, min_value, max_value):
lv = len(value)
if min_value > lv or lv > max_value:
raise ValueError("Must be between {} and {}".format(min_value, max_value))
@attrs
class C:
x = attrib(validator=partial(range_validator, min_value=10, max_value=30))
Alternatively you can use a closure:
def make_range_validator(min_value, max_value):
def range_validator(instance, attribute, value):
lv = len(value)
if min_value > lv or lv > max_value:
raise ValueError("Must be between {} and {}".format(min_value, max_value))
return range_validator
@attrs
class C:
x = attrib(validator=make_range_validator(10, 30))
I personally like the closure factory approach better because they are more explicit about what you’re doing. Partials always feel a bit ad-hoc to me, but that might just be me.
(Please note that I took the liberty to fix a logic bug in your validator – you may want to apply it too. :))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With