Commit 843cc998 authored by Fred Drake's avatar Fred Drake

- Added an ``IBTreeContainer`` interface that allows an argument to the

  ``items``, ``keys``, and ``values`` methods with the same semantics as for
  a BTree object.  The extended interface is implemented by the
  ``BTreeContainer`` class.
parent 3dd2cccf
...@@ -2,6 +2,14 @@ ...@@ -2,6 +2,14 @@
CHANGES CHANGES
======= =======
3.6.0 (unreleased)
------------------
- Added an ``IBTreeContainer`` interface that allows an argument to the
``items``, ``keys``, and ``values`` methods with the same semantics as for
a BTree object. The extended interface is implemented by the
``BTreeContainer`` class.
3.5.3 (2007-11-09) 3.5.3 (2007-11-09)
------------------ ------------------
......
...@@ -26,12 +26,15 @@ from persistent import Persistent ...@@ -26,12 +26,15 @@ from persistent import Persistent
from BTrees.OOBTree import OOBTree from BTrees.OOBTree import OOBTree
from BTrees.Length import Length from BTrees.Length import Length
from zope.app.container.interfaces import IBTreeContainer
from zope.app.container.sample import SampleContainer from zope.app.container.sample import SampleContainer
from zope.cachedescriptors.property import Lazy from zope.cachedescriptors.property import Lazy
from zope.interface import implements
class BTreeContainer(SampleContainer, Persistent): class BTreeContainer(SampleContainer, Persistent):
# implements(what my base classes implement) implements(IBTreeContainer)
# TODO: It appears that BTreeContainer uses SampleContainer only to # TODO: It appears that BTreeContainer uses SampleContainer only to
# get the implementation of __setitem__(). All the other methods # get the implementation of __setitem__(). All the other methods
...@@ -99,3 +102,21 @@ class BTreeContainer(SampleContainer, Persistent): ...@@ -99,3 +102,21 @@ class BTreeContainer(SampleContainer, Persistent):
l.change(-1) l.change(-1)
has_key = __contains__ has_key = __contains__
def items(self, key=None):
if key is None:
return super(BTreeContainer, self).items()
else:
return self._SampleContainer__data.items(key)
def keys(self, key=None):
if key is None:
return super(BTreeContainer, self).keys()
else:
return self._SampleContainer__data.keys(key)
def values(self, key=None):
if key is None:
return super(BTreeContainer, self).values()
else:
return self._SampleContainer__data.values(key)
...@@ -137,6 +137,46 @@ class IContainer(IReadContainer, IWriteContainer): ...@@ -137,6 +137,46 @@ class IContainer(IReadContainer, IWriteContainer):
"""Readable and writable content container.""" """Readable and writable content container."""
class IBTreeContainer(IContainer):
"""Container that supports BTree semantics for some methods."""
def items(key=None):
"""Return an iterator over the key-value pairs in the container.
If ``None`` is passed as `key`, this method behaves as if no argument
were passed; exactly as required for ``IContainer.items()``.
If `key` is in the container, the first item provided by the iterator
will correspond to that key. Otherwise, the first item will be for
the key that would come next if `key` were in the container.
"""
def keys(key=None):
"""Return an iterator over the keys in the container.
If ``None`` is passed as `key`, this method behaves as if no argument
were passed; exactly as required for ``IContainer.keys()``.
If `key` is in the container, the first key provided by the iterator
will be that key. Otherwise, the first key will be the one that would
come next if `key` were in the container.
"""
def values(key=None):
"""Return an iterator over the values in the container.
If ``None`` is passed as `key`, this method behaves as if no argument
were passed; exactly as required for ``IContainer.values()``.
If `key` is in the container, the first value provided by the iterator
will correspond to that key. Otherwise, the first value will be for
the key that would come next if `key` were in the container.
"""
class IOrderedContainer(IContainer): class IOrderedContainer(IContainer):
"""Containers whose contents are maintained in order.""" """Containers whose contents are maintained in order."""
......
...@@ -16,17 +16,21 @@ ...@@ -16,17 +16,21 @@
$Id$ $Id$
""" """
from unittest import TestCase, main, makeSuite, TestSuite from unittest import TestCase, main, makeSuite, TestSuite
from zope.interface.verify import verifyObject
from zope.testing.doctestunit import DocTestSuite from zope.testing.doctestunit import DocTestSuite
from zope.app.testing import placelesssetup from zope.app.testing import placelesssetup
from test_icontainer import TestSampleContainer from test_icontainer import TestSampleContainer
from zope.app.container.btree import BTreeContainer from zope.app.container.btree import BTreeContainer
from zope.app.container.interfaces import IBTreeContainer
class TestBTreeContainer(TestSampleContainer, TestCase): class TestBTreeContainer(TestSampleContainer, TestCase):
def makeTestObject(self): def makeTestObject(self):
return BTreeContainer() return BTreeContainer()
class TestBTreeLength(TestCase):
class TestBTreeSpecials(TestCase):
def testStoredLength(self): def testStoredLength(self):
# This is lazy for backward compatibility. If the len is not # This is lazy for backward compatibility. If the len is not
...@@ -40,11 +44,118 @@ class TestBTreeLength(TestCase): ...@@ -40,11 +44,118 @@ class TestBTreeLength(TestCase):
self.assertEqual(len(bc), 1) self.assertEqual(len(bc), 1)
self.assertEqual(bc.__dict__['_BTreeContainer__len'](), 1) self.assertEqual(bc.__dict__['_BTreeContainer__len'](), 1)
# The tests which follow test the additional signatures and declarations
# for the BTreeContainer that allow it to provide the IBTreeContainer
# interface.
def testBTreeContainerInterface(self):
bc = BTreeContainer()
self.assert_(verifyObject(IBTreeContainer, bc))
self.checkIterable(bc.items())
self.checkIterable(bc.keys())
self.checkIterable(bc.values())
def testEmptyItemsWithArg(self):
bc = BTreeContainer()
self.assertEqual(list(bc.items(None)), list(bc.items()))
self.assertEqual(list(bc.items("")), [])
self.assertEqual(list(bc.items("not-there")), [])
self.checkIterable(bc.items(None))
self.checkIterable(bc.items(""))
self.checkIterable(bc.items("not-there"))
def testEmptyKeysWithArg(self):
bc = BTreeContainer()
self.assertEqual(list(bc.keys(None)), list(bc.keys()))
self.assertEqual(list(bc.keys("")), [])
self.assertEqual(list(bc.keys("not-there")), [])
self.checkIterable(bc.keys(None))
self.checkIterable(bc.keys(""))
self.checkIterable(bc.keys("not-there"))
def testEmptyValuesWithArg(self):
bc = BTreeContainer()
self.assertEqual(list(bc.values(None)), list(bc.values()))
self.assertEqual(list(bc.values("")), [])
self.assertEqual(list(bc.values("not-there")), [])
self.checkIterable(bc.values(None))
self.checkIterable(bc.values(""))
self.checkIterable(bc.values("not-there"))
def testNonemptyItemsWithArg(self):
bc = BTreeContainer()
bc["0"] = 1
bc["1"] = 2
bc["2"] = 3
self.assertEqual(list(bc.items(None)), list(bc.items()))
self.assertEqual(list(bc.items("")), [("0", 1), ("1", 2), ("2", 3)])
self.assertEqual(list(bc.items("3")), [])
self.assertEqual(list(bc.items("2.")), [])
self.assertEqual(list(bc.items("2")), [("2", 3)])
self.assertEqual(list(bc.items("1.")), [("2", 3)])
self.assertEqual(list(bc.items("1")), [("1", 2), ("2", 3)])
self.assertEqual(list(bc.items("0.")), [("1", 2), ("2", 3)])
self.assertEqual(list(bc.items("0")), [("0", 1), ("1", 2), ("2", 3)])
self.checkIterable(bc.items(None))
self.checkIterable(bc.items(""))
self.checkIterable(bc.items("0."))
self.checkIterable(bc.items("3"))
def testNonemptyKeysWithArg(self):
bc = BTreeContainer()
bc["0"] = 1
bc["1"] = 2
bc["2"] = 3
self.assertEqual(list(bc.keys(None)), list(bc.keys()))
self.assertEqual(list(bc.keys("")), ["0", "1", "2"])
self.assertEqual(list(bc.keys("3")), [])
self.assertEqual(list(bc.keys("2.")), [])
self.assertEqual(list(bc.keys("2")), ["2"])
self.assertEqual(list(bc.keys("1.")), ["2"])
self.assertEqual(list(bc.keys("1")), ["1", "2"])
self.assertEqual(list(bc.keys("0.")), ["1", "2"])
self.assertEqual(list(bc.keys("0")), ["0", "1", "2"])
self.checkIterable(bc.keys(None))
self.checkIterable(bc.keys(""))
self.checkIterable(bc.keys("0."))
self.checkIterable(bc.keys("3"))
def testNonemptyValueWithArg(self):
bc = BTreeContainer()
bc["0"] = 1
bc["1"] = 2
bc["2"] = 3
self.assertEqual(list(bc.values(None)), list(bc.values()))
self.assertEqual(list(bc.values("")), [1, 2, 3])
self.assertEqual(list(bc.values("3")), [])
self.assertEqual(list(bc.values("2.")), [])
self.assertEqual(list(bc.values("2")), [3])
self.assertEqual(list(bc.values("1.")), [3])
self.assertEqual(list(bc.values("1")), [2, 3])
self.assertEqual(list(bc.values("0.")), [2, 3])
self.assertEqual(list(bc.values("0")), [1, 2, 3])
self.checkIterable(bc.values(None))
self.checkIterable(bc.values(""))
self.checkIterable(bc.values("0."))
self.checkIterable(bc.values("3"))
def checkIterable(self, iterable):
it = iter(iterable)
self.assert_(callable(it.next))
self.assert_(callable(it.__iter__))
self.assert_(iter(it) is it)
# Exhaust the iterator:
first_time = list(it)
self.assertRaises(StopIteration, it.next)
# Subsequent iterations will return the same values:
self.assertEqual(list(iterable), first_time)
self.assertEqual(list(iterable), first_time)
def test_suite(): def test_suite():
return TestSuite(( return TestSuite((
makeSuite(TestBTreeContainer), makeSuite(TestBTreeContainer),
makeSuite(TestBTreeLength), makeSuite(TestBTreeSpecials),
DocTestSuite('zope.app.container.btree', DocTestSuite('zope.app.container.btree',
setUp=placelesssetup.setUp, setUp=placelesssetup.setUp,
tearDown=placelesssetup.tearDown), tearDown=placelesssetup.tearDown),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment