Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create validators not tied to attributes #647

Open
shashankchaudhry opened this issue May 22, 2020 · 5 comments
Open

Create validators not tied to attributes #647

shashankchaudhry opened this issue May 22, 2020 · 5 comments
Labels

Comments

@shashankchaudhry
Copy link

Currently if I need to add a validator to check a condition that affects two attributes, I have to make it a validator of one of them. For example:

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

     @x.validator
     def x_smaller_than_y(self, _ , value):
          if value >= self.y:
          raise ValueError("'x' has to be smaller than 'y'!")

This feels a little unintuitive because this validator is not really a validator on just 'x'. It should be a validator on 'x' and 'y'. It made me wonder if the order of writing x and y in the class matters, in case the validator is run right after an attribute is set.

I wonder what folks think about a generic validator of this form:

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

     @validator
     def x_smaller_than_y(self):
          if self.x >= self.y:
          raise ValueError("'x' has to be smaller than 'y'!")
@hynek
Copy link
Member

hynek commented May 24, 2020

This seems like something for __attrs_post_init__ and not a validator?

@wsanchez
Copy link

This may be something to think about in the context of the __setattr__ conversation; presumably this validation should happen any time x or y are assigned to. In which case, it should be separate from __attrs_post_init__.

@shashankchaudhry
Copy link
Author

@wsanchez : What is the __setattr__ conversation?

@hynek : __attrs_post_init__ to me feels like a place to mutate the attrs after initialization, rather than a place to validate them. Since you explicitly have validators, and it is pretty common to want to do multi-attr validation, it seems more natural if you could natively support that. An alternate approach I can think of is some syntax like:

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

     @multi_validator(['x', 'y'])
     def x_smaller_than_y(self, x, y):
          if x >= y:
              raise ValueError("'x' has to be smaller than 'y'!")

@wsanchez
Copy link

@shashankchaudhry Sorry I should have included a pointer. See #645.

Since we are considering validation when attributes are assigned to, then even a validator not specific to a given attribute would probably need to be triggered when you set either any or relevant-to-the-validator attributes. So a solution that only work in the context of the init cycle is probably going to be unsatisfactory.

@hynek
Copy link
Member

hynek commented Jun 7, 2020

I’m starting to remember that at some point we had a “validate the whole instance” conversation but it got turned down?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants