[Zope3-checkins] SVN: Zope3/branches/jim-indexing/src/zope/app/index/ Removed subscription responsibilities from indexes.

Jim Fulton jim at zope.com
Tue May 25 08:27:17 EDT 2004


Log message for revision 24957:

Removed subscription responsibilities from indexes.
Indexes are no-longer subscribers.  

Also moved the code out of the __init__.py module.




-=-
Modified: Zope3/branches/jim-indexing/src/zope/app/index/browser/field/control.pt
===================================================================
--- Zope3/branches/jim-indexing/src/zope/app/index/browser/field/control.pt	2004-05-25 10:05:18 UTC (rev 24956)
+++ Zope3/branches/jim-indexing/src/zope/app/index/browser/field/control.pt	2004-05-25 12:27:16 UTC (rev 24957)
@@ -20,17 +20,6 @@
       information but not update itself further.
   </p>
 
-  <!-- XXX: Too much logic for a template -->
-  <span tal:condition="request/callSubscribe|nothing" tal:omit-tag="">
-    <span tal:define="dummy context/subscribe" tal:omit-tag=""/>
-    <span i18n:translate="">Successfully subscribed.</span>
-  </span>
-
-  <span tal:condition="request/callUnsubscribe|nothing" tal:omit-tag="">
-    <span tal:define="dummy context/unsubscribe" tal:omit-tag=""/>
-    <span i18n:translate="">Successfully unsubscribed.</span>
-  </span>
-
   <div tal:condition="context/interface" i18n:translate="">
     Adapting objects to: 
     <span tal:replace="view/interface_name" i18n:name="iface_name" />
@@ -46,21 +35,6 @@
     <span tal:replace="context/documentCount" i18n:name="doc_count"/>
   </div>
 
-  <form method="POST">
-    <span tal:condition="context/isSubscribed" tal:omit-tag="">
-      <span i18n:translate="">Subscription state: ON</span>
-      <input type="submit" value="Unsubscribe" name="callUnsubscribe" 
-             i18n:attributes="value unsubscribe-button"/>
-     </span>
-     <span tal:condition="not:context/isSubscribed" tal:omit-tag="">
-       <span i18n:translate="">Subscription state: OFF</span>
-       <input type="submit" value="Subscribe" name="callSubscribe"
-              i18n:attributes="value subscribe-button"/>
-     </span>
-     <input type="hidden" name="queryText" value=""
-            tal:attributes="value request/queryText|nothing" />
-  </form>
-
   <form method="GET">
     <input type="text" name="queryText" value=""
            tal:attributes="value request/queryText|nothing" />

Modified: Zope3/branches/jim-indexing/src/zope/app/index/browser/text/control.pt
===================================================================
--- Zope3/branches/jim-indexing/src/zope/app/index/browser/text/control.pt	2004-05-25 10:05:18 UTC (rev 24956)
+++ Zope3/branches/jim-indexing/src/zope/app/index/browser/text/control.pt	2004-05-25 12:27:16 UTC (rev 24957)
@@ -20,17 +20,6 @@
         information but not update itself further.
     </p>
 
-  <!-- XXX: Too much logic for a template -->
-  <span tal:condition="request/callSubscribe|nothing" tal:omit-tag="">
-    <span tal:define="dummy context/subscribe" tal:omit-tag=""/>
-    <span i18n:translate="">Successfully subscribed.</span>
-  </span>
-
-  <span tal:condition="request/callUnsubscribe|nothing" tal:omit-tag="">
-    <span tal:define="dummy context/unsubscribe" tal:omit-tag=""/>
-    <span i18n:translate="">Successfully unsubscribed.</span>
-  </span>
-
   <div i18n:translate="">
     Documents: 
     <span tal:replace="context/documentCount" i18n:name="doc_count"/>
@@ -41,21 +30,6 @@
     <span tal:replace="context/wordCount" i18n:name="word_count"/>
   </div>
 
-  <form method="POST">
-    <span tal:condition="context/isSubscribed" tal:omit-tag="">
-      <span i18n:translate="">Subscription state: ON</span>
-      <input type="submit" value="Unsubscribe" name="callUnsubscribe" 
-             i18n:attributes="value unsubscribe-button"/>
-     </span>
-     <span tal:condition="not:context/isSubscribed" tal:omit-tag="">
-       <span i18n:translate="">Subscription state: OFF</span>
-       <input type="submit" value="Subscribe" name="callSubscribe"
-              i18n:attributes="value subscribe-button"/>
-     </span>
-     <input type="hidden" name="queryText" value=""
-            tal:attributes="value request/queryText|nothing" />
-  </form>
-
   <form method="GET">
     <input type="text" name="queryText" value=""
            tal:attributes="value request/queryText|nothing" />

Modified: Zope3/branches/jim-indexing/src/zope/app/index/field/index.py
===================================================================
--- Zope3/branches/jim-indexing/src/zope/app/index/field/index.py	2004-05-25 10:05:18 UTC (rev 24956)
+++ Zope3/branches/jim-indexing/src/zope/app/index/field/index.py	2004-05-25 12:27:16 UTC (rev 24957)
@@ -11,13 +11,8 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
-"""This is a field index which can be subscribed to an event service.
+"""This is a field index
 
-Events related to object creation and deletion are translated into
-index_doc() and unindex_doc() calls.
-
-In addition, this implements TTW subscription management.
-
 $Id$
 """
 from zope.component import getService
@@ -29,7 +24,7 @@
 from zope.app.hub.interfaces import IRegistrationHubEvent
 from zope.app.index.interfaces.field import IUIFieldIndex, IUIFieldCatalogIndex
 from zope.app.catalog.interfaces.index import ICatalogIndex
-from zope.app.index import InterfaceIndexingSubscriber
+from zope.app.index.ifaceindex import InterfaceIndexingSubscriber
 
 class FieldCatalogIndex(InterfaceIndexingSubscriber, FieldIndexWrapper,
                         Contained):
@@ -39,36 +34,3 @@
 
     implements(IUIFieldIndex)
 
-    currentlySubscribed = False # Default subscription state
-
-    def subscribe(self, channel=None, update=True):
-        if self.currentlySubscribed:
-            raise RuntimeError, "already subscribed; please unsubscribe first"
-        channel = self._getChannel(channel)
-        channel.subscribe(self, IRegistrationHubEvent)
-        channel.subscribe(self, IObjectModifiedHubEvent)
-        if update:
-            self._update(channel.iterObjectRegistrations())
-        self.currentlySubscribed = True
-
-    def unsubscribe(self, channel=None):
-        if not self.currentlySubscribed:
-            raise RuntimeError, "not subscribed; please subscribe first"
-        channel = self._getChannel(channel)
-        channel.unsubscribe(self, IObjectModifiedHubEvent)
-        channel.unsubscribe(self, IRegistrationHubEvent)
-        self.currentlySubscribed = False
-
-    def isSubscribed(self):
-        return self.currentlySubscribed
-
-    def _getChannel(self, channel):
-        if channel is None:
-            channel = getService(self, HubIds)
-        return channel
-
-    def _update(self, registrations):
-        for location, hubid, wrapped_object in registrations:
-            value = self._getValue(wrapped_object)
-            if value is not None:
-                self.index_doc(hubid, value)

Copied: Zope3/branches/jim-indexing/src/zope/app/index/ifaceindex.py (from rev 24956, Zope3/branches/jim-indexing/src/zope/app/index/__init__.py)
===================================================================
--- Zope3/branches/jim-indexing/src/zope/app/index/__init__.py	2004-05-25 10:05:18 UTC (rev 24956)
+++ Zope3/branches/jim-indexing/src/zope/app/index/ifaceindex.py	2004-05-25 12:27:16 UTC (rev 24957)
@@ -0,0 +1,137 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+"""
+$Id$
+"""
+from zope.interface import implements
+from zope.app.index.interfaces import IInterfaceIndexer
+
+class InterfaceIndexingSubscriber(object):
+    """Index interface-defined fields
+
+       Mixin for indexing a particular field name, after first adapting the
+       object to be indexed to an interface.
+
+       The class is meant to be mixed with a base class that defines an
+       index_doc method:
+       
+         >>> class BaseIndex(object):
+         ...     def __init__(self):
+         ...         self.data = []
+         ...     def index_doc(self, id, value):
+         ...         self.data.append((id, value))
+
+       The class does two things. The first is to get a named field
+       from an object:
+
+         >>> class Data:
+         ...     def __init__(self, v):
+         ...         self.x = v
+
+         >>> class Index(InterfaceIndexingSubscriber, BaseIndex):
+         ...     pass
+
+         >>> index = Index('x')
+         >>> index.index_doc(11, Data(1))
+         >>> index.index_doc(22, Data(2))
+         >>> index.data
+         [(11, 1), (22, 2)]
+
+       A method can be indexed:
+
+         >>> Data.z = lambda self: self.x + 20
+         >>> index = Index('z')
+         >>> index.index_doc(11, Data(1))
+         >>> index.index_doc(22, Data(2))
+         >>> index.data
+         [(11, 21), (22, 22)]
+         
+       The class can also adapt an object to an interface:
+
+         >>> from zope.interface import Interface
+         >>> class I(Interface):
+         ...     pass
+
+         >>> class Data:
+         ...     def __init__(self, v):
+         ...         self.x = v
+         ...     def __conform__(self, iface):
+         ...         if iface is I:
+         ...             return Data2(self.x)
+
+         >>> class Data2:
+         ...     def __init__(self, v):
+         ...         self.y = v*v
+         
+         >>> index = Index('y', I)
+         >>> index.index_doc(11, Data(3))
+         >>> index.index_doc(22, Data(2))
+         >>> index.data
+         [(11, 9), (22, 4)]
+
+       When you define an index class, you can define a default
+       interface and/or a default interface:
+
+         >>> class Index(InterfaceIndexingSubscriber, BaseIndex):
+         ...     default_interface = I
+         ...     default_field_name = 'y'
+        
+         >>> index = Index()
+         >>> index.index_doc(11, Data(3))
+         >>> index.index_doc(22, Data(2))
+         >>> index.data
+         [(11, 9), (22, 4)]
+
+       """
+    implements(IInterfaceIndexer)
+    default_field_name = None
+    default_interface = None
+
+    def __init__(self, field_name=None, interface=None):
+        super(InterfaceIndexingSubscriber, self).__init__()
+        if field_name is None and self.default_field_name is None:
+            raise ValueError, "Must pass a field_name"
+        if field_name is None:
+            self._field_name = self.default_field_name
+        else:
+            self._field_name = field_name
+        if interface is None:
+            self._interface = self.default_interface
+        else:
+            self._interface = interface
+
+    field_name = property(lambda self: self._field_name)
+    interface = property(lambda self: self._interface)
+
+    def _getValue(self, object):
+        if self._interface is not None:
+            object = self._interface(object, None)
+            if object is None:
+                return None
+
+        value = getattr(object, self._field_name, None)
+        if value is None:
+            return None
+
+        if callable(value):
+            try:
+                value = value()
+            except:
+                return None
+
+        return value
+        
+    def index_doc(self, docid, object):
+        value = self._getValue(object)
+        return super(InterfaceIndexingSubscriber, self).index_doc(docid, value)

Added: Zope3/branches/jim-indexing/src/zope/app/index/tests/test_ifaceindex.py
===================================================================
--- Zope3/branches/jim-indexing/src/zope/app/index/tests/test_ifaceindex.py	2004-05-25 10:05:18 UTC (rev 24956)
+++ Zope3/branches/jim-indexing/src/zope/app/index/tests/test_ifaceindex.py	2004-05-25 12:27:16 UTC (rev 24957)
@@ -0,0 +1,28 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+"""Test interface indexers
+
+$Id$
+"""
+import unittest
+from zope.testing.doctestunit import DocTestSuite
+
+def test_suite():
+    return unittest.TestSuite((
+        DocTestSuite('zope.app.index.ifaceindex'),
+        ))
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')
+


Property changes on: Zope3/branches/jim-indexing/src/zope/app/index/tests/test_ifaceindex.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Modified: Zope3/branches/jim-indexing/src/zope/app/index/text/index.py
===================================================================
--- Zope3/branches/jim-indexing/src/zope/app/index/text/index.py	2004-05-25 10:05:18 UTC (rev 24956)
+++ Zope3/branches/jim-indexing/src/zope/app/index/text/index.py	2004-05-25 12:27:16 UTC (rev 24957)
@@ -11,11 +11,8 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
-"""This is a text index which can be subscribed to an event service.
+"""This is a text index
 
-Events related to object creation and deletion are translated into
-index_doc() and unindex_doc() calls.
-
 In addition, this implements TTW subscription management.
 
 $Id$
@@ -30,7 +27,7 @@
 from zope.app.index.interfaces.text import ISearchableText
 from zope.app.index.interfaces.text import IUITextIndex, IUITextCatalogIndex
 from zope.interface import implements
-from zope.app.index import InterfaceIndexingSubscriber
+from zope.app.index.ifaceindex import InterfaceIndexingSubscriber
 from zope.app.catalog.interfaces.index import ICatalogIndex
 
 
@@ -45,37 +42,4 @@
 
     implements(IUITextIndex)
 
-    currentlySubscribed = False # Default subscription state
 
-    def subscribe(wrapped_self, channel=None, update=True):
-        if wrapped_self.currentlySubscribed:
-            raise RuntimeError, "already subscribed; please unsubscribe first"
-        channel = wrapped_self._getChannel(channel)
-        channel.subscribe(wrapped_self, IRegistrationHubEvent)
-        channel.subscribe(wrapped_self, IObjectModifiedHubEvent)
-        if update:
-            wrapped_self._update(channel.iterObjectRegistrations())
-        wrapped_self.currentlySubscribed = True
-
-    def unsubscribe(wrapped_self, channel=None):
-        if not wrapped_self.currentlySubscribed:
-            raise RuntimeError, "not subscribed; please subscribe first"
-        channel = wrapped_self._getChannel(channel)
-        channel.unsubscribe(wrapped_self, IObjectModifiedHubEvent)
-        channel.unsubscribe(wrapped_self, IRegistrationHubEvent)
-        wrapped_self.currentlySubscribed = False
-
-    def isSubscribed(self):
-        return self.currentlySubscribed
-
-    def _getChannel(wrapped_self, channel):
-        if channel is None:
-            channel = getService(wrapped_self, HubIds)
-        return channel
-
-    def _update(wrapped_self, registrations):
-        for location, hubid, wrapped_object in registrations:
-            texts = wrapped_self._getValue(wrapped_object)
-            if texts is not None:
-                wrapped_self.index_doc(hubid, texts)
-

Deleted: Zope3/branches/jim-indexing/src/zope/app/index/text/tests/test_index.py
===================================================================
--- Zope3/branches/jim-indexing/src/zope/app/index/text/tests/test_index.py	2004-05-25 10:05:18 UTC (rev 24956)
+++ Zope3/branches/jim-indexing/src/zope/app/index/text/tests/test_index.py	2004-05-25 12:27:16 UTC (rev 24957)
@@ -1,144 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (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.
-#
-##############################################################################
-"""Tests for text index.
-
-$Id$
-"""
-
-import unittest
-
-from zope.app.event.objectevent import ObjectModifiedEvent
-from zope.app.site.tests.placefulsetup import PlacefulSetup
-from zope.app.traversing import traverse
-from zope.component import getService
-from zope.app.servicenames import HubIds
-from zope.app.hub.interfaces import \
-     IRegistrationHubEvent, IObjectModifiedHubEvent
-from zope.app.hub import \
-     ObjectRegisteredHubEvent, ObjectUnregisteredHubEvent, \
-     ObjectModifiedHubEvent
-
-from zope.app.index.interfaces.text import ISearchableText
-from zope.app.index.text.index import TextIndex
-from zope.interface import implements
-
-
-class FakeSearchableObject:
-    implements(ISearchableText)
-    def __init__(self):
-        self.texts = [u"Bruce"]
-    def getSearchableText(self):
-        return self.texts
-
-Bruce = u"Bruce"
-Sheila = u"Sheila"
-
-class Test(PlacefulSetup, unittest.TestCase):
-
-    def setUp(self):
-        PlacefulSetup.setUp(self, site=True)
-        self.index = TextIndex()
-        self.rootFolder['myIndex'] = self.index
-        self.rootFolder['bruce'] = FakeSearchableObject()
-        self.object = self.rootFolder['bruce']
-
-    def assertPresent(self, word, docid):
-        results, total = self.index.query(word)
-        self.assertEqual(total, 1)
-        self.assertEqual(results[0][0], docid)
-
-    def assertAbsent(self, word):
-        self.assertEqual(self.index.query(word), ([], 0))
-
-    def testNotification(self):
-        docid = 1000
-        event = ObjectRegisteredHubEvent(None, docid, object=self.object)
-        self.index.notify(event)
-        self.assertPresent(Bruce, docid)
-
-        self.object.texts = [Sheila]
-        event = ObjectModifiedHubEvent(None, docid, object=self.object)
-        self.index.notify(event)
-        self.assertPresent(Sheila, docid)
-        self.assertAbsent(Bruce)
-
-        event = ObjectUnregisteredHubEvent(None, docid,
-                                           location="fake",
-                                           object=self.object)
-        self.index.notify(event)
-        self.assertAbsent(Bruce)
-        self.assertAbsent(Sheila)
-
-    def testNotIndexing(self):
-        docid = 1000
-        self.object.texts = None
-        event = ObjectRegisteredHubEvent(None, docid, object=self.object)
-        self.index.notify(event)
-        self.assertEqual(self.index.documentCount(), 0)
-
-    def testHubMachinery(self):
-        # Technically this is a functional test
-        self.createStandardServices()
-        index = traverse(self.rootFolder, '/myIndex')
-        hub = getService(self.rootFolder, HubIds)
-        
-        hub.subscribe(index, IRegistrationHubEvent)
-        hub.subscribe(index, IObjectModifiedHubEvent)
-        location = "/bruce"
-
-        hubid = hub.register(location)
-        self.assertPresent(Bruce, hubid)
-
-        self.object.texts = [Sheila]
-        event = ObjectModifiedEvent(self.object)
-        hub.notify(event)
-        self.assertPresent(Sheila, hubid)
-        self.assertAbsent(Bruce)
-
-        hub.unregister(location)
-        self.assertAbsent(Bruce)
-        self.assertAbsent(Sheila)
-
-    def testBootstrap(self):
-        # Need to set up a HubIds service because the standard subscription
-        # mix-ins expect to see one.
-        self.createStandardServices()
-    
-        index = traverse(self.rootFolder, '/myIndex')
-        self.assertEqual(index.isSubscribed(), False)
-        self.assertAbsent(Bruce)
-        self.assertAbsent(Sheila)
-        location = '/bruce'
-        hub = getService(self.rootFolder, HubIds)
-        hubid = hub.register(location)
-        index.subscribe(hub)
-        self.assertEqual(index.isSubscribed(), True)
-        self.assertPresent(Bruce, hubid)
-
-        index.unsubscribe(hub)
-        self.assertEqual(index.isSubscribed(), False)
-        self.assertPresent(Bruce, hubid)
-
-        self.object.texts = [Sheila]
-        event = ObjectModifiedEvent(self.object)
-        hub.notify(event)
-        self.assertPresent(Bruce, hubid)
-        self.assertAbsent(Sheila)
-
-
-def test_suite():
-    return unittest.makeSuite(Test)
-
-if __name__=='__main__':
-    unittest.main(defaultTest='test_suite')




More information about the Zope3-Checkins mailing list