M PyShell.py

M rpc.py

SF Bug 676398 Doesn't handle non-built-in exceptions
1. Move exception formatting to the subprocess; allows subclassing of
   exceptions, including subclasses created in the shell without
   introducing excessive complexity in the RPC mechanism.
2. Provide access to linecache from subprocess to support this.
This commit is contained in:
Kurt B. Kaiser 2003-01-31 05:06:43 +00:00
parent d17406830c
commit 8cd0def10d
2 changed files with 42 additions and 84 deletions

View file

@ -353,6 +353,7 @@ class ModifiedInterpreter(InteractiveInterpreter):
self.rpcclt.register("stdout", self.tkconsole.stdout) self.rpcclt.register("stdout", self.tkconsole.stdout)
self.rpcclt.register("stderr", self.tkconsole.stderr) self.rpcclt.register("stderr", self.tkconsole.stderr)
self.rpcclt.register("flist", self.tkconsole.flist) self.rpcclt.register("flist", self.tkconsole.flist)
self.rpcclt.register("linecache", linecache)
self.transfer_path() self.transfer_path()
self.poll_subprocess() self.poll_subprocess()
@ -404,23 +405,6 @@ class ModifiedInterpreter(InteractiveInterpreter):
if what is not None: if what is not None:
print >>console, `what` print >>console, `what`
elif how == "EXCEPTION": elif how == "EXCEPTION":
mod, name, args, tb = what
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)
val = etype()
val.args = args
except TypeError: # string exception!
etype = name
val = args
lines = traceback.format_exception_only(etype, val)
for line in lines[:-1]:
traceback._print(console, line, '')
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":
@ -430,36 +414,6 @@ class ModifiedInterpreter(InteractiveInterpreter):
# we received a response to the currently active seq number: # we received a response to the currently active seq number:
self.tkconsole.endexecuting() self.tkconsole.endexecuting()
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):
break # found an exclude, break for: and delete tb[0]
else:
break # no excludes, have left RPC code, break while:
del tb[0]
while tb:
for rpcfile in exclude:
if tb[-1][0].count(rpcfile):
break
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 == '?':
nm = "-toplevel-"
if not line and fn.startswith("<pyshell#"):
line = linecache.getline(fn, ln)
tb[i] = fn, ln, nm, line
def kill_subprocess(self): def kill_subprocess(self):
clt = self.rpcclt clt = self.rpcclt
self.rpcclt = None self.rpcclt = None

View file

@ -154,26 +154,49 @@ class SocketIO:
ret = remoteref(ret) ret = remoteref(ret)
return ("OK", ret) return ("OK", ret)
except: except:
##traceback.print_exc(file=sys.__stderr__) self.debug("localcall:EXCEPTION")
efile = sys.stderr
typ, val, tb = info = sys.exc_info() typ, val, tb = info = sys.exc_info()
sys.last_type, sys.last_value, sys.last_traceback = info sys.last_type, sys.last_value, sys.last_traceback = info
if isinstance(typ, type(Exception)): tbe = traceback.extract_tb(tb)
# Class exception print >>efile, 'Traceback (most recent call last):'
mod = typ.__module__ exclude = ("run.py", "rpc.py", "RemoteDebugger.py", "bdb.py")
name = typ.__name__ self.cleanup_traceback(tbe, exclude)
if issubclass(typ, Exception): traceback.print_list(tbe, file=efile)
args = val.args lines = traceback.format_exception_only(typ, val)
else: for line in lines:
args = (str(val),) print>>efile, line,
return ("EXCEPTION", None)
def cleanup_traceback(self, tb, exclude):
"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):
break # found an exclude, break for: and delete tb[0]
else: else:
# User string exception break # no excludes, have left RPC code, break while:
mod = None del tb[0]
name = typ while tb:
if val is None: val = '' for rpcfile in exclude:
args = str(val) if tb[-1][0].count(rpcfile):
tb = traceback.extract_tb(tb) break
self.debug("localcall:EXCEPTION: ", mod, name, args, tb) else:
return ("EXCEPTION", (mod, name, args, tb)) break
del tb[-1]
if len(tb) == 0:
# error was in RPC internals, don't prune!
tb[:] = orig_tb[:]
print>>sys.stderr, "** RPC Internal Error: ", tb
for i in range(len(tb)):
fn, ln, nm, line = tb[i]
if nm == '?':
nm = "-toplevel-"
if not line and fn.startswith("<pyshell#"):
line = self.remotecall('linecache', 'getline',
(fn, ln), {})
tb[i] = fn, ln, nm, line
def remotecall(self, oid, methodname, args, kwargs): def remotecall(self, oid, methodname, args, kwargs):
self.debug("calling asynccall via remotecall") self.debug("calling asynccall via remotecall")
@ -198,26 +221,7 @@ class SocketIO:
if how == "OK": if how == "OK":
return what return what
if how == "EXCEPTION": if how == "EXCEPTION":
self.debug("decoderesponse: EXCEPTION:", what) raise Exception, "RPC SocketIO.decoderesponse exception"
mod, name, args, tb = what
self.traceback = tb
if mod: # not string exception
try:
__import__(mod)
module = sys.modules[mod]
except ImportError:
pass
else:
try:
cls = getattr(module, name)
except AttributeError:
pass
else:
# instantiate a built-in exception object and raise it
raise getattr(__import__(mod), name)(*args)
name = mod + "." + name
# do the best we can:
raise name, args
if how == "ERROR": if how == "ERROR":
self.debug("decoderesponse: Internal ERROR:", what) self.debug("decoderesponse: Internal ERROR:", what)
raise RuntimeError, what raise RuntimeError, what