mirror of
				https://github.com/python/cpython.git
				synced 2025-10-30 21:21:22 +00:00 
			
		
		
		
	 721459831a
			
		
	
	
		721459831a
		
			
		
	
	
	
	
		
			
			(cherry picked from commit f49df4f486)
Co-authored-by: Eugene Triguba <eugenetriguba@gmail.com>
		
	
			
		
			
				
	
	
		
			141 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			141 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| from code import InteractiveConsole
 | |
| from functools import partial
 | |
| from typing import Iterable
 | |
| from unittest.mock import MagicMock
 | |
| 
 | |
| from _pyrepl.console import Console, Event
 | |
| from _pyrepl.readline import ReadlineAlikeReader, ReadlineConfig
 | |
| from _pyrepl.simple_interact import _strip_final_indent
 | |
| 
 | |
| 
 | |
| def multiline_input(reader: ReadlineAlikeReader, namespace: dict | None = None):
 | |
|     saved = reader.more_lines
 | |
|     try:
 | |
|         reader.more_lines = partial(more_lines, namespace=namespace)
 | |
|         reader.ps1 = reader.ps2 = ">>>"
 | |
|         reader.ps3 = reader.ps4 = "..."
 | |
|         return reader.readline()
 | |
|     finally:
 | |
|         reader.more_lines = saved
 | |
|         reader.paste_mode = False
 | |
| 
 | |
| 
 | |
| def more_lines(text: str, namespace: dict | None = None):
 | |
|     if namespace is None:
 | |
|         namespace = {}
 | |
|     src = _strip_final_indent(text)
 | |
|     console = InteractiveConsole(namespace, filename="<stdin>")
 | |
|     try:
 | |
|         code = console.compile(src, "<stdin>", "single")
 | |
|     except (OverflowError, SyntaxError, ValueError):
 | |
|         return False
 | |
|     else:
 | |
|         return code is None
 | |
| 
 | |
| 
 | |
| def code_to_events(code: str):
 | |
|     for c in code:
 | |
|         yield Event(evt="key", data=c, raw=bytearray(c.encode("utf-8")))
 | |
| 
 | |
| 
 | |
| def prepare_reader(console: Console, **kwargs):
 | |
|     config = ReadlineConfig(readline_completer=None)
 | |
|     reader = ReadlineAlikeReader(console=console, config=config)
 | |
|     reader.more_lines = partial(more_lines, namespace=None)
 | |
|     reader.paste_mode = True  # Avoid extra indents
 | |
| 
 | |
|     def get_prompt(lineno, cursor_on_line) -> str:
 | |
|         return ""
 | |
| 
 | |
|     reader.get_prompt = get_prompt  # Remove prompt for easier calculations of (x, y)
 | |
| 
 | |
|     for key, val in kwargs.items():
 | |
|         setattr(reader, key, val)
 | |
| 
 | |
|     return reader
 | |
| 
 | |
| 
 | |
| def prepare_console(events: Iterable[Event], **kwargs):
 | |
|     console = MagicMock()
 | |
|     console.get_event.side_effect = events
 | |
|     console.height = 100
 | |
|     console.width = 80
 | |
|     for key, val in kwargs.items():
 | |
|         setattr(console, key, val)
 | |
|     return console
 | |
| 
 | |
| 
 | |
| def handle_all_events(
 | |
|     events, prepare_console=prepare_console, prepare_reader=prepare_reader
 | |
| ):
 | |
|     console = prepare_console(events)
 | |
|     reader = prepare_reader(console)
 | |
|     try:
 | |
|         while True:
 | |
|             reader.handle1()
 | |
|     except StopIteration:
 | |
|         pass
 | |
|     return reader, console
 | |
| 
 | |
| 
 | |
| handle_events_narrow_console = partial(
 | |
|     handle_all_events,
 | |
|     prepare_console=partial(prepare_console, width=10),
 | |
| )
 | |
| 
 | |
| 
 | |
| class FakeConsole(Console):
 | |
|     def __init__(self, events, encoding="utf-8"):
 | |
|         self.events = iter(events)
 | |
|         self.encoding = encoding
 | |
|         self.screen = []
 | |
|         self.height = 100
 | |
|         self.width = 80
 | |
| 
 | |
|     def get_event(self, block: bool = True) -> Event | None:
 | |
|         return next(self.events)
 | |
| 
 | |
|     def getpending(self) -> Event:
 | |
|         return self.get_event(block=False)
 | |
| 
 | |
|     def getheightwidth(self) -> tuple[int, int]:
 | |
|         return self.height, self.width
 | |
| 
 | |
|     def refresh(self, screen: list[str], xy: tuple[int, int]) -> None:
 | |
|         pass
 | |
| 
 | |
|     def prepare(self) -> None:
 | |
|         pass
 | |
| 
 | |
|     def restore(self) -> None:
 | |
|         pass
 | |
| 
 | |
|     def move_cursor(self, x: int, y: int) -> None:
 | |
|         pass
 | |
| 
 | |
|     def set_cursor_vis(self, visible: bool) -> None:
 | |
|         pass
 | |
| 
 | |
|     def push_char(self, char: int | bytes) -> None:
 | |
|         pass
 | |
| 
 | |
|     def beep(self) -> None:
 | |
|         pass
 | |
| 
 | |
|     def clear(self) -> None:
 | |
|         pass
 | |
| 
 | |
|     def finish(self) -> None:
 | |
|         pass
 | |
| 
 | |
|     def flushoutput(self) -> None:
 | |
|         pass
 | |
| 
 | |
|     def forgetinput(self) -> None:
 | |
|         pass
 | |
| 
 | |
|     def wait(self) -> None:
 | |
|         pass
 | |
| 
 | |
|     def repaint(self) -> None:
 | |
|         pass
 |