[Zope-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 Zope-Checkins
mailing list