Skip to content

Commit

Permalink
backport from the trunk:
Browse files Browse the repository at this point in the history
Fixed bug #175388 (bad btree length calculation)
  • Loading branch information
ccomb committed Jun 16, 2008
1 parent 590b2d9 commit 8ebf804
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 27 deletions.
5 changes: 5 additions & 0 deletions CHANGES.txt
Expand Up @@ -12,6 +12,11 @@ CHANGES
- prevent the namechooser from failing on '+', '@' and '/'
- added tests in the namechooser
- be sure the name chooser returns unicode
- fixed #175388 : the setitem's size modification is now done in setitemf:
setting an existing item does not change the size,
and the event subscribers should see the new size instead of the old size.
Reimplemented the BTreeContainer so that it directly accesses the btree
methods (removed an old #TODO)

3.5.3 (2007-11-09)
------------------
Expand Down
68 changes: 41 additions & 27 deletions src/zope/app/container/btree.py
Expand Up @@ -11,12 +11,7 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""This module provides a sample container implementation.
This is primarily for testing purposes.
It might be useful as a mix-in for some classes, but many classes will
need a very different implementation.
"""This module provides a sample btree container implementation.
$Id$
"""
Expand All @@ -25,22 +20,19 @@
from persistent import Persistent
from BTrees.OOBTree import OOBTree
from BTrees.Length import Length

from zope.app.container.sample import SampleContainer
from zope.interface import implements
from zope.app.container.contained import Contained, setitem, uncontained
from zope.app.container.interfaces import IContainer
from zope.cachedescriptors.property import Lazy

class BTreeContainer(SampleContainer, Persistent):

# implements(what my base classes implement)
class BTreeContainer(Contained, Persistent):

# TODO: It appears that BTreeContainer uses SampleContainer only to
# get the implementation of __setitem__(). All the other methods
# provided by that base class are just slower replacements for
# operations on the BTree itself. It would probably be clearer to
# just delegate those methods directly to the btree.
implements(IContainer)

def __init__(self):
super(BTreeContainer, self).__init__()
# We keep the previous attribute to store the data
# for backward compatibility
self._SampleContainer__data = self._newContainerData()
self.__len = Length()

def _newContainerData(self):
Expand All @@ -50,15 +42,13 @@ def _newContainerData(self):
The value returned is a mapping object that also has get,
has_key, keys, items, and values methods.
The default implementation uses an OOBTree.
"""
return OOBTree()

def __contains__(self, key):
'''See interface IReadContainer
Reimplement this method, since has_key() returns the key if available,
while we expect True or False.
>>> c = BTreeContainer()
>>> "a" in c
False
Expand All @@ -72,29 +62,53 @@ def __contains__(self, key):

@Lazy
def _BTreeContainer__len(self):
import logging
log = logging.getLogger('zope.app.container.btree')
l=Length()
ol = super(BTreeContainer, self).__len__()
ol = len(self._SampleContainer__data)
if ol>0:
l.change(ol)
self._p_changed=True
log.info("Storing length of %r" % self)
return l

def __len__(self):
return self.__len()

def __setitem__(self, key, value):
def _setitemf(self, key, value):
# make sure our lazy property gets set
l = self.__len
super(BTreeContainer, self).__setitem__(key, value)
self._SampleContainer__data[key] = value
l.change(1)

def __iter__(self):
return iter(self._SampleContainer__data)

def __getitem__(self, key):
'''See interface `IReadContainer`'''
return self._SampleContainer__data[key]

def get(self, key, default=None):
'''See interface `IReadContainer`'''
return self._SampleContainer__data.get(key, default)

def __setitem__(self, key, value):
setitem(self, self._setitemf, key, value)

def __delitem__(self, key):
# make sure our lazy property gets set
l = self.__len
super(BTreeContainer, self).__delitem__(key)
uncontained(self._SampleContainer__data[key], self, key)
del self._SampleContainer__data[key]
l.change(-1)

has_key = __contains__

def items(self):
'''See interface `IReadContainer`'''
return self._SampleContainer__data.items()

def keys(self):
'''See interface `IReadContainer`'''
return self._SampleContainer__data.keys()

def values(self):
'''See interface `IReadContainer`'''
return self._SampleContainer__data.values()
11 changes: 11 additions & 0 deletions src/zope/app/container/tests/test_btree.py
Expand Up @@ -40,6 +40,17 @@ def testStoredLength(self):
self.assertEqual(len(bc), 1)
self.assertEqual(bc.__dict__['_BTreeContainer__len'](), 1)

def testCorrectLengthWhenAddingExistingItem(self):
"""
for bug #175388
"""
bc = BTreeContainer()
bc[u'x'] = object()
self.assertEqual(len(bc), 1)
bc[u'x'] = bc[u'x']
self.assertEqual(len(bc), 1)
self.assertEqual(list(bc), [u'x'])


def test_suite():
return TestSuite((
Expand Down

0 comments on commit 8ebf804

Please sign in to comment.