Source code for remote_pdb

from __future__ import print_function

import errno
import logging
import os
import re
import socket
import sys
from pdb import Pdb

__version__ = '2.1.0'

PY3 = sys.version_info[0] == 3
log = logging.getLogger(__name__)


def cry(message, stderr=sys.__stderr__):
    log.critical(message)
    print(message, file=stderr)
    stderr.flush()


class LF2CRLF_FileWrapper(object):
    def __init__(self, connection):
        self.connection = connection
        self.stream = fh = connection.makefile('rw')
        self.read = fh.read
        self.readline = fh.readline
        self.readlines = fh.readlines
        self.close = fh.close
        self.flush = fh.flush
        self.fileno = fh.fileno
        if hasattr(fh, 'encoding'):
            self._send = lambda data: connection.sendall(data.encode(fh.encoding))
        else:
            self._send = connection.sendall

    @property
    def encoding(self):
        return self.stream.encoding

    def __iter__(self):
        return self.stream.__iter__()

    def write(self, data, nl_rex=re.compile("\r?\n")):
        data = nl_rex.sub("\r\n", data)
        self._send(data)

    def writelines(self, lines, nl_rex=re.compile("\r?\n")):
        for line in lines:
            self.write(line, nl_rex)


[docs]class RemotePdb(Pdb): """ This will run pdb as a ephemeral telnet service. Once you connect no one else can connect. On construction this object will block execution till a client has connected. Based on https://github.com/tamentis/rpdb I think ... To use this:: RemotePdb(host='0.0.0.0', port=4444).set_trace() Then run: telnet 127.0.0.1 4444 """ active_instance = None def __init__(self, host, port, patch_stdstreams=False, quiet=False): self._quiet = quiet listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) listen_socket.bind((host, port)) if not self._quiet: cry("RemotePdb session open at %s:%s, waiting for connection ..." % listen_socket.getsockname()) listen_socket.listen(1) connection, address = listen_socket.accept() if not self._quiet: cry("RemotePdb accepted connection from %s." % repr(address)) self.handle = LF2CRLF_FileWrapper(connection) Pdb.__init__(self, completekey='tab', stdin=self.handle, stdout=self.handle) self.backup = [] if patch_stdstreams: for name in ( 'stderr', 'stdout', '__stderr__', '__stdout__', 'stdin', '__stdin__', ): self.backup.append((name, getattr(sys, name))) setattr(sys, name, self.handle) RemotePdb.active_instance = self def __restore(self): if self.backup and not self._quiet: cry('Restoring streams: %s ...' % self.backup) for name, fh in self.backup: setattr(sys, name, fh) self.handle.close() RemotePdb.active_instance = None
[docs] def do_quit(self, arg): self.__restore() return Pdb.do_quit(self, arg)
do_q = do_exit = do_quit
[docs] def set_trace(self, frame=None): if frame is None: frame = sys._getframe().f_back try: Pdb.set_trace(self, frame) except IOError as exc: if exc.errno != errno.ECONNRESET: raise
[docs]def set_trace(host=None, port=None, patch_stdstreams=False, quiet=None): """ Opens a remote PDB on first available port. """ if host is None: host = os.environ.get('REMOTE_PDB_HOST', '127.0.0.1') if port is None: port = int(os.environ.get('REMOTE_PDB_PORT', '0')) if quiet is None: quiet = bool(os.environ.get('REMOTE_PDB_QUIET', '')) rdb = RemotePdb(host=host, port=port, patch_stdstreams=patch_stdstreams, quiet=quiet) rdb.set_trace(frame=sys._getframe().f_back)