Changeset 304
- Timestamp:
- 04/03/08 17:04:10 (9 months ago)
- Files:
-
- trunk/ChangeLog (modified) (1 diff)
- trunk/formal/examples/main.py (modified) (1 diff)
- trunk/formal/examples/sequences.py (added)
- trunk/formal/types.py (modified) (1 diff)
- trunk/formal/validation.py (modified) (2 diffs)
- trunk/formal/widget.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/ChangeLog
r298 r304 1 2008-04-03 Matt Goodall <matt@pollenation.net> 2 3 Enhanced the Sequence type and the TextAreaList (the default widget for the 4 type). 5 6 The TextAreaList no longer strips all lines, leaving it to the Sequence's 7 item type to decide. 8 9 The Sequence now also runs it's type's validator on each item allowing 10 constructs such as: 11 12 Sequence(String(validators=[LengthValidator(min=2)]), 13 validators=[LengthValidator(max=3, unit=u"lines")]) 14 15 i.e. a list containing a maximum of 3 strings, where each string is at 16 least 2 characters long. 17 1 18 2007-09-29 Matt Goodall <matt@pollenation.net> 2 19 trunk/formal/examples/main.py
r289 r304 27 27 'formal.examples.textareawithselect.TextAreaWithSelectFormPage', 28 28 'formal.examples.richtextarea.RichTextAreaFormPage', 29 'formal.examples.sequences.SequencesFormPage', 29 30 ] 30 31 trunk/formal/types.py
r298 r304 134 134 135 135 def validate(self, value): 136 # Map empty sequence to None 136 # Map empty sequence to None. Otherwise validate each item according to 137 # type. 137 138 if not value: 138 value = None 139 return super(Sequence, self).validate(value) 139 d = defer.succeed(None) 140 else: 141 d = self._validateItems(value) 142 # Return superclass's response 143 return d.addCallback(super(Sequence, self).validate) 144 145 def _validateItems(self, value): 146 147 def validated(response): 148 for (success, result) in response: 149 if not success: 150 raise result 151 yield result 152 153 d = defer.DeferredList([self.type.validate(item) for item in value], 154 consumeErrors=True) 155 d.addCallback(validated) 156 d.addCallback(list) 157 return d 140 158 141 159 trunk/formal/validation.py
r301 r304 63 63 implements(iformal.IValidator) 64 64 65 def __init__(self, min=None, max=None ):65 def __init__(self, min=None, max=None, unit="characters"): 66 66 self.min = min 67 67 self.max = max 68 self.unit = unit 68 69 assert self.min is not None or self.max is not None 69 70 70 71 def validationErrorMessage(self, field): 71 72 if self.min is not None and self.max is None: 72 return 'Must be longer than %r characters'%(self.min,)73 return 'Must be at least %r %s'%(self.min, self.unit) 73 74 if self.min is None and self.max is not None: 74 return 'Must be shorter than %r characters'%(self.max,)75 return 'Must be between %r and %r characters'%(self.min, self.max)75 return 'Must be at most %r %s'%(self.max, self.unit) 76 return 'Must be between %r and %r %s'%(self.min, self.max, self.unit) 76 77 77 78 def validate(self, field, value): … … 97 98 def validationErrorMessage(self, field): 98 99 if self.min is not None and self.max is None: 99 return 'Must be greater than %r'%(self.min,)100 return 'Must be %r or greater'%(self.min,) 100 101 if self.min is None and self.max is not None: 101 return 'Must be less than %r'%(self.max,)102 return 'Must be %r or less'%(self.max,) 102 103 return 'Must be between %r and %r'%(self.min, self.max) 103 104 trunk/formal/widget.py
r294 r304 194 194 # Get the whole string 195 195 value = args.get(key, [''])[0].decode(util.getPOSTCharset(ctx)) 196 # Split into lines 197 values = value.splitlines() 198 # Strip each line 199 values = [v.strip() for v in values] 200 # Discard empty lines 201 values = [v for v in values if v] 196 # Split into lines, discarding empty lines 197 values = [line for line in value.splitlines() if line.strip()] 202 198 # Convert values to correct type 203 199 converter = iformal.IStringConvertible(self.original.type)
