[Checkins] SVN: megrok.z3cform.base/trunk/ added decorators for validator, invariant, default

Christian Klinger cklinger at novareto.de
Mon Mar 22 09:56:42 EDT 2010


Log message for revision 110108:
  added decorators for validator, invariant, default

Changed:
  U   megrok.z3cform.base/trunk/buildout.cfg
  U   megrok.z3cform.base/trunk/docs/HISTORY.txt
  U   megrok.z3cform.base/trunk/setup.py
  U   megrok.z3cform.base/trunk/src/megrok/z3cform/base/__init__.py
  A   megrok.z3cform.base/trunk/src/megrok/z3cform/base/declarations.py
  U   megrok.z3cform.base/trunk/src/megrok/z3cform/base/meta.py
  A   megrok.z3cform.base/trunk/src/megrok/z3cform/base/tests/test_declarations.py

-=-
Modified: megrok.z3cform.base/trunk/buildout.cfg
===================================================================
--- megrok.z3cform.base/trunk/buildout.cfg	2010-03-22 05:32:44 UTC (rev 110107)
+++ megrok.z3cform.base/trunk/buildout.cfg	2010-03-22 13:56:41 UTC (rev 110108)
@@ -1,7 +1,7 @@
 [buildout]
 develop = .
 parts = test releaser
-extends = http://grok.zope.org/releaseinfo/grok-1.1a1.cfg
+extends = http://grok.zope.org/releaseinfo/grok-1.1rc1.cfg
 versions = versions
 newest = false
 

Modified: megrok.z3cform.base/trunk/docs/HISTORY.txt
===================================================================
--- megrok.z3cform.base/trunk/docs/HISTORY.txt	2010-03-22 05:32:44 UTC (rev 110107)
+++ megrok.z3cform.base/trunk/docs/HISTORY.txt	2010-03-22 13:56:41 UTC (rev 110108)
@@ -4,7 +4,8 @@
 0.4 (unreleased)
 ----------------
 
-* ...
+* Added decorators for validator, invariant and default_value.
+  The idea of these decoraters is from plone.directives.form.
 
 
 0.3 (2010-02-11)

Modified: megrok.z3cform.base/trunk/setup.py
===================================================================
--- megrok.z3cform.base/trunk/setup.py	2010-03-22 05:32:44 UTC (rev 110107)
+++ megrok.z3cform.base/trunk/setup.py	2010-03-22 13:56:41 UTC (rev 110108)
@@ -17,7 +17,7 @@
     'megrok.pagetemplate >= 0.3',
     ]
 
-test_requires = install_requires + ['grok >= 1.0',]
+test_requires = install_requires + ['grok >= 1.0', 'zope.app.testing']
 
 setup(name=name,
       version=version,

Modified: megrok.z3cform.base/trunk/src/megrok/z3cform/base/__init__.py
===================================================================
--- megrok.z3cform.base/trunk/src/megrok/z3cform/base/__init__.py	2010-03-22 05:32:44 UTC (rev 110107)
+++ megrok.z3cform.base/trunk/src/megrok/z3cform/base/__init__.py	2010-03-22 13:56:41 UTC (rev 110108)
@@ -13,3 +13,4 @@
 from components import *
 from interfaces import IGrokForm, ICancelButton
 from utils import apply_data_event, notify_changes, set_fields_data
+from declarations import validator, invariant, default_value

Added: megrok.z3cform.base/trunk/src/megrok/z3cform/base/declarations.py
===================================================================
--- megrok.z3cform.base/trunk/src/megrok/z3cform/base/declarations.py	                        (rev 0)
+++ megrok.z3cform.base/trunk/src/megrok/z3cform/base/declarations.py	2010-03-22 13:56:41 UTC (rev 110108)
@@ -0,0 +1,144 @@
+# -*- coding: utf-8 -*-
+
+import sys
+
+from zope.interface import implementer
+from z3c.form.validator import InvariantsValidator
+from z3c.form.widget import ComputedWidgetAttribute
+from z3c.form.validator import SimpleFieldValidator
+from z3c.form.validator import WidgetValidatorDiscriminators
+from z3c.form.interfaces import IValidator, IManagerValidator
+from z3c.form.validator import WidgetsValidatorDiscriminators
+
+
+class DecoratedInvariantsValidator(InvariantsValidator):
+    """ Decorator for Invariants"""
+
+    def __init__(self, fn, context, request, view, schema, manager):
+        super(DecoratedInvariantsValidator, self).__init__(
+                              context, request, view, schema, manager)
+        self.fn = fn
+
+    def validateObject(self, obj):
+        errors = super(DecoratedInvariantsValidator, self).validateObject(obj)
+        error = self.fn(obj)
+        if error:
+            errors += error
+        return errors
+
+
+class invariant(object):
+    """Decorator for functions to be registered as validator for invairants
+    """
+
+    def __init__(self, **kw):
+        self.discriminators = kw
+
+    def __call__(self, fn):
+
+        @implementer(IManagerValidator)
+        def factory(context, request, view, schema, manager):
+            return DecoratedInvariantsValidator(
+                        fn, context, request, view, schema, manager)
+
+        WidgetsValidatorDiscriminators(factory, **self.discriminators)
+
+        frame = sys._getframe(1)
+        adapters = frame.f_locals.get('__form_validator_adapters__', None)
+        if adapters is None:
+            frame.f_locals['__form_validator_adapters__'] = adapters = []
+        adapters.append(factory)
+
+        return fn
+
+
+class DecoratedValidator(SimpleFieldValidator):
+
+    def __init__(self, fn, context, request, view, field, widget):
+        super(DecoratedValidator, self).__init__(
+                           context, request, view, field, widget)
+        self.fn = fn
+
+    def validate(self, value):
+        super(DecoratedValidator, self).validate(value)
+        self.fn(value)
+
+
+class validator(object):
+    """Decorator for functions to be registered as validators
+    """
+
+    def __init__(self, **kw):
+        self.discriminators = kw
+
+    def __call__(self, fn):
+
+        @implementer(IValidator)
+        def factory(context, request, view, field, widget):
+            return DecoratedValidator(
+                fn, context, request, view, field, widget)
+
+        WidgetValidatorDiscriminators(factory, **self.discriminators)
+
+        frame = sys._getframe(1)
+        adapters = frame.f_locals.get('__form_validator_adapters__', None)
+        if adapters is None:
+            frame.f_locals['__form_validator_adapters__'] = adapters = []
+        adapters.append(factory)
+
+        return fn
+
+
+class _computed_value(object):
+    """Decorator for things using z3c.form.value IValue creators.
+    """
+
+    # should be set by subclass
+    factory = None
+
+    def __init__(self, name, **kw):
+        self.name = name
+        self.discriminators = kw
+
+    def __call__(self, ob):
+
+        try:
+            value_adapter = (self.factory(ob, **self.discriminators), self.name)
+        except ValueError, e:
+            raise ValueError(u"Error constructing value adapter for %s: %s" % (str(ob), str(e)))
+
+        frame = sys._getframe(1)
+        adapters = frame.f_locals.get('__form_value_adapters__', None)
+        if adapters is None:
+            frame.f_locals['__form_value_adapters__'] = adapters = []
+        adapters.append(value_adapter)
+return ob
+
+
+class default_value(_computed_value):
+    """Decorator for functions providing a default field value when rendering the form
+    """
+
+    factory = ComputedWidgetAttribute
+
+    def __init__(self, context=None, request=None, view=None, field=None, widget=None, form=None, layer=None):
+        if not field and not widget:
+            raise TypeError(u"Either 'field' or 'widget' must be specified")
+
+        if form and view:
+            raise TypeError(u"You cannot specify both 'view' and 'form' - one is an alias for the other")
+        elif form and not view:
+            view = form
+
+        if request and layer:
+            raise TypeError(u"You cannot specify both 'request' and 'layer' - one is an alias for the other")
+        elif layer and not request:
+            request = layer
+
+        super(default_value, self).__init__('default',
+                context=context,
+                request=request,
+                view=view,
+                field=field,
+                widget=widget,
+            )

Modified: megrok.z3cform.base/trunk/src/megrok/z3cform/base/meta.py
===================================================================
--- megrok.z3cform.base/trunk/src/megrok/z3cform/base/meta.py	2010-03-22 05:32:44 UTC (rev 110107)
+++ megrok.z3cform.base/trunk/src/megrok/z3cform/base/meta.py	2010-03-22 13:56:41 UTC (rev 110108)
@@ -7,6 +7,7 @@
 from z3c.form import field
 from martian.error import GrokError
 from zope.interface import Interface
+from zope.component.zcml import adapter
 from megrok.z3cform.base import directives
 from megrok.z3cform.base import components
 from zope.interface.interfaces import IInterface
@@ -15,7 +16,6 @@
 from grokcore.formlib.formlib import most_specialized_interfaces
 from zope.publisher.interfaces.browser import IDefaultBrowserLayer
 
-
 def get_auto_fields(context):
     """Get the form fields for context.
     This methods is the same than for formlib implementation, but use
@@ -72,3 +72,27 @@
         widgetTemplateDirective(config, template, context, layer,
                     view=view, field=field, widget=widget, mode=mode)
         return True
+
+
+class ValidatorAdapterGrokker(martian.GlobalGrokker):
+    
+    def grok(self, name, module, module_info, config, **kw):
+        # context = grokcore.component.context.bind().get(module=module)
+        adapters = module_info.getAnnotation('form.validator_adapters', [])
+        for factory in adapters:
+            adapter(config, factory=(factory,),
+            )
+        return True
+
+class ValueAdapterGrokker(martian.GlobalGrokker):
+    
+    def grok(self, name, module, module_info, config, **kw):
+        # context = grokcore.component.context.bind().get(module=module)
+        adapters = module_info.getAnnotation('form.value_adapters', [])
+        for factory, name in adapters:
+            adapter(config,
+                factory=(factory,),
+                name=name
+            )
+        return True
+

Added: megrok.z3cform.base/trunk/src/megrok/z3cform/base/tests/test_declarations.py
===================================================================
--- megrok.z3cform.base/trunk/src/megrok/z3cform/base/tests/test_declarations.py	                        (rev 0)
+++ megrok.z3cform.base/trunk/src/megrok/z3cform/base/tests/test_declarations.py	2010-03-22 13:56:41 UTC (rev 110108)
@@ -0,0 +1,107 @@
+"""
+  >>> from zope import component
+  >>> from zope.interface import alsoProvides
+  >>> from zope.publisher.browser import TestRequest
+
+  >>> otto = Mammoth()
+
+Check that fields have been created on the edition page:
+
+  >>> request = TestRequest(form={'form.widgets.name': u'Karl'})
+  >>> view = component.getMultiAdapter((otto, request), name='myform')
+  >>> view.updateForm()
+  >>> data, errors = view.extractData()
+  >>> len(errors) is 1
+  True
+
+  >>> errors[0].error.args[0]
+  u"Otto's name is otto"
+
+  >>> request = TestRequest(form={'form.widgets.name': u'otto',})
+  >>> view = component.getMultiAdapter((otto, request), name='myform')
+  >>> view.updateForm()
+  >>> data, errors = view.extractData()
+  >>> len(errors) is 0
+  True
+
+  >>> request = TestRequest(form={'form.widgets.name': u'otto', 'form.widgets.age': '34'})
+  >>> view = component.getMultiAdapter((otto, request), name='myform')
+  >>> view.updateForm()
+  >>> data, errors = view.extractData()
+  >>> len(errors) is 1
+  True
+
+  >>> print errors[0].render()
+  <div class="error">Otto is not 20.</div>
+
+
+  >>> request = TestRequest()
+  >>> view = component.getMultiAdapter((otto, request), name='contextless')
+  >>> view.updateForm()
+  >>> print view.render()
+  <form...
+       <input id="form-widgets-age" name="form.widgets.age"
+              class="text-widget int-field" value="5"
+              type="text" />
+  ...
+  </form>
+"""
+import grokcore.component as grok
+
+from z3c.form import util
+from zope.interface import Invalid
+from zope import interface, schema
+from megrok.z3cform.base import Form, validator, invariant, default_value
+from zope.schema.fieldproperty import FieldProperty
+
+
+class IMammoth(interface.Interface):
+    name = schema.TextLine(
+        title=u"Name",
+        required=False
+        )
+
+    age = schema.Int(
+        title=u"Age",
+        required=False,
+        )
+
+
+ at validator(field=IMammoth['name'])
+def validate_name(value):
+    if value != 'otto':
+        raise schema.ValidationError(u"Otto's name is otto")
+
+
+ at invariant(schema=util.getSpecification(IMammoth, force=True))
+def validate_invariant(obj):
+    if obj.age > 20:
+        return (Invalid('Otto is not 20.'),)
+
+
+ at default_value(field=IMammoth['age'])
+def get_default(data):
+    return 5 
+
+
+class Mammoth(grok.Context):
+    interface.implements(IMammoth)
+
+    name = FieldProperty(IMammoth['name'])
+    age = FieldProperty(IMammoth['age'])
+
+
+class MyForm(Form):
+    pass
+
+
+class ContextLess(Form):
+    ignoreContext = True
+
+def test_suite():
+    from zope.testing import doctest
+    from megrok.z3cform.base.tests import FunctionalLayer
+    suite = doctest.DocTestSuite(optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS)
+    suite.layer = FunctionalLayer
+    return suite
+



More information about the checkins mailing list