Skip to content

Commit b48c6d2

Browse files
dberlinmarcan
authored andcommitted
Add ipython shell to proxyclient
Same functionality as the readline shell, but based on ipython so that it has nicer help/autocomplete/etc Signed-off-by: Daniel Berlin <[email protected]>
1 parent 232836b commit b48c6d2

3 files changed

Lines changed: 212 additions & 0 deletions

File tree

proxyclient/m1n1/ishell.py

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
# SPDX-License-Identifier: MIT
2+
import builtins
3+
import sys
4+
5+
import __main__
6+
from IPython import embed
7+
from traitlets.config import get_config
8+
9+
c = get_config()
10+
c.InteractiveShellEmbed.colors = "Linux"
11+
from inspect import signature
12+
13+
from . import sysreg
14+
from .proxy import *
15+
from .proxyutils import *
16+
from .utils import *
17+
18+
__all__ = ["run_ishell"]
19+
20+
21+
cmd_list = {}
22+
subcmd_list = {}
23+
# Debug levels
24+
DBL_NONE = 0
25+
DBL_INFO = 1
26+
DBL_TRACE = 2
27+
DBL_DEBUG = 3
28+
DBL_EDEBUG = 4
29+
30+
db_level = DBL_NONE
31+
32+
33+
def debug_cmd(db=None):
34+
"""Set debug level to integer %d(none)...%d(extreme debug)""" % (
35+
DBL_NONE,
36+
DBL_EDEBUG,
37+
)
38+
global db_level
39+
if db:
40+
db_level = db
41+
print("debug level=%d" % db_level)
42+
43+
44+
def help_cmd(arg=None):
45+
if db_level >= DBL_DEBUG:
46+
print("arg=%s" % repr(arg))
47+
if arg:
48+
# cmd = arg.__qualname__
49+
if callable(arg):
50+
cmd = arg.__name__
51+
elif isinstance(arg, str):
52+
cmd = arg
53+
else:
54+
print("Unknown command: %s" % repr(arg))
55+
return
56+
if db_level >= DBL_DEBUG:
57+
print("cmd=%s" % repr(cmd))
58+
if cmd not in cmd_list:
59+
print("Undocumented command %s" % cmd)
60+
return
61+
hinfo = cmd_list[cmd]
62+
if isinstance(hinfo, str):
63+
print("%-10s : %s" % (cmd, hinfo))
64+
return
65+
if cmd in subcmd_list:
66+
clist = subcmd_list[cmd]
67+
aname = cmd
68+
if db_level >= DBL_DEBUG:
69+
print("subcmd_list[%s] = %s" % (repr(cmd), repr(clist)))
70+
else:
71+
print("command %s is not documented" % cmd)
72+
return
73+
else:
74+
clist = cmd_list
75+
aname = "top level"
76+
print("Note: To display a category's commands quote the name e.g. help('HV')")
77+
print("List of %s commands:" % aname)
78+
for cmd in clist.keys():
79+
hinfo = clist[cmd]
80+
if isinstance(hinfo, str):
81+
msg = hinfo.strip().split("\n", 1)[0]
82+
elif isinstance(hinfo, int):
83+
msg = "%s category - %d subcommands" % (cmd, hinfo)
84+
else:
85+
print("%s ?" % cmd)
86+
continue
87+
if len(cmd) <= 10:
88+
print("%-10s : %s" % (cmd, msg))
89+
else:
90+
print("%s:\n %s" % (cmd, msg))
91+
92+
93+
# commands is a dictionary for constructing the
94+
# InteractiveConsole with. It adds in the callables
95+
# in proxy utils iface and sysreg into commands
96+
def run_ishell(commands, msg=""):
97+
saved_display = sys.displayhook
98+
try:
99+
100+
def display(val):
101+
if isinstance(val, int) and not isinstance(val, bool):
102+
builtins._ = val
103+
print(hex(val))
104+
elif callable(val):
105+
val()
106+
else:
107+
saved_display(val)
108+
109+
sys.displayhook = display
110+
111+
# convenience
112+
commands["h"] = hex
113+
commands["sysreg"] = sysreg
114+
115+
if "proxy" in commands and "p" not in commands:
116+
commands["p"] = commands["proxy"]
117+
if "utils" in commands and "u" not in commands:
118+
commands["u"] = commands["utils"]
119+
120+
for obj_name in ("iface", "p", "u"):
121+
obj = commands.get(obj_name)
122+
obj_class = type(obj)
123+
if obj is None:
124+
continue
125+
126+
for attr in dir(obj_class):
127+
if attr in commands or attr.startswith("_"):
128+
continue
129+
130+
member = getattr(obj_class, attr)
131+
if callable(member) and not isinstance(member, property):
132+
cmd = getattr(obj, attr)
133+
commands[attr] = cmd
134+
135+
for attr in dir(sysreg):
136+
commands[attr] = getattr(sysreg, attr)
137+
138+
commands["help"] = help_cmd
139+
commands["debug"] = debug_cmd
140+
for obj_name in commands.keys():
141+
obj = commands.get(obj_name)
142+
if obj is None or obj_name.startswith("_"):
143+
continue
144+
if callable(obj) and not isinstance(obj, property):
145+
try:
146+
desc = obj_name + str(signature(obj))
147+
except:
148+
continue
149+
qn = obj.__qualname__
150+
if qn.find(".") > 0:
151+
a = qn.split(".")
152+
if a[0] not in subcmd_list:
153+
subcmd_list[a[0]] = {}
154+
if a[0] not in cmd_list:
155+
cmd_list[a[0]] = 1
156+
else:
157+
cmd_list[a[0]] += 1
158+
clist = subcmd_list[a[0]]
159+
else:
160+
clist = None
161+
if commands[obj_name].__doc__:
162+
desc += " - " + commands[obj_name].__doc__
163+
cmd_list[obj_name] = desc
164+
if isinstance(clist, dict):
165+
clist[obj_name] = desc
166+
167+
embed(config=c, extensions=["m1n1.ishell_ext"], header=msg, user_ns=commands)
168+
finally:
169+
sys.displayhook = saved_display
170+
171+
172+
if __name__ == "__main__":
173+
from .setup import *
174+
175+
commands = dict(__main__.__dict__)
176+
177+
run_ishell(commands, msg="Have fun!")

proxyclient/m1n1/ishell_ext.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# SPDX-License-Identifier: MIT
2+
# Extension for ipython to handle monitor polling
3+
# and simd context after each executed line
4+
5+
6+
class PostExecuteWatcher(object):
7+
def __init__(self, ip):
8+
self.shell = ip
9+
10+
def post_execute(self):
11+
mon = self.shell.user_ns.get("mon", None)
12+
if mon != None:
13+
try:
14+
mon.poll()
15+
except Exception as e:
16+
print(f"mon.poll() failed: {e!r}")
17+
u = self.shell.user_ns.get("u", None)
18+
if u != None:
19+
u.push_simd()
20+
21+
22+
def load_ipython_extension(ip):
23+
pew = PostExecuteWatcher(ip)
24+
ip.events.register("post_execute", pew.post_execute)

proxyclient/tools/ishell.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/usr/bin/env python3
2+
# SPDX-License-Identifier: MIT
3+
import pathlib
4+
import sys
5+
6+
sys.path.append(str(pathlib.Path(__file__).resolve().parents[1]))
7+
8+
from m1n1.setup import *
9+
from m1n1.ishell import run_ishell
10+
11+
run_ishell(globals(), msg="Have fun!")

0 commit comments

Comments
 (0)