[Zope3-checkins] CVS: Zope3/src/zope/app/form - utility.py:1.22.2.1 widget.py:1.7.2.1
Garrett Smith
garrett@mojave-corp.com
Tue, 22 Jul 2003 09:01:35 -0400
Update of /cvs-repository/Zope3/src/zope/app/form
In directory cvs.zope.org:/tmp/cvs-serv26193/src/zope/app/form
Modified Files:
Tag: garrett-widgets-branch
utility.py widget.py
Log Message:
CVS: ----------------------------------------------------------------------
CVS: Enter Log. Lines beginning with `CVS:' are removed automatically
CVS:
CVS: Committing in .
CVS:
CVS: Modified Files:
CVS: Tag: garrett-widgets-branch
CVS: src/zope/app/browser/cache/cacheable.py
CVS: src/zope/app/browser/component/interfacewidget.py
CVS: src/zope/app/browser/component/tests/test_interfacewidget.py
CVS: src/zope/app/browser/form/editview.py
CVS: src/zope/app/browser/form/vocabularywidget.py
CVS: src/zope/app/browser/form/widget.py
CVS: src/zope/app/browser/form/tests/test_browserwidget.py
CVS: src/zope/app/browser/form/tests/test_checkboxwidget.py
CVS: src/zope/app/browser/form/tests/test_datetimewidget.py
CVS: src/zope/app/browser/form/tests/test_editview.py
CVS: src/zope/app/browser/form/tests/test_floatwidget.py
CVS: src/zope/app/browser/form/tests/test_intwidget.py
CVS: src/zope/app/browser/form/tests/test_objectwidget.py
CVS: src/zope/app/browser/form/tests/test_sequencewidget.py
CVS: src/zope/app/browser/form/tests/test_vocabularywidget.py
CVS: src/zope/app/browser/security/permissionwidget.py
CVS: src/zope/app/browser/services/field.py
CVS: src/zope/app/browser/services/registration/__init__.py
CVS: src/zope/app/browser/services/tests/test_field_widget.py
CVS: src/zope/app/browser/skins/rotterdam/editingwidgets.py
CVS: src/zope/app/dav/configure.zcml src/zope/app/dav/widget.py
CVS: src/zope/app/form/utility.py src/zope/app/form/widget.py
CVS: src/zope/app/form/tests/test_utility.py
CVS: src/zope/app/form/tests/test_widget_geddon_deprecations.py
CVS: src/zope/app/interfaces/form.py
CVS: src/zope/schema/_bootstrapfields.py
CVS: ----------------------------------------------------------------------
Several changes related to widgets:
- Changed haveData to hasData.
- Propogated the use of Field.missing_value as an alternative to
explicit checks for None and '' (empty string).
- Changed the default implementation of hasData (was haveData) to return
True only if the one of the following was true:
- setData had been called for the widget. Per IWidget, values passed to
setData override all other data sources for a widget.
- There is a value in the request form that corresponds to the widget
field.
Prior to this change, hasData would return False if the widget's data
equaled the field's missing value. E.g., a text widget with an empty
string would return False, indicating that it has no data, even though
the empty string, a legitmate value, was submitted in the request.
This change required a handful of other changes to reflect the new
logic.
The bulk of this change effected widget.py. To see how the new logic
implementation of hasData effected widgets, see test_browserwidget.py
and test_utility.py.
- Modified the update logic for objects to skip fields that are not
present in the request form. Prior to this change, unspecified values
(i.e. values not in the request form) would cause default values to be
set for corresponding object fields.
- Exposed missing_value in initializer for Field - developers can now
specify a missing value for a schema field.
- Changed the default implementation of field validation. Prior to this
change, validation failed if a required value was missing. Now validation
is limited to validating non-missing values and the check for required
values is performed elsewhere.
- Text fields have a missing_value of '' (empty string) instead of None.
- Widget related error classes have been revamped:
- WidgetInputError, the base class for all widget related errors, now
provides two attributes: widget, the widget associated with the
error, and error_msg, a string describing the error,
- WidgetInputError implements 'args' so it can be rendered like other
errors.
- MissingInputError uses a standard error message.
- All uses of WidgetInputError and its subclasses have been updated
to use the new class.
- Deleted class zope.app.browser.form.widget.PossiblyEmptyMeansMissing.
This capability is now handled by setting a field's missing_value to ''
(empty string).
- Changed widget's _showData:
- Renamed to getUnconvertedData to clarify the method meaning and signal
its use as a public method.
- Positioned the method as a complement to getData, which returns data
in its converted form. getUnconvertedData returns data in its
unconvereted form using _unconvert.
- Renamed the 'force' argument used in various setUpWidget methods in
utility.py to 'ignore_unspecified'. This argument is set to True to
ensure that fields that are not in a form are not used to update their
corresponding widget. This argument should be true during object
updates (see editview.py) to ensure that unspecified fields are not
updated.
- Removed the 'strict' argument from applyWidgetChanges since no one was
using it and there's no clear application for it.
=== Zope3/src/zope/app/form/utility.py 1.22 => 1.22.2.1 ===
--- Zope3/src/zope/app/form/utility.py:1.22 Sun Jul 13 02:47:21 2003
+++ Zope3/src/zope/app/form/utility.py Tue Jul 22 09:00:59 2003
@@ -38,9 +38,11 @@
from zope.component import getView, getDefaultViewName
from zope.schema import getFieldsInOrder
from zope.schema.interfaces import ValidationError
+from zope.schema.errornames import RequiredMissing
from zope.app.interfaces.form import IWidget
-from zope.app.interfaces.form import WidgetsError, MissingInputError
-from zope.app.interfaces.form import InputErrors
+from zope.app.interfaces.form import WidgetsError
+from zope.app.interfaces.form import MissingInputError
+from zope.app.interfaces.form import WidgetInputError
from zope.component.interfaces import IViewFactory
def _fieldlist(names, schema):
@@ -89,20 +91,23 @@
return getattr(self.__widget, name)
def setUpWidget(view, name, field, value=None, prefix=None,
- force=False, vname=None, context=None):
+ ignore_unspecified=False, vname=None, context=None):
"""Set up a single view widget
The widget will be an attribute of the view. If there is already
an attribute of the given name, it must be a widget and it will be
- initialized with the given value if not None.
+ initialized with the given value
If there isn't already a view attribute of the given name, then a
widget will be created and assigned to the attribute.
+
+ If ignore_unspecified is True, widget values that aren't in the request
+ form (i.e. are not specified) will be ignored, preserving the field's
+ current value.
"""
# Has a (custom) widget already been defined?
wname = name+'_widget'
-
widget = getattr(view, wname, None)
installold = False
if widget is None:
@@ -161,53 +166,54 @@
if prefix:
widget.setPrefix(prefix)
- # XXX
- # Only set data if the widget doesn't have any itself already from the
- # request. This is a problem for something like a checkbox, where it
- # always claims to have data, becuase when there is no name in the request
- # for it, its value is False.
- # This is only a problem when force is False.
- #
- # It took me a while to work out what 'force' means in all these methods.
- # Perhaps it should be renamed 'preserveExistingData', and have the
- # opposite meaning.
- if value is not None and (force or not widget.haveData()):
+ if not ignore_unspecified and not widget.hasData():
widget.setData(value)
-def setUpWidgets(view, schema, prefix=None, force=False,
+def setUpWidgets(view, schema, prefix=None, ignore_unspecified=False,
initial={}, names=None, context=None):
- """Set up widgets for the fields defined by a schema
+ """Set up widgets for the fields defined by a schema.
+ Calls setUpWidget for each field in the specified schema. names can
+ contain a sequence of field names to use instead of those defined
+ in schema.
+
+ initial can be used to provide the intial widget values, keyed by
+ the field name.
+
+ If ignore_unspecified is True, values for fields that are not in the
+ request form (i.e. are 'unspecified' in the form submission) are not
+ used to update the field's widget data.
"""
for (name, field) in _fieldlist(names, schema):
setUpWidget(view, name, field, initial.get(name),
- prefix=prefix, force=force, context=context)
+ prefix=prefix, ignore_unspecified=ignore_unspecified,
+ context=context)
-def setUpEditWidgets(view, schema, content=None, prefix=None, force=False,
- names=None, context=None):
+def setUpEditWidgets(view, schema, content=None, prefix=None,
+ ignore_unspecified=False, names=None, context=None):
"""Set up widgets for the fields defined by a schema
Initial data is provided by content object attributes.
No initial data is provided if the content lacks a named
attribute, or if the named attribute value is None.
"""
- _setUpWidgets(view, schema, content, prefix, force,
+ _setUpWidgets(view, schema, content, prefix, ignore_unspecified,
names, context, 'display', 'edit')
-def setUpDisplayWidgets(view, schema, content=None, prefix=None, force=False,
- names=None, context=None):
+def setUpDisplayWidgets(view, schema, content=None, prefix=None,
+ ignore_unspecified=False, names=None, context=None):
"""Set up widgets for the fields defined by a schema
Initial data is provided by content object attributes.
No initial data is provided if the content lacks a named
attribute, or if the named attribute value is None.
"""
- _setUpWidgets(view, schema, content, prefix, force,
+ _setUpWidgets(view, schema, content, prefix, ignore_unspecified,
names, context, 'display', 'display')
-def _setUpWidgets(view, schema, content, prefix, force,
+def _setUpWidgets(view, schema, content, prefix, ignore_unspecified,
names, context, displayname, editname):
# Set up widgets for the fields defined by a schema.
#
@@ -239,23 +245,23 @@
value = None
setUpWidget(view, name, field, value,
- prefix=prefix, force=force, vname=vname, context=context)
+ prefix=prefix, ignore_unspecified=ignore_unspecified,
+ vname=vname, context=context)
-def haveWidgetsData(view, schema, names=None):
+def hasWidgetsData(view, schema, names=None):
"""Check if we have any user-entered data defined by a schema
Returns true if any schema field related widget has data
that was entered by the user.
"""
for name, field in _fieldlist(names, schema):
- if getattr(view, name+'_widget').haveData():
+ if getattr(view, name+'_widget').hasData():
return True
return False
-def applyWidgetsChanges(view, content, schema, strict=True,
- names=None, set_missing=True, do_not_raise=False,
- exclude_readonly=False):
+def applyWidgetsChanges(view, content, schema, names=None,
+ do_not_raise=False, exclude_readonly=False):
"""Apply changes in widgets to the object."""
errors = []
@@ -264,16 +270,17 @@
widget = getattr(view, name+'_widget')
if exclude_readonly and field.readonly:
continue
- if widget.haveData():
+
+ # only apply change if widget has data
+ if widget.hasData():
+ error = None
try:
changed = widget.applyChanges(content) or changed
- except InputErrors, v:
- errors.append(v)
- elif strict and field.required:
- err = MissingInputError(name, widget.title, 'the field is required')
- errors.append(err)
- elif set_missing:
- field.set(content, field.missing_value)
+ except WidgetInputError, v:
+ error = v
+ if error is not None:
+ errors.append(error)
+ widget.error = error
if errors and not do_not_raise:
raise WidgetsError(*errors)
@@ -321,15 +328,13 @@
widget = getattr(view, name+'_widget')
if exclude_readonly and widget.context.readonly:
continue
- if widget.haveData():
+ if widget.hasData():
try:
result[name] = widget.getData()
- except InputErrors, v:
+ except WidgetInputError, v:
errors.append(v)
elif strict and field.required:
- errors.append(MissingInputError(name, widget.title,
- 'the field is required')
- )
+ errors.append(MissingInputError(widget))
elif set_missing:
result[name] = field.missing_value
@@ -421,8 +426,7 @@
value = prop
result[name] = value
elif strict and field.required:
- errors.append(MissingInputError(name, name,
- 'the field is required'))
+ errors.append(ValidationError('the field is required', name))
elif set_missing:
result[name] = field.missing_value
=== Zope3/src/zope/app/form/widget.py 1.7 => 1.7.2.1 ===
--- Zope3/src/zope/app/form/widget.py:1.7 Mon Jul 14 11:06:10 2003
+++ Zope3/src/zope/app/form/widget.py Tue Jul 22 09:00:59 2003
@@ -26,7 +26,8 @@
implements(IWidget)
_prefix = 'field.'
- _data = None
+ _data_marker = object()
+ _data = _data_marker
def __init__(self, context, request):
self.context = context
@@ -50,8 +51,8 @@
def setData(self, value):
self._data = value
- def haveData(self):
- raise TypeError("haveData has not been implemented")
+ def hasData(self):
+ raise TypeError("hasData has not been implemented")
def getData(self):
raise TypeError("getData has not been implemented")