1 """
2 Event support for emma
3
4 The events are addressed by L{Event} class, with the event name, interface and
5 identifier of the L{interface} related to it. Any complement can be scubcribed
6 and trigger any event.
7
8 @copyright: (c) 2011 hackmeeting U{http://sindominio.net/hackmeeting}
9 @author: Ruben Pollan
10 @organization: hackmeeting U{http://sindominio.net/hackmeeting}
11 @contact: meskio@sindominio.net
12 @license:
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the Do What The Fuck You Want To
15 Public License, Version 2, as published by Sam Hocevar. See
16 U{http://sam.zoy.org/projects/COPYING.WTFPL} for more details.
17 """
18
19 import thread
20 import itertools
21 import logging
22
23
25 """
26 Event addressing class
27
28 It holds the event name, interface and identifier of the event. You can
29 access to each of them from the object once instanciated:
30
31 >>> myEvent = Event(event="foo", identifier="bar")
32 >>> myEvent.event
33 'foo'
34 >>> myEvent.interface
35 >>> myEvent.identifier
36 'bar'
37 """
38 - def __init__(self, event=None, interface=None, identifier=None):
39 """
40 Define the event
41
42 Set the event name, interface and identifier, none of them is required.
43 Any of the three elements empty will mean that the event subscription
44 will get all the events with the element or elements defined.
45
46 @type event: string
47 @param event: name of the event
48 @type interface: string
49 @param interface: interface producer or receiver of the event
50 @type identifier: string
51 @param identifier: the identifier string of the interface
52 """
53 self.event = event
54 self.interface = interface
55 self.identifier = identifier
56
59
62
64 """
65 Get the elements of the event
66
67 @returns: (event, interface, identifier)
68 """
69 return (self.event, self.interface, self.identifier)
70
72 """
73 Get all the events that will be trigger with it
74
75 @returns: [all the combinations of None and elements of the event]
76 @attention: this method is meant to be use only inside L{emma.events}
77 """
78 event_tuples = itertools.product((self.event, None), \
79 (self.interface, None), \
80 (self.identifier, None))
81 events = set([Event(x, y, z) for x, y, z in event_tuples])
82 return events
83
84
85 _events = {}
86 _events_lock = thread.allocate_lock()
87
88
95
96
98 """
99 Trigger an event on background
100
101 Execute in a new thread each handler L{subscribe}d to the event.
102
103 @type event: L{Event}
104 @param event: event to be triggered, it must have all the elements
105 @type data: undefined
106 @param data: the information passed by the event, each event will define
107 it's data structure
108 @warning: event can not have any None value
109 """
110 handlers = _get_handlers(event)
111
112 for handler in handlers:
113 thread.start_new_thread(handler, (event, data))
114
115
117 """
118 Run an event waiting for it's result
119
120 Execute each handler L{subscribe}d to the event secuentially getting back
121 the return value of each handler.
122
123 @type event: L{Event}
124 @param event: event to be triggered, it must have all the elements
125 @type data: undefined
126 @param data: the information passed by the event, each event will define
127 it's data structure
128 @returns: [return value of each event handler]
129 @warning: event can not have any None value
130 """
131 handlers = _get_handlers(event)
132
133 res = []
134 for handler in handlers:
135 res.append(handler(event, data))
136 return res
137
138
140 """
141 Subscribe to an event
142
143 Set a function to be call if an event is produced. The event can have some
144 (or all) elements undefined, so it was call by any event with the defined
145 elements equals to the subscribed event.
146
147 @type event: L{Event}
148 @param event: event to be triggered
149 @type handler: fun(event, data)
150 @param handler: function to call if the event is trigger
151 """
152 with _events_lock:
153 if event not in _events:
154 _events[event] = [handler]
155 else:
156 _events[event].append(handler)
157
158
160 """
161 Unsubscribe from an event
162
163 @type event: L{Event}
164 @param event: event used for subscription
165 @type handler: fun(event, data)
166 @param handler: the function used for subscription
167 @warning: it is not properly tested might have bugs
168 """
169 with _events_lock:
170 if event in _events:
171 _events[event].remove(handler)
172 else:
173 log_str = _("[core] can't unsubscribe identifier," \
174 " it was not subscribed")
175 logging.warning(log_str)
176