Ignore:
Timestamp:
4 Jun 2011, 02:29:21 (13 years ago)
Author:
uli
Message:

Finally make the new converter work. API-wise it is as good as the old one (can import everyting, the old one could),
but design-wise it might be much more powerfull. Basically it can handle/convert all content-types for which one can
create an Add- or EditForm? successfully. In other words: if you manage to write an edit form for some content type,
then you can also create an importer for that content-type. Still finetuning needed (for dates, bool data, etc.) but
the main things work.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • main/waeup.sirp/trunk/src/waeup/sirp/utils/converters.py

    r6263 r6273  
    245245from zope.formlib import form
    246246from zope.formlib.form import (
    247     _widgetKey, WidgetInputError, ValidationError, InputErrors, expandPrefix)
     247    _widgetKey, WidgetInputError, ValidationError, InputErrors, expandPrefix,
     248    setUpInputWidgets)
    248249from zope.formlib.interfaces import IInputWidget
    249250from zope.publisher.browser import TestRequest
     251from waeup.sirp.interfaces import IObjectConverter
    250252
    251253def 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    """
    252270    errors = []
    253271    form_prefix = expandPrefix(form_prefix)
     
    271289    return errors
    272290
    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 any
    279         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 an
    287         object or string as `context`.
    288 
    289         If `context` is a string, this is understood as a factory name
    290         and we will try to create a proper object calling
    291         ``createObject()``.
    292 
    293         `form_fields` are by default (``None``) buildt from the given
    294         `iface` but can also be passed in to override the
    295         default. This might be handy if you want to omit or select
    296         certains fields from the interface.
    297 
    298         Returns a tuple ``(<ERROR_LIST, INV_ERR_LIST, OBJ>)`` where
    299         ``ERROR_DICT`` is a dict of errors for single fields (if
    300         happened), ``INV_ERR_LIST`` is a list of invariant errors
    301         happened (errors that apply to several fields), and ``OBJ`` is
    302         the created/updated object.
    303         """
    304 
    305291class 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.
    309296    """
    310297
     
    314301    def __init__(self, iface):
    315302        self.iface = iface
    316         self.form_fields = form.Fields(iface)
     303        self.default_form_fields = form.Fields(iface)
    317304        return
    318305
    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        """
    320347        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
    322353
    323354        obj = context
    324355        if isinstance(context, basestring):
    325356            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(
    330359            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
Note: See TracChangeset for help on using the changeset viewer.