diff --git a/src/evdev/eventio_async.py b/src/evdev/eventio_async.py index 4af1aab..89a2ede 100644 --- a/src/evdev/eventio_async.py +++ b/src/evdev/eventio_async.py @@ -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)) @@ -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()) @@ -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 `. """ - future = asyncio.Future() + future = asyncio.get_running_loop().create_future() self._do_when_readable(lambda: self._set_result(future, self.read_one)) return future @@ -84,7 +91,7 @@ def async_read(self): a generator object that yields :class:`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 @@ -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())