Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 19 additions & 11 deletions src/evdev/eventio_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def __aiter__(self) -> Self:
return self

def __anext__(self) -> "asyncio.Future[InputEvent]":
future = asyncio.Future()
future = asyncio.get_running_loop().create_future()
try:
# Read from the previous batch of events.
future.set_result(next(self.current_batch))
Expand All @@ -54,8 +54,15 @@ def next_batch_ready(batch):


class EventIO(eventio.EventIO):
# The event loop a reader was last registered on, or None if no async read
# has been awaited yet. Set in _do_when_readable, used by close().
_loop: "asyncio.AbstractEventLoop | None" = None

def _do_when_readable(self, callback):
loop = asyncio.get_event_loop()
# Remember the loop the reader is registered on so that close() can
# remove it later, even when called without a running event loop.
loop = asyncio.get_running_loop()
self._loop = loop

def ready():
loop.remove_reader(self.fileno())
Expand All @@ -74,7 +81,7 @@ def async_read_one(self):
Asyncio coroutine to read and return a single input event as
an instance of :class:`InputEvent <evdev.events.InputEvent>`.
"""
future = asyncio.Future()
future = asyncio.get_running_loop().create_future()
self._do_when_readable(lambda: self._set_result(future, self.read_one))
return future

Expand All @@ -84,7 +91,7 @@ def async_read(self):
a generator object that yields :class:`InputEvent <evdev.events.InputEvent>`
instances.
"""
future = asyncio.Future()
future = asyncio.get_running_loop().create_future()
self._do_when_readable(lambda: self._set_result(future, self.read))
return future

Expand All @@ -97,10 +104,11 @@ def async_read_loop(self) -> ReadIterator:
return ReadIterator(self)

def close(self):
try:
loop = asyncio.get_event_loop()
loop.remove_reader(self.fileno())
except RuntimeError:
# no event loop present, so there is nothing to
# remove the reader from. Ignore
pass
# A reader is only registered once an async read has been awaited, in
# which case _do_when_readable recorded the loop it was added to.
loop = self._loop
if loop is None or loop.is_closed():
# No reader was ever registered, or its loop is already gone, so
# there is nothing to remove the reader from.
return
loop.remove_reader(self.fileno())