Ben Bass avatar Ben Bass committed cfc9ec8

add debug_interactive_console function

Comments (0)

Files changed (4)

 -----
 rpcpdb is a wrapper around the Python pdb debugger which
 makes it more suitable for use in RPC contexts.
+It also provides a similar interface to a code.InteractiveConsole
+instance within the context of the target RPC process.
 
 It is designed to fulfil the need to debug a function on
 an already-running server which uses threads or processes
 
  * Update examples, tidy up, document.
  * Support other interfaces than termsock / UNIX socket.
+ * Support json-rpc
 
 Done
 ----
 
 Changes
 -------
+0.3.2
+ * add debug_interactive_console mixin function to gain an interactive
+   console into the target RPC API
 0.3.1
  * add .hgignore file
  * add updb creation without specifying a socket name. One will be

rpcpdb/__init__.py

-__VERSION__ = "0.3.1"
+__VERSION__ = "0.3.2"
 
 # pull a few useful things into our namespace
 from rpcpdb.updb import UPdb, UPdb_mixin
 import sys
 import os
 import tempfile
+import threading
+import code
 
 
 class UPdb(pdb.Pdb):
         os.rmdir(os.path.dirname(self._sock_path))
 
 
+class DebugConsole(code.InteractiveConsole):
+
+    def __init__(self, socket_addr, *o, **k):
+        code.InteractiveConsole.__init__(self, *o, **k)
+        self.__sock_path = socket_addr
+        self.__sock = socket.socket(socket.AF_UNIX,
+                                    socket.SOCK_STREAM)
+        self.__sock.bind(self.__sock_path)
+        self.__sock.listen(1)
+        self.__conn = self.__sock.accept()[0]
+        self._debug_handle = self.__conn.makefile('rw')
+        #sys.stdout = self._debug_handle
+        #sys.stderr = self._debug_handle
+        #sys.stdin = self._debug_handle
+        sys.displayhook = self._displayhook
+
+    def _displayhook(self, obj):
+        if obj is None:
+            return
+        #__builtins__._ = None
+        self.write(repr(obj) + '\n')
+        #__builtins__._ = obj
+
+    def write(self, data):
+        if data:
+            self._debug_handle.write(data)
+            self._debug_handle.flush()
+
+    def raw_input(self, prompt=''):
+        self.write(prompt)
+        return self._debug_handle.readline()
+
+
 class UPdb_mixin(object):
     """
     This is designed to be mixed-in to an RPC server
         """
         if f in self._updb_debug_func:
             setattr(self, f, self._updb_debug_func.pop(f)[0])
+
+    def debug_interactive_console(self):
+        """
+        start an interactive console in a new thread
+        return socket address to connect to it.
+        """
+        con_sock_path = "%s/con_sock" % tempfile.mkdtemp(prefix='updb_')
+        context = globals()
+        context['_debug_api'] = self
+
+        def run_console():
+            context['_debug_console'] = DebugConsole(con_sock_path, context)
+            try:
+                context['_debug_console'].interact()
+            finally:
+                os.remove(con_sock_path)
+                os.rmdir(os.path.dirname(con_sock_path))
+
+        t = threading.Thread(target=run_console)
+        t.daemon = True
+        t.start()
+        return con_sock_path
 
 setup(
     name="rpcpdb",
-    version="0.3.1",
+    version="0.3.2",
     description="Debug support for RPC servers",
     long_description=open('README.txt').read(),
     author="Ben Bass",
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.