[Checkins] SVN: zope.app.container/trunk/ - Added an ``IBTreeContainer`` interface that allows an argument to the

Fred L. Drake, Jr. fdrake at gmail.com
Tue Apr 15 22:10:56 EDT 2008


Log message for revision 85414:
  - 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.
  

Changed:
  U   zope.app.container/trunk/CHANGES.txt
  U   zope.app.container/trunk/src/zope/app/container/btree.py
  U   zope.app.container/trunk/src/zope/app/container/interfaces.py
  U   zope.app.container/trunk/src/zope/app/container/tests/test_btree.py

-=-
Modified: zope.app.container/trunk/CHANGES.txt
===================================================================
--- zope.app.container/trunk/CHANGES.txt	2008-04-16 01:30:16 UTC (rev 85413)
+++ zope.app.container/trunk/CHANGES.txt	2008-04-16 02:10:55 UTC (rev 85414)
@@ -2,6 +2,14 @@
 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)
 ------------------
 

Modified: zope.app.container/trunk/src/zope/app/container/btree.py
===================================================================
--- zope.app.container/trunk/src/zope/app/container/btree.py	2008-04-16 01:30:16 UTC (rev 85413)
+++ zope.app.container/trunk/src/zope/app/container/btree.py	2008-04-16 02:10:55 UTC (rev 85414)
@@ -26,12 +26,15 @@
 from BTrees.OOBTree import OOBTree
 from BTrees.Length import Length
 
+from zope.app.container.interfaces import IBTreeContainer
 from zope.app.container.sample import SampleContainer
 from zope.cachedescriptors.property import Lazy
+from zope.interface import implements
 
+
 class BTreeContainer(SampleContainer, Persistent):
 
-    # implements(what my base classes implement)
+    implements(IBTreeContainer)
 
     # TODO: It appears that BTreeContainer uses SampleContainer only to
     # get the implementation of __setitem__().  All the other methods
@@ -99,3 +102,21 @@
         l.change(-1)
 
     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)

Modified: zope.app.container/trunk/src/zope/app/container/interfaces.py
===================================================================
--- zope.app.container/trunk/src/zope/app/container/interfaces.py	2008-04-16 01:30:16 UTC (rev 85413)
+++ zope.app.container/trunk/src/zope/app/container/interfaces.py	2008-04-16 02:10:55 UTC (rev 85414)
@@ -137,6 +137,46 @@
     """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):
     """Containers whose contents are maintained in order."""
 

Modified: zope.app.container/trunk/src/zope/app/container/tests/test_btree.py
===================================================================
--- zope.app.container/trunk/src/zope/app/container/tests/test_btree.py	2008-04-16 01:30:16 UTC (rev 85413)
+++ zope.app.container/trunk/src/zope/app/container/tests/test_btree.py	2008-04-16 02:10:55 UTC (rev 85414)
@@ -16,18 +16,22 @@
 $Id$
 """
 from unittest import TestCase, main, makeSuite, TestSuite
+from zope.interface.verify import verifyObject
 from zope.testing.doctestunit import DocTestSuite
 from zope.app.testing import placelesssetup
 from test_icontainer import TestSampleContainer
 from zope.app.container.btree import BTreeContainer
+from zope.app.container.interfaces import IBTreeContainer
 
+
 class TestBTreeContainer(TestSampleContainer, TestCase):
 
     def makeTestObject(self):
         return BTreeContainer()
 
-class TestBTreeLength(TestCase):
 
+class TestBTreeSpecials(TestCase):
+
     def testStoredLength(self):
         # This is lazy for backward compatibility.  If the len is not
         # stored already we set it to the length of the underlying
@@ -40,11 +44,118 @@
         self.assertEqual(len(bc), 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():
     return TestSuite((
         makeSuite(TestBTreeContainer),
-        makeSuite(TestBTreeLength),
+        makeSuite(TestBTreeSpecials),
         DocTestSuite('zope.app.container.btree',
                      setUp=placelesssetup.setUp,
                      tearDown=placelesssetup.tearDown),



More information about the Checkins mailing list