def test_method_handler_invoking_other(): h = event.HasEvents() # This used not not work # with raises(RuntimeError): # class Foo(event.HasEvents): # # @h.connect('x1') # def handler(self, *events): # self.was_invoked = True # But now it does! class Foo(event.HasEvents): @h.connect('x1') def handler(self, *events): self.was_invoked = True foo = Foo() h.emit('x1') event.loop.iter() assert foo.was_invoked
def test_dispose3(): # Test that connecting a "volatile" object to a static object works well # w.r.t. cleanup. relay = event.HasEvents() class Foo: def bar(self, *events): pass foo = Foo() handler = relay.connect(foo.bar, 'xx') handler_ref = weakref.ref(handler) foo_ref = weakref.ref(foo) del foo del handler gc.collect() assert foo_ref() is None assert handler_ref() is not None relay.emit('xx') event.loop.iter() gc.collect() assert foo_ref() is None assert handler_ref() is None
def test_connecting(): # We've done all the normal connections. We test mosly fails here h = event.HasEvents() with raises(RuntimeError): # connect() needs args @event.connect def foo(*events): pass with raises(RuntimeError): @h.connect def foo(*events): pass with raises(ValueError): # connect() needs strings @event.connect(3) def foo(*events): pass with raises(ValueError): @h.connect(3) def foo(*events): pass with raises(TypeError): # connect() needs callable event.connect('x')(3) with raises(TypeError): # connect() needs callable h.connect('x')(3) with raises(RuntimeError): # cannot connect h.xx = None @h.connect('xx.foobar') def foo(*events): pass
def test_emit(): h = event.HasEvents() events = [] @h.connect('foo', 'bar') def handler(*evts): events.extend(evts) h.emit('foo', {}) h.emit('bar', {'x': 1, 'y': 2}) h.emit('spam', {}) # not registered handler.handle_now() assert len(events) == 2 for ev in events: assert isinstance(ev, dict) assert ev.source is h assert len(events[0]) == 2 assert len(events[1]) == 4 assert events[0].type == 'foo' assert events[1].type == 'bar' assert events[1].x == 1 assert events[1]['y'] == 2 # Fail with raises(ValueError): h.emit('foo:a', {}) with raises(TypeError): h.emit('foo', 4) with raises(TypeError): h.emit('foo', 'bla')
def test_func_handler_invoking(): called = [] h = event.HasEvents() @h.connect('x1', 'x2') def handler(*events): called.append(len(events)) handler() handler.handle_now() h.emit('x1', {}) handler.handle_now() h.emit('x1', {}) h.emit('x1', {}) handler.handle_now() h.emit('x1', {}) h.emit('x2', {}) handler.handle_now() handler() handler.handle_now() assert called == [0, 1, 2, 2, 0]
def test_basics(): # Simplest h = event.HasEvents() assert not h.__handlers__ assert not h.__emitters__ # Test __emitters__ class Foo(event.HasEvents): @event.prop def a_prop(self, v=0): return v @event.readonly def a_readonly(self, v=0): return v @event.emitter def a_emitter(self, v): return {} @event.emitter # deliberately define it twice def a_emitter(self, v): return {'x': 1} # foo = Foo() assert not foo.__handlers__ assert len(foo.__emitters__) == 1 assert len(foo.__properties__) == 2 assert 'a_prop' in foo.__properties__ assert 'a_readonly' in foo.__properties__ assert 'a_emitter' in foo.__emitters__ # assert foo.get_event_types() == ['a_emitter', 'a_prop', 'a_readonly'] assert foo.get_event_handlers('a_prop') == [] # Test __handlers__ class Bar(event.HasEvents): @event.connect('x') def spam(self, *events): pass @event.connect('eggs') def on_eggs(self, *events): pass # foo = Bar() assert not foo.__emitters__ assert len(foo.__handlers__) == 2 #assert len(foo.__handlers__) == 1 assert 'spam' in foo.__handlers__ assert 'on_eggs' in foo.__handlers__ # assert foo.get_event_types() == ['eggs', 'x'] assert foo.get_event_handlers('x') == [foo.spam]
def test_method_handler_invoking_other(): h = event.HasEvents() with raises(RuntimeError): class Foo(event.HasEvents): @h.connect('x1') def handler(self, *events): self.was_invoked = True
def test_registering_handlers(): h = event.HasEvents() @h.connect('foo') def handler1(*evts): events.extend(evts) @h.connect('foo') def handler2(*evts): events.extend(evts) @h.connect('foo') def handler3(*evts): events.extend(evts) handler1.dispose() handler2.dispose() handler3.dispose() # Checks before we start assert h.get_event_types() == ['foo'] assert h.get_event_handlers('foo') == [] # Test adding handlers h._register_handler('foo', handler1) h._register_handler('foo:a', handler2) h._register_handler('foo:z', handler3) assert h.get_event_handlers('foo') == [handler2, handler1, handler3] # Unregestering one handler h.disconnect('foo', handler2) assert h.get_event_handlers('foo') == [handler1, handler3] # Reset h._register_handler('foo:a', handler2) assert h.get_event_handlers('foo') == [handler2, handler1, handler3] # Unregestering one handler + invalid label -> no unregister h.disconnect('foo:xx', handler2) assert h.get_event_handlers('foo') == [handler2, handler1, handler3] # Reset assert h.get_event_handlers('foo') == [handler2, handler1, handler3] # Unregestering one handler by label h.disconnect('foo:a') assert h.get_event_handlers('foo') == [handler1, handler3] # Reset h._register_handler('foo:a', handler2) assert h.get_event_handlers('foo') == [handler2, handler1, handler3] # Unregestering by type h.disconnect('foo') assert h.get_event_handlers('foo') == []
def test_connecting_and_getting_cached_event(): h = event.HasEvents() h.emit('foo') res = [] @h.connect('foo') def handle(ev): res.append(ev) event.loop.iter() event.loop.iter() assert len(res) == 1
def test_dispose2(): h = event.HasEvents() @h.connect('x1', 'x2') def handler(*events): pass handler_ref = weakref.ref(handler) del handler gc.collect() assert handler_ref() is not None # h is holding on h.dispose() # <=== only this line is different from test_dispose1() gc.collect() assert handler_ref() is None
def test_dispose1(): h = event.HasEvents() @h.connect('x1', 'x2') def handler(*events): pass handler_ref = weakref.ref(handler) del handler gc.collect() assert handler_ref() is not None # h is holding on handler_ref().dispose() gc.collect() assert handler_ref() is None
def test_exceptions(): h = event.HasEvents() @h.connect('foo') def handle_foo(*events): 1 / 0 h.emit('foo', {}) sys.last_traceback = None assert sys.last_traceback is None # No exception should be thrown here event.loop.iter() event.loop.iter() # But we should have prepared for PM debugging assert sys.last_traceback # Its different for a direct call with raises(ZeroDivisionError): handle_foo()
def __init__(self): super().__init__() self.bar = event.HasEvents() self.bars = [self.bar]