mirror of
https://github.com/djohnlewis/stackdump
synced 2025-12-07 00:13:33 +00:00
Initial commit. Still building up the env and some parsing code.
This commit is contained in:
221
python/packages/formencode/compound.py
Normal file
221
python/packages/formencode/compound.py
Normal file
@@ -0,0 +1,221 @@
|
||||
"""
|
||||
Validators for applying validations in sequence.
|
||||
"""
|
||||
|
||||
from api import *
|
||||
|
||||
# @@ ianb 2005-05: should CompoundValidator be included?
|
||||
__all__ = ['Any', 'All', 'Pipe']
|
||||
|
||||
############################################################
|
||||
## Compound Validators
|
||||
############################################################
|
||||
|
||||
def to_python(validator, value, state):
|
||||
return validator.to_python(value, state)
|
||||
|
||||
|
||||
def from_python(validator, value, state):
|
||||
return validator.from_python(value, state)
|
||||
|
||||
|
||||
class CompoundValidator(FancyValidator):
|
||||
|
||||
if_invalid = NoDefault
|
||||
|
||||
validators = []
|
||||
|
||||
__unpackargs__ = ('*', 'validatorArgs')
|
||||
|
||||
__mutableattributes__ = ('validators',)
|
||||
|
||||
def __classinit__(cls, new_attrs):
|
||||
toAdd = []
|
||||
for name, value in new_attrs.items():
|
||||
if name in ('view',):
|
||||
continue
|
||||
if is_validator(value) and value is not Identity:
|
||||
toAdd.append((name, value))
|
||||
# @@: Should we really delete too?
|
||||
delattr(cls, name)
|
||||
toAdd.sort()
|
||||
cls.validators.extend([v for n, v in toAdd])
|
||||
|
||||
def __init__(self, *args, **kw):
|
||||
Validator.__init__(self, *args, **kw)
|
||||
self.validators = self.validators[:]
|
||||
self.validators.extend(self.validatorArgs)
|
||||
|
||||
def _reprVars(names):
|
||||
return [n for n in Validator._reprVars(names)
|
||||
if n != 'validatorArgs']
|
||||
_reprVars = staticmethod(_reprVars)
|
||||
|
||||
def attempt_convert(self, value, state, convertFunc):
|
||||
raise NotImplementedError, "Subclasses must implement attempt_convert"
|
||||
|
||||
def _to_python(self, value, state=None):
|
||||
return self.attempt_convert(value, state,
|
||||
to_python)
|
||||
|
||||
def _from_python(self, value, state=None):
|
||||
return self.attempt_convert(value, state,
|
||||
from_python)
|
||||
|
||||
def subvalidators(self):
|
||||
return self.validators
|
||||
|
||||
|
||||
class Any(CompoundValidator):
|
||||
"""
|
||||
This class is like an 'or' operator for validators. The first
|
||||
validator/converter that validates the value will be used. (You
|
||||
can pass in lists of validators, which will be ANDed)
|
||||
"""
|
||||
|
||||
def attempt_convert(self, value, state, validate):
|
||||
lastException = None
|
||||
if validate is to_python:
|
||||
validators = self.validators[::-1]
|
||||
else:
|
||||
validators = self.validators
|
||||
for validator in validators:
|
||||
try:
|
||||
return validate(validator, value, state)
|
||||
except Invalid, e:
|
||||
lastException = e
|
||||
if self.if_invalid is NoDefault:
|
||||
raise lastException
|
||||
else:
|
||||
return self.if_invalid
|
||||
|
||||
def not_empty__get(self):
|
||||
not_empty = True
|
||||
for validator in self.validators:
|
||||
not_empty = not_empty and getattr(validator, 'not_empty', False)
|
||||
return not_empty
|
||||
not_empty = property(not_empty__get)
|
||||
|
||||
def is_empty(self, value):
|
||||
# sub-validators should handle emptiness.
|
||||
return False
|
||||
|
||||
|
||||
class All(CompoundValidator):
|
||||
"""
|
||||
This class is like an 'and' operator for validators. All
|
||||
validators must work, and the results are passed in turn through
|
||||
all validators for conversion.
|
||||
"""
|
||||
|
||||
def __repr__(self):
|
||||
return '<All %s>' % self.validators
|
||||
|
||||
def attempt_convert(self, value, state, validate):
|
||||
# To preserve the order of the transformations, we do them
|
||||
# differently when we are converting to and from python.
|
||||
if validate is to_python:
|
||||
validators = list(self.validators)
|
||||
validators.reverse()
|
||||
else:
|
||||
validators = self.validators
|
||||
try:
|
||||
for validator in validators:
|
||||
value = validate(validator, value, state)
|
||||
return value
|
||||
except Invalid:
|
||||
if self.if_invalid is NoDefault:
|
||||
raise
|
||||
return self.if_invalid
|
||||
|
||||
def with_validator(self, validator):
|
||||
"""
|
||||
Adds the validator (or list of validators) to a copy of
|
||||
this validator.
|
||||
"""
|
||||
new = self.validators[:]
|
||||
if isinstance(validator, list) or isinstance(validator, tuple):
|
||||
new.extend(validator)
|
||||
else:
|
||||
new.append(validator)
|
||||
return self.__class__(*new, **dict(if_invalid=self.if_invalid))
|
||||
|
||||
def join(cls, *validators):
|
||||
"""
|
||||
Joins several validators together as a single validator,
|
||||
filtering out None and trying to keep `All` validators from
|
||||
being nested (which isn't needed).
|
||||
"""
|
||||
validators = filter(lambda v: v and v is not Identity, validators)
|
||||
if not validators:
|
||||
return Identity
|
||||
if len(validators) == 1:
|
||||
return validators[0]
|
||||
elif isinstance(validators[0], All):
|
||||
return validators[0].with_validator(validators[1:])
|
||||
else:
|
||||
return cls(*validators)
|
||||
join = classmethod(join)
|
||||
|
||||
def if_missing__get(self):
|
||||
for validator in self.validators:
|
||||
v = validator.if_missing
|
||||
if v is not NoDefault:
|
||||
return v
|
||||
return NoDefault
|
||||
if_missing = property(if_missing__get)
|
||||
|
||||
def not_empty__get(self):
|
||||
not_empty = False
|
||||
for validator in self.validators:
|
||||
not_empty = not_empty or getattr(validator, 'not_empty', False)
|
||||
return not_empty
|
||||
not_empty = property(not_empty__get)
|
||||
|
||||
def is_empty(self, value):
|
||||
# sub-validators should handle emptiness.
|
||||
return False
|
||||
|
||||
|
||||
class Pipe(All):
|
||||
"""
|
||||
This class works like 'All', all validators muss pass, but the result
|
||||
of one validation pass is handled over to the next validator. A behaviour
|
||||
known to Unix and GNU users as 'pipe'.
|
||||
|
||||
::
|
||||
|
||||
>>> from validators import DictConverter
|
||||
>>> pv = Pipe(validators=[DictConverter({1: 2}), DictConverter({2: 3}), DictConverter({3: 4})])
|
||||
>>> pv.to_python(1)
|
||||
4
|
||||
>>> pv.to_python(1)
|
||||
4
|
||||
>>> pv.from_python(4)
|
||||
1
|
||||
>>> pv.from_python(4)
|
||||
1
|
||||
>>> pv.to_python(1)
|
||||
4
|
||||
|
||||
"""
|
||||
|
||||
def __repr__(self):
|
||||
return '<Pipe %s>' % self.validators
|
||||
|
||||
def attempt_convert(self, value, state, validate):
|
||||
# To preserve the order of the transformations, we do them
|
||||
# differently when we are converting to and from Python.
|
||||
if validate is from_python:
|
||||
validators = list(self.validators)
|
||||
validators.reverse()
|
||||
else:
|
||||
validators = self.validators
|
||||
try:
|
||||
for validator in validators:
|
||||
value = validate(validator, value, state)
|
||||
return value
|
||||
except Invalid:
|
||||
if self.if_invalid is NoDefault:
|
||||
raise
|
||||
return self.if_invalid
|
||||
Reference in New Issue
Block a user