[ZODB-Dev] PersistentMapping glitches

Tim Peters tim at zope.com
Mon Aug 22 10:44:08 EDT 2005


Collector

    http://www.zope.org/Collectors/Zope/1873

raises some odd issues.  One (although the poster didn't realize this, it's
_part_ of their complaint) is that PersistentMapping doesn't play well with
the newer Python iteration protocol:

>>> from ZODB.PersistentMapping import PersistentMapping 
>>> pm = PersistentMapping({1: 2}) 

>>> for x in pm: 
...     print x 
Traceback (most recent call last): 
  File "<stdin>", line 1, in ? 
  File "C:\python23\lib\UserDict.py", line 19, in __getitem__ 
    def __getitem__(self, key): return self.data[key] 
KeyError: 0 

>>> list(pm) 
Traceback (most recent call last): 
  File "<stdin>", line 1, in ? 
  File "C:\python23\lib\UserDict.py", line 19, in __getitem__ 
    def __getitem__(self, key): return self.data[key] 
KeyError: 0 

>>> i = iter(pm) 
>>> i.next() 
Traceback (most recent call last): 
  File "<stdin>", line 1, in ? 
  File "C:\python23\lib\UserDict.py", line 19, in __getitem__ 
    def __getitem__(self, key): return self.data[key] 
KeyError: 0

Oddly enough, the same thing happens if you try to update a BTree with a
PersistentMapping object (which appears to be the point of the collector
issue -- and I agree it's at best surprising this doesn't work):

>>> from BTrees.OOBTree import OOBTree 
>>> b = OOBTree()
>>> b.update(pm)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "C:\python23\lib\UserDict.py", line 19, in __getitem__
    def __getitem__(self, key): return self.data[key]
KeyError: 0

That's for a related reason:  the BTree update() method, and a BTree
constructor, take _either_ a sequence (in which case it must be a sequence
of 2-tuples), or an object with an .items() method.

At the C level, PySequence_Check(pm) returns true, so the BTree code doesn't
even look for .items() in this case.  Then Python synthesizes an iterator
for pm, passing keys 0, 1, 2, ... to pm.__getitem__() in turn (well, in ZODB
3.3+, Python synthesizes this iterator; in ZODB 3.2, ZODB's C code does it
"by hand").  As above, that dies on the first try, before the BTree code
gets a chance to complain that a 2-tuple isn't returned.

Making PersistentMapping play well with the iteration protocol is just a
matter of giving it an __iter__ method, akin to the __iter__ method of
Python dicts.

That's not enough to let aBTree.update(aPersistentMapping) work, though, and
I think that "should" work.  A sufficient change should be to look for an
.items() method first.  In some cases that could be backward incompatible.
Does anyone care?  The question there is whether this could go into a bugfix
release (3.2.10, 3.4.2), or whether people simple couldn't do
aBTree.update(aPersistentMapping) or XXBTree(aPersistentMapping)
construction before 3.6.



More information about the ZODB-Dev mailing list