Screen shot of the
python name_you_gave_it.py. Make sure you got a copy of the python.org interpreter.
Recent changes, printing correct info on break.
import tkinter,sys,inspect,filedialog
version = "1.485"
def TabCount(s) :
i =0
max = len(s)
while (s[i:i+1].isspace()) & (i < max ): i=i+1
return i
#TabCount = lambda d,s : s.count(d, 0,len(s))
#define a snippet under test
class Snippet :
def __init__(self):
self.root = None
self.flag = -2
self.maxline = 1
self.prevlineno = 1
self.lineno = 1
self.source_name = "none"
self.init_name = 'none'
self.source_text = "pass"
self.break_text = "pass"
self.status_text = "idle"
self.usertext = "none"
self.frame = None
self.packagename = "none" # Import this user defined module on request
self.globals = None
self.strvar = None
self.source_line = 'pass'
self.breaks = []
self.lines = []
self.start = 1
self.end = 1
self.trace_option = 3
self.sourcesize = 1
def list(self) : print(self.lineno,self.maxline,self.source_name,self.source_text,self.sourcesize)
# find the char index pointing to given line
def markline(self,index) :
i = index
for i in range( index,self.sourcesize-1) :
if self.source_text[i] == '\n' : break
i = i+1
return i
def setmsg(self,text) :
self.status_text=text
self.strvar.set(self.status_text)
self.root.update_idletasks()
self.root.update()
def run(self,f) :
self.flag= 1
try :
exec(self.source_text,self.globals)
except(IOError,EOFError,LookupError,RuntimeError, TypeError, NameError,UnboundLocalError) as e:
self.setmsg("Source error: %s :%3d: %s" % (e, TestCode.lineno,TestCode.source_line ))
#### Helpers
SIndex = lambda j : ("%d.0")%(j)
DPtr = lambda str,chr : str.find(chr,0,len(str))
Atom = lambda x,y : x[0:DPtr(x,y)-1]
iLine = lambda index : int(index[0:DPtr(index,'.')])
iChar = lambda index : int(index[DPtr(index,'.')-1:3])
######## Call backs from interpreter
from inspect import getframeinfo, stack
def WaitLoop(event,frame):
global TestCode
global DisplayUpdate
if(TestCode.flag == 3) :
exec(TestCode.breakexpression) # this should set the flag for futher processing)
if(TestCode.flag != 1) : return
if TestCode.flag == 2 and TestCode.breaks.count(frame.f_lineno) == 0 : return
# we are stepping
TestCode.frame = frame
TestCode.lineno = frame.f_lineno
#print(inspect.getsource(frame))
if TestCode.flag == 0 :
print("Recurse error ")
return
if frame.f_code.co_filename == '<string>' :
TestCode.flag = 0
TestCode.source_line= TestCode.source_text[TestCode.lines[frame.f_lineno-1]:TestCode.lines[frame.f_lineno]]
TestCode.setmsg("Trace: %4s :%3d: %s" % (event, TestCode.lineno,TestCode.source_line ))
if TestCode.lineno != TestCode.prevlineno : DisplayUpdate()
while True :
if TestCode.flag != 0 :
#print("Exit loop")
break
TestCode.root.update_idletasks()
TestCode.root.update()
def getfile() :
global TestCode
TestCode.status_text = "File Opened "
r = tkinter.Tk()
r.withdraw()
fd = filedialog.LoadFileDialog(r)
fileobj = fd.go(key="test")
return(fileobj)
def inittest() :
global TestCode,source_text
filename = TestCode.source_name
fobj=open(filename,'r')
TestCode.source_text = fobj.read()
fobj.close()
TestCode.globals = dict()
TestCode.sourcesize = len(TestCode.source_text)
# Add line numbersgetfile
index = -1
count = 1
source_text.delete("0.0",'end')
while index < TestCode.sourcesize-1 :
prev = index
index = TestCode.markline(prev+1)
line = ("%3d %s\n") % (count,TestCode.source_text[prev+1:index])
source_text.insert('end', line)
TestCode.lines.append(prev)
count = count + 1
def proffun(frame,event,arg) :
global TestCode
if (TestCode.trace_option & 2) and (TestCode.flag > 0 ): WaitLoop(event,frame)
return(proffun)
def tracefun(frame,event,arg) :
global TestCode
if (TestCode.trace_option & 1) and (TestCode.flag > 0 ) > 0 : WaitLoop(event,frame)
return(tracefun)
#call backs for widgets.
############### Call backs ########
def QuitCallback() :
global TestCode
TestCode.flag =-2
sys.settrace(None)
sys.setprofile(None)
TestCode.setmsg("Exit")
exit()
# Use eval to grab a source svatiable value, return it in a string
def ScriptCallback() :
TestCode.source_name = getfile()
inittest()
def InitCallback() :
filename= getfile()
TestCode.init_name = filename
print(filename)
fobj=open(filename,'r')
TestCode.usertext = fobj.read()
fobj.close()
print(TestCode.usertext )
exec(TestCode.usertext)
def ExtractValFromPython(varname) :
global TestCode
try :
result = eval(varname,TestCode.globals)
except(LookupError,RuntimeError, TypeError, NameError,UnboundLocalError) as e:
result=e
return(result)
def DisplayUpdate() :
global WatchText
global source_text
global TestCode
p = TestCode.prevlineno
c = TestCode.lineno
TestCode.prevlineno = TestCode.lineno
source_text.tag_remove('halt', SIndex(p),SIndex(p+1))
source_text.tag_add('halt', SIndex(c),SIndex(c+1))
source_text.see(SIndex(c))
max = iLine(WatchText.index('end'))
i = max -2
while i > 0 : # zero based count and we also skip the last "\n" char
varName = WatchText.get(SIndex(i),SIndex(i+1))
varName.replace("\n"," ")
j = DPtr(varName," ")
if j < 0 : j = len(varName)
ReturnString = ExtractValFromPython(varName[0:j])
WatchString = ("%s %s\n") % (varName[0:j], ReturnString)
WatchText.replace(SIndex(i),SIndex(i+1),WatchString)
i = i - 1
# check userdefined break
if (TestCode.flag == 3) and (TestCode.breaktext != "none") :
TestCode.flag = eval(TestCode.breaktext)
def RestartMsg() :
global TestCode
TestCode.setmsg("End File, Restart: %3d" % (TestCode.lineno))
def StepCallback(event) :
global TestCode
if TestCode.flag < 0 : RestartMsg()
else : TestCode.flag = 1
# run the whole code
def UntilCallback(event) : # wait for break
global TestCode
if TestCode.flag < 0 : RestartMsg() # just restart
else : TestCode.flag = 2
def StartCallback(event) : # Start fresh
global TestCode
# Shut down the call back if waiting
TestCode.flag = -2
TestCode.root.update_idletasks()
TestCode.root.update()
TestCode.run(1) # just restart
def StopCallback(event) : # wait for break
global TestCode
TestCode.flag = -2
def AddWatchCallback(event) :
global WatchText,source_text
t = source_text.selection_get()
t.strip()
WatchText.insert('end', ("%s %s\n") % (t,"None" ) )
DisplayUpdate()
def DelWatchCallback(event) :
global WatchText
i = iLine(WatchText.index('insert'))
WatchText.delete(SIndex(i),SIndex(i+1))
def AddBreakCallback(event) :
global source_text
global TestCode
i = source_text.index('insert')
l = iLine(i)
if TestCode.breaks.count(l) == 0 :
TestCode.breaks.append(l)
source_text.tag_add('break', SIndex(l),SIndex(l+1))
def DelBreakCallback(event) :
global source_text
i = source_text.index('insert')
l = iLine(i)
if TestCode.breaks.count(l) > 0 :
TestCode.breaks.remove(l)
source_text.tag_remove('break', SIndex(l),SIndex(l+1))
def popupmsg(msg):
popup = tkinter.Tk()
popup.wm_title("!")
label = tkinter.Label(popup, text=msg,justify='left')
label.pack(side="top", fill="x", pady=10)
B1 = tkinter.Button(popup, text="Okay", command = popup.destroy)
B1.pack()
popup.mainloop()
# constructors for the GUI
def NextButton(w,name,callback) :
b = tkinter.Button(w,text=name)
b.pack(side='left')
b.bind("<Button-1>", callback)
def AddMenu(root) :
menubar = tkinter.Menu(root)
menubar.add_command(label="Files", command=ScriptCallback)
menubar.add_command(label="Init", command=InitCallback)
menubar.add_command(label="Help", command=HelpCallback)
menubar.add_command(label="Quit", command=QuitCallback)
root.config(menu=menubar)
#menubar.pack(side='left')
def controls(r) :
global TestCode
NextButton(r,"Start",StartCallback)
NextButton(r,"Halt",StopCallback)
NextButton(r,"Until",UntilCallback)
NextButton(r,"Step",StepCallback)
NextButton(r,"Br Del",DelBreakCallback)
NextButton(r,"Br Add",AddBreakCallback)
NextButton(r,"Watch",AddWatchCallback)
NextButton(r,"Drop",DelWatchCallback)
b = tkinter.Label(r,textvariable=TestCode.strvar)
b.pack(side='left')
#Inline help text makes the debugger self contained
helptext = \
"\nThe online help for pbug, " + version + " a lightweight python debugger\
\n Contact:youngsanger at gmail dot com. \n\nThis app is a light weight debugger written in python and using \
\nthe python.org interpreter The mini debuger is an entirely self contained debugger, requires these modules:\
\ntkinter, sys and inspect. And has its own inline help. A single file but aloows user specified\ initialization and analysis source\n\
\n Written 350 lines of code including self contained help,it is designed for easy maintainence and modification.\
\n This is a fully functional. Start the debugger from icon or command line with\n\
\n..\..\python pbug.py ## this starts pdbug in the tkinter folder.\n\
\nThese are the buttons:\n " + "\
\nFile - Loads a file and keeps the original copy in a string. The text box is loaded with a copy having \
\nthe line number inserted. All parts of the class Snippet are set up to manage the file under test.\
\nStart - Loads the source string into exec with the run flags set to step.\
\nUntil and Step - Until runs free until a break point, Step goes one step\
\n Note: Two trace functions are both working and we twice per line. \
\nWatch and Drop - Adds and deletes watch variable. Select variable on source window for add and put cursor\
\n on watch line for delete. \
\n"
def HelpCallback() :
global helptext
popupmsg(helptext)
# set up the frame and paned windows
global source_text
global WatchText
TestCode = Snippet()
TestCode.list()
TestCode.breaks.append(1)
# Tracers are set to shut
# but the call back is permanent
TestCode.flag = -2 # Traces shut
sys.settrace(tracefun)
sys.setprofile(proffun)
TestCode.root = tkinter.Tk()
TestCode.root.wm_title("Mini debugger for pythn Release " + version)
AddMenu(TestCode.root)
TestCode.strvar = tkinter.StringVar()
TestCode.strvar.set('Initializing')
m1 = tkinter.PanedWindow(TestCode.root,orient = 'vertical',width=1000)
m1.pack( fill = 'both',expand=1)
separator = tkinter.Frame(m1,height=2, bd=1, relief='sunken')
controls(separator)
m1.add(separator)
m2 = tkinter.PanedWindow( TestCode.root,orient='horizontal')
m1.add(m2)
source_text = tkinter.Text(TestCode.root) #left pane")
source_text.pack( padx=5, pady=5)
Scroller = tkinter.Scrollbar(source_text)
source_text.config(yscrollcommand=Scroller.set)
m2.add(source_text)
WatchText = tkinter.Text(TestCode.root)
WatchText.pack( padx=5, pady=5)
Scroller.pack(side='right',fill='y')
Scroller.config(command=source_text.yview) #ScrollCallback)
m2.add(WatchText)
source_text.tag_config('halt', background='red')
source_text.tag_config('break', background='blue')
print("5: watch",WatchText.index('end'),WatchText.index('insert'),WatchText.index('current'))
TestCode.root.mainloop()
No comments:
Post a Comment