[Zope-Checkins] SVN: Zope/branches/2.12/src/Products/PluginIndexes/PathIndex/ Reorder to match interfaces; comply with interface semantics.

Tres Seaver tseaver at palladion.com
Mon Apr 12 12:25:32 EDT 2010


Log message for revision 110751:
  Reorder to match interfaces;  comply with interface semantics.

Changed:
  U   Zope/branches/2.12/src/Products/PluginIndexes/PathIndex/PathIndex.py
  U   Zope/branches/2.12/src/Products/PluginIndexes/PathIndex/tests/testPathIndex.py

-=-
Modified: Zope/branches/2.12/src/Products/PluginIndexes/PathIndex/PathIndex.py
===================================================================
--- Zope/branches/2.12/src/Products/PluginIndexes/PathIndex/PathIndex.py	2010-04-12 15:44:26 UTC (rev 110750)
+++ Zope/branches/2.12/src/Products/PluginIndexes/PathIndex/PathIndex.py	2010-04-12 16:25:30 UTC (rev 110751)
@@ -11,8 +11,6 @@
 #
 ##############################################################################
 """Path index.
-
-$Id$
 """
 
 from logging import getLogger
@@ -35,7 +33,6 @@
 from Products.PluginIndexes.interfaces import IPathIndex
 from Products.PluginIndexes.interfaces import IUniqueValueIndex
 
-_marker = []
 LOG = getLogger('Zope.PathIndex')
 
 
@@ -71,34 +68,29 @@
         self.useOperator = 'or'
         self.clear()
 
-    def clear(self):
-        self._depth = 0
-        self._index = OOBTree()
-        self._unindex = IOBTree()
-        self._length = Length(0)
+    def __len__(self):
+        return self._length()
 
-    def insertEntry(self, comp, id, level):
-        """Insert an entry.
+    # IPluggableIndex implementation
 
-           comp is a path component
-           id is the docid
-           level is the level of the component inside the path
+    def getEntryForObject(self, docid, default=None):
+        """ See IPluggableIndex.
         """
+        try:
+            return self._unindex[docid]
+        except KeyError:
+            return default
 
-        if not self._index.has_key(comp):
-            self._index[comp] = IOBTree()
+    def getIndexSourceNames(self):
+        """ See IPluggableIndex.
+        """
+        return (self.id, 'getPhysicalPath', )
 
-        if not self._index[comp].has_key(level):
-            self._index[comp][level] = IITreeSet()
-
-        self._index[comp][level].insert(id)
-        if level > self._depth:
-            self._depth = level
-
     def index_object(self, docid, obj ,threshold=100):
-        """ hook for (Z)Catalog """
+        """ See IPluggableIndex.
+        """
+        f = getattr(obj, self.id, None)
 
-        f = getattr(obj, self.id, None)
         if f is not None:
             if safe_callable(f):
                 try:
@@ -118,20 +110,21 @@
 
         if isinstance(path, (list, tuple)):
             path = '/'+ '/'.join(path[1:])
+
         comps = filter(None, path.split('/'))
 
         if not self._unindex.has_key(docid):
             self._length.change(1)
 
         for i in range(len(comps)):
-            self.insertEntry(comps[i], docid, i)
+            self._insertEntry(comps[i], docid, i)
         self._unindex[docid] = path
         return 1
 
     def unindex_object(self, docid):
-        """ hook for (Z)Catalog """
-
-        if not self._unindex.has_key(docid):
+        """ See IPluggableIndex.
+        """
+        if docid not in self._unindex:
             LOG.debug('Attempt to unindex nonexistent document with id %s'
                       % docid)
             return
@@ -156,15 +149,107 @@
         self._length.change(-1)
         del self._unindex[docid]
 
-    def search(self, path, default_level=0):
+    def _apply_index(self, request):
+        """ See IPluggableIndex.
+
+        o Unpacks args from catalog and mapps onto '_search'.
         """
-        path is either a string representing a
-        relative URL or a part of a relative URL or
-        a tuple (path,level).
+        record = parseIndexRequest(request, self.id, self.query_options)
+        if record.keys is None:
+            return None
 
-        level >= 0  starts searching at the given level
-        level <  0  match at *any* level
+        level = record.get("level", 0)
+        operator = record.get('operator', self.useOperator).lower()
+
+        # depending on the operator we use intersection of union
+        if operator == "or":
+            set_func = union
+        else:
+            set_func = intersection
+
+        res = None
+        for k in record.keys:
+            rows = self._search(k,level)
+            res = set_func(res,rows)
+
+        if res:
+            return res, (self.id,)
+        else:
+            return IISet(), (self.id,)
+
+    def numObjects(self):
+        """ See IPluggableIndex.
         """
+        return len(self._unindex)
+
+    def indexSize(self):
+        """ See IPluggableIndex.
+        """
+        return len(self)
+
+    def clear(self):
+        """ See IPluggableIndex.
+        """
+        self._depth = 0
+        self._index = OOBTree()
+        self._unindex = IOBTree()
+        self._length = Length(0)
+
+    # IUniqueValueIndex implementation
+
+    def hasUniqueValuesFor(self, name):
+        """ See IUniqueValueIndex.
+        """
+        return name == self.id
+
+    def uniqueValues(self, name=None, withLength=0):
+        """  See IUniqueValueIndex.
+        """
+        if name in (None, self.id, 'getPhysicalPath'):
+            if withLength:
+                for key in self._index:
+                    yield key, len(self._search(key, -1))
+            else:
+                for key in self._index.keys():
+                    yield key
+
+    # Helper methods
+
+    def _insertEntry(self, comp, id, level):
+        """ Insert an entry.
+
+        'comp' is an individual path component
+
+        'id' is the docid
+
+        .level'is the level of the component inside the path
+        """
+
+        if not self._index.has_key(comp):
+            self._index[comp] = IOBTree()
+
+        if not self._index[comp].has_key(level):
+            self._index[comp][level] = IITreeSet()
+
+        self._index[comp][level].insert(id)
+        if level > self._depth:
+            self._depth = level
+
+    def _search(self, path, default_level=0):
+        """ Perform the actual search.
+
+        ``path``
+            a string representing a relative URL, or a part of a relative URL,
+            or a tuple ``(path, level)``.  In the first two cases, use
+            ``default_level`` as the level for the search.
+
+        ``default_level``
+            the level to use for non-tuple queries.
+
+        ``level >= 0`` =>  match ``path`` only at the given level.
+
+        ``level <  0`` =>  match ``path`` at *any* level
+        """
         if isinstance(path, str):
             level = default_level
         else:
@@ -174,7 +259,7 @@
         if level < 0:
             # Search at every level, return the union of all results
             return multiunion(
-                [self.search(path, level) 
+                [self._search(path, level) 
                  for level in xrange(self._depth + 1)])
 
         comps = filter(None, path.split('/'))
@@ -192,66 +277,6 @@
             results = intersection(results, self._index[comp][level+i])
         return results
 
-    def numObjects(self):
-        """Return the number of indexed objects."""
-        return len(self._unindex)
-
-    def indexSize(self):
-        """Return the size of the index in terms of distinct values."""
-        return len(self)
-
-    def __len__(self):
-        return self._length()
-
-    def _apply_index(self, request):
-        """ hook for (Z)Catalog
-            'request' --  mapping type (usually {"path": "..." }
-             additionaly a parameter "path_level" might be passed
-             to specify the level (see search())
-        """
-        record = parseIndexRequest(request, self.id, self.query_options)
-        if record.keys is None:
-            return None
-
-        level    = record.get("level",0)
-        operator = record.get('operator',self.useOperator).lower()
-
-        # depending on the operator we use intersection of union
-        if operator == "or":  set_func = union
-        else: set_func = intersection
-
-        res = None
-        for k in record.keys:
-            rows = self.search(k,level)
-            res = set_func(res,rows)
-
-        if res:
-            return res, (self.id,)
-        else:
-            return IISet(), (self.id,)
-
-    def hasUniqueValuesFor(self, name):
-        """has unique values for column name"""
-        return name == self.id
-
-    def uniqueValues(self, name=None, withLength=0):
-        """ needed to be consistent with the interface """
-        return self._index.keys()
-
-    def getIndexSourceNames(self):
-        """ return names of indexed attributes """
-        return ('getPhysicalPath', )
-
-    def getEntryForObject(self, docid, default=_marker):
-        """ Takes a document ID and returns all the information
-            we have on that specific object.
-        """
-        try:
-            return self._unindex[docid]
-        except KeyError:
-            # XXX Why is default ignored?
-            return None
-
     manage = manage_main = DTMLFile('dtml/managePathIndex', globals())
     manage_main._setName('manage_main')
 

Modified: Zope/branches/2.12/src/Products/PluginIndexes/PathIndex/tests/testPathIndex.py
===================================================================
--- Zope/branches/2.12/src/Products/PluginIndexes/PathIndex/tests/testPathIndex.py	2010-04-12 15:44:26 UTC (rev 110750)
+++ Zope/branches/2.12/src/Products/PluginIndexes/PathIndex/tests/testPathIndex.py	2010-04-12 16:25:30 UTC (rev 110751)
@@ -94,16 +94,25 @@
         self.assertEqual(len(index._unindex), 0)
         self.assertEqual(index._length(), 0)
 
-    def test_clear(self):
+    def test_getEntryForObject_miss_no_default(self):
         index = self._makeOne()
+        self.assertEqual(index.getEntryForObject(1234), None)
+
+    def test_getEntryForObject_miss_w_default(self):
+        index = self._makeOne()
+        default = object()
+        self.failUnless(index.getEntryForObject(1234, default) is default)
+
+    def test_getEntryForObject_hit(self):
+        index = self._makeOne()
         _populateIndex(index)
-        index.clear()
-        self.assertEqual(len(index), 0)
-        self.assertEqual(index._depth, 0)
-        self.assertEqual(len(index._index), 0)
-        self.assertEqual(len(index._unindex), 0)
-        self.assertEqual(index._length(), 0)
+        self.assertEqual(index.getEntryForObject(1), DUMMIES[1].path)
 
+    def test_getIndexSourceNames(self):
+        index = self._makeOne('foo')
+        self.assertEqual(list(index.getIndexSourceNames()),
+                         ['foo', 'getPhysicalPath'])
+
     def test_index_object_broken_path_raises_TypeError(self):
         index = self._makeOne()
         doc = Dummy({})
@@ -234,71 +243,6 @@
         self.assertEqual(len(index._index), 0)
         self.assertEqual(len(index._unindex), 0)
 
-    def test_search_empty_index_string_query(self):
-        index = self._makeOne()
-        self.assertEqual(list(index.search('/xxx')), [])
-
-    def test_search_empty_index_tuple_query(self):
-        index = self._makeOne()
-        self.assertEqual(list(index.search(('/xxx', 0))), [])
-
-    def test_search_empty_path(self):
-        index = self._makeOne()
-        doc = Dummy('/aa')
-        index.index_object(1, doc)
-        self.assertEqual(list(index.search('/')), [1])
-
-    def test_search_matching_path(self):
-        index = self._makeOne()
-        doc = Dummy('/aa')
-        index.index_object(1, doc)
-        self.assertEqual(list(index.search('/aa')), [1])
-
-    def test_search_mismatched_path(self):
-        index = self._makeOne()
-        doc = Dummy('/aa')
-        index.index_object(1, doc)
-        self.assertEqual(list(index.search('/bb')), [])
-
-    def test_search_w_level_0(self):
-        index = self._makeOne()
-        doc = Dummy('/aa/bb')
-        index.index_object(1, doc)
-        self.assertEqual(list(index.search('aa', 0)), [1])
-        self.assertEqual(list(index.search('aa', 1)), [])
-        self.assertEqual(list(index.search('bb', 1)), [1])
-        self.assertEqual(list(index.search('aa/bb', 0)), [1])
-        self.assertEqual(list(index.search('aa/bb', 1)), [])
-
-    def test_numObjects_empty(self):
-        index = self._makeOne()
-        self.assertEqual(index.numObjects(), 0)
-
-    def test_numObjects_filled(self):
-        index = self._makeOne()
-        _populateIndex(index)
-        self.assertEqual(index.numObjects(), len(DUMMIES))
-
-    def test_indexSize_empty(self):
-        index = self._makeOne()
-        self.assertEqual(index.indexSize(), 0)
-
-    def test_indexSize_filled(self):
-        index = self._makeOne()
-        _populateIndex(index)
-        self.assertEqual(index.indexSize(), len(DUMMIES))
-
-    def test_indexSize_multiple_items_same_path(self):
-        index = self._makeOne()
-        doc1 = Dummy('/shared')
-        doc2 = Dummy('/shared')
-        index.index_object(1, doc1)
-        index.index_object(2, doc2)
-        self.assertEqual(len(index._index), 1)
-        self.assertEqual(len(index), 2)
-        self.assertEqual(index.numObjects(), 2)
-        self.assertEqual(index.indexSize(), 2)
-
     def test__apply_index_no_match_in_query(self):
         index = self._makeOne()
         self.assertEqual(index._apply_index({'foo': 'xxx'}), None)
@@ -397,6 +341,45 @@
         lst = list(res[0].keys())
         self.assertEqual(lst, [2, 3, 4])
 
+    def test_numObjects_empty(self):
+        index = self._makeOne()
+        self.assertEqual(index.numObjects(), 0)
+
+    def test_numObjects_filled(self):
+        index = self._makeOne()
+        _populateIndex(index)
+        self.assertEqual(index.numObjects(), len(DUMMIES))
+
+    def test_indexSize_empty(self):
+        index = self._makeOne()
+        self.assertEqual(index.indexSize(), 0)
+
+    def test_indexSize_filled(self):
+        index = self._makeOne()
+        _populateIndex(index)
+        self.assertEqual(index.indexSize(), len(DUMMIES))
+
+    def test_indexSize_multiple_items_same_path(self):
+        index = self._makeOne()
+        doc1 = Dummy('/shared')
+        doc2 = Dummy('/shared')
+        index.index_object(1, doc1)
+        index.index_object(2, doc2)
+        self.assertEqual(len(index._index), 1)
+        self.assertEqual(len(index), 2)
+        self.assertEqual(index.numObjects(), 2)
+        self.assertEqual(index.indexSize(), 2)
+
+    def test_clear(self):
+        index = self._makeOne()
+        _populateIndex(index)
+        index.clear()
+        self.assertEqual(len(index), 0)
+        self.assertEqual(index._depth, 0)
+        self.assertEqual(len(index._index), 0)
+        self.assertEqual(len(index._unindex), 0)
+        self.assertEqual(index._length(), 0)
+
     def test_hasUniqueValuesFor_miss(self):
         index = self._makeOne()
         self.failIf(index.hasUniqueValuesFor('miss'))
@@ -407,35 +390,70 @@
 
     def test_uniqueValues_empty(self):
         index = self._makeOne()
-        self.assertEqual(len(index.uniqueValues()), 0)
+        self.assertEqual(len(list(index.uniqueValues())), 0)
 
-    def test_uniqueValues_filled(self):
-        index = self._makeOne()
+    def test_uniqueValues_miss(self):
+        index = self._makeOne('foo')
         _populateIndex(index)
-        self.assertEqual(len(index.uniqueValues()), len(DUMMIES) + 3)
+        self.assertEqual(len(list(index.uniqueValues('bar'))), 0)
 
-    def test_getEntryForObject_miss_no_default(self):
+    def test_uniqueValues_hit(self):
+        index = self._makeOne('foo')
+        _populateIndex(index)
+        self.assertEqual(len(list(index.uniqueValues('foo'))),
+                         len(DUMMIES) + 3)
+
+    def test_uniqueValues_hit_w_withLength(self):
+        index = self._makeOne('foo')
+        _populateIndex(index)
+        results = dict(index.uniqueValues('foo', True))
+        self.assertEqual(len(results), len(DUMMIES) + 3)
+        for i in range(1, 19):
+            self.assertEqual(results['%s.html' % i], 1)
+        self.assertEqual(results['aa'],
+                         len([x for x in DUMMIES.values() if 'aa' in x.path]))
+        self.assertEqual(results['bb'],
+                         len([x for x in DUMMIES.values() if 'bb' in x.path]))
+        self.assertEqual(results['cc'],
+                         len([x for x in DUMMIES.values() if 'cc' in x.path]))
+
+    def test__search_empty_index_string_query(self):
         index = self._makeOne()
-        self.assertEqual(index.getEntryForObject(1234), None)
+        self.assertEqual(list(index._search('/xxx')), [])
 
-    def test_getEntryForObject_miss_w_default(self):
+    def test__search_empty_index_tuple_query(self):
         index = self._makeOne()
-        default = object()
-        # XXX  this is wrong:  should return the default
-        self.assertEqual(index.getEntryForObject(1234, default), None)
+        self.assertEqual(list(index._search(('/xxx', 0))), [])
 
-    def test_getEntryForObject_hit(self):
+    def test__search_empty_path(self):
         index = self._makeOne()
-        _populateIndex(index)
-        self.assertEqual(index.getEntryForObject(1), DUMMIES[1].path)
+        doc = Dummy('/aa')
+        index.index_object(1, doc)
+        self.assertEqual(list(index._search('/')), [1])
 
-    def test_getIndexSourceNames(self):
+    def test__search_matching_path(self):
         index = self._makeOne()
-        # XXX  this is wrong:  should include the index ID as well
-        self.assertEqual(list(index.getIndexSourceNames()),
-                         ['getPhysicalPath'])
+        doc = Dummy('/aa')
+        index.index_object(1, doc)
+        self.assertEqual(list(index._search('/aa')), [1])
 
+    def test__search_mismatched_path(self):
+        index = self._makeOne()
+        doc = Dummy('/aa')
+        index.index_object(1, doc)
+        self.assertEqual(list(index._search('/bb')), [])
 
+    def test__search_w_level_0(self):
+        index = self._makeOne()
+        doc = Dummy('/aa/bb')
+        index.index_object(1, doc)
+        self.assertEqual(list(index._search('aa', 0)), [1])
+        self.assertEqual(list(index._search('aa', 1)), [])
+        self.assertEqual(list(index._search('bb', 1)), [1])
+        self.assertEqual(list(index._search('aa/bb', 0)), [1])
+        self.assertEqual(list(index._search('aa/bb', 1)), [])
+
+
 def test_suite():
     return unittest.TestSuite((
             unittest.makeSuite(PathIndexTests),



More information about the Zope-Checkins mailing list