140 lines
4.5 KiB
Python
140 lines
4.5 KiB
Python
import bdb
|
|
import json
|
|
import sys
|
|
from types import FrameType
|
|
|
|
|
|
class PyBugBridgeDebugger(bdb.Bdb):
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.waiting = False
|
|
|
|
def send(self, msg: dict):
|
|
sys.stdout.write(json.dumps(msg) + "\n")
|
|
sys.stdout.flush()
|
|
|
|
def recv(self) -> dict:
|
|
return json.loads(sys.stdin.readline())
|
|
|
|
def user_line(self, frame: FrameType):
|
|
print("TRACE:", frame.f_code.co_filename, frame.f_lineno)
|
|
self.send(
|
|
{
|
|
"event": "stopped",
|
|
"file": frame.f_code.co_filename,
|
|
"line": frame.f_lineno,
|
|
}
|
|
)
|
|
|
|
self.interaction_loop(frame)
|
|
|
|
def interaction_loop(self, frame: FrameType):
|
|
while True:
|
|
print("DEBUG: waiting for command", file=sys.stderr, flush=True)
|
|
cmd = self.recv()
|
|
print(f"DEBUG: received command {cmd}", file=sys.stderr, flush=True)
|
|
|
|
match cmd["cmd"]:
|
|
case "continue":
|
|
return self.set_continue()
|
|
case "step":
|
|
return self.set_step()
|
|
case "next":
|
|
return self.set_next(frame)
|
|
case "locals":
|
|
self.send(
|
|
{
|
|
"request_id": cmd["request_id"],
|
|
"event": "locals",
|
|
"vars": {
|
|
k: repr(v)
|
|
for k, v in frame.f_locals.items()
|
|
if k not in frame.f_globals.keys()
|
|
},
|
|
}
|
|
)
|
|
case "eval":
|
|
try:
|
|
result = eval(cmd["expr"], frame.f_globals, frame.f_locals)
|
|
self.send(
|
|
{
|
|
"request_id": cmd["request_id"],
|
|
"event": "eval",
|
|
"status": "ok",
|
|
"value": repr(result),
|
|
}
|
|
)
|
|
except Exception as e:
|
|
self.send(
|
|
{
|
|
"request_id": cmd["request_id"],
|
|
"event": "eval",
|
|
"status": "error",
|
|
"value": str(e),
|
|
}
|
|
)
|
|
case "break":
|
|
err = self.set_break(cmd["file"], cmd["line"])
|
|
if err:
|
|
self.send(
|
|
{
|
|
"request_id": cmd["request_id"],
|
|
"event": "break",
|
|
"status": "error",
|
|
"error": err,
|
|
}
|
|
)
|
|
else:
|
|
self.send(
|
|
{
|
|
"request_id": cmd["request_id"],
|
|
"event": "break",
|
|
"status": "ok",
|
|
}
|
|
)
|
|
case "unbreak":
|
|
err = self.clear_break(cmd["file"], cmd["line"])
|
|
if err:
|
|
self.send(
|
|
{
|
|
"request_id": cmd["request_id"],
|
|
"event": "unbreak",
|
|
"status": "error",
|
|
"error": err,
|
|
}
|
|
)
|
|
else:
|
|
self.send(
|
|
{
|
|
"request_id": cmd["request_id"],
|
|
"event": "unbreak",
|
|
"status": "ok",
|
|
}
|
|
)
|
|
|
|
|
|
def main():
|
|
if len(sys.argv) < 2:
|
|
print("Usage: pydbug_runtime <script.py>")
|
|
|
|
script = sys.argv[1]
|
|
sys.argv = sys.argv[1:]
|
|
|
|
dbg = PyBugBridgeDebugger()
|
|
|
|
with open(script, "rb") as f:
|
|
code = compile(f.read(), script, "exec")
|
|
|
|
globals_dict = {
|
|
"__name__": "__main__",
|
|
"__file__": script,
|
|
"__package__": None,
|
|
}
|
|
|
|
dbg.set_step()
|
|
dbg.run(code, globals_dict, globals_dict)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|