| 
									
										
										
										
											2019-05-27 13:42:29 +02:00
										 |  |  | import ast | 
					
						
							|  |  |  | import asyncio | 
					
						
							|  |  |  | import concurrent.futures | 
					
						
							|  |  |  | import inspect | 
					
						
							| 
									
										
										
										
											2024-05-31 23:15:44 +02:00
										 |  |  | import os | 
					
						
							| 
									
										
										
										
											2024-03-01 20:39:16 +01:00
										 |  |  | import site | 
					
						
							| 
									
										
										
										
											2019-05-27 13:42:29 +02:00
										 |  |  | import sys | 
					
						
							|  |  |  | import threading | 
					
						
							|  |  |  | import types | 
					
						
							|  |  |  | import warnings | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-31 23:15:44 +02:00
										 |  |  | from _colorize import can_colorize, ANSIColors  # type: ignore[import-not-found] | 
					
						
							|  |  |  | from _pyrepl.console import InteractiveColoredConsole | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-27 13:42:29 +02:00
										 |  |  | from . import futures | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-31 23:15:44 +02:00
										 |  |  | class AsyncIOInteractiveConsole(InteractiveColoredConsole): | 
					
						
							| 
									
										
										
										
											2019-05-27 13:42:29 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, locals, loop): | 
					
						
							| 
									
										
										
										
											2024-05-31 23:15:44 +02:00
										 |  |  |         super().__init__(locals, filename="<stdin>") | 
					
						
							| 
									
										
										
										
											2019-05-27 13:42:29 +02:00
										 |  |  |         self.compile.compiler.flags |= ast.PyCF_ALLOW_TOP_LEVEL_AWAIT | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.loop = loop | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def runcode(self, code): | 
					
						
							| 
									
										
										
										
											2024-05-31 23:15:44 +02:00
										 |  |  |         global return_code | 
					
						
							| 
									
										
										
										
											2019-05-27 13:42:29 +02:00
										 |  |  |         future = concurrent.futures.Future() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def callback(): | 
					
						
							| 
									
										
										
										
											2024-05-31 23:15:44 +02:00
										 |  |  |             global return_code | 
					
						
							| 
									
										
										
										
											2019-05-27 13:42:29 +02:00
										 |  |  |             global repl_future | 
					
						
							| 
									
										
										
										
											2024-05-31 23:15:44 +02:00
										 |  |  |             global keyboard_interrupted | 
					
						
							| 
									
										
										
										
											2019-05-27 13:42:29 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             repl_future = None | 
					
						
							| 
									
										
										
										
											2024-05-31 23:15:44 +02:00
										 |  |  |             keyboard_interrupted = False | 
					
						
							| 
									
										
										
										
											2019-05-27 13:42:29 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             func = types.FunctionType(code, self.locals) | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 coro = func() | 
					
						
							| 
									
										
										
										
											2024-05-31 23:15:44 +02:00
										 |  |  |             except SystemExit as se: | 
					
						
							|  |  |  |                 return_code = se.code | 
					
						
							|  |  |  |                 self.loop.stop() | 
					
						
							|  |  |  |                 return | 
					
						
							| 
									
										
										
										
											2019-05-27 13:42:29 +02:00
										 |  |  |             except KeyboardInterrupt as ex: | 
					
						
							| 
									
										
										
										
											2024-05-31 23:15:44 +02:00
										 |  |  |                 keyboard_interrupted = True | 
					
						
							| 
									
										
										
										
											2019-05-27 13:42:29 +02:00
										 |  |  |                 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() | 
					
						
							| 
									
										
										
										
											2024-05-31 23:15:44 +02:00
										 |  |  |         except SystemExit as se: | 
					
						
							|  |  |  |             return_code = se.code | 
					
						
							|  |  |  |             self.loop.stop() | 
					
						
							|  |  |  |             return | 
					
						
							| 
									
										
										
										
											2019-05-27 13:42:29 +02:00
										 |  |  |         except BaseException: | 
					
						
							| 
									
										
										
										
											2024-05-31 23:15:44 +02:00
										 |  |  |             if keyboard_interrupted: | 
					
						
							| 
									
										
										
										
											2019-05-27 13:42:29 +02:00
										 |  |  |                 self.write("\nKeyboardInterrupt\n") | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 self.showtraceback() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class REPLThread(threading.Thread): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def run(self): | 
					
						
							| 
									
										
										
										
											2024-05-31 23:15:44 +02:00
										 |  |  |         global return_code | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-27 13:42:29 +02:00
										 |  |  |         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' | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-31 23:15:44 +02:00
										 |  |  |             console.write(banner) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if startup_path := os.getenv("PYTHONSTARTUP"): | 
					
						
							|  |  |  |                 import tokenize | 
					
						
							|  |  |  |                 with tokenize.open(startup_path) as f: | 
					
						
							|  |  |  |                     startup_code = compile(f.read(), startup_path, "exec") | 
					
						
							|  |  |  |                     exec(startup_code, console.locals) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             ps1 = getattr(sys, "ps1", ">>> ") | 
					
						
							| 
									
										
										
										
											2024-07-16 00:49:41 +02:00
										 |  |  |             if can_colorize() and CAN_USE_PYREPL: | 
					
						
							| 
									
										
										
										
											2024-05-31 23:15:44 +02:00
										 |  |  |                 ps1 = f"{ANSIColors.BOLD_MAGENTA}{ps1}{ANSIColors.RESET}" | 
					
						
							|  |  |  |             console.write(f"{ps1}import asyncio\n") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-16 00:49:41 +02:00
										 |  |  |             if CAN_USE_PYREPL: | 
					
						
							| 
									
										
										
										
											2024-05-31 23:15:44 +02:00
										 |  |  |                 from _pyrepl.simple_interact import ( | 
					
						
							|  |  |  |                     run_multiline_interactive_console, | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |                 try: | 
					
						
							| 
									
										
										
										
											2024-07-16 00:49:41 +02:00
										 |  |  |                     run_multiline_interactive_console(console) | 
					
						
							| 
									
										
										
										
											2024-05-31 23:15:44 +02:00
										 |  |  |                 except SystemExit: | 
					
						
							|  |  |  |                     # expected via the `exit` and `quit` commands | 
					
						
							|  |  |  |                     pass | 
					
						
							|  |  |  |                 except BaseException: | 
					
						
							|  |  |  |                     # unexpected issue | 
					
						
							|  |  |  |                     console.showtraceback() | 
					
						
							|  |  |  |                     console.write("Internal error, ") | 
					
						
							|  |  |  |                     return_code = 1 | 
					
						
							| 
									
										
										
										
											2024-07-16 00:49:41 +02:00
										 |  |  |             else: | 
					
						
							|  |  |  |                 console.interact(banner="", exitmsg="") | 
					
						
							| 
									
										
										
										
											2019-05-27 13:42:29 +02:00
										 |  |  |         finally: | 
					
						
							|  |  |  |             warnings.filterwarnings( | 
					
						
							|  |  |  |                 'ignore', | 
					
						
							|  |  |  |                 message=r'^coroutine .* was never awaited$', | 
					
						
							|  |  |  |                 category=RuntimeWarning) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             loop.call_soon_threadsafe(loop.stop) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == '__main__': | 
					
						
							| 
									
										
										
										
											2024-07-16 00:49:41 +02:00
										 |  |  |     if os.getenv('PYTHON_BASIC_REPL'): | 
					
						
							|  |  |  |         CAN_USE_PYREPL = False | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         from _pyrepl.main import CAN_USE_PYREPL | 
					
						
							| 
									
										
										
										
											2024-05-31 23:15:44 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return_code = 0 | 
					
						
							| 
									
										
										
										
											2019-05-27 13:42:29 +02:00
										 |  |  |     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 | 
					
						
							| 
									
										
										
										
											2024-05-31 23:15:44 +02:00
										 |  |  |     keyboard_interrupted = False | 
					
						
							| 
									
										
										
										
											2019-05-27 13:42:29 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         import readline  # NoQA | 
					
						
							|  |  |  |     except ImportError: | 
					
						
							| 
									
										
										
										
											2024-05-09 17:47:31 +02:00
										 |  |  |         readline = None | 
					
						
							| 
									
										
										
										
											2019-05-27 13:42:29 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-01 20:39:16 +01:00
										 |  |  |     interactive_hook = getattr(sys, "__interactivehook__", None) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if interactive_hook is not None: | 
					
						
							|  |  |  |         interactive_hook() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if interactive_hook is site.register_readline: | 
					
						
							|  |  |  |         # Fix the completer function to use the interactive console locals | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             import rlcompleter | 
					
						
							|  |  |  |         except: | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2024-05-09 17:47:31 +02:00
										 |  |  |             if readline is not None: | 
					
						
							|  |  |  |                 completer = rlcompleter.Completer(console.locals) | 
					
						
							|  |  |  |                 readline.set_completer(completer.complete) | 
					
						
							| 
									
										
										
										
											2024-03-01 20:39:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-31 23:15:44 +02:00
										 |  |  |     repl_thread = REPLThread(name="Interactive thread") | 
					
						
							| 
									
										
										
										
											2019-05-27 13:42:29 +02:00
										 |  |  |     repl_thread.daemon = True | 
					
						
							|  |  |  |     repl_thread.start() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while True: | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             loop.run_forever() | 
					
						
							|  |  |  |         except KeyboardInterrupt: | 
					
						
							| 
									
										
										
										
											2024-05-31 23:15:44 +02:00
										 |  |  |             keyboard_interrupted = True | 
					
						
							| 
									
										
										
										
											2019-05-27 13:42:29 +02:00
										 |  |  |             if repl_future and not repl_future.done(): | 
					
						
							|  |  |  |                 repl_future.cancel() | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             break | 
					
						
							| 
									
										
										
										
											2024-05-31 23:15:44 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     console.write('exiting asyncio REPL...\n') | 
					
						
							|  |  |  |     sys.exit(return_code) |