[PEAK] Using attribute bindings within constructor when
using Component Factories
Phillip J. Eby
pje at telecommunity.com
Sat Jan 17 20:30:43 EST 2004
At 06:43 PM 1/17/04 -0600, Wayne Larsen wrote:
>Hi,
>
>I've been learning PEAK by 'peakifying' an existing app. I really like
>what I've seen so far. However, I believe I've encountered a bug -- if it
>isn't, can you tell me where I went wrong? The problem is - when using
>the Component Factories method of initialization, accessing an attribute
>binding from the constructor causes the following exception:
>
> File "/usr/lib/python2.3/site-packages/peak/config/interfaces.py", line
> 107, in noMoreValues
> raise exceptions.InvalidRoot(
>peak.exceptions.InvalidRoot: Root component <test1.TestService object at
>0x404f514c> does not implement 'IConfigurationRoot' (was looking up
>peak.naming.initialContextFactory for <test1.TestService object at 0x404f514c>)
Components are designed to be able to "snap together" at
runtime. Sometimes, you create a parent component, then create a child
component already knowing its parent component. Other times, you create
the child first, and thus can't give it a parent right away.
The [Component Factories] aspect of PEAK is only *one* example of the
latter scenario. There are many, many places where PEAK will create a
child component first, then find out the parent later. For example,
loading components from a ZConfig file currently works that way.
So, the issue here is that when a component is constructed, it may not know
its parent yet. In your example code, you tried to look up a log object
that needed to access configuration data. The component didn't have a
parent yet, and didn't supply the needed configuration data, so you got an
error instead.
To make a long story short: don't override the binding.Component
constructor, unless you really really need to, and you're sure that either
1) your new constructor won't cause any lookups that require a parent, or
2) the constructor will always be given a parent. And note that item #2
will *NOT* be guaranteed by any part of PEAK itself. If there is a part of
PEAK today that happens to invoke constructors with a parent, that's
entirely coincidental and should not be relied upon.
So, really, that boils down to "don't override the constructor unless
you're doing something that does no lookups", or just, "don't override the
constructor".
Instead, you should be using "assembly events". For example, if you wanted
your TestService to log a message as soon as it's "snapped into" the
application, you could add:
def __logStartup(self):
self.log.info(self.message)
__logStartup = binding.Make(__logStartup, uponAssembly=True)
Then, as soon as the service knows its parent (and the parent knows its
parent, and so on up to a "known root" component (a component that knows it
has no parents), the __logStartup method will be called. This is much
better than overriding the constructor, since you can access any attributes
and do any lookups with full access to your parent components.
More information about the PEAK
mailing list