Commit 5afa1dfb authored by Kurt B. Kaiser's avatar Kurt B. Kaiser

M CallTips.py Add support for getting calltip from subprocess,

                   refactor a bit and clean up.

M PyShell.py       Cosmetic changes, delete blank lines, add # on some
                   blank lines.

M rpc.py           Add more debugging capability

M run.py           Add support for getting calltip from subprocess
                   Move import statements
parent 853ddd5c
# CallTips.py - An IDLE extension that provides "Call Tips" - ie, a floating window that """CallTips.py - An IDLE Extension to Jog Your Memory
# displays parameter information as you open parens.
Call Tips are floating windows which display function/method parameter
information as you open the parameter parenthesis, and which disappear when you
type the closing parenthesis. Future plans include extending the functionality
to include class attributes.
"""
import sys
import string import string
import types import types
import CallTipWindow
import __main__
class CallTips: class CallTips:
menudefs = [ menudefs = [
] ]
def __init__(self, editwin): def __init__(self, editwin=None):
if editwin == None: # subprocess and test
self.editwin = None
return
self.editwin = editwin self.editwin = editwin
self.text = editwin.text self.text = editwin.text
self.calltip = None self.calltip = None
if hasattr(self.text, "make_calltip_window"):
self._make_calltip_window = self.text.make_calltip_window
else:
self._make_calltip_window = self._make_tk_calltip_window self._make_calltip_window = self._make_tk_calltip_window
def close(self): def close(self):
self._make_calltip_window = None self._make_calltip_window = None
# Makes a Tk based calltip window. Used by IDLE, but not Pythonwin.
# See __init__ above for how this is used.
def _make_tk_calltip_window(self): def _make_tk_calltip_window(self):
import CallTipWindow # See __init__ for usage
return CallTipWindow.CallTip(self.text) return CallTipWindow.CallTip(self.text)
def _remove_calltip_window(self): def _remove_calltip_window(self):
...@@ -34,7 +42,8 @@ class CallTips: ...@@ -34,7 +42,8 @@ class CallTips:
def paren_open_event(self, event): def paren_open_event(self, event):
self._remove_calltip_window() self._remove_calltip_window()
arg_text = get_arg_text(self.get_object_at_cursor()) name = self.get_name_at_cursor()
arg_text = self.fetch_tip(name)
if arg_text: if arg_text:
self.calltip_start = self.text.index("insert") self.calltip_start = self.text.index("insert")
self.calltip = self._make_calltip_window() self.calltip = self._make_calltip_window()
...@@ -53,7 +62,8 @@ class CallTips: ...@@ -53,7 +62,8 @@ class CallTips:
# or off the calltip line, then cancel the tip. # or off the calltip line, then cancel the tip.
# (Later need to be smarter about multi-line, etc) # (Later need to be smarter about multi-line, etc)
if self.text.compare("insert", "<=", self.calltip_start) or \ if self.text.compare("insert", "<=", self.calltip_start) or \
self.text.compare("insert", ">", self.calltip_start + " lineend"): self.text.compare("insert", ">", self.calltip_start
+ " lineend"):
self._remove_calltip_window() self._remove_calltip_window()
return "" #so the event is handled normally. return "" #so the event is handled normally.
...@@ -61,29 +71,34 @@ class CallTips: ...@@ -61,29 +71,34 @@ class CallTips:
self._remove_calltip_window() self._remove_calltip_window()
return "" #so the event is handled normally. return "" #so the event is handled normally.
def get_object_at_cursor(self, __IDCHARS = "._" + string.ascii_letters + string.digits
wordchars="._" + string.ascii_letters + string.digits):
# Usage of ascii_letters is necessary to avoid UnicodeErrors def get_name_at_cursor(self):
# if chars contains non-ASCII. idchars = self.__IDCHARS
str = self.text.get("insert linestart", "insert")
# XXX - This needs to be moved to a better place i = len(str)
# so the "." attribute lookup code can also use it. while i and str[i-1] in idchars:
text = self.text i -= 1
chars = text.get("insert linestart", "insert") return str[i:]
i = len(chars)
while i and chars[i-1] in wordchars: def fetch_tip(self, name):
i = i-1 interp = self.editwin and self.editwin.flist.pyshell.interp
word = chars[i:] rpcclt = interp and interp.rpcclt
if word: if rpcclt:
# How is this for a hack! return rpcclt.remotecall("exec", "get_the_calltip",
import sys, __main__ (name,), {})
else:
entity = self.get_entity(name)
return get_arg_text(entity)
def get_entity(self, name):
if name:
namespace = sys.modules.copy() namespace = sys.modules.copy()
namespace.update(__main__.__dict__) namespace.update(__main__.__dict__)
try: try:
return eval(word, namespace) return eval(name, namespace)
except: except:
pass return None
return None # Can't find an object.
def _find_constructor(class_ob): def _find_constructor(class_ob):
# Given a class object, return a function object used for the # Given a class object, return a function object used for the
...@@ -142,7 +157,6 @@ def get_arg_text(ob): ...@@ -142,7 +157,6 @@ def get_arg_text(ob):
if argText: if argText:
argText += "\n" argText += "\n"
argText += doc[:pos] argText += doc[:pos]
return argText return argText
################################################# #################################################
...@@ -168,17 +182,21 @@ if __name__=='__main__': ...@@ -168,17 +182,21 @@ if __name__=='__main__':
def t5(self, a, *args): "(a, ...)" def t5(self, a, *args): "(a, ...)"
def t6(self, a, b=None, *args, **kw): "(a, b=None, ..., ***)" def t6(self, a, b=None, *args, **kw): "(a, b=None, ..., ***)"
def test( tests ): def test(tests):
ct = CallTips()
failed=[] failed=[]
for t in tests: for t in tests:
expected = t.__doc__ + "\n" + t.__doc__ expected = t.__doc__ + "\n" + t.__doc__
if get_arg_text(t) != expected: name = t.__name__
arg_text = ct.fetch_tip(name)
if arg_text != expected:
failed.append(t) failed.append(t)
print "%s - expected %s, but got %s" % (t, `expected`, `get_arg_text(t)`) print "%s - expected %s, but got %s" % (t, expected,
get_arg_text(entity))
print "%d of %d tests failed" % (len(failed), len(tests)) print "%d of %d tests failed" % (len(failed), len(tests))
tc = TC() tc = TC()
tests = t1, t2, t3, t4, t5, t6, \ tests = (t1, t2, t3, t4, t5, t6,
TC, tc.t1, tc.t2, tc.t3, tc.t4, tc.t5, tc.t6 TC, tc.t1, tc.t2, tc.t3, tc.t4, tc.t5, tc.t6)
test(tests) test(tests)
...@@ -414,7 +414,6 @@ class ModifiedInterpreter(InteractiveInterpreter): ...@@ -414,7 +414,6 @@ class ModifiedInterpreter(InteractiveInterpreter):
if self.tkconsole.executing: if self.tkconsole.executing:
display_executing_dialog() display_executing_dialog()
return return
#
self.checklinecache() 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
...@@ -425,7 +424,6 @@ class ModifiedInterpreter(InteractiveInterpreter): ...@@ -425,7 +424,6 @@ class ModifiedInterpreter(InteractiveInterpreter):
self.active_seq = self.rpcclt.asynccall("exec", "runcode", self.active_seq = self.rpcclt.asynccall("exec", "runcode",
(code,), {}) (code,), {})
return return
#
try: try:
self.tkconsole.beginexecuting() self.tkconsole.beginexecuting()
try: try:
...@@ -444,7 +442,6 @@ class ModifiedInterpreter(InteractiveInterpreter): ...@@ -444,7 +442,6 @@ class ModifiedInterpreter(InteractiveInterpreter):
self.showtraceback() self.showtraceback()
except: except:
self.showtraceback() self.showtraceback()
#
finally: finally:
self.tkconsole.endexecuting() self.tkconsole.endexecuting()
...@@ -480,14 +477,14 @@ class PyShell(OutputWindow): ...@@ -480,14 +477,14 @@ class PyShell(OutputWindow):
fixwordbreaks(root) fixwordbreaks(root)
root.withdraw() root.withdraw()
flist = PyShellFileList(root) flist = PyShellFileList(root)
#
OutputWindow.__init__(self, flist, None, None) OutputWindow.__init__(self, flist, None, None)
#
import __builtin__ import __builtin__
__builtin__.quit = __builtin__.exit = "To exit, type Ctrl-D." __builtin__.quit = __builtin__.exit = "To exit, type Ctrl-D."
#
self.config(usetabs=1, indentwidth=8, context_use_ps1=1) self.config(usetabs=1, indentwidth=8, context_use_ps1=1)
#
text = self.text text = self.text
text.configure(wrap="char") text.configure(wrap="char")
text.bind("<<newline-and-indent>>", self.enter_callback) text.bind("<<newline-and-indent>>", self.enter_callback)
...@@ -499,7 +496,7 @@ class PyShell(OutputWindow): ...@@ -499,7 +496,7 @@ class PyShell(OutputWindow):
text.bind("<<toggle-debugger>>", self.toggle_debugger) text.bind("<<toggle-debugger>>", self.toggle_debugger)
text.bind("<<open-python-shell>>", self.flist.open_shell) text.bind("<<open-python-shell>>", self.flist.open_shell)
text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer) text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
#
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
...@@ -510,9 +507,9 @@ class PyShell(OutputWindow): ...@@ -510,9 +507,9 @@ class PyShell(OutputWindow):
sys.stdout = self.stdout sys.stdout = self.stdout
sys.stderr = self.stderr sys.stderr = self.stderr
sys.stdin = self sys.stdin = self
#
self.history = self.History(self.text) self.history = self.History(self.text)
#
if use_subprocess: if use_subprocess:
self.interp.start_subprocess() self.interp.start_subprocess()
......
...@@ -177,9 +177,12 @@ class SocketIO: ...@@ -177,9 +177,12 @@ class SocketIO:
def remotecall(self, oid, methodname, args, kwargs): def remotecall(self, oid, methodname, args, kwargs):
self.debug("remotecall:", oid, methodname, args, kwargs) self.debug("remotecall:", oid, methodname, args, kwargs)
seq = self.asynccall(oid, methodname, args, kwargs) seq = self.asynccall(oid, methodname, args, kwargs)
return self.asyncreturn(seq) ret = self.asyncreturn(seq)
self.debug("return:", ret)
return ret
def asynccall(self, oid, methodname, args, kwargs): def asynccall(self, oid, methodname, args, kwargs):
self.debug("asyncall:", oid, methodname, args, kwargs)
request = ("call", (oid, methodname, args, kwargs)) request = ("call", (oid, methodname, args, kwargs))
seq = self.putrequest(request) seq = self.putrequest(request)
return seq return seq
......
import sys import sys
import time import time
import socket import socket
import CallTips
import RemoteDebugger
import RemoteObjectBrowser
import StackViewer
import rpc import rpc
import __main__
def main(): def main():
"""Start the Python execution server in a subprocess """Start the Python execution server in a subprocess
In Idle, RPCServer is instantiated with handlerclass MyHandler, which In the Python subprocess, RPCServer is instantiated with handlerclass
inherits register/unregister methods from RPCHandler via the mix-in class MyHandler, which inherits register/unregister methods from RPCHandler via
SocketIO. the mix-in class SocketIO.
When the RPCServer is instantiated, the TCPServer initialization creates an When the RPCServer svr is instantiated, the TCPServer initialization
instance of run.MyHandler and calls its handle() method. handle() creates an instance of run.MyHandler and calls its handle() method.
instantiates a run.Executive, passing it a reference to the MyHandler handle() instantiates a run.Executive object, passing it a reference to the
object. That reference is saved as an attribute of the Executive instance. MyHandler object. That reference is saved as attribute rpchandler of the
The Executive methods have access to the reference and can pass it on to Executive instance. The Executive methods have access to the reference and
entities that they command (e.g. RemoteDebugger.Debugger.start_debugger()). can pass it on to entities that they command
The latter, in turn, can call MyHandler(SocketIO) register/unregister (e.g. RemoteDebugger.Debugger.start_debugger()). The latter, in turn, can
methods via the reference to register and unregister themselves. call MyHandler(SocketIO) register/unregister methods via the reference to
register and unregister themselves.
""" """
port = 8833 port = 8833
...@@ -55,28 +63,28 @@ class Executive: ...@@ -55,28 +63,28 @@ class Executive:
def __init__(self, rpchandler): def __init__(self, rpchandler):
self.rpchandler = rpchandler self.rpchandler = rpchandler
import __main__
self.locals = __main__.__dict__ self.locals = __main__.__dict__
self.calltip = CallTips.CallTips()
def runcode(self, code): def runcode(self, code):
exec code in self.locals exec code in self.locals
def start_the_debugger(self, gui_adap_oid): def start_the_debugger(self, gui_adap_oid):
import RemoteDebugger
return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid) return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid)
def stop_the_debugger(self, idb_adap_oid): def stop_the_debugger(self, idb_adap_oid):
"Unregister the Idb Adapter. Link objects and Idb then subject to GC" "Unregister the Idb Adapter. Link objects and Idb then subject to GC"
self.rpchandler.unregister(idb_adap_oid) self.rpchandler.unregister(idb_adap_oid)
def get_the_calltip(self, name):
return self.calltip.fetch_tip(name)
def stackviewer(self, flist_oid=None): def stackviewer(self, flist_oid=None):
if not hasattr(sys, "last_traceback"): if not hasattr(sys, "last_traceback"):
return None return None
flist = None flist = None
if flist_oid is not None: if flist_oid is not None:
flist = self.rpchandler.get_remote_proxy(flist_oid) flist = self.rpchandler.get_remote_proxy(flist_oid)
import RemoteObjectBrowser
import StackViewer
tb = sys.last_traceback tb = sys.last_traceback
while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]: while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
tb = tb.tb_next tb = tb.tb_next
......
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