import sys, os, re


class ValidatorMeta(type):

    def __new__(cls, name, bases, class_dict):
        for name, validator in class_dict.items():
            if name[:2] == "__":
                continue

            
            def get_get(name):
                def get(self):
                    return getattr(self, "_%s" % name)
                return get
            try:
                coercer, validator = validator

                def get_set(name, c, v):
                    def set(self, value):
                        if value is not None and value != "":
                            v(value)
                            setattr(self, "_%s" % name, c(value))
                        else:
                            setattr(self, "_%s" % name, None)
                            
                    return set

                setter = get_set(name, coercer, validator)
            except TypeError:
                def get_set(name, v):
                    def set(self, value):
                        if value is not None and value != "":
                            setattr(self, "_%s" % name, v(value))
                        else:
                            setattr(self, "_%s" % name, None)
                    return set
                setter = get_set(name, validator)
            class_dict[name] = property(get_get(name), setter)
        return type(name, bases, class_dict)
    


class ComposableValidator(object):
    def __init__(self, v):
        self._v = v

    def __call__(self, value):
        return self._v(value)

    def __or__(self, other_v):
        class OrValidator(object):
            def __init__(self, left, right):
                self._left, self._right = left, right

            def __call__(self, value):
                try:
                    self._left(value)
                    return value
                except ValueError:
                    return self._right(value)

        return OrValidator(self._v, other_v._v)

    def __and__(self, other_v):
        class AndValidator(object):
            def __init__(self, left, right):
                self._left, self._right = left, right

            def __call__(self, value):
                self._left(value)
                return self._right(value)

        return AndValidator(self._v, other_v._v)

    
def zip_v(value):
    int(value)
    return value


def rex_v(pattern):
    rex = re.compile(pattern)
    def _rex_v(value):
        if not rex.match(value):
            raise ValueError, "Invalid value <%s> for pattern <%s>" % (value, pattern)
        return value
    return _rex_v

cv = ComposableValidator

class SomeForm(object):
    __metaclass__ = ValidatorMeta

    intprop = int 
    floatprop = float
    stringprop = str
    zip = zip_v
    rexprop = rex_v(r"^[a-z]+$")

    int_but_string = (str, int)
    int_or_abc = (str, cv(rex_v(r"^[a-z]+$")) | cv(int))
    
if __name__ == "__main__":
    sf = SomeForm()
    sf.intprop = "10"
    print repr(sf.intprop)
    sf.floatprop = "232"
    sf.zip = "12345"
    sf.rexprop = "abce"
    sf.int_but_string = "1234"
    print repr(sf.int_but_string)
    sf.intprop = ""
    sf.int_or_abc = "10"
    sf.int_or_abc = "abc"
    sf.int_or_abc = "abce10"
