[Zope3-checkins] CVS: Zope3/src/zope/app/form/tests - test_utility.py:1.19.22.2

Garrett Smith garrett at mojave-corp.com
Mon Mar 1 18:33:43 EST 2004


Update of /cvs-repository/Zope3/src/zope/app/form/tests
In directory cvs.zope.org:/tmp/cvs-serv27606/src/zope/app/form/tests

Modified Files:
      Tag: garrett-widgets2-branch
	test_utility.py 
Log Message:
Changes related to widget machinery:

- Added source argument to setUpEditWidgets and setUpDisplayWidgets.
- Renamed IEditWidget to IInputWidget.
- Added a widgetsData attribute to zope.app.interfaces.formWidgetsError.



=== Zope3/src/zope/app/form/tests/test_utility.py 1.19.22.1 => 1.19.22.2 ===
--- Zope3/src/zope/app/form/tests/test_utility.py:1.19.22.1	Thu Feb 26 00:10:55 2004
+++ Zope3/src/zope/app/form/tests/test_utility.py	Mon Mar  1 18:33:12 2004
@@ -35,7 +35,7 @@
 from zope.app.form.widget import Widget
 
 from zope.app.interfaces.form import IWidget
-from zope.app.interfaces.form import IEditWidget
+from zope.app.interfaces.form import IInputWidget
 from zope.app.interfaces.form import IDisplayWidget
 from zope.app.interfaces.form import WidgetsError
 
@@ -141,8 +141,7 @@
         If the existing attribute value implements IViewFactory, it is used
         to create a widget:
            
-            >>> boundField = IContent['foo'].bind(Content())
-            >>> widget = FooWidget(boundField, request)
+            >>> widget = FooWidget(IContent['foo'], request)
             >>> class Factory:
             ...     implements(IViewFactory)
             ...     def __call__(self, request, context):
@@ -239,32 +238,30 @@
         >>> setUp()
         
         If the view does not already have a widget configured for the
-        specified fieldl name, setUpWidget will look up a widget using
+        specified field name, setUpWidget will look up a widget using
         an interface specified for the widgetType argument.
         
-        Widgets are typically looked up for IEditWidget and IDisplayWidget
+        Widgets are typically looked up for IInputWidget and IDisplayWidget
         types. To illustrate this, we'll create two widgets, one for editing
         and another for displaying IFoo attributes. Each widget is registered
         as a view providing the appropriate widget type.
         
             >>> class EditFooWidget(Widget):
-            ...     implements(IEditWidget)
+            ...     implements(IInputWidget)
             ...     def hasInput(self):
             ...         return False
-            >>> ztapi.browserView(IFoo, '', EditFooWidget, 
-            ...                   providing=IEditWidget)
-            
+            >>> ztapi.browserViewProviding(IFoo, EditFooWidget, IInputWidget)
             >>> class DisplayFooWidget(Widget):
             ...     implements(IDisplayWidget)            
-            >>> ztapi.browserView(IFoo, '', DisplayFooWidget, 
-            ...                   providing=IDisplayWidget)
+            >>> ztapi.browserViewProviding(IFoo, DisplayFooWidget, 
+            ...                            IDisplayWidget)
             
-        A call to setUpWidget will lookup the widgets based on the type
-        specified.
+        A call to setUpWidget will lookup the widgets based on the specified 
+        type.
             
             >>> view = BrowserView(Content(), request)
-            >>> setUpWidget(view, 'foo', IContent['foo'], IEditWidget)
-            >>> IEditWidget.isImplementedBy(view.foo_widget)
+            >>> setUpWidget(view, 'foo', IContent['foo'], IInputWidget)
+            >>> IInputWidget.isImplementedBy(view.foo_widget)
             True
             >>> delattr(view, 'foo_widget')
             >>> setUpWidget(view, 'foo', IContent['foo'], IDisplayWidget)
@@ -290,8 +287,8 @@
         >>> setUp()
         
         Widgets support a prefix that can be used to group related widgets
-        on a view. To specify the prefix that a widget should use, specify it
-        in the call to setUpWidget:
+        on a view. To specify the prefix for a widget, specify in the call to
+        setUpWidget:
             
             >>> view = BrowserView(Content(), request)
             >>> setUpWidget(view, 'foo', IContent['foo'], IFooWidget,
@@ -367,25 +364,25 @@
         
         setUpWidget inferst that a widget has a sticky value if:
             
-            - The widget implements IEditWidget
+            - The widget implements IInputWidget
             - The widget returns True for its hasInput method
             
         To illustrate, we'll create and register an edit widget for foo that 
         has input:
             
             >>> class EditFooWidget(Widget):
-            ...     implements(IEditWidget)
+            ...     implements(IInputWidget)
             ...     _data = "Original Value"
             ...     def hasInput(self): return True
             ...     def getRenderedValue(self): return self._data
             >>> ztapi.browserView(IFoo, '', EditFooWidget, 
-            ...                   providing=IEditWidget)
+            ...                   providing=IInputWidget)
             
         Specifying a value to setUpWidget would typically cause that value
         to be set for the widget:
         
             >>> view = BrowserView(Content(), request)
-            >>> setUpWidget(view, 'foo', IContent['foo'], IEditWidget,
+            >>> setUpWidget(view, 'foo', IContent['foo'], IInputWidget,
             ...     value="A New Value")
             
         However, because EditFooWidget has input (i.e. has a 'sticky' value), 
@@ -399,7 +396,7 @@
         the 'value' argument:
             
             >>> delattr(view, 'foo_widget')
-            >>> setUpWidget(view, 'foo', IContent['foo'], IEditWidget,
+            >>> setUpWidget(view, 'foo', IContent['foo'], IInputWidget,
             ...             value="A New Value", ignoreStickyValues=True)
             >>> view.foo_widget.getRenderedValue()
             'A New Value'
@@ -459,6 +456,8 @@
         for a view:
             
             >>> view = BrowserView(Content(), request)
+            >>> IContent.names()
+            ['foo', 'bar']
             >>> setUpWidgets(view, IContent, IWidget, names=('bar',))
             >>> hasattr(view, 'foo_widget')
             False
@@ -472,10 +471,19 @@
         """Tests setUpWidgets' use of setUpWidget.
         
         >>> setUp()
+        
+        setUpWidgets delegates several of its arguments to multiple calls to
+        setUpWidget - one call for each widget being configured. The arguments
+        passed directly through to calls to setUpWidget are:
+            
+            view
+            viewType
+            prefix
+            ignoreStickyValues
+            context
 
-        setUpWidgets uses setUpWidget to perform the configuration of widgets 
-        on a view. To verify this, we'll replace setUpWidget in the utility 
-        module and capture arguments passed to it when setUpWidgets is called.
+        To illustrate this, we'll replace setUpWidget in the utility module 
+        and capture arguments passed to it when setUpWidgets is called.
         
             >>> def setUpWidget(view, name, field, viewType, value=None, 
             ...                 prefix=None, ignoreStickyValues=False, 
@@ -533,70 +541,70 @@
         
         >>> setUp()
         
-        setUpEditWidgets configures a view for use as an edit form. The
-        function looks up widgets of type IEditWidget for the specified
-        schema.
+        setUpEditWidgets configures a view to collect field values from a
+        user. The function looks up widgets of type IInputWidget for the 
+        specified schema.
         
-        We'll first create and register widgets for the schame fields
-        we want to edit:
+        We'll first create and register widgets for the schema fields for
+        which we want input:
             
-            >>> class EditWidget(Widget):
-            ...     implements(IEditWidget)
+            >>> class InputWidget(Widget):
+            ...     implements(IInputWidget)
             ...     def hasInput(self):
             ...         return False
             ...     def getRenderedValue(self): return self._data
-            >>> ztapi.browserView(IFoo, '', EditWidget, providing=IEditWidget)
-            >>> ztapi.browserView(IBar, '', EditWidget, providing=IEditWidget)
+            >>> ztapi.browserViewProviding(IFoo, InputWidget, IInputWidget)
+            >>> ztapi.browserViewProviding(IBar, InputWidget, IInputWidget)
 
-        Next we'll configure a context object to be edited:
+        Next we'll configure a view with a context object:
             
             >>> context = Content()
             >>> context.foo = 'abc'
             >>> context.bar = 'def'
+            >>> view = BrowserView(context, request)
             
-        Calling setUpEditWidget with a view of context:
+        A call to setUpEditWidgets with the view:
             
-            >>> view = BrowserView(context, request)
             >>> setUpEditWidgets(view, IContent)
             
-        configures the view with widgets that can edit the context fields:
+        configures the view with widgets that accept input for the context 
+        field values:
             
-            >>> isinstance(view.foo_widget, EditWidget)
+            >>> isinstance(view.foo_widget, InputWidget)
             True
             >>> view.foo_widget.getRenderedValue()
             'abc'
-            >>> isinstance(view.bar_widget, EditWidget)
+            >>> isinstance(view.bar_widget, InputWidget)
             True
             >>> view.bar_widget.getRenderedValue()
             'def'
             
-        setUpEditWidgets accepts a 'context' argument that provides an
+        setUpEditWidgets provides a 'source' argument that provides an
         alternate source of values to be edited:
             
             >>> view = BrowserView(context, request)
-            >>> altContext = Content()
-            >>> altContext.foo = 'abc2'
-            >>> altContext.bar = 'def2'
-            >>> setUpEditWidgets(view, IContent, context=altContext)
+            >>> source = Content()
+            >>> source.foo = 'abc2'
+            >>> source.bar = 'def2'
+            >>> setUpEditWidgets(view, IContent, source=source)
             >>> view.foo_widget.getRenderedValue()
             'abc2'
             >>> view.bar_widget.getRenderedValue()
             'def2'
             
         If a field is read only, setUpEditWidgets will use a display widget
-        (IDisplayWidget) intead of an edit widget to display the field value.
+        (IDisplayWidget) intead of an input widget to display the field value.
         
             >>> class DisplayWidget(Widget):
             ...     implements(IDisplayWidget)
-            >>> ztapi.browserView(IFoo, '', DisplayWidget,
-            ...                   providing=IDisplayWidget)
-            >>> save = IContent['foo'].readonly
+            >>> ztapi.browserViewProviding(IFoo, DisplayWidget, IDisplayWidget)
+            >>> save = IContent['foo'].readonly  # save readonly value
             >>> IContent['foo'].readonly = True
-            >>> view = BrowserView(Content(), request)
+            >>> delattr(view, 'foo_widget')
             >>> setUpEditWidgets(view, IContent)
             >>> isinstance(view.foo_widget, DisplayWidget)
             True
-            >>> IContent['foo'].readonly = save
+            >>> IContent['foo'].readonly = save  # restore readonly value
         
         >>> tearDown()
         """
@@ -616,20 +624,18 @@
             >>> class DisplayWidget(Widget):
             ...     implements(IDisplayWidget)
             ...     def getRenderedValue(self): return self._data
-            >>> ztapi.browserView(IFoo, '', DisplayWidget,
-            ...                   providing=IDisplayWidget)
-            >>> ztapi.browserView(IBar, '', DisplayWidget,
-            ...                   providing=IDisplayWidget)
+            >>> ztapi.browserViewProviding(IFoo, DisplayWidget, IDisplayWidget)
+            >>> ztapi.browserViewProviding(IBar, DisplayWidget, IDisplayWidget)
 
-        Next we'll configure a context object to be edited:
+        Next we'll configure a view with a context object:
             
             >>> context = Content()
             >>> context.foo = 'abc'
             >>> context.bar = 'def'
+            >>> view = BrowserView(context, request)
             
-        Calling setUpDisplayWidget with a view of context:
+        A call to setUpEditWidgets with the view:
             
-            >>> view = BrowserView(context, request)
             >>> setUpDisplayWidgets(view, IContent)
             
         configures the view with widgets that display the context fields:
@@ -643,14 +649,14 @@
             >>> view.bar_widget.getRenderedValue()
             'def'
             
-        setUpDisplayWidgets accepts a 'context' argument that provides an
-        alternate source of values to be edited:
+        Like setUpEditWidgets, setUpDisplayWidgets accepts a 'source'
+        argument that provides an alternate source of values to be edited:
             
             >>> view = BrowserView(context, request)
-            >>> altContext = Content()
-            >>> altContext.foo = 'abc2'
-            >>> altContext.bar = 'def2'
-            >>> setUpDisplayWidgets(view, IContent, context=altContext)
+            >>> source = Content()
+            >>> source.foo = 'abc2'
+            >>> source.bar = 'def2'
+            >>> setUpDisplayWidgets(view, IContent, source=source)
             >>> view.foo_widget.getRenderedValue()
             'abc2'
             >>> view.bar_widget.getRenderedValue()
@@ -672,17 +678,17 @@
         This method is typically invoked on a view that has been configured
         with one setUpEditWidgets.
         
-            >>> class EditWidget(Widget):
-            ...     implements(IEditWidget)
+            >>> class InputWidget(Widget):
+            ...     implements(IInputWidget)
             ...     input = None
             ...     def hasInput(self):
             ...         return self.input is not None
-            >>> ztapi.browserView(IFoo, '', EditWidget, providing=IEditWidget)
-            >>> ztapi.browserView(IBar, '', EditWidget, providing=IEditWidget)
+            >>> ztapi.browserViewProviding(IFoo, InputWidget, IInputWidget)
+            >>> ztapi.browserViewProviding(IBar, InputWidget, IInputWidget)
             >>> view = BrowserView(Content(), request)
             >>> setUpEditWidgets(view, IContent)
             
-        Because EditWidget is configured to not have input by default, the
+        Because InputWidget is configured to not have input by default, the
         view does not have input:
             
             >>> viewHasInput(view, IContent)
@@ -709,8 +715,8 @@
         We'll first create a simple edit widget that can be used to update
         an object:
         
-            >>> class EditWidget(Widget):
-            ...     implements(IEditWidget)           
+            >>> class InputWidget(Widget):
+            ...     implements(IInputWidget)           
             ...     input = None
             ...     def hasInput(self):
             ...         return input is not None
@@ -718,7 +724,7 @@
             ...         field = self.context
             ...         field.set(object, self.input)
             ...         return True
-            >>> ztapi.browserView(IFoo, '', EditWidget, providing=IEditWidget)
+            >>> ztapi.browserViewProviding(IFoo, InputWidget, IInputWidget)
             
         Before calling applyWidgetsUpdate, we need to configure a context and
         a view with edit widgets:
@@ -736,6 +742,30 @@
             True
             >>> context.foo
             'The quick brown fox...'
+            
+        By default, applyWidgetsChanges applies the new widget values to the
+        view context. Alternatively, we can provide a 'target' argument to
+        be updated:
+            
+            >>> target = Content()
+            >>> target.foo
+            'Foo'
+            >>> applyWidgetsChanges(view, IContent, target=target, 
+            ...                     names=('foo',))
+            True
+            >>> target.foo
+            'The quick brown fox...'
+            
+        applyWidgetsChanges is typically used in conjunction with one of the
+        setUp utility functions. If applyWidgetsChanges is called using a
+        view that was not previously configured with a setUp function, or
+        was not otherwise configured with widgets for each of the applicable
+        fields, an AttributeError will be raised:
+            
+            >>> view = BrowserView(context, request)
+            >>> applyWidgetsChanges(view, IContent, names=('foo',))
+            Traceback (most recent call last):
+            AttributeError: 'BrowserView' object has no attribute 'foo_widget'
 
         >>> tearDown()
         """
@@ -751,15 +781,15 @@
         For this test, we'll create a simple edit widget and register it
         for the schema field types:
             
-            >>> class EditWidget(Widget):
-            ...     implements(IEditWidget)
+            >>> class InputWidget(Widget):
+            ...     implements(IInputWidget)
             ...     input = None
             ...     def hasInput(self):
             ...         return self.input is not None
             ...     def getInputValue(self):
             ...         return self.input
-            >>> ztapi.browserView(IFoo, '', EditWidget, providing=IEditWidget)
-            >>> ztapi.browserView(IBar, '', EditWidget, providing=IEditWidget)
+            >>> ztapi.browserViewProviding(IFoo, InputWidget, IInputWidget)
+            >>> ztapi.browserViewProviding(IBar, InputWidget, IInputWidget)
 
         We use setUpEditWidgets to configure a view with widgets for the
         IContent schema:
@@ -823,6 +853,55 @@
             ['bar']
             
         >>> tearDown()
+        """
+        
+    def test_widgetsErrorException(self):
+        """Documents and tests WidgetsError.
+        
+        XXX Move this test into zope.app.interfaces.tests.test_form when
+        that module is created.
+        
+        WidgetsError wraps one or more errors, which are specified as a
+        sequence in the 'errors' argument:
+        
+            >>> error = WidgetsError(('foo',))
+            >>> error
+            str: foo
+            
+        WidgetsError also provides a 'widgetsData' attribute, which is a
+        map of valid field values, keyed by field name, that were obtained
+        in the same read operation that generated the errors:
+            
+            >>> error = WidgetsError(('foo',), widgetsData={'bar': 'Bar'})
+            >>> error.widgetsData
+            {'bar': 'Bar'}
+            
+        The most typical use of this error is when reading a set of widget
+        values -- the read operation can generate more than one error, as well
+        as a set of successfully read values:
+            
+            >>> values = {'foo': 'Foo'}
+            >>> errors = []
+            >>> widgetsData = {}
+            >>> for name in ('foo', 'bar'):  # some list of values to read
+            ...     try:
+            ...         widgetsData[name] = values[name]  # read operation
+            ...     except Exception, e:
+            ...         errors.append(e)    # capture all errors
+            >>> if errors:
+            ...     widgetsError = WidgetsError(errors, widgetsData)
+            ...     raise widgetsError
+            Traceback (most recent call last):
+            WidgetsError: KeyError: 'bar'
+            
+        The handler of error can access all of the widget error as well as
+        the widget values read:
+            
+            >>> for error in widgetsError:
+            ...     error.__class__.__name__
+            'KeyError'
+            >>> widgetsError.widgetsData
+            {'foo': 'Foo'}
         """
             
 def test_suite():




More information about the Zope3-Checkins mailing list