mirror of
https://github.com/python/cpython.git
synced 2025-09-26 10:19:53 +00:00
GvR's rpc patch
This commit is contained in:
parent
38d53451b7
commit
5d2af63cc3
7 changed files with 1208 additions and 94 deletions
|
@ -1,5 +1,6 @@
|
||||||
import os
|
import os
|
||||||
import bdb
|
import bdb
|
||||||
|
import types
|
||||||
import traceback
|
import traceback
|
||||||
from Tkinter import *
|
from Tkinter import *
|
||||||
from WindowList import ListedToplevel
|
from WindowList import ListedToplevel
|
||||||
|
@ -7,20 +8,66 @@ from WindowList import ListedToplevel
|
||||||
import StackViewer
|
import StackViewer
|
||||||
|
|
||||||
|
|
||||||
class Debugger(bdb.Bdb):
|
class Idb(bdb.Bdb):
|
||||||
|
|
||||||
|
def __init__(self, gui):
|
||||||
|
self.gui = gui
|
||||||
|
bdb.Bdb.__init__(self)
|
||||||
|
|
||||||
|
def user_line(self, frame):
|
||||||
|
# get the currently executing function
|
||||||
|
co_filename = frame.f_code.co_filename
|
||||||
|
co_name = frame.f_code.co_name
|
||||||
|
try:
|
||||||
|
func = frame.f_locals[co_name]
|
||||||
|
if getattr(func, "DebuggerStepThrough", 0):
|
||||||
|
print "XXXX DEBUGGER STEPPING THROUGH"
|
||||||
|
self.set_step()
|
||||||
|
return
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if co_filename in ('rpc.py', '<string>'):
|
||||||
|
self.set_step()
|
||||||
|
return
|
||||||
|
if co_filename.endswith('threading.py'):
|
||||||
|
self.set_step()
|
||||||
|
return
|
||||||
|
message = self.__frame2message(frame)
|
||||||
|
self.gui.interaction(message, frame)
|
||||||
|
|
||||||
|
def user_exception(self, frame, info):
|
||||||
|
message = self.__frame2message(frame)
|
||||||
|
self.gui.interaction(message, frame, info)
|
||||||
|
|
||||||
|
def __frame2message(self, frame):
|
||||||
|
code = frame.f_code
|
||||||
|
filename = code.co_filename
|
||||||
|
lineno = frame.f_lineno
|
||||||
|
basename = os.path.basename(filename)
|
||||||
|
message = "%s:%s" % (basename, lineno)
|
||||||
|
if code.co_name != "?":
|
||||||
|
message = "%s: %s()" % (message, code.co_name)
|
||||||
|
return message
|
||||||
|
|
||||||
|
|
||||||
|
class Debugger:
|
||||||
|
|
||||||
interacting = 0
|
interacting = 0
|
||||||
|
|
||||||
vstack = vsource = vlocals = vglobals = None
|
vstack = vsource = vlocals = vglobals = None
|
||||||
|
|
||||||
def __init__(self, pyshell):
|
def __init__(self, pyshell, idb=None):
|
||||||
bdb.Bdb.__init__(self)
|
if idb is None:
|
||||||
|
idb = Idb(self)
|
||||||
self.pyshell = pyshell
|
self.pyshell = pyshell
|
||||||
|
self.idb = idb
|
||||||
self.make_gui()
|
self.make_gui()
|
||||||
|
|
||||||
def canonic(self, filename):
|
def run(self, *args):
|
||||||
# Canonicalize filename -- called by Bdb
|
try:
|
||||||
return os.path.normcase(os.path.abspath(filename))
|
self.interacting = 1
|
||||||
|
return self.idb.run(*args)
|
||||||
|
finally:
|
||||||
|
self.interacting = 0
|
||||||
|
|
||||||
def close(self, event=None):
|
def close(self, event=None):
|
||||||
if self.interacting:
|
if self.interacting:
|
||||||
|
@ -31,24 +78,6 @@ class Debugger(bdb.Bdb):
|
||||||
self.pyshell.close_debugger()
|
self.pyshell.close_debugger()
|
||||||
self.top.destroy()
|
self.top.destroy()
|
||||||
|
|
||||||
def run(self, *args):
|
|
||||||
try:
|
|
||||||
self.interacting = 1
|
|
||||||
return apply(bdb.Bdb.run, (self,) + args)
|
|
||||||
finally:
|
|
||||||
self.interacting = 0
|
|
||||||
|
|
||||||
def user_line(self, frame):
|
|
||||||
self.interaction(frame)
|
|
||||||
|
|
||||||
def user_return(self, frame, rv):
|
|
||||||
# XXX show rv?
|
|
||||||
##self.interaction(frame)
|
|
||||||
pass
|
|
||||||
|
|
||||||
def user_exception(self, frame, info):
|
|
||||||
self.interaction(frame, info)
|
|
||||||
|
|
||||||
def make_gui(self):
|
def make_gui(self):
|
||||||
pyshell = self.pyshell
|
pyshell = self.pyshell
|
||||||
self.flist = pyshell.flist
|
self.flist = pyshell.flist
|
||||||
|
@ -128,16 +157,8 @@ class Debugger(bdb.Bdb):
|
||||||
|
|
||||||
frame = None
|
frame = None
|
||||||
|
|
||||||
def interaction(self, frame, info=None):
|
def interaction(self, message, frame, info=None):
|
||||||
self.frame = frame
|
self.frame = frame
|
||||||
code = frame.f_code
|
|
||||||
file = code.co_filename
|
|
||||||
base = os.path.basename(file)
|
|
||||||
lineno = frame.f_lineno
|
|
||||||
#
|
|
||||||
message = "%s:%s" % (base, lineno)
|
|
||||||
if code.co_name != "?":
|
|
||||||
message = "%s: %s()" % (message, code.co_name)
|
|
||||||
self.status.configure(text=message)
|
self.status.configure(text=message)
|
||||||
#
|
#
|
||||||
if info:
|
if info:
|
||||||
|
@ -160,7 +181,7 @@ class Debugger(bdb.Bdb):
|
||||||
#
|
#
|
||||||
sv = self.stackviewer
|
sv = self.stackviewer
|
||||||
if sv:
|
if sv:
|
||||||
stack, i = self.get_stack(self.frame, tb)
|
stack, i = self.idb.get_stack(self.frame, tb)
|
||||||
sv.load_stack(stack, i)
|
sv.load_stack(stack, i)
|
||||||
#
|
#
|
||||||
self.show_variables(1)
|
self.show_variables(1)
|
||||||
|
@ -184,32 +205,34 @@ class Debugger(bdb.Bdb):
|
||||||
frame = self.frame
|
frame = self.frame
|
||||||
if not frame:
|
if not frame:
|
||||||
return
|
return
|
||||||
|
filename, lineno = self.__frame2fileline(frame)
|
||||||
|
if filename[:1] + filename[-1:] != "<>" and os.path.exists(filename):
|
||||||
|
self.flist.gotofileline(filename, lineno)
|
||||||
|
|
||||||
|
def __frame2fileline(self, frame):
|
||||||
code = frame.f_code
|
code = frame.f_code
|
||||||
file = code.co_filename
|
filename = code.co_filename
|
||||||
lineno = frame.f_lineno
|
lineno = frame.f_lineno
|
||||||
if file[:1] + file[-1:] != "<>" and os.path.exists(file):
|
return filename, lineno
|
||||||
edit = self.flist.open(file)
|
|
||||||
if edit:
|
|
||||||
edit.gotoline(lineno)
|
|
||||||
|
|
||||||
def cont(self):
|
def cont(self):
|
||||||
self.set_continue()
|
self.idb.set_continue()
|
||||||
self.root.quit()
|
self.root.quit()
|
||||||
|
|
||||||
def step(self):
|
def step(self):
|
||||||
self.set_step()
|
self.idb.set_step()
|
||||||
self.root.quit()
|
self.root.quit()
|
||||||
|
|
||||||
def next(self):
|
def next(self):
|
||||||
self.set_next(self.frame)
|
self.idb.set_next(self.frame)
|
||||||
self.root.quit()
|
self.root.quit()
|
||||||
|
|
||||||
def ret(self):
|
def ret(self):
|
||||||
self.set_return(self.frame)
|
self.idb.set_return(self.frame)
|
||||||
self.root.quit()
|
self.root.quit()
|
||||||
|
|
||||||
def quit(self):
|
def quit(self):
|
||||||
self.set_quit()
|
self.idb.set_quit()
|
||||||
self.root.quit()
|
self.root.quit()
|
||||||
|
|
||||||
stackviewer = None
|
stackviewer = None
|
||||||
|
@ -219,7 +242,7 @@ class Debugger(bdb.Bdb):
|
||||||
self.stackviewer = sv = StackViewer.StackViewer(
|
self.stackviewer = sv = StackViewer.StackViewer(
|
||||||
self.fstack, self.flist, self)
|
self.fstack, self.flist, self)
|
||||||
if self.frame:
|
if self.frame:
|
||||||
stack, i = self.get_stack(self.frame, None)
|
stack, i = self.idb.get_stack(self.frame, None)
|
||||||
sv.load_stack(stack, i)
|
sv.load_stack(stack, i)
|
||||||
else:
|
else:
|
||||||
sv = self.stackviewer
|
sv = self.stackviewer
|
||||||
|
@ -233,6 +256,7 @@ class Debugger(bdb.Bdb):
|
||||||
self.sync_source_line()
|
self.sync_source_line()
|
||||||
|
|
||||||
def show_frame(self, (frame, lineno)):
|
def show_frame(self, (frame, lineno)):
|
||||||
|
# Called from OldStackViewer
|
||||||
self.frame = frame
|
self.frame = frame
|
||||||
self.show_variables()
|
self.show_variables()
|
||||||
|
|
||||||
|
@ -295,15 +319,15 @@ class Debugger(bdb.Bdb):
|
||||||
text.tag_add("BREAK", "insert linestart", "insert lineend +1char")
|
text.tag_add("BREAK", "insert linestart", "insert lineend +1char")
|
||||||
|
|
||||||
# A literal copy of Bdb.set_break() without the print statement at the end
|
# A literal copy of Bdb.set_break() without the print statement at the end
|
||||||
def set_break(self, filename, lineno, temporary=0, cond = None):
|
#def set_break(self, filename, lineno, temporary=0, cond = None):
|
||||||
import linecache # Import as late as possible
|
# import linecache # Import as late as possible
|
||||||
filename = self.canonic(filename)
|
# filename = self.canonic(filename)
|
||||||
line = linecache.getline(filename, lineno)
|
# line = linecache.getline(filename, lineno)
|
||||||
if not line:
|
# if not line:
|
||||||
return 'That line does not exist!'
|
# return 'That line does not exist!'
|
||||||
if not self.breaks.has_key(filename):
|
# if not self.breaks.has_key(filename):
|
||||||
self.breaks[filename] = []
|
# self.breaks[filename] = []
|
||||||
list = self.breaks[filename]
|
# list = self.breaks[filename]
|
||||||
if not lineno in list:
|
# if not lineno in list:
|
||||||
list.append(lineno)
|
# list.append(lineno)
|
||||||
bp = bdb.Breakpoint(filename, lineno, temporary, cond)
|
# bp = bdb.Breakpoint(filename, lineno, temporary, cond)
|
||||||
|
|
|
@ -29,7 +29,10 @@ import string
|
||||||
import getopt
|
import getopt
|
||||||
import re
|
import re
|
||||||
import protocol
|
import protocol
|
||||||
|
import socket
|
||||||
|
import time
|
||||||
import warnings
|
import warnings
|
||||||
|
import traceback
|
||||||
|
|
||||||
import linecache
|
import linecache
|
||||||
from code import InteractiveInterpreter
|
from code import InteractiveInterpreter
|
||||||
|
@ -45,6 +48,21 @@ from OutputWindow import OutputWindow, OnDemandOutputWindow
|
||||||
from configHandler import idleConf
|
from configHandler import idleConf
|
||||||
import idlever
|
import idlever
|
||||||
|
|
||||||
|
import rpc
|
||||||
|
|
||||||
|
use_subprocess = 0 # Set to 1 to spawn subprocess for command execution
|
||||||
|
|
||||||
|
# Change warnings module to write to sys.__stderr__
|
||||||
|
try:
|
||||||
|
import warnings
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
def idle_showwarning(message, category, filename, lineno):
|
||||||
|
file = sys.__stderr__
|
||||||
|
file.write(warnings.formatwarning(message, category, filename, lineno))
|
||||||
|
warnings.showwarning = idle_showwarning
|
||||||
|
|
||||||
# We need to patch linecache.checkcache, because we don't want it
|
# We need to patch linecache.checkcache, because we don't want it
|
||||||
# to throw away our <pyshell#...> entries.
|
# to throw away our <pyshell#...> entries.
|
||||||
# Rather than repeating its code here, we save those entries,
|
# Rather than repeating its code here, we save those entries,
|
||||||
|
@ -186,6 +204,99 @@ class ModifiedInterpreter(InteractiveInterpreter):
|
||||||
InteractiveInterpreter.__init__(self, locals=locals)
|
InteractiveInterpreter.__init__(self, locals=locals)
|
||||||
self.save_warnings_filters = None
|
self.save_warnings_filters = None
|
||||||
|
|
||||||
|
global flist
|
||||||
|
self.output = OnDemandOutputWindow(flist)
|
||||||
|
|
||||||
|
rpcclt = None
|
||||||
|
rpcpid = None
|
||||||
|
|
||||||
|
def spawn_subprocess(self):
|
||||||
|
port = 8833
|
||||||
|
addr = ("localhost", port)
|
||||||
|
w = ['-W' + s for s in sys.warnoptions]
|
||||||
|
args = [sys.executable] + w + ["-c", "__import__('run').main()",
|
||||||
|
str(port)]
|
||||||
|
self.rpcpid = os.spawnv(os.P_NOWAIT, args[0], args)
|
||||||
|
for i in range(5):
|
||||||
|
time.sleep(i)
|
||||||
|
try:
|
||||||
|
self.rpcclt = rpc.RPCClient(addr)
|
||||||
|
break
|
||||||
|
except socket.error, err:
|
||||||
|
if i > 3:
|
||||||
|
print >>sys.__stderr__, "Socket error:", err, "; retry..."
|
||||||
|
else:
|
||||||
|
# XXX Make this a dialog?
|
||||||
|
print >>sys.__stderr__, "Can't spawn subprocess!"
|
||||||
|
return
|
||||||
|
self.output.stdout=PseudoFile(self.output, "stdout")
|
||||||
|
self.output.stderr=PseudoFile(self.output, "stderr")
|
||||||
|
self.rpcclt.register("stdin", self.output)
|
||||||
|
self.rpcclt.register("stdout", self.output.stdout)
|
||||||
|
self.rpcclt.register("stderr", self.output.stderr)
|
||||||
|
self.rpcclt.register("flist", self.tkconsole.flist)
|
||||||
|
self.poll_subprocess()
|
||||||
|
|
||||||
|
active_seq = None
|
||||||
|
|
||||||
|
def poll_subprocess(self):
|
||||||
|
clt = self.rpcclt
|
||||||
|
if clt is None:
|
||||||
|
return
|
||||||
|
response = clt.pollresponse(self.active_seq)
|
||||||
|
self.tkconsole.text.after(50, self.poll_subprocess)
|
||||||
|
if response:
|
||||||
|
self.tkconsole.resetoutput()
|
||||||
|
self.active_seq = None
|
||||||
|
how, what = response
|
||||||
|
file = self.tkconsole.console
|
||||||
|
if how == "OK":
|
||||||
|
if what is not None:
|
||||||
|
print >>file, `what`
|
||||||
|
elif how == "EXCEPTION":
|
||||||
|
mod, name, args, tb = what
|
||||||
|
print >>file, 'Traceback (most recent call last):'
|
||||||
|
while tb and tb[0][0] in ("run.py", "rpc.py"):
|
||||||
|
del tb[0]
|
||||||
|
while tb and tb[-1][0] in ("run.py", "rpc.py"):
|
||||||
|
del tb[-1]
|
||||||
|
for i in range(len(tb)):
|
||||||
|
fn, ln, nm, line = tb[i]
|
||||||
|
if not line and fn.startswith("<pyshell#"):
|
||||||
|
line = linecache.getline(fn, ln)
|
||||||
|
tb[i] = fn, ln, nm, line
|
||||||
|
traceback.print_list(tb, file=file)
|
||||||
|
if mod and mod != "exceptions":
|
||||||
|
name = mod + "." + name
|
||||||
|
print >>file, name + ":", " ".join(map(str, args))
|
||||||
|
if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
|
||||||
|
self.remote_stack_viewer()
|
||||||
|
elif how == "ERROR":
|
||||||
|
print >>sys.__stderr__, "Oops:", how, what
|
||||||
|
print >>file, "Oops:", how, what
|
||||||
|
self.tkconsole.endexecuting()
|
||||||
|
|
||||||
|
def kill_subprocess(self):
|
||||||
|
clt = self.rpcclt
|
||||||
|
self.rpcclt = None
|
||||||
|
if clt is not None:
|
||||||
|
clt.close()
|
||||||
|
|
||||||
|
def remote_stack_viewer(self):
|
||||||
|
import RemoteObjectBrowser
|
||||||
|
oid = self.rpcclt.remotecall("exec", "stackviewer", ("flist",), {})
|
||||||
|
if oid is None:
|
||||||
|
self.tkconsole.root.bell()
|
||||||
|
return
|
||||||
|
item = RemoteObjectBrowser.StubObjectTreeItem(self.rpcclt, oid)
|
||||||
|
from TreeWidget import ScrolledCanvas, TreeNode
|
||||||
|
top = Toplevel(self.tkconsole.root)
|
||||||
|
sc = ScrolledCanvas(top, bg="white", highlightthickness=0)
|
||||||
|
sc.frame.pack(expand=1, fill="both")
|
||||||
|
node = TreeNode(sc.canvas, None, item)
|
||||||
|
node.expand()
|
||||||
|
# XXX Should GC the remote tree when closing the window
|
||||||
|
|
||||||
gid = 0
|
gid = 0
|
||||||
|
|
||||||
def execsource(self, source):
|
def execsource(self, source):
|
||||||
|
@ -264,10 +375,11 @@ class ModifiedInterpreter(InteractiveInterpreter):
|
||||||
|
|
||||||
def showtraceback(self):
|
def showtraceback(self):
|
||||||
# Extend base class method to reset output properly
|
# Extend base class method to reset output properly
|
||||||
text = self.tkconsole.text
|
|
||||||
self.tkconsole.resetoutput()
|
self.tkconsole.resetoutput()
|
||||||
self.checklinecache()
|
self.checklinecache()
|
||||||
InteractiveInterpreter.showtraceback(self)
|
InteractiveInterpreter.showtraceback(self)
|
||||||
|
if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
|
||||||
|
self.tkconsole.open_stack_viewer()
|
||||||
|
|
||||||
def checklinecache(self):
|
def checklinecache(self):
|
||||||
c = linecache.cache
|
c = linecache.cache
|
||||||
|
@ -283,12 +395,43 @@ class ModifiedInterpreter(InteractiveInterpreter):
|
||||||
def getdebugger(self):
|
def getdebugger(self):
|
||||||
return self.debugger
|
return self.debugger
|
||||||
|
|
||||||
|
def runcommand(self, code):
|
||||||
|
# This runs the code without invoking the debugger.
|
||||||
|
# The code better not raise an exception!
|
||||||
|
if self.tkconsole.executing:
|
||||||
|
tkMessageBox.showerror(
|
||||||
|
"Already executing",
|
||||||
|
"The Python Shell window is already executing a command; "
|
||||||
|
"please wait until it is finished.",
|
||||||
|
master=self.tkconsole.text)
|
||||||
|
return 0
|
||||||
|
if self.rpcclt:
|
||||||
|
self.rpcclt.remotecall("exec", "runcode", (code,), {})
|
||||||
|
else:
|
||||||
|
exec code in self.locals
|
||||||
|
return 1
|
||||||
|
|
||||||
def runcode(self, code):
|
def runcode(self, code):
|
||||||
# Override base class method
|
# Override base class method
|
||||||
|
if self.tkconsole.executing:
|
||||||
|
tkMessageBox.showerror(
|
||||||
|
"Already executing",
|
||||||
|
"The Python Shell window is already executing a command; "
|
||||||
|
"please wait until it is finished.",
|
||||||
|
master=self.tkconsole.text)
|
||||||
|
return
|
||||||
|
|
||||||
|
self.checklinecache()
|
||||||
if self.save_warnings_filters is not None:
|
if self.save_warnings_filters is not None:
|
||||||
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.active_seq = self.rpcclt.asynccall("exec", "runcode",
|
||||||
|
(code,), {})
|
||||||
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.tkconsole.beginexecuting()
|
self.tkconsole.beginexecuting()
|
||||||
try:
|
try:
|
||||||
|
@ -305,12 +448,8 @@ class ModifiedInterpreter(InteractiveInterpreter):
|
||||||
raise
|
raise
|
||||||
else:
|
else:
|
||||||
self.showtraceback()
|
self.showtraceback()
|
||||||
if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
|
|
||||||
self.tkconsole.open_stack_viewer()
|
|
||||||
except:
|
except:
|
||||||
self.showtraceback()
|
self.showtraceback()
|
||||||
if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
|
|
||||||
self.tkconsole.open_stack_viewer()
|
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
self.tkconsole.endexecuting()
|
self.tkconsole.endexecuting()
|
||||||
|
@ -319,7 +458,6 @@ class ModifiedInterpreter(InteractiveInterpreter):
|
||||||
# Override base class write
|
# Override base class write
|
||||||
self.tkconsole.console.write(s)
|
self.tkconsole.console.write(s)
|
||||||
|
|
||||||
|
|
||||||
class PyShell(OutputWindow):
|
class PyShell(OutputWindow):
|
||||||
|
|
||||||
shell_title = "Python Shell"
|
shell_title = "Python Shell"
|
||||||
|
@ -366,13 +504,19 @@ class PyShell(OutputWindow):
|
||||||
self.save_stdout = sys.stdout
|
self.save_stdout = sys.stdout
|
||||||
self.save_stderr = sys.stderr
|
self.save_stderr = sys.stderr
|
||||||
self.save_stdin = sys.stdin
|
self.save_stdin = sys.stdin
|
||||||
sys.stdout = PseudoFile(self, "stdout")
|
self.stdout = PseudoFile(self, "stdout")
|
||||||
sys.stderr = PseudoFile(self, "stderr")
|
self.stderr = PseudoFile(self, "stderr")
|
||||||
sys.stdin = self
|
|
||||||
self.console = PseudoFile(self, "console")
|
self.console = PseudoFile(self, "console")
|
||||||
|
if not use_subprocess:
|
||||||
|
sys.stdout = self.stdout
|
||||||
|
sys.stderr = self.stderr
|
||||||
|
sys.stdin = self
|
||||||
|
|
||||||
self.history = self.History(self.text)
|
self.history = self.History(self.text)
|
||||||
|
|
||||||
|
if use_subprocess:
|
||||||
|
self.interp.spawn_subprocess()
|
||||||
|
|
||||||
reading = 0
|
reading = 0
|
||||||
executing = 0
|
executing = 0
|
||||||
canceled = 0
|
canceled = 0
|
||||||
|
@ -411,12 +555,22 @@ class PyShell(OutputWindow):
|
||||||
self.set_debugger_indicator()
|
self.set_debugger_indicator()
|
||||||
|
|
||||||
def open_debugger(self):
|
def open_debugger(self):
|
||||||
|
if self.interp.rpcclt:
|
||||||
|
return self.open_remote_debugger()
|
||||||
import Debugger
|
import Debugger
|
||||||
self.interp.setdebugger(Debugger.Debugger(self))
|
self.interp.setdebugger(Debugger.Debugger(self))
|
||||||
sys.ps1 = "[DEBUG ON]\n>>> "
|
sys.ps1 = "[DEBUG ON]\n>>> "
|
||||||
self.showprompt()
|
self.showprompt()
|
||||||
self.set_debugger_indicator()
|
self.set_debugger_indicator()
|
||||||
|
|
||||||
|
def open_remote_debugger(self):
|
||||||
|
import RemoteDebugger
|
||||||
|
gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt, self)
|
||||||
|
self.interp.setdebugger(gui)
|
||||||
|
sys.ps1 = "[DEBUG ON]\n>>> "
|
||||||
|
self.showprompt()
|
||||||
|
self.set_debugger_indicator()
|
||||||
|
|
||||||
def beginexecuting(self):
|
def beginexecuting(self):
|
||||||
# Helper for ModifiedInterpreter
|
# Helper for ModifiedInterpreter
|
||||||
self.resetoutput()
|
self.resetoutput()
|
||||||
|
@ -430,6 +584,7 @@ class PyShell(OutputWindow):
|
||||||
##self._cancel_check = None
|
##self._cancel_check = None
|
||||||
self.executing = 0
|
self.executing = 0
|
||||||
self.canceled = 0
|
self.canceled = 0
|
||||||
|
self.showprompt()
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
# Extend base class method
|
# Extend base class method
|
||||||
|
@ -449,6 +604,7 @@ class PyShell(OutputWindow):
|
||||||
|
|
||||||
def _close(self):
|
def _close(self):
|
||||||
self.close_debugger()
|
self.close_debugger()
|
||||||
|
self.interp.kill_subprocess()
|
||||||
# Restore std streams
|
# Restore std streams
|
||||||
sys.stdout = self.save_stdout
|
sys.stdout = self.save_stdout
|
||||||
sys.stderr = self.save_stderr
|
sys.stderr = self.save_stderr
|
||||||
|
@ -520,9 +676,18 @@ class PyShell(OutputWindow):
|
||||||
self.showprompt()
|
self.showprompt()
|
||||||
return "break"
|
return "break"
|
||||||
self.endoffile = 0
|
self.endoffile = 0
|
||||||
self.canceled = 1
|
|
||||||
if self.reading:
|
if self.reading:
|
||||||
|
self.canceled = 1
|
||||||
self.top.quit()
|
self.top.quit()
|
||||||
|
elif (self.executing and self.interp.rpcclt and
|
||||||
|
self.interp.rpcpid and hasattr(os, "kill")):
|
||||||
|
try:
|
||||||
|
from signal import SIGINT
|
||||||
|
except ImportError:
|
||||||
|
SIGINT = 2
|
||||||
|
os.kill(self.interp.rpcpid, SIGINT)
|
||||||
|
else:
|
||||||
|
self.canceled = 1
|
||||||
return "break"
|
return "break"
|
||||||
|
|
||||||
def eof_callback(self, event):
|
def eof_callback(self, event):
|
||||||
|
@ -532,11 +697,6 @@ class PyShell(OutputWindow):
|
||||||
self.text.compare("insert", "==", "end-1c")):
|
self.text.compare("insert", "==", "end-1c")):
|
||||||
return # Let the default binding (delete next char) take over
|
return # Let the default binding (delete next char) take over
|
||||||
if not self.executing:
|
if not self.executing:
|
||||||
## if not tkMessageBox.askokcancel(
|
|
||||||
## "Exit?",
|
|
||||||
## "Are you sure you want to exit?",
|
|
||||||
## default="ok", master=self.text):
|
|
||||||
## return "break"
|
|
||||||
self.resetoutput()
|
self.resetoutput()
|
||||||
self.close()
|
self.close()
|
||||||
else:
|
else:
|
||||||
|
@ -656,6 +816,8 @@ class PyShell(OutputWindow):
|
||||||
return self._cancel_check
|
return self._cancel_check
|
||||||
|
|
||||||
def open_stack_viewer(self, event=None):
|
def open_stack_viewer(self, event=None):
|
||||||
|
if self.interp.rpcclt:
|
||||||
|
return self.interp.remote_stack_viewer()
|
||||||
try:
|
try:
|
||||||
sys.last_traceback
|
sys.last_traceback
|
||||||
except:
|
except:
|
||||||
|
@ -675,6 +837,7 @@ class PyShell(OutputWindow):
|
||||||
s = ""
|
s = ""
|
||||||
self.console.write(s)
|
self.console.write(s)
|
||||||
self.text.mark_set("insert", "end-1c")
|
self.text.mark_set("insert", "end-1c")
|
||||||
|
self.set_line_and_column()
|
||||||
|
|
||||||
def resetoutput(self):
|
def resetoutput(self):
|
||||||
source = self.text.get("iomark", "end-1c")
|
source = self.text.get("iomark", "end-1c")
|
||||||
|
@ -683,6 +846,7 @@ class PyShell(OutputWindow):
|
||||||
if self.text.get("end-2c") != "\n":
|
if self.text.get("end-2c") != "\n":
|
||||||
self.text.insert("end-1c", "\n")
|
self.text.insert("end-1c", "\n")
|
||||||
self.text.mark_set("iomark", "end-1c")
|
self.text.mark_set("iomark", "end-1c")
|
||||||
|
self.set_line_and_column()
|
||||||
sys.stdout.softspace = 0
|
sys.stdout.softspace = 0
|
||||||
|
|
||||||
def write(self, s, tags=()):
|
def write(self, s, tags=()):
|
||||||
|
@ -698,6 +862,7 @@ class PseudoFile:
|
||||||
def __init__(self, shell, tags):
|
def __init__(self, shell, tags):
|
||||||
self.shell = shell
|
self.shell = shell
|
||||||
self.tags = tags
|
self.tags = tags
|
||||||
|
self.softspace = 0
|
||||||
|
|
||||||
def write(self, s):
|
def write(self, s):
|
||||||
self.shell.write(s, self.tags)
|
self.shell.write(s, self.tags)
|
||||||
|
@ -718,9 +883,10 @@ idle file(s) (without options) edit the file(s)
|
||||||
|
|
||||||
-c cmd run the command in a shell
|
-c cmd run the command in a shell
|
||||||
-d enable the debugger
|
-d enable the debugger
|
||||||
|
-e edit mode; arguments are files to be edited
|
||||||
-i open an interactive shell
|
-i open an interactive shell
|
||||||
-i file(s) open a shell and also an editor window for each file
|
-i file(s) open a shell and also an editor window for each file
|
||||||
-r script run a file as a script in a shell
|
-r script use experimental remote (subprocess) execution feature
|
||||||
-s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
|
-s run $IDLESTARTUP or $PYTHONSTARTUP before anything else
|
||||||
-t title set title of shell window
|
-t title set title of shell window
|
||||||
|
|
||||||
|
@ -822,9 +988,10 @@ be a security risk on a single-user machine.
|
||||||
interactive = 0
|
interactive = 0
|
||||||
script = None
|
script = None
|
||||||
startup = 0
|
startup = 0
|
||||||
|
global use_subprocess
|
||||||
|
|
||||||
try:
|
try:
|
||||||
opts, args = getopt.getopt(argv, "c:dir:st:")
|
opts, args = getopt.getopt(sys.argv[1:], "c:deir:st:")
|
||||||
except getopt.error, msg:
|
except getopt.error, msg:
|
||||||
sys.stderr.write("Error: %s\n" % str(msg))
|
sys.stderr.write("Error: %s\n" % str(msg))
|
||||||
sys.stderr.write(usage_msg)
|
sys.stderr.write(usage_msg)
|
||||||
|
@ -836,10 +1003,14 @@ be a security risk on a single-user machine.
|
||||||
cmd = a
|
cmd = a
|
||||||
if o == '-d':
|
if o == '-d':
|
||||||
debug = 1
|
debug = 1
|
||||||
|
if o == '-e':
|
||||||
|
edit = 1
|
||||||
if o == '-i':
|
if o == '-i':
|
||||||
interactive = 1
|
interactive = 1
|
||||||
if o == '-r':
|
if o == '-r':
|
||||||
|
edit = 1
|
||||||
script = a
|
script = a
|
||||||
|
use_subprocess = 1
|
||||||
if o == '-s':
|
if o == '-s':
|
||||||
startup = 1
|
startup = 1
|
||||||
if o == '-t':
|
if o == '-t':
|
||||||
|
|
287
Lib/idlelib/RemoteDebugger.py
Normal file
287
Lib/idlelib/RemoteDebugger.py
Normal file
|
@ -0,0 +1,287 @@
|
||||||
|
"""Support for remote Python debugging.
|
||||||
|
|
||||||
|
Some ASCII art to describe the structure:
|
||||||
|
|
||||||
|
IN PYTHON SUBPROCESS # IN IDLE PROCESS
|
||||||
|
#
|
||||||
|
# oid='gui_adapter'
|
||||||
|
+----------+ # +------------+ +-----+
|
||||||
|
| GUIProxy |--remote#call-->| GUIAdapter |--calls-->| GUI |
|
||||||
|
+-----+--calls-->+----------+ # +------------+ +-----+
|
||||||
|
| Idb | # /
|
||||||
|
+-----+<-calls--+------------+ # +----------+<--calls-/
|
||||||
|
| IdbAdapter |<--remote#call--| IdbProxy |
|
||||||
|
+------------+ # +----------+
|
||||||
|
oid='idb_adapter' #
|
||||||
|
|
||||||
|
The purpose of the Proxy and Adapter classes is to translate certain
|
||||||
|
arguments and return values that cannot be transported through the RPC
|
||||||
|
barrier, in particular frame and traceback objects.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import rpc
|
||||||
|
import Debugger
|
||||||
|
|
||||||
|
# In the PYTHON subprocess
|
||||||
|
|
||||||
|
frametable = {}
|
||||||
|
dicttable = {}
|
||||||
|
codetable = {}
|
||||||
|
|
||||||
|
def wrap_frame(frame):
|
||||||
|
fid = id(frame)
|
||||||
|
frametable[fid] = frame
|
||||||
|
return fid
|
||||||
|
|
||||||
|
def wrap_info(info):
|
||||||
|
if info is None:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return None # XXX for now
|
||||||
|
|
||||||
|
class GUIProxy:
|
||||||
|
|
||||||
|
def __init__(self, conn, oid):
|
||||||
|
self.conn = conn
|
||||||
|
self.oid = oid
|
||||||
|
|
||||||
|
def interaction(self, message, frame, info=None):
|
||||||
|
self.conn.remotecall(self.oid, "interaction",
|
||||||
|
(message, wrap_frame(frame), wrap_info(info)),
|
||||||
|
{})
|
||||||
|
|
||||||
|
class IdbAdapter:
|
||||||
|
|
||||||
|
def __init__(self, idb):
|
||||||
|
self.idb = idb
|
||||||
|
|
||||||
|
def set_step(self):
|
||||||
|
self.idb.set_step()
|
||||||
|
|
||||||
|
def set_quit(self):
|
||||||
|
self.idb.set_quit()
|
||||||
|
|
||||||
|
def set_continue(self):
|
||||||
|
self.idb.set_continue()
|
||||||
|
|
||||||
|
def set_next(self, fid):
|
||||||
|
frame = frametable[fid]
|
||||||
|
self.idb.set_next(frame)
|
||||||
|
|
||||||
|
def set_return(self, fid):
|
||||||
|
frame = frametable[fid]
|
||||||
|
self.idb.set_return(frame)
|
||||||
|
|
||||||
|
def get_stack(self, fid, tbid):
|
||||||
|
##print >>sys.__stderr__, "get_stack(%s, %s)" % (`fid`, `tbid`)
|
||||||
|
frame = frametable[fid]
|
||||||
|
tb = None # XXX for now
|
||||||
|
stack, i = self.idb.get_stack(frame, tb)
|
||||||
|
##print >>sys.__stderr__, "get_stack() ->", stack
|
||||||
|
stack = [(wrap_frame(frame), k) for frame, k in stack]
|
||||||
|
##print >>sys.__stderr__, "get_stack() ->", stack
|
||||||
|
return stack, i
|
||||||
|
|
||||||
|
def run(self, cmd):
|
||||||
|
import __main__
|
||||||
|
self.idb.run(cmd, __main__.__dict__)
|
||||||
|
|
||||||
|
def frame_attr(self, fid, name):
|
||||||
|
frame = frametable[fid]
|
||||||
|
return getattr(frame, name)
|
||||||
|
|
||||||
|
def frame_globals(self, fid):
|
||||||
|
frame = frametable[fid]
|
||||||
|
dict = frame.f_globals
|
||||||
|
did = id(dict)
|
||||||
|
dicttable[did] = dict
|
||||||
|
return did
|
||||||
|
|
||||||
|
def frame_locals(self, fid):
|
||||||
|
frame = frametable[fid]
|
||||||
|
dict = frame.f_locals
|
||||||
|
did = id(dict)
|
||||||
|
dicttable[did] = dict
|
||||||
|
return did
|
||||||
|
|
||||||
|
def frame_code(self, fid):
|
||||||
|
frame = frametable[fid]
|
||||||
|
code = frame.f_code
|
||||||
|
cid = id(code)
|
||||||
|
codetable[cid] = code
|
||||||
|
return cid
|
||||||
|
|
||||||
|
def code_name(self, cid):
|
||||||
|
code = codetable[cid]
|
||||||
|
return code.co_name
|
||||||
|
|
||||||
|
def code_filename(self, cid):
|
||||||
|
code = codetable[cid]
|
||||||
|
return code.co_filename
|
||||||
|
|
||||||
|
def dict_keys(self, did):
|
||||||
|
dict = dicttable[did]
|
||||||
|
return dict.keys()
|
||||||
|
|
||||||
|
def dict_item(self, did, key):
|
||||||
|
dict = dicttable[did]
|
||||||
|
value = dict[key]
|
||||||
|
try:
|
||||||
|
# Test for picklability
|
||||||
|
import cPickle
|
||||||
|
cPickle.dumps(value)
|
||||||
|
except:
|
||||||
|
value = None
|
||||||
|
return value
|
||||||
|
|
||||||
|
def start_debugger(conn, gui_oid):
|
||||||
|
#
|
||||||
|
# launched in the python subprocess
|
||||||
|
#
|
||||||
|
gui = GUIProxy(conn, gui_oid)
|
||||||
|
idb = Debugger.Idb(gui)
|
||||||
|
ada = IdbAdapter(idb)
|
||||||
|
ada_oid = "idb_adapter"
|
||||||
|
conn.register(ada_oid, ada)
|
||||||
|
return ada_oid
|
||||||
|
|
||||||
|
# In the IDLE process
|
||||||
|
|
||||||
|
class FrameProxy:
|
||||||
|
|
||||||
|
def __init__(self, conn, fid):
|
||||||
|
self._conn = conn
|
||||||
|
self._fid = fid
|
||||||
|
self._oid = "idb_adapter"
|
||||||
|
self._dictcache = {}
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
if name[:1] == "_":
|
||||||
|
raise AttributeError, name
|
||||||
|
if name == "f_code":
|
||||||
|
return self._get_f_code()
|
||||||
|
if name == "f_globals":
|
||||||
|
return self._get_f_globals()
|
||||||
|
if name == "f_locals":
|
||||||
|
return self._get_f_locals()
|
||||||
|
return self._conn.remotecall(self._oid, "frame_attr",
|
||||||
|
(self._fid, name), {})
|
||||||
|
|
||||||
|
def _get_f_code(self):
|
||||||
|
cid = self._conn.remotecall(self._oid, "frame_code", (self._fid,), {})
|
||||||
|
return CodeProxy(self._conn, self._oid, cid)
|
||||||
|
|
||||||
|
def _get_f_globals(self):
|
||||||
|
did = self._conn.remotecall(self._oid, "frame_globals",
|
||||||
|
(self._fid,), {})
|
||||||
|
return self._get_dict_proxy(did)
|
||||||
|
|
||||||
|
def _get_f_locals(self):
|
||||||
|
did = self._conn.remotecall(self._oid, "frame_locals",
|
||||||
|
(self._fid,), {})
|
||||||
|
return self._get_dict_proxy(did)
|
||||||
|
|
||||||
|
def _get_dict_proxy(self, did):
|
||||||
|
if self._dictcache.has_key(did):
|
||||||
|
return self._dictcache[did]
|
||||||
|
dp = DictProxy(self._conn, self._oid, did)
|
||||||
|
self._dictcache[did] = dp
|
||||||
|
return dp
|
||||||
|
|
||||||
|
class CodeProxy:
|
||||||
|
|
||||||
|
def __init__(self, conn, oid, cid):
|
||||||
|
self._conn = conn
|
||||||
|
self._oid = oid
|
||||||
|
self._cid = cid
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
if name == "co_name":
|
||||||
|
return self._conn.remotecall(self._oid, "code_name",
|
||||||
|
(self._cid,), {})
|
||||||
|
if name == "co_filename":
|
||||||
|
return self._conn.remotecall(self._oid, "code_filename",
|
||||||
|
(self._cid,), {})
|
||||||
|
|
||||||
|
class DictProxy:
|
||||||
|
|
||||||
|
def __init__(self, conn, oid, did):
|
||||||
|
self._conn = conn
|
||||||
|
self._oid = oid
|
||||||
|
self._did = did
|
||||||
|
|
||||||
|
def keys(self):
|
||||||
|
return self._conn.remotecall(self._oid, "dict_keys", (self._did,), {})
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
return self._conn.remotecall(self._oid, "dict_item",
|
||||||
|
(self._did, key), {})
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
##print >>sys.__stderr__, "failed DictProxy.__getattr__:", name
|
||||||
|
raise AttributeError, name
|
||||||
|
|
||||||
|
class GUIAdaper:
|
||||||
|
|
||||||
|
def __init__(self, conn, gui):
|
||||||
|
self.conn = conn
|
||||||
|
self.gui = gui
|
||||||
|
|
||||||
|
def interaction(self, message, fid, iid):
|
||||||
|
print "interaction(%s, %s, %s)" % (`message`, `fid`, `iid`)
|
||||||
|
frame = FrameProxy(self.conn, fid)
|
||||||
|
info = None # XXX for now
|
||||||
|
self.gui.interaction(message, frame, info)
|
||||||
|
|
||||||
|
class IdbProxy:
|
||||||
|
|
||||||
|
def __init__(self, conn, oid):
|
||||||
|
self.oid = oid
|
||||||
|
self.conn = conn
|
||||||
|
|
||||||
|
def call(self, methodname, *args, **kwargs):
|
||||||
|
##print "call %s %s %s" % (methodname, args, kwargs)
|
||||||
|
value = self.conn.remotecall(self.oid, methodname, args, kwargs)
|
||||||
|
##print "return %s" % `value`
|
||||||
|
return value
|
||||||
|
|
||||||
|
def run(self, cmd, locals):
|
||||||
|
# Ignores locals on purpose!
|
||||||
|
self.call("run", cmd)
|
||||||
|
|
||||||
|
def get_stack(self, frame, tb):
|
||||||
|
stack, i = self.call("get_stack", frame._fid, None)
|
||||||
|
stack = [(FrameProxy(self.conn, fid), k) for fid, k in stack]
|
||||||
|
return stack, i
|
||||||
|
|
||||||
|
def set_continue(self):
|
||||||
|
self.call("set_continue")
|
||||||
|
|
||||||
|
def set_step(self):
|
||||||
|
self.call("set_step")
|
||||||
|
|
||||||
|
def set_next(self, frame):
|
||||||
|
self.call("set_next", frame._fid)
|
||||||
|
|
||||||
|
def set_return(self, frame):
|
||||||
|
self.call("set_return", frame._fid)
|
||||||
|
|
||||||
|
def set_quit(self):
|
||||||
|
self.call("set_quit")
|
||||||
|
|
||||||
|
def start_remote_debugger(conn, pyshell):
|
||||||
|
#
|
||||||
|
# instruct the (remote) subprocess to create
|
||||||
|
# a debugger instance, and lets it know that
|
||||||
|
# the local GUIAdapter called "gui_adapter"
|
||||||
|
# is waiting notification of debugging events
|
||||||
|
#
|
||||||
|
ada_oid = "gui_adapter"
|
||||||
|
idb_oid = conn.remotecall("exec", "start_debugger", (ada_oid,), {})
|
||||||
|
idb = IdbProxy(conn, idb_oid)
|
||||||
|
gui = Debugger.Debugger(pyshell, idb)
|
||||||
|
ada = GUIAdaper(conn, gui)
|
||||||
|
conn.register(ada_oid, ada)
|
||||||
|
return gui
|
36
Lib/idlelib/RemoteObjectBrowser.py
Normal file
36
Lib/idlelib/RemoteObjectBrowser.py
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import rpc
|
||||||
|
|
||||||
|
def remote_object_tree_item(item):
|
||||||
|
wrapper = WrappedObjectTreeItem(item)
|
||||||
|
oid = id(wrapper)
|
||||||
|
rpc.objecttable[oid] = wrapper
|
||||||
|
return oid
|
||||||
|
|
||||||
|
class WrappedObjectTreeItem:
|
||||||
|
# Lives in PYTHON subprocess
|
||||||
|
|
||||||
|
def __init__(self, item):
|
||||||
|
self.__item = item
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
value = getattr(self.__item, name)
|
||||||
|
return value
|
||||||
|
|
||||||
|
def _GetSubList(self):
|
||||||
|
list = self.__item._GetSubList()
|
||||||
|
return map(remote_object_tree_item, list)
|
||||||
|
|
||||||
|
class StubObjectTreeItem:
|
||||||
|
# Lives in IDLE process
|
||||||
|
|
||||||
|
def __init__(self, sockio, oid):
|
||||||
|
self.sockio = sockio
|
||||||
|
self.oid = oid
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
value = rpc.MethodProxy(self.sockio, self.oid, name)
|
||||||
|
return value
|
||||||
|
|
||||||
|
def _GetSubList(self):
|
||||||
|
list = self.sockio.remotecall(self.oid, "_GetSubList", (), {})
|
||||||
|
return [StubObjectTreeItem(self.sockio, oid) for oid in list]
|
|
@ -14,6 +14,14 @@ namespace. Output goes to the shell window.
|
||||||
- Run module (Control-F5) does the same but executes the module's
|
- Run module (Control-F5) does the same but executes the module's
|
||||||
code in the __main__ namespace.
|
code in the __main__ namespace.
|
||||||
|
|
||||||
|
XXX Redesign this interface (yet again) as follows:
|
||||||
|
|
||||||
|
- Present a dialog box for ``Run script''
|
||||||
|
|
||||||
|
- Allow specify command line arguments in the dialog box
|
||||||
|
|
||||||
|
- Restart the interpreter when running a script
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
@ -25,9 +33,9 @@ indent_message = """Error: Inconsistent indentation detected!
|
||||||
|
|
||||||
This means that either:
|
This means that either:
|
||||||
|
|
||||||
(1) your indentation is outright incorrect (easy to fix), or
|
1) your indentation is outright incorrect (easy to fix), or
|
||||||
|
|
||||||
(2) your indentation mixes tabs and spaces in a way that depends on \
|
2) your indentation mixes tabs and spaces in a way that depends on \
|
||||||
how many spaces a tab is worth.
|
how many spaces a tab is worth.
|
||||||
|
|
||||||
To fix case 2, change all tabs to spaces by using Select All followed \
|
To fix case 2, change all tabs to spaces by using Select All followed \
|
||||||
|
@ -105,28 +113,31 @@ class ScriptBinding:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def import_module_event(self, event):
|
def import_module_event(self, event):
|
||||||
|
flist = self.editwin.flist
|
||||||
|
shell = flist.open_shell()
|
||||||
|
interp = shell.interp
|
||||||
|
|
||||||
filename = self.getfilename()
|
filename = self.getfilename()
|
||||||
if not filename:
|
if not filename:
|
||||||
return
|
return
|
||||||
|
|
||||||
modname, ext = os.path.splitext(os.path.basename(filename))
|
modname, ext = os.path.splitext(os.path.basename(filename))
|
||||||
if sys.modules.has_key(modname):
|
|
||||||
mod = sys.modules[modname]
|
|
||||||
else:
|
|
||||||
mod = imp.new_module(modname)
|
|
||||||
sys.modules[modname] = mod
|
|
||||||
mod.__file__ = filename
|
|
||||||
setattr(sys.modules['__main__'], modname, mod)
|
|
||||||
|
|
||||||
dir = os.path.dirname(filename)
|
dir = os.path.dirname(filename)
|
||||||
dir = os.path.normpath(os.path.abspath(dir))
|
dir = os.path.normpath(os.path.abspath(dir))
|
||||||
if dir not in sys.path:
|
|
||||||
sys.path.insert(0, dir)
|
|
||||||
|
|
||||||
flist = self.editwin.flist
|
interp.runcode("""if 1:
|
||||||
shell = flist.open_shell()
|
import sys as _sys
|
||||||
interp = shell.interp
|
if %s not in _sys.path:
|
||||||
interp.runcode("reload(%s)" % modname)
|
_sys.path.insert(0, %s)
|
||||||
|
if _sys.modules.get(%s):
|
||||||
|
del _sys
|
||||||
|
import %s
|
||||||
|
reload(%s)
|
||||||
|
else:
|
||||||
|
del _sys
|
||||||
|
import %s
|
||||||
|
\n""" % (`dir`, `dir`, `modname`, modname, modname, modname))
|
||||||
|
|
||||||
def run_script_event(self, event):
|
def run_script_event(self, event):
|
||||||
filename = self.getfilename()
|
filename = self.getfilename()
|
||||||
|
@ -136,10 +147,16 @@ class ScriptBinding:
|
||||||
flist = self.editwin.flist
|
flist = self.editwin.flist
|
||||||
shell = flist.open_shell()
|
shell = flist.open_shell()
|
||||||
interp = shell.interp
|
interp = shell.interp
|
||||||
if (not sys.argv or
|
# XXX Too often this discards arguments the user just set...
|
||||||
os.path.basename(sys.argv[0]) != os.path.basename(filename)):
|
interp.runcommand("""if 1:
|
||||||
# XXX Too often this discards arguments the user just set...
|
_filename = %s
|
||||||
sys.argv = [filename]
|
import sys as _sys
|
||||||
|
from os.path import basename as _basename
|
||||||
|
if (not _sys.argv or
|
||||||
|
_basename(_sys.argv[0]) != _basename(_filename)):
|
||||||
|
_sys.argv = [_filename]
|
||||||
|
del _filename, _sys, _basename
|
||||||
|
\n""" % `filename`)
|
||||||
interp.execfile(filename)
|
interp.execfile(filename)
|
||||||
|
|
||||||
def getfilename(self):
|
def getfilename(self):
|
||||||
|
|
530
Lib/idlelib/rpc.py
Normal file
530
Lib/idlelib/rpc.py
Normal file
|
@ -0,0 +1,530 @@
|
||||||
|
# ASCII-art documentation
|
||||||
|
#
|
||||||
|
# +---------------------------------+ +----------+
|
||||||
|
# | SocketServer.BaseRequestHandler | | SocketIO |
|
||||||
|
# +---------------------------------+ +----------+
|
||||||
|
# ^ ^ ^
|
||||||
|
# | | |
|
||||||
|
# | + -------------------+ |
|
||||||
|
# | | |
|
||||||
|
# +-------------------------+ +-----------------+
|
||||||
|
# | RPCHandler | | RPCClient |
|
||||||
|
# |-------------------------| |-----------------|
|
||||||
|
# | register() | | remotecall() |
|
||||||
|
# | unregister() | | register() |
|
||||||
|
# | | | unregister() |
|
||||||
|
# | | | get_remote_proxy|
|
||||||
|
# +-------------------------+ +-----------------+
|
||||||
|
#
|
||||||
|
import sys
|
||||||
|
import socket
|
||||||
|
import select
|
||||||
|
import SocketServer
|
||||||
|
import struct
|
||||||
|
import cPickle as pickle
|
||||||
|
import threading
|
||||||
|
import traceback
|
||||||
|
import copy_reg
|
||||||
|
import types
|
||||||
|
import marshal
|
||||||
|
|
||||||
|
def unpickle_code(ms):
|
||||||
|
co = marshal.loads(ms)
|
||||||
|
assert isinstance(co, types.CodeType)
|
||||||
|
return co
|
||||||
|
|
||||||
|
def pickle_code(co):
|
||||||
|
assert isinstance(co, types.CodeType)
|
||||||
|
ms = marshal.dumps(co)
|
||||||
|
return unpickle_code, (ms,)
|
||||||
|
|
||||||
|
def unpickle_function(ms):
|
||||||
|
return ms
|
||||||
|
|
||||||
|
def pickle_function(fn):
|
||||||
|
assert isinstance(fn, type.FunctionType)
|
||||||
|
return `fn`
|
||||||
|
|
||||||
|
copy_reg.pickle(types.CodeType, pickle_code, unpickle_code)
|
||||||
|
copy_reg.pickle(types.FunctionType, pickle_function, unpickle_function)
|
||||||
|
|
||||||
|
BUFSIZE = 8*1024
|
||||||
|
|
||||||
|
class RPCServer(SocketServer.TCPServer):
|
||||||
|
|
||||||
|
def __init__(self, addr, handlerclass=None):
|
||||||
|
if handlerclass is None:
|
||||||
|
handlerclass = RPCHandler
|
||||||
|
self.objtable = objecttable
|
||||||
|
SocketServer.TCPServer.__init__(self, addr, handlerclass)
|
||||||
|
|
||||||
|
def verify_request(self, request, client_address):
|
||||||
|
host, port = client_address
|
||||||
|
if host != "127.0.0.1":
|
||||||
|
print "Disallowed host:", host
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def register(self, oid, object):
|
||||||
|
self.objtable[oid] = object
|
||||||
|
|
||||||
|
def unregister(self, oid):
|
||||||
|
try:
|
||||||
|
del self.objtable[oid]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
objecttable = {}
|
||||||
|
|
||||||
|
class SocketIO:
|
||||||
|
|
||||||
|
debugging = 0
|
||||||
|
|
||||||
|
def __init__(self, sock, objtable=None, debugging=None):
|
||||||
|
self.mainthread = threading.currentThread()
|
||||||
|
if debugging is not None:
|
||||||
|
self.debugging = debugging
|
||||||
|
self.sock = sock
|
||||||
|
if objtable is None:
|
||||||
|
objtable = objecttable
|
||||||
|
self.objtable = objtable
|
||||||
|
self.statelock = threading.Lock()
|
||||||
|
self.responses = {}
|
||||||
|
self.cvars = {}
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
sock = self.sock
|
||||||
|
self.sock = None
|
||||||
|
if sock is not None:
|
||||||
|
sock.close()
|
||||||
|
|
||||||
|
def debug(self, *args):
|
||||||
|
if not self.debugging:
|
||||||
|
return
|
||||||
|
s = str(threading.currentThread().getName())
|
||||||
|
for a in args:
|
||||||
|
s = s + " " + str(a)
|
||||||
|
s = s + "\n"
|
||||||
|
sys.__stderr__.write(s)
|
||||||
|
|
||||||
|
def register(self, oid, object):
|
||||||
|
self.objtable[oid] = object
|
||||||
|
|
||||||
|
def unregister(self, oid):
|
||||||
|
try:
|
||||||
|
del self.objtable[oid]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def localcall(self, request):
|
||||||
|
##self.debug("localcall:", request)
|
||||||
|
try:
|
||||||
|
how, (oid, methodname, args, kwargs) = request
|
||||||
|
except TypeError:
|
||||||
|
return ("ERROR", "Bad request format")
|
||||||
|
assert how == "call"
|
||||||
|
if not self.objtable.has_key(oid):
|
||||||
|
return ("ERROR", "Unknown object id: %s" % `oid`)
|
||||||
|
obj = self.objtable[oid]
|
||||||
|
if methodname == "__methods__":
|
||||||
|
methods = {}
|
||||||
|
_getmethods(obj, methods)
|
||||||
|
return ("OK", methods)
|
||||||
|
if methodname == "__attributes__":
|
||||||
|
attributes = {}
|
||||||
|
_getattributes(obj, attributes)
|
||||||
|
return ("OK", attributes)
|
||||||
|
if not hasattr(obj, methodname):
|
||||||
|
return ("ERROR", "Unsupported method name: %s" % `methodname`)
|
||||||
|
method = getattr(obj, methodname)
|
||||||
|
try:
|
||||||
|
ret = method(*args, **kwargs)
|
||||||
|
if isinstance(ret, RemoteObject):
|
||||||
|
ret = remoteref(ret)
|
||||||
|
return ("OK", ret)
|
||||||
|
except:
|
||||||
|
##traceback.print_exc(file=sys.__stderr__)
|
||||||
|
typ, val, tb = info = sys.exc_info()
|
||||||
|
sys.last_type, sys.last_value, sys.last_traceback = info
|
||||||
|
if isinstance(typ, type(Exception)):
|
||||||
|
# Class exceptions
|
||||||
|
mod = typ.__module__
|
||||||
|
name = typ.__name__
|
||||||
|
if issubclass(typ, Exception):
|
||||||
|
args = val.args
|
||||||
|
else:
|
||||||
|
args = (str(val),)
|
||||||
|
else:
|
||||||
|
# String exceptions
|
||||||
|
mod = None
|
||||||
|
name = typ
|
||||||
|
args = (str(val),)
|
||||||
|
tb = traceback.extract_tb(tb)
|
||||||
|
return ("EXCEPTION", (mod, name, args, tb))
|
||||||
|
|
||||||
|
def remotecall(self, oid, methodname, args, kwargs):
|
||||||
|
seq = self.asynccall(oid, methodname, args, kwargs)
|
||||||
|
return self.asyncreturn(seq)
|
||||||
|
|
||||||
|
def asynccall(self, oid, methodname, args, kwargs):
|
||||||
|
request = ("call", (oid, methodname, args, kwargs))
|
||||||
|
seq = self.putrequest(request)
|
||||||
|
return seq
|
||||||
|
|
||||||
|
def asyncreturn(self, seq):
|
||||||
|
response = self.getresponse(seq)
|
||||||
|
return self.decoderesponse(response)
|
||||||
|
|
||||||
|
def decoderesponse(self, response):
|
||||||
|
how, what = response
|
||||||
|
if how == "OK":
|
||||||
|
return what
|
||||||
|
if how == "EXCEPTION":
|
||||||
|
mod, name, args, tb = what
|
||||||
|
self.traceback = tb
|
||||||
|
if mod:
|
||||||
|
try:
|
||||||
|
__import__(mod)
|
||||||
|
module = sys.modules[mod]
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
cls = getattr(module, name)
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
raise getattr(__import__(mod), name)(*args)
|
||||||
|
else:
|
||||||
|
if mod:
|
||||||
|
name = mod + "." + name
|
||||||
|
raise name, args
|
||||||
|
if how == "ERROR":
|
||||||
|
raise RuntimeError, what
|
||||||
|
raise SystemError, (how, what)
|
||||||
|
|
||||||
|
def mainloop(self):
|
||||||
|
try:
|
||||||
|
self.getresponse(None)
|
||||||
|
except EOFError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def getresponse(self, myseq):
|
||||||
|
response = self._getresponse(myseq)
|
||||||
|
if response is not None:
|
||||||
|
how, what = response
|
||||||
|
if how == "OK":
|
||||||
|
response = how, self._proxify(what)
|
||||||
|
return response
|
||||||
|
|
||||||
|
def _proxify(self, obj):
|
||||||
|
if isinstance(obj, RemoteProxy):
|
||||||
|
return RPCProxy(self, obj.oid)
|
||||||
|
if isinstance(obj, types.ListType):
|
||||||
|
return map(self._proxify, obj)
|
||||||
|
# XXX Check for other types -- not currently needed
|
||||||
|
return obj
|
||||||
|
|
||||||
|
def _getresponse(self, myseq):
|
||||||
|
if threading.currentThread() is self.mainthread:
|
||||||
|
# Main thread: does all reading of requests and responses
|
||||||
|
while 1:
|
||||||
|
response = self.pollresponse(myseq, None)
|
||||||
|
if response is not None:
|
||||||
|
return response
|
||||||
|
else:
|
||||||
|
# Auxiliary thread: wait for notification from main thread
|
||||||
|
cvar = threading.Condition(self.statelock)
|
||||||
|
self.statelock.acquire()
|
||||||
|
self.cvars[myseq] = cvar
|
||||||
|
while not self.responses.has_key(myseq):
|
||||||
|
cvar.wait()
|
||||||
|
response = self.responses[myseq]
|
||||||
|
del self.responses[myseq]
|
||||||
|
del self.cvars[myseq]
|
||||||
|
self.statelock.release()
|
||||||
|
return response
|
||||||
|
|
||||||
|
def putrequest(self, request):
|
||||||
|
seq = self.newseq()
|
||||||
|
self.putmessage((seq, request))
|
||||||
|
return seq
|
||||||
|
|
||||||
|
nextseq = 0
|
||||||
|
|
||||||
|
def newseq(self):
|
||||||
|
self.nextseq = seq = self.nextseq + 2
|
||||||
|
return seq
|
||||||
|
|
||||||
|
def putmessage(self, message):
|
||||||
|
try:
|
||||||
|
s = pickle.dumps(message)
|
||||||
|
except:
|
||||||
|
print >>sys.__stderr__, "Cannot pickle:", `message`
|
||||||
|
raise
|
||||||
|
s = struct.pack("<i", len(s)) + s
|
||||||
|
while len(s) > 0:
|
||||||
|
n = self.sock.send(s)
|
||||||
|
s = s[n:]
|
||||||
|
|
||||||
|
def ioready(self, wait=0.0):
|
||||||
|
r, w, x = select.select([self.sock.fileno()], [], [], wait)
|
||||||
|
return len(r)
|
||||||
|
|
||||||
|
buffer = ""
|
||||||
|
bufneed = 4
|
||||||
|
bufstate = 0 # meaning: 0 => reading count; 1 => reading data
|
||||||
|
|
||||||
|
def pollpacket(self, wait=0.0):
|
||||||
|
self._stage0()
|
||||||
|
if len(self.buffer) < self.bufneed:
|
||||||
|
if not self.ioready(wait):
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
s = self.sock.recv(BUFSIZE)
|
||||||
|
except socket.error:
|
||||||
|
raise EOFError
|
||||||
|
if len(s) == 0:
|
||||||
|
raise EOFError
|
||||||
|
self.buffer += s
|
||||||
|
self._stage0()
|
||||||
|
return self._stage1()
|
||||||
|
|
||||||
|
def _stage0(self):
|
||||||
|
if self.bufstate == 0 and len(self.buffer) >= 4:
|
||||||
|
s = self.buffer[:4]
|
||||||
|
self.buffer = self.buffer[4:]
|
||||||
|
self.bufneed = struct.unpack("<i", s)[0]
|
||||||
|
self.bufstate = 1
|
||||||
|
|
||||||
|
def _stage1(self):
|
||||||
|
if self.bufstate == 1 and len(self.buffer) >= self.bufneed:
|
||||||
|
packet = self.buffer[:self.bufneed]
|
||||||
|
self.buffer = self.buffer[self.bufneed:]
|
||||||
|
self.bufneed = 4
|
||||||
|
self.bufstate = 0
|
||||||
|
return packet
|
||||||
|
|
||||||
|
def pollmessage(self, wait=0.0):
|
||||||
|
packet = self.pollpacket(wait)
|
||||||
|
if packet is None:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
message = pickle.loads(packet)
|
||||||
|
except:
|
||||||
|
print >>sys.__stderr__, "-----------------------"
|
||||||
|
print >>sys.__stderr__, "cannot unpickle packet:", `packet`
|
||||||
|
traceback.print_stack(file=sys.__stderr__)
|
||||||
|
print >>sys.__stderr__, "-----------------------"
|
||||||
|
raise
|
||||||
|
return message
|
||||||
|
|
||||||
|
def pollresponse(self, myseq, wait=0.0):
|
||||||
|
# Loop while there's no more buffered input or until specific response
|
||||||
|
while 1:
|
||||||
|
message = self.pollmessage(wait)
|
||||||
|
if message is None:
|
||||||
|
return None
|
||||||
|
wait = 0.0
|
||||||
|
seq, resq = message
|
||||||
|
if resq[0] == "call":
|
||||||
|
response = self.localcall(resq)
|
||||||
|
self.putmessage((seq, response))
|
||||||
|
continue
|
||||||
|
elif seq == myseq:
|
||||||
|
return resq
|
||||||
|
else:
|
||||||
|
self.statelock.acquire()
|
||||||
|
self.responses[seq] = resq
|
||||||
|
cv = self.cvars.get(seq)
|
||||||
|
if cv is not None:
|
||||||
|
cv.notify()
|
||||||
|
self.statelock.release()
|
||||||
|
continue
|
||||||
|
|
||||||
|
class RemoteObject:
|
||||||
|
# Token mix-in class
|
||||||
|
pass
|
||||||
|
|
||||||
|
def remoteref(obj):
|
||||||
|
oid = id(obj)
|
||||||
|
objecttable[oid] = obj
|
||||||
|
return RemoteProxy(oid)
|
||||||
|
|
||||||
|
class RemoteProxy:
|
||||||
|
|
||||||
|
def __init__(self, oid):
|
||||||
|
self.oid = oid
|
||||||
|
|
||||||
|
class RPCHandler(SocketServer.BaseRequestHandler, SocketIO):
|
||||||
|
|
||||||
|
debugging = 0
|
||||||
|
|
||||||
|
def __init__(self, sock, addr, svr):
|
||||||
|
svr.current_handler = self ## cgt xxx
|
||||||
|
SocketIO.__init__(self, sock)
|
||||||
|
SocketServer.BaseRequestHandler.__init__(self, sock, addr, svr)
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
SocketServer.BaseRequestHandler.setup(self)
|
||||||
|
print >>sys.__stderr__, "Connection from", self.client_address
|
||||||
|
|
||||||
|
def finish(self):
|
||||||
|
print >>sys.__stderr__, "End connection from", self.client_address
|
||||||
|
SocketServer.BaseRequestHandler.finish(self)
|
||||||
|
|
||||||
|
def handle(self):
|
||||||
|
self.mainloop()
|
||||||
|
|
||||||
|
def get_remote_proxy(self, oid):
|
||||||
|
return RPCProxy(self, oid)
|
||||||
|
|
||||||
|
class RPCClient(SocketIO):
|
||||||
|
|
||||||
|
nextseq = 1 # Requests coming from the client are odd
|
||||||
|
|
||||||
|
def __init__(self, address, family=socket.AF_INET, type=socket.SOCK_STREAM):
|
||||||
|
sock = socket.socket(family, type)
|
||||||
|
sock.connect(address)
|
||||||
|
SocketIO.__init__(self, sock)
|
||||||
|
|
||||||
|
def get_remote_proxy(self, oid):
|
||||||
|
return RPCProxy(self, oid)
|
||||||
|
|
||||||
|
class RPCProxy:
|
||||||
|
|
||||||
|
__methods = None
|
||||||
|
__attributes = None
|
||||||
|
|
||||||
|
def __init__(self, sockio, oid):
|
||||||
|
self.sockio = sockio
|
||||||
|
self.oid = oid
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
if self.__methods is None:
|
||||||
|
self.__getmethods()
|
||||||
|
if self.__methods.get(name):
|
||||||
|
return MethodProxy(self.sockio, self.oid, name)
|
||||||
|
if self.__attributes is None:
|
||||||
|
self.__getattributes()
|
||||||
|
if not self.__attributes.has_key(name):
|
||||||
|
raise AttributeError, name
|
||||||
|
__getattr__.DebuggerStepThrough=1
|
||||||
|
|
||||||
|
def __getattributes(self):
|
||||||
|
self.__attributes = self.sockio.remotecall(self.oid,
|
||||||
|
"__attributes__", (), {})
|
||||||
|
|
||||||
|
def __getmethods(self):
|
||||||
|
self.__methods = self.sockio.remotecall(self.oid,
|
||||||
|
"__methods__", (), {})
|
||||||
|
|
||||||
|
def _getmethods(obj, methods):
|
||||||
|
# Helper to get a list of methods from an object
|
||||||
|
# Adds names to dictionary argument 'methods'
|
||||||
|
for name in dir(obj):
|
||||||
|
attr = getattr(obj, name)
|
||||||
|
if callable(attr):
|
||||||
|
methods[name] = 1
|
||||||
|
if type(obj) == types.InstanceType:
|
||||||
|
_getmethods(obj.__class__, methods)
|
||||||
|
if type(obj) == types.ClassType:
|
||||||
|
for super in obj.__bases__:
|
||||||
|
_getmethods(super, methods)
|
||||||
|
|
||||||
|
def _getattributes(obj, attributes):
|
||||||
|
for name in dir(obj):
|
||||||
|
attr = getattr(obj, name)
|
||||||
|
if not callable(attr):
|
||||||
|
attributes[name] = 1
|
||||||
|
|
||||||
|
class MethodProxy:
|
||||||
|
|
||||||
|
def __init__(self, sockio, oid, name):
|
||||||
|
self.sockio = sockio
|
||||||
|
self.oid = oid
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
def __call__(self, *args, **kwargs):
|
||||||
|
value = self.sockio.remotecall(self.oid, self.name, args, kwargs)
|
||||||
|
return value
|
||||||
|
|
||||||
|
#
|
||||||
|
# Self Test
|
||||||
|
#
|
||||||
|
|
||||||
|
def testServer(addr):
|
||||||
|
class RemotePerson:
|
||||||
|
def __init__(self,name):
|
||||||
|
self.name = name
|
||||||
|
def greet(self, name):
|
||||||
|
print "(someone called greet)"
|
||||||
|
print "Hello %s, I am %s." % (name, self.name)
|
||||||
|
print
|
||||||
|
def getName(self):
|
||||||
|
print "(someone called getName)"
|
||||||
|
print
|
||||||
|
return self.name
|
||||||
|
def greet_this_guy(self, name):
|
||||||
|
print "(someone called greet_this_guy)"
|
||||||
|
print "About to greet %s ..." % name
|
||||||
|
remote_guy = self.server.current_handler.get_remote_proxy(name)
|
||||||
|
remote_guy.greet("Thomas Edison")
|
||||||
|
print "Done."
|
||||||
|
print
|
||||||
|
|
||||||
|
person = RemotePerson("Thomas Edison")
|
||||||
|
svr = RPCServer(addr)
|
||||||
|
svr.register('thomas', person)
|
||||||
|
person.server = svr # only required if callbacks are used
|
||||||
|
|
||||||
|
# svr.serve_forever()
|
||||||
|
svr.handle_request() # process once only
|
||||||
|
|
||||||
|
def testClient(addr):
|
||||||
|
|
||||||
|
#
|
||||||
|
# demonstrates RPC Client
|
||||||
|
#
|
||||||
|
import time
|
||||||
|
clt=RPCClient(addr)
|
||||||
|
thomas = clt.get_remote_proxy("thomas")
|
||||||
|
print "The remote person's name is ..."
|
||||||
|
print thomas.getName()
|
||||||
|
# print clt.remotecall("thomas", "getName", (), {})
|
||||||
|
print
|
||||||
|
time.sleep(1)
|
||||||
|
print "Getting remote thomas to say hi..."
|
||||||
|
thomas.greet("Alexander Bell")
|
||||||
|
#clt.remotecall("thomas","greet",("Alexander Bell",), {})
|
||||||
|
print "Done."
|
||||||
|
print
|
||||||
|
time.sleep(2)
|
||||||
|
|
||||||
|
# demonstrates remote server calling local instance
|
||||||
|
class LocalPerson:
|
||||||
|
def __init__(self,name):
|
||||||
|
self.name = name
|
||||||
|
def greet(self, name):
|
||||||
|
print "You've greeted me!"
|
||||||
|
def getName(self):
|
||||||
|
return self.name
|
||||||
|
person = LocalPerson("Alexander Bell")
|
||||||
|
clt.register("alexander",person)
|
||||||
|
thomas.greet_this_guy("alexander")
|
||||||
|
# clt.remotecall("thomas","greet_this_guy",("alexander",), {})
|
||||||
|
|
||||||
|
def test():
|
||||||
|
addr=("localhost",8833)
|
||||||
|
if len(sys.argv) == 2:
|
||||||
|
if sys.argv[1]=='-server':
|
||||||
|
testServer(addr)
|
||||||
|
return
|
||||||
|
testClient(addr)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
test()
|
||||||
|
|
||||||
|
|
49
Lib/idlelib/run.py
Normal file
49
Lib/idlelib/run.py
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
import sys
|
||||||
|
import rpc
|
||||||
|
|
||||||
|
def main():
|
||||||
|
port = 8833
|
||||||
|
if sys.argv[1:]:
|
||||||
|
port = int(sys.argv[1])
|
||||||
|
sys.argv[:] = [""]
|
||||||
|
addr = ("localhost", port)
|
||||||
|
svr = rpc.RPCServer(addr, MyHandler)
|
||||||
|
svr.handle_request() # A single request only
|
||||||
|
|
||||||
|
class MyHandler(rpc.RPCHandler):
|
||||||
|
|
||||||
|
def handle(self):
|
||||||
|
executive = Executive(self)
|
||||||
|
self.register("exec", executive)
|
||||||
|
sys.stdin = self.get_remote_proxy("stdin")
|
||||||
|
sys.stdout = self.get_remote_proxy("stdout")
|
||||||
|
sys.stderr = self.get_remote_proxy("stderr")
|
||||||
|
rpc.RPCHandler.handle(self)
|
||||||
|
|
||||||
|
class Executive:
|
||||||
|
|
||||||
|
def __init__(self, rpchandler):
|
||||||
|
self.conn = rpchandler
|
||||||
|
import __main__
|
||||||
|
self.locals = __main__.__dict__
|
||||||
|
|
||||||
|
def runcode(self, code):
|
||||||
|
exec code in self.locals
|
||||||
|
|
||||||
|
def start_debugger(self, gui_oid):
|
||||||
|
import RemoteDebugger
|
||||||
|
return RemoteDebugger.start_debugger(self.conn, gui_oid)
|
||||||
|
|
||||||
|
def stackviewer(self, flist_oid=None):
|
||||||
|
if not hasattr(sys, "last_traceback"):
|
||||||
|
return None
|
||||||
|
flist = None
|
||||||
|
if flist_oid is not None:
|
||||||
|
flist = self.conn.get_remote_proxy(flist_oid)
|
||||||
|
import RemoteObjectBrowser
|
||||||
|
import StackViewer
|
||||||
|
tb = sys.last_traceback
|
||||||
|
while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
|
||||||
|
tb = tb.tb_next
|
||||||
|
item = StackViewer.StackTreeItem(flist, tb)
|
||||||
|
return RemoteObjectBrowser.remote_object_tree_item(item)
|
Loading…
Add table
Add a link
Reference in a new issue