[TransWarp] Finding an object that provides the interface (was: Infinite recursion computing a binded attribute)

Phillip J. Eby pje at telecommunity.com
Wed May 21 12:34:15 EDT 2003

At 08:02 PM 5/21/03 +0400, Oleg Broytmann wrote:
>On Tue, May 20, 2003 at 12:05:50PM -0400, Phillip J. Eby wrote:
> >
> > >components = "ui", "httpd"
> > >component.ui = "ank.MedapE.UiServer.HtmlServer.HtmlServer"
> > >component.httpd = "ank.MedapE.UiFrontend.BaseHTTPD.BaseHTTPD"
> >
> > I don't understand what this part above does.
>    There is a component loader, which inports and initialize classes
>according to the app.components list and app.component.* classes.


>    Yes, I got it. And I found the reason. There are two instances of (some
>of) my components. One instance was created by the component loader
>mentioned above. These instances were provided with correct parentComponent
>and hence they can acquire .log and other attributes. Other, "wrong"
>instances were created by binfingTo. For example:
>class ScenarioServer(Runnable.Runnable):
>     protocols.advise(instancesProvide=[interfaces.IScenarioServer])
>class HtmlServer(ThreadRunnable.ThreadRunnable):
>     protocols.advise(instancesProvide=[interfaces.IUiServer])
>     # link to ScenarioServer
>     s_server = binding.Once(
>         lambda s, d, a: config.findUtility(s, interfaces.IScenarioServer),
>         doc="Main application server (ScenarioServer)")

Note that the above can be replaced with:

     s_server = binding.bindTo(interfaces.IScenarioServer)

as Zope and PEAK interfaces are both usable as IComponentKeys.

>    In the HtmlServer instances first reference to self.s_server created new
>ScenarioServer instance (due to [Provide Utilities]) with wrong
>parentComponent - peak.config.config_components.ConfigurationRoot instead
>of my application object.

Right; this is why in my previous e-mail I suggested you load such 
application-specific objects from a configuration file directly into your 
app object, rather than into the configuration root.

>    Why findUtility does not find already created instance of

Probably because you didn't register it using registerProvider.  When you 
use attribute bindings with a 'provides' keyword, or use [Provide 
Utilities], a provider is registered with the class or instance for you 

Please note that declaring that an object implements an interface has 
nothing to do with whether you are publishing that instance as a provider 
of the interface.  For example, I may have many components that implement 
ISQLConnection, but that doesn't mean I want to publish them to my 
subcomponents as the ISQLConnection I want them to use.

>    Initially (as I have said some emails ago) the classes was declared as
>class ScenarioServer(Runnable.Runnable):
>     __implements__ = interfaces.IScenarioServer

PEAK does not register providers or find utilities on the basis of what an 
object implements.  You could in fact register the number "42" as a utility 
that provides IScenarioServer, and PEAK would accept it.  Publication of a 
utility must occur explicitly, through Provide Utilities, via the 
provides() keyword, or the registerProvider() method.

Given this confusion, I'm strongly considering renaming the 'provides' 
keyword and 'registerProvider()' method in alpha 3, perhaps to something 
like 'publishAs' and 'publishProvider()'.  Now that the protocols package 
talks about "providing" interfaces, it seems easy to confuse this with a 
component "providing" a utility or properties to its children.  So maybe 
the terminology should change to a component "publishing" utilities and 
properties, as that is a very different thing.

More information about the PEAK mailing list