[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