Your script doesn't behave like expected, though the syntax is correct and code
looks sane. Here are some tricky things which can explain its observed behaviour.
Table of Contents
Python "is" keyword gives unexpected results when comparing objects.
>>> context.foo is context.foo
This is because foo object is wrapped by zope at access in an acquisition wrapper,
and that acquisition wrapper is generated at every access. A possible solution if
you want to stick to "is" keyword would be.
>>> from Acquisition import aq_base
>>>aq_base(context.foo) is aq_base(context.foo)
But be reminded that this relies on zope's object cache behaviour: if one day it
decides to cache multiple versions of the same object from the point of view of
a given thread, this test will fail. Another possibility, if you can access it,
is to check for object's oid, but it requires at least a (sub) transaction to have
been commited since object was created, and oid is not directly available from
When accessing any object, be prepared to get trapped by acquisition. Accessing
successfully foo from bar does not mean the foo was the object you were searching
for in the first place. This is espacially tricky in categories when the same
structure is repeated among multiples "brothers" trees, with some exceptions.
For example, the following structure (taken from
ERP5Banking unit tests) can easily mislead the programer into thinking his
Here, accessing testsite/siege/caveau will end up with testsite/caveau object
inside an "unusual" acquisition context which will make getParentValue use tricky.
getattr(context.portal_categories.testsite.paris, "another_id", None)
Will return None, unless another_id can be acquired from context. In this case,
it's recommanded to start from the portal object, using:
getattr(context.getPortalObject().portal_categories.testsite.paris, "another_id", None)