[Zope3-dev] My Experiences using Interface invariants with Formlib

Gary Poster gary at zope.com
Mon Jan 30 10:33:18 EST 2006


On Jan 30, 2006, at 3:21 AM, Michael Howitz wrote:

> Hi, as suggested in #zope3-dev I'll post my experiences with interface
> invariants and formlib here.
>
> I have an interface with two password fields which should be equal:
>
> class IUser(Interface):
>     password=zope.schema.Password(title=u"password")
>     password2=zope.schema.Password(title=u"password again")
>
> # this Exception is raised when password are not equal
> class PasswordsAreNotEqual(zope.schema.ValidationError):
>     u"""Passwords are not equal."""
>     # the docstring is shown in UI becuase it is a ValidationError
>     implements(zope.app.form.interfaces.IWidgetInputError)
>     # see below why
>
> # this function tests equality
> def arePasswordsEqual(obj)
>     if obj.password != obj.password2:
>         raise PasswordsAreNotEqual
>
> # set the test function as invariant
> IUser.setTaggedValue('invariants': [arePasswordsEqual])

You may already be aware of this and rejecting it for religious  
reasons, but it is arguably easier to do this by defining it in the  
interface, either with an "@invariant" or "arePasswordsEqual =  
invariant(arePasswordsEqual)" (invariant as imported from  
zope.interface and defined in  zope.interface.interface).

> Formlib expects Errors raised by invariants to be subclasses from
> zope.interface.Invalid (which zope.schema.ValidationError is).

That constraint is actually defined in zope.interface, fwiw.

> To dislay the error formlib tries to get a multi adapter which  
> provides
> zope.app.form.browser.interfaces.IWidgetInputErrorView. There is only
> one such adapter in Zope3

Yes; generally, we define our own views.

> (zope.app.form.browser.exception.WidgetInputErrorView) because it  
> seems
> that all other errors in FormBase's self.errors are implementing
> zope.app.form.interfaces.IWidgetInputError or even they are  
> instances of
> zope.app.form.interfaces.WidgetInputError. (Did not try.)
>
> So I implemented zope.app.form.interfaces.IWidgetInputError in my  
> error
> class. (Which really implements this interface because the only method
> the interface provides (doc) is implemented by
> zope.schema.ValidationError.
>
> If the exception has an attribute widget_title (which is not in the
> interface zope.app.form.interfaces.IWidgetInputError but only in the
> class zope.app.form.interfaces.WidgetInputError) then the value of  
> this
> attribute is displayed in front of the error message separted by a
> colon.

That's arguably a bit of a hack: these aren't widget errors.  But  
it's a reasonable prototype decision.

> The error message is only displayed on the top of the form. Maybe  
> there
> is also a way to get the error message displayed under a widget.

Not currently; the exception would have to have some data to help  
this.  We don't do this, and formlib doesn't help with it, but it  
would be a nice option.

> Is this the way it should be done?

As above.

Gary


More information about the Zope3-dev mailing list