mirror of
https://github.com/python/cpython.git
synced 2025-08-31 22:18:28 +00:00
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:
parent
d17406830c
commit
8cd0def10d
2 changed files with 42 additions and 84 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue