[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