[Checkins] SVN: z3c.form/branches/adamg-objectwidget/src/z3c/form/ made setErrors go recursive over forms and widgets

Adam Groszer agroszer at gmail.com
Tue Oct 14 12:30:08 EDT 2008


Log message for revision 92198:
  made setErrors go recursive over forms and widgets
  

Changed:
  U   z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/image.py
  U   z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object.txt
  U   z3c.form/branches/adamg-objectwidget/src/z3c/form/field.py
  U   z3c.form/branches/adamg-objectwidget/src/z3c/form/form.py
  U   z3c.form/branches/adamg-objectwidget/src/z3c/form/interfaces.py
  U   z3c.form/branches/adamg-objectwidget/src/z3c/form/object.py
  U   z3c.form/branches/adamg-objectwidget/src/z3c/form/widget.py

-=-
Modified: z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/image.py
===================================================================
--- z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/image.py	2008-10-14 15:22:29 UTC (rev 92197)
+++ z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/image.py	2008-10-14 16:30:08 UTC (rev 92198)
@@ -34,7 +34,7 @@
     src = FieldProperty(IHTMLImageWidget['src'])
     klass = u'image-widget'
 
-    def extract(self, default=interfaces.NOVALUE):
+    def extract(self, default=interfaces.NOVALUE, setErrors=True):
         """See z3c.form.interfaces.IWidget."""
         if self.name + '.x' not in self.request:
             return default

Modified: z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object.txt
===================================================================
--- z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object.txt	2008-10-14 15:22:29 UTC (rev 92197)
+++ z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object.txt	2008-10-14 16:30:08 UTC (rev 92198)
@@ -250,71 +250,73 @@
   'ThisMustStayTheSame'
 
 
+HMMMM.... do we to test error handling here?
+I'm tempted to leave it out as no widgets seem to do this.
 
-Error handling is next. Let's use the value "bad" (an invalid integer literal)
-as input for our internal (sub) widget.
+#Error handling is next. Let's use the value "bad" (an invalid integer literal)
+#as input for our internal (sub) widget.
+#
+#  >>> widget.request = TestRequest(form={'subobject.widgets.foofield':u'55',
+#  ...                                    'subobject.widgets.barfield':u'bad',
+#  ...                                    'subobject-empty-marker':u'1'})
+#
+#
+#  >>> widget.update()
+#  >>> print widget.render()
+#  <html>
+#    <body>
+#      <div class="object-widget required">
+#        <div class="label">
+#          <label for="subobject-widgets-foofield">
+#            <span>My foo field</span>
+#            <span class="required">*</span>
+#          </label>
+#        </div>
+#        <div class="widget">
+#          <input class="text-widget required int-field"
+#          id="subobject-widgets-foofield"
+#          name="subobject.widgets.foofield"
+#          type="text" value="55">
+#        </div>
+#        <div class="label">
+#          <label for="subobject-widgets-barfield">
+#            <span>My dear bar</span>
+#          </label>
+#        </div>
+#        <div class="error">
+#          <div class="error">The entered value is not a valid integer literal.</div>
+#        </div>
+#        <div class="widget">
+#          <input class="text-widget int-field"
+#          id="subobject-widgets-barfield"
+#          name="subobject.widgets.barfield"
+#          type="text" value="bad">
+#        </div>
+#        <input name="subobject-empty-marker" type="hidden" value="1">
+#      </div>
+#    </body>
+#  </html>
+#
+#Getting the widget value raises the widget errors:
+#
+#  >>> widget.value
+#  Traceback (most recent call last):
+#  ...
+#  MultipleErrors
+#
+#Our object still must retain the old values:
+#
+#  >>> v
+#  <z3c.form.testing.MySubObject object at ...>
+#  >>> v.foofield
+#  42
+#  >>> v.barfield
+#  666
+#  >>> v.__marker__
+#  'ThisMustStayTheSame'
 
-  >>> widget.request = TestRequest(form={'subobject.widgets.foofield':u'55',
-  ...                                    'subobject.widgets.barfield':u'bad',
-  ...                                    'subobject-empty-marker':u'1'})
 
 
-  >>> widget.update()
-  >>> print widget.render()
-  <html>
-    <body>
-      <div class="object-widget required">
-        <div class="label">
-          <label for="subobject-widgets-foofield">
-            <span>My foo field</span>
-            <span class="required">*</span>
-          </label>
-        </div>
-        <div class="widget">
-          <input class="text-widget required int-field"
-          id="subobject-widgets-foofield"
-          name="subobject.widgets.foofield"
-          type="text" value="55">
-        </div>
-        <div class="label">
-          <label for="subobject-widgets-barfield">
-            <span>My dear bar</span>
-          </label>
-        </div>
-        <div class="error">
-          <div class="error">The entered value is not a valid integer literal.</div>
-        </div>
-        <div class="widget">
-          <input class="text-widget int-field"
-          id="subobject-widgets-barfield"
-          name="subobject.widgets.barfield"
-          type="text" value="bad">
-        </div>
-        <input name="subobject-empty-marker" type="hidden" value="1">
-      </div>
-    </body>
-  </html>
-
-Getting the widget value raises the widget errors:
-
-  >>> widget.value
-  Traceback (most recent call last):
-  ...
-  MultipleErrors
-
-Our object still must retain the old values:
-
-  >>> v
-  <z3c.form.testing.MySubObject object at ...>
-  >>> v.foofield
-  42
-  >>> v.barfield
-  666
-  >>> v.__marker__
-  'ThisMustStayTheSame'
-
-
-
 In forms
 ========
 
@@ -1039,129 +1041,129 @@
 
 
 
-#Object in an Object situation
-#=============================
-#
-#
-#We define an interface containing a subobject, and an addform for it:
-#
-#  >>> from z3c.form import form, field
-#  >>> from z3c.form.testing import MyComplexObject, IMyComplexObject
-#
-#Note, that creating an object will print some information about it:
-#
-#  >>> class MyAddForm(form.AddForm):
-#  ...     fields = field.Fields(IMyComplexObject)
-#  ...     def create(self, data):
-#  ...         print "MyAddForm.create", str(data)
-#  ...         return MyObject(**data)
-#  ...     def add(self, obj):
-#  ...         self.context[obj.name] = obj
-#  ...     def nextURL(self):
-#  ...         pass
-#
-#We create the form and try to update it:
-#
-#  >>> request = TestRequest()
-#
-##>>> from pub.dbgpclient import brk; brk('192.168.32.1')
-#
-#  >>> myaddform =  MyAddForm(root, request)
-#
-#  >>> from pub.dbgpclient import brk; brk('192.168.32.1')
-#
-#
-#  >>> myaddform.update()
-#
-#As usual, the form contains a widget manager with the expected widget
-#
-#  >>> myaddform.widgets.keys()
-#  ['subobject', 'name']
-#  >>> myaddform.widgets.values()
-#  [<ObjectWidget 'form.widgets.subobject'>, <TextWidget 'form.widgets.name'>]
-#
-#The addform has our ObjectWidget which in turn contains a subform:
-#
-#  >>> myaddform.widgets['subobject'].subform
-#  <z3c.form.object.ObjectSubForm object at ...>
-#
-#Which in turn contains the sub-widgets:
-#
-#  >>> myaddform.widgets['subobject'].subform.widgets.keys()
-#  ['subfield', 'moofield']
-#
-#  >>> myaddform.widgets['subobject'].subform.widgets['subfield'].subform.widgets.keys()
-#  ['foofield', 'barfield']
-#
-#If we want to render the addform, we must give it a template:
-#
-#  >>> addTemplate(myaddform)
-#
-#Now rendering the addform renders the subform as well:
-#
-#  >>> print myaddform.render()
-#  <html xmlns="http://www.w3.org/1999/xhtml">
-#    <body>
-#      <form action=".">
-#        <div class="row">
-#          <label for="form-widgets-subobject">my object</label>
-#          <div class="object-widget required">
-#            <div class="label">
-#              <label for="form-widgets-subobject-widgets-subfield">
-#                <span>Second-subobject</span>
-#                <span class="required">*</span>
-#              </label>
-#            </div>
-#            <div class="widget">
-#              <div class="object-widget required">
-#                <div class="label">
-#                  <label for="form-widgets-subobject-widgets-subfield-widgets-foofield">
-#                    <span>My foo field</span>
-#                    <span class="required">*</span>
-#                  </label>
-#                </div>
-#                <div class="widget">
-#                  <input class="text-widget required int-field"
-#                  id="form-widgets-subobject-widgets-subfield-widgets-foofield"
-#                  name="form.widgets.subobject.widgets.subfield.widgets.foofield"
-#                  type="text" value="1,111">
-#                </div>
-#                <div class="label">
-#                  <label for="form-widgets-subobject-widgets-subfield-widgets-barfield">
-#                    <span>My dear bar</span>
-#                  </label>
-#                </div>
-#                <div class="widget">
-#                  <input class="text-widget int-field"
-#                  id="form-widgets-subobject-widgets-subfield-widgets-barfield"
-#                  name="form.widgets.subobject.widgets.subfield.widgets.barfield"
-#                  type="text" value="2,222">
-#                </div>
-#                <input name="form.widgets.subobject.widgets.subfield-empty-marker" type="hidden" value="1">
-#              </div>
-#            </div>
-#            <div class="label">
-#              <label for="form-widgets-subobject-widgets-moofield">
-#                <span>Something</span>
-#                <span class="required">*</span>
-#              </label>
-#            </div>
-#            <div class="widget">
-#              <input class="text-widget required textline-field"
-#              id="form-widgets-subobject-widgets-moofield"
-#              name="form.widgets.subobject.widgets.moofield" type="text" value="">
-#            </div>
-#            <input name="form.widgets.subobject-empty-marker" type="hidden" value="1">
-#          </div>
-#        </div>
-#        <div class="row">
-#          <label for="form-widgets-name">name</label>
-#          <input class="text-widget required textline-field"
-#          id="form-widgets-name" name="form.widgets.name" type="text" value="">
-#        </div>
-#        <div class="action">
-#          <input class="submit-widget button-field" id="form-buttons-add" name="form.buttons.add" type="submit" value="Add">
-#        </div>
-#      </form>
-#    </body>
-#  </html>
+Object in an Object situation
+=============================
+
+
+We define an interface containing a subobject, and an addform for it:
+
+  >>> from z3c.form import form, field
+  >>> from z3c.form.testing import MyComplexObject, IMyComplexObject
+
+Note, that creating an object will print some information about it:
+
+  >>> class MyAddForm(form.AddForm):
+  ...     fields = field.Fields(IMyComplexObject)
+  ...     def create(self, data):
+  ...         print "MyAddForm.create", str(data)
+  ...         return MyObject(**data)
+  ...     def add(self, obj):
+  ...         self.context[obj.name] = obj
+  ...     def nextURL(self):
+  ...         pass
+
+We create the form and try to update it:
+
+  >>> request = TestRequest()
+
+#>>> from pub.dbgpclient import brk; brk('192.168.32.1')
+
+  >>> myaddform =  MyAddForm(root, request)
+
+#>>> from pub.dbgpclient import brk; brk('192.168.32.1')
+
+
+  >>> myaddform.update()
+
+As usual, the form contains a widget manager with the expected widget
+
+  >>> myaddform.widgets.keys()
+  ['subobject', 'name']
+  >>> myaddform.widgets.values()
+  [<ObjectWidget 'form.widgets.subobject'>, <TextWidget 'form.widgets.name'>]
+
+The addform has our ObjectWidget which in turn contains a subform:
+
+  >>> myaddform.widgets['subobject'].subform
+  <z3c.form.object.ObjectSubForm object at ...>
+
+Which in turn contains the sub-widgets:
+
+  >>> myaddform.widgets['subobject'].subform.widgets.keys()
+  ['subfield', 'moofield']
+
+  >>> myaddform.widgets['subobject'].subform.widgets['subfield'].subform.widgets.keys()
+  ['foofield', 'barfield']
+
+If we want to render the addform, we must give it a template:
+
+  >>> addTemplate(myaddform)
+
+Now rendering the addform renders the subform as well:
+
+  >>> print myaddform.render()
+  <html xmlns="http://www.w3.org/1999/xhtml">
+    <body>
+      <form action=".">
+        <div class="row">
+          <label for="form-widgets-subobject">my object</label>
+          <div class="object-widget required">
+            <div class="label">
+              <label for="form-widgets-subobject-widgets-subfield">
+                <span>Second-subobject</span>
+                <span class="required">*</span>
+              </label>
+            </div>
+            <div class="widget">
+              <div class="object-widget required">
+                <div class="label">
+                  <label for="form-widgets-subobject-widgets-subfield-widgets-foofield">
+                    <span>My foo field</span>
+                    <span class="required">*</span>
+                  </label>
+                </div>
+                <div class="widget">
+                  <input class="text-widget required int-field"
+                  id="form-widgets-subobject-widgets-subfield-widgets-foofield"
+                  name="form.widgets.subobject.widgets.subfield.widgets.foofield"
+                  type="text" value="1,111">
+                </div>
+                <div class="label">
+                  <label for="form-widgets-subobject-widgets-subfield-widgets-barfield">
+                    <span>My dear bar</span>
+                  </label>
+                </div>
+                <div class="widget">
+                  <input class="text-widget int-field"
+                  id="form-widgets-subobject-widgets-subfield-widgets-barfield"
+                  name="form.widgets.subobject.widgets.subfield.widgets.barfield"
+                  type="text" value="2,222">
+                </div>
+                <input name="form.widgets.subobject.widgets.subfield-empty-marker" type="hidden" value="1">
+              </div>
+            </div>
+            <div class="label">
+              <label for="form-widgets-subobject-widgets-moofield">
+                <span>Something</span>
+                <span class="required">*</span>
+              </label>
+            </div>
+            <div class="widget">
+              <input class="text-widget required textline-field"
+              id="form-widgets-subobject-widgets-moofield"
+              name="form.widgets.subobject.widgets.moofield" type="text" value="">
+            </div>
+            <input name="form.widgets.subobject-empty-marker" type="hidden" value="1">
+          </div>
+        </div>
+        <div class="row">
+          <label for="form-widgets-name">name</label>
+          <input class="text-widget required textline-field"
+          id="form-widgets-name" name="form.widgets.name" type="text" value="">
+        </div>
+        <div class="action">
+          <input class="submit-widget button-field" id="form-buttons-add" name="form.buttons.add" type="submit" value="Add">
+        </div>
+      </form>
+    </body>
+  </html>

Modified: z3c.form/branches/adamg-objectwidget/src/z3c/form/field.py
===================================================================
--- z3c.form/branches/adamg-objectwidget/src/z3c/form/field.py	2008-10-14 15:22:29 UTC (rev 92197)
+++ z3c.form/branches/adamg-objectwidget/src/z3c/form/field.py	2008-10-14 16:30:08 UTC (rev 92198)
@@ -276,7 +276,7 @@
                 continue
             value = widget.field.missing_value
             try:
-                raw = widget.extract()
+                raw = widget.extract(setErrors=setErrors)
                 if raw is not interfaces.NOVALUE:
                     value = interfaces.IDataConverter(widget).toFieldValue(raw)
                 zope.component.getMultiAdapter(

Modified: z3c.form/branches/adamg-objectwidget/src/z3c/form/form.py
===================================================================
--- z3c.form/branches/adamg-objectwidget/src/z3c/form/form.py	2008-10-14 15:22:29 UTC (rev 92197)
+++ z3c.form/branches/adamg-objectwidget/src/z3c/form/form.py	2008-10-14 16:30:08 UTC (rev 92198)
@@ -127,9 +127,9 @@
         self.widgets.ignoreReadonly = self.ignoreReadonly
         self.widgets.update()
 
-    def extractData(self):
+    def extractData(self, setErrors=True):
         '''See interfaces.IForm'''
-        return self.widgets.extract()
+        return self.widgets.extract(setErrors=setErrors)
 
     def update(self):
         '''See interfaces.IForm'''

Modified: z3c.form/branches/adamg-objectwidget/src/z3c/form/interfaces.py
===================================================================
--- z3c.form/branches/adamg-objectwidget/src/z3c/form/interfaces.py	2008-10-14 15:22:29 UTC (rev 92197)
+++ z3c.form/branches/adamg-objectwidget/src/z3c/form/interfaces.py	2008-10-14 16:30:08 UTC (rev 92198)
@@ -404,7 +404,7 @@
         default=False,
         required=False)
 
-    def extract(default=NOVALUE):
+    def extract(default=NOVALUE, setErrors=True):
         """Extract the string value(s) of the widget from the form.
 
         The return value may be any Python construct, but is typically a
@@ -414,10 +414,12 @@
 
         If an error occurs during the extraction, the default value should be
         returned. Since this should never happen, if the widget is properly
-        designed and used, it is okay to not raise an error here, since we do
+        designed and used, it is okay to NOT raise an error here, since we do
         not want to crash the system during an inproper request.
 
         If there is no value to extract, the default is to be returned.
+
+        setErrors: needs to be passed on to possible sub-widgets
         """
 
     def update():
@@ -582,8 +584,11 @@
     def update():
         """Setup widgets."""
 
-    def extract():
+    def extract(setErrors=True):
         """Extract the values from the widgets and validate them.
+
+        setErrors: decides whether to set errors on self and on the widgets
+                   also needs to be passed on to sub-widgets
         """
 
 
@@ -843,9 +848,11 @@
         mainly meant to be a hook for subclasses.
         '''
 
-    def extractData():
-        '''Extract the data of the form.'''
+    def extractData(setErrors=True):
+        '''Extract the data of the form.
 
+        setErrors: needs to be passed to extract() and to sub-widgets'''
+
     def update():
         '''Update the form.'''
 

Modified: z3c.form/branches/adamg-objectwidget/src/z3c/form/object.py
===================================================================
--- z3c.form/branches/adamg-objectwidget/src/z3c/form/object.py	2008-10-14 15:22:29 UTC (rev 92197)
+++ z3c.form/branches/adamg-objectwidget/src/z3c/form/object.py	2008-10-14 16:30:08 UTC (rev 92198)
@@ -65,7 +65,7 @@
                 view.update()
                 widget.error = view
 
-    def update(self, ignoreContext=None):
+    def update(self, ignoreContext=None, setErrors=True):
         self.fields = Fields(self.__parent__.field.schema)
 
         #update stuff from parent to be sure
@@ -87,7 +87,9 @@
 
         super(ObjectSubForm, self).update()
 
-        self._validate()
+        if setErrors:
+            #hmmm, do we need this here? seems to be over-validated
+            self._validate()
 
     def getContent(self):
         return self.__parent__._value
@@ -187,7 +189,7 @@
              form, self, self.field),
             interfaces.ISubformFactory)()
 
-    def updateWidgets(self):
+    def updateWidgets(self, setErrors=True):
         if self._value is not interfaces.NOVALUE:
             self._getForm(self._value)
             ignore = None
@@ -195,14 +197,14 @@
             self._getForm(None)
             ignore = True
 
-        self.subform.update(ignore)
+        self.subform.update(ignore, setErrors=setErrors)
 
     def update(self):
         #very-very-nasty: skip raising exceptions in extract while we're updating
         self._updating = True
         try:
             super(ObjectWidget, self).update()
-            self.updateWidgets()
+            self.updateWidgets(setErrors=False)
         finally:
             self._updating = False
 
@@ -210,7 +212,7 @@
     def value():
         """This invokes updateWidgets on any value change e.g. update/extract."""
         def get(self):
-            return self.extract()
+            return self.extract(setErrors=True)
         def set(self, value):
             self._value = value
             # ensure that we apply our new values to the widgets
@@ -218,30 +220,20 @@
         return property(get, set)
 
 
-    def extract(self, default=interfaces.NOVALUE):
+    def extract(self, default=interfaces.NOVALUE, setErrors=True):
         if self.name+'-empty-marker' in self.request:
-            self.updateWidgets()
+            self.updateWidgets(setErrors=False)
 
-            value = self.subform.extractData()
-            #value here is (data-dict, (error1, error2))
+            value, errors = self.subform.extractData(setErrors=setErrors)
 
-            if value[1]:
+            if errors:
                 #very-very-nasty: skip raising exceptions in extract
                 #while we're updating
                 if self._updating:
-                    #very-very-nasty: kill all errors on subwidgets
-                    if self.subform.widgets.errors:
-                        pass
-                        #from pub.dbgpclient import brk; brk('192.168.32.1')
-
-                    self.subform.widgets.errors = ()
-                    for w in self.subform.widgets.values():
-                        w.error=None
-
                     return default
-                raise MultipleErrors(value[1])
+                raise MultipleErrors(errors)
 
-            return value[0]
+            return value
 
         else:
             return default

Modified: z3c.form/branches/adamg-objectwidget/src/z3c/form/widget.py
===================================================================
--- z3c.form/branches/adamg-objectwidget/src/z3c/form/widget.py	2008-10-14 15:22:29 UTC (rev 92197)
+++ z3c.form/branches/adamg-objectwidget/src/z3c/form/widget.py	2008-10-14 16:30:08 UTC (rev 92198)
@@ -77,7 +77,9 @@
         lookForDefault = False
         # Step 1.1: If possible, get a value from the request
         if not self.ignoreRequest:
-            widget_value = self.extract()
+            #at this turn we do not need errors to be set on widgets
+            #errors will be set when extract gets called from form.extractData
+            widget_value = self.extract(setErrors=False)
             if widget_value is not interfaces.NOVALUE:
                 # Once we found the value in the request, it takes precendence
                 # over everything and nothing else has to be done.
@@ -136,7 +138,7 @@
                 IPageTemplate, name=self.mode)
         return template(self)
 
-    def extract(self, default=interfaces.NOVALUE):
+    def extract(self, default=interfaces.NOVALUE, setErrors=True):
         """See z3c.form.interfaces.IWidget."""
         return self.request.get(self.name, default)
 
@@ -195,7 +197,7 @@
         self.updateTerms()
         super(SequenceWidget, self).update()
 
-    def extract(self, default=interfaces.NOVALUE):
+    def extract(self, default=interfaces.NOVALUE, setErrors=True):
         """See z3c.form.interfaces.IWidget."""
         if (self.name not in self.request and
             self.name+'-empty-marker' in self.request):
@@ -338,7 +340,7 @@
             self.updateWidgets()
         return property(get, set)
 
-    def extract(self, default=interfaces.NOVALUE):
+    def extract(self, default=interfaces.NOVALUE, setErrors=True):
         # This method is responsible to get the widgets value based on the
         # request and nothing else.
         # We have to setup the widgets for extract their values, because we



More information about the Checkins mailing list