- Notifications
You must be signed in to change notification settings - Fork 31.7k
/
Copy pathsimple_interact.py
165 lines (138 loc) · 5.15 KB
/
simple_interact.py
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# 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__ importannotations
import_sitebuiltins
importfunctools
importos
importsys
importcode
from .readlineimport_get_reader, multiline_input
TYPE_CHECKING=False
ifTYPE_CHECKING:
fromtypingimportAny
_error: tuple[type[Exception], ...] |type[Exception]
try:
from .unix_consoleimport_error
exceptModuleNotFoundError:
from .windows_consoleimport_error
defcheck() ->str:
"""Returns the error message if there is a problem initializing the state."""
try:
_get_reader()
except_errorase:
ifterm:=os.environ.get("TERM", ""):
term=f"; TERM={term}"
returnstr(str(e) orrepr(e) or"unknown error") +term
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)
ifn>0andtext[n-1] =="\n":
returnshort
returntext
def_clear_screen():
reader=_get_reader()
reader.scheduled_commands.append("clear_screen")
REPL_COMMANDS= {
"exit": _sitebuiltins.Quitter('exit', ''),
"quit": _sitebuiltins.Quitter('quit' ,''),
"copyright": _sitebuiltins._Printer('copyright', sys.copyright),
"help": _sitebuiltins._Helper(),
"clear": _clear_screen,
"\x1a": _sitebuiltins.Quitter('\x1a', ''),
}
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)
iflen(lines) ==1:
returnFalse
last_line=lines[-1]
was_indented=last_line.startswith((" ", "\t"))
not_empty=last_line.strip() !=""
incomplete=notlast_line.endswith("\n")
return (was_indentedornot_empty) andincomplete
else:
returncodeisNone
defrun_multiline_interactive_console(
console: code.InteractiveConsole,
*,
future_flags: int=0,
) ->None:
from .readlineimport_setup
_setup(console.locals)
iffuture_flags:
console.compile.compiler.flags|=future_flags
more_lines=functools.partial(_more_lines, console)
input_n=0
defmaybe_run_command(statement: str) ->bool:
statement=statement.strip()
ifstatementinconsole.localsorstatementnotinREPL_COMMANDS:
returnFalse
reader=_get_reader()
reader.history.pop() # skip internal commands in history
command=REPL_COMMANDS[statement]
ifcallable(command):
# Make sure that history does not change because of commands
withreader.suspend_history():
command()
returnTrue
returnFalse
while1:
try:
try:
sys.stdout.flush()
exceptException:
pass
ps1=getattr(sys, "ps1", ">>> ")
ps2=getattr(sys, "ps2", "... ")
try:
statement=multiline_input(more_lines, ps1, ps2)
exceptEOFError:
break
ifmaybe_run_command(statement):
continue
input_name=f"<python-input-{input_n}>"
more=console.push(_strip_final_indent(statement), filename=input_name, _symbol="single") # type: ignore[call-arg]
assertnotmore
input_n+=1
exceptKeyboardInterrupt:
r=_get_reader()
ifr.input_transisr.isearch_trans:
r.do_cmd(("isearch-end", [""]))
r.pos=len(r.get_unicode())
r.dirty=True
r.refresh()
r.in_bracketed_paste=False
console.write("\nKeyboardInterrupt\n")
console.resetbuffer()
exceptMemoryError:
console.write("\nMemoryError\n")
console.resetbuffer()