[Zope3-dev] Re: Field binding considered icky

Philipp von Weitershausen philipp at weitershausen.de
Thu Apr 1 03:37:14 EST 2004


Jim,

I'm not going to reason with you why field binding is supposed to be 
considered icky. Field binding is a simple process that I'm sure every 
python developer using Zope3 will understand. Though I even sympathize 
with your finding it icky, I wonder whether it's a good idea to 
complicate things to an unnecessary extend.

Anyway, nothing we couldn't do with adapters, eh? Here are my comments:

> 2. We may need to consider object identity, or a current object value.
> 
>    To illustrate this, consider a bumper car ride.  We have a system
>    that let's us assign bumper cars to riders.  Clearly we should only
>    assign unoccupied bumper cars.  But suppose that someone is already
>    in a bumper car.  In that case, the car they are sitting in should
>    be a valid choice for them, even though it is occupied.  To properly
>    validate, or to generate a correct UI, we need to take into account
>    the identity of the rider we're pickling a bumper car for.
> 
> 3. Perhaps there are other cases where we want to take context into
>    account for some reason.  Perhaps allowable values for a field
>    depend on data acquired from a folder.  This is hypothetical, but
>    people I trust have told me that this is likely.

While I think this particular case is yagni, I would definitely not rule 
out the possibility of having a vocabulary field highly depend on the 
context or even the exact location.

> Here's a possible approach I wanted to run by y'all: use adapters. :)

I already see it before me, the Zope3 canon:

Everything can be adapted.
Everything is a utility.
Explicit is better than implicit.
Except when it's not.

> A. Validating values
> 
>    We would get rid of the validate method of fields.
> 
>    When we want to validate a field, we'll adapt it *with* it's
>    context:
> 
>      >>> validator = getMultiAdapter((field, context), IValidator)
>      >>> validator.validate(value)
> 
>    So, in the bumper car example, when editing a rider, we'd:
> 
>      >>> validator = getMultiAdapter((field, rider), IValidator)
> 
>    But, when adding a rider, we'd use an adding object as the context::
> 
>      >>> validator = getMultiAdapter((field, adding), IValidator)
> 
>    Now, we might not have an adapter for IAdding, but we might have a
>    default adapter (registered for IBumperCarField and Interface) that
>    allows only unoccupied bumper cars.
> 
>    A disadvantage of this approach is that it will require either
>    that:
> 
>    - We remove validation logic from zope.schema, or

Well, we are really only talking about field types that depend on a 
context. I think we can draw a line quite easily between field types 
that could validate on their own (Int, Bool, TextLine, etc.) and those 
that can't (I can only think of VocabularyField). OTOH, maybe we don't 
need to draw the line and simply have Int, Bool, TextLine etc. implement 
IValidator and thus the adaption return the field itself. Yes, I would 
like that.

>    - Introduce a dependency of zope.schema on zope.component.  Later,
>      if we merge zope.schema into zope.interface, we'd introduce a
>      dependency of zope.interface on zope.component.

Alas, I consider the adapter machinery so crucial to component and 
interface-based Python apps that I would even go a step further and say: 
the interface registry implementation already is in zope.interface, why 
not move the whole adaption machinery there? Or at least to a package 
called zope.adapter, which we might have less of a problem to depend on 
than on zope.component.

> B. Widgets
> 
>    Widgets would become multi-views:
> 
>      >>> widget = getMultiView((field, context), '', request, IInputWidget)
> 
>    So, in the bumper car example, when editing a rider, we'd use:
> 
>      >>> widget = getMultiView((field, rider), '', request, IInputWidget)
> 
>    But, when adding a rider, we'd use an adding object as the context::
> 
>      >>> widget = getMultiView((field, adding), '', request, IInputWidget)

+1
I like the notion of widgets not only being a view on a field.

> an alternative to B:
> 
> B'. Rather than using multi-views, use views of multi-adapters:
> 
>     >>> widget = getViewProviding(
>     ...             getMultiAdapter((field, context), someinterface),
>     ...             request, IInputWidget,
>     ...             )
> 
>     The idea is that the widget need not know about context. Any knowledge
>     of the context is restricted to the adapter.  I think that this
>     has some appeal, but I don't know that I want to require it.
> 
>     I don't like this option because:
> 
>     - It's not clear what `someinterface` should be.  It was suggested
>       that it should be `IField`, but `IField` doesn't really provide
>       enough information.

I guess, in consideration of the point below concerning the context, it 
could be something called IBoundField::

   class IBoundField(IField):
       context = Field(...)

Instead of binding::

   >>> bound_field = field.bind(context)
   >>> bound_field.context is context
   True

we would be adapting to IBoundField::

   >>> bound_field = getMultiAdapter((field, context), IBoundField)
   >>> bound_field.context is context
   True

Doesn't seem like difference to me. The adaption looks like a fancy 
binding. It's really only syntactic sugar with the difference that we 
depend on zope.component.

>     - It doesn't allow the widget to use the context directly, unless
>       `someinterface` exposes it somehow. IMO, it should be possible
>       for the widget implementation to depend on the context if it
>       wants to. If it doesn't want to, it can always get an adapter
>       itself and forget about context.

I'm with you on this. Here's a use case for a widget explicitly wanting 
to have access to the context:

I imagine a widget for Text (or some other field) embedding the Kupu 
wysiwyg editor (http://kupu.oscom.org). As a document centric editor, it 
can handle document metadata, so the widget might actually want to get a 
DublinCore adapter for the context and send that along with the field 
contents to Kupu. Viceversa, when saving, we'd like to store the 
metadata back into the DublinCore adapter.

Philipp




More information about the Zope3-dev mailing list