"""Provide an interactive event loop class.""" import asyncio import functools from . import server from . import console class InteractiveEventLoop(asyncio.SelectorEventLoop): """Event loop running a python console.""" console_class = console.AsynchronousConsole def __init__( self, *, selector=None, locals=None, banner=None, serve=None, prompt_control=None, ): self.console = None self.console_task = None self.console_server = None super().__init__(selector=selector) # Factory self.factory = lambda streams: self.console_class( streams, locals=locals, prompt_control=prompt_control, loop=self ) # Local console if serve is None: self.console = self.factory(None) coro = self.console.interact(banner, stop=True, handle_sigint=True) self.console_task = asyncio.ensure_future(coro, loop=self) # Serving console else: host, port = serve coro = server.start_interactive_server( self.factory, host=host, port=port, banner=banner, loop=self ) self.console_server = self.run_until_complete(coro) server.print_server(self.console_server) def close(self): if self.console_task and not self.is_running(): asyncio.Future.cancel(self.console_task) super().close() def __del__(self): if self.console_task and self.console_task.done(): self.console_task.exception() try: super().__del__() except AttributeError: pass class InteractiveEventLoopPolicy(asyncio.DefaultEventLoopPolicy): """Policy to use the interactive event loop by default.""" def __init__(self, *, locals=None, banner=None, serve=None, prompt_control=None): self._loop_factory = functools.partial( InteractiveEventLoop, locals=locals, banner=banner, serve=serve, prompt_control=prompt_control, ) super().__init__() def set_interactive_policy( *, locals=None, banner=None, serve=None, prompt_control=None ): """Use an interactive event loop by default.""" policy = InteractiveEventLoopPolicy( locals=locals, banner=banner, serve=serve, prompt_control=prompt_control ) asyncio.set_event_loop_policy(policy) def run_console(*, locals=None, banner=None, serve=None, prompt_control=None): """Run the interactive event loop.""" loop = InteractiveEventLoop( locals=locals, banner=banner, serve=serve, prompt_control=prompt_control ) asyncio.set_event_loop(loop) try: loop.run_forever() except KeyboardInterrupt: pass