0001"""
0002Validators for applying validations in sequence.
0003"""
0004
0005from api import *
0006
0007
0008__all__ = ['Any', 'All']
0009
0010
0011
0012
0013
0014def to_python(validator, value, state):
0015 return validator.to_python(value, state)
0016
0017def from_python(validator, value, state):
0018 return validator.from_python(value, state)
0019
0020class CompoundValidator(FancyValidator):
0021
0022 if_invalid = NoDefault
0023
0024 validators = []
0025
0026 __unpackargs__ = ('*', 'validatorArgs')
0027
0028 __mutableattributes__ = ('validators',)
0029
0030 def __classinit__(cls, new_attrs):
0031 toAdd = []
0032 for name, value in new_attrs.items():
0033 if name in ('view',):
0034 continue
0035 if is_validator(value) and value is not Identity:
0036 toAdd.append((name, value))
0037
0038 delattr(cls, name)
0039 toAdd.sort()
0040 cls.validators.extend([v for n, v in toAdd])
0041
0042 def __init__(self, *args, **kw):
0043 Validator.__init__(self, *args, **kw)
0044 self.validators = self.validators[:]
0045 self.validators.extend(self.validatorArgs)
0046
0047 def _reprVars(names):
0048 return [n for n in Validator._reprVars(names)
0049 if n != 'validatorArgs']
0050 _reprVars = staticmethod(_reprVars)
0051
0052 def attempt_convert(self, value, state, convertFunc):
0053 raise NotImplementedError, "Subclasses must implement attempt_convert"
0054
0055 def _to_python(self, value, state=None):
0056 return self.attempt_convert(value, state,
0057 to_python)
0058
0059 def _from_python(self, value, state=None):
0060 return self.attempt_convert(value, state,
0061 from_python)
0062
0063 def subvalidators(self):
0064 return self.validators
0065
0066class Any(CompoundValidator):
0067
0068 """
0069 This class is like an 'or' operator for validators. The first
0070 validator/converter that validates the value will be used. (You
0071 can pass in lists of validators, which will be ANDed)
0072 """
0073
0074 def attempt_convert(self, value, state, validate):
0075 lastException = None
0076 if validate is to_python:
0077 validators = self.validators[::-1]
0078 else:
0079 validators = self.validators
0080 for validator in validators:
0081 try:
0082 return validate(validator, value, state)
0083 except Invalid, e:
0084 lastException = e
0085 if self.if_invalid is NoDefault:
0086 raise lastException
0087 else:
0088 return self.if_invalid
0089
0090 def not_empty__get(self):
0091 not_empty = True
0092 for validator in self.validators:
0093 not_empty = not_empty and getattr(validator, 'not_empty', False)
0094 return not_empty
0095 not_empty = property(not_empty__get)
0096
0097class All(CompoundValidator):
0098
0099 """
0100 This class is like an 'and' operator for validators. All
0101 validators must work, and the results are passed in turn through
0102 all validators for conversion.
0103 """
0104
0105 def __repr__(self):
0106 return '<All %s>' % self.validators
0107
0108 def attempt_convert(self, value, state, validate):
0109
0110
0111 if validate is to_python:
0112 validators = list(self.validators)
0113 validators.reverse()
0114 else:
0115 validators = self.validators
0116 try:
0117 for validator in validators:
0118 value = validate(validator, value, state)
0119 return value
0120 except Invalid:
0121 if self.if_invalid is NoDefault:
0122 raise
0123 return self.if_invalid
0124
0125 def with_validator(self, validator):
0126 """
0127 Adds the validator (or list of validators) to a copy of
0128 this validator.
0129 """
0130 new = self.validators[:]
0131 if isinstance(validator, list) or isinstance(validator, tuple):
0132 new.extend(validator)
0133 else:
0134 new.append(validator)
0135 return self.__class__(*new, **{'if_invalid': self.if_invalid})
0136
0137 def join(cls, *validators):
0138 """
0139 Joins several validators together as a single validator,
0140 filtering out None and trying to keep `All` validators from
0141 being nested (which isn't needed).
0142 """
0143 validators = filter(lambda v: v and v is not Identity, validators)
0144 if not validators:
0145 return Identity
0146 if len(validators) == 1:
0147 return validators[0]
0148 elif isinstance(validators[0], All):
0149 return validators[0].with_validator(validators[1:])
0150 else:
0151 return cls(*validators)
0152 join = classmethod(join)
0153
0154 def if_missing__get(self):
0155 for validator in self.validators:
0156 v = validator.if_missing
0157 if v is not NoDefault:
0158 return v
0159 return NoDefault
0160 if_missing = property(if_missing__get)
0161
0162 def not_empty__get(self):
0163 not_empty = False
0164 for validator in self.validators:
0165 not_empty = not_empty or getattr(validator, 'not_empty', False)
0166 return not_empty
0167 not_empty = property(not_empty__get)