Skip to content

Commit

Permalink
backported missing zope.formlib bugfixes from trunk (r40546:68015):
Browse files Browse the repository at this point in the history
r40608, r41043, r41119, part of r41757, r67264, r67278, r67279, r67774
  • Loading branch information
Unknown committed Sep 28, 2006
1 parent c36db55 commit ecc2d6a
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 17 deletions.
9 changes: 8 additions & 1 deletion form.py
Expand Up @@ -30,14 +30,15 @@
from zope.interface.interface import InterfaceClass
import zope.interface.interfaces
from zope.schema.interfaces import IField
from zope.schema.interfaces import ValidationError
import zope.security

import zope.app.container.interfaces
import zope.app.event.objectevent
import zope.app.form.browser.interfaces
from zope.app.form.interfaces import IInputWidget, IDisplayWidget
from zope.app.form.interfaces import WidgetsError, MissingInputError
from zope.app.form.interfaces import InputErrors
from zope.app.form.interfaces import InputErrors, WidgetInputError
from zope.app.pagetemplate import ViewPageTemplateFile
from zope.app.publisher.browser import BrowserView

Expand Down Expand Up @@ -316,6 +317,10 @@ def getWidgetsData(widgets, form_prefix, data):

try:
data[name] = widget.getInputValue()
except ValidationError, error:
# convert field ValidationError to WidgetInputError
error = WidgetInputError(widget.name, widget.label, error)
errors.append(error)
except InputErrors, error:
errors.append(error)

Expand Down Expand Up @@ -753,6 +758,8 @@ def error_views(self):
zope.app.form.browser.interfaces.IWidgetInputErrorView)
title = getattr(error, 'widget_title', None) # duck typing
if title:
if isinstance(title, zope.i18n.Message):
title = zope.i18n.translate(title, context=self.request)
yield '%s: %s' % (title, view.snippet())
else:
yield view.snippet()
Expand Down
30 changes: 15 additions & 15 deletions form.txt
Expand Up @@ -12,15 +12,15 @@ print statements to keep the examples simpler. Most forms will use
templates in practice.

This document starts with low-level APIs. We eventually build up to
higherlevel APIs that allow forms to be defined with just a little bit
of meta data. Impatiant readers may wish to skip to the later
higher-level APIs that allow forms to be defined with just a little bit
of meta data. Impatient readers may wish to skip to the later
sections, especially the section on `Helpful base classes`_. :)

A form class can define ordered collections of "form fields" using
the `Fields` constructor. Form fields are distinct from and build on
schema fields. A schema field specified attribute values. Form
fields specify how a schema field should be used in a form. The
simplest way to define a collection onf form fields is by passing a
simplest way to define a collection of form fields is by passing a
schema to the `Fields` constructor:

>>> from zope import interface, schema
Expand Down Expand Up @@ -53,7 +53,7 @@ We can also select and order subsets using the select method of form fields:
>>> [w.__name__ for w in MyForm.form_fields.select('name', 'identifier')]
['name', 'identifier']

or by omiting fields:
or by omitting fields:

>>> [w.__name__ for w in MyForm.form_fields.omit('now', 'identifier')]
['name', 'min_size', 'max_size']
Expand Down Expand Up @@ -86,8 +86,8 @@ instances. Let's look at an example that displays some input widgets:
... ignore_request=ignore_request)
... return '\n'.join([w() for w in widgets])

Here we used form.setUpWidgets to create widget instances from our
form-field specifications. The second argument to `setUpWidgets` is a
Here we used ``form.setUpWidgets`` to create widget instances from our
form-field specifications. The second argument to ``setUpWidgets`` is a
form prefix. All of the widgets on this form are given the same
prefix. This allows multiple forms to be used within a single form
tag, assuming that each form uses a different form prefix.
Expand Down Expand Up @@ -654,7 +654,7 @@ rearrange our form quite a bit to make things more modular:
- `status` is a string that, if set, is displayed at the top of the
form.

- `errors` is the set of errors found when valiadting.
- `errors` is the set of errors found when validating.

- `widgets` is a list of set-up widgets

Expand Down Expand Up @@ -850,7 +850,7 @@ Ah, much better. And our order has been updated:
Helpful base classes
====================

Our form has a lot of repetative code. A number of helpful base
Our form has a lot of repetitive code. A number of helpful base
classes provide standard form implementation.

Form
Expand All @@ -869,7 +869,7 @@ It provides:
To render the form

`template`
A default template. Note that this a NamedTemplate named "default",
A default template. Note that this is a NamedTemplate named "default",
so the template may also be overridden by registering an alternate
default template.

Expand Down Expand Up @@ -932,7 +932,7 @@ We inherited most of our behavior from the base class.

We also used the `action` decorator. The action decorator:

- creates an `actions` variable if one isn't aleady created,
- creates an `actions` variable if one isn't already created,

- defines an action with the given label and any other arguments, and

Expand Down Expand Up @@ -997,7 +997,7 @@ EditForm
Our `handle_edit_action` action is common to edit forms. An
`EditForm` base class captures this commonality. It also sets up
widget widgets a bit differently. The `EditForm` base class sets up
widgets as if the form fields had been set up with the render_context`
widgets as if the form fields had been set up with the `render_context`
option.

>>> class MyForm(form.EditForm):
Expand Down Expand Up @@ -1207,7 +1207,7 @@ Form-field manipulations
========================

The form-field constructor is very flexible. We've already seen that
we can sppply multiple schemas. Here are some other things you can
we can supply multiple schemas. Here are some other things you can
do.

Specifying individual fields
Expand Down Expand Up @@ -1245,11 +1245,11 @@ You can also use stand-alone fields:

But make sure the fields have a '__name__', as was done above.

Concatinating field collections
Concatenating field collections
-------------------------------

It is sometimes convenient to combine multiple field collections.
Field collections support concatination. For example, we may want to
Field collections support concatenation. For example, we may want to
combine field definitions:

>>> class MyExpandedForm(form.Form):
Expand Down Expand Up @@ -1312,7 +1312,7 @@ Using fields for input
----------------------

We may want to indicate that some fields should be used for input even
if the underlying schema field is readonly. We can do this using the
if the underlying schema field is read-only. We can do this using the
`for_input` option when setting up form_fields:

>>> class MyForm(form.Form):
Expand Down
2 changes: 1 addition & 1 deletion pageform.pt
Expand Up @@ -29,7 +29,7 @@ function toggleFormFieldHelp(ob,state) {
e.style.visibility = viz;
}
}
var help = document.getElementById("field-help-for-" + field.name);
var help = document.getElementById("field-help-for-" + ob.htmlFor);
if (help) {
help.style.visibility = state && 'visible' || 'hidden';
}
Expand Down
81 changes: 81 additions & 0 deletions tests.py
Expand Up @@ -226,6 +226,87 @@ def make_sure_i18n_is_called_correctly_for_actions():
"""


def test_error_views_i18n():
"""\
>>> from zope.i18n.simpletranslationdomain import SimpleTranslationDomain
>>> from zope.i18n.interfaces import ITranslationDomain
>>> messageDic = {('ja', u'Summary'): u'MatomeYaken'}
>>> sd = SimpleTranslationDomain('KansaiBen.domain', messageDic)
>>> component.provideUtility(provides=ITranslationDomain,
... component=sd,
... name='KansaiBen.domain')
>>> from zope.i18n.negotiator import negotiator
>>> component.provideUtility(negotiator)
>>> _ = zope.i18nmessageid.MessageFactory('KansaiBen.domain')
>>> myError = zope.app.form.interfaces.WidgetInputError(
... field_name='summary',
... widget_title=_(u'Summary'))
>>> from zope.publisher.browser import TestRequest
>>> req = TestRequest()
>>> req._environ['HTTP_ACCEPT_LANGUAGE'] = 'ja; q=1.0'
>>> mybase = form.FormBase(None, req)
>>> mybase.errors = (myError,)
>>> save = mybase.error_views()
>>> save.next()
u'MatomeYaken: <span class="error"></span>'
"""


def test_error_handling():
"""\
Let's test the getWidgetsData method which is responsible for handling widget
erros raised by the widgets getInputValue method.
>>> from zope.interface import implements
>>> from zope.app.form.interfaces import IInputWidget
>>> class Widget(object):
... implements(IInputWidget)
... def __init__(self):
... self.name = 'form.summary'
... self.label = 'Summary'
... def hasInput(self):
... return True
... def getInputValue(self):
... raise zope.app.form.interfaces.WidgetInputError(
... field_name='summary',
... widget_title=u'Summary')
>>> widget = Widget()
>>> inputs = [(True, widget)]
>>> widgets = form.Widgets(inputs, 5)
>>> errors = form.getWidgetsData(widgets, 'form', {'summary':'value'})
>>> errors #doctest: +ELLIPSIS
[<zope.app.form.interfaces.WidgetInputError instance at ...>]
Let's see what happens if a widget doesn't convert a ValidationError
raised by a field to a WidgetInputError. This should not happen if a widget
converts ValidationErrors to WidgetInputErrors. But since I just fixed
yesterday the sequence input widget, I decided to catch ValidationError also
in the formlib as a fallback if some widget doen't handle errors correct. (ri)
>>> from zope.schema.interfaces import ValidationError
>>> class Widget(object):
... implements(IInputWidget)
... def __init__(self):
... self.name = 'form.summary'
... self.label = 'summary'
... def hasInput(self):
... return True
... def getInputValue(self):
... raise ValidationError('A error message')
>>> widget = Widget()
>>> inputs = [(True, widget)]
>>> widgets = form.Widgets(inputs, 5)
>>> errors = form.getWidgetsData(widgets, 'form', {'summary':'value'})
>>> errors #doctest: +ELLIPSIS
[<zope.app.form.interfaces.WidgetInputError instance at ...>]
"""


def test_form_template_i18n():
"""\
Let's try to check that the formlib templates handle i18n correctly.
Expand Down

0 comments on commit ecc2d6a

Please sign in to comment.