Having a simple Python class like this:
class Spam(object):
__init__(self, description, value):
self.description = description
self.value
You can try pyfields:
from pyfields import field
class Spam(object):
description = field(validators={"description can not be empty": lambda s: len(s) > 0})
value = field(validators={"value must be greater than zero": lambda x: x > 0})
s = Spam()
s.description = "hello"
s.description = "" # <-- raises error, see below
It yields
ValidationError[ValueError]: Error validating [<...>.Spam.description=''].
InvalidValue: description can not be empty.
Function [] returned [False] for value ''.
It is compliant with python 2 and 3.5 (as opposed to pydantic), and validation happens everytime the value is changed (not only the first time, as opposed to attrs). It can create the constructor for you, but does not do it by default as shown above.
Note that you may wish to optionally use mini-lambda instead of plain old lambda functions if you wish the error messages to be even more straightforward (they will display the failing expression).
See pyfields documentation for details (I'm the author by the way ;) )