[TransWarp] Infinite recursion computing a binded attribute
Phillip J. Eby
pje at telecommunity.com
Tue May 20 12:05:50 EDT 2003
At 05:49 PM 5/20/03 +0400, Oleg Broytmann wrote:
>Hello! I've got a problem. Infinite recursion. I think I am doing something
>wrong, but what?
>
> Let me briefly describe my hierarchy of classes:
>
>class Component(binding.Component):
> appname = binding.bindTo("appname")
> appver = binding.bindTo("appver")
> log = binding.bindTo("log")
Maybe I'm confused, but based on your config file, shouldn't this be
log = binding.bindToProperty("MedapE.log")
or:
log = binding.bindTo("config:MedapE.log/")
or:
log = binding.bindTo(PropertyName("MedapE.log"))
???
> Components are loaded from config file:
>
>[Provide Utilities]
>ank.MedapE.interfaces.IUiFrontend =
>config.provideInstance('ank.MedapE.UiFrontEnd.BaseHTTPD.BaseHTTPD')
>ank.MedapE.interfaces.IUiServer =
>config.provideInstance('ank.MedapE.UiServer.HtmlServer.HtmlServer')
>
>[MedapE]
>log = naming.lookup(targetObj, 'logfile:./MedapE.log?level=DEBUG')
By the way, if you use the "config:MedapE.log/" approach, the above can be:
log = naming.LinkRef('logfile:./MedapE.log?level=DEBUG')
>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.
>def run():
> _root = config.makeRoot(iniFiles=(("peak", "peak.ini"), "MedapE.cfg"))
> app = Application(parentComponent=_root)
> app.start()
>
> Boom!
>
>STARTDIR=./ank/MedapE PEAK_CONFIG=`pwd`/MedapE.cfg PYTHONPATH=. python
>-t ./ank/MedapE/app.py
>error: uncaptured python exception, closing channel
><ank.MedapE.UiFrontend.BaseHTTPD.BaseHTTPDServer listening localhost:8084
>at 0x869a534> (exceptions.RuntimeError:maximum recursion depth exceeded
>[/usr/local/lib/python2.2/asyncore.py|poll3|183]
>[/usr/local/lib/python2.2/asyncore.py|handle_read_event|390]
>[BaseHTTPD.py|handle_accept|73]
>[BaseHTTPD.py|__init__|42]
>[/usr/local/lib/python2.2/SocketServer.py|__init__|514]
>[/usr/local/lib/python2.2/BaseHTTPServer.py|handle|266]
>[BaseHTTPD.py|process_request|47]
>[BaseHTTPD.py|process_request|161]
>[HtmlServer.py|handle|118]
>
> There is just self.log.debug() in the line 118, but it seems peak cannot
>compute self.log. Very strange, because in BaseHTTPD self.log was accessed
>and used, no problems.
>
>[C:\cygwin\home\pje\PEAK\src/peak/binding/_once.pyx|_once.OnceDescriptor.__get__|119]
>
>[C:\cygwin\home\pje\PEAK\src/peak/binding/_once.pyx|_once.__get__|106]
>[/usr/local/lib/python2.2/site-packages/peak/binding/components.py|computeValue|438]
>
>[/usr/local/lib/python2.2/site-packages/peak/binding/components.py|lookupComponent|319]
>
>[/usr/local/lib/python2.2/site-packages/peak/binding/components.py|lookup|399]
>
>[/usr/local/lib/python2.2/site-packages/peak/binding/components.py|lookup|258]
>
>[/usr/local/lib/python2.2/site-packages/peak/binding/components.py|acquireComponent|189]
>
>[/usr/local/lib/python2.2/site-packages/peak/config/config_components.py|nameNotFound|407]
>
Right here, what we see is that the lookup for "log" passed off the top of
the component hierarchy. It was attempting to acquire a "log" attribute (I
presume) and none of that component's parents had such an attribute. It
then tried to do a lookup in the default naming context, and that's what
went into an infinite loop.
I just tried duplicating this effect with the following code:
>>> from peak.api import *
>>> r=config.makeRoot()
>>> r.lookupComponent('log')
And received the same infinite loop. So now I will go find out what causes
the infinite loop. Meanwhile, I think you can see what you need to change
to make your app work: the infinite recursion is merely a different error
than the error message you should be getting: something you're looking for
hasn't been found. I've now found and fixed the recursion in PEAK, so you
will just get 'NameNotFound' errors instead.
(Note that 'provideInstance()' effectively sets the parent component of the
provided instance, to be the object whose configuration the instance is
loaded from. In the case of your app, this is the root object. So, even
if your App object had a 'log' attribute, the instance wouldn't find it.
If you want to have things configured in your app object, call
'config.loadConfigFile()' on your app object, rather than configuring those
items in the root. Or, of course if the configuration is relatively
static, then wiring up the configuration in the app class is also doable, e.g.:
class App(binding.Component):
__uiServer = binding.New(
'ank.MedapE.UiServer.HtmlServer.HtmlServer',
provides = ank.MedapE.interfaces.IUiServer
)
This would make the class default to providing its '_App__uiServer'
attribute as the implementer of that interface. However, any configuration
loaded from the config file directly into the App instance, will override
that. So if you define a provider in the config file, it will be used
instead, and the '__uiServer' attribute will never be activated unless you
refer to it in code. However, if the config file *doesn't* define a
provider, then the class-defined default will apply as shown.
More information about the PEAK
mailing list