# -*- coding: cp1251 -*- from pybase.utils import safe, atof def _avoid_value(hole): """Decorator - return validator which enable any value except hole""" def f(value): if value==hole: raise ValueError else: return value return f class BaseValidator: """Base validation. Default behaviour is to `eat` any not None value: >>> bv = BaseValidator() >>> bv(0) 0 >>> bv('a') 'a' >>> bv(None) Traceback (most recent call last): ... ValueError """ def __init__(self, vfunc=_avoid_value(None), hint="", opts={}, **kw): """vfunc is validation function which must raise Exception (ValueError!) on invalid data and return casted value to it's domain. opts is additional options for validator, default is value to be returned instead of exception raised when is set""" self.opts = dict(opts) self.hint = hint or self.__class__.__name__ if "default" in kw: self.vfunc = safe(vfunc, kw["default"]) else: self.vfunc = vfunc def __call__(self, *a, **kw): return self.vfunc(*a, **kw) class SetValidator(BaseValidator): """Validate that value is in set. Note, in_ __init__ arg must have __contains__ and __str__. >>> sv = SetValidator() >>> sv.hint 'any' >>> sv(9) 9 >>> sv = SetValidator(in_=(1,2,3)) >>> sv.hint 'in (1, 2, 3)' >>> sv(3) 3 >>> sv(9) Traceback (most recent call last): ... ValueError >>> sv = SetValidator("available weight", (1,2,3)) >>> sv.hint 'available weight' >>> sv(3) 3 >>> sv = SetValidator(in_=(1,2), default='unknown') >>> sv(0) 'unknown' >>> sv = SetValidator(in_=xrange(0,1000)) >>> sv(1) 1 >>> sv(1) 1 """ def __init__(self, hint=None, in_=None, **kw): self.in_ = in_ hint = hint or ("any" if in_ is None else "in %s"%str(in_)) def vfunc(value): if self.in_ is None or value in self.in_: return value else: raise ValueError BaseValidator.__init__(self, vfunc, hint, **kw) class IntValidator(BaseValidator): """Validate that value is integer: >>> iv = IntValidator() >>> iv("9") 9 >>> iv("a") Traceback (most recent call last): ... ValueError: invalid literal for int() with base 10: 'a' >>> iv("a", 16) 10 """ def __init__(self, hint=None, **kw): BaseValidator.__init__(self, int, hint, **kw) class FloatValidator(BaseValidator): """Validate that value is float: >>> fv = FloatValidator("weight", default='no') >>> fv.hint 'weight' >>> fv(9) 9.0 >>> fv("9.12") 9.12 >>> fv("9,12") 9.12 >>> fv("a") 'no' """ def __init__(self, hint=None, **kw): def vfunc(value): if isinstance(value, str): return atof(value) else: return float(value) BaseValidator.__init__(self, vfunc, hint, **kw) class ChainValidator(BaseValidator): """Validators chaining: all validators pipes value. If exception occurs in piping then default of this validator will be returned or exception occurs (if default is not set): >>> sv = SetValidator(in_=(1,2,3,4)) >>> sv('1') Traceback (most recent call last): ... ValueError >>> iv = IntValidator(default=4) >>> av = ChainValidator(and_=(iv, sv), default='what?') >>> av('1') 1 >>> av('2') 2 >>> av('10') 'what?' >>> av('x') 4 >>> av.hint 'IntValidator & in (1, 2, 3, 4)' >>> av = ChainValidator(and_=(iv, sv), hint="int list", opts={"something":123}) >>> av.hint 'int list' >>> av.opts["something"] 123 """ def __init__(self, and_, hint=None, **kw): self.and_ = and_ def vfunc(value): v = value for validator in and_: v = validator(v) return v if not hint: h = [] for v in and_: h.append(str(v.hint)) h = " & ".join(h) #if h: h = "[%s]"%h else: h = hint BaseValidator.__init__(self, vfunc, h, **kw) if __name__=="__main__": import doctest doctest.testmod()
Here are examples of usage (and extending):
def IntSetValidator(hint, in_, *a, **kw): """Checks does int set contents a value""" iv = IntValidator() sv = SetValidator(in_, *a, **kw) return ChainValidator(hint=hint, and_=(iv, sv)) class IntRangeValidator(BaseValidator): "Checks does value is contained in 'a-b' range" def __init__(self, hint=None, **kw): def vfunc(value): """Should raise ValueError (ONLY) on invalid value, else returns parsed value""" try: rng = [int(x.strip()) for x in value.split('-')] if rng[1] <= rng[0]: raise Exception else: return rng except: raise ValueError BaseValidator.__init__(self, vfunc, hint, **kw)
Комментариев нет:
Отправить комментарий
Thanks for your posting!