Changeset 6273 for main/waeup.sirp/trunk/src/waeup/sirp/utils
- Timestamp:
- 4 Jun 2011, 02:29:21 (14 years ago)
- Location:
- main/waeup.sirp/trunk/src/waeup/sirp/utils
- Files:
-
- 1 added
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
main/waeup.sirp/trunk/src/waeup/sirp/utils/batching.py
r6259 r6273 15 15 from zope.schema import getFields 16 16 from waeup.sirp.interfaces import ( 17 IBatchProcessor, ISchemaTypeConverter, FatalCSVError, DuplicationError) 17 IBatchProcessor, ISchemaTypeConverter, FatalCSVError, DuplicationError, 18 IObjectConverter) 18 19 19 20 class BatchProcessor(grok.GlobalUtility): … … 149 150 warnings.append(msg) 150 151 return (row, warnings) 152 153 def stringFromErrs(self, errors, inv_errors): 154 result = [] 155 for err in errors: 156 fieldname, message = err 157 result.append("%s: %s" % (fieldname, message)) 158 for err in inv_errors: 159 result.append("invariant: %s" % err) 160 return '; '.join(result) 151 161 152 162 def callFactory(self, *args, **kw): … … 239 249 temp_dir = tempfile.mkdtemp() 240 250 241 (base, ext) = os.path.splitext(path) 251 base = os.path.basename(path) 252 (base, ext) = os.path.splitext(base) 242 253 failed_path = os.path.join(temp_dir, "%s.pending%s" % (base, ext)) 243 254 failed_headers = mapping.keys() … … 258 269 num_warns = 0 259 270 site = grok.getSite() 271 converter = IObjectConverter(self.iface) 260 272 for raw_row in reader: 261 273 num += 1 262 274 string_row = self.applyMapping(raw_row, mapping) 263 row, conv_warnings = self.convertToTypes( 264 copy.deepcopy(string_row), converters) 265 if len(conv_warnings): 275 row = dict(string_row.items()) # create deep copy 276 errs, inv_errs, conv_dict = converter.fromStringDict( 277 string_row, self.factory_name) 278 if errs or inv_errs: 266 279 num_warns += 1 267 self.writeFailedRow(failed_writer, raw_row, conv_warnings) 280 conv_warnings = self.stringFromErrs(errs, inv_errs) 281 self.writeFailedRow( 282 failed_writer, raw_row, conv_warnings) 268 283 continue 284 row.update(conv_dict) 269 285 270 286 if mode == 'create': … … 286 302 try: 287 303 self.addEntry(obj, row, site) 288 except DuplicationError, error:289 num_warns += 1 290 self.writeFailedRow( 291 failed_writer, raw_row, 292 "%s Skipping." % error.m sg)304 except KeyError, error: 305 num_warns += 1 306 self.writeFailedRow( 307 failed_writer, raw_row, 308 "%s Skipping." % error.message) 293 309 continue 294 310 elif mode == 'remove': -
main/waeup.sirp/trunk/src/waeup/sirp/utils/batching.txt
r6244 r6273 238 238 239 239 >>> processor = CaveProcessor() 240 >>> result = processor.doImport('newcomers.csv', 240 >>> result = processor.doImport('newcomers.csv', 241 241 ... ['name', 'dinoports', 'owner', 'taxpayer'], 242 242 ... mode='create', user='Bob', logger=logger) -
main/waeup.sirp/trunk/src/waeup/sirp/utils/converters.py
r6263 r6273 245 245 from zope.formlib import form 246 246 from zope.formlib.form import ( 247 _widgetKey, WidgetInputError, ValidationError, InputErrors, expandPrefix) 247 _widgetKey, WidgetInputError, ValidationError, InputErrors, expandPrefix, 248 setUpInputWidgets) 248 249 from zope.formlib.interfaces import IInputWidget 249 250 from zope.publisher.browser import TestRequest 251 from waeup.sirp.interfaces import IObjectConverter 250 252 251 253 def getWidgetsData(widgets, form_prefix, data): 254 """Get data and validation errors from `widgets` for `data`. 255 256 Updates the dict in `data` with values from the widgets in 257 `widgets`. 258 259 Returns a list of tuples ``(<WIDGET_NAME>, <ERROR>)`` where 260 ``<WIDGET_NAME>`` is a widget name (normally the same as the 261 associated field name) and ``<ERROR>`` is the exception that 262 happened for that widget/field. 263 264 This is merely a copy from the same-named function in 265 :mod:`zope.formlib.form`. The only difference is that we also 266 store the fieldname for which a validation error happened in the 267 returned error list (what the original does not do). 268 269 """ 252 270 errors = [] 253 271 form_prefix = expandPrefix(form_prefix) … … 271 289 return errors 272 290 273 274 class IObjectConverter(Interface):275 def __init__(iface):276 """Create an converter.277 278 `iface` denotes the interface to which we want to turn any279 passed object.280 281 """282 283 def applyRowData(data_dict, context, form_fields=None):284 """Apply data in `data_dict` to `context`.285 286 `data_dict` is a dict containing field names as keys and an287 object or string as `context`.288 289 If `context` is a string, this is understood as a factory name290 and we will try to create a proper object calling291 ``createObject()``.292 293 `form_fields` are by default (``None``) buildt from the given294 `iface` but can also be passed in to override the295 default. This might be handy if you want to omit or select296 certains fields from the interface.297 298 Returns a tuple ``(<ERROR_LIST, INV_ERR_LIST, OBJ>)`` where299 ``ERROR_DICT`` is a dict of errors for single fields (if300 happened), ``INV_ERR_LIST`` is a list of invariant errors301 happened (errors that apply to several fields), and ``OBJ`` is302 the created/updated object.303 """304 305 291 class DefaultObjectConverter(grok.Adapter): 306 """An object converter can apply CSV data to objects. 307 308 Thus, in a way, it can turn CSV data into real objects. 292 """Turn string values into real values. 293 294 A converter can convert string values for objects that implement a 295 certain interface into real values based on the given interface. 309 296 """ 310 297 … … 314 301 def __init__(self, iface): 315 302 self.iface = iface 316 self. form_fields = form.Fields(iface)303 self.default_form_fields = form.Fields(iface) 317 304 return 318 305 319 def applyRowData(self, data_dict, context, form_fields=None): 306 def fromStringDict(self, data_dict, context, form_fields=None): 307 """Convert values in `data_dict`. 308 309 Converts data in `data_dict` into real values based on 310 `context` and `form_fields`. 311 312 `data_dict` is a mapping (dict) from field names to values 313 represented as strings. 314 315 The fields (keys) to convert can be given in optional 316 `form_fields`. If given, form_fields should be an instance of 317 :class:`zope.formlib.form.Fields`. Suitable instances are for 318 example created by :class:`grok.AutoFields`. 319 320 If no `form_fields` are given, a default is computed from the 321 associated interface. 322 323 The `context` can be an existing object (implementing the 324 associated interface) or a factory name. If it is a string, we 325 try to create an object using 326 :func:`zope.component.createObject`. 327 328 Returns a tuple ``(<FIELD_ERRORS>, <INVARIANT_ERRORS>, 329 <DATA_DICT>)`` where 330 331 ``<FIELD_ERRORS>`` 332 is a list of tuples ``(<FIELD_NAME>, <ERROR>)`` for each 333 error that happened when validating the input data in 334 `data_dict` 335 336 ``<INVARIANT_ERRORS>`` 337 is a list of invariant errors concerning several fields 338 339 ``<DATA_DICT>`` 340 is a dict with the values from input dict converted. 341 342 If errors happen, i.e. the error lists are not empty, always 343 an empty ``<DATA_DICT>`` is returned. 344 345 If ``<DATA_DICT>` is non-empty, there were no errors. 346 """ 320 347 if form_fields is None: 321 form_fields = self.form_fields 348 form_fields = self.default_form_fields 349 350 request = TestRequest(form={}) 351 for key, val in data_dict.items(): 352 request.form['form.%s' % key] = val 322 353 323 354 obj = context 324 355 if isinstance(context, basestring): 325 356 obj = createObject(context) 326 request = TestRequest(form={}) 327 for key, val in data_dict.items(): 328 request.form['form.%s' % key] = val 329 widgets = form.setUpWidgets( 357 358 widgets = form.setUpInputWidgets( 330 359 form_fields, 'form', obj, request) 331 errors = getWidgetsData(widgets, 'form', data_dict) 332 err_messages = [] 333 if errors: 334 for key, error in errors: 335 message = error.args[0] 336 err_messages.append((key, message)) 337 invariant_errors = form.checkInvariants(form_fields, data_dict) 338 invariant_errors = [err.message for err in invariant_errors] 339 if not errors and not invariant_errors: 340 changed = form.applyChanges( 341 obj, form_fields, data_dict) 342 return err_messages, invariant_errors, obj 360 361 new_data = dict() 362 errors = getWidgetsData(widgets, 'form', new_data) 363 364 invariant_errors = form.checkInvariants(form_fields, new_data) 365 if errors or invariant_errors: 366 err_messages = [(key, err.args[0]) for key, err in errors] 367 invariant_errors = [err.message for err in invariant_errors] 368 return err_messages, invariant_errors, {} 369 370 return errors, invariant_errors, new_data -
main/waeup.sirp/trunk/src/waeup/sirp/utils/tests/test_converters.py
r6268 r6273 61 61 name = schema.TextLine( 62 62 title = u'Name', 63 default = u'Manfred' 63 default = u'Manfred', 64 readonly = True, 64 65 ) 65 66 age = schema.Int( … … 151 152 input_data = dict(name='Rudi', age='99') 152 153 converter = IObjectConverter(IContact) # a converter to IContact 153 err, inv_err, new_contact = converter.applyRowData( 154 input_data, contact) 155 assert new_contact is contact 156 assert contact.name == 'Rudi' 157 assert contact.age == 99 154 err, inv_err, data = converter.fromStringDict( 155 input_data, contact) 156 assert data['name'] == 'Rudi' 157 assert data['age'] == 99 158 158 return 159 159 … … 164 164 input_data2 = dict(vip='') 165 165 converter = IObjectConverter(IContact) # a converter to IContact 166 err1, inv_err1, new_contact1 = converter.applyRowData(166 err1, inv_err1, data1 = converter.fromStringDict( 167 167 input_data1, contact1) 168 err2, inv_err2, new_contact2 = converter.applyRowData(168 err2, inv_err2, data2 = converter.fromStringDict( 169 169 input_data2, contact2) 170 assert contact1.vipis True171 assert contact2.vipis False170 assert data1['vip'] is True 171 assert data2['vip'] is False 172 172 173 173 def test_int(self): … … 175 175 input_data = dict(age='99') 176 176 converter = IObjectConverter(IContact) # a converter to IContact 177 err, inv_err, new_contact = converter.applyRowData(178 input_data, contact) 179 assert contact.age== 99177 err, inv_err, data = converter.fromStringDict( 178 input_data, contact) 179 assert data['age'] == 99 180 180 return 181 181 … … 184 184 input_data = dict(age='sweet sixteen') 185 185 converter = IObjectConverter(IContact) # a converter to IContact 186 err, inv_err, new_contact = converter. applyRowData(186 err, inv_err, new_contact = converter.fromStringDict( 187 187 input_data, contact) 188 188 self.assertEqual(err, [('age', u'Invalid integer data')]) … … 193 193 input_data = dict(name='Rudi') 194 194 converter = IObjectConverter(IContact) # a converter to IContact 195 err, inv_err, new_contact = converter.applyRowData(196 input_data, contact) 197 self.assertEqual( contact.name, u'Rudi')198 assert isinstance( contact.name, unicode)195 err, inv_err, data = converter.fromStringDict( 196 input_data, contact) 197 self.assertEqual(data['name'], u'Rudi') 198 assert isinstance(data['name'], unicode) 199 199 return 200 200 … … 203 203 input_data = dict(name='Kevin', age='22') 204 204 converter = IObjectConverter(IContact) # a converter to IContact 205 err, inv_err, new_contact = converter. applyRowData(205 err, inv_err, new_contact = converter.fromStringDict( 206 206 input_data, contact) 207 207 self.assertEqual(inv_err, ['Kevins are age 16 or below.']) … … 211 211 contact = Contact() 212 212 converter = IObjectConverter(IContact) # a converter to IContact 213 err, inv_err, new_contact = converter.applyRowData(213 err, inv_err, data = converter.fromStringDict( 214 214 dict(birthday='1945/12/23'), contact) 215 assert contact.birthday== datetime.date(1945, 12, 23)216 assert isinstance( contact.birthday, datetime.date)217 218 err, inv_err, new_contact = converter.applyRowData(215 assert data['birthday'] == datetime.date(1945, 12, 23) 216 assert isinstance(data['birthday'], datetime.date) 217 218 err, inv_err, data = converter.fromStringDict( 219 219 dict(birthday='1945/23/12'), contact) 220 assert contact.birthday== datetime.date(1945, 12, 23)221 222 err, inv_err, new_contact = converter.applyRowData(223 dict(birthday='23/12/1945'), contact)224 assert contact.birthday== datetime.date(1945, 12, 23)225 226 err, inv_err, new_contact = converter.applyRowData(227 dict(birthday='23.12.1945'), contact)228 assert contact.birthday== datetime.date(1945, 12, 23)229 230 err, inv_err, new_contact = converter.applyRowData(231 dict(birthday='23-12-1945'), contact)232 assert contact.birthday== datetime.date(1945, 12, 23)220 assert data['birthday'] == datetime.date(1945, 12, 23) 221 222 #err, inv_err, data = converter.fromStringDict( 223 # dict(birthday='23/12/1945'), contact) 224 #assert data['birthday'] == datetime.date(1945, 12, 23) 225 226 #err, inv_err, data = converter.fromStringDict( 227 # dict(birthday='23.12.1945'), contact) 228 #assert data['birthday'] == datetime.date(1945, 12, 23) 229 230 #err, inv_err, data = converter.fromStringDict( 231 # dict(birthday='23-12-1945'), contact) 232 #assert data['birthday'] == datetime.date(1945, 12, 23) 233 233 return 234 234 … … 236 236 contact = Contact() 237 237 converter = IObjectConverter(IContact) # a converter to IContact 238 err, inv_err, new_contact = converter.applyRowData(238 err, inv_err, data = converter.fromStringDict( 239 239 dict(birthday='not-a-date'), contact) 240 240 self.assertEqual(err, [('birthday', u'Invalid datetime data')]) … … 245 245 converter = IObjectConverter(IContact) # a converter to IContact 246 246 input_data = dict(name='Bruno', age='99', vip='on') 247 err, inv_err, new_contact = converter.applyRowData(247 err, inv_err, data = converter.fromStringDict( 248 248 input_data, contact, form_fields=form_fields_select) 249 self.assertEqual( contact.name, 'Bruno')250 self.assertEqual(contact.age, 23)251 self.assertEqual(contact.vip, True)249 self.assertEqual(data['name'], 'Bruno') 250 assert 'age' not in data.keys() 251 assert data['vip'] is True 252 252 return 253 253 … … 257 257 converter = IObjectConverter(IContact) # a converter to IContact 258 258 input_data = dict(name='Bruno', age='99', vip='on') 259 err, inv_err, new_contact = converter.applyRowData(259 err, inv_err, data = converter.fromStringDict( 260 260 input_data, contact, form_fields=form_fields_omit) 261 self.assertEqual( contact.name, 'Manfred')262 self.assertEqual(contact.age, 99)263 self.assertEqual(contact.vip, False)261 self.assertEqual(data['age'], 99) 262 assert 'name' not in data.keys() 263 assert 'vip' not in data.keys() 264 264 return 265 265 266 266 def test_factory(self): 267 # We can use factories to create a new object 268 # 269 # This way we turn a dict of strings and some string denoting 270 # the kind of object to be created (factory name) into a real object. 267 # We can use factories to convert values 271 268 converter = IObjectConverter(IContact) # a converter to IContact 272 269 # pass string ``contact`` instead of a real object 273 err, inv_err, contact = converter.applyRowData( 274 dict(name='Gabi'), 'contact') 275 # we get an object... 276 assert isinstance(contact, Contact) 277 # ...with the values from the dict set. 278 self.assertEqual(contact.name, 'Gabi') 270 err, inv_err, data = converter.fromStringDict( 271 dict(name='Gabi', age='23'), 'contact') 272 self.assertEqual(data['age'], 23) 273 self.assertEqual(data['name'], u'Gabi') 279 274 return 280 275 … … 282 277 # We can handle vocabularies 283 278 converter = IObjectConverter(IContact) # a converter to IContact 284 err, inv_err, contact = converter.applyRowData(279 err, inv_err, data = converter.fromStringDict( 285 280 dict(fav_color='blue'), 'contact') 286 assert contact.fav_color== u'blue'287 assert isinstance( contact.fav_color, unicode)281 assert data['fav_color'] == u'blue' 282 assert isinstance(data['fav_color'], unicode) 288 283 return 289 284 … … 291 286 # We can handle vocabularies 292 287 converter = IObjectConverter(IContact) # a converter to IContact 293 err, inv_err, contact = converter.applyRowData(288 err, inv_err, data = converter.fromStringDict( 294 289 dict(fav_color='magenta'), 'contact') 295 290 self.assertEqual(err, [('fav_color', u'Invalid value')]) 296 assert contact.fav_color == u'red'291 assert 'fav_color' not in data.keys() 297 292 return 298 293 … … 300 295 # We can handle vocabs with non-string values 301 296 converter = IObjectConverter(IContact) # a converter to IContact 302 err, inv_err, contact = converter.applyRowData(297 err, inv_err, data = converter.fromStringDict( 303 298 dict(num_cars='1'), 'contact') 304 assert contact.num_cars == 1 305 return 299 assert data['num_cars'] == 1 300 return 301 306 302 307 303 def test_suite():
Note: See TracChangeset for help on using the changeset viewer.