Welcome, guest | Sign In | My Account | Store | Cart

An example of a simple event dispatcher mini-framework

Python, 184 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#!/usr/bin/env python
# -*- coding: utf-8 -*-


# -----------------------------------------------------------------------------
# Event and EventDispatcher classes
# -----------------------------------------------------------------------------
    
class Event( object ):
    """
    Generic event to use with EventDispatcher.
    """
    
    def __init__(self, event_type, data=None):
        """
        The constructor accepts an event type as string and a custom data
        """
        self._type = event_type
        self._data = data
        
    @property 
    def type(self):
        """
        Returns the event type
        """
        return self._type
        
    @property
    def data(self):
        """
        Returns the data associated to the event
        """
        return self._data


class EventDispatcher( object ):
    """
    Generic event dispatcher which listen and dispatch events
    """
    
    def __init__(self):
        self._events = dict()
        
    def __del__(self):
        """
        Remove all listener references at destruction time
        """
        self._events = None
    
    def has_listener(self, event_type, listener):
        """
        Return true if listener is register to event_type
        """
        # Check for event type and for the listener
        if event_type in self._events.keys():
            return listener in self._events[ event_type ]
        else:
            return False
        
    def dispatch_event(self, event):
        """
        Dispatch an instance of Event class
        """
        # Dispatch the event to all the associated listeners 
        if event.type in self._events.keys():
            listeners = self._events[ event.type ]
            
            for listener in listeners:
                listener( event )
        
    def add_event_listener(self, event_type, listener):
        """
        Add an event listener for an event type
        """
        # Add listener to the event type
        if not self.has_listener( event_type, listener ):
            listeners = self._events.get( event_type, [] )
        
            listeners.append( listener )
            
            self._events[ event_type ] = listeners
    
    def remove_event_listener(self, event_type, listener):
        """
        Remove event listener.
        """
        # Remove the listener from the event type
        if self.has_listener( event_type, listener ):
            listeners = self._events[ event_type ]
            
            if len( listeners ) == 1:
                # Only this listener remains so remove the key
                del self._events[ event_type ]
                
            else:
                # Update listeners chain
                listeners.remove( listener )
                
                self._events[ event_type ] = listeners


# ------------------------------------------------------------------------------
# Events and Dispatcher example
#
# In this example we create a simple event MyEvent with only two event types,
# ASK and RESPOND, and two classes: WhoAsk, which send AKS event and listen for
# the RESPOND event, and WhoRespond, which listen for ASK events and send back
# a RESPOND event
# -----------------------------------------------------------------------------

class MyEvent( Event ):
    """
    When subclassing Event class the only thing you must do is to define
    a list of class level constants which defines the event types and the 
    string associated to them
    """
    
    ASK     = "askMyEvent"
    RESPOND = "respondMyEvent"


class WhoAsk( object ):
    """
    First class which ask who is listening to it
    """
    def __init__(self, event_dispatcher):
        # Save a reference to the event dispatch
        self.event_dispatcher = event_dispatcher
        
        # Listen for the RESPOND event type
        self.event_dispatcher.add_event_listener( 
            MyEvent.RESPOND, self.on_answer_event 
        )
        
    def ask(self):
        """
        Dispatch the ask event
        """
        print ">>> I'm instance {0}. Who are listening to me ?".format( self )

        self.event_dispatcher.dispatch_event( 
            MyEvent( MyEvent.ASK, self ) 
        )
        
    def on_answer_event(self, event):
        """
        Event handler for the RESPOND event type
        """
        print "<<< Thank you instance {0}".format( event.data )
        

class WhoRespond( object ):
    """
    Second class who respond to ASK events
    """
    def __init__(self, event_dispatcher):
        # Save event dispatcher reference
        self.event_dispatcher = event_dispatcher
        
        # Listen for ASK event type
        self.event_dispatcher.add_event_listener( 
            MyEvent.ASK, self.on_ask_event 
        )
        
    def on_ask_event(self, event):
        """
        Event handler for ASK event type
        """
        self.event_dispatcher.dispatch_event( 
            MyEvent ( MyEvent.RESPOND, self ) 
        )


if __name__ == "__main__":
    # Create and instance of event dispatcher
    dispatcher = EventDispatcher()
    
    # Create an instance of WhoAsk class and two instance of WhoRespond class
    who_ask = WhoAsk( dispatcher )
    who_responde1 = WhoRespond( dispatcher )
    who_responde2 = WhoRespond( dispatcher )
    
    # WhoAsk ask :-)
    who_ask.ask()

2 comments

reckoner 13 years, 6 months ago  # | flag

How is this related to enthought's Traits package? Does this accomplish the same thing?

Naga Harish 7 years, 5 months ago  # | flag

Hi Daniele, this was really helpful. Thanks for posting. I have seen a similar code at http://docs.openstack.org/deve.... I was just wondering if I need to use the Apache License if I plan to use this code in one of my products.

Created by Daniele Esposti on Tue, 19 Oct 2010 (MIT)
Python recipes (4591)
Daniele Esposti's recipes (1)

Required Modules

  • (none specified)

Other Information and Tasks