2
Validators for applying validations in sequence.
7
# @@ ianb 2005-05: should CompoundValidator be included?
8
__all__ = ['Any', 'All', 'Pipe']
10
############################################################
12
############################################################
14
def to_python(validator, value, state):
15
return validator.to_python(value, state)
17
def from_python(validator, value, state):
18
return validator.from_python(value, state)
20
class CompoundValidator(FancyValidator):
22
if_invalid = NoDefault
26
__unpackargs__ = ('*', 'validatorArgs')
28
__mutableattributes__ = ('validators',)
30
def __classinit__(cls, new_attrs):
32
for name, value in new_attrs.items():
35
if is_validator(value) and value is not Identity:
36
toAdd.append((name, value))
37
# @@: Should we really delete too?
40
cls.validators.extend([v for n, v in toAdd])
42
def __init__(self, *args, **kw):
43
Validator.__init__(self, *args, **kw)
44
self.validators = self.validators[:]
45
self.validators.extend(self.validatorArgs)
48
return [n for n in Validator._reprVars(names)
49
if n != 'validatorArgs']
50
_reprVars = staticmethod(_reprVars)
52
def attempt_convert(self, value, state, convertFunc):
53
raise NotImplementedError, "Subclasses must implement attempt_convert"
55
def _to_python(self, value, state=None):
56
return self.attempt_convert(value, state,
59
def _from_python(self, value, state=None):
60
return self.attempt_convert(value, state,
63
def subvalidators(self):
64
return self.validators
66
class Any(CompoundValidator):
69
This class is like an 'or' operator for validators. The first
70
validator/converter that validates the value will be used. (You
71
can pass in lists of validators, which will be ANDed)
74
def attempt_convert(self, value, state, validate):
76
if validate is to_python:
77
validators = self.validators[::-1]
79
validators = self.validators
80
for validator in validators:
82
return validate(validator, value, state)
85
if self.if_invalid is NoDefault:
88
return self.if_invalid
90
def not_empty__get(self):
92
for validator in self.validators:
93
not_empty = not_empty and getattr(validator, 'not_empty', False)
95
not_empty = property(not_empty__get)
97
def is_empty(self, value):
98
# sub-validators should handle emptiness.
101
class All(CompoundValidator):
104
This class is like an 'and' operator for validators. All
105
validators must work, and the results are passed in turn through
106
all validators for conversion.
110
return '<All %s>' % self.validators
112
def attempt_convert(self, value, state, validate):
113
# To preserve the order of the transformations, we do them
114
# differently when we are converting to and from python.
115
if validate is to_python:
116
validators = list(self.validators)
119
validators = self.validators
121
for validator in validators:
122
value = validate(validator, value, state)
125
if self.if_invalid is NoDefault:
127
return self.if_invalid
129
def with_validator(self, validator):
131
Adds the validator (or list of validators) to a copy of
134
new = self.validators[:]
135
if isinstance(validator, list) or isinstance(validator, tuple):
136
new.extend(validator)
138
new.append(validator)
139
return self.__class__(*new, **{'if_invalid': self.if_invalid})
141
def join(cls, *validators):
143
Joins several validators together as a single validator,
144
filtering out None and trying to keep `All` validators from
145
being nested (which isn't needed).
147
validators = filter(lambda v: v and v is not Identity, validators)
150
if len(validators) == 1:
152
elif isinstance(validators[0], All):
153
return validators[0].with_validator(validators[1:])
155
return cls(*validators)
156
join = classmethod(join)
158
def if_missing__get(self):
159
for validator in self.validators:
160
v = validator.if_missing
161
if v is not NoDefault:
164
if_missing = property(if_missing__get)
166
def not_empty__get(self):
168
for validator in self.validators:
169
not_empty = not_empty or getattr(validator, 'not_empty', False)
171
not_empty = property(not_empty__get)
173
def is_empty(self, value):
174
# sub-validators should handle emptiness.
179
This class works like 'All', all validators muss pass, but the result
180
of one validation pass is handled over to the next validator. A behaviour
181
known to Unix and GNU users as 'pipe'.
185
>>> from validators import DictConverter
186
>>> pv = Pipe(validators=[DictConverter({1: 2}), DictConverter({2: 3}), DictConverter({3: 4})])
191
>>> pv.from_python(4)
193
>>> pv.from_python(4)
201
return '<Pipe %s>' % self.validators
203
def attempt_convert(self, value, state, validate):
204
# To preserve the order of the transformations, we do them
205
# differently when we are converting to and from python.
206
if validate is from_python:
207
validators = list(self.validators)
210
validators = self.validators
212
for validator in validators:
213
value = validate(validator, value, state)
216
if self.if_invalid is NoDefault:
218
return self.if_invalid