Example #1
0
class PdbDebug(object):

    RE_BREAKPOINT = re.compile(b'\(Pdb\)\sBreakpoint\s(\d{1,})\sat\s(.*?$)')
    RE_WHERE = re.compile(b'[\s|>]\s(.*?)\((\d{1,})\)<module')
    STEP_CMD = (b'c\n', b'n\n', b's\n')

    def __init__(self, file):
        self._breakpoints = []
        self._pipe = Pipe(['python3', '-m', 'pdb', file])
        # clean when process startup
        self._pipe.output()

    def _check_point(self, bp):
        if bp in self._breakpoints:
            idx = self._breakpoints.index(bp)
            self._pipe.execute(b'clear %d\n' % (idx + 1))
            self._breakpoints.pop(idx)
            return -idx

        stdout, _ = self._pipe.execute(b'b %s:%d\n' % bp)
        if stdout[0] != b'(Pdb) *** Blank or comment':
            r = self.RE_BREAKPOINT.search(stdout[0])
            if r is not None:
                self._breakpoints.append(bp)
                return bp[1]
        return 0

    def breakpoint(self, file, line):
        bp = (normcase(normpath(file)).encode('utf-8'), line)
        line = self._check_point(bp)
        return bp if line > 0 else (file, line)

    def _trackback(self, stdout, stderr):
        file, line = self._parse_where(stdout[-2])
        return (file, line, stderr[-1])

    def _parse_where(self, line):
        r = self.RE_WHERE.search(line)
        return (r.group(1), r.group(2)) if r else None

    def _where(self, stdout):
        flag, line = stdout[0], stdout[0]
        if len(stdout) >= 3:
            line = stdout[-2]

        postion = self._parse_where(line)
        if postion is None:
            stdout, _ = self._pipe.execute(b'w\n')
            # TODO: list index out of range
            postion = self._parse_where(stdout[3])

        return postion if postion else ('', -2)

    def step(self, cmd):
        '''
        param cmd 0: continue
                  1: next
                  2: step
        '''
        stdout, stderr = self._pipe.execute(self.STEP_CMD[cmd])
        if not stderr:
            return self._where(stdout)
        return self._trackback(stdout, stderr)

    def _pprint(self, var):
        stdout, _ = self._pipe.execute(b'pp %s\n' % var)
        return stdout[0].split(b'(Pdb) ')[1]

    def pprint(self, var):
        var = var.encode('utf-8')
        l = self._pprint(b"hasattr(%s, '__dict__')" % var)
        # NameError or SyntaxError
        if not l.startswith(b'*** '):
            data = self._pprint(var + b'.__dict__' if l == b'True' else var)
            type_ = self._pprint(b"type(%s)" % var)
            return b'%s %s = %s ' % (type_, var, data)
        return ''