Skip to content

Commit

Permalink
merged branch icemac_validate_NOT_CHANGED
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Howitz committed May 17, 2009
1 parent fcd2f6d commit 2f736c3
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 4 deletions.
3 changes: 2 additions & 1 deletion AUTHOR.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ Dan Korostelev
Daniel Nouri
Darryl Cousins
Herman Himmelbauer
Jacob Holm
Laurent Mignon
Malthe Borch
Marius Gedminas
Martijn Faassen
Michael Howitz
Michael Kerrin
Paul Carduner
Paul Carduner
4 changes: 4 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@ Version 2.0.0 (unreleased)

- Bug: Don't cause warnings in Python 2.6.

- Bug: `validator.SimpleFieldValidator` is now able to handle
`interfaces.NOT_CHANGED`. This value is set for file uploads when
the user does not choose a file for upload.


Version 1.9.0 (2008-08-26)
--------------------------
Expand Down
23 changes: 21 additions & 2 deletions src/z3c/form/validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,28 @@ def __init__(self, context, request, view, field, widget):

def validate(self, value):
"""See interfaces.IValidator"""
context = self.context
field = self.field
if self.context is not None:
field = field.bind(self.context)
widget = self.widget
if context is not None:
field = field.bind(context)
if value is interfaces.NOT_CHANGED:
if (interfaces.IContextAware.providedBy(widget) and
not widget.ignoreContext):
# get value from context
value = zope.component.getMultiAdapter(
(context, field),
interfaces.IDataManager).query()
else:
value = interfaces.NO_VALUE
if value is interfaces.NO_VALUE:
# look up default value
value = field.default
adapter = zope.component.queryMultiAdapter(
(context, self.request, self.view, field, widget),
interfaces.IValue, name='default')
if adapter:
value = adapter.get()
return field.validate(value)

def __repr__(self):
Expand Down
119 changes: 118 additions & 1 deletion src/z3c/form/validator.txt
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ Let's now create a validator that also requires at least 1 numerical character
in the login name:

>>> import re

>>> class LoginValidator(validator.SimpleFieldValidator):
...
... def validate(self, value):
Expand Down Expand Up @@ -182,6 +181,124 @@ again:
... (None, None, None, IPerson['email'], None),
... interfaces.IValidator)

Widget Validators and File-Uploads
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

File-Uploads behave a bit different than the other form
elements. Whether the user did not choose a file to upload
``interfaces.NOT_CHANGED`` is set as value. But the validator knows
how to handle this.

The example has two bytes fields where File-Uploads are possible, one
field is required the other one not:

>>> class IPhoto(zope.interface.Interface):
... data = zope.schema.Bytes(
... title=u'Photo')
...
... thumb = zope.schema.Bytes(
... title=u'Thumbnail',
... required=False)

There are several possible cases to differentiate between:

No widget
+++++++++

If there is no widget or the widget does not provide
``interfaces.IContextAware``, no value is looked up from the
context. So the not required field validates successfully but the
required one has an required missing error, as the default value of
the field is looked up on the field:

>>> simple_thumb = validator.SimpleFieldValidator(
... None, None, None, IPhoto['thumb'], None)
>>> simple_thumb.validate(interfaces.NOT_CHANGED)

>>> simple_data = validator.SimpleFieldValidator(
... None, None, None, IPhoto['data'], None)
>>> simple_data.validate(interfaces.NOT_CHANGED)
Traceback (most recent call last):
RequiredMissing

Widget which ignores context
++++++++++++++++++++++++++++

If the context is ignored in the widget - as in the add form - the
behavior is the same as if there was no widget:

>>> import z3c.form.widget
>>> widget = z3c.form.widget.Widget(None)
>>> zope.interface.alsoProvides(widget, interfaces.IContextAware)
>>> widget.ignoreContext = True
>>> simple_thumb = validator.SimpleFieldValidator(
... None, None, None, IPhoto['thumb'], widget)
>>> simple_thumb.validate(interfaces.NOT_CHANGED)

>>> simple_data = validator.SimpleFieldValidator(
... None, None, None, IPhoto['data'], widget)
>>> simple_data.validate(interfaces.NOT_CHANGED)
Traceback (most recent call last):
RequiredMissing

Look up value from default adapter
++++++++++++++++++++++++++++++++++

When the value is ``interfaces.NOT_CHANGED`` the validator tries to
look up the default value using a ``interfaces.IValue``
adapter. Whether the adapter is found, its value is used as default,
so the validation of the required field is successful here:

>>> data_default = z3c.form.widget.StaticWidgetAttribute(
... 'data', context=None, request=None, view=None,
... field=IPhoto['data'], widget=widget)
>>> zope.component.provideAdapter(data_default, name='default')
>>> simple_data.validate(interfaces.NOT_CHANGED)


Look up value from context
++++++++++++++++++++++++++

If there is a context aware widget which does not ignore its context,
the value is looked up on the context using a data manager:

>>> class Photo(object):
... zope.interface.implements(IPhoto)
...
... data = None
... thumb = None
>>> photo = Photo()
>>> widget.ignoreContext = False
>>> zope.component.provideAdapter(z3c.form.datamanager.AttributeField)

>>> simple_thumb = validator.SimpleFieldValidator(
... photo, None, None, IPhoto['thumb'], widget)
>>> simple_thumb.validate(interfaces.NOT_CHANGED)

If the value is not set on the context it is a required missing as
neither context nor input have a valid value:

>>> simple_data = validator.SimpleFieldValidator(
... photo, None, None, IPhoto['data'], widget)
>>> simple_data.validate(interfaces.NOT_CHANGED)
Traceback (most recent call last):
RequiredMissing

After setting the value validation is successful:

>>> photo.data = 'data'
>>> simple_data.validate(interfaces.NOT_CHANGED)


Clean-up
++++++++

>>> gsm = zope.component.getGlobalSiteManager()
>>> gsm.unregisterAdapter(z3c.form.datamanager.AttributeField)
True
>>> gsm.unregisterAdapter(data_default, name='default')
True


Widget Manager Validators
-------------------------
Expand Down

0 comments on commit 2f736c3

Please sign in to comment.