Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import attr
- class AutoValidator:
- _expr = None
- _counter = 0
- def _newvar(self):
- num = AutoValidator._counter
- AutoValidator._counter += 1
- return f'_v{num}'
- def __call__(self, cls, attr, value):
- if self._expr is None:
- self._expr = self._compile()
- return self._expr(cls, attr, value)
- def _compile(self):
- scope = dict(self._scope)
- scope['_pretty'] = self._pretty
- scope['_type_err'] = TypeError
- body = (
- 'def _func(_cls, _attr, _value):\n'
- f' if not {self._source}:\n'
- ' raise _type_err(f"{_cls}.{_attr.name} fails check {_pretty}")'
- )
- exec(body, scope)
- return scope['_func']
- def __add__(self, other):
- return Binary('+', self, other)
- def __radd__(self, other):
- return Binary('+', other, self)
- def __mul__(self, other):
- return Binary('*', self, other)
- def __rmul__(self, other):
- return Binary('*', other, self)
- def __lt__(self, other):
- return Binary('<', self, other)
- def __le__(self, other):
- return Binary('<=', self, other)
- def __eq__(self, other):
- return Binary('==', self, other)
- def __ne__(self, other):
- return Binary('!=', self, other)
- def __gt__(self, other):
- return Binary('>', self, other)
- def __ge__(self, other):
- return Binary('>=', self, other)
- def len(self):
- return Func(len, self)
- def isa(self, *type_expr):
- def isa_check(val):
- return isinstance(val, type_expr)
- return Func(isa_check, self)
- def __repr__(self):
- return self._pretty
- class Value(AutoValidator):
- _source = '_value'
- @property
- def _scope(self):
- return {}
- _pretty = 'VAL'
- VAL = Value()
- class Constant(AutoValidator):
- def __init__(self, constant):
- var = self._newvar()
- self._scope = {var: constant}
- self._source = var
- self._pretty = repr(constant)
- def _autoify(value):
- return value if isinstance(value, AutoValidator) else Constant(value)
- class Binary(AutoValidator):
- def __init__(self, op, left, right):
- left = _autoify(left)
- right = _autoify(right)
- self._scope = dict(left._scope)
- self._scope.update(right._scope)
- self._source = f'({left._source} {op} {right._source})'
- self._pretty = f'({left} {op} {right})'
- class Func(AutoValidator):
- def __init__(self, func, arg):
- var = self._newvar()
- arg = _autoify(arg)
- self._scope = {var: func}
- self._scope.update(arg._scope)
- self._source = f'{var}({arg._source})'
- self._pretty = f'{func.__name__}({arg})'
- @attr.s
- class Test:
- positive = attr.ib(validator=[VAL.isa(int, float), VAL > 0.0])
- nonempty = attr.ib(validator=[VAL.len() >= 1])
Add Comment
Please, Sign In to add comment