[Zope3-checkins] CVS: Zope3/src/zope/event - __init__.py:1.1.2.1 eventchannel.py:1.1.2.1 subscribable.py:1.1.2.1

Jim Fulton jim@zope.com
Mon, 23 Dec 2002 14:32:49 -0500


Update of /cvs-repository/Zope3/src/zope/event
In directory cvs.zope.org:/tmp/cvs-serv19908/zope/event

Added Files:
      Tag: NameGeddon-branch
	__init__.py eventchannel.py subscribable.py 
Log Message:
Initial renaming before debugging

=== Added File Zope3/src/zope/event/__init__.py ===
##############################################################################
#
# 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: __init__.py,v 1.1.2.1 2002/12/23 19:32:48 jim Exp $
"""

from zope.component import getService
from zope.interfaces.event import IEvent


def getEventService(context):
    return getService(context, 'Events')

def publish(context, event):
    return getEventService(context).publish(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
    subscribe = getEventService(context).subscribe
    for event_type in event_types:
        subscribe(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)



=== Added File Zope3/src/zope/event/eventchannel.py ===
##############################################################################
#
# 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: eventchannel.py,v 1.1.2.1 2002/12/23 19:32:48 jim Exp $
"""

from zope.event.subscribable import Subscribable
from zope.interfaces.event import IEventChannel

class EventChannel(Subscribable):
    
    __implements__ = IEventChannel
        
    def notify(self, event):
        
        for subscriptions in self.subscriptionsForEvent(event):
            
            for subscriber, filter in subscriptions:
                if filter is not None and not filter(event):
                    continue
                subscriber.notify(event)

    

    


=== Added File Zope3/src/zope/event/subscribable.py ===
##############################################################################
#
# 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: subscribable.py,v 1.1.2.1 2002/12/23 19:32:48 jim Exp $
"""
__metaclass__ = type

from zope.interface.type import TypeRegistry
from zope.exceptions import NotFoundError
from zope.interfaces.event import ISubscribable
from zope.interfaces.event import ISubscriptionAware
from zope.interfaces.event import IEvent
from zope.proxy.introspection import removeAllProxies

class Subscribable:
    """a global mix-in"""
    
    __implements__ = ISubscribable
        # plus has subscriptionsForEvent

    def __init__(self):
        self._registry = TypeRegistry()
        self._subscribers = [] # using a list 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)
        
        if event_type is IEvent:
            event_type = None # optimization
        
        subscribers = self._registry.setdefault(event_type, [])
        subscribers.append((clean_subscriber, filter))

        for sub in self._subscribers:
            if sub[0] == clean_subscriber:
                sub[1][event_type] = 1
                break
        else:
            self._subscribers.append((clean_subscriber, {event_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.get(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.get(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 subscriptionsForEvent(self, event):
        # XXX currently a non-interface method:
        # just a more readable prettification
        # used only for notify methods now.  Could this be replaced
        # with an explanatory comment in the code that uses it?
        return self._registry.getAllForObject(event)
    
    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.get(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.get(ev_type)
                if subscriptions:
                    for sub in subscriptions:
                        if sub[0]==subscriber:
                            result.append((ev_type or IEvent, sub[1]))
        return result