[z3-five] PT has no attribute 'getPhysicalRoot'

Martin Aspeli optilude at gmx.net
Sat Dec 9 00:11:45 CET 2006


Dennis Schulz wrote:
> I tried to subclass the DomainClass in alchemist from 
> Acquisition.Explicit (and tried also Implicit) but still the same error 
> messages like before.
> When I print out context.aq_chain then says that 'List' object has no 
> attribute 'aq_chain'. So its useless in this case to get the aquisition 
> context like that.


I'm struggling to follow your reports here, but just some general notes 
on Acquisition and Five:

Anything you publish in Zope 2 really needs an acquisition wrapper. A 
lack of such often manifests itself in odd security errors (like 
username not found, or simply Unauthorized). Acquisition.Explicit will 
normally do. Views generally need this - and this is what you get with 
Products.Five.browser.BrowserView as a base class.

Sometimes, things expect to be able to acquire things implicitly. In 
that case, Acquisition.Implicit is a better base class, but I try to 
avoid it.

I've found in a few cases that I need to inherit from 
OFS.SimpleItem.SimpleItem for things to work; this normally means that 
the code is expecting to be a pretty fully-featured Zope 2 object (e.g. 
it has a role manager). To be honest, this is like shooting pigeons with 
cannons, but it's sometimes a useful thing to try, if just to see 
whether you are missing some mix-in class.

If you have a browser view that mixes in Acquisition (as you nearly 
always need to) then you may run into strange acquisition chain 
problems. Normally, it goes like this:

from Products.Five.browser import BrowserView
class MyView(BrowserView):

     def __init__(self, context, request):
         self.context = context
         self.request = request

     def my_function(self):
         # do something with self.context

Since you assigned context to self.context, and context is most likely a 
Zope 2 object, then context has an inner acquisition chain based on 
containment (aq_parent(context) is the parent object of the context 
object in the containment hierarchy). However, the outermost acquistion 
chain involves the MyView class, because it has Acquisition.Explicit and 
anything you retrieve from it by attribute access gets wrapped in that 
object.

So, aq_chain(self.context) will be something like MyContext - MyView - 
aq_parent(MyView) ...; in most cases this is not what you really expect. 
It normally works fine, until you do something with context that expects 
a sane acquisition chain. Sometimes you can also get nested acquisition 
chains, which is really nasty.

The most common solution is to always use aq_inner(self.context). I tend 
do start most of my functions with:

from Acquisition import aq_inner

     def my_function(self):
         context = aq_inner(self.context)
         # do something with context, not self.context

Another pattern, which you see in Plone (and which I dislike, but it's a 
  bit safer) is to do this:

     def __init__(self, context, request):
         self._context = [context]
         self.context = context # you normally need this anyway
         self.request = request

     def my_function(self):
         context = self._context[0]

Since self._context is a list, the items in that list are not 
acquisition wrapped, so you're safe.

Anyway, I hope that helps a bit. It's normally quite instructive to 
print aq_chain(context) in a debug session and see whether it looks sane 
(normally, it should reflect containment and end with BaseRequest).

Martin



More information about the z3-five mailing list