source: main/waeup.sirp/trunk/src/waeup/sirp/utils/converters.py @ 7193

Last change on this file since 7193 was 7137, checked in by Henrik Bettermann, 13 years ago

Set value Id for property svn:keywords in all Python files.

  • Property svn:keywords set to Id
File size: 5.9 KB
Line 
1"""Converters for zope.schema-based datatypes.
2"""
3import grok
4from zope.component import createObject
5from zope.formlib import form
6from zope.formlib.boolwidgets import CheckBoxWidget
7from zope.formlib.form import (
8    _widgetKey, WidgetInputError, ValidationError, InputErrors, expandPrefix)
9from zope.formlib.interfaces import IInputWidget, ISimpleInputWidget
10from zope.interface import Interface
11from zope.publisher.browser import TestRequest
12from waeup.sirp.interfaces import IObjectConverter
13
14class ExtendedCheckBoxWidget(CheckBoxWidget):
15    """A checkbox widget that supports more input values as True/False
16       markers.
17
18    The default bool widget expects the string 'on' as only valid
19    ``True`` value in HTML forms for bool fields.
20
21    This widget also accepts '1', 'true' and 'yes' for that. Also all
22    uppercase/lowecase combinations of these strings are accepted.
23
24    The widget still renders ``True`` to ``'on'`` when a form is
25    generated.
26    """
27    true_markers = ['1', 'true', 'on', 'yes']
28
29    def _toFieldValue(self, input):
30        """Convert from HTML presentation to Python bool."""
31        if not isinstance(input, basestring):
32            return False
33        return input.lower() in self.true_markers
34
35    def _getFormInput(self):
36        """Returns the form input used by `_toFieldValue`.
37
38        Return values:
39
40          ``'on'``  checkbox is checked
41          ``''``    checkbox is not checked
42          ``None``  form input was not provided
43
44        """
45        value = self.request.get(self.name)
46        if isinstance(value, basestring):
47            value = value.lower()
48        if value in self.true_markers:
49            return 'on'
50        elif self.name + '.used' in self.request:
51            return ''
52        else:
53            return None
54
55def getWidgetsData(widgets, form_prefix, data):
56    """Get data and validation errors from `widgets` for `data`.
57
58    Updates the dict in `data` with values from the widgets in
59    `widgets`.
60
61    Returns a list of tuples ``(<WIDGET_NAME>, <ERROR>)`` where
62    ``<WIDGET_NAME>`` is a widget name (normally the same as the
63    associated field name) and ``<ERROR>`` is the exception that
64    happened for that widget/field.
65
66    This is merely a copy from the same-named function in
67    :mod:`zope.formlib.form`. The only difference is that we also
68    store the fieldname for which a validation error happened in the
69    returned error list (what the original does not do).
70
71    """
72    errors = []
73    form_prefix = expandPrefix(form_prefix)
74
75    for input, widget in widgets.__iter_input_and_widget__():
76        if input and IInputWidget.providedBy(widget):
77            name = _widgetKey(widget, form_prefix)
78
79            if not widget.hasInput():
80                continue
81
82            try:
83                data[name] = widget.getInputValue()
84            except ValidationError, error:
85                # convert field ValidationError to WidgetInputError
86                error = WidgetInputError(widget.name, widget.label, error)
87                errors.append((name, error))
88            except InputErrors, error:
89                errors.append((name, error))
90
91    return errors
92
93
94class DefaultObjectConverter(grok.Adapter):
95    """Turn string values into real values.
96
97    A converter can convert string values for objects that implement a
98    certain interface into real values based on the given interface.
99    """
100
101    grok.context(Interface)
102    grok.provides(IObjectConverter)
103
104    def __init__(self, iface):
105        self.iface = iface
106        self.default_form_fields = form.Fields(iface)
107        return
108
109    def fromStringDict(self, data_dict, context, form_fields=None):
110        """Convert values in `data_dict`.
111
112        Converts data in `data_dict` into real values based on
113        `context` and `form_fields`.
114
115        `data_dict` is a mapping (dict) from field names to values
116        represented as strings.
117
118        The fields (keys) to convert can be given in optional
119        `form_fields`. If given, form_fields should be an instance of
120        :class:`zope.formlib.form.Fields`. Suitable instances are for
121        example created by :class:`grok.AutoFields`.
122
123        If no `form_fields` are given, a default is computed from the
124        associated interface.
125
126        The `context` can be an existing object (implementing the
127        associated interface) or a factory name. If it is a string, we
128        try to create an object using
129        :func:`zope.component.createObject`.
130
131        Returns a tuple ``(<FIELD_ERRORS>, <INVARIANT_ERRORS>,
132        <DATA_DICT>)`` where
133
134        ``<FIELD_ERRORS>``
135           is a list of tuples ``(<FIELD_NAME>, <ERROR>)`` for each
136           error that happened when validating the input data in
137           `data_dict`
138
139        ``<INVARIANT_ERRORS>``
140           is a list of invariant errors concerning several fields
141
142        ``<DATA_DICT>``
143           is a dict with the values from input dict converted.
144
145        If errors happen, i.e. the error lists are not empty, always
146        an empty ``<DATA_DICT>`` is returned.
147
148        If ``<DATA_DICT>` is non-empty, there were no errors.
149        """
150        if form_fields is None:
151            form_fields = self.default_form_fields
152
153        request = TestRequest(form={})
154        for key, val in data_dict.items():
155            request.form['form.%s' % key] = val
156
157        obj = context
158        if isinstance(context, basestring):
159            obj = createObject(context)
160
161        widgets = form.setUpInputWidgets(
162            form_fields, 'form', obj, request)
163
164        new_data = dict()
165        errors = getWidgetsData(widgets, 'form', new_data)
166
167        invariant_errors = form.checkInvariants(form_fields, new_data)
168        if errors or invariant_errors:
169            err_messages = [(key, err.args[0]) for key, err in errors]
170            invariant_errors = [err.message for err in invariant_errors]
171            return err_messages, invariant_errors, {}
172
173        return errors, invariant_errors, new_data
Note: See TracBrowser for help on using the repository browser.