Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python-attrs: validator in child class

Using the Python module attrs, I'm trying to have a subclass with a condition on its attributes more restrictive than its parent, like in the minimal example below.

import attr

@attr.s
class Base:
    x = attr.ib()
    y = attr.ib()

@attr.s
class Child(Base):

    @x.validator
    def _x_validator(self, a, x):
        if x < 0:
            raise ValueError()

Defining a validator like above raises an error (NameError: name 'x' is not defined).

I've found a workaround by redefining x in the child class.

@attr.s
class Child(Base):
    x = attr.ib()

    @x.validator
    def _x_validator(self, a, x):
        if x < 0:
            raise ValueError()

However it messes up the ordering of the attributes.

In [5]: Child(5, 10)
Out[5]: Child(y=5, x=10)

So, finally, I ended up redefining all the attributes in the child class (and there are more than two in the actual code).

Is there a more elegant way to do this?

like image 569
Matthieu Avatar asked Oct 19 '25 17:10

Matthieu


1 Answers

Finally, the simplest workaround I found was simply not to use a validator in the child class:

@attr.s
class Child(Base):
    def __attrs_post_init__(self):
        assert self.x > 0

Thanks to bruno desthuilliers for rightly pointing out Liskov principle. Note that the problem does not only occur for @x.validator but also for other constructs such as the attribute default value @x.default. It seems that the upcoming dataclass for Python 3.7 works slightly better with inheritance than attrs in this case.

like image 78
Matthieu Avatar answered Oct 22 '25 07:10

Matthieu



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!