[Zope3-checkins] SVN: zope.formlib/trunk/ `checkInvariants` now takes the context of the form into account when checking interface invariants.

Michael Howitz cvs-admin at zope.org
Thu Mar 15 07:59:30 UTC 2012


Log message for revision 124594:
  `checkInvariants` now takes the context of the form into account when checking interface invariants.
  

Changed:
  U   zope.formlib/trunk/CHANGES.txt
  U   zope.formlib/trunk/setup.py
  U   zope.formlib/trunk/src/zope/formlib/form.py
  U   zope.formlib/trunk/src/zope/formlib/form.txt
  U   zope.formlib/trunk/src/zope/formlib/tests/test_formlib.py

-=-
Modified: zope.formlib/trunk/CHANGES.txt
===================================================================
--- zope.formlib/trunk/CHANGES.txt	2012-03-13 19:15:31 UTC (rev 124593)
+++ zope.formlib/trunk/CHANGES.txt	2012-03-15 07:59:25 UTC (rev 124594)
@@ -2,10 +2,13 @@
 Changes
 =======
 
-4.0.7 (unreleased)
+4.1.0 (unreleased)
 ==================
 
+- `checkInvariants` now takes the context of the form into account when
+  checking interface invariants.
 
+
 4.0.6 (2011-08-20)
 ==================
 

Modified: zope.formlib/trunk/setup.py
===================================================================
--- zope.formlib/trunk/setup.py	2012-03-13 19:15:31 UTC (rev 124593)
+++ zope.formlib/trunk/setup.py	2012-03-15 07:59:25 UTC (rev 124594)
@@ -24,7 +24,7 @@
 def read(*rnames):
     return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
 
-version = '4.0.7dev'
+version = '4.1.0dev'
 
 setup(name='zope.formlib',
       version=version,

Modified: zope.formlib/trunk/src/zope/formlib/form.py
===================================================================
--- zope.formlib/trunk/src/zope/formlib/form.py	2012-03-13 19:15:31 UTC (rev 124593)
+++ zope.formlib/trunk/src/zope/formlib/form.py	2012-03-15 07:59:25 UTC (rev 124594)
@@ -459,13 +459,15 @@
 
 class FormData:
 
-    def __init__(self, schema, data):
+    def __init__(self, schema, data, context):
         self._FormData_data___ = data
         self._FormData_schema___ = schema
+        self._FormData_context___ = context
 
     def __getattr__(self, name):
         schema = self._FormData_schema___
         data = self._FormData_data___
+        context = self._FormData_context___
         try:
             field = schema[name]
         except KeyError:
@@ -473,7 +475,21 @@
         else:
             value = data.get(name, data)
             if value is data:
-                raise NoInputData(name)
+                if context is None:
+                    raise NoInputData(name)
+                # The value is not in the form look it up on the context:
+                field = schema[name]
+                adapted_context = schema(context)
+                if IField.providedBy(field):
+                    value = field.get(adapted_context)
+                elif (zope.interface.interfaces.IAttribute.providedBy(field)
+                      and
+                      not zope.interface.interfaces.IMethod.providedBy(field)):
+                    # Fallback for non-field schema contents:
+                    value = getattr(adapted_context, name)
+                else:
+                    # Don't know how to extract value
+                    raise NoInputData(name)
             if zope.interface.interfaces.IMethod.providedBy(field):
                 if not IField.providedBy(field):
                     raise RuntimeError(
@@ -486,7 +502,7 @@
         raise AttributeError(name)
 
 
-def checkInvariants(form_fields, form_data):
+def checkInvariants(form_fields, form_data, context):
 
     # First, collect the data for the various schemas
     schema_data = {}
@@ -506,7 +522,7 @@
     errors = []
     for schema, data in schema_data.items():
         try:
-            schema.validateInvariants(FormData(schema, data), errors)
+            schema.validateInvariants(FormData(schema, data, context), errors)
         except interface.Invalid:
             pass # Just collect the errors
 
@@ -740,7 +756,7 @@
 
     def validate(self, action, data):
         return (getWidgetsData(self.widgets, self.prefix, data)
-                + checkInvariants(self.form_fields, data))
+                + checkInvariants(self.form_fields, data, self.context))
 
     template = namedtemplate.NamedTemplate('default')
 

Modified: zope.formlib/trunk/src/zope/formlib/form.txt
===================================================================
--- zope.formlib/trunk/src/zope/formlib/form.txt	2012-03-13 19:15:31 UTC (rev 124593)
+++ zope.formlib/trunk/src/zope/formlib/form.txt	2012-03-15 07:59:25 UTC (rev 124594)
@@ -227,7 +227,7 @@
     <input class="textType" id="form.max_size" name="form.max_size" size="10"
            type="text" value=""  />
     <span class="error">Required input is missing.</span>
-    <input class="textType" id="form.color" name="form.color" size="20" 
+    <input class="textType" id="form.color" name="form.color" size="20"
            type="text" value=""  />
     {'name': u'bob'}
 
@@ -288,8 +288,8 @@
     ...         if 'submit' in self.request:
     ...             data = {}
     ...             errors = form.getWidgetsData(widgets, 'form', data)
-    ...             invariant_errors = form.checkInvariants(self.form_fields,
-    ...                                                     data)
+    ...             invariant_errors = form.checkInvariants(
+    ...                 self.form_fields, data, self.context)
     ...             if errors:
     ...                 print 'There were field errors:'
     ...                 for error in errors:
@@ -504,8 +504,8 @@
     ...         if 'submit' in self.request:
     ...             data = {}
     ...             errors = form.getWidgetsData(widgets, 'form', data)
-    ...             invariant_errors = form.checkInvariants(self.form_fields,
-    ...                                                     data)
+    ...             invariant_errors = form.checkInvariants(
+    ...                 self.form_fields, data, self.context)
     ...             if errors:
     ...                 print 'There were field errors:'
     ...                 for error in errors:
@@ -698,7 +698,8 @@
     ...
     ...     def validate(self, action, data):
     ...         return (form.getWidgetsData(self.widgets, self.prefix, data) +
-    ...                 form.checkInvariants(self.form_fields, data))
+    ...                 form.checkInvariants(
+    ...                     self.form_fields, data, self.context))
     ...
     ...     def handle_edit_action(self, action, data):
     ...         if form.applyChanges(self.context, self.form_fields, data):
@@ -1566,15 +1567,15 @@
     ...         super(MyAddForm, self).setUpWidgets(ignore_request)
 
     >>> print MyAddForm(None, request)() # doctest: +NORMALIZE_WHITESPACE
-    <input class="textType" id="form.identifier" name="form.identifier" 
+    <input class="textType" id="form.identifier" name="form.identifier"
            size="10" type="text" value=""  />
-    <input class="textType" id="form.name" name="form.name" size="20" 
+    <input class="textType" id="form.name" name="form.name" size="20"
            type="text" value=""  />
-    <input class="textType" id="form.min_size" name="form.min_size" 
+    <input class="textType" id="form.min_size" name="form.min_size"
            size="10" type="text" value=""  />
-    <input class="textType" id="form.max_size" name="form.max_size" 
+    <input class="textType" id="form.max_size" name="form.max_size"
            size="10" type="text" value=""  />
-    <input class="textType" id="form.now" name="form.now" size="20" 
+    <input class="textType" id="form.now" name="form.now" size="20"
            type="text" value="2002-12-02 12:30:00"  />
 
 Note that a EditForm can't make use of a get_rendered method. The get_rendered
@@ -1801,7 +1802,7 @@
   <input class="textType" id="form.title" name="form.title"
          size="20" type="text" value="" />
 
-  >>> form.checkInvariants(form_fields, {'title': 'new'})
+  >>> form.checkInvariants(form_fields, {'title': 'new'}, blah)
   []
 
   >>> form.applyChanges(blah, form_fields, {'title': 'new'})

Modified: zope.formlib/trunk/src/zope/formlib/tests/test_formlib.py
===================================================================
--- zope.formlib/trunk/src/zope/formlib/tests/test_formlib.py	2012-03-13 19:15:31 UTC (rev 124593)
+++ zope.formlib/trunk/src/zope/formlib/tests/test_formlib.py	2012-03-15 07:59:25 UTC (rev 124594)
@@ -630,6 +630,87 @@
 """
 
 
+def checkInvariants_falls_back_to_context_if_value_not_in_form():
+    """
+`checkInvariants` is able to access the values from the form and the context to
+make sure invariants are not violated:
+
+    >>> class IFlexMaximum(zope.interface.Interface):
+    ...     max = zope.schema.Int(title=u"Maximum")
+    ...     value = zope.schema.Int(title=u"Value")
+    ...
+    ...     @zope.interface.invariant
+    ...     def value_not_bigger_than_max(data):
+    ...         if data.value > data.max:
+    ...             raise zope.interface.Invalid('value bigger than max')
+
+    >>> class Content(object):
+    ...     zope.interface.implements(IFlexMaximum)
+    ...     max = 10
+    ...     value = 7
+
+    >>> class ValueEditForm(zope.formlib.form.EditForm):
+    ...     form_fields = zope.formlib.form.FormFields(
+    ...         IFlexMaximum).omit('max')
+
+If the value entered in the example form is bigger than the maximum the
+interface invariant triggers an error:
+
+    >>> from zope.publisher.browser import TestRequest
+    >>> request = TestRequest(
+    ...     form={'form.value': 42, 'form.actions.apply': '1'})
+    >>> form = ValueEditForm(Content(), request)
+    >>> form.update()
+    >>> form.errors
+    (Invalid('value bigger than max',),)
+
+If the value is below the maximum no error occures:
+
+    >>> request = TestRequest(
+    ...     form={'form.value': 8, 'form.actions.apply': '1'})
+    >>> form = ValueEditForm(Content(), request)
+    >>> form.update()
+    >>> form.errors
+    ()
+"""
+
+
+def FormData___getattr___handles_zope_interrface_attributes_correctly():
+    """
+`FormData.__getattr__` reads objects defined as zope.interface.Attribute in
+interface correctly from context:
+
+    >>> class IStaticMaximum(zope.interface.Interface):
+    ...     max = zope.interface.Attribute("Predefined maximum")
+
+    >>> class Content(object):
+    ...     zope.interface.implements(IStaticMaximum)
+    ...     max = 10
+
+    >>> formdata = zope.formlib.form.FormData(IStaticMaximum, {}, Content())
+    >>> formdata.max
+    10
+"""
+
+
+def FormData___getattr___raises_exception_if_unknown_how_to_access_value():
+    """
+`FormData.__getattr__` raises an exception if it cannot determine how to
+read the object from context:
+
+    >>> class IStaticMaximum(zope.interface.Interface):
+    ...     def max(): pass
+
+    >>> class Content(object):
+    ...     zope.interface.implements(IStaticMaximum)
+
+    >>> formdata = zope.formlib.form.FormData(IStaticMaximum, {}, Content())
+    >>> formdata.max
+    Traceback (most recent call last):
+    NoInputData: max
+"""
+
+
 def test_suite():
     import doctest
     checker = zope.testing.renormalizing.RENormalizing([



More information about the Zope3-Checkins mailing list