diff --git a/pyee/base.py b/pyee/base.py index be65c8e..99c9962 100644 --- a/pyee/base.py +++ b/pyee/base.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- -from collections import defaultdict, OrderedDict +from collections import OrderedDict from threading import Lock -from typing import Any, Callable, Dict, List, Optional, Tuple +from typing import Any, Callable, Dict, List, Optional, Set, Tuple class PyeeException(Exception): @@ -44,7 +44,7 @@ def __init__(self) -> None: self._events: Dict[ str, "OrderedDict[Callable, Callable]", - ] = defaultdict(OrderedDict) + ] = dict() self._lock: Lock = Lock() def on(self, event: str, f: Optional[Callable] = None) -> Callable: @@ -110,6 +110,8 @@ def _add_event_handler(self, event: str, k: Callable, v: Callable): # different for `once` handlers, where v is a wrapped version # of k which removes itself before calling k with self._lock: + if event not in self._events: + self._events[event] = OrderedDict() self._events[event][k] = v def _emit_run( @@ -120,6 +122,10 @@ def _emit_run( ) -> None: f(*args, **kwargs) + def event_names(self) -> Set[str]: + """Get a list of events that this emitter is listening to.""" + return set(self._events.keys()) + def _emit_handle_potential_error(self, event: str, error: Any) -> None: if event == "error": if isinstance(error, Exception): @@ -136,7 +142,7 @@ def _call_handlers( handled = False with self._lock: - funcs = list(self._events[event].values()) + funcs = list(self._events.get(event, OrderedDict()).values()) for f in funcs: self._emit_run(f, args, kwargs) handled = True @@ -203,6 +209,8 @@ def g( def _remove_listener(self, event: str, f: Callable) -> None: """Naked unprotected removal.""" self._events[event].pop(f) + if not len(self._events[event]): + del self._events[event] def remove_listener(self, event: str, f: Callable) -> None: """Removes the function ``f`` from ``event``.""" @@ -217,7 +225,7 @@ def remove_all_listeners(self, event: Optional[str] = None) -> None: if event is not None: self._events[event] = OrderedDict() else: - self._events = defaultdict(OrderedDict) + self._events = dict() def listeners(self, event: str) -> List[Callable]: """Returns a list of all listeners registered to the ``event``.""" diff --git a/tests/test_sync.py b/tests/test_sync.py index 61d3dc7..e4e460c 100644 --- a/tests/test_sync.py +++ b/tests/test_sync.py @@ -22,6 +22,8 @@ def event_handler(data, **kwargs): call_me() assert data == "emitter is emitted!" + assert ee.event_names() == {"event"} + # Making sure data is passed propers ee.emit("event", "emitter is emitted!", error=False) @@ -43,6 +45,8 @@ def test_emit_error(): def on_error(exc): call_me() + assert ee.event_names() == {"error"} + # No longer raises and error instead return True indicating handled assert ee.emit("error", test_exception) is True call_me.assert_called_once() @@ -56,6 +60,8 @@ def test_emit_return(): call_me = Mock() ee = EventEmitter() + assert ee.event_names() == set() + # make sure emitting without a callback returns False assert not ee.emit("data") @@ -79,6 +85,8 @@ def test_new_listener_event(): def event_handler(data): pass + assert ee.event_names() == {"new_listener", "event"} + call_me.assert_called_once_with("event", event_handler) @@ -106,6 +114,8 @@ def fourth(): ee.on("event", fourth) + assert ee.event_names() == {"event"} + assert ee._events["event"] == OrderedDict( [(first, first), (second, second), (third, third), (fourth, fourth)] ) @@ -120,7 +130,7 @@ def fourth(): assert ee._events["event"] == OrderedDict([(third, third), (fourth, fourth)]) ee.remove_all_listeners("event") - assert ee._events["event"] == OrderedDict() + assert "event" not in ee._events["event"] def test_listener_removal_on_emit(): @@ -137,6 +147,8 @@ def should_remove(): ee.on("remove", should_remove) ee.on("remove", call_me) + assert ee.event_names() == {"remove"} + ee.emit("remove") call_me.assert_called_once() @@ -148,6 +160,8 @@ def should_remove(): ee.on("remove", call_me) ee.on("remove", should_remove) + assert ee.event_names() == {"remove"} + ee.emit("remove") call_me.assert_called_once() @@ -169,11 +183,15 @@ def once_handler(data): # Tests to make sure that after event is emitted that it's gone. ee.once("event", once_handler) + assert ee.event_names() == {"event"} + ee.emit("event", "emitter is emitted!") call_me.assert_called_once() - assert ee._events["event"] == OrderedDict() + assert ee.event_names() == set() + + assert "event" not in ee._events def test_once_removal(): @@ -187,10 +205,12 @@ def once_handler(data): handle = ee.once("event", once_handler) assert handle == once_handler + assert ee.event_names() == {"event"} ee.remove_listener("event", handle) - assert ee._events["event"] == OrderedDict() + assert "event" not in ee._events + assert ee.event_names() == set() def test_listeners():