| | import ast |
| | import asyncio |
| | import code |
| | import concurrent.futures |
| | import inspect |
| | import sys |
| | import threading |
| | import types |
| | import warnings |
| |
|
| | from . import futures |
| |
|
| |
|
| | class AsyncIOInteractiveConsole(code.InteractiveConsole): |
| |
|
| | def __init__(self, locals, loop): |
| | super().__init__(locals) |
| | self.compile.compiler.flags |= ast.PyCF_ALLOW_TOP_LEVEL_AWAIT |
| |
|
| | self.loop = loop |
| |
|
| | def runcode(self, code): |
| | future = concurrent.futures.Future() |
| |
|
| | def callback(): |
| | global repl_future |
| | global repl_future_interrupted |
| |
|
| | repl_future = None |
| | repl_future_interrupted = False |
| |
|
| | func = types.FunctionType(code, self.locals) |
| | try: |
| | coro = func() |
| | except SystemExit: |
| | raise |
| | except KeyboardInterrupt as ex: |
| | repl_future_interrupted = True |
| | future.set_exception(ex) |
| | return |
| | except BaseException as ex: |
| | future.set_exception(ex) |
| | return |
| |
|
| | if not inspect.iscoroutine(coro): |
| | future.set_result(coro) |
| | return |
| |
|
| | try: |
| | repl_future = self.loop.create_task(coro) |
| | futures._chain_future(repl_future, future) |
| | except BaseException as exc: |
| | future.set_exception(exc) |
| |
|
| | loop.call_soon_threadsafe(callback) |
| |
|
| | try: |
| | return future.result() |
| | except SystemExit: |
| | raise |
| | except BaseException: |
| | if repl_future_interrupted: |
| | self.write("\nKeyboardInterrupt\n") |
| | else: |
| | self.showtraceback() |
| |
|
| |
|
| | class REPLThread(threading.Thread): |
| |
|
| | def run(self): |
| | try: |
| | banner = ( |
| | f'asyncio REPL {sys.version} on {sys.platform}\n' |
| | f'Use "await" directly instead of "asyncio.run()".\n' |
| | f'Type "help", "copyright", "credits" or "license" ' |
| | f'for more information.\n' |
| | f'{getattr(sys, "ps1", ">>> ")}import asyncio' |
| | ) |
| |
|
| | console.interact( |
| | banner=banner, |
| | exitmsg='exiting asyncio REPL...') |
| | finally: |
| | warnings.filterwarnings( |
| | 'ignore', |
| | message=r'^coroutine .* was never awaited$', |
| | category=RuntimeWarning) |
| |
|
| | loop.call_soon_threadsafe(loop.stop) |
| |
|
| |
|
| | if __name__ == '__main__': |
| | loop = asyncio.new_event_loop() |
| | asyncio.set_event_loop(loop) |
| |
|
| | repl_locals = {'asyncio': asyncio} |
| | for key in {'__name__', '__package__', |
| | '__loader__', '__spec__', |
| | '__builtins__', '__file__'}: |
| | repl_locals[key] = locals()[key] |
| |
|
| | console = AsyncIOInteractiveConsole(repl_locals, loop) |
| |
|
| | repl_future = None |
| | repl_future_interrupted = False |
| |
|
| | try: |
| | import readline |
| | except ImportError: |
| | pass |
| |
|
| | repl_thread = REPLThread() |
| | repl_thread.daemon = True |
| | repl_thread.start() |
| |
|
| | while True: |
| | try: |
| | loop.run_forever() |
| | except KeyboardInterrupt: |
| | if repl_future and not repl_future.done(): |
| | repl_future.cancel() |
| | repl_future_interrupted = True |
| | continue |
| | else: |
| | break |
| |
|