|  | # Copyright 2016 The Chromium Authors. All rights reserved. | 
|  | # Use of this source code is governed by a BSD-style license that can be | 
|  | # found in the LICENSE file. | 
|  |  | 
|  | """Java-like event module. | 
|  |  | 
|  | To use this simply decorate the callback method with @event.Event, subscribe | 
|  | to the callbacks using method += callback, and call the event method to | 
|  | send the events. | 
|  |  | 
|  | class Foo(object): | 
|  |  | 
|  | @event.Event | 
|  | def on_event_raised_1(self): | 
|  | # This is defined as a pass since this won't directly operate on the call. | 
|  | # This event takes no args when called. | 
|  | pass | 
|  |  | 
|  | @event.Event | 
|  | def on_event_raised_2(self, arg): | 
|  | # This event takes 1 arg | 
|  | pass | 
|  |  | 
|  | def do_something(self): | 
|  | # This method will raise an event on each handler | 
|  | self.on_event_raised_1() | 
|  | self.on_event_raised_2('foo') | 
|  |  | 
|  | To subscribe to events use the following code | 
|  |  | 
|  | def callback_1(): | 
|  | print 'In callback 1' | 
|  |  | 
|  | def callback_2(arg): | 
|  | print 'In callback 2', arg | 
|  |  | 
|  | foo = Foo() | 
|  | foo.on_event_raised_1 += callback_1 | 
|  | foo.on_event_raised_2 += callback_2 | 
|  | foo.do_something() | 
|  |  | 
|  | Each event can be associated with zero or more callback handlers, and each | 
|  | callback handler can be associated with one or more events. | 
|  |  | 
|  | """ | 
|  |  | 
|  | import logging | 
|  | import traceback | 
|  |  | 
|  |  | 
|  | class Event(object): | 
|  | """"A Java-like event class.""" | 
|  |  | 
|  | def __init__(self, method): | 
|  | self._method = method | 
|  | self._callbacks = [] | 
|  |  | 
|  | def __iadd__(self, callback): | 
|  | """Allow method += callback syntax.""" | 
|  | assert callback not in self._callbacks | 
|  | self._callbacks.append(callback) | 
|  | return self | 
|  |  | 
|  | def __isub__(self, callback): | 
|  | """Allow method -= callback syntax.""" | 
|  | self._callbacks.remove(callback) | 
|  | return self | 
|  |  | 
|  | def __call__(self, *args, **kwargs): | 
|  | """Dispatches a method call to the appropriate callback handlers.""" | 
|  | for callback in self._callbacks: | 
|  | try: | 
|  | callback(*args, **kwargs) | 
|  | except:  # pylint: disable=bare-except | 
|  | # Catch all exceptions here and log them. This way one exception won't | 
|  | # stop the remaining callbacks from being executed. | 
|  | logging.error(traceback.format_exc()) |