14adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao"""Support for remote Python debugging.
24adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
34adfde8bc82dd39f59e0445588c3e599ada477dJosh GaoSome ASCII art to describe the structure:
44adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
54adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao       IN PYTHON SUBPROCESS          #             IN IDLE PROCESS
64adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                                     #
74adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                                     #        oid='gui_adapter'
84adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                 +----------+        #       +------------+          +-----+
94adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                 | GUIProxy |--remote#call-->| GUIAdapter |--calls-->| GUI |
104adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao+-----+--calls-->+----------+        #       +------------+          +-----+
114adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao| Idb |                               #                             /
124adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao+-----+<-calls--+------------+         #      +----------+<--calls-/
134adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                | IdbAdapter |<--remote#call--| IdbProxy |
144adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                +------------+         #      +----------+
154adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                oid='idb_adapter'      #
164adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
174adfde8bc82dd39f59e0445588c3e599ada477dJosh GaoThe purpose of the Proxy and Adapter classes is to translate certain
184adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoarguments and return values that cannot be transported through the RPC
194adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaobarrier, in particular frame and traceback objects.
204adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
214adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao"""
224adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
234adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoimport types
244adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaofrom idlelib import rpc
254adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaofrom idlelib import Debugger
264adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
274adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodebugging = 0
284adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
294adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoidb_adap_oid = "idb_adapter"
304adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaogui_adap_oid = "gui_adapter"
314adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
324adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#=======================================
334adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#
344adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# In the PYTHON subprocess:
354adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
364adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoframetable = {}
374adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodicttable = {}
384adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaocodetable = {}
394adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaotracebacktable = {}
404adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
414adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef wrap_frame(frame):
424adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    fid = id(frame)
434adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    frametable[fid] = frame
444adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    return fid
454adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
464adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef wrap_info(info):
474adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    "replace info[2], a traceback instance, by its ID"
484adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    if info is None:
494adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return None
504adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    else:
514adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        traceback = info[2]
524adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        assert isinstance(traceback, types.TracebackType)
534adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        traceback_id = id(traceback)
544adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        tracebacktable[traceback_id] = traceback
554adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        modified_info = (info[0], info[1], traceback_id)
564adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return modified_info
574adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
584adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass GUIProxy:
594adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
604adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __init__(self, conn, gui_adap_oid):
614adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.conn = conn
624adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.oid = gui_adap_oid
634adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
644adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def interaction(self, message, frame, info=None):
654adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # calls rpc.SocketIO.remotecall() via run.MyHandler instance
664adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # pass frame and traceback object IDs instead of the objects themselves
674adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.conn.remotecall(self.oid, "interaction",
684adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                             (message, wrap_frame(frame), wrap_info(info)),
694adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                             {})
704adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
714adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass IdbAdapter:
724adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
734adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __init__(self, idb):
744adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.idb = idb
754adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
764adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    #----------called by an IdbProxy----------
774adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
784adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def set_step(self):
794adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.idb.set_step()
804adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
814adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def set_quit(self):
824adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.idb.set_quit()
834adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
844adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def set_continue(self):
854adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.idb.set_continue()
864adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
874adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def set_next(self, fid):
884adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        frame = frametable[fid]
894adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.idb.set_next(frame)
904adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
914adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def set_return(self, fid):
924adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        frame = frametable[fid]
934adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.idb.set_return(frame)
944adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
954adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def get_stack(self, fid, tbid):
964adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        ##print >>sys.__stderr__, "get_stack(%r, %r)" % (fid, tbid)
974adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        frame = frametable[fid]
984adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if tbid is None:
994adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            tb = None
1004adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        else:
1014adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            tb = tracebacktable[tbid]
1024adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        stack, i = self.idb.get_stack(frame, tb)
1034adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        ##print >>sys.__stderr__, "get_stack() ->", stack
1044adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        stack = [(wrap_frame(frame), k) for frame, k in stack]
1054adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        ##print >>sys.__stderr__, "get_stack() ->", stack
1064adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return stack, i
1074adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1084adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def run(self, cmd):
1094adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        import __main__
1104adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.idb.run(cmd, __main__.__dict__)
1114adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1124adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def set_break(self, filename, lineno):
1134adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        msg = self.idb.set_break(filename, lineno)
1144adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return msg
1154adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1164adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def clear_break(self, filename, lineno):
1174adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        msg = self.idb.clear_break(filename, lineno)
1184adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return msg
1194adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1204adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def clear_all_file_breaks(self, filename):
1214adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        msg = self.idb.clear_all_file_breaks(filename)
1224adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return msg
1234adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1244adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    #----------called by a FrameProxy----------
1254adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1264adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def frame_attr(self, fid, name):
1274adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        frame = frametable[fid]
1284adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return getattr(frame, name)
1294adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1304adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def frame_globals(self, fid):
1314adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        frame = frametable[fid]
1324adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        dict = frame.f_globals
1334adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        did = id(dict)
1344adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        dicttable[did] = dict
1354adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return did
1364adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1374adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def frame_locals(self, fid):
1384adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        frame = frametable[fid]
1394adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        dict = frame.f_locals
1404adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        did = id(dict)
1414adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        dicttable[did] = dict
1424adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return did
1434adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1444adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def frame_code(self, fid):
1454adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        frame = frametable[fid]
1464adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        code = frame.f_code
1474adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        cid = id(code)
1484adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        codetable[cid] = code
1494adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return cid
1504adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1514adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    #----------called by a CodeProxy----------
1524adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1534adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def code_name(self, cid):
1544adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        code = codetable[cid]
1554adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return code.co_name
1564adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1574adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def code_filename(self, cid):
1584adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        code = codetable[cid]
1594adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return code.co_filename
1604adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1614adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    #----------called by a DictProxy----------
1624adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1634adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def dict_keys(self, did):
1644adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        dict = dicttable[did]
1654adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return dict.keys()
1664adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1674adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def dict_item(self, did, key):
1684adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        dict = dicttable[did]
1694adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        value = dict[key]
1704adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        value = repr(value)
1714adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return value
1724adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1734adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#----------end class IdbAdapter----------
1744adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1754adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1764adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef start_debugger(rpchandler, gui_adap_oid):
1774adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    """Start the debugger and its RPC link in the Python subprocess
1784adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1794adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    Start the subprocess side of the split debugger and set up that side of the
1804adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    RPC link by instantiating the GUIProxy, Idb debugger, and IdbAdapter
1814adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    objects and linking them together.  Register the IdbAdapter with the
1824adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    RPCServer to handle RPC requests from the split debugger GUI via the
1834adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    IdbProxy.
1844adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1854adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    """
1864adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    gui_proxy = GUIProxy(rpchandler, gui_adap_oid)
1874adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    idb = Debugger.Idb(gui_proxy)
1884adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    idb_adap = IdbAdapter(idb)
1894adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    rpchandler.register(idb_adap_oid, idb_adap)
1904adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    return idb_adap_oid
1914adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1924adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1934adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#=======================================
1944adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao#
1954adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# In the IDLE process:
1964adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1974adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1984adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass FrameProxy:
1994adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2004adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __init__(self, conn, fid):
2014adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self._conn = conn
2024adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self._fid = fid
2034adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self._oid = "idb_adapter"
2044adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self._dictcache = {}
2054adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2064adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __getattr__(self, name):
2074adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if name[:1] == "_":
2084adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            raise AttributeError, name
2094adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if name == "f_code":
2104adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            return self._get_f_code()
2114adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if name == "f_globals":
2124adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            return self._get_f_globals()
2134adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if name == "f_locals":
2144adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            return self._get_f_locals()
2154adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return self._conn.remotecall(self._oid, "frame_attr",
2164adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                                     (self._fid, name), {})
2174adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2184adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def _get_f_code(self):
2194adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        cid = self._conn.remotecall(self._oid, "frame_code", (self._fid,), {})
2204adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return CodeProxy(self._conn, self._oid, cid)
2214adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2224adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def _get_f_globals(self):
2234adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        did = self._conn.remotecall(self._oid, "frame_globals",
2244adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                                    (self._fid,), {})
2254adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return self._get_dict_proxy(did)
2264adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2274adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def _get_f_locals(self):
2284adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        did = self._conn.remotecall(self._oid, "frame_locals",
2294adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                                    (self._fid,), {})
2304adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return self._get_dict_proxy(did)
2314adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2324adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def _get_dict_proxy(self, did):
2334adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if did in self._dictcache:
2344adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            return self._dictcache[did]
2354adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        dp = DictProxy(self._conn, self._oid, did)
2364adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self._dictcache[did] = dp
2374adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return dp
2384adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2394adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2404adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass CodeProxy:
2414adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2424adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __init__(self, conn, oid, cid):
2434adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self._conn = conn
2444adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self._oid = oid
2454adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self._cid = cid
2464adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2474adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __getattr__(self, name):
2484adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if name == "co_name":
2494adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            return self._conn.remotecall(self._oid, "code_name",
2504adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                                         (self._cid,), {})
2514adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if name == "co_filename":
2524adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            return self._conn.remotecall(self._oid, "code_filename",
2534adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                                         (self._cid,), {})
2544adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2554adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2564adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass DictProxy:
2574adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2584adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __init__(self, conn, oid, did):
2594adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self._conn = conn
2604adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self._oid = oid
2614adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self._did = did
2624adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2634adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def keys(self):
2644adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return self._conn.remotecall(self._oid, "dict_keys", (self._did,), {})
2654adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2664adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __getitem__(self, key):
2674adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return self._conn.remotecall(self._oid, "dict_item",
2684adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                                     (self._did, key), {})
2694adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2704adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __getattr__(self, name):
2714adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        ##print >>sys.__stderr__, "failed DictProxy.__getattr__:", name
2724adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        raise AttributeError, name
2734adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2744adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2754adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass GUIAdapter:
2764adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2774adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __init__(self, conn, gui):
2784adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.conn = conn
2794adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.gui = gui
2804adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2814adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def interaction(self, message, fid, modified_info):
2824adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        ##print "interaction: (%s, %s, %s)" % (message, fid, modified_info)
2834adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        frame = FrameProxy(self.conn, fid)
2844adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.gui.interaction(message, frame, modified_info)
2854adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2864adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2874adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass IdbProxy:
2884adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2894adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __init__(self, conn, shell, oid):
2904adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.oid = oid
2914adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.conn = conn
2924adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.shell = shell
2934adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2944adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def call(self, methodname, *args, **kwargs):
2954adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        ##print "**IdbProxy.call %s %s %s" % (methodname, args, kwargs)
2964adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        value = self.conn.remotecall(self.oid, methodname, args, kwargs)
2974adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        ##print "**IdbProxy.call %s returns %r" % (methodname, value)
2984adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return value
2994adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3004adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def run(self, cmd, locals):
3014adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # Ignores locals on purpose!
3024adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        seq = self.conn.asyncqueue(self.oid, "run", (cmd,), {})
3034adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.shell.interp.active_seq = seq
3044adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3054adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def get_stack(self, frame, tbid):
3064adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # passing frame and traceback IDs, not the objects themselves
3074adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        stack, i = self.call("get_stack", frame._fid, tbid)
3084adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        stack = [(FrameProxy(self.conn, fid), k) for fid, k in stack]
3094adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return stack, i
3104adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3114adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def set_continue(self):
3124adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.call("set_continue")
3134adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3144adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def set_step(self):
3154adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.call("set_step")
3164adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3174adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def set_next(self, frame):
3184adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.call("set_next", frame._fid)
3194adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3204adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def set_return(self, frame):
3214adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.call("set_return", frame._fid)
3224adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3234adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def set_quit(self):
3244adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.call("set_quit")
3254adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3264adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def set_break(self, filename, lineno):
3274adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        msg = self.call("set_break", filename, lineno)
3284adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return msg
3294adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3304adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def clear_break(self, filename, lineno):
3314adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        msg = self.call("clear_break", filename, lineno)
3324adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return msg
3334adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3344adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def clear_all_file_breaks(self, filename):
3354adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        msg = self.call("clear_all_file_breaks", filename)
3364adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return msg
3374adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3384adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef start_remote_debugger(rpcclt, pyshell):
3394adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    """Start the subprocess debugger, initialize the debugger GUI and RPC link
3404adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3414adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    Request the RPCServer start the Python subprocess debugger and link.  Set
3424adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    up the Idle side of the split debugger by instantiating the IdbProxy,
3434adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    debugger GUI, and debugger GUIAdapter objects and linking them together.
3444adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3454adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    Register the GUIAdapter with the RPCClient to handle debugger GUI
3464adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    interaction requests coming from the subprocess debugger via the GUIProxy.
3474adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3484adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    The IdbAdapter will pass execution and environment requests coming from the
3494adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    Idle debugger GUI to the subprocess debugger via the IdbProxy.
3504adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3514adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    """
3524adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    global idb_adap_oid
3534adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3544adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    idb_adap_oid = rpcclt.remotecall("exec", "start_the_debugger",\
3554adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                                   (gui_adap_oid,), {})
3564adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    idb_proxy = IdbProxy(rpcclt, pyshell, idb_adap_oid)
3574adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    gui = Debugger.Debugger(pyshell, idb_proxy)
3584adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    gui_adap = GUIAdapter(rpcclt, gui)
3594adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    rpcclt.register(gui_adap_oid, gui_adap)
3604adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    return gui
3614adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3624adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef close_remote_debugger(rpcclt):
3634adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    """Shut down subprocess debugger and Idle side of debugger RPC link
3644adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3654adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    Request that the RPCServer shut down the subprocess debugger and link.
3664adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    Unregister the GUIAdapter, which will cause a GC on the Idle process
3674adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    debugger and RPC link objects.  (The second reference to the debugger GUI
3684adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    is deleted in PyShell.close_remote_debugger().)
3694adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3704adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    """
3714adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    close_subprocess_debugger(rpcclt)
3724adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    rpcclt.unregister(gui_adap_oid)
3734adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3744adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef close_subprocess_debugger(rpcclt):
3754adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    rpcclt.remotecall("exec", "stop_the_debugger", (idb_adap_oid,), {})
3764adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
3774adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef restart_subprocess_debugger(rpcclt):
3784adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    idb_adap_oid_ret = rpcclt.remotecall("exec", "start_the_debugger",\
3794adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                                         (gui_adap_oid,), {})
3804adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    assert idb_adap_oid_ret == idb_adap_oid, 'Idb restarted with different oid'
381