Changeset 239
- Timestamp:
- 07/05/06 09:53:11 (3 years ago)
- Files:
-
- branches/composite/formal/__init__.py (modified) (2 diffs)
- branches/composite/formal/examples/composite.py (modified) (3 diffs)
- branches/composite/formal/test/test_types.py (modified) (9 diffs)
- branches/composite/formal/types.py (modified) (1 diff)
- branches/composite/formal/widgets/composite.py (added)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
branches/composite/formal/__init__.py
r231 r239 12 12 from formal.validation import * 13 13 from formal.widget import * 14 from formal.widgets.composite import * 14 15 from formal.widgets.restwidget import * 15 16 from formal.widgets.multiselect import * … … 45 46 registerAdapter(TextInput, Time, iformal.IWidget) 46 47 registerAdapter(FileUploadRaw, File, iformal.IWidget) 48 registerAdapter(CompositeWidget, Composite, iformal.IWidget) 47 49 registerAdapter(SequenceKeyLabelAdapter, tuple, iformal.IKey) 48 50 registerAdapter(SequenceKeyLabelAdapter, tuple, iformal.ILabel) branches/composite/formal/examples/composite.py
r237 r239 1 from zope.interface import implements 2 from twisted.python.components import registerAdapter 3 from nevow import inevow, tags as T 4 import formal, formal.iformal, formal.types, formal.widget, formal.util 1 import formal 5 2 from formal.examples import main 6 7 8 9 #####10 # TODO:11 #12 # * composition labels, and position (?)13 # * composition widgets14 # * composition errors (?)15 # * composition description (?)16 # * Validate XHTML17 #18 19 20 21 class Composite(formal.types.Type):22 23 def __init__(self, composition, *a, **k):24 super(Composite, self).__init__(*a, **k)25 self.composition = composition26 27 28 def validate(self, value):29 30 # Check we have the correct number of values, otherwise the final value31 # could be completely wrong because we're relying on zip to build the32 # dict.33 if len(value) != len(self.composition):34 raise ValueError("Incorrect number of values to validate")35 36 # If nothing has been entered then we'll have a sequence of None37 # instances, in which case my value if None (not a sequence). If there38 # is anything other than None in the sequence then pass validation on to39 # the composite types.40 if not filter(None, value):41 value = None42 else:43 value = dict([44 (name, type.validate(value))45 for (name, type), value in zip(self.composition, value)])46 47 # Allow normal validation to run on the new value48 return super(Composite, self).validate(value)49 50 51 52 class CompositeWidget(object):53 implements(formal.iformal.IWidget)54 55 56 labels = None57 widgetFactories = None58 59 60 def __init__(self, composite, labels=None, widgetFactories=None):61 self.composite = composite62 if labels is not None:63 self.labels = labels64 if widgetFactories is not None:65 self.widgetFactories = widgetFactories66 67 68 def render(self, ctx, key, args, errors):69 for name, type in self.composite.composition:70 childKey = '.'.join([key, name])71 yield T.div(class_=name)[72 T.label(for_=formal.util.render_cssid(childKey))[73 formal.util.titleFromName(name)74 ],75 formal.iformal.IWidget(type).render(ctx, childKey, args, errors)76 ]77 78 79 def renderImmutable(self, ctx, key, args, errors):80 for name, type in self.composite.composition:81 childKey = '.'.join([key, name])82 yield T.div(class_=name)[83 T.label[formal.util.titleFromName(name)],84 formal.iformal.IWidget(type).renderImmutable(ctx, childKey,85 args, errors)86 ]87 88 89 def processInput(self, ctx, key, args):90 value = []91 for name, type in self.composite.composition:92 childKey = '.'.join([key, name])93 value.append(formal.iformal.IWidget(type).processInput(ctx,94 childKey, args))95 return tuple(value)96 97 98 99 registerAdapter(CompositeWidget, Composite, formal.iformal.IWidget)100 3 101 4 … … 113 16 # Add a required name where the family name is required but the first 114 17 # name is optional. 115 form.add(formal.Field('name', Composite([18 form.add(formal.Field('name', formal.Composite([ 116 19 ('family', formal.String(required=True)), 117 20 ('first', formal.String())], … … 120 23 # Add an optional temperature field where, once entered, both values 121 24 # must be entered. 122 form.add(formal.Field('temperature', Composite([25 form.add(formal.Field('temperature', formal.Composite([ 123 26 ('temperature', formal.Integer(required=True)), 124 27 ('units', formal.String(required=True))]))) 125 28 126 29 # Add a required height field where both values are also required. 127 form.add(formal.Field('height', Composite([30 form.add(formal.Field('height', formal.Composite([ 128 31 ('feet', formal.Integer(required=True)), 129 32 ('inches', formal.Integer(required=True))], branches/composite/formal/test/test_types.py
r237 r239 127 127 128 128 129 from formal.examples.composite import Composite130 131 129 class TestComposite(unittest.TestCase): 132 130 133 131 def test_one(self): 134 self.assertEquals( Composite([132 self.assertEquals(formal.Composite([ 135 133 ('foo', formal.String()) 136 134 ]).validate([u'bar']), {'foo': u'bar'}) 137 self.assertEquals( Composite([135 self.assertEquals(formal.Composite([ 138 136 ('foo', formal.Integer()) 139 137 ]).validate([123]), {'foo': 123}) 140 138 141 139 def test_multisame(self): 142 self.assertEquals( Composite([140 self.assertEquals(formal.Composite([ 143 141 ('foo', formal.String()), 144 142 ('bar', formal.String()) 145 143 ]).validate([u'foo', u'bar']), {'foo': u'foo', 'bar': u'bar'}) 146 self.assertEquals( Composite([144 self.assertEquals(formal.Composite([ 147 145 ('foo', formal.Integer()), 148 146 ('bar', formal.Integer()), … … 150 148 151 149 def test_multidiff(self): 152 self.assertEquals( Composite([150 self.assertEquals(formal.Composite([ 153 151 ('foo', formal.String()), 154 152 ('bar', formal.Integer()) 155 153 ]).validate([u'foo', 123]), {'foo': u'foo', 'bar': 123}) 156 self.assertEquals( Composite([154 self.assertEquals(formal.Composite([ 157 155 ('foo', formal.String()), 158 156 ('bar', formal.Integer()) … … 160 158 161 159 def test_none(self): 162 self.assertEquals( Composite([('foo',160 self.assertEquals(formal.Composite([('foo', 163 161 formal.String())]).validate([None]), None) 164 self.assertEquals( Composite([162 self.assertEquals(formal.Composite([ 165 163 ('foo', formal.String()), 166 164 ('bar', formal.Integer()) … … 169 167 def test_missing(self): 170 168 missing = object() 171 self.assertEquals( Composite([('foo',169 self.assertEquals(formal.Composite([('foo', 172 170 formal.String())], missing=missing).validate([None]), missing) 173 171 174 172 def test_notrequired_required(self): 175 self.assertEquals( Composite([173 self.assertEquals(formal.Composite([ 176 174 ('foo', formal.String(required=True)) 177 175 ]).validate([u'foo']), {'foo': u'foo'}) 178 self.assertEquals( Composite([176 self.assertEquals(formal.Composite([ 179 177 ('foo', formal.String(required=True)), 180 178 ('bar', formal.Integer(required=True)) 181 179 ]).validate([u'foo', 123]), {'foo': u'foo', 'bar': 123}) 182 self.assertEquals( Composite([180 self.assertEquals(formal.Composite([ 183 181 ('foo', formal.String(required=True)) 184 182 ]).validate([None]), None) 185 self.assertEquals( Composite([183 self.assertEquals(formal.Composite([ 186 184 ('foo', formal.String(required=True)), 187 185 ('bar', formal.Integer(required=True)) … … 189 187 190 188 def test_notrequired_onerequired(self): 191 self.assertEquals( Composite([189 self.assertEquals(formal.Composite([ 192 190 ('foo', formal.String(required=True)), 193 191 ('bar', formal.Integer()) 194 192 ]).validate([u'foo', None]), {'foo': u'foo', 'bar': None}) 195 self.assertEquals( Composite([193 self.assertEquals(formal.Composite([ 196 194 ('foo', formal.String(required=True)), 197 195 ('bar', formal.Integer()) 198 196 ]).validate([None, None]), None) 199 self.assertRaises(formal.FieldValidationError, Composite([197 self.assertRaises(formal.FieldValidationError, formal.Composite([ 200 198 ('foo', formal.String(required=True)), 201 199 ('bar', formal.Integer()) … … 203 201 204 202 def test_required(self): 205 self.assertEquals( Composite([203 self.assertEquals(formal.Composite([ 206 204 ('foo', formal.String()) 207 205 ], required=True).validate([u'foo']), {'foo': u'foo'}) 208 self.assertEquals( Composite([206 self.assertEquals(formal.Composite([ 209 207 ('foo', formal.String()), 210 208 ('bar', formal.Integer()) 211 209 ], required=True).validate([u'foo', None]), {'foo': u'foo', 'bar': None}) 212 self.assertEquals( Composite([210 self.assertEquals(formal.Composite([ 213 211 ('foo', formal.String()), 214 212 ('bar', formal.Integer()) 215 213 ], required=True).validate([None, 123]), {'foo': None, 'bar': 123}) 216 self.assertRaises(formal.FieldRequiredError, Composite([214 self.assertRaises(formal.FieldRequiredError, formal.Composite([ 217 215 ('foo', formal.String()) 218 216 ], required=True).validate, [None]) 219 self.assertRaises(formal.FieldRequiredError, Composite([217 self.assertRaises(formal.FieldRequiredError, formal.Composite([ 220 218 ('foo', formal.String()), 221 219 ('bar', formal.Integer()) … … 223 221 224 222 def test_required_onerequired(self): 225 self.assertEquals( Composite([223 self.assertEquals(formal.Composite([ 226 224 ('foo', formal.String(required=True)), 227 225 ('bar', formal.Integer()) 228 226 ], required=True).validate([u'foo', None]), {'foo': u'foo', 'bar': None}) 229 self.assertEquals( Composite([227 self.assertEquals(formal.Composite([ 230 228 ('foo', formal.String(required=True)), 231 229 ('bar', formal.Integer()) 232 230 ], required=True).validate([u'foo', 123]), {'foo': u'foo', 'bar': 123}) 233 self.assertRaises(formal.FieldRequiredError, Composite([231 self.assertRaises(formal.FieldRequiredError, formal.Composite([ 234 232 ('foo', formal.String(required=True)), 235 233 ('bar', formal.Integer()) 236 234 ], required=True).validate, [None, None]) 237 self.assertRaises(formal.FieldRequiredError, Composite([235 self.assertRaises(formal.FieldRequiredError, formal.Composite([ 238 236 ('foo', formal.String(required=True)), 239 237 ('bar', formal.Integer()) … … 241 239 242 240 def test_required_allrequired(self): 243 self.assertRaises(formal.FieldRequiredError, Composite([241 self.assertRaises(formal.FieldRequiredError, formal.Composite([ 244 242 ('foo', formal.String(required=True)) 245 243 ], required=True).validate, [None]) 246 self.assertRaises(formal.FieldRequiredError, Composite([244 self.assertRaises(formal.FieldRequiredError, formal.Composite([ 247 245 ('foo', formal.String(required=True)), 248 246 ('bar', formal.Integer(required=True)) 249 247 ], required=True).validate, [None, None]) 250 self.assertRaises(formal.FieldRequiredError, Composite([248 self.assertRaises(formal.FieldRequiredError, formal.Composite([ 251 249 ('foo', formal.String(required=True)), 252 250 ('bar', formal.Integer(required=True)) … … 254 252 255 253 def test_wrongNumberOfValues(self): 256 self.assertRaises(ValueError, Composite([254 self.assertRaises(ValueError, formal.Composite([ 257 255 ('foo', formal.Integer()), 258 256 ('bar', formal.String()), branches/composite/formal/types.py
r196 r239 132 132 133 133 134 135 class Composite(Type): 136 137 138 def __init__(self, composition, *a, **k): 139 super(Composite, self).__init__(*a, **k) 140 self.composition = composition 141 142 143 def validate(self, value): 144 145 # Check we have the correct number of values, otherwise the final value 146 # could be completely wrong because we're relying on zip to build the 147 # dict. 148 if len(value) != len(self.composition): 149 raise ValueError("Incorrect number of values to validate") 150 151 # If nothing has been entered then we'll have a sequence of None 152 # instances, in which case my value if None (not a sequence). If there 153 # is anything other than None in the sequence then pass validation on to 154 # the composite types. 155 if not filter(None, value): 156 value = None 157 else: 158 value = dict([ 159 (name, type.validate(value)) 160 for (name, type), value in zip(self.composition, value)]) 161 162 # Allow normal validation to run on the new value 163 return super(Composite, self).validate(value) 164 165 166 134 167 __all__ = [ 135 'Boolean', 'Date', 'File', 'Float', 'Integer', 'Sequence', 'String', 'Time', 168 'Boolean', 'Composite', 'Date', 'File', 'Float', 'Integer', 'Sequence', 169 'String', 'Time', 136 170 ] 137 171
