Added more tests, improved README, removed simple_example.py

This commit is contained in:
nocturn9x 2021-12-25 18:38:20 +01:00
parent c9456e0837
commit 5ba185c11b
9 changed files with 130 additions and 42 deletions

View File

@ -63,7 +63,7 @@ async def main():
# with different priorities will be executed in order
print("Firing non-blocking event 'hi'")
await emit("hi", block=False) # This one spawns hi() and returns immediately
print("Non-blocking event 'hello' fired")
print("Non-blocking event 'hi' fired")
await emit("event3") # Does nothing: No handlers registered for event3!
# We wait now for the the handler of the "hi" event to complete
t = time.time()
@ -76,6 +76,11 @@ if __name__ == "__main__":
asyncio.run(main())
```
__Note__: This example showed that the event names match the functions' names: this is just for explanatory purposes!
It's not compulsory for your event and their respective handlers' names to match. You can also register as many
functions you want for the same or multiple events and asyncevents will call them all when one of them is fired.
For more usage examples (until the documentation is done), check out the tests directory or read the source code:
it's pretty straightforward, I promise.
## TODOs

View File

@ -72,7 +72,7 @@ class AsyncEventEmitter:
:type event: str
"""
if self.handlers.get(event, None) is None:
if not self.handlers.get(event):
if self.on_unknown_event == UnknownEventHandling.IGNORE:
return
elif self.on_unknown_event == UnknownEventHandling.ERROR:
@ -83,7 +83,7 @@ class AsyncEventEmitter:
# It's a coroutine! Call it
await self.on_unknown_event(self, event)
async def _catch_errors_in_awaitable(self, event: str, obj: Awaitable):
async def _handle_errors_in_awaitable(self, event: str, obj: Awaitable):
# Thanks to asyncio's *utterly amazing* (HUGE sarcasm there)
# exception handling, we have to make this wrapper so we can
# catch errors on a per-handler basis
@ -125,7 +125,7 @@ class AsyncEventEmitter:
temp[-1][-2],
)
)
self._tasks.append((event, asyncio.create_task(self._catch_errors_in_awaitable(event, task))))
self._tasks.append((event, asyncio.create_task(self._handle_errors_in_awaitable(event, task))))
# We push back the elements
for t in temp:
heappush(self.handlers[event], t)
@ -145,7 +145,7 @@ class AsyncEventEmitter:
t = heappop(temp)
if t[-1]:
self.unregister_handler(event, t[-2])
await self._catch_errors_in_awaitable(event, t[-2](self, event))
await self._handle_errors_in_awaitable(event, t[-2](self, event))
def __init__(
self,

17
tests/blocking.py Normal file
View File

@ -0,0 +1,17 @@
import asyncio
from asyncevents import on_event, emit
@on_event("hello")
async def hello(_, event: str):
print(f"Hello {event!r}!")
async def main():
print("Firing blocking event 'hello'")
await emit("hello")
print("Handlers for event 'hello' have exited")
if __name__ == "__main__":
asyncio.run(main())

View File

@ -0,0 +1,21 @@
import asyncio
from asyncevents import on_event, emit
@on_event("test")
@on_event("hello")
async def hello(_, event: str):
print(f"Hello {event!r}!")
async def main():
print("Firing blocking event 'hello'")
await emit("hello")
print("Handlers for event 'hello' have exited")
print("Firing blocking event 'test'")
await emit("test")
print("Handlers for event 'test' have exited")
if __name__ == "__main__":
asyncio.run(main())

23
tests/non_blocking.py Normal file
View File

@ -0,0 +1,23 @@
import time
import asyncio
from asyncevents import on_event, emit, wait
@on_event("hi")
async def hi(_, event: str):
print(f"Hi {event!r}! I'm going to sleep for 5 seconds")
await asyncio.sleep(5) # Simulates some work
async def main():
print("Emitting event 'hi'")
await emit("hi", block=False)
print("Event 'hi' fired")
t = time.time()
print("Waiting on event 'hi'")
await wait("hi")
print(f"Waited for {time.time() - t:.2f} seconds")
if __name__ == "__main__":
asyncio.run(main())

View File

@ -4,10 +4,14 @@ from asyncevents import on_event, emit, get_current_emitter, ExceptionHandling
@on_event("error")
async def oh_no(_, event: str):
print("Goodbye!")
print(f"Goodbye after {event!r}!")
raise ValueError("D:")
async def handle_error(_, exc: Exception, event: str):
print(f"Exception {type(exc).__name__!r} from {event!r} handled!")
async def main():
try:
await emit("error") # The error propagates
@ -21,6 +25,10 @@ async def main():
get_current_emitter().on_error = ExceptionHandling.IGNORE # Silences the exception
await emit("error") # This won't raise nor log anything to the console. Yay x2!
print("We're safe again!")
# Let's try using a coroutine function as an exception handler
get_current_emitter().on_error = handle_error
await emit("error") # This will call handle_error with the exception object and the event name
print("We're safe once again!")
if __name__ == "__main__":

32
tests/on_unknown_event.py Normal file
View File

@ -0,0 +1,32 @@
import asyncio
from asyncevents import on_event, emit, get_current_emitter, UnknownEventHandling
from asyncevents.errors import UnknownEvent
@on_event("test")
@on_event("test2")
async def oh_no(_, event: str):
print(f"The event {event!r} definitely exists!")
async def handle_unknown_event(_, event: str):
print(f"The event {event!r} definitely does not exist!")
async def main():
await emit("test")
await emit("test2")
await emit("test3") # Does nothing by default
get_current_emitter().on_unknown_event = UnknownEventHandling.LOG
await emit("test3") # Logs an error message
get_current_emitter().on_unknown_event = UnknownEventHandling.ERROR # Raises an exception
try:
await emit("test3")
except UnknownEvent:
print("Bang!")
get_current_emitter().on_unknown_event = handle_unknown_event # Calls the function with the event as argument
await emit("test3")
if __name__ == "__main__":
asyncio.run(main())

18
tests/oneshot.py Normal file
View File

@ -0,0 +1,18 @@
import asyncio
from asyncevents import on_event, emit
@on_event("hello", oneshot=True) # The handler is removed after it fires once
async def hello(_, event: str):
print(f"Hello {event!r}!")
async def main():
print("Firing blocking event 'hello'")
await emit("hello")
print("Handlers for event 'hello' have exited")
await emit("hello") # Nothing happens
if __name__ == "__main__":
asyncio.run(main())

View File

@ -1,36 +0,0 @@
import time
import asyncio
from asyncevents import on_event, emit, wait
@on_event("hello")
async def hello(_, event: str):
print(f"Hello {event!r}!")
@on_event("hi")
async def hi(_, event: str):
print(f"Hi {event!r}! I'm going to sleep for 5 seconds")
await asyncio.sleep(5) # Simulates some work
async def main():
print("Firing blocking event 'hello'")
await emit("hello") # This call blocks until hello() terminates
print("Handlers for event 'hello' have exited")
# Notice how, until here, the output is in order: this is on purpose!
# When using blocking mode, asyncevents even guarantees that handlers
# with different priorities will be executed in order
print("Firing non-blocking event 'hi'")
await emit("hi", block=False) # This one spawns hi() and returns immediately
print("Non-blocking event 'hello' fired")
await emit("event3") # Does nothing: No handlers registered for event3!
# We wait now for the the handler of the "hi" event to complete
t = time.time()
print("Waiting on event 'hi'")
await wait("hi") # Waits until all the handlers triggered by the "hi" event exit
print(f"Waited for {time.time() - t:.2f} seconds") # Should print roughly 5 seconds
if __name__ == "__main__":
asyncio.run(main())