Debugger#

Note

This page serves as a starting point to design and implement a debugger for WebTJ 3.

Ressources#

Using the bdb module#

import bdb
import inspect
import os
 
class Mydb(bdb.Bdb):
    def head(self, frame):
        return f'{os.path.basename(frame.f_code.co_filename)}: {frame.f_lineno} :'
 
    def hprint(self, frame, *args, **kwargs):
        print(self.head(frame), *args, **kwargs)
 
    def user_call(self, frame, arg):
        # arg is None (see the doc of sys.settrace)
        L, n = inspect.getsourcelines(frame)
        print(L, n)
        self.hprint(frame, f'-> {L[frame.f_lineno - n].rstrip()} {frame.f_locals}')
        input("next")
 
    def user_line(self, frame):
        L, n = inspect.getsourcelines(frame)
        self.hprint(frame, L[frame.f_lineno - n], end='')
        input("next")
 
    def user_return(self, frame, value):
        L, n = inspect.getsourcelines(frame)
        self.hprint(frame, f'<- {frame.f_code.co_name}: {value}')
 
def eggs(x):
    return x + x
 
def spam(a, b):
    return f'{eggs(b)} {eggs(a)}'
 
def main():
    x = 2 + 2
    spam(7, 'ham')
    return x
 
if __name__ == '__main__':
    mydb = Mydb()
    mydb.runcall(main)

It also works with sleep#

import bdb
import inspect
import os

from time import sleep

wait_time = 1

class Mydb(bdb.Bdb):
    def head(self, frame):
        return f'{os.path.basename(frame.f_code.co_filename)}: {frame.f_lineno} :'
 
    def hprint(self, frame, *args, **kwargs):
        print(self.head(frame), *args, **kwargs)
 
    def user_call(self, frame, arg):
        # arg is None (see the doc of sys.settrace)
        L, n = inspect.getsourcelines(frame)
        print(L, n)
        self.hprint(frame, f'-> {L[frame.f_lineno - n].rstrip()} {frame.f_locals}')
        sleep(wait_time)
 
    def user_line(self, frame):
        L, n = inspect.getsourcelines(frame)
        self.hprint(frame, L[frame.f_lineno - n], end='')
        sleep(wait_time)
 
    def user_return(self, frame, value):
        L, n = inspect.getsourcelines(frame)
        self.hprint(frame, f'<- {frame.f_code.co_name}: {value}')
        sleep(wait_time)
 
def eggs(x):
    return x + x
 
def spam(a, b):
    return f'{eggs(b)} {eggs(a)}'
 
def main():
    x = 2 + 2
    spam(7, 'ham')
    return x
 
if __name__ == '__main__':
    mydb = Mydb()
    mydb.runcall(main)

Ideas for the visualization#