[Zope3-checkins] SVN: zope.formlib/branches/faassen-zaf/ zope.app.form.interfaces -> zope.formlib.interfaces
Martijn Faassen
faassen at startifact.com
Wed Dec 30 13:41:16 EST 2009
Log message for revision 107372:
zope.app.form.interfaces -> zope.formlib.interfaces
Changed:
U zope.formlib/branches/faassen-zaf/buildout.cfg
U zope.formlib/branches/faassen-zaf/src/zope/formlib/errors.txt
U zope.formlib/branches/faassen-zaf/src/zope/formlib/form.py
U zope.formlib/branches/faassen-zaf/src/zope/formlib/form.txt
U zope.formlib/branches/faassen-zaf/src/zope/formlib/interfaces.py
U zope.formlib/branches/faassen-zaf/src/zope/formlib/tests.py
-=-
Modified: zope.formlib/branches/faassen-zaf/buildout.cfg
===================================================================
--- zope.formlib/branches/faassen-zaf/buildout.cfg 2009-12-30 18:36:02 UTC (rev 107371)
+++ zope.formlib/branches/faassen-zaf/buildout.cfg 2009-12-30 18:41:15 UTC (rev 107372)
@@ -1,5 +1,5 @@
[buildout]
-develop = .
+develop = . ../zope.app.form
parts = test python
[test]
Modified: zope.formlib/branches/faassen-zaf/src/zope/formlib/errors.txt
===================================================================
--- zope.formlib/branches/faassen-zaf/src/zope/formlib/errors.txt 2009-12-30 18:36:02 UTC (rev 107371)
+++ zope.formlib/branches/faassen-zaf/src/zope/formlib/errors.txt 2009-12-30 18:41:15 UTC (rev 107372)
@@ -59,7 +59,7 @@
WidgetInputError exceptions also work with i18n messages:
- >>> from zope.app.form.interfaces import WidgetInputError
+ >>> from zope.formlib.interfaces import WidgetInputError
>>> myError = WidgetInputError(
... field_name='summary',
... widget_title=_(u'Summary'),
Modified: zope.formlib/branches/faassen-zaf/src/zope/formlib/form.py
===================================================================
--- zope.formlib/branches/faassen-zaf/src/zope/formlib/form.py 2009-12-30 18:36:02 UTC (rev 107371)
+++ zope.formlib/branches/faassen-zaf/src/zope/formlib/form.py 2009-12-30 18:41:15 UTC (rev 107372)
@@ -39,9 +39,9 @@
from zope.browserpage import namedtemplate
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, WidgetInputError
+from zope.formlib.interfaces import IInputWidget, IDisplayWidget
+from zope.formlib.interfaces import WidgetsError, MissingInputError
+from zope.formlib.interfaces import InputErrors, WidgetInputError
from zope.formlib import interfaces
from zope.i18nmessageid import MessageFactory
Modified: zope.formlib/branches/faassen-zaf/src/zope/formlib/form.txt
===================================================================
--- zope.formlib/branches/faassen-zaf/src/zope/formlib/form.txt 2009-12-30 18:36:02 UTC (rev 107371)
+++ zope.formlib/branches/faassen-zaf/src/zope/formlib/form.txt 2009-12-30 18:41:15 UTC (rev 107372)
@@ -1630,7 +1630,7 @@
Even though the form machinery only has a single errors attribute, if designers
wish to render widget errors differently than invariant errors, they can be
separated reasonably easily. The separation takes advantage of the fact that
-all widget errors should implement zope.app.form.interfaces.IWidgetInputError,
+all widget errors should implement zope.formlib.interfaces.IWidgetInputError,
and invariant errors shouldn't, because they don't come from a widget.
Therefore, a simple division such as the following should suffice.
Modified: zope.formlib/branches/faassen-zaf/src/zope/formlib/interfaces.py
===================================================================
--- zope.formlib/branches/faassen-zaf/src/zope/formlib/interfaces.py 2009-12-30 18:36:02 UTC (rev 107371)
+++ zope.formlib/branches/faassen-zaf/src/zope/formlib/interfaces.py 2009-12-30 18:41:15 UTC (rev 107372)
@@ -15,10 +15,235 @@
$Id$
"""
import re
-from zope import interface, schema
+from zope import schema
from zope.publisher.interfaces.browser import IBrowserPage
+from zope.schema.interfaces import ValidationError
+from zope.publisher.interfaces import IView
+from zope.interface import Attribute, Interface, implements
+from zope.schema import Bool
+from zope.exceptions.interfaces import UserError
+class IWidgetInputError(Interface):
+ """Placeholder for a snippet View"""
+ def doc():
+ """Returns a string that represents the error message."""
+
+class WidgetInputError(UserError):
+ """One or more user input errors occurred."""
+
+ implements(IWidgetInputError)
+
+ def __init__(self, field_name, widget_title, errors=None):
+ """Initialize Error
+
+ `errors` is a ``ValidationError`` or a list of ValidationError objects
+ """
+ UserError.__init__(self, field_name, widget_title, errors)
+ self.field_name = field_name
+ self.widget_title = widget_title
+ self.errors = errors
+
+ def doc(self):
+ # TODO this duck typing is to get the code working. See
+ # collector issue 372
+ if isinstance(self.errors, basestring):
+ return self.errors
+ elif getattr(self.errors, 'doc', None) is not None:
+ return self.errors.doc()
+ return ''
+
+
+class MissingInputError(WidgetInputError):
+ """Required data was not supplied."""
+
+
+class ConversionError(Exception):
+ """A conversion error occurred."""
+
+ implements(IWidgetInputError)
+
+ def __init__(self, error_name, original_exception=None):
+ Exception.__init__(self, error_name, original_exception)
+ self.error_name = error_name
+ self.original_exception = original_exception
+
+ def doc(self):
+ return self.error_name
+
+InputErrors = WidgetInputError, ValidationError, ConversionError
+
+
+class ErrorContainer(Exception):
+ """A base error class for collecting multiple errors."""
+
+ def append(self, error):
+ self.args += (error, )
+
+ def __len__(self):
+ return len(self.args)
+
+ def __iter__(self):
+ return iter(self.args)
+
+ def __getitem__(self, i):
+ return self.args[i]
+
+ def __str__(self):
+ return "\n".join(
+ ["%s: %s" % (error.__class__.__name__, error)
+ for error in self.args]
+ )
+
+ __repr__ = __str__
+
+class WidgetsError(ErrorContainer):
+ """A collection of errors from widget processing.
+
+ widgetValues is a map containing the list of values that were obtained
+ from the widgets, keyed by field name.
+ """
+
+ def __init__(self, errors, widgetsData={}):
+ ErrorContainer.__init__(self, *errors)
+ self.widgetsData = widgetsData
+
+class IWidget(IView):
+ """Generically describes the behavior of a widget.
+
+ Note that this level must be still presentation independent.
+ """
+
+ name = Attribute(
+ """The unique widget name
+
+ This must be unique within a set of widgets.""")
+
+ label = Attribute(
+ """The widget label.
+
+ Label may be translated for the request.
+
+ The attribute may be implemented as either a read-write or read-only
+ property, depending on the requirements for a specific implementation.
+
+ """)
+
+ hint = Attribute(
+ """A hint regarding the use of the widget.
+
+ Hints are traditionally rendered using tooltips in GUIs, but may be
+ rendered differently depending on the UI implementation.
+
+ Hint may be translated for the request.
+
+ The attribute may be implemented as either a read-write or read-only
+ property, depending on the requirements for a specific implementation.
+
+ """)
+
+ visible = Attribute(
+ """A flag indicating whether or not the widget is visible.""")
+
+ def setRenderedValue(value):
+ """Set the value to be rendered by the widget.
+
+ Calling this method will override any values provided by the user.
+
+ For input widgets (`IInputWidget` implementations), calling
+ this sets the value that will be rendered even if there is
+ already user input.
+
+ """
+
+ def setPrefix(prefix):
+ """Set the name prefix used for the widget
+
+ The widget name is used to identify the widget's data within
+ input data. For example, for HTTP forms, the widget name is
+ used for the form key.
+
+ It is acceptable to *reset* the prefix: set it once to read
+ values from the request, and again to redraw with a different
+ prefix but maintained state.
+
+ """
+
+class IInputWidget(IWidget):
+ """A widget for editing a field value."""
+
+ required = Bool(
+ title=u"Required",
+ description=u"""If True, widget should be displayed as requiring input.
+
+ By default, this value is the field's 'required' attribute. This
+ field can be set to False for widgets that always provide input (e.g.
+ a checkbox) to avoid unnecessary 'required' UI notations.
+ """)
+
+ def getInputValue():
+ """Return value suitable for the widget's field.
+
+ The widget must return a value that can be legally assigned to
+ its bound field or otherwise raise ``WidgetInputError``.
+
+ The return value is not affected by `setRenderedValue()`.
+ """
+
+ def applyChanges(content):
+ """Validate the user input data and apply it to the content.
+
+ Return a boolean indicating whether a change was actually applied.
+
+ This raises an error if there is no user input.
+ """
+
+ def hasInput():
+ """Returns ``True`` if the widget has input.
+
+ Input is used by the widget to calculate an 'input value', which is
+ a value that can be legally assigned to a field.
+
+ Note that the widget may return ``True``, indicating it has input, but
+ still be unable to return a value from `getInputValue`. Use
+ `hasValidInput` to determine whether or not `getInputValue` will return
+ a valid value.
+
+ A widget that does not have input should generally not be used
+ to update its bound field. Values set using
+ `setRenderedValue()` do not count as user input.
+
+ A widget that has been rendered into a form which has been
+ submitted must report that it has input. If the form
+ containing the widget has not been submitted, the widget
+ shall report that it has no input.
+
+ """
+
+ def hasValidInput():
+ """Returns ``True`` is the widget has valid input.
+
+ This method is similar to `hasInput` but it also confirms that the
+ input provided by the user can be converted to a valid field value
+ based on the field constraints.
+ """
+
+class IDisplayWidget(IWidget):
+ """A widget for displaying a field value."""
+
+ required = Bool(
+ title=u"Required",
+ description=u"""If True, widget should be displayed as requiring input.
+
+ Display widgets should never be required.
+ """)
+
+class IWidgetFactory(Interface):
+ """A factory that creates the widget"""
+
+ def __call__(context, request):
+ """Return a widget"""
+
class FormError(Exception):
"""There was an error in managing the form
"""
@@ -31,7 +256,7 @@
return True
raise interface.Invalid(value, explanation)
-class ISubPage(interface.Interface):
+class ISubPage(Interface):
"""A component that computes part of a page
"""
@@ -61,7 +286,7 @@
"""
-class IFormAPI(interface.Interface):
+class IFormAPI(Interface):
"""API to facilitate creating forms, provided by zope.formlib.form
"""
@@ -365,7 +590,7 @@
"""
- FormBase = interface.Attribute("""Base class for creating forms
+ FormBase = Attribute("""Base class for creating forms
The FormBase class provides reuasable implementation for creating
forms. It implements ISubPage, IBrowserPage, and IFormBaseCustomization.
@@ -384,33 +609,33 @@
"""
- label = interface.Attribute("A label to display at the top of a form")
+ label = Attribute("A label to display at the top of a form")
- status = interface.Attribute(
+ status = Attribute(
"""An update status message
This is normally generated by success or failure handlers.
""")
- errors = interface.Attribute(
+ errors = Attribute(
"""Sequence of errors encountered during validation
""")
- form_result = interface.Attribute(
+ form_result = Attribute(
"""Return from action result method
""")
- form_reset = interface.Attribute(
+ form_reset = Attribute(
"""Boolean indicating whether the form needs to be reset
""")
- form_fields = interface.Attribute(
+ form_fields = Attribute(
"""The form's form field definitions
This attribute is used by many of the default methods.
""")
- widgets = interface.Attribute(
+ widgets = Attribute(
"""The form's widgets
- set by setUpWidgets
@@ -434,7 +659,7 @@
validator then this function will be called.
"""
- template = interface.Attribute(
+ template = Attribute(
"""Template used to display the form
This can be overridden in 2 ways:
@@ -458,7 +683,7 @@
-class IFormFields(interface.Interface):
+class IFormFields(Interface):
"""A colection of form fields (IFormField objects)
"""
@@ -511,7 +736,7 @@
SKIP_UNAUTHORIZED = 2
DISPLAY_UNWRITEABLE = 4
-class IFormField(interface.Interface):
+class IFormField(Interface):
"""Definition of a field to be included in a form
This should not be confused with a schema field.
@@ -527,7 +752,7 @@
"""
)
- field = interface.Attribute(
+ field = Attribute(
"""Schema field that defines the data of the form field
"""
)
@@ -560,7 +785,7 @@
"""
)
- custom_widget = interface.Attribute(
+ custom_widget = Attribute(
"""Factory to use for widget construction.
If not set, normal view lookup will be used.
@@ -606,7 +831,7 @@
missing_value=False,
)
- get_rendered = interface.Attribute(
+ get_rendered = Attribute(
"""Object to call to get a rendered value
This attribute may be set to a callable object or to
@@ -622,7 +847,7 @@
"""
)
-class IWidgets(interface.Interface):
+class IWidgets(Interface):
"""A widget collection
IWidgets provide ordered collections of widgets that also support:
@@ -666,7 +891,7 @@
"""
-class IForm(interface.Interface):
+class IForm(Interface):
"""Base type for forms
This exists primarily to provide something for which to register
@@ -697,7 +922,7 @@
data = schema.Dict(title=u"Application data")
- condition = interface.Attribute(
+ condition = Attribute(
"""Action condition
This is a callable object that will be passed a form and an
@@ -706,7 +931,7 @@
""")
- validator = interface.Attribute(
+ validator = Attribute(
"""Action validator
This is a callable object that will be passed a form and an
@@ -754,7 +979,7 @@
valid only after the action has been bound to a form.
"""
-class IActions(interface.Interface):
+class IActions(Interface):
"""An action collection
IActions provide ordered collections of actions that also support
@@ -789,7 +1014,7 @@
"""An action that has been bound to a form
"""
- form = interface.Attribute("The form to which the action is bound")
+ form = Attribute("The form to which the action is bound")
class IAddFormCustomization(IFormBaseCustomization):
Modified: zope.formlib/branches/faassen-zaf/src/zope/formlib/tests.py
===================================================================
--- zope.formlib/branches/faassen-zaf/src/zope/formlib/tests.py 2009-12-30 18:36:02 UTC (rev 107371)
+++ zope.formlib/branches/faassen-zaf/src/zope/formlib/tests.py 2009-12-30 18:41:15 UTC (rev 107372)
@@ -35,7 +35,7 @@
import zope.app.form.browser
import zope.app.form.browser.exception
import zope.app.form.browser.interfaces
-import zope.app.form.interfaces
+import zope.formlib.interfaces
import zope.formlib
import zope.formlib.form
@@ -93,60 +93,60 @@
[zope.schema.interfaces.ITextLine,
zope.publisher.interfaces.browser.IBrowserRequest,
],
- zope.app.form.interfaces.IInputWidget,
+ zope.formlib.interfaces.IInputWidget,
)
provideAdapter(
zope.app.form.browser.FloatWidget,
[zope.schema.interfaces.IFloat,
zope.publisher.interfaces.browser.IBrowserRequest,
],
- zope.app.form.interfaces.IInputWidget,
+ zope.formlib.interfaces.IInputWidget,
)
provideAdapter(
zope.app.form.browser.UnicodeDisplayWidget,
[zope.schema.interfaces.IInt,
zope.publisher.interfaces.browser.IBrowserRequest,
],
- zope.app.form.interfaces.IDisplayWidget,
+ zope.formlib.interfaces.IDisplayWidget,
)
provideAdapter(
zope.app.form.browser.IntWidget,
[zope.schema.interfaces.IInt,
zope.publisher.interfaces.browser.IBrowserRequest,
],
- zope.app.form.interfaces.IInputWidget,
+ zope.formlib.interfaces.IInputWidget,
)
provideAdapter(
zope.app.form.browser.UnicodeDisplayWidget,
[zope.schema.interfaces.IFloat,
zope.publisher.interfaces.browser.IBrowserRequest,
],
- zope.app.form.interfaces.IDisplayWidget,
+ zope.formlib.interfaces.IDisplayWidget,
)
provideAdapter(
zope.app.form.browser.UnicodeDisplayWidget,
[zope.schema.interfaces.ITextLine,
zope.publisher.interfaces.browser.IBrowserRequest,
],
- zope.app.form.interfaces.IDisplayWidget,
+ zope.formlib.interfaces.IDisplayWidget,
)
provideAdapter(
zope.app.form.browser.DatetimeDisplayWidget,
[zope.schema.interfaces.IDatetime,
zope.publisher.interfaces.browser.IBrowserRequest,
],
- zope.app.form.interfaces.IDisplayWidget,
+ zope.formlib.interfaces.IDisplayWidget,
)
provideAdapter(
zope.app.form.browser.DatetimeWidget,
[zope.schema.interfaces.IDatetime,
zope.publisher.interfaces.browser.IBrowserRequest,
],
- zope.app.form.interfaces.IInputWidget,
+ zope.formlib.interfaces.IInputWidget,
)
provideAdapter(
zope.app.form.browser.exception.WidgetInputErrorView,
- [zope.app.form.interfaces.IWidgetInputError,
+ [zope.formlib.interfaces.IWidgetInputError,
zope.publisher.interfaces.browser.IBrowserRequest,
],
zope.app.form.browser.interfaces.IWidgetInputErrorView,
@@ -297,16 +297,16 @@
Let's test the getWidgetsData method which is responsible for handling widget
erros raised by the widgets getInputValue method.
- >>> import zope.app.form.interfaces
+ >>> import zope.formlib.interfaces
>>> class Widget(object):
- ... zope.interface.implements(zope.app.form.interfaces.IInputWidget)
+ ... zope.interface.implements(zope.formlib.interfaces.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(
+ ... raise zope.formlib.interfaces.WidgetInputError(
... field_name='summary',
... widget_title=u'Summary')
>>> widget = Widget()
@@ -314,7 +314,7 @@
>>> widgets = zope.formlib.form.Widgets(inputs, 5)
>>> errors = zope.formlib.form.getWidgetsData(widgets, 'form', {'summary':'value'})
>>> errors #doctest: +ELLIPSIS
- [<zope.app.form.interfaces.WidgetInputError instance at ...>]
+ [<zope.formlib.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
@@ -323,7 +323,7 @@
in the formlib as a fallback if some widget doen't handle errors correct. (ri)
>>> class Widget(object):
- ... zope.interface.implements(zope.app.form.interfaces.IInputWidget)
+ ... zope.interface.implements(zope.formlib.interfaces.IInputWidget)
... def __init__(self):
... self.name = 'form.summary'
... self.label = 'summary'
@@ -336,7 +336,7 @@
>>> widgets = zope.formlib.form.Widgets(inputs, 5)
>>> errors = zope.formlib.form.getWidgetsData(widgets, 'form', {'summary':'value'})
>>> errors #doctest: +ELLIPSIS
- [<zope.app.form.interfaces.WidgetInputError instance at ...>]
+ [<zope.formlib.interfaces.WidgetInputError instance at ...>]
"""
@@ -535,9 +535,9 @@
from zope.testing import doctest
checker = zope.testing.renormalizing.RENormalizing([
(re.compile(r"\[WidgetInputError\('form.summary', 'summary', ValidationError\('A error message'\)\)\]"),
- r"[<zope.app.form.interfaces.WidgetInputError instance at ...>]"),
+ r"[<zope.formlib.interfaces.WidgetInputError instance at ...>]"),
(re.compile(r"\[WidgetInputError\('summary', u'Summary', None\)\]"),
- r"[<zope.app.form.interfaces.WidgetInputError instance at ...>]"),
+ r"[<zope.formlib.interfaces.WidgetInputError instance at ...>]"),
(re.compile(r" ValueError\('invalid literal for float\(\): (bob'|10,0'),\)"),
r"\n <exceptions.ValueError instance at ...>"),
])
More information about the Zope3-Checkins
mailing list