[Zope3-dev] Context and Component Lookup II

Jim Fulton jim at zope.com
Thu Aug 7 12:34:59 EDT 2003


This is an update to the earlier proposal, "Context and Component
Lookup" in response to Phillip Eby's remarks. Thanks Phillip.

Summary:

   I propose the component architecture API be modified so that all
   component-lookup calls have an optional "context" keyword argument.
   When a context is provided, it will control how components are
   looked up.  When we get a context, we will adapt it to
   IServiceService, and use the resulting object to get the needed
   service.

   If no context is passed to a component-lookup function, then an
   application-defined strategy will be used.  The default strategy is
   to use the global service manager. In Zope, the site containing the
   published object will be used.

   Whether or not a context is passed to a component-lookup routine
   will depend on whether the calling code is particular about where
   components come from. In many cases, we don't care where a component
   comes from as long as it satisfies a specified interface.  If
   calling code *does* care, then it must explcitly provide an
   appropriate context.

   Zope will provide an adapter from IContained to IServiceService to
   support explicit location-based component lookup. IContained is an
   interface implemented by components that track location in a
   containment hierarchy.

Updated proposal

This is, essentially a proposal. It is here, rather than the Wiki due
to the birthing pains of new zope.org. :)

As things stand now, component lookup is based on location. For
example, suppose we have two sites, S1 and S11. S11 is a subsite of
S1, which is a subsite of the root folder, which is also typically a
site.  Now, suppose we have object O in site S11.  If we look up an
adapter for O:

   a = getAdapter(O, IFoo)

we'll look for an adapter factory in S11, then in S1, then in the root
site, and finally in the global adapter service.  This is all well and
good, I think. Note that to do this, we use contextual information for
O. For example, now, we use the context wrapper around O to figure out
where it is. In the future we might use a __container__ attribute of
O.

Now, supposer we access a subobject of O, O.x. Further, suppose
we don't have context information for O.x:

   x = O.x
   a = getAdapter(x, IBar)

Now, because x doesn't have any context information, we'll only look
in the global adapter service.  This is likely to lead to unpleasant
surprises if S1 or the root site defined an applicable adapter.

Now consider a slightly different case. Suppose we access a view of O
in S11 via a URL:

   http://eek.com/S1/x/y/S11/z//O/someview.html

So we have a request in S11. Now suppose that in that view, we access
object P from S1.  We use a view, V, of P in generating the output
(for the view of O in S11).  There are different definitions of this
view in S1 and S11. Which one should we use?  I'm inclined to think
that we should use the one from S11.

Now, suppose, from someview.html, we call a method on P.  Let's
supposer that P needs to look up a utility to provide IFoo.  Now,
imagine that S1 and S11 each provide a (separate) utility for IFoo.
Which one should we use.  I suggest that that depends on how flexible
P is.  P might be happy to use *any* utility as long as it implements
IFoo. It might even prefer to use the utility available in the place
where it's used, if possible.  On the other hand, P may have some
dependency on a particular utility or utility source.  If, for some
reason, it's important for P to be able to get a utility from a
particular place, there should be a way for it to do so.

In discussing the previous version of this proposal with Phillip Eby,
Phillip argued that code calling the component-lookup API should
control how components are looked up.  I'd prefer to say that code
calling component-lookup routines should be able to control
how components are looked up.

In summary, I'd like to address 2 issues:

- Code that has no context information cannot get at locally-defined
   components.

- Components that are designed to fit into whatever context they're
   used in have no convenient way to cause components they need to be
   lookup up in that context.

Proposed solution

   We will update the component-lookup APIs to always accept an
   optional "context" keyword argument.

   If no context is provided, then an application-defined lookup policy
   will be used. The default policy will be to use the global service
   manager.  The default Zope policy will be to use the (most specific)
   site containing the published object for a request.  This policy
   will, of course, be pluggable.

   If a context is provided (and is not None), it will be adapted to
   IServiceService, and the resulting service service will be used to
   look up the service to handler the lookup.  Zope will provide a
   default adapter from IContained that provides location-based
   lookup::

     class IContained(Interface):
         """Objects contained in containers
         """

         __container__ = Attribute("The container")

         __name__ = schema.TextLine(
             __doc__=
             """The name within the container

             The container can be traversed with this name to get the object.
             """)


Some examples:

1. getAdapter(X, I)

    Adapt X to I using an application-defined lookup strategy.
    Note that, by default, and in (future) Zope, X's location does not
    affect component lookup.

2. getAdapter(X, I, context=C)

    Adapt X to I using a lookup strategy determined by C.

3. getAdapter(X, I, context=self)

    Adapt X to I using a lookup strategy determined by self.
    This is essentially the same as 2. If self is some content object
    that implements IContained, then, in Zope, we'll look up the
    component in self's site.

4. getAdapter(X, I, context=globalServiceManager)

    Adapt X to I using an adapter found in the global service manager,
    bypassing any local customizations.

5. getUtility(I)

    Get a utility that provides I using an application-defined lookup
    strategy.  Note that we have changed the signature of getUtility so
    that it no longer accepts a positional context argument. The
    context is now optiona..

6. getUtility(I, context=C)

    Get a utility that provides I using a lookup strategy determined by C.

Thoughts?

Jim

-- 
Jim Fulton           mailto:jim at zope.com       Python Powered!
CTO                  (703) 361-1714            http://www.python.org
Zope Corporation     http://www.zope.com       http://www.zope.org




More information about the Zope3-dev mailing list