[Zope-Coders] new getattr behaviour in Python 2.2b1 breaks traversal code
Steve Alexander
steve@cat-box.net
Sun, 11 Nov 2001 13:00:17 +0000
I've just been caught out by a change between Python 2.1 and Python 2.2b1.
This is a bad change which will mean changing various parts of Zope and
Zope products, if it remains in Python 2.2 final.
Here's some information about the change.
http://sourceforge.net/tracker/index.php?func=browse&group_id=5470&atid=105470&set=&offset=100
In summary, the getattr builtin will only return its default value if a
__getattr__ method raises an AttributeError.
This is a problem because various __getattr__ methods in Zope are the
same as __getitem__ methods, and return KeyErrors.
Basically, this code works as expected:
Python 2.2b1 (#1, Oct 28 2001, 17:32:42)
[GCC 2.96 20000731 (Red Hat Linux 7.1 2.96-85)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class Foo:
... def __getitem__(self, key):
... print "__getitem__ %s" % (key,)
... raise AttributeError, key
... __getattr__=__getitem__
>>>
>>> getattr(f,'asd','default value')
__getitem__ asd
'default value'
However, this code does not work as expected:
>>> class Foo:
... def __getitem__(self, key):
... print "__getitem__ %s" % (key,)
... raise KeyError, key
... __getattr__=__getitem__
...
>>>
>>> f=Foo()
>>> getattr(f, 'asd', 'default val')
__getitem__ asd
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 4, in __getitem__
KeyError: asd
There is code in Zope which uses the latter idiom of using the same
method for __getattr__ and __getitem__. An immediate effect of this is
that TTW PageTemplates don't work with Zope and Python 2.2b1.
Line 338 of PageTemplates/Expressions.py
t=get(object, '__bobo_traverse__', N)
At this point, get is a local alias for getattr. N is None.
Unfortunately, an HTTPRequest object raises a KeyError rather than an
AttributeError, as it uses the latter idiom above.
See ZPublisher/HTTPRequest.py, around line 898.
If this change must remain in Python 2.2, Zope could be fixed by
removing all occurances of __getattr__=__getitem__ (or vice versa) and
writing them as separate methods. Of course, this will have to be done
in third party products as well.
Otherwise, the traversal code could be hardened against KeyErrors raise
by getattr.
--
Steve Alexander
Software Engineer
Cat-Box limited