[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