You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
119 lines
3.7 KiB
119 lines
3.7 KiB
6 years ago
|
"""
|
||
|
Win32 asyncio event loop.
|
||
|
|
||
|
Windows notes:
|
||
|
- Somehow it doesn't seem to work with the 'ProactorEventLoop'.
|
||
|
"""
|
||
|
from __future__ import unicode_literals
|
||
|
|
||
|
from .base import EventLoop
|
||
|
from .context import wrap_in_current_context
|
||
|
from .future import Future
|
||
|
from .utils import ThreadWithFuture
|
||
|
from .win32 import wait_for_handles
|
||
|
|
||
|
import asyncio
|
||
|
|
||
|
__all__ = [
|
||
|
'Win32AsyncioEventLoop',
|
||
|
]
|
||
|
|
||
|
|
||
|
class Win32AsyncioEventLoop(EventLoop):
|
||
|
"""
|
||
|
Wrapper around the Asyncio event loop, but compatible with prompt_toolkit.
|
||
|
"""
|
||
|
def __init__(self, loop=None):
|
||
|
super(Win32AsyncioEventLoop, self).__init__()
|
||
|
|
||
|
self.loop = loop or asyncio.get_event_loop()
|
||
|
self.closed = False
|
||
|
|
||
|
# Maps win32 handles to their callbacks.
|
||
|
self._handle_callbacks = {}
|
||
|
|
||
|
def close(self):
|
||
|
# Note: we should not close the asyncio loop itself, because that one
|
||
|
# was not created here.
|
||
|
self.closed = True
|
||
|
|
||
|
def run_until_complete(self, future, inputhook=None):
|
||
|
if inputhook:
|
||
|
raise ValueError("Win32AsyncioEventLoop doesn't support input hooks.")
|
||
|
|
||
|
return self.loop.run_until_complete(future)
|
||
|
|
||
|
def run_forever(self, inputhook=None):
|
||
|
if inputhook:
|
||
|
raise ValueError("Win32AsyncioEventLoop doesn't support input hooks.")
|
||
|
|
||
|
self.loop.run_forever()
|
||
|
|
||
|
def run_in_executor(self, callback, _daemon=False):
|
||
|
if _daemon:
|
||
|
# Asyncio doesn't support 'daemon' executors.
|
||
|
th = ThreadWithFuture(callback, daemon=True)
|
||
|
self.call_from_executor(th.start)
|
||
|
return th.future
|
||
|
else:
|
||
|
asyncio_f = self.loop.run_in_executor(None, callback)
|
||
|
return Future.from_asyncio_future(asyncio_f, loop=self)
|
||
|
|
||
|
def call_from_executor(self, callback, _max_postpone_until=None):
|
||
|
callback = wrap_in_current_context(callback)
|
||
|
self.loop.call_soon_threadsafe(callback)
|
||
|
|
||
|
def add_reader(self, fd, callback):
|
||
|
" Start watching the file descriptor for read availability. "
|
||
|
callback = wrap_in_current_context(callback)
|
||
|
self.loop.add_reader(fd, callback)
|
||
|
|
||
|
def remove_reader(self, fd):
|
||
|
" Stop watching the file descriptor for read availability. "
|
||
|
self.loop.remove_reader(fd)
|
||
|
|
||
|
def add_signal_handler(self, signum, handler):
|
||
|
return self.loop.add_signal_handler(signum, handler)
|
||
|
|
||
|
def get_exception_handler(self):
|
||
|
return self.loop.get_exception_handler()
|
||
|
|
||
|
def set_exception_handler(self, handler):
|
||
|
self.loop.set_exception_handler(handler)
|
||
|
|
||
|
def call_exception_handler(self, context):
|
||
|
self.loop.call_exception_handler(context)
|
||
|
|
||
|
def default_exception_handler(self, context):
|
||
|
self.loop.default_exception_handler(context)
|
||
|
|
||
|
def add_win32_handle(self, handle, callback):
|
||
|
" Add a Win32 handle to the event loop. "
|
||
|
callback = wrap_in_current_context(callback)
|
||
|
self._handle_callbacks[handle] = callback
|
||
|
|
||
|
# Add reader.
|
||
|
def ready():
|
||
|
# Tell the callback that input's ready.
|
||
|
try:
|
||
|
callback()
|
||
|
finally:
|
||
|
self.run_in_executor(wait)
|
||
|
|
||
|
# Wait for the input to become ready.
|
||
|
# (Use an executor for this, the Windows asyncio event loop doesn't
|
||
|
# allow us to wait for handles like stdin.)
|
||
|
def wait():
|
||
|
if self._handle_callbacks.get(handle) != callback:
|
||
|
return
|
||
|
|
||
|
wait_for_handles([handle])
|
||
|
self.call_from_executor(ready)
|
||
|
|
||
|
self.run_in_executor(wait, _daemon=True)
|
||
|
|
||
|
def remove_win32_handle(self, handle):
|
||
|
" Remove a Win32 handle from the event loop. "
|
||
|
if handle in self._handle_callbacks:
|
||
|
del self._handle_callbacks[handle]
|