1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
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) -> MagicMock | Console:
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
|