import socket
from gevent import monkey; monkey.patch_all()
import sys
import random
from code import InteractiveConsole


class RemoteConsole(InteractiveConsole):
    def __init__(self, handle, locals=None):
        self.handle = handle
        sys.stderr = self.handle
        InteractiveConsole.__init__(self, locals=locals)

    def write(self, data):
        self.handle.write(data)

    def runcode(self, code):
        # preserve stdout/stderr
        oldstdout = sys.stdout
        oldstderr = sys.stderr
        sys.stdout = self.handle
        sys.stderr = self.handle

        InteractiveConsole.runcode(self, code)

        sys.stdout = oldstdout
        sys.stderr = oldstderr

    def raw_input(self, prompt=""):
        self.handle.write(prompt)
        self.handle.flush()
        return self.handle.readline()


def break_to_interpreter(address="localhost", portmin=4000, portmax=5000):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    port = random.randint(portmin, portmax)
    sock.bind((address, port))
    sock.listen(1)
    print "Interpreter waiting on %s port %d..." % (address, port)
    (clientsocket, address) = sock.accept()
    handle = clientsocket.makefile('rw')
    handle.write('Embedded interpreter')
    console = RemoteConsole(handle, locals())
    console.interact()


# example usage - connect with 'netcat localhost 4444'
if __name__ == '__main__':
    break_to_interpreter()

Break into a python interpreter from anywhere
Break into a python interpreter from anywhere

Summary:
I use pdb a lot when debugging and I find it really annoying that we only get stack traces from errors on gunks. Wouldn't it be cool to be able to at least have access to an interpreter at the bottom of a stack trace? Well, rdb does this. To use it, insert a call to "rdb.break_to_interpreter" and the greenlet will block while waiting for a telnet (or netcat if you can) connection on localhost (and without blocking the whole process).

Currently the debugger is very basic - it's still possible to examine the stackframe using sys._getframe, though. I'm looking for a way to make the frame data available in locals() and to have greenlets break into the debugger whenever they get an uncaught exception.

Test Plan: Ran a sync

Reviewers: charles, spang, emfree

Reviewed By: emfree

Projects: #inbox-sync

Differential Revision: https://review.inboxapp.com/D321
