Commit da004130 authored by Kurt B. Kaiser's avatar Kurt B. Kaiser

M PyShell.py

M RemoteDebugger.py
M rpc.py

Fix the incorrect shell exception tracebacks generated when running
under debugger control:

1. Use rpc.SocketIO.asynccall() instead of remotecall() to handle the
   IdbProxy.run() command.
2. Add a 'shell' attribute to RemoteDebugger.IdbProxy to allow setting
   of ModifiedInterpreter's active_seq attribute from RemoteDebugger code.
3. Cleanup PyShell.ModifiedInterpreter.runcode() and remove ambiguity
   regarding use of begin/endexecuting().
4. In runcode() and cleanup_traceback() use 'console' instead of 'file' to
   denote the entity to which the exception traceback is printed.
5. Enhance cleanup_traceback() so if the traceback is pruned entirely away
   (the error is in IDLE internals) it will be displayed in its entirety
   instead.
6. ModifiedInterpreter.runcode() now prints ERROR RPC returns to both
   console and __stderr__.
7. Make a small tweak to the rpc.py debug messages.
parent ab3cf81e
...@@ -399,16 +399,16 @@ class ModifiedInterpreter(InteractiveInterpreter): ...@@ -399,16 +399,16 @@ class ModifiedInterpreter(InteractiveInterpreter):
self.tkconsole.resetoutput() self.tkconsole.resetoutput()
self.active_seq = None self.active_seq = None
how, what = response how, what = response
file = self.tkconsole.console console = self.tkconsole.console
if how == "OK": if how == "OK":
if what is not None: if what is not None:
print >>file, `what` print >>console, `what`
elif how == "EXCEPTION": elif how == "EXCEPTION":
mod, name, args, tb = what mod, name, args, tb = what
print >>file, 'Traceback (most recent call last):' print >>console, 'Traceback (most recent call last):'
exclude = ("run.py", "rpc.py") exclude = ("run.py", "rpc.py", "RemoteDebugger.py", "bdb.py")
self.cleanup_traceback(tb, exclude) self.cleanup_traceback(tb, exclude, console)
traceback.print_list(tb, file=file) traceback.print_list(tb, file=console)
# try to reinstantiate the exception, stuff in the args: # try to reinstantiate the exception, stuff in the args:
try: try:
etype = eval(mod + '.' + name) etype = eval(mod + '.' + name)
...@@ -419,18 +419,20 @@ class ModifiedInterpreter(InteractiveInterpreter): ...@@ -419,18 +419,20 @@ class ModifiedInterpreter(InteractiveInterpreter):
val = args val = args
lines = traceback.format_exception_only(etype, val) lines = traceback.format_exception_only(etype, val)
for line in lines[:-1]: for line in lines[:-1]:
traceback._print(file, line, '') traceback._print(console, line, '')
traceback._print(file, lines[-1], '') traceback._print(console, lines[-1], '')
if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"): if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
self.remote_stack_viewer() self.remote_stack_viewer()
elif how == "ERROR": elif how == "ERROR":
errmsg = "PyShell.ModifiedInterpreter: Subprocess ERROR:\n" errmsg = "PyShell.ModifiedInterpreter: Subprocess ERROR:\n"
print >>sys.__stderr__, errmsg, what print >>sys.__stderr__, errmsg, what
print >>file, errmsg, what print >>console, errmsg, what
# we received a response to the currently active seq number:
self.tkconsole.endexecuting() self.tkconsole.endexecuting()
def cleanup_traceback(self, tb, exclude): def cleanup_traceback(self, tb, exclude, console):
"Remove excluded traces from beginning/end of tb; get cached lines" "Remove excluded traces from beginning/end of tb; get cached lines"
orig_tb = tb[:]
while tb: while tb:
for rpcfile in exclude: for rpcfile in exclude:
if tb[0][0].count(rpcfile): if tb[0][0].count(rpcfile):
...@@ -445,6 +447,11 @@ class ModifiedInterpreter(InteractiveInterpreter): ...@@ -445,6 +447,11 @@ class ModifiedInterpreter(InteractiveInterpreter):
else: else:
break break
del tb[-1] del tb[-1]
if len(tb) == 0:
# error was in IDLE internals, don't prune!
tb[:] = orig_tb[:]
print>>sys.__stderr__, "** IDLE Internal Error: ", tb
print>>console, "** IDLE Internal Error **"
for i in range(len(tb)): for i in range(len(tb)):
fn, ln, nm, line = tb[i] fn, ln, nm, line = tb[i]
if nm == '?': if nm == '?':
...@@ -617,31 +624,26 @@ class ModifiedInterpreter(InteractiveInterpreter): ...@@ -617,31 +624,26 @@ class ModifiedInterpreter(InteractiveInterpreter):
warnings.filters[:] = self.save_warnings_filters warnings.filters[:] = self.save_warnings_filters
self.save_warnings_filters = None self.save_warnings_filters = None
debugger = self.debugger debugger = self.debugger
if not debugger and self.rpcclt is not None: self.tkconsole.beginexecuting()
self.tkconsole.beginexecuting()
self.active_seq = self.rpcclt.asynccall("exec", "runcode",
(code,), {})
return
try: try:
self.tkconsole.beginexecuting() if not debugger and self.rpcclt is not None:
try: self.active_seq = self.rpcclt.asynccall("exec", "runcode",
if debugger: (code,), {})
debugger.run(code, self.locals) elif debugger:
else: debugger.run(code, self.locals)
exec code in self.locals else:
except SystemExit: exec code in self.locals
if tkMessageBox.askyesno( except SystemExit:
"Exit?", if tkMessageBox.askyesno(
"Do you want to exit altogether?", "Exit?",
default="yes", "Do you want to exit altogether?",
master=self.tkconsole.text): default="yes",
raise master=self.tkconsole.text):
else: raise
self.showtraceback() else:
except:
self.showtraceback() self.showtraceback()
finally: except:
self.tkconsole.endexecuting() self.showtraceback()
def write(self, s): def write(self, s):
"Override base class method" "Override base class method"
......
...@@ -287,19 +287,21 @@ class GUIAdapter: ...@@ -287,19 +287,21 @@ class GUIAdapter:
class IdbProxy: class IdbProxy:
def __init__(self, conn, oid): def __init__(self, conn, shell, oid):
self.oid = oid self.oid = oid
self.conn = conn self.conn = conn
self.shell = shell
def call(self, methodname, *args, **kwargs): def call(self, methodname, *args, **kwargs):
##print "call %s %s %s" % (methodname, args, kwargs) ##print "**IdbProxy.call %s %s %s" % (methodname, args, kwargs)
value = self.conn.remotecall(self.oid, methodname, args, kwargs) value = self.conn.remotecall(self.oid, methodname, args, kwargs)
##print "return %s" % `value` ##print "**IdbProxy.call %s returns %s" % (methodname, `value`)
return value return value
def run(self, cmd, locals): def run(self, cmd, locals):
# Ignores locals on purpose! # Ignores locals on purpose!
self.call("run", cmd) seq = self.conn.asynccall(self.oid, "run", (cmd,), {})
self.shell.interp.active_seq = seq
def get_stack(self, frame, tbid): def get_stack(self, frame, tbid):
# passing frame and traceback IDs, not the objects themselves # passing frame and traceback IDs, not the objects themselves
...@@ -352,7 +354,7 @@ def start_remote_debugger(rpcclt, pyshell): ...@@ -352,7 +354,7 @@ def start_remote_debugger(rpcclt, pyshell):
idb_adap_oid = rpcclt.remotecall("exec", "start_the_debugger",\ idb_adap_oid = rpcclt.remotecall("exec", "start_the_debugger",\
(gui_adap_oid,), {}) (gui_adap_oid,), {})
idb_proxy = IdbProxy(rpcclt, idb_adap_oid) idb_proxy = IdbProxy(rpcclt, pyshell, idb_adap_oid)
gui = Debugger.Debugger(pyshell, idb_proxy) gui = Debugger.Debugger(pyshell, idb_proxy)
gui_adap = GUIAdapter(rpcclt, gui) gui_adap = GUIAdapter(rpcclt, gui)
rpcclt.register(gui_adap_oid, gui_adap) rpcclt.register(gui_adap_oid, gui_adap)
......
...@@ -361,9 +361,10 @@ class SocketIO: ...@@ -361,9 +361,10 @@ class SocketIO:
seq, resq = message seq, resq = message
self.debug("pollresponse:%d:myseq:%s" % (seq, myseq)) self.debug("pollresponse:%d:myseq:%s" % (seq, myseq))
if resq[0] == "call": if resq[0] == "call":
self.debug("pollresponse:%d:call_localcall" % seq) self.debug("pollresponse:%d:localcall:call:" % seq)
response = self.localcall(resq) response = self.localcall(resq)
self.debug("pollresponse:%d:response:%s" % (seq, response)) self.debug("pollresponse:%d:localcall:response:%s"
% (seq, response))
self.putmessage((seq, response)) self.putmessage((seq, response))
continue continue
elif seq == myseq: elif seq == myseq:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment