| 
									
										
										
										
											2024-05-05 21:32:23 +02:00
										 |  |  | #   Copyright 2000-2010 Michael Hudson-Doyle <micahel@gmail.com> | 
					
						
							|  |  |  | #                       Armin Rigo | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #                        All Rights Reserved | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Permission to use, copy, modify, and distribute this software and | 
					
						
							|  |  |  | # its documentation for any purpose is hereby granted without fee, | 
					
						
							|  |  |  | # provided that the above copyright notice appear in all copies and | 
					
						
							|  |  |  | # that both that copyright notice and this permission notice appear in | 
					
						
							|  |  |  | # supporting documentation. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # THE AUTHOR MICHAEL HUDSON DISCLAIMS ALL WARRANTIES WITH REGARD TO | 
					
						
							|  |  |  | # THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | 
					
						
							|  |  |  | # AND FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, | 
					
						
							|  |  |  | # INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER | 
					
						
							|  |  |  | # RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF | 
					
						
							|  |  |  | # CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | 
					
						
							|  |  |  | # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | """This is an alternative to python_reader which tries to emulate
 | 
					
						
							|  |  |  | the CPython prompt as closely as possible, with the exception of | 
					
						
							|  |  |  | allowing multiline input and multiline history entries. | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from __future__ import annotations | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import _sitebuiltins | 
					
						
							|  |  |  | import linecache | 
					
						
							| 
									
										
										
										
											2024-07-16 01:33:57 +02:00
										 |  |  | import functools | 
					
						
							| 
									
										
										
										
											2024-09-25 11:22:03 -07:00
										 |  |  | import os | 
					
						
							| 
									
										
										
										
											2024-05-05 21:32:23 +02:00
										 |  |  | import sys | 
					
						
							|  |  |  | import code | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from .readline import _get_reader, multiline_input | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-11 13:40:31 -04:00
										 |  |  | TYPE_CHECKING = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if TYPE_CHECKING: | 
					
						
							|  |  |  |     from typing import Any | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-31 00:49:03 -07:00
										 |  |  | _error: tuple[type[Exception], ...] | type[Exception] | 
					
						
							|  |  |  | try: | 
					
						
							|  |  |  |     from .unix_console import _error | 
					
						
							|  |  |  | except ModuleNotFoundError: | 
					
						
							|  |  |  |     from .windows_console import _error | 
					
						
							| 
									
										
										
										
											2024-05-05 21:32:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | def check() -> str: | 
					
						
							|  |  |  |     """Returns the error message if there is a problem initializing the state.""" | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         _get_reader() | 
					
						
							|  |  |  |     except _error as e: | 
					
						
							| 
									
										
										
										
											2024-09-25 11:22:03 -07:00
										 |  |  |         if term := os.environ.get("TERM", ""): | 
					
						
							|  |  |  |             term = f"; TERM={term}" | 
					
						
							|  |  |  |         return str(str(e) or repr(e) or "unknown error") + term | 
					
						
							| 
									
										
										
										
											2024-05-05 21:32:23 +02:00
										 |  |  |     return "" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _strip_final_indent(text: str) -> str: | 
					
						
							|  |  |  |     # kill spaces and tabs at the end, but only if they follow '\n'. | 
					
						
							|  |  |  |     # meant to remove the auto-indentation only (although it would of | 
					
						
							|  |  |  |     # course also remove explicitly-added indentation). | 
					
						
							|  |  |  |     short = text.rstrip(" \t") | 
					
						
							|  |  |  |     n = len(short) | 
					
						
							|  |  |  |     if n > 0 and text[n - 1] == "\n": | 
					
						
							|  |  |  |         return short | 
					
						
							|  |  |  |     return text | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-25 17:15:54 +01:00
										 |  |  | def _clear_screen(): | 
					
						
							|  |  |  |     reader = _get_reader() | 
					
						
							|  |  |  |     reader.scheduled_commands.append("clear_screen") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-05 21:32:23 +02:00
										 |  |  | REPL_COMMANDS = { | 
					
						
							|  |  |  |     "exit": _sitebuiltins.Quitter('exit', ''), | 
					
						
							|  |  |  |     "quit": _sitebuiltins.Quitter('quit' ,''), | 
					
						
							|  |  |  |     "copyright": _sitebuiltins._Printer('copyright', sys.copyright), | 
					
						
							| 
									
										
										
										
											2025-01-21 22:04:30 +01:00
										 |  |  |     "help": _sitebuiltins._Helper(), | 
					
						
							| 
									
										
										
										
											2024-05-25 17:15:54 +01:00
										 |  |  |     "clear": _clear_screen, | 
					
						
							| 
									
										
										
										
											2024-07-30 05:03:52 -07:00
										 |  |  |     "\x1a": _sitebuiltins.Quitter('\x1a', ''), | 
					
						
							| 
									
										
										
										
											2024-05-05 21:32:23 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-16 01:33:57 +02:00
										 |  |  | def _more_lines(console: code.InteractiveConsole, unicodetext: str) -> bool: | 
					
						
							|  |  |  |     # ooh, look at the hack: | 
					
						
							|  |  |  |     src = _strip_final_indent(unicodetext) | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         code = console.compile(src, "<stdin>", "single") | 
					
						
							|  |  |  |     except (OverflowError, SyntaxError, ValueError): | 
					
						
							|  |  |  |         lines = src.splitlines(keepends=True) | 
					
						
							|  |  |  |         if len(lines) == 1: | 
					
						
							|  |  |  |             return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         last_line = lines[-1] | 
					
						
							|  |  |  |         was_indented = last_line.startswith((" ", "\t")) | 
					
						
							|  |  |  |         not_empty = last_line.strip() != "" | 
					
						
							|  |  |  |         incomplete = not last_line.endswith("\n") | 
					
						
							|  |  |  |         return (was_indented or not_empty) and incomplete | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         return code is None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-05 21:32:23 +02:00
										 |  |  | def run_multiline_interactive_console( | 
					
						
							| 
									
										
										
										
											2024-07-16 00:24:18 +02:00
										 |  |  |     console: code.InteractiveConsole, | 
					
						
							|  |  |  |     *, | 
					
						
							| 
									
										
										
										
											2024-05-31 16:26:02 -04:00
										 |  |  |     future_flags: int = 0, | 
					
						
							| 
									
										
										
										
											2024-05-05 21:32:23 +02:00
										 |  |  | ) -> None: | 
					
						
							|  |  |  |     from .readline import _setup | 
					
						
							| 
									
										
										
										
											2024-07-16 00:24:18 +02:00
										 |  |  |     _setup(console.locals) | 
					
						
							| 
									
										
										
										
											2024-05-05 21:32:23 +02:00
										 |  |  |     if future_flags: | 
					
						
							|  |  |  |         console.compile.compiler.flags |= future_flags | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-16 01:33:57 +02:00
										 |  |  |     more_lines = functools.partial(_more_lines, console) | 
					
						
							| 
									
										
										
										
											2024-05-05 21:32:23 +02:00
										 |  |  |     input_n = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def maybe_run_command(statement: str) -> bool: | 
					
						
							|  |  |  |         statement = statement.strip() | 
					
						
							|  |  |  |         if statement in console.locals or statement not in REPL_COMMANDS: | 
					
						
							|  |  |  |             return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         reader = _get_reader() | 
					
						
							|  |  |  |         reader.history.pop()  # skip internal commands in history | 
					
						
							|  |  |  |         command = REPL_COMMANDS[statement] | 
					
						
							|  |  |  |         if callable(command): | 
					
						
							| 
									
										
										
										
											2025-01-21 22:04:30 +01:00
										 |  |  |             # Make sure that history does not change because of commands | 
					
						
							|  |  |  |             with reader.suspend_history(): | 
					
						
							|  |  |  |                 command() | 
					
						
							| 
									
										
										
										
											2024-05-05 21:32:23 +02:00
										 |  |  |             return True | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-02 04:39:28 +08:00
										 |  |  |     while True: | 
					
						
							| 
									
										
										
										
											2024-05-05 21:32:23 +02:00
										 |  |  |         try: | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 sys.stdout.flush() | 
					
						
							|  |  |  |             except Exception: | 
					
						
							|  |  |  |                 pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             ps1 = getattr(sys, "ps1", ">>> ") | 
					
						
							|  |  |  |             ps2 = getattr(sys, "ps2", "... ") | 
					
						
							|  |  |  |             try: | 
					
						
							| 
									
										
										
										
											2024-05-22 01:28:32 -04:00
										 |  |  |                 statement = multiline_input(more_lines, ps1, ps2) | 
					
						
							| 
									
										
										
										
											2024-05-05 21:32:23 +02:00
										 |  |  |             except EOFError: | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if maybe_run_command(statement): | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             input_name = f"<python-input-{input_n}>" | 
					
						
							|  |  |  |             linecache._register_code(input_name, statement, "<stdin>")  # type: ignore[attr-defined] | 
					
						
							| 
									
										
										
										
											2024-05-21 19:16:56 -04:00
										 |  |  |             more = console.push(_strip_final_indent(statement), filename=input_name, _symbol="single")  # type: ignore[call-arg] | 
					
						
							| 
									
										
										
										
											2024-05-05 21:32:23 +02:00
										 |  |  |             assert not more | 
					
						
							|  |  |  |             input_n += 1 | 
					
						
							|  |  |  |         except KeyboardInterrupt: | 
					
						
							| 
									
										
										
										
											2024-07-16 01:38:54 +02:00
										 |  |  |             r = _get_reader() | 
					
						
							| 
									
										
										
										
											2024-09-25 11:22:03 -07:00
										 |  |  |             if r.input_trans is r.isearch_trans: | 
					
						
							|  |  |  |                 r.do_cmd(("isearch-end", [""])) | 
					
						
							| 
									
										
										
										
											2024-09-06 13:15:00 +02:00
										 |  |  |             r.pos = len(r.get_unicode()) | 
					
						
							|  |  |  |             r.dirty = True | 
					
						
							| 
									
										
										
										
											2024-07-16 01:38:54 +02:00
										 |  |  |             r.refresh() | 
					
						
							|  |  |  |             r.in_bracketed_paste = False | 
					
						
							|  |  |  |             console.write("\nKeyboardInterrupt\n") | 
					
						
							| 
									
										
										
										
											2024-05-05 21:32:23 +02:00
										 |  |  |             console.resetbuffer() | 
					
						
							|  |  |  |         except MemoryError: | 
					
						
							|  |  |  |             console.write("\nMemoryError\n") | 
					
						
							|  |  |  |             console.resetbuffer() |