[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