[Checkins] SVN: Produts.RecentItemsIndex/trunk/ Cleanups.

Tres Seaver tseaver at palladion.com
Tue Mar 16 18:48:08 EDT 2010


Log message for revision 110004:
  Cleanups.

Changed:
  U   Produts.RecentItemsIndex/trunk/COPYRIGHT.txt
  U   Produts.RecentItemsIndex/trunk/Products/RecentItemsIndex/index.py
  U   Produts.RecentItemsIndex/trunk/Products/RecentItemsIndex/tests/test_index.py

-=-
Modified: Produts.RecentItemsIndex/trunk/COPYRIGHT.txt
===================================================================
--- Produts.RecentItemsIndex/trunk/COPYRIGHT.txt	2010-03-16 22:21:06 UTC (rev 110003)
+++ Produts.RecentItemsIndex/trunk/COPYRIGHT.txt	2010-03-16 22:48:08 UTC (rev 110004)
@@ -1,4 +1,4 @@
-Copyright (c) 2004 Zope Corporation and Contributors.
+Copyright (c) 2004, 2010 Zope Foundation and Contributors.
 All Rights Reserved.
 
 This software is subject to the provisions of the Zope Public License,

Modified: Produts.RecentItemsIndex/trunk/Products/RecentItemsIndex/index.py
===================================================================
--- Produts.RecentItemsIndex/trunk/Products/RecentItemsIndex/index.py	2010-03-16 22:21:06 UTC (rev 110003)
+++ Produts.RecentItemsIndex/trunk/Products/RecentItemsIndex/index.py	2010-03-16 22:48:08 UTC (rev 110004)
@@ -1,6 +1,6 @@
 ##############################################################################
 #
-# Copyright (c) 2004 Zope Corporation and Contributors.
+# Copyright (c) 2004, 2010 Zope Foundation and Contributors.
 # All Rights Reserved.
 #
 # This software is subject to the provisions of the Zope Public License,
@@ -28,15 +28,16 @@
 from App.special_dtml import DTMLFile
 from App.class_init import InitializeClass
 from OFS.SimpleItem import SimpleItem
-from Products.PluginIndexes.interfaces import IPluggableIndex
+from Products.PluginIndexes.interfaces import IUniqueValueIndex
 from Products.ZCatalog.Lazy import LazyMap
 from zLOG import LOG
 from zLOG import WARNING
-    
+
 _marker = []
 
 def _getSourceValue(obj, attrname):
-    """Return the data to be indexed for obj"""
+    """ Return the data to be indexed for obj.
+    """
     value = getattr(obj, attrname)
     try:
         # Try calling it
@@ -46,10 +47,10 @@
     return value
 
 class RecentItemsIndex(SimpleItem):
-    """Recent items index"""
+    """ Recent items index.
+    """
+    implements(IUniqueValueIndex)
 
-    implements(IPluggableIndex)
-    
     meta_type = 'Recent Items Index'
 
     # class default;  instances get Length() in their clear()
@@ -58,38 +59,45 @@
     manage_options = (
         {'label': 'Overview', 'action': 'manage_main'},
     )
-    
+
     manage_main = DTMLFile('www/manageIndex', globals())
-    
+
     security = ClassSecurityInfo()
     security.declareObjectProtected(Permissions.manage_zcatalog_indexes)
-    
-    def __init__(
-        self, id, field_name=None, date_name=None, max_length=None, 
-        guard_roles=None, guard_permission=None, extra=None, caller=None):
-        """Recent items index constructor
-        
+
+    def __init__(self,
+                 id,
+                 field_name=None,
+                 date_name=None,
+                 max_length=None,
+                 guard_roles=None,
+                 guard_permission=None,
+                 extra=None,
+                 caller=None,
+                ):
+        """ Recent items index constructor
+
         id -- Zope id for index in
-        
+
         field_name -- Name of attribute used to classify the objects. A
         recent item list is created for each value of this field indexed.
         If this value is omitted, then a single recent item list for all
         cataloged objects is created.
-        
+
         date_name -- Name of attribute containing a date which specifies the
         object's age.
-        
+
         max_length -- Maximum length of each recent items list.
-        
+
         guard_roles -- A list of one or more roles that must be granted the
         guard permission in order for an object to be indexed. Ignored if
         no guard_permission value is given.
-        
+
         guard_permission -- The permission that must be granted to the
         guard roles for an object in order for it to be indexed. Ignored if
         no guard_roles value is given.
-        
-        extra and caller are used by the wonderous ZCatalog addIndex 
+
+        extra and caller are used by the wonderous ZCatalog addIndex
         machinery. You can ignore them, unfortunately I can't 8^/
         """
         self.id = id
@@ -107,84 +115,32 @@
         else:
             self.guard_permission = self.guard_roles = None
         self.clear()
-    
-    ## Index specific methods ##
 
+    ## IPluggableIndex implementation.
+    def getEntryForObject(self, docid, default=None):
+        """ See IPluggableIndex.
+        """
+        try:
+            fieldvalue = self._rid2value[docid]
+        except KeyError:
+            return default
+        for date, rid in self._value2items[fieldvalue].keys():
+            if rid == docid:
+                return {'value':fieldvalue, 'date':date}
+        # If we get here then _rid2values is inconsistent with _value2items
+        LOG('RecentItemsIndex', WARNING,
+            'Field value found for item %s, but no date. '
+            'This should not happen.' % docid)
+        return default
+
     def getIndexSourceNames(self):
         """ See IPluggableIndex.
         """
         return (self.field_name,)
 
-    def indexSize(self):
+    def index_object(self, docid, obj, theshold=None):
         """ See IPluggableIndex.
         """
-        return len(self._value2items)
-    
-    def getItemCounts(self):
-        """Return a dict of field value => item count"""
-        counts = {}
-        for value, items in self._value2items.items():
-            counts[value] = len(items)
-        return counts
-        
-    def query(self, value=None, limit=None, merge=1):
-        """Return a lazy sequence of catalog brains like a catalog search
-        that coorespond to the most recent items for the value(s) given.
-        If value is omitted, then the most recent for all values are returned.
-        The result are returned in order, newest first. An integer value
-        can be specified in limit which restricts the maximum number of
-        results if desired. If no limit is specified, the indexes'
-        maximum length is used as the limit
-        """
-        catalog = aq_parent(aq_inner(self))
-        if value is None and self.field_name is not None:
-            # Query all values
-            value = list(self._value2items.keys())
-        elif value is not None and self.field_name is None:
-            # Ignore value given if there is no classifier field
-            value = None
-        if isinstance(value, (types.TupleType, types.ListType)):
-            # Query for multiple values
-            results = []
-            for fieldval in value:
-                try:
-                    itempairs = self._value2items[fieldval].keys()
-                except KeyError:
-                    pass
-                else:
-                    results.extend(itempairs)
-            results.sort()
-            if merge:
-                results = [rid for date, rid in results]
-            else:
-                # Create triples expected by mergeResults()
-                results = [(date, rid, catalog.__getitem__)
-                           for date, rid in results]
-        else:
-            # Query for single value
-            try:
-                items = self._value2items[value]                    
-            except KeyError:
-                results = []
-            else:
-                if merge:
-                    results = items.values()
-                else:
-                    # Create triples expected by mergeResults()
-                    results = [(date, rid, catalog.__getitem__)
-                               for date, rid in items.keys()]
-        results.reverse()
-        if limit is not None:
-            results = results[:limit]
-        if merge:
-            return LazyMap(catalog.__getitem__, results, len(results))
-        else:
-            return results
-    
-    ## Pluggable Index API ##
-    
-    def index_object(self, docid, obj, theshold=None):
-        """Add document to index"""
         if self.guard_permission is not None and self.guard_roles:
             allowed_roles = rolesForPermissionOn(self.guard_permission, obj)
             for role in allowed_roles:
@@ -208,11 +164,11 @@
             return 0
         datevalue = datevalue.timeTime()
         entry = self.getEntryForObject(docid)
-        if (entry is None or fieldvalue != entry['value'] 
+        if (entry is None or fieldvalue != entry['value']
             or datevalue != entry['date']):
             # XXX Note that setting the date older than a previously pruned
             #     object will result in an incorrect index state. This may
-            #     present a problem if dates are changed arbitrarily 
+            #     present a problem if dates are changed arbitrarily
             if entry is None:
                 self.numObjects.change(1)
             else:
@@ -237,16 +193,16 @@
                 try:
                     del self._rid2value[oldrid]
                 except KeyError:
-                    LOG('RecentItemsIndex', WARNING, 
+                    LOG('RecentItemsIndex', WARNING,
                         'Could not unindex field value for %s.' % oldrid)
             return 1
         else:
             # Index is up to date, nothing to do
             return 0
-    
+
     def unindex_object(self, docid):
-        """Remove docid from the index. If docid is not in the index,
-        do nothing"""
+        """ See IPluggableIndex.
+        """
         try:
             fieldvalue = self._rid2value[docid]
         except KeyError:
@@ -261,53 +217,119 @@
                     del self._value2items[fieldvalue]
                 return 1
         return 1
-    
+
     def _apply_index(self, request, cid=''):
-        """We do not play in normal catalog queries"""
+        """ See IPluggableIndex.
+        """
         return None
-        
-    def getEntryForObject(self, docid, default=None):
-        """Return a dict containing the field value and date for
-        docid, or default if it is not in the index. The returned dict
-        has the keys 'value' and 'date'
+
+    def indexSize(self):
+        """ See IPluggableIndex.
         """
-        try:
-            fieldvalue = self._rid2value[docid]
-        except KeyError:
-            return default
-        for date, rid in self._value2items[fieldvalue].keys():
-            if rid == docid:
-                return {'value':fieldvalue, 'date':date}
-        # If we get here then _rid2values is inconsistent with _value2items
-        LOG('RecentItemsIndex', WARNING, 
-            'Field value found for item %s, but no date. '
-            'This should not happen.' % docid)
-        return default
-    
+        return len(self._value2items)
+
+    def clear(self):
+        """ See IPluggableIndex.
+        """
+        self.numObjects = Length()
+        # Mapping field value => top items
+        self._value2items = OOBTree()
+        # Mapping indexed rid => field value for unindexing
+        self._rid2value = IOBTree()
+
+    # IUniqueValueIndex implementation.
     def hasUniqueValuesFor(self, name):
-        """Return true if the index holds the unique values for name"""
+        """ See IUniqueValueIndex.
+        """
         return name == self.field_name
-    
-    def uniqueValues(self, name=None):
-        """Return the unique field values indexed"""
+
+    def uniqueValues(self, name=None, withLengths=0):
+        """ See IUniqueValueIndex.
+        """
+        if withLengths:
+            return self.getItemCounts().items()
+
         if name is None:
             name = self.field_name
         if name == self.field_name:
             return self._value2items.keys()
         else:
             return []
+
+    ## Index specific methods ##
+    def getItemCounts(self):
+        """ Return a mapping of field values => item counts.
+        """
+        counts = {}
+        for value, items in self._value2items.items():
+            counts[value] = len(items)
+        return counts
+
+    def query(self, value=None, limit=None, merge=1):
+        """ Return a lazy sequence of catalog brains like a catalog search.
+
+        Brains coorespond to the most recent items for the value(s) given.
+
+        If 'value' is omitted, return the most recent for all values.
+
+        The results are returned in order, newest first.
         
-    ## ZCatalog ZMI methods ##
+        'limit', if passed, must be an integer value restricting the maximum
+        number of results.
+        
+        If no limit is specified, the indexes' maximum length is used as
+        the limit.
 
-    def clear(self):
-        """reinitialize the index"""
-        self.numObjects = Length()
-        # Mapping field value => top items
-        self._value2items = OOBTree()
-        # Mapping indexed rid => field value for unindexing
-        self._rid2value = IOBTree()
-    
+        'merge' is a flag:  if true, return a lazy map of the brains.  If
+        false, return a sequence of (value, rid, fetch) tuples which can
+        be merged later.
+        """
+        catalog = aq_parent(aq_inner(self))
+        if value is None and self.field_name is not None:
+            # Query all values
+            value = list(self._value2items.keys())
+        elif value is not None and self.field_name is None:
+            # Ignore value given if there is no classifier field
+            value = None
+        if isinstance(value, (types.TupleType, types.ListType)):
+            # Query for multiple values
+            results = []
+            for fieldval in value:
+                try:
+                    itempairs = self._value2items[fieldval].keys()
+                except KeyError:
+                    pass
+                else:
+                    results.extend(itempairs)
+            results.sort()
+            if merge:
+                results = [rid for date, rid in results]
+            else:
+                # Create triples expected by mergeResults()
+                results = [(date, rid, catalog.__getitem__)
+                           for date, rid in results]
+        else:
+            # Query for single value
+            try:
+                items = self._value2items[value]
+            except KeyError:
+                results = []
+            else:
+                if merge:
+                    results = items.values()
+                else:
+                    # Create triples expected by mergeResults()
+                    results = [(date, rid, catalog.__getitem__)
+                               for date, rid in items.keys()]
+        results.reverse()
+        if limit is not None:
+            results = results[:limit]
+        if merge:
+            return LazyMap(catalog.__getitem__, results, len(results))
+        else:
+            return results
 
+
 InitializeClass(RecentItemsIndex)
 
 addIndexForm = DTMLFile('www/addIndex', globals())

Modified: Produts.RecentItemsIndex/trunk/Products/RecentItemsIndex/tests/test_index.py
===================================================================
--- Produts.RecentItemsIndex/trunk/Products/RecentItemsIndex/tests/test_index.py	2010-03-16 22:21:06 UTC (rev 110003)
+++ Produts.RecentItemsIndex/trunk/Products/RecentItemsIndex/tests/test_index.py	2010-03-16 22:48:08 UTC (rev 110004)
@@ -28,8 +28,8 @@
                  max_length=10,
                  *args, **kw):
         catalog = self._makeCatalog()
-        index = self._getTargetClass()(id, field_name, date_name, max_length,
-                                        *args, **kw)
+        klass = self._getTargetClass()
+        index = klass(id, field_name, date_name, max_length, *args, **kw)
         return index.__of__(catalog)
 
     def _makeDoc(self, **kw):
@@ -100,6 +100,17 @@
         index = self._makeOne()
         verifyObject(IPluggableIndex, index)
 
+    def test_class_conforms_to_IUniqueValueIndex(self):
+        from zope.interface.verify import verifyClass
+        from Products.PluginIndexes.interfaces import IUniqueValueIndex
+        verifyClass(IUniqueValueIndex, self._getTargetClass())
+
+    def test_instance_conforms_to_IUniqueValueIndex(self):
+        from zope.interface.verify import verifyObject
+        from Products.PluginIndexes.interfaces import IUniqueValueIndex
+        index = self._makeOne()
+        verifyObject(IUniqueValueIndex, index)
+
     def test_construct_with_extra(self):
         # Simulate instantiating from ZCatalog
         class extra:



More information about the checkins mailing list