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 restricted environment.
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 code works:
Here, accessing testsite/siege/caveau will end up with testsite/caveau object
inside an "unusual" acquisition context which will make getParentValue use
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)