[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.
Okay.
> 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
>ScenarioServer?
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
automatically.
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