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.
This commit is contained in:
Kurt B. Kaiser 2003-01-25 21:33:40 +00:00
parent cd5c8c2120
commit bc2861313c
3 changed files with 45 additions and 40 deletions

View File

@ -399,16 +399,16 @@ class ModifiedInterpreter(InteractiveInterpreter):
self.tkconsole.resetoutput()
self.active_seq = None
how, what = response
file = self.tkconsole.console
console = self.tkconsole.console
if how == "OK":
if what is not None:
print >>file, `what`
print >>console, `what`
elif how == "EXCEPTION":
mod, name, args, tb = what
print >>file, 'Traceback (most recent call last):'
exclude = ("run.py", "rpc.py")
self.cleanup_traceback(tb, exclude)
traceback.print_list(tb, file=file)
print >>console, 'Traceback (most recent call last):'
exclude = ("run.py", "rpc.py", "RemoteDebugger.py", "bdb.py")
self.cleanup_traceback(tb, exclude, console)
traceback.print_list(tb, file=console)
# try to reinstantiate the exception, stuff in the args:
try:
etype = eval(mod + '.' + name)
@ -419,18 +419,20 @@ class ModifiedInterpreter(InteractiveInterpreter):
val = args
lines = traceback.format_exception_only(etype, val)
for line in lines[:-1]:
traceback._print(file, line, '')
traceback._print(file, lines[-1], '')
traceback._print(console, line, '')
traceback._print(console, lines[-1], '')
if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
self.remote_stack_viewer()
elif how == "ERROR":
errmsg = "PyShell.ModifiedInterpreter: Subprocess ERROR:\n"
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()
def cleanup_traceback(self, tb, exclude):
def cleanup_traceback(self, tb, exclude, console):
"Remove excluded traces from beginning/end of tb; get cached lines"
orig_tb = tb[:]
while tb:
for rpcfile in exclude:
if tb[0][0].count(rpcfile):
@ -445,6 +447,11 @@ class ModifiedInterpreter(InteractiveInterpreter):
else:
break
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)):
fn, ln, nm, line = tb[i]
if nm == '?':
@ -617,31 +624,26 @@ class ModifiedInterpreter(InteractiveInterpreter):
warnings.filters[:] = self.save_warnings_filters
self.save_warnings_filters = None
debugger = self.debugger
if not debugger and self.rpcclt is not None:
self.tkconsole.beginexecuting()
self.active_seq = self.rpcclt.asynccall("exec", "runcode",
(code,), {})
return
self.tkconsole.beginexecuting()
try:
self.tkconsole.beginexecuting()
try:
if debugger:
debugger.run(code, self.locals)
else:
exec code in self.locals
except SystemExit:
if tkMessageBox.askyesno(
"Exit?",
"Do you want to exit altogether?",
default="yes",
master=self.tkconsole.text):
raise
else:
self.showtraceback()
except:
if not debugger and self.rpcclt is not None:
self.active_seq = self.rpcclt.asynccall("exec", "runcode",
(code,), {})
elif debugger:
debugger.run(code, self.locals)
else:
exec code in self.locals
except SystemExit:
if tkMessageBox.askyesno(
"Exit?",
"Do you want to exit altogether?",
default="yes",
master=self.tkconsole.text):
raise
else:
self.showtraceback()
finally:
self.tkconsole.endexecuting()
except:
self.showtraceback()
def write(self, s):
"Override base class method"

View File

@ -287,19 +287,21 @@ class GUIAdapter:
class IdbProxy:
def __init__(self, conn, oid):
def __init__(self, conn, shell, oid):
self.oid = oid
self.conn = conn
self.shell = shell
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)
##print "return %s" % `value`
##print "**IdbProxy.call %s returns %s" % (methodname, `value`)
return value
def run(self, cmd, locals):
# 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):
# passing frame and traceback IDs, not the objects themselves
@ -352,7 +354,7 @@ def start_remote_debugger(rpcclt, pyshell):
idb_adap_oid = rpcclt.remotecall("exec", "start_the_debugger",\
(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_adap = GUIAdapter(rpcclt, gui)
rpcclt.register(gui_adap_oid, gui_adap)

View File

@ -361,9 +361,10 @@ class SocketIO:
seq, resq = message
self.debug("pollresponse:%d:myseq:%s" % (seq, myseq))
if resq[0] == "call":
self.debug("pollresponse:%d:call_localcall" % seq)
self.debug("pollresponse:%d:localcall:call:" % seq)
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))
continue
elif seq == myseq: