[Checkins] SVN: Zope/trunk/ Added a new BooleanIndex to the standard PluginIndexes, sponsored by Jarn AS and based on work in the Products.BooleanIndex distribution.

Hanno Schlichting hannosch at hannosch.eu
Sat Sep 25 18:03:22 EDT 2010


Log message for revision 116949:
  Added a new BooleanIndex to the standard PluginIndexes, sponsored by Jarn AS and based on work in the Products.BooleanIndex distribution.
  

Changed:
  U   Zope/trunk/doc/CHANGES.rst
  A   Zope/trunk/src/Products/PluginIndexes/BooleanIndex/
  A   Zope/trunk/src/Products/PluginIndexes/BooleanIndex/BooleanIndex.py
  A   Zope/trunk/src/Products/PluginIndexes/BooleanIndex/__init__.py
  A   Zope/trunk/src/Products/PluginIndexes/BooleanIndex/dtml/
  A   Zope/trunk/src/Products/PluginIndexes/BooleanIndex/dtml/addBooleanIndex.dtml
  A   Zope/trunk/src/Products/PluginIndexes/BooleanIndex/dtml/manageBooleanIndex.dtml
  A   Zope/trunk/src/Products/PluginIndexes/BooleanIndex/tests.py
  U   Zope/trunk/src/Products/PluginIndexes/__init__.py

-=-
Modified: Zope/trunk/doc/CHANGES.rst
===================================================================
--- Zope/trunk/doc/CHANGES.rst	2010-09-25 21:57:29 UTC (rev 116948)
+++ Zope/trunk/doc/CHANGES.rst	2010-09-25 22:03:22 UTC (rev 116949)
@@ -19,6 +19,8 @@
 Features Added
 ++++++++++++++
 
+- Added a new BooleanIndex to the standard PluginIndexes.
+
 - Update to Zope Toolkit 1.0c1.
 
 - Add ability to define extra zopectl commands via setuptools entrypoints.

Added: Zope/trunk/src/Products/PluginIndexes/BooleanIndex/BooleanIndex.py
===================================================================
--- Zope/trunk/src/Products/PluginIndexes/BooleanIndex/BooleanIndex.py	                        (rev 0)
+++ Zope/trunk/src/Products/PluginIndexes/BooleanIndex/BooleanIndex.py	2010-09-25 22:03:22 UTC (rev 116949)
@@ -0,0 +1,155 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Foundation and Contributors.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+from logging import getLogger
+
+from App.special_dtml import DTMLFile
+from BTrees.IIBTree import IIBTree, IITreeSet, IISet
+from BTrees.IIBTree import union, intersection, difference
+import BTrees.Length
+from ZODB.POSException import ConflictError
+
+from Products.PluginIndexes.common.util import parseIndexRequest
+from Products.PluginIndexes.common.UnIndex import UnIndex
+
+_marker = object()
+LOG = getLogger('BooleanIndex.UnIndex')
+
+
+class BooleanIndex(UnIndex):
+    """Index for booleans
+
+       self._index = set([documentId1, documentId2])
+       self._unindex = {documentId:[True/False]}
+
+       False doesn't have actual entries in _index.
+    """
+
+    meta_type = "BooleanIndex"
+
+    manage_options= (
+        {'label': 'Settings',
+         'action': 'manage_main'},
+        {'label': 'Browse',
+         'action': 'manage_browse'},
+    )
+
+    query_options = ["query"]
+
+    manage = manage_main = DTMLFile('dtml/manageBooleanIndex', globals())
+    manage_main._setName('manage_main')
+    manage_browse = DTMLFile('../dtml/browseIndex', globals())
+
+    def clear(self):
+        self._length = BTrees.Length.Length()
+        self._index = IITreeSet()
+        self._unindex = IIBTree()
+
+    def insertForwardIndexEntry(self, entry, documentId):
+        """If True, insert directly into treeset
+        """
+        if entry:
+            self._index.insert(documentId)
+            self._length.change(1)
+
+    def removeForwardIndexEntry(self, entry, documentId):
+        """Take the entry provided and remove any reference to documentId
+        in its entry in the index.
+        """
+        try:
+            if entry:
+                self._index.remove(documentId)
+                self._length.change(-1)
+        except ConflictError:
+            raise
+        except Exception:
+            LOG.exception('%s: unindex_object could not remove '
+                          'documentId %s from index %s. This '
+                          'should not happen.' % (self.__class__.__name__,
+                          str(documentId), str(self.id)))
+
+    def _index_object(self, documentId, obj, threshold=None, attr=''):
+        """ index and object 'obj' with integer id 'documentId'"""
+        returnStatus = 0
+
+        # First we need to see if there's anything interesting to look at
+        datum = self._get_object_datum(obj, attr)
+
+        # Make it boolean, int as an optimization
+        datum = int(bool(datum))
+
+        # We don't want to do anything that we don't have to here, so we'll
+        # check to see if the new and existing information is the same.
+        oldDatum = self._unindex.get(documentId, _marker)
+        if datum != oldDatum:
+            if oldDatum is not _marker:
+                self.removeForwardIndexEntry(oldDatum, documentId)
+                if datum is _marker:
+                    try:
+                        del self._unindex[documentId]
+                    except ConflictError:
+                        raise
+                    except Exception:
+                        LOG.error('Should not happen: oldDatum was there, now '
+                                  'its not, for document with id %s' %
+                                  documentId)
+
+            if datum is not _marker:
+                if datum:
+                    self.insertForwardIndexEntry(datum, documentId)
+                self._unindex[documentId] = datum
+
+            returnStatus = 1
+
+        return returnStatus
+
+    def _apply_index(self, request, resultset=None):
+        record = parseIndexRequest(request, self.id, self.query_options)
+        if record.keys is None:
+            return None
+
+        index = self._index
+
+        for key in record.keys:
+            if key:
+                # If True, check index
+                return (intersection(index, resultset), (self.id, ))
+            else:
+                # Otherwise, remove from resultset or _unindex
+                if resultset is None:
+                    return (union(difference(self._unindex, index), IISet([])),
+                            (self.id, ))
+                else:
+                    return (difference(resultset, index), (self.id, ))
+        return (IISet(), (self.id, ))
+
+    def indexSize(self):
+        """Return distinct values, as an optimization we always claim 2."""
+        return 2
+
+    def items(self):
+        items = []
+        for v, k in self._unindex.items():
+            if isinstance(v, int):
+                v = IISet((v, ))
+            items.append((k, v))
+        return items
+
+manage_addBooleanIndexForm = DTMLFile('dtml/addBooleanIndex', globals())
+
+
+def manage_addBooleanIndex(self, id, extra=None,
+                REQUEST=None, RESPONSE=None, URL3=None):
+    """Add a boolean index"""
+    return self.manage_addIndex(id, 'BooleanIndex', extra=extra, \
+             REQUEST=REQUEST, RESPONSE=RESPONSE, URL1=URL3)


Property changes on: Zope/trunk/src/Products/PluginIndexes/BooleanIndex/BooleanIndex.py
___________________________________________________________________
Added: svn:eol-style
   + native


Property changes on: Zope/trunk/src/Products/PluginIndexes/BooleanIndex/__init__.py
___________________________________________________________________
Added: svn:eol-style
   + native

Added: Zope/trunk/src/Products/PluginIndexes/BooleanIndex/dtml/addBooleanIndex.dtml
===================================================================
--- Zope/trunk/src/Products/PluginIndexes/BooleanIndex/dtml/addBooleanIndex.dtml	                        (rev 0)
+++ Zope/trunk/src/Products/PluginIndexes/BooleanIndex/dtml/addBooleanIndex.dtml	2010-09-25 22:03:22 UTC (rev 116949)
@@ -0,0 +1,60 @@
+<dtml-var manage_page_header>
+
+<dtml-var "manage_form_title(this(), _, form_title='Add BooleanIndex')">
+
+
+<p class="form-help">
+<strong>Boolean Indexes</strong> can be used for keeping track of
+whether objects fulfills a certain contract, like isFolderish
+</p>
+
+
+<form action="manage_addBooleanIndex" method="post" enctype="multipart/form-data">
+<table cellspacing="0" cellpadding="2" border="0">
+  <tr>
+    <td align="left" valign="top">
+    <div class="form-label">
+    Id
+    </div>
+    </td>
+    <td align="left" valign="top">
+    <input type="text" name="id" size="40" />
+    </td>
+  </tr>
+
+  <tr>
+    <td align="left" valign="top">
+    <div class="form-label">
+    Indexed attributes
+    </div>
+    </td>
+    <td align="left" valign="top">
+    <input type="text" name="extra.indexed_attrs:record:string" size="40" />
+    <em>attribute1,attribute2,...</em> or leave empty
+    </td>
+  </tr>
+
+  <tr>
+    <td align="left" valign="top">
+    <div class="form-optional">
+    Type
+    </div>
+    </td>
+    <td align="left" valign="top">
+     Boolean Index
+    </td>
+  </tr>
+  <tr>
+    <td align="left" valign="top">
+    </td>
+    <td align="left" valign="top">
+    <div class="form-element">
+    <input class="form-element" type="submit" name="submit" 
+     value=" Add " /> 
+    </div>
+    </td>
+  </tr>
+</table>
+</form>
+
+<dtml-var manage_page_footer>


Property changes on: Zope/trunk/src/Products/PluginIndexes/BooleanIndex/dtml/addBooleanIndex.dtml
___________________________________________________________________
Added: svn:eol-style
   + native

Added: Zope/trunk/src/Products/PluginIndexes/BooleanIndex/dtml/manageBooleanIndex.dtml
===================================================================
--- Zope/trunk/src/Products/PluginIndexes/BooleanIndex/dtml/manageBooleanIndex.dtml	                        (rev 0)
+++ Zope/trunk/src/Products/PluginIndexes/BooleanIndex/dtml/manageBooleanIndex.dtml	2010-09-25 22:03:22 UTC (rev 116949)
@@ -0,0 +1,10 @@
+<dtml-var manage_page_header>
+<dtml-var manage_tabs>
+
+<p class="form-help">
+Objects indexed: <dtml-var numObjects>
+<br>
+Distinct values: <dtml-var indexSize>
+</p>
+
+<dtml-var manage_page_footer>


Property changes on: Zope/trunk/src/Products/PluginIndexes/BooleanIndex/dtml/manageBooleanIndex.dtml
___________________________________________________________________
Added: svn:eol-style
   + native

Added: Zope/trunk/src/Products/PluginIndexes/BooleanIndex/tests.py
===================================================================
--- Zope/trunk/src/Products/PluginIndexes/BooleanIndex/tests.py	                        (rev 0)
+++ Zope/trunk/src/Products/PluginIndexes/BooleanIndex/tests.py	2010-09-25 22:03:22 UTC (rev 116949)
@@ -0,0 +1,104 @@
+##############################################################################
+#
+# Copyright (c) 2010 Zope Foundation and Contributors.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+import unittest
+
+from BTrees.IIBTree import IISet
+
+
+class Dummy(object):
+
+    def __init__(self, docid, truth):
+        self.id = docid
+        self.truth = truth
+
+
+class TestBooleanIndex(unittest.TestCase):
+
+    def _getTargetClass(self):
+        from Products.PluginIndexes.BooleanIndex import BooleanIndex
+        return BooleanIndex.BooleanIndex
+
+    def _makeOne(self, attr='truth'):
+        return self._getTargetClass()(attr)
+
+    def test_index_true(self):
+        index = self._makeOne()
+        obj = Dummy(1, True)
+        index._index_object(obj.id, obj, attr='truth')
+        self.failUnless(1 in index._unindex)
+        self.failUnless(1 in index._index)
+
+    def test_index_false(self):
+        index = self._makeOne()
+        obj = Dummy(1, False)
+        index._index_object(obj.id, obj, attr='truth')
+        self.failUnless(1 in index._unindex)
+        self.failIf(1 in index._index)
+
+    def test_search_true(self):
+        index = self._makeOne()
+        obj = Dummy(1, True)
+        index._index_object(obj.id, obj, attr='truth')
+        obj = Dummy(2, False)
+        index._index_object(obj.id, obj, attr='truth')
+
+        res, idx = index._apply_index({'truth': True})
+        self.failUnlessEqual(idx, ('truth', ))
+        self.failUnlessEqual(list(res), [1])
+
+    def test_search_false(self):
+        index = self._makeOne()
+        obj = Dummy(1, True)
+        index._index_object(obj.id, obj, attr='truth')
+        obj = Dummy(2, False)
+        index._index_object(obj.id, obj, attr='truth')
+
+        res, idx = index._apply_index({'truth': False})
+        self.failUnlessEqual(idx, ('truth', ))
+        self.failUnlessEqual(list(res), [2])
+
+    def test_search_inputresult(self):
+        index = self._makeOne()
+        obj = Dummy(1, True)
+        index._index_object(obj.id, obj, attr='truth')
+        obj = Dummy(2, False)
+        index._index_object(obj.id, obj, attr='truth')
+
+        res, idx = index._apply_index({'truth': True}, resultset=IISet([]))
+        self.failUnlessEqual(idx, ('truth', ))
+        self.failUnlessEqual(list(res), [])
+
+        res, idx = index._apply_index({'truth': True}, resultset=IISet([2]))
+        self.failUnlessEqual(idx, ('truth', ))
+        self.failUnlessEqual(list(res), [])
+
+        res, idx = index._apply_index({'truth': True}, resultset=IISet([1]))
+        self.failUnlessEqual(idx, ('truth', ))
+        self.failUnlessEqual(list(res), [1])
+
+        res, idx = index._apply_index({'truth': True}, resultset=IISet([1, 2]))
+        self.failUnlessEqual(idx, ('truth', ))
+        self.failUnlessEqual(list(res), [1])
+
+        res, idx = index._apply_index({'truth': False},
+                                      resultset=IISet([1, 2]))
+        self.failUnlessEqual(idx, ('truth', ))
+        self.failUnlessEqual(list(res), [2])
+
+
+def test_suite():
+    from unittest import TestSuite, makeSuite
+    suite = TestSuite()
+    suite.addTest(makeSuite(TestBooleanIndex))
+    return suite


Property changes on: Zope/trunk/src/Products/PluginIndexes/BooleanIndex/tests.py
___________________________________________________________________
Added: svn:eol-style
   + native

Modified: Zope/trunk/src/Products/PluginIndexes/__init__.py
===================================================================
--- Zope/trunk/src/Products/PluginIndexes/__init__.py	2010-09-25 21:57:29 UTC (rev 116948)
+++ Zope/trunk/src/Products/PluginIndexes/__init__.py	2010-09-25 22:03:22 UTC (rev 116949)
@@ -91,3 +91,17 @@
                           icon='www/index.gif',
                           visibility=None,
                          )
+
+    from Products.PluginIndexes.BooleanIndex.BooleanIndex import BooleanIndex
+    from Products.PluginIndexes.BooleanIndex.BooleanIndex import \
+        manage_addBooleanIndex
+    from Products.PluginIndexes.BooleanIndex.BooleanIndex import \
+        manage_addBooleanIndexForm
+
+    context.registerClass(BooleanIndex,
+                          permission='Add Pluggable Index',
+                          constructors=(manage_addBooleanIndexForm,
+                                        manage_addBooleanIndex),
+                          icon='www/index.gif',
+                          visibility=None,
+                         )



More information about the checkins mailing list