[Zope-dev] AQ-Parent branch test failues was: Re: Five and browser-oriented components

Hanno Schlichting plone at hannosch.info
Wed Apr 16 03:48:57 EDT 2008


Hi again.

Hanno Schlichting wrote:
> I kept my promise and added the simple tests for the first two issues I 
> found while doing testing against Plone.

I have meanwhile fixed the first trivial issue (conflicting argument 
called 'instance') and added a simple test for the second one.

Now after a good night of sleep here is the condensed version of the 
problem, for those too lazy to look at the branch and the commits:

All code is in Products.Five.browser. In .tests.aqlegacy.py we define 
two views:

class LegacyTemplate(BrowserView):

     template = ViewPageTemplateFile('falcon.pt')

     def __call__(self):
         return self.template()

class LegacyTemplateTwo(BrowserView):

     def __init__(self, context, request):
         self.__parent__ = context
         self.context = context
         self.request = request
         self.template = ViewPageTemplateFile('falcon.pt')

     def __call__(self):
         return self.template()

Both are registered in ZCML as:

<browser:page
   for="*"
   name="template"
   class=".aqlegacy.LegacyTemplate"
   permission="zope.Public"
   />

<browser:page
   for="*"
   name="template_two"
   class=".aqlegacy.LegacyTemplateTwo"
   permission="zope.Public"
   />

And in the aqlegacy_ftests.txt we call both of them via:

 >>> view = getMultiAdapter((self.folder, request), name='template')
 >>> view.template
<BoundPageTemplateFile of <Products.Five.metaclass.LegacyTemplate ...>>
 >>> print view()
<p>The falcon has taken flight</p>


 >>> view = getMultiAdapter((self.folder, request), name='template_two')
 >>> view.template
<Products.Five.browser.pagetemplatefile.ViewPageTemplateFile ...>
 >>> print view()
TypeError: __call__() takes at least 2 arguments (1 given)


Now as you can see the only difference is that one of them uses a class 
variable for assigning the template and the other one is using an 
instance variable.

 From what I understand some magic place in between doesn't find the 
template instance variable during ZCML processing as it operates on 
classes only and therefor doesn't turn the template into a 
BoundPageTemplateFile.

 From what I can tell the purpose of the BoundPageTemplateFile is to 
inject the view class into the method call of __call__, so you don't 
have to pass it in explicitly for each call. It does so, via some 
interesting code which boils down to:

class BoundPageTemplate(object):
     def __init__(self, pt, ob):
         object.__setattr__(self, 'im_func', pt)
         object.__setattr__(self, 'im_self', ob)

     def __call__(self, *args, **kw):
         if self.im_self is None:
             im_self, args = args[0], args[1:]
         else:
             im_self = self.im_self
         return self.im_func(im_self, *args, **kw)


Using an instance variable called template and calling it later on 
without passing in the view as the first argument doesn't work at all in 
Zope3. In Zope2 it did so far, as the ViewPageTemplateFile would use 
Acquisition to find its view.

I don't have any good idea on how to handle this problem. We can 
probably walk up the stack frame to find the view in most cases, as the 
template is called in almost all cases directly from the view.

But the third test failure, which I haven't written a test for yet, 
breaks even then. Essentially it puts in an adapter in between the view 
and the template where the adapter doesn't have any reference to the 
view anymore, so getting to the view from the template is impossible 
even by walking up the stack frame. This use-case is highly specialized 
(the code is in plone.app.form._named) but currently it works in Zope2.

Ideas from people who know more about this side of Zope are still most 
welcome :)

Hanno



More information about the Zope-Dev mailing list