[Zope-Checkins] CVS: Zope3/lib/python/Zope/Event - EventChannel.py:1.2 GlobalEventService.py:1.2 IEvent.py:1.2 IEventChannel.py:1.2 IEventFilter.py:1.2 IEventService.py:1.2 IEventSet.py:1.2 IObjectEvent.py:1.2 ISubscribable.py:1.2 ISubscriber.py:1.2 ISubscriptionAware.py:1.2 Logger.py:1.2 ObjectEvent.py:1.2 Subscribable.py:1.2 __init__.py:1.2 event-meta.zcml:1.2 event.zcml:1.2 metaConfigure.py:1.2

Jim Fulton jim@zope.com
Mon, 10 Jun 2002 19:29:57 -0400


Update of /cvs-repository/Zope3/lib/python/Zope/Event
In directory cvs.zope.org:/tmp/cvs-serv20468/lib/python/Zope/Event

Added Files:
	EventChannel.py GlobalEventService.py IEvent.py 
	IEventChannel.py IEventFilter.py IEventService.py IEventSet.py 
	IObjectEvent.py ISubscribable.py ISubscriber.py 
	ISubscriptionAware.py Logger.py ObjectEvent.py Subscribable.py 
	__init__.py event-meta.zcml event.zcml metaConfigure.py 
Log Message:
Merged Zope-3x-branch into newly forked Zope3 CVS Tree.

=== Zope3/lib/python/Zope/Event/EventChannel.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 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.
+# 
+##############################################################################
+"""
+
+Revision information:
+$Id$
+"""
+
+from Subscribable import Subscribable
+from IEventChannel import IEventChannel
+
+class EventChannel(Subscribable):
+    
+    __implements__ = IEventChannel
+        
+    def notify(self, event):
+        
+        subscriptionses = self._registry.getAllForObject(event)
+
+        for subscriptions in subscriptionses:
+            
+            for subscriber,filter in subscriptions:
+                if filter is not None and not filter(event):
+                    continue
+                subscriber.notify(event)
+
+    
+
+    


=== Zope3/lib/python/Zope/Event/GlobalEventService.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 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.
+# 
+##############################################################################
+"""
+
+Revision information:
+$Id$
+"""
+
+from IEventService import IEventService
+from Subscribable import Subscribable
+
+class GlobalEventService(Subscribable):
+    
+    __implements__ = IEventService
+        
+    def publishEvent(self, event):
+        
+        subscriptionses = self._registry.getAllForObject(event)
+
+        for subscriptions in subscriptionses:
+            
+            for subscriber,filter in subscriptions:
+                if filter is not None and not filter(event):
+                    continue
+                subscriber.notify(event)
+    
+
+eventService = GlobalEventService()
+
+
+_clear = eventService._clear
+
+# Register our cleanup with Testing.CleanUp to make writing unit tests simpler.
+from Zope.Testing.CleanUp import addCleanUp
+addCleanUp(_clear)
+del addCleanUp


=== Zope3/lib/python/Zope/Event/IEvent.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 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.
+# 
+##############################################################################
+"""
+
+Revision information:
+$Id$
+"""
+
+from Interface import Interface
+
+class IEvent(Interface):
+    """The Base interface for Events"""


=== Zope3/lib/python/Zope/Event/IEventChannel.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 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.
+# 
+##############################################################################
+"""
+
+Revision information:
+$Id$
+"""
+
+from ISubscribable import ISubscribable
+from ISubscriber import ISubscriber
+
+class IEventChannel(ISubscribable, ISubscriber):
+    """Interface for objects which distribute events to subscribers. """
+    
+    


=== Zope3/lib/python/Zope/Event/IEventFilter.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 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.
+# 
+##############################################################################
+"""
+
+Revision information:
+$Id$
+"""
+
+from Interface import Interface
+
+class IEventFilter(Interface):
+    """Interface for predicates used to filter events."""
+
+    def __call__(event):
+        """Return true if event passes, or false."""


=== Zope3/lib/python/Zope/Event/IEventService.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 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.
+# 
+##############################################################################
+"""
+
+Revision information:
+$Id$
+"""
+
+from ISubscribable import ISubscribable
+
+class IEventService(ISubscribable):
+    """The EventService service is the 'root channel'.
+    
+    Its subscribers include other channels.
+
+    It is also the 'default destination' for events
+    when they are generated.
+    """
+    
+    def publishEvent(event):
+        """
+        Notify all subscribers of the channel of event.
+
+        Events will often be propagated to higher level IEventServices;
+        This is a policy decision for the IEventService.
+        """
+
+    
+
+    


=== Zope3/lib/python/Zope/Event/IEventSet.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 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.
+# 
+##############################################################################
+"""
+
+Revision information:
+$Id$
+"""
+
+from Interface import Interface
+
+class IEventSet(ISubscriber):
+    """An unordered collection of location-independent events."""
+
+    def size():
+        """Returns the number of events stored."""
+
+    def get(n=None):
+        """Returns a collection of events.
+
+        This must be iteratable.
+        """


=== Zope3/lib/python/Zope/Event/IObjectEvent.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 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.
+# 
+##############################################################################
+"""
+
+Revision information:
+$Id$
+"""
+
+from IEvent import IEvent
+
+class IObjectEvent(IEvent):
+    """Something has happened to an object.
+
+    The object that generated this event is not necessarily the object
+    refered to by getLocation.
+    """
+
+    def getLocation():        
+        """returns the object location."""
+
+class IObjectAddedEvent(IObjectEvent):
+    """An object has been added to a container."""
+
+    def getLocation():        
+        """returns the object location after it has been added to the container"""
+
+class IObjectModifiedEvent(IObjectEvent):
+    """An object has been modified"""
+
+class IObjectRemovedEvent(IObjectEvent):
+    """An object has been removed from a container"""
+    
+    def getLocation():
+        """location of the object before it was removed"""
+        
+    def getObject():
+        """the object that was removed"""
+
+class IObjectMovedEvent(IObjectEvent):
+    """An object has been moved"""
+
+    def getFromLocation():
+        """location of the object before it was moved"""
+
+    def getLocation():
+        """location of the object after it was moved"""


=== Zope3/lib/python/Zope/Event/ISubscribable.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 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.
+# 
+##############################################################################
+"""
+
+Revision information:
+$Id$
+"""
+
+from Interface import Interface
+from IEvent import IEvent
+
+class ISubscribable(Interface):
+    """Objects that broadcast events to subscribers."""
+
+    def subscribe(subscriber, event_type=IEvent, filter=None):
+        """Add subscriber to the list of subscribers for the channel.
+        
+        subscriber must implement ISubscriber.
+        Probable subscriber types include the following:
+        
+            o Hard Reference (for placeless, global objects and event service)
+
+                Simply register the subscriber directly, in which case, the
+                subscription, and possibly the subscriber, is as persistent as the
+                subscribable.  The subscriber will not be wrapped for context
+                or security when called.
+
+            o Soft reference (for placeful, local objects and event service)
+
+                Register an object with a notify method and a path that
+                dereferences the path and delegates notifications.
+
+            o Location-independent reference (for placeful)
+
+                Register an object with a notify method and an ObjectHub ruid that
+                dereferences the ruid via the hub and delegates notifications.
+
+            o Abstract reference (for both)
+
+                Register an object with a notify method and an IReference that
+                dereferences the IReference and delegates notifications.
+        
+        event_type, if supplied, is the event interface
+        about which subscriber should be notified, and must implement
+        IEvent.  The subscriber will be notified of all events of this
+        event_type and of subclasses of this event_type.
+        The default value, IEvent, as the parent type,
+        is effectively a single catch-all event type that will pass all
+        event types to the subscriber.
+
+        filter, if supplied, must implement IEventFilter; subscriber
+        will be notified of events only if they pass.
+
+        A subscriber may subscribe more than once, even if it has
+        already been subscribed with the same event type and
+        filter.  In this case the subscriber will receive multiple
+        calls to its notify method.
+        
+        If the subscriber implements ISubscriptionAware, this function
+        will call the subscriber's subscribedTo method.
+        """
+        
+    def unsubscribe(subscriber, event_type=None, filter=None):
+        """Unsubscribe subscriber from receiving event types from this
+        subscribable.
+        
+        The subscriber is matched via equality (not identity).
+        
+        If event_type is None, the default value, the subscriber is
+        unsubscribed completely for all event types from this
+        subscribable (and its parents, if the subscribable is a placeful
+        service).  If no subscriptions for this subscriber are
+        present, no error is raised.
+        
+        if event_type is supplied, this method will unsubscribe the
+        subscriber from one subscription exactly matching the
+        event_type/filter pair given (the default filter being None).
+        If other subscriptions are present they will remain.  If the
+        subscription cannot be found and the subscribable is a placeful
+        service, the unsubscription request is passed to parent
+        services.  Raises Zope.Exceptions.NotFound if subscriber wasn't 
+        subscribed as expected.
+        
+        If the subscriber implements ISubscriptionAware, this function
+        will call the subscriber's unsubscribedFrom method for each
+        individual unsubscribe.
+        """
+        
+    def listSubscriptions(subscriber, event_type=None):
+        """returns an iterator of the subscriptions to this channel for
+        the subscriber. if event_type is supplied, the list is limited
+        to that exact event_type.  If the subscribable is a placeful
+        service, the list will include subscriptions to parent services.
+        The subscriber is matched via equality (not identity).  No
+        subscriptions returns an empty iterator.  Each subscription is
+        represented as a tuple (event_type, filter)."""


=== Zope3/lib/python/Zope/Event/ISubscriber.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 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.
+# 
+##############################################################################
+"""
+
+Revision information:
+$Id$
+"""
+
+from Interface import Interface
+
+class ISubscriber(Interface):
+    """Interface for objects which receiving event notifications."""
+
+    def notify(event):
+        """ISubscribables call this method to indicate an event.
+
+        This method must not block!
+
+        This method may raise an exception to veto the event.
+        """
+
+class IIndirectSubscriber(ISubscriber):
+    """Interface for objects that handle subscriptions for another object"""
+    
+    def __eq__(other):
+        """this standard python hook allows indirect subscribers to
+        participate in subscribable introspection and unsubscription
+        without being the actual original subscriber object"""
+
+    
+    


=== Zope3/lib/python/Zope/Event/ISubscriptionAware.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 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.
+# 
+##############################################################################
+"""
+
+Revision information:
+$Id$
+"""
+from Interface import Interface
+
+# these are calls and not events because they are traditional messages
+# between two objects, not events of general interest.
+
+class ISubscriptionAware(Interface):
+    
+    def subscribedTo(subscribable, event_type, filter):
+        """alerts the object that it has subscribed, via a call from
+        itself or from another object, to the subscribable.  The
+        event_type and filter match the arguments provided to the
+        ISubscribable.subscribe.
+        
+        The subscribable must be appropriately placefully wrapped (note
+        that the global event service will have no wrapping)."""
+    
+    def unsubscribedFrom(subscribable, event_type, filter):
+        """alerts the object that it has unsubscribed, via a call from
+        itself or from another object, to the subscribable.  The
+        event_type and filter match the exact event_type and filter of
+        the deleted subscription, rather than, necessarily, the
+        arguments provided to the ISubscribable.unsubscribe.
+        
+        The subscribable must be appropriately placefully wrapped (note
+        that the global event service will have no wrapping)."""
\ No newline at end of file


=== Zope3/lib/python/Zope/Event/Logger.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 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.
+# 
+##############################################################################
+"""
+
+Revision information:
+$Id$
+"""
+
+from ISubscriber import ISubscriber
+from zLOG import LOG,BLATHER
+from pprint import pprint
+from StringIO import StringIO
+
+class Logger:
+
+    __implements__ = ISubscriber
+
+    def __init__(self,severity=BLATHER):
+        self.severity = severity
+        
+    def notify(self, event):
+        c = event.__class__
+        detail = StringIO()
+        pprint (event.__dict__,detail)
+        LOG('Event.Logger',
+            self.severity,
+            c.__module__+'.'+c.__name__,
+            detail.getvalue())
+        
+    


=== Zope3/lib/python/Zope/Event/ObjectEvent.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 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.
+# 
+##############################################################################
+"""
+
+Revision information:
+$Id$
+"""
+
+from IObjectEvent import IObjectAddedEvent, IObjectModifiedEvent
+from IObjectEvent import IObjectRemovedEvent, IObjectMovedEvent
+
+class ObjectAddedEvent:
+    """An object has been added to a container."""
+
+    __implements__ = IObjectAddedEvent
+
+    def __init__(self, location):
+        self.__location = location
+        
+    def getLocation(self):        
+        """returns the object location after it has been added to the container"""
+        return self.__location
+
+class ObjectModifiedEvent(ObjectAddedEvent):
+    """An object has been modified"""
+
+    __implements__ = IObjectModifiedEvent
+
+class ObjectRemovedEvent:
+    """An object has been removed from a container"""
+
+    __implements__ = IObjectRemovedEvent
+
+
+    def __init__(self, location, obj):
+        self.__location = location
+        self.__obj = obj
+        
+    def getLocation(self):        
+        """returns the location the object was removed from"""
+        return self.__location
+        
+    def getObject(self):
+        """returns the object that was removed."""
+        return self.__obj
+
+
+class ObjectMovedEvent(ObjectAddedEvent):
+    """An object has been moved"""
+
+    __implements__ = IObjectMovedEvent
+
+    def __init__(self, from_location, location):
+        ObjectAddedEvent.__init__(self, location)
+        self.__from_location = from_location
+        
+    def getFromLocation(self):
+        """location of the object before it was moved"""
+        return self.__from_location


=== Zope3/lib/python/Zope/Event/Subscribable.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 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.
+# 
+##############################################################################
+"""
+
+Revision information:
+$Id$
+"""
+
+from Zope.ComponentArchitecture.IToIRegistry import TypeRegistry
+from Zope.Exceptions import NotFoundError
+from ISubscribable import ISubscribable
+from ISubscriptionAware import ISubscriptionAware
+from IEvent import IEvent
+from Zope.Proxy.ProxyIntrospection import removeAllProxies
+
+class Subscribable(object): # do we need this to be a type?
+    """a global mix-in"""
+    
+    __implements__=ISubscribable
+
+    def __init__(self):
+        self._registry = TypeRegistry()
+        self._subscribers = [] # using an array rather than a dict so
+        # that subscribers may define custom __eq__ methods
+        
+    _clear = __init__
+
+    def subscribe(self, subscriber, event_type=IEvent, filter=None):
+        
+        clean_subscriber=removeAllProxies(subscriber)
+        
+        if ISubscriptionAware.isImplementedBy(subscriber):
+            subscriber.subscribedTo(self, event_type, filter)
+        
+        ev_type=event_type
+        if ev_type is IEvent: ev_type=None # optimization
+        
+        subscribers = self._registry.getJustForType(ev_type)
+        if subscribers is None:
+            subscribers = []
+            self._registry.register(ev_type, subscribers)
+        subscribers.append((clean_subscriber, filter))
+
+        subs = self._subscribers
+        for sub in subs:
+            if sub[0]==clean_subscriber:
+                sub[1][ev_type]=1
+                break
+        else:
+            subs.append((clean_subscriber,{ev_type:1}))
+        
+        self._registry=self._registry #trigger persistence, if pertinent
+        
+    
+    def unsubscribe(self, subscriber, event_type=None, filter=None):
+        
+        clean_subscriber=removeAllProxies(subscriber)
+        
+        for subscriber_index in range(len(self._subscribers)):
+            sub=self._subscribers[subscriber_index]
+            if sub[0]==clean_subscriber:
+                ev_set=sub[1]
+                break
+        else:
+            if event_type: raise NotFoundError(subscriber)
+            else: return # this was a generic unsubscribe all request;
+            # work may have been done by a local service
+        
+        
+        do_alert=ISubscriptionAware.isImplementedBy(clean_subscriber)
+        
+        if event_type:
+            ev_type=event_type
+            if event_type is IEvent:
+                ev_type=None # handle optimization
+            if ev_type not in ev_set:
+                raise NotFoundError(subscriber, event_type, filter)
+            subscriptions = self._registry.getJustForType(ev_type)
+            if not subscriptions:
+                raise NotFoundError(subscriber, event_type, filter)
+            try: 
+                subscriptions.remove((clean_subscriber, filter))
+            except ValueError:
+                raise NotFoundError(subscriber, event_type, filter)
+            if do_alert:
+                subscriber.unsubscribedFrom(self, event_type, filter)
+            if len(ev_set)==1:
+                for sub in subscriptions:
+                    if sub[0]==clean_subscriber:
+                        break
+                else:
+                    del self._subscribers[subscriber_index]
+        else:
+            for ev_type in ev_set:
+                subscriptions = self._registry.getJustForType(ev_type)
+                subs=subscriptions[:]
+                subscriptions[:] = []
+                for sub in subs:
+                    if sub[0] == clean_subscriber: # deleted (not added back)
+                        if do_alert:
+                            subscriber.unsubscribedFrom(
+                                self, ev_type or IEvent, sub[1])
+                            # IEvent switch is to make optimization transparent
+                    else: # kept (added back)
+                        subscriptions.append(sub)
+            del self._subscribers[subscriber_index]
+        self._registry=self._registry #trigger persistence, if pertinent
+    
+    def listSubscriptions(self, subscriber, event_type=None):
+        
+        subscriber=removeAllProxies(subscriber)
+        
+        result=[]
+        if event_type:
+            ev_type=event_type
+            if event_type is IEvent:
+                ev_type=None # handle optimization
+            subscriptions = self._registry.getJustForType(ev_type)
+            if subscriptions:
+                for sub in subscriptions:
+                    if sub[0]==subscriber:
+                        result.append((event_type, sub[1]))
+        else:
+            for subscriber_index in range(len(self._subscribers)):
+                sub=self._subscribers[subscriber_index]
+                if sub[0]==subscriber:
+                    ev_set=sub[1]
+                    break
+            else:
+                return result
+            for ev_type in ev_set:
+                subscriptions = self._registry.getJustForType(ev_type)
+                if subscriptions:
+                    for sub in subscriptions:
+                        if sub[0]==subscriber:
+                            result.append((ev_type or IEvent, sub[1]))
+        return result
\ No newline at end of file


=== Zope3/lib/python/Zope/Event/__init__.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 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.
+# 
+##############################################################################
+"""
+
+Revision information:
+$Id$
+"""
+
+from Zope.ComponentArchitecture import getService
+from IEvent import IEvent
+
+
+def getEventService(context):
+    return getService(context, 'Events')
+
+def publishEvent(context, event):
+    return getEventService(context).publishEvent(event)
+
+def subscribe(subscriber, event_type=IEvent, filter=None, context=None):
+    if context is None: context=subscriber
+    return getEventService(context).subscribe(
+        subscriber, event_type, filter)
+
+def subscribeMany(subscriber, event_types=(IEvent,), filter=None, context=None):
+    if context is None: context=subscriber
+    es= getEventService(context).subscribe
+    for event_type in event_types:
+        es(subscriber, event_type, filter)
+
+def unsubscribe(subscriber, event_type=None, filter=None, context=None):
+    if context is None: context=subscriber
+    return getEventService(context).unsubscribe(
+        subscriber, event_type, filter)
+
+def listSubscriptions(subscriber, event_type=None, context=None):
+    if context is None: context=subscriber
+    return getEventService(context).listSubscriptions(
+        subscriber, event_type)
+
+
+
+def _clear():
+    from EventService import _clear; _clear()


=== Zope3/lib/python/Zope/Event/event-meta.zcml 1.1 => 1.2 ===
+  
+  <!-- Zope.Event -->
+  <directives namespace="http://namespaces.zope.org/event">
+    <directive name="subscribe" attributes="subscriber event_types filter"
+       handler="Zope.Event.metaConfigure.subscribe" />
+  </directives>
+
+
+</zopeConfigure>
+
+


=== Zope3/lib/python/Zope/Event/event.zcml 1.1 => 1.2 ===
+   xmlns='http://namespaces.zope.org/zope'
+   xmlns:security='http://namespaces.zope.org/security'
+   xmlns:zmi='http://namespaces.zope.org/zmi'
+   xmlns:browser='http://namespaces.zope.org/browser'
+>
+
+<serviceType id='Events' 
+             interface='Zope.Event.IEventService.' />
+
+<service serviceType='Events'
+         component='Zope.Event.GlobalEventService.eventService' />
+
+</zopeConfigure>


=== Zope3/lib/python/Zope/Event/metaConfigure.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 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.
+# 
+##############################################################################
+"""
+
+Revision information:
+$Id$
+"""
+
+from Zope.Configuration.Action import Action
+
+from Zope.Event import subscribeMany
+from Zope.Event.IEvent import IEvent
+
+counter = 0
+
+def subscribe(_context, subscriber, event_types=(IEvent,), filter=None):
+    global counter
+    counter += 1
+
+    subscriber = _context.resolve(subscriber)
+
+    event_type_names = event_types
+    event_types=[]
+    for event_type_name in event_type_names.split():
+        event_types.append(_context.resolve(event_type_name))
+                        
+    if filter is not None:
+        filter = _context.resolve(filter)
+
+    return [
+        Action(
+             # subscriptions can never conflict
+             discriminator = ('subscribe', counter),
+             callable = subscribeMany,
+             args = (subscriber, event_types, filter)
+             )
+        ]