[Zope3-checkins] CVS: Zope3/src/zope/app/services - event.py:1.14

Steve Alexander steve@cat-box.net
Tue, 18 Feb 2003 10:19:23 -0500


Update of /cvs-repository/Zope3/src/zope/app/services
In directory cvs.zope.org:/tmp/cvs-serv5632/src/zope/app/services

Modified Files:
	event.py 
Log Message:
Fixed bug in event service where it was subscribing three times
to its parent event service. This was revealed by a unit test when the
erroneous 'Subscriptions' service id was replaced with the symbolic
constant. One bug had hidden the other. Symbolic service names are a
good idea.


=== Zope3/src/zope/app/services/event.py 1.13 => 1.14 ===
--- Zope3/src/zope/app/services/event.py:1.13	Fri Feb 14 18:06:08 2003
+++ Zope3/src/zope/app/services/event.py	Tue Feb 18 10:19:22 2003
@@ -85,8 +85,7 @@
         hubGet = getService(wrapped_self, HubIds).getObject
         pathGet = getAdapter(wrapped_self, ITraverser).traverse
 
-        badSubscribers = {}
-
+        badSubscribers = {}  # using a dict as a set
         for subscriptions in subscriptionsForEvent:
             for subscriber,filter in subscriptions:
                 if filter is not None and not filter(event):
@@ -95,13 +94,13 @@
                     try:
                         obj = hubGet(subscriber)
                     except NotFoundError:
-                        badSubscribers[subscriber] = 1
+                        badSubscribers[subscriber] = None
                         continue
                 else:
                     try:
                         obj = pathGet(subscriber)
                     except NotFoundError:
-                        badSubscribers[subscriber] = 1
+                        badSubscribers[subscriber] = None
                         continue
                 # Get an ISubscriber adapter in the context of the object
                 # This is probably the right context to use.
@@ -112,7 +111,7 @@
                 # adding this subscriber to badSubscribers is inappropriate.
                 getAdapter(obj, ISubscriber).notify(event)
 
-        for subscriber in badSubscribers.keys():
+        for subscriber in badSubscribers:
             # XXX this ought to be logged
             clean_self.unsubscribe(subscriber)
 
@@ -147,7 +146,7 @@
         # the name of the service that this object is providing, or
         # None if unbound
 
-    _subscribeToServiceName = "Subscriptions"
+    _subscribeToServiceName = Subscription
     _subscribeToServiceInterface = IEvent
     _subscribeToServiceFilter = None
 
@@ -165,10 +164,14 @@
         # this and the unbound code must be conditional for the
         # pertinent service that should trigger event subscription
         clean_self = removeAllProxies(wrapped_self)
-        clean_self._serviceName = name # for LocalServiceSubscribable
+        clean_self._serviceName = name  # for ServiceSubscribable
         if clean_self.subscribeOnBind:
             es = queryService(wrapped_self, clean_self._subscribeToServiceName)
             if es is not None:
+                if removeAllProxies(es) is clean_self:
+                    es = queryNextService(
+                        wrapped_self, clean_self._subscribeToServiceName)
+            if es is not None:
                 es.subscribe(
                     wrapped_self,
                     clean_self._subscribeToServiceInterface,
@@ -178,7 +181,9 @@
 
     def unbound(wrapped_self, name):
         "See IBindingAware"
-        # see comment in "bound" above
+        # Note: if a component is used for more than one service then
+        # this and the unbound code must be conditional for the
+        # pertinent service that should trigger event subscription
 
         clean_self = removeAllProxies(wrapped_self)
 
@@ -314,32 +319,34 @@
     def publish(wrapped_self, event):
         "see IEventPublisher"
         clean_self = removeAllProxies(wrapped_self)
-        clean_self._notify(wrapped_self, event)
 
-        publishedEvents = getattr(clean_self, "_v_publishedEvents", None)
-        if publishedEvents is None:
-            publishedEvents = clean_self._v_publishedEvents = [event]
-        else:
-            publishedEvents.append(event)
-        if (clean_self.isPromotableEvent(event)):
-            getNextService(wrapped_self, Events).publish(event)
-        publishedEvents.remove(event)
+        publishedEvents = getattr(clean_self, "_v_publishedEvents", [])
+        clean_self._v_publishedEvents = publishedEvents
+        publishedEvents.append(event)
+        try:
+            clean_self._notify(wrapped_self, event)
+            if clean_self.isPromotableEvent(event):
+                getNextService(wrapped_self, Events).publish(event)
+        finally:
+            publishedEvents.remove(event)
     publish = ContextMethod(publish)
 
     def notify(wrapped_self, event):
         "see ISubscriber"
         clean_self = removeAllProxies(wrapped_self)
-        publishedEvents = getattr(clean_self, "_v_publishedEvents", None)
-        if publishedEvents is None or event not in publishedEvents:
+        publishedEvents = getattr(clean_self, "_v_publishedEvents", [])
+        if event not in publishedEvents:
             clean_self._notify(wrapped_self, event)
     notify = ContextMethod(notify)
 
     def bound(wrapped_self, name):
         "See IBindingAware"
-        ContextSuper(EventService, wrapped_self).bound(name)
+        # An event service is bound as Subscription and as Events.
+        # We only want to subscribe to the next event service when we're bound
+        # as Subscription
         if name == Subscription:
             clean_self = removeAllProxies(wrapped_self)
-            clean_self._serviceName = name # for LocalServiceSubscribable
+            clean_self._serviceName = name  # for ServiceSubscribable
             if clean_self.subscribeOnBind:
                 try:
                     es = getNextService(wrapped_self, Subscription)
@@ -351,6 +358,9 @@
 
     def unbound(wrapped_self, name):
         "See IBindingAware"
+        # An event service is bound as Subscription and as Events.
+        # We only want to unsubscribe from the next event service when
+        # we're unbound as Subscription
         if name == Subscription:
             clean_self = removeAllProxies(wrapped_self)
             clean_self._v_unbinding = True