17db96d56Sopenharmony_ci"""Support for remote Python debugging. 27db96d56Sopenharmony_ci 37db96d56Sopenharmony_ciSome ASCII art to describe the structure: 47db96d56Sopenharmony_ci 57db96d56Sopenharmony_ci IN PYTHON SUBPROCESS # IN IDLE PROCESS 67db96d56Sopenharmony_ci # 77db96d56Sopenharmony_ci # oid='gui_adapter' 87db96d56Sopenharmony_ci +----------+ # +------------+ +-----+ 97db96d56Sopenharmony_ci | GUIProxy |--remote#call-->| GUIAdapter |--calls-->| GUI | 107db96d56Sopenharmony_ci+-----+--calls-->+----------+ # +------------+ +-----+ 117db96d56Sopenharmony_ci| Idb | # / 127db96d56Sopenharmony_ci+-----+<-calls--+------------+ # +----------+<--calls-/ 137db96d56Sopenharmony_ci | IdbAdapter |<--remote#call--| IdbProxy | 147db96d56Sopenharmony_ci +------------+ # +----------+ 157db96d56Sopenharmony_ci oid='idb_adapter' # 167db96d56Sopenharmony_ci 177db96d56Sopenharmony_ciThe purpose of the Proxy and Adapter classes is to translate certain 187db96d56Sopenharmony_ciarguments and return values that cannot be transported through the RPC 197db96d56Sopenharmony_cibarrier, in particular frame and traceback objects. 207db96d56Sopenharmony_ci 217db96d56Sopenharmony_ci""" 227db96d56Sopenharmony_ciimport reprlib 237db96d56Sopenharmony_ciimport types 247db96d56Sopenharmony_cifrom idlelib import debugger 257db96d56Sopenharmony_ci 267db96d56Sopenharmony_cidebugging = 0 277db96d56Sopenharmony_ci 287db96d56Sopenharmony_ciidb_adap_oid = "idb_adapter" 297db96d56Sopenharmony_cigui_adap_oid = "gui_adapter" 307db96d56Sopenharmony_ci 317db96d56Sopenharmony_ci#======================================= 327db96d56Sopenharmony_ci# 337db96d56Sopenharmony_ci# In the PYTHON subprocess: 347db96d56Sopenharmony_ci 357db96d56Sopenharmony_ciframetable = {} 367db96d56Sopenharmony_cidicttable = {} 377db96d56Sopenharmony_cicodetable = {} 387db96d56Sopenharmony_citracebacktable = {} 397db96d56Sopenharmony_ci 407db96d56Sopenharmony_cidef wrap_frame(frame): 417db96d56Sopenharmony_ci fid = id(frame) 427db96d56Sopenharmony_ci frametable[fid] = frame 437db96d56Sopenharmony_ci return fid 447db96d56Sopenharmony_ci 457db96d56Sopenharmony_cidef wrap_info(info): 467db96d56Sopenharmony_ci "replace info[2], a traceback instance, by its ID" 477db96d56Sopenharmony_ci if info is None: 487db96d56Sopenharmony_ci return None 497db96d56Sopenharmony_ci else: 507db96d56Sopenharmony_ci traceback = info[2] 517db96d56Sopenharmony_ci assert isinstance(traceback, types.TracebackType) 527db96d56Sopenharmony_ci traceback_id = id(traceback) 537db96d56Sopenharmony_ci tracebacktable[traceback_id] = traceback 547db96d56Sopenharmony_ci modified_info = (info[0], info[1], traceback_id) 557db96d56Sopenharmony_ci return modified_info 567db96d56Sopenharmony_ci 577db96d56Sopenharmony_ciclass GUIProxy: 587db96d56Sopenharmony_ci 597db96d56Sopenharmony_ci def __init__(self, conn, gui_adap_oid): 607db96d56Sopenharmony_ci self.conn = conn 617db96d56Sopenharmony_ci self.oid = gui_adap_oid 627db96d56Sopenharmony_ci 637db96d56Sopenharmony_ci def interaction(self, message, frame, info=None): 647db96d56Sopenharmony_ci # calls rpc.SocketIO.remotecall() via run.MyHandler instance 657db96d56Sopenharmony_ci # pass frame and traceback object IDs instead of the objects themselves 667db96d56Sopenharmony_ci self.conn.remotecall(self.oid, "interaction", 677db96d56Sopenharmony_ci (message, wrap_frame(frame), wrap_info(info)), 687db96d56Sopenharmony_ci {}) 697db96d56Sopenharmony_ci 707db96d56Sopenharmony_ciclass IdbAdapter: 717db96d56Sopenharmony_ci 727db96d56Sopenharmony_ci def __init__(self, idb): 737db96d56Sopenharmony_ci self.idb = idb 747db96d56Sopenharmony_ci 757db96d56Sopenharmony_ci #----------called by an IdbProxy---------- 767db96d56Sopenharmony_ci 777db96d56Sopenharmony_ci def set_step(self): 787db96d56Sopenharmony_ci self.idb.set_step() 797db96d56Sopenharmony_ci 807db96d56Sopenharmony_ci def set_quit(self): 817db96d56Sopenharmony_ci self.idb.set_quit() 827db96d56Sopenharmony_ci 837db96d56Sopenharmony_ci def set_continue(self): 847db96d56Sopenharmony_ci self.idb.set_continue() 857db96d56Sopenharmony_ci 867db96d56Sopenharmony_ci def set_next(self, fid): 877db96d56Sopenharmony_ci frame = frametable[fid] 887db96d56Sopenharmony_ci self.idb.set_next(frame) 897db96d56Sopenharmony_ci 907db96d56Sopenharmony_ci def set_return(self, fid): 917db96d56Sopenharmony_ci frame = frametable[fid] 927db96d56Sopenharmony_ci self.idb.set_return(frame) 937db96d56Sopenharmony_ci 947db96d56Sopenharmony_ci def get_stack(self, fid, tbid): 957db96d56Sopenharmony_ci frame = frametable[fid] 967db96d56Sopenharmony_ci if tbid is None: 977db96d56Sopenharmony_ci tb = None 987db96d56Sopenharmony_ci else: 997db96d56Sopenharmony_ci tb = tracebacktable[tbid] 1007db96d56Sopenharmony_ci stack, i = self.idb.get_stack(frame, tb) 1017db96d56Sopenharmony_ci stack = [(wrap_frame(frame2), k) for frame2, k in stack] 1027db96d56Sopenharmony_ci return stack, i 1037db96d56Sopenharmony_ci 1047db96d56Sopenharmony_ci def run(self, cmd): 1057db96d56Sopenharmony_ci import __main__ 1067db96d56Sopenharmony_ci self.idb.run(cmd, __main__.__dict__) 1077db96d56Sopenharmony_ci 1087db96d56Sopenharmony_ci def set_break(self, filename, lineno): 1097db96d56Sopenharmony_ci msg = self.idb.set_break(filename, lineno) 1107db96d56Sopenharmony_ci return msg 1117db96d56Sopenharmony_ci 1127db96d56Sopenharmony_ci def clear_break(self, filename, lineno): 1137db96d56Sopenharmony_ci msg = self.idb.clear_break(filename, lineno) 1147db96d56Sopenharmony_ci return msg 1157db96d56Sopenharmony_ci 1167db96d56Sopenharmony_ci def clear_all_file_breaks(self, filename): 1177db96d56Sopenharmony_ci msg = self.idb.clear_all_file_breaks(filename) 1187db96d56Sopenharmony_ci return msg 1197db96d56Sopenharmony_ci 1207db96d56Sopenharmony_ci #----------called by a FrameProxy---------- 1217db96d56Sopenharmony_ci 1227db96d56Sopenharmony_ci def frame_attr(self, fid, name): 1237db96d56Sopenharmony_ci frame = frametable[fid] 1247db96d56Sopenharmony_ci return getattr(frame, name) 1257db96d56Sopenharmony_ci 1267db96d56Sopenharmony_ci def frame_globals(self, fid): 1277db96d56Sopenharmony_ci frame = frametable[fid] 1287db96d56Sopenharmony_ci dict = frame.f_globals 1297db96d56Sopenharmony_ci did = id(dict) 1307db96d56Sopenharmony_ci dicttable[did] = dict 1317db96d56Sopenharmony_ci return did 1327db96d56Sopenharmony_ci 1337db96d56Sopenharmony_ci def frame_locals(self, fid): 1347db96d56Sopenharmony_ci frame = frametable[fid] 1357db96d56Sopenharmony_ci dict = frame.f_locals 1367db96d56Sopenharmony_ci did = id(dict) 1377db96d56Sopenharmony_ci dicttable[did] = dict 1387db96d56Sopenharmony_ci return did 1397db96d56Sopenharmony_ci 1407db96d56Sopenharmony_ci def frame_code(self, fid): 1417db96d56Sopenharmony_ci frame = frametable[fid] 1427db96d56Sopenharmony_ci code = frame.f_code 1437db96d56Sopenharmony_ci cid = id(code) 1447db96d56Sopenharmony_ci codetable[cid] = code 1457db96d56Sopenharmony_ci return cid 1467db96d56Sopenharmony_ci 1477db96d56Sopenharmony_ci #----------called by a CodeProxy---------- 1487db96d56Sopenharmony_ci 1497db96d56Sopenharmony_ci def code_name(self, cid): 1507db96d56Sopenharmony_ci code = codetable[cid] 1517db96d56Sopenharmony_ci return code.co_name 1527db96d56Sopenharmony_ci 1537db96d56Sopenharmony_ci def code_filename(self, cid): 1547db96d56Sopenharmony_ci code = codetable[cid] 1557db96d56Sopenharmony_ci return code.co_filename 1567db96d56Sopenharmony_ci 1577db96d56Sopenharmony_ci #----------called by a DictProxy---------- 1587db96d56Sopenharmony_ci 1597db96d56Sopenharmony_ci def dict_keys(self, did): 1607db96d56Sopenharmony_ci raise NotImplementedError("dict_keys not public or pickleable") 1617db96d56Sopenharmony_ci## dict = dicttable[did] 1627db96d56Sopenharmony_ci## return dict.keys() 1637db96d56Sopenharmony_ci 1647db96d56Sopenharmony_ci ### Needed until dict_keys is type is finished and pickealable. 1657db96d56Sopenharmony_ci ### Will probably need to extend rpc.py:SocketIO._proxify at that time. 1667db96d56Sopenharmony_ci def dict_keys_list(self, did): 1677db96d56Sopenharmony_ci dict = dicttable[did] 1687db96d56Sopenharmony_ci return list(dict.keys()) 1697db96d56Sopenharmony_ci 1707db96d56Sopenharmony_ci def dict_item(self, did, key): 1717db96d56Sopenharmony_ci dict = dicttable[did] 1727db96d56Sopenharmony_ci value = dict[key] 1737db96d56Sopenharmony_ci value = reprlib.repr(value) ### can't pickle module 'builtins' 1747db96d56Sopenharmony_ci return value 1757db96d56Sopenharmony_ci 1767db96d56Sopenharmony_ci#----------end class IdbAdapter---------- 1777db96d56Sopenharmony_ci 1787db96d56Sopenharmony_ci 1797db96d56Sopenharmony_cidef start_debugger(rpchandler, gui_adap_oid): 1807db96d56Sopenharmony_ci """Start the debugger and its RPC link in the Python subprocess 1817db96d56Sopenharmony_ci 1827db96d56Sopenharmony_ci Start the subprocess side of the split debugger and set up that side of the 1837db96d56Sopenharmony_ci RPC link by instantiating the GUIProxy, Idb debugger, and IdbAdapter 1847db96d56Sopenharmony_ci objects and linking them together. Register the IdbAdapter with the 1857db96d56Sopenharmony_ci RPCServer to handle RPC requests from the split debugger GUI via the 1867db96d56Sopenharmony_ci IdbProxy. 1877db96d56Sopenharmony_ci 1887db96d56Sopenharmony_ci """ 1897db96d56Sopenharmony_ci gui_proxy = GUIProxy(rpchandler, gui_adap_oid) 1907db96d56Sopenharmony_ci idb = debugger.Idb(gui_proxy) 1917db96d56Sopenharmony_ci idb_adap = IdbAdapter(idb) 1927db96d56Sopenharmony_ci rpchandler.register(idb_adap_oid, idb_adap) 1937db96d56Sopenharmony_ci return idb_adap_oid 1947db96d56Sopenharmony_ci 1957db96d56Sopenharmony_ci 1967db96d56Sopenharmony_ci#======================================= 1977db96d56Sopenharmony_ci# 1987db96d56Sopenharmony_ci# In the IDLE process: 1997db96d56Sopenharmony_ci 2007db96d56Sopenharmony_ci 2017db96d56Sopenharmony_ciclass FrameProxy: 2027db96d56Sopenharmony_ci 2037db96d56Sopenharmony_ci def __init__(self, conn, fid): 2047db96d56Sopenharmony_ci self._conn = conn 2057db96d56Sopenharmony_ci self._fid = fid 2067db96d56Sopenharmony_ci self._oid = "idb_adapter" 2077db96d56Sopenharmony_ci self._dictcache = {} 2087db96d56Sopenharmony_ci 2097db96d56Sopenharmony_ci def __getattr__(self, name): 2107db96d56Sopenharmony_ci if name[:1] == "_": 2117db96d56Sopenharmony_ci raise AttributeError(name) 2127db96d56Sopenharmony_ci if name == "f_code": 2137db96d56Sopenharmony_ci return self._get_f_code() 2147db96d56Sopenharmony_ci if name == "f_globals": 2157db96d56Sopenharmony_ci return self._get_f_globals() 2167db96d56Sopenharmony_ci if name == "f_locals": 2177db96d56Sopenharmony_ci return self._get_f_locals() 2187db96d56Sopenharmony_ci return self._conn.remotecall(self._oid, "frame_attr", 2197db96d56Sopenharmony_ci (self._fid, name), {}) 2207db96d56Sopenharmony_ci 2217db96d56Sopenharmony_ci def _get_f_code(self): 2227db96d56Sopenharmony_ci cid = self._conn.remotecall(self._oid, "frame_code", (self._fid,), {}) 2237db96d56Sopenharmony_ci return CodeProxy(self._conn, self._oid, cid) 2247db96d56Sopenharmony_ci 2257db96d56Sopenharmony_ci def _get_f_globals(self): 2267db96d56Sopenharmony_ci did = self._conn.remotecall(self._oid, "frame_globals", 2277db96d56Sopenharmony_ci (self._fid,), {}) 2287db96d56Sopenharmony_ci return self._get_dict_proxy(did) 2297db96d56Sopenharmony_ci 2307db96d56Sopenharmony_ci def _get_f_locals(self): 2317db96d56Sopenharmony_ci did = self._conn.remotecall(self._oid, "frame_locals", 2327db96d56Sopenharmony_ci (self._fid,), {}) 2337db96d56Sopenharmony_ci return self._get_dict_proxy(did) 2347db96d56Sopenharmony_ci 2357db96d56Sopenharmony_ci def _get_dict_proxy(self, did): 2367db96d56Sopenharmony_ci if did in self._dictcache: 2377db96d56Sopenharmony_ci return self._dictcache[did] 2387db96d56Sopenharmony_ci dp = DictProxy(self._conn, self._oid, did) 2397db96d56Sopenharmony_ci self._dictcache[did] = dp 2407db96d56Sopenharmony_ci return dp 2417db96d56Sopenharmony_ci 2427db96d56Sopenharmony_ci 2437db96d56Sopenharmony_ciclass CodeProxy: 2447db96d56Sopenharmony_ci 2457db96d56Sopenharmony_ci def __init__(self, conn, oid, cid): 2467db96d56Sopenharmony_ci self._conn = conn 2477db96d56Sopenharmony_ci self._oid = oid 2487db96d56Sopenharmony_ci self._cid = cid 2497db96d56Sopenharmony_ci 2507db96d56Sopenharmony_ci def __getattr__(self, name): 2517db96d56Sopenharmony_ci if name == "co_name": 2527db96d56Sopenharmony_ci return self._conn.remotecall(self._oid, "code_name", 2537db96d56Sopenharmony_ci (self._cid,), {}) 2547db96d56Sopenharmony_ci if name == "co_filename": 2557db96d56Sopenharmony_ci return self._conn.remotecall(self._oid, "code_filename", 2567db96d56Sopenharmony_ci (self._cid,), {}) 2577db96d56Sopenharmony_ci 2587db96d56Sopenharmony_ci 2597db96d56Sopenharmony_ciclass DictProxy: 2607db96d56Sopenharmony_ci 2617db96d56Sopenharmony_ci def __init__(self, conn, oid, did): 2627db96d56Sopenharmony_ci self._conn = conn 2637db96d56Sopenharmony_ci self._oid = oid 2647db96d56Sopenharmony_ci self._did = did 2657db96d56Sopenharmony_ci 2667db96d56Sopenharmony_ci## def keys(self): 2677db96d56Sopenharmony_ci## return self._conn.remotecall(self._oid, "dict_keys", (self._did,), {}) 2687db96d56Sopenharmony_ci 2697db96d56Sopenharmony_ci # 'temporary' until dict_keys is a pickleable built-in type 2707db96d56Sopenharmony_ci def keys(self): 2717db96d56Sopenharmony_ci return self._conn.remotecall(self._oid, 2727db96d56Sopenharmony_ci "dict_keys_list", (self._did,), {}) 2737db96d56Sopenharmony_ci 2747db96d56Sopenharmony_ci def __getitem__(self, key): 2757db96d56Sopenharmony_ci return self._conn.remotecall(self._oid, "dict_item", 2767db96d56Sopenharmony_ci (self._did, key), {}) 2777db96d56Sopenharmony_ci 2787db96d56Sopenharmony_ci def __getattr__(self, name): 2797db96d56Sopenharmony_ci ##print("*** Failed DictProxy.__getattr__:", name) 2807db96d56Sopenharmony_ci raise AttributeError(name) 2817db96d56Sopenharmony_ci 2827db96d56Sopenharmony_ci 2837db96d56Sopenharmony_ciclass GUIAdapter: 2847db96d56Sopenharmony_ci 2857db96d56Sopenharmony_ci def __init__(self, conn, gui): 2867db96d56Sopenharmony_ci self.conn = conn 2877db96d56Sopenharmony_ci self.gui = gui 2887db96d56Sopenharmony_ci 2897db96d56Sopenharmony_ci def interaction(self, message, fid, modified_info): 2907db96d56Sopenharmony_ci ##print("*** Interaction: (%s, %s, %s)" % (message, fid, modified_info)) 2917db96d56Sopenharmony_ci frame = FrameProxy(self.conn, fid) 2927db96d56Sopenharmony_ci self.gui.interaction(message, frame, modified_info) 2937db96d56Sopenharmony_ci 2947db96d56Sopenharmony_ci 2957db96d56Sopenharmony_ciclass IdbProxy: 2967db96d56Sopenharmony_ci 2977db96d56Sopenharmony_ci def __init__(self, conn, shell, oid): 2987db96d56Sopenharmony_ci self.oid = oid 2997db96d56Sopenharmony_ci self.conn = conn 3007db96d56Sopenharmony_ci self.shell = shell 3017db96d56Sopenharmony_ci 3027db96d56Sopenharmony_ci def call(self, methodname, /, *args, **kwargs): 3037db96d56Sopenharmony_ci ##print("*** IdbProxy.call %s %s %s" % (methodname, args, kwargs)) 3047db96d56Sopenharmony_ci value = self.conn.remotecall(self.oid, methodname, args, kwargs) 3057db96d56Sopenharmony_ci ##print("*** IdbProxy.call %s returns %r" % (methodname, value)) 3067db96d56Sopenharmony_ci return value 3077db96d56Sopenharmony_ci 3087db96d56Sopenharmony_ci def run(self, cmd, locals): 3097db96d56Sopenharmony_ci # Ignores locals on purpose! 3107db96d56Sopenharmony_ci seq = self.conn.asyncqueue(self.oid, "run", (cmd,), {}) 3117db96d56Sopenharmony_ci self.shell.interp.active_seq = seq 3127db96d56Sopenharmony_ci 3137db96d56Sopenharmony_ci def get_stack(self, frame, tbid): 3147db96d56Sopenharmony_ci # passing frame and traceback IDs, not the objects themselves 3157db96d56Sopenharmony_ci stack, i = self.call("get_stack", frame._fid, tbid) 3167db96d56Sopenharmony_ci stack = [(FrameProxy(self.conn, fid), k) for fid, k in stack] 3177db96d56Sopenharmony_ci return stack, i 3187db96d56Sopenharmony_ci 3197db96d56Sopenharmony_ci def set_continue(self): 3207db96d56Sopenharmony_ci self.call("set_continue") 3217db96d56Sopenharmony_ci 3227db96d56Sopenharmony_ci def set_step(self): 3237db96d56Sopenharmony_ci self.call("set_step") 3247db96d56Sopenharmony_ci 3257db96d56Sopenharmony_ci def set_next(self, frame): 3267db96d56Sopenharmony_ci self.call("set_next", frame._fid) 3277db96d56Sopenharmony_ci 3287db96d56Sopenharmony_ci def set_return(self, frame): 3297db96d56Sopenharmony_ci self.call("set_return", frame._fid) 3307db96d56Sopenharmony_ci 3317db96d56Sopenharmony_ci def set_quit(self): 3327db96d56Sopenharmony_ci self.call("set_quit") 3337db96d56Sopenharmony_ci 3347db96d56Sopenharmony_ci def set_break(self, filename, lineno): 3357db96d56Sopenharmony_ci msg = self.call("set_break", filename, lineno) 3367db96d56Sopenharmony_ci return msg 3377db96d56Sopenharmony_ci 3387db96d56Sopenharmony_ci def clear_break(self, filename, lineno): 3397db96d56Sopenharmony_ci msg = self.call("clear_break", filename, lineno) 3407db96d56Sopenharmony_ci return msg 3417db96d56Sopenharmony_ci 3427db96d56Sopenharmony_ci def clear_all_file_breaks(self, filename): 3437db96d56Sopenharmony_ci msg = self.call("clear_all_file_breaks", filename) 3447db96d56Sopenharmony_ci return msg 3457db96d56Sopenharmony_ci 3467db96d56Sopenharmony_cidef start_remote_debugger(rpcclt, pyshell): 3477db96d56Sopenharmony_ci """Start the subprocess debugger, initialize the debugger GUI and RPC link 3487db96d56Sopenharmony_ci 3497db96d56Sopenharmony_ci Request the RPCServer start the Python subprocess debugger and link. Set 3507db96d56Sopenharmony_ci up the Idle side of the split debugger by instantiating the IdbProxy, 3517db96d56Sopenharmony_ci debugger GUI, and debugger GUIAdapter objects and linking them together. 3527db96d56Sopenharmony_ci 3537db96d56Sopenharmony_ci Register the GUIAdapter with the RPCClient to handle debugger GUI 3547db96d56Sopenharmony_ci interaction requests coming from the subprocess debugger via the GUIProxy. 3557db96d56Sopenharmony_ci 3567db96d56Sopenharmony_ci The IdbAdapter will pass execution and environment requests coming from the 3577db96d56Sopenharmony_ci Idle debugger GUI to the subprocess debugger via the IdbProxy. 3587db96d56Sopenharmony_ci 3597db96d56Sopenharmony_ci """ 3607db96d56Sopenharmony_ci global idb_adap_oid 3617db96d56Sopenharmony_ci 3627db96d56Sopenharmony_ci idb_adap_oid = rpcclt.remotecall("exec", "start_the_debugger",\ 3637db96d56Sopenharmony_ci (gui_adap_oid,), {}) 3647db96d56Sopenharmony_ci idb_proxy = IdbProxy(rpcclt, pyshell, idb_adap_oid) 3657db96d56Sopenharmony_ci gui = debugger.Debugger(pyshell, idb_proxy) 3667db96d56Sopenharmony_ci gui_adap = GUIAdapter(rpcclt, gui) 3677db96d56Sopenharmony_ci rpcclt.register(gui_adap_oid, gui_adap) 3687db96d56Sopenharmony_ci return gui 3697db96d56Sopenharmony_ci 3707db96d56Sopenharmony_cidef close_remote_debugger(rpcclt): 3717db96d56Sopenharmony_ci """Shut down subprocess debugger and Idle side of debugger RPC link 3727db96d56Sopenharmony_ci 3737db96d56Sopenharmony_ci Request that the RPCServer shut down the subprocess debugger and link. 3747db96d56Sopenharmony_ci Unregister the GUIAdapter, which will cause a GC on the Idle process 3757db96d56Sopenharmony_ci debugger and RPC link objects. (The second reference to the debugger GUI 3767db96d56Sopenharmony_ci is deleted in pyshell.close_remote_debugger().) 3777db96d56Sopenharmony_ci 3787db96d56Sopenharmony_ci """ 3797db96d56Sopenharmony_ci close_subprocess_debugger(rpcclt) 3807db96d56Sopenharmony_ci rpcclt.unregister(gui_adap_oid) 3817db96d56Sopenharmony_ci 3827db96d56Sopenharmony_cidef close_subprocess_debugger(rpcclt): 3837db96d56Sopenharmony_ci rpcclt.remotecall("exec", "stop_the_debugger", (idb_adap_oid,), {}) 3847db96d56Sopenharmony_ci 3857db96d56Sopenharmony_cidef restart_subprocess_debugger(rpcclt): 3867db96d56Sopenharmony_ci idb_adap_oid_ret = rpcclt.remotecall("exec", "start_the_debugger",\ 3877db96d56Sopenharmony_ci (gui_adap_oid,), {}) 3887db96d56Sopenharmony_ci assert idb_adap_oid_ret == idb_adap_oid, 'Idb restarted with different oid' 3897db96d56Sopenharmony_ci 3907db96d56Sopenharmony_ci 3917db96d56Sopenharmony_ciif __name__ == "__main__": 3927db96d56Sopenharmony_ci from unittest import main 3937db96d56Sopenharmony_ci main('idlelib.idle_test.test_debugger_r', verbosity=2, exit=False) 394