[Checkins] SVN: z3c.form/trunk/ Reporting invariant invalid errors was not working. Here is what was

Stephan Richter srichter at cosmos.phy.tufts.edu
Tue Aug 7 23:21:33 EDT 2007


Log message for revision 78679:
  Reporting invariant invalid errors was not working. Here is what was 
  needed:
  
  - Feature: A new ``InvalidErrorViewSnippet`` class provides an error view
    snippet for ``zope.interface.Invalid`` exceptions, which are frequently used
    for invariants.
  
  - Bug: When extracting and validating data in the widget manager, invariant
    errors were not converted to error view snippets.
  
  - Bug: When error view snippets were not widget-specific -- in other words,
    the ``widget`` attribute was ``None`` -- rendering the template would fail.
  
  

Changed:
  U   z3c.form/trunk/CHANGES.txt
  U   z3c.form/trunk/src/z3c/form/configure.zcml
  U   z3c.form/trunk/src/z3c/form/error.py
  U   z3c.form/trunk/src/z3c/form/error.txt
  U   z3c.form/trunk/src/z3c/form/field.py
  U   z3c.form/trunk/src/z3c/form/field.txt
  U   z3c.form/trunk/src/z3c/form/form.txt
  U   z3c.form/trunk/src/z3c/form/testing.py
  U   z3c.form/trunk/src/z3c/form/tests/simple_caredit.pt
  U   z3c.form/trunk/src/z3c/form/tests/simple_edit.pt
  U   z3c.form/trunk/src/z3c/form/tests/simple_groupedit.pt
  U   z3c.form/trunk/src/z3c/form/tests/simple_owneredit.pt
  U   z3c.form/trunk/src/z3c/form/tests/simple_subedit.pt
  U   z3c.form/trunk/src/z3c/form/validator.txt

-=-
Modified: z3c.form/trunk/CHANGES.txt
===================================================================
--- z3c.form/trunk/CHANGES.txt	2007-08-07 21:07:40 UTC (rev 78678)
+++ z3c.form/trunk/CHANGES.txt	2007-08-08 03:21:31 UTC (rev 78679)
@@ -5,6 +5,10 @@
 Version 1.6.0 (?/??/2007)
 -------------------------
 
+- Feature: A new ``InvalidErrorViewSnippet`` class provides an error view
+  snippet for ``zope.interface.Invalid`` exceptions, which are frequently used
+  for invariants.
+
 - Feature: When a widget is required, HTML-based widgets now declare a
   "required" class.
 
@@ -38,7 +42,13 @@
 - Documentation: While reviewing the ``form.txt`` with some people, several
   unclear and incomplete statements were discovered and fixed.
 
+- Bug: When extracting and validating data in the widget manager, invariant
+  errors were not converted to error view snippets.
 
+- Bug: When error view snippets were not widget-specific -- in other words,
+  the ``widget`` attribute was ``None`` -- rendering the template would fail.
+
+
 Version 1.5.0 (7/18/2007)
 -------------------------
 

Modified: z3c.form/trunk/src/z3c/form/configure.zcml
===================================================================
--- z3c.form/trunk/src/z3c/form/configure.zcml	2007-08-07 21:07:40 UTC (rev 78678)
+++ z3c.form/trunk/src/z3c/form/configure.zcml	2007-08-08 03:21:31 UTC (rev 78679)
@@ -97,6 +97,11 @@
       permission="zope.Public"
       />
   <adapter
+      factory=".error.InvalidErrorViewSnippet"
+      trusted="True"
+      permission="zope.Public"
+      />
+  <adapter
       factory=".error.ValueErrorViewSnippet"
       trusted="True"
       permission="zope.Public"

Modified: z3c.form/trunk/src/z3c/form/error.py
===================================================================
--- z3c.form/trunk/src/z3c/form/error.py	2007-08-07 21:07:40 UTC (rev 78678)
+++ z3c.form/trunk/src/z3c/form/error.py	2007-08-08 03:21:31 UTC (rev 78679)
@@ -58,6 +58,9 @@
         self.form = form
         self.content = content
 
+    def createMessage(self):
+        return self.error.doc()
+
     def update(self):
         value = zope.component.queryMultiAdapter(
             (self.context, self.request, self.widget,
@@ -66,7 +69,7 @@
         if value is not None:
             self.message = value.get()
         else:
-            self.message = self.error.doc()
+            self.message = self.createMessage()
 
     def render(self):
         template = zope.component.getMultiAdapter(
@@ -83,17 +86,21 @@
     zope.component.adapts(
         ValueError, None, None, None, None, None)
 
-    message = _('The system could not process the given value.')
+    defaultMessage = _('The system could not process the given value.')
 
-    def update(self):
-        value = zope.component.queryMultiAdapter(
-            (self.context, self.request, self.widget,
-             self.field, self.form, self),
-            interfaces.IValue, name='message')
-        if value is not None:
-            self.message = value.get()
+    def createMessage(self):
+        return self.defaultMessage
 
 
+class InvalidErrorViewSnippet(ErrorViewSnippet):
+    """Error view snippet."""
+    zope.component.adapts(
+        zope.interface.Invalid, None, None, None, None, None)
+
+    def createMessage(self):
+        return self.error.args[0]
+
+
 class ErrorViewTemplateFactory(object):
     """Error view template factory."""
 

Modified: z3c.form/trunk/src/z3c/form/error.txt
===================================================================
--- z3c.form/trunk/src/z3c/form/error.txt	2007-08-07 21:07:40 UTC (rev 78678)
+++ z3c.form/trunk/src/z3c/form/error.txt	2007-08-08 03:21:31 UTC (rev 78679)
@@ -166,3 +166,25 @@
   >>> errorView.update()
   >>> print errorView.render()
   <div class="error">The entered value is not valid.</div>
+
+
+Invalid Error View Snippets
+---------------------------
+
+When invariants are used, commonly the ``Invalid`` exception (from the
+``zope.interface`` package) is raised from within the invariant, if the
+invariant finds a problem. We need a special error view snippet for this class
+of errors:
+
+  >>> invalidError = zope.interface.Invalid(u'The data was invalid.')
+  >>> errorView = error.InvalidErrorViewSnippet(
+  ...     invalidError, TestRequest(), None, None, None, None)
+
+Since the same template as before is used, the error simply renders:
+
+  >>> errorView.update()
+  >>> print errorView.render()
+  <div class="error">The data was invalid.</div>
+
+As you can see, the first argument to the exception is used as the explanatory
+message of the error.

Modified: z3c.form/trunk/src/z3c/form/field.py
===================================================================
--- z3c.form/trunk/src/z3c/form/field.py	2007-08-07 21:07:40 UTC (rev 78678)
+++ z3c.form/trunk/src/z3c/form/field.py	2007-08-08 03:21:31 UTC (rev 78679)
@@ -290,5 +290,10 @@
             else:
                 name = widget.__name__
                 data[name] = value
-        self.errors += self.validate(data)
+        for error in self.validate(data):
+            view = zope.component.getMultiAdapter(
+                (error, self.request, None, None, self.form, self.content),
+                interfaces.IErrorViewSnippet)
+            view.update()
+            self.errors += (view,)
         return data, self.errors

Modified: z3c.form/trunk/src/z3c/form/field.txt
===================================================================
--- z3c.form/trunk/src/z3c/form/field.txt	2007-08-07 21:07:40 UTC (rev 78678)
+++ z3c.form/trunk/src/z3c/form/field.txt	2007-08-08 03:21:31 UTC (rev 78679)
@@ -675,10 +675,12 @@
   >>> manager.ignoreContext = True
   >>> manager.update()
   >>> data, errors = manager.extract()
-  >>> errors[0].doc()
+  >>> errors[0].error.doc()
   'The last name is too short.'
 
-And that's all.
+Note that the errors coming from invariants are all error view snippets as
+well, just as it is the case for field-specific validation errors. And that's
+really all there is!
 
 
 Fields -- Custom Widget Factories

Modified: z3c.form/trunk/src/z3c/form/form.txt
===================================================================
--- z3c.form/trunk/src/z3c/form/form.txt	2007-08-07 21:07:40 UTC (rev 78678)
+++ z3c.form/trunk/src/z3c/form/form.txt	2007-08-08 03:21:31 UTC (rev 78679)
@@ -42,6 +42,12 @@
   ...         min=0,
   ...         default=20,
   ...         required=False)
+  ...
+  ...     @zope.interface.invariant
+  ...     def ensureIdAndNameNotEuqal(person):
+  ...         if person.id == person.name:
+  ...             raise zope.interface.Invalid(
+  ...                 "The id and name cannot be the same.")
 
   >>> from zope.schema.fieldproperty import FieldProperty
   >>> class Person(object):
@@ -445,6 +451,37 @@
 
 Note that the values of the field are now extracted from the request.
 
+Another way to receive an error is by not fulfilling the invariants of the
+schema. In our case, the id and name cannot be the same. So let's provoke the
+error now, ...
+
+  >>> request = TestRequest(form={
+  ...     'form.widgets.id': u'Stephan',
+  ...     'form.widgets.name': u'Stephan',
+  ...     'form.widgets.gender': ['male'],
+  ...     'form.widgets.age': u'23',
+  ...     'form.buttons.add': u'Add'}
+  ...     )
+
+  >>> addForm = PersonAddForm(root, request)
+  >>> addTemplate(addForm)
+  >>> addForm.update()
+
+and see how the form looks like:
+
+  >>> print addForm.render()
+  <html>
+    <body>
+      <i>There were some errors.</i>
+      <ul>
+        <li>
+          <div class="error">The id and name cannot be the same.</div>
+        </li>
+      </ul>
+      ...
+    </body>
+  </html>
+
 Let's now also provide a negative age, which is not possible either:
 
   >>> request = TestRequest(form={

Modified: z3c.form/trunk/src/z3c/form/testing.py
===================================================================
--- z3c.form/trunk/src/z3c/form/testing.py	2007-08-07 21:07:40 UTC (rev 78678)
+++ z3c.form/trunk/src/z3c/form/testing.py	2007-08-08 03:21:31 UTC (rev 78679)
@@ -145,6 +145,7 @@
     zope.component.provideAdapter(button.ButtonActionHandler)
     # Error View(s)
     zope.component.provideAdapter(error.ErrorViewSnippet)
+    zope.component.provideAdapter(error.InvalidErrorViewSnippet)
     zope.component.provideAdapter(error.StandardErrorViewTemplate)
 
 def tearDown(test):

Modified: z3c.form/trunk/src/z3c/form/tests/simple_caredit.pt
===================================================================
--- z3c.form/trunk/src/z3c/form/tests/simple_caredit.pt	2007-08-07 21:07:40 UTC (rev 78678)
+++ z3c.form/trunk/src/z3c/form/tests/simple_caredit.pt	2007-08-08 03:21:31 UTC (rev 78679)
@@ -3,8 +3,10 @@
     <i tal:condition="view/status" tal:content="view/status" />
     <ul tal:condition="view/widgets/errors">
       <li tal:repeat="error view/widgets/errors">
-        <tal:block replace="error/widget/label"
-        />: <tal:block replace="structure error/render" />
+        <tal:block condition="error/widget">
+          <tal:block replace="error/widget/label" />:
+        </tal:block>
+        <tal:block replace="structure error/render" />
       </li>
     </ul>
     <form action=".">

Modified: z3c.form/trunk/src/z3c/form/tests/simple_edit.pt
===================================================================
--- z3c.form/trunk/src/z3c/form/tests/simple_edit.pt	2007-08-07 21:07:40 UTC (rev 78678)
+++ z3c.form/trunk/src/z3c/form/tests/simple_edit.pt	2007-08-08 03:21:31 UTC (rev 78679)
@@ -3,8 +3,10 @@
     <i tal:condition="view/status" tal:content="view/status" />
     <ul tal:condition="view/widgets/errors">
       <li tal:repeat="error view/widgets/errors">
-        <tal:block replace="error/widget/label"
-        />: <tal:block replace="structure error/render" />
+        <tal:block condition="error/widget">
+          <tal:block replace="error/widget/label" />:
+        </tal:block>
+        <tal:block replace="structure error/render" />
       </li>
     </ul>
     <form action=".">

Modified: z3c.form/trunk/src/z3c/form/tests/simple_groupedit.pt
===================================================================
--- z3c.form/trunk/src/z3c/form/tests/simple_groupedit.pt	2007-08-07 21:07:40 UTC (rev 78678)
+++ z3c.form/trunk/src/z3c/form/tests/simple_groupedit.pt	2007-08-08 03:21:31 UTC (rev 78679)
@@ -4,8 +4,10 @@
     <ul tal:condition="view/widgets/errors"
         metal:define-macro="errors">
       <li tal:repeat="error view/widgets/errors">
-        <tal:block replace="error/widget/label"
-        />: <tal:block replace="structure error/render" />
+        <tal:block condition="error/widget">
+          <tal:block replace="error/widget/label" />:
+        </tal:block>
+        <tal:block replace="structure error/render" />
       </li>
     </ul>
     <form action=".">

Modified: z3c.form/trunk/src/z3c/form/tests/simple_owneredit.pt
===================================================================
--- z3c.form/trunk/src/z3c/form/tests/simple_owneredit.pt	2007-08-07 21:07:40 UTC (rev 78678)
+++ z3c.form/trunk/src/z3c/form/tests/simple_owneredit.pt	2007-08-08 03:21:31 UTC (rev 78679)
@@ -1,8 +1,10 @@
 <i tal:condition="view/status" tal:content="view/status" />
 <ul tal:condition="view/widgets/errors">
   <li tal:repeat="error view/widgets/errors">
-    <tal:block replace="error/widget/label"
-    />: <tal:block replace="structure error/render" />
+    <tal:block condition="error/widget">
+      <tal:block replace="error/widget/label" />:
+    </tal:block>
+    <tal:block replace="structure error/render" />
   </li>
 </ul>
 <div class="row" tal:repeat="widget view/widgets/values">

Modified: z3c.form/trunk/src/z3c/form/tests/simple_subedit.pt
===================================================================
--- z3c.form/trunk/src/z3c/form/tests/simple_subedit.pt	2007-08-07 21:07:40 UTC (rev 78678)
+++ z3c.form/trunk/src/z3c/form/tests/simple_subedit.pt	2007-08-08 03:21:31 UTC (rev 78679)
@@ -1,8 +1,10 @@
 <i tal:condition="view/status" tal:content="view/status" />
 <ul tal:condition="view/widgets/errors">
   <li tal:repeat="error view/widgets/errors">
-    <tal:block replace="error/widget/label"
-    />: <tal:block replace="structure error/render" />
+    <tal:block condition="error/widget">
+      <tal:block replace="error/widget/label" />:
+    </tal:block>
+    <tal:block replace="structure error/render" />
   </li>
 </ul>
 <div class="row" tal:repeat="widget view/widgets/values">

Modified: z3c.form/trunk/src/z3c/form/validator.txt
===================================================================
--- z3c.form/trunk/src/z3c/form/validator.txt	2007-08-07 21:07:40 UTC (rev 78678)
+++ z3c.form/trunk/src/z3c/form/validator.txt	2007-08-08 03:21:31 UTC (rev 78679)
@@ -257,7 +257,7 @@
   ...     CustomValidator, schema=util.getSpecification(IPerson, force=True))
 
 Note: Of course we could have used the ``zope.component.adapts()`` function
-      from within the class, but I think it is too tediuos, since you have to
+      from within the class, but I think it is too tedious, since you have to
       specify all discriminators and not only the specific ones you are
       interested in.
 



More information about the Checkins mailing list