本日のマトメは
以下です。
ソースとは、関係がないけど。。。
・気になる、PDBコマンド送出後の対応(待ちますか?)
・setFuncは大丈夫かな? 同期が必要かな
・
・
#!/usr/bin/python -u
# -*- coding: utf-8 -*-
import io
import sys,os
import time
import subprocess
import threading
import signal
import editPane
import textCmd
import textSrc
import gridEx
import wx
import wx.lib.newevent
ERR_FILE ="errTrace.log"
'''---------------------------------------------------
global function
------------------------------------------------------'''
def getErrInfo( s ):
'''エラー情報を取り出す'''
data =[]
errData = s = s.split("\n")
no =0 #対応する行
i = 0
startSw=False
for line in s:
i +=1
print "line",i,line
if s == "Traceback (most recent call last):": startSw= True
if " File " not in line:
continue
#print "line2",line
if "pdb.py" in line and "main" in line :
continue
if "pdb.py" in line and "_runscript" in line :
continue
if "bdb.py" in line and "run" in line :
continue
if "<string>" in line and "<module>" in line :
continue
print "gaitou",line
data.append( line + "\n" )
no =i
l = len( data )-1
sss = data[ l ].strip()
sss = sss.split(", ")
file = sss[0][5:].strip('"')
line = sss[1][5:]
return file,line, no, errData
def getKakData( kigo1,kigo2, lineData):
'''括弧で包まれた内容を取得する'''
start= lineData.index( kigo1 ) +1
end = lineData.index( kigo2 )
ct = end -start
data= lineData[start:start+ct]
return data
def hanteiSTD( lineData ):
'''標準入力が必要かを判定する'''
cmd = ""
stdSW =True
fnm =""
mnm =False
lineNO = 0
if lineData == "(Pdb) ":
stdSW= False
elif lineData[:3] == "-> ":
stdSW= False
elif lineData[:2] == "> ":
stdSW= False
start= lineData.index('(') +1
lineNO= getKakData('(',')', lineData )
lineNO= int( lineNO )
fnm = lineData[2:start-1]
mnm= "<module>" in lineData
elif lineData == "--Return--" or lineData == "--Call--":
stdSW= False
return stdSW, fnm, lineNO, mnm
hanteiSTD.cmd = ""
class dbgSub(threading.Thread):
def __init__(self, outS, func, fm ):
threading.Thread.__init__(self)
self.outS = outS
self.func = func
self.fm = fm
# キューイベント、スレッド処理
self.queEvent, self.QUE_EVENT = wx.lib.newevent.NewEvent()
self.QUE_EVENT( self.fm, func)
self.fm.Bind( self.QUE_EVENT, func)
def run(self):
print ' === start sub thread ==='
dest = bytearray(9000) # all zero bytes
v = memoryview(dest)
while True:
#output= self.outS.read(1)
nn = self.outS.readinto( v )
#print "*",nn,dest
if nn==0: break
#print(repr(dest))
#continue
#self.func( output )
#print "run Data nasi desu"
output = str( dest)
output = output[0:nn]
evt = self.queEvent( data=output )
wx.PostEvent(self.fm, evt)
"""
sys.stdout.write( output )
sys.stdout.flush()
"""
print ' === end sub thread ==='
class dbg( threading.Thread ):
def __init__(self, aPara, func, func2,fm ):
threading.Thread.__init__(self)
self.arg = ["python","-u","-m","pdb"]
self.arg.extend( aPara )
self.func = func
self.func2= func2
self.fm = fm
dbg.prgSrc = False
dbg.cmdList=['r','n','s'] #デバッカーコマンド 制御(行移動)あり
dbg.cmdSave="" #エンターのみの場合は、以前のコマンドw実行
def run(self):
self.stopFlag = False
self.proc = subprocess.Popen(
self.arg,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
bufsize=0)
self.outS = io.open( self.proc.stdout.fileno(), mode="rb",
closefd=False,buffering=0)
self.outE = io.open( self.proc.stderr.fileno(), mode="rb",
closefd=False,buffering=0)
self.th = dbgSub( self.outS, self.func, self.fm )
self.thErr = dbgSub( self.outE, self.func2, self.fm )
self.thErr.setDaemon(True)
self.th.setDaemon(True)
self.thErr.start()
self.th.start()
time.sleep(1)
print ' === start thread ==='
while self.stopFlag == False:
time.sleep(1)
print ' === end thread ==='
sys.exit(0)
def stop(self):
self.stopFlag = True
"""スレッドを停止させる"""
"""
self.stop_event.set()
self.thread.join() #スレッドが停止するのを待つ
"""
def cmd( self, cmd, prgSrc=False ):
dbg.prgSrc = prgSrc
# CURSOR --wait
wx.SetCursor ( wx.StockCursor ( wx.CURSOR_WAIT ) )
self.fm.timer.Start( 1000 )
#エンターのみの場合は、以前のコマンドだよ
if cmd =="":
cmd = dbg.cmdSave
elif cmd in dbg.cmdList:
dbg.cmdSave = cmd
#変数代入の場合
if cmd[:2]=="fo" or cmd[:2]=="__":
hanteiSTD.cmd = cmd
elif "=" in cmd:
hanteiSTD.cmd = "="
else:
hanteiSTD.cmd = cmd
#print "hanteiSTD.cmd=",hanteiSTD.cmd
self.proc.stdin.write( cmd + "\n" )
def end( self ):
self.stop()
'''
---------------------------------------------------
debug-core main
---------------------------------------------------
'''
class DbgC():
""" debug core class """
inst =None
def __init__(self):
DbgC.inst = self # instance save
self.rcvData=""
self.frame = None
self.timer = None
self.editPane= None
self.panel = PanelEx.inst
self.txt = textCmd.TextCmd.inst
self.pSrc = textSrc.TextSrc.inst
self.pdb = None
self.app = None
self.dbgVal1 ="__x=locals();; del __x['__builtins__']"
self.dbgVal2 ="for __key in __x.iterkeys(): print __key "
self.dbgVal3 ="__keylist="
self.dbgVal4 ="for __key in __keylist: print '%s,%s,%s' %( __key, type(__x[ __key ] ), __x[ __key ] ) "
self.bpTbl ={}
def setAppInst( self, inst ):
self.app = inst
def setEditPaneInst( self, inst ):
self.editPane= inst
self.editPane.setFunc( self.cmdSrcFunction )
def cmdSrcFunction( self, inst ):
self.pSrc = self.editPane.fileInst
self.pSrc.setFunc( self.cmdFunc )
def setFrameInst( self, fm ):
self.frame = fm.inst
self.timer = fm.timer
def toolBarEnable( self, st,n, flg):
for i in range( n ):
self.frame.toolbar.EnableTool( st+i, flg)
def dbgStart( self ):
''' debug start functione '''
self.frame.SetStatusText( "debug start" )
# setting breakPoint table
self.bpTbl.clear()
# プログラムソース画面のインスタンス
self.pSrc = self.editPane.fileInst
args =[ self.editPane.fileName ]
#ここでは、ツールバー以外からよびだされた場合、イメージをONする
if self.frame.toolbar.GetToolState( 900 )== False:
self.frame.toolbar.ToggleTool(900, True)
self.rcvData ="" #エラー時に、大丈夫かな
#os.remove( ERR_FILE )
f = open( ERR_FILE, 'w')
f.write( "" )
f.close()
#self.pSrc.setDbgMode(True)
for fnInst in self.editPane.instList:
fnInst.setDbgMode(True)
self.pdb = dbg( args, self.rcv, self.rcvErr, self.frame )
self.pdb.setDaemon(True)
self.pdb.start()
self.pSrc.SetFocus()
print "start pdb"
#self.panel.SetBackgroundColour("green")
self.txt.start()
self.toolBarEnable(800,3,False) #ツールバーの無効
self.toolBarEnable(901,6,True)
def dbgEnd( self ):
''' debug end '''
#ここでは、ツールバー以外からよびだされた場合、イメージをオフする
if self.frame.toolbar.GetToolState( 900 ):
self.frame.toolbar.ToggleTool(900, False)
else:
self.pdb.cmd( "q" )
self.pdb.stop()
for fnInst in self.editPane.instList:
fnInst.setDbgMode(False)
#マウスポインターを通常にする
wx.SetCursor ( wx.StockCursor ( wx.CURSOR_ARROW ) )
self.timer.Stop()
print "stop pdb"
self.rcvData ="" #エラー時に、大丈夫かな
#self.panel.SetBackgroundColour("#AFAFAF")
self.txt.end()
self.toolBarEnable(800,3,True) #ツールバーの無効
self.toolBarEnable(901,6,False)
def rcvErr( self, event ):
''' pdbからの出力(エラー出力)'''
data = event.data
#マウスポインターを通常にする
wx.SetCursor ( wx.StockCursor ( wx.CURSOR_ARROW ) )
self.timer.Stop()
f = open( ERR_FILE, 'a')
f.write( data )
f.close()
def cmdInput( self, cmd ):
'''self.pdbへのコマンド送出'''
prgSrc = dbg.prgSrc #コマンドはソースウインドウから入力されて、フォーカス移動あり
print "commdin", cmd, "command-out"
self.pdb.cmd( cmd )
if cmd =="q":
self.dbgEnd()
return
#元のフォーカスへもどしますよん
if prgSrc:
#self.pSrc.SetFocus()
self.app.chgFocus(0)
def cmdFunc( self, ch, lineNo ):
''' デバッカーのソース画面からの、1文字コマンド '''
print "cmdFunc",ch
if ch =="R":
self.dbgStart() # debug start -----
return
if ch =="q":
self.pdb.cmd( ch )
self.dbgEnd()
return
# jump command
if ch=="j":
ch = "%s %d" %( ch,lineNo )
# GO command
if ch=="g":
ch = "tbreak %d;;c" %( lineNo )
#ブレークポイント
s ="%s:%d" %( self.editPane.fileName, lineNo )
if ch =="b":
if s in self.bpTbl:
ch="cl %s" % self.bpTbl[ s ]
del self.bpTbl[ s ]
else:
ch = "b %d" %( lineNo )
print "cmdFunc", ch,s
self.pdb.cmd( ch, prgSrc=True )
xyLast = self.txt.GetLastPosition()
self.txt.Remove( xyLast-6, xyLast)
'''
----------------------------------------
ローカル変数の対応
----------------------------------------
'''
def localVal( self ):
# ローカル変数の処理
# --- dbgVal1
if hanteiSTD.cmd[0:5] == self.dbgVal1[0:5]:
self.pdb.cmd( self.dbgVal2 )
self.rcvData =""
return True
# --- dbgVal2
if hanteiSTD.cmd[0:5]== self.dbgVal2[0:5]:
self.rcvData = self.rcvData.replace("\n(Pdb) ","" )
self.rcvData = self.rcvData.split("\n")
#print "1=====>\n",self.rcvData,len(self.rcvData)
keyList =[]
for s in self.rcvData :
#print "ですよ",s,type(s),"[",s[0:2],"]"
if s != "__return__":
if s[0:2] == "__" or s[0:17] == "*** RuntimeError:":
#print "該当しました",s
continue
keyList.append( "'%s'" %s )
if len( keyList )==0:
#print "該当キーはありませんよ",keyList
self.rcvData =""
return True
keys = self.dbgVal3 + "[%s]" %( ','.join( keyList ) )
#print 'keys', keys
self.pdb.cmd( keys )
self.rcvData =""
return True
# --- dbgVal3
if hanteiSTD.cmd[0:5]== self.dbgVal3[0:5]:
cmd = self.dbgVal4
#print 'dbgVal3.cmd', cmd
self.pdb.cmd( cmd )
self.rcvData =""
return True
# --- dbgVal4
if hanteiSTD.cmd[0:5]== self.dbgVal4[0:5]:
self.rcvData = self.rcvData.replace("\n(Pdb) ","" )
self.rcvData = self.rcvData.split("\n")
#print "444444=====>\n",self.rcvData,len(self.rcvData)
localVal={}
localVal.clear()
#いらないモジュールや関数は削除する
for s in self.rcvData:
if "<type 'function'>" in s or "<type 'module'>" in s:
continue
#print "for s==>",s
item = s.split(",")
#print "dbg-item", item
key = str( item[0] )
ty = str( item[1] )
del item[0]
del item[0]
s = ",".join( item )
val = str( s )
#localVal[ key ] = ty
localVal[ key ] = {"val":val, "type":ty }
#print "--------------------- start ----------"
#print localVal
g = gridEx.GridEx.inst
g.setCell(localVal)
#print "--------------------- end ----------"
self.rcvData =""
return True
return False
def errAndNml( self, s ):
# 正常終了
if s=="The program finished and will be restarted" \
or s == "> <string>(1)<module>()->None":
self.dbgEnd()
self.frame.SetStatusText( "正常終了" )
return True
#致命的なエラー
if s =='Uncaught exception. Entering post mortem debugging':
return False
if s=="Running 'cont' or 'step' will restart the program":
self.dbgEnd()
f = open( ERR_FILE, 'r')
data= f.read()
f.close()
#os.remove( ERR_FILE )
f = open( ERR_FILE, 'w')
f.write( "" )
f.close()
print "致命的なエラーです"
self.frame.SetStatusText( "致命的なエラーです" )
f,l,no,errData = getErrInfo( data )
self.pSrc.goLine( int(l) )
for i in range( len(errData) ):
col ="black"
sss= errData [i]
if sss[:1] != " ": col ="red"
if i==no: col ="red"
self.txt.ColorLine( sss+"\n", col )
print "lInfo",sss,col
self.rcvData =""
return True
return False
def rcv( self, event ):
'''self.pdbからの受信ですよ'''
data = event.data
self.rcvData += data
chkLen= len( self.rcvData )
print "*",self.rcvData[-6:-1],"*"
if self.rcvData[-6:-1] == "(Pdb)":
#マウスポインターを通常にする
wx.SetCursor ( wx.StockCursor ( wx.CURSOR_ARROW ) )
self.timer.Stop()
#ローカル変数の処理
st = self.localVal()
if st: return
#print "print",self.rcvData
self.rcvData = self.rcvData.split("\n")
for s in self.rcvData:
print "+", s
xyLast = self.txt.GetLastPosition()
self.txt.SetInsertionPoint(xyLast)
#正常、致命的なエラーの場合
st = self.errAndNml( s )
if st: return
if s== "(Pdb) ":
self.txt.AppendColorLine( s+ "" ) # コマンドプロンプトを表示するばあい
#self.txt.cmdPos = self.txt.GetInsertionPoint()
#変数表示コマンド(変数の代入)
if hanteiSTD.cmd == "=":
# 変数を表示の為に
self.pdb.cmd( self.dbgVal1 )
continue
elif s[:4] == "*** ":
self.frame.SetStatusText( "エラー:" +s )
continue
elif s[:3] == "-> ":
# デバッカーからの行内容は表示しない "-> "
continue
elif s[:2] == "> ":
self.txt.AppendColorLine( s+ "\n" )
#self.txt.cmdPos = self.txt.GetInsertionPoint()
else:
self.txt.AppendColorLine( s+ "\n" )
# breakpoint
#Breakpoint 2 at /home/koba/fx/pdb/1st.py:32
if hanteiSTD.cmd[:1] == "b":
item = s.split(" ")
if item[0] == "Breakpoint":
self.bpTbl[ item[3] ] = item[1]
print "break---", self.bpTbl
stdSW, fnm, lineNo, mnm = hanteiSTD( s )
print "hanteiSTD==>",stdSW, fnm, lineNo, mnm
if stdSW==False:
if fnm != "":
# デバックソースでカーソル移動して、変数取得の為にコマンドを送る
# ここでは、ファイル名がない場合は、notebookにファイルを追加する
if self.editPane.fileName != fnm:
#self.pSrc.setDbgMode(False) # 前のソースは、編集可能
self.pSrc = self.editPane.setFile( fnm )
print "************** file chnage ***********************"
self.pSrc.setDbgMode(True)
#self.pSrc.setFunc( self.cmdFunc )
#self.pSrc.SetFocus()
self.pSrc.goLine( lineNo )
# 変数を表示の為に
self.pdb.cmd( self.dbgVal1 )
self.rcvData =""
return
def onActive(event):
id = event.GetId()
#print "onActive", id
event.Skip()
if id ==1000:
onActive.focusNo=1
txt.SetFocus()
return
txt.SetEditable(True)
pSrc.StyleSetBackground( wx.stc.STC_STYLE_DEFAULT,"gray")
pSrc.StyleSetSpec( wx.stc.STC_P_DEFAULT,"back:gray")
txt.SetBackgroundColour("white")
#txt.SetForegroundColour( "white" )
if id ==1001:
onActive.focusNo=2
pSrc.SetFocus()
return
pSrc.StyleSetBackground( wx.stc.STC_STYLE_DEFAULT,"white")
pSrc.StyleSetSpec( wx.stc.STC_P_DEFAULT,"back:white")
txt.SetBackgroundColour("MEDIUM GREY")
#txt.SetForegroundColour( "GREY" )
lastPos = txt.GetLastPosition()
#txt.SetStyle(0 , lastPos, wx.TextAttr("", ""))
#txt.clear()
txt.SetEditable(False)
#txt.SetBackgroundColour((255,23,23))
onActive.focusNo=0
onActive.focusSv=0
debugCmd ={
901:"n"
,902:"s"
,903:"r"
,905:"b"
,906:"c"
,2007:"g"
}
'''-----------------------------------
クラス定義 フレーム
--------------------------------------'''
class FrameExDbg(wx.Frame):
''' クラス定義 フレーム '''
inst=None
def __init__(self, *args, **kwargs):
''' コンストラクター '''
wx.Frame.__init__(self, title="kobayashi -title",*args, **kwargs)
#インスタンスを保持する
FrameExDbg.inst = self
# setting up toolbar
self.toolbar = self.CreateToolBar( wx.TB_HORIZONTAL | wx.NO_BORDER | wx.TB_FLAT | wx.TB_TEXT )
#self.toolbar.AddSimpleTool(801, wx.Bitmap('icons/stock_new.png'), 'New', '')
self.toolbar.AddSimpleTool(800, wx.Bitmap('Document-Blank-icon.png'), 'New', '')
self.toolbar.AddSimpleTool(801, wx.Bitmap('open-file-icon.png'), 'Open', '')
self.toolbar.AddSimpleTool(802, wx.Bitmap('Actions-document-save-icon.png'), 'Save', '')
self.toolbar.AddSeparator()
self.toolbar.AddCheckLabelTool(900, "", wx.Bitmap('Halloween-Bug-icon.png') )
#self.toolbar.AddCheckLabelTool(900, "",wx.Bitmap('Halloween-Bug-icon.png'), 'Ctrl+R Debug', '')
self.toolbar.AddSimpleTool(901, wx.Bitmap('Button-Download-icon.png'), 'n next', '')
self.toolbar.AddSimpleTool(902, wx.Bitmap('Inbox-Into-icon.png'), 's step', '')
self.toolbar.AddSimpleTool(903, wx.Bitmap('Inbox-Out-icon.png'), 'r return', '')
self.toolbar.AddSimpleTool(904, wx.Bitmap('Actions-go-jump-icon.png'), 'j jump', '')
self.toolbar.AddSeparator()
self.toolbar.AddSimpleTool(905, wx.Bitmap('Actions-process-stop-icon.png'), 'B breakPoint', '')
self.toolbar.AddSimpleTool(906, wx.Bitmap('download-icon.png'), 'C continue', '')
self.toolbar.Realize()
# timer
self.timer = wx.Timer( self )
self.Bind(wx.EVT_TIMER, self.onTimer)
def onTimer( self, event):
'''タイマーです、はじめまして'''
global txt
print "timeput"
#マウスポインターを通常にする
wx.SetCursor ( wx.StockCursor ( wx.CURSOR_ARROW ) )
self.timer.Stop()
txt.SetFocus()
'''-----------------------------------
パネルクラス
--------------------------------------'''
class PanelEx(wx.Panel):
inst = None
def __init__(self, parent,id):
PanelEx.inst = self
wx.Panel.__init__(self, parent,id)
"""
---------------------------------------------------
GUIのメイン
---------------------------------------------------
"""
class MyApp(wx.App):
inst =None
def OnInit(self):
#os.remove( ERR_FILE ) #trace-error-log
f = open( ERR_FILE, 'w')
f.write( "" )
f.close()
self.frame = FrameExDbg( None,50, pos=(1,1),size=(1000,600))
self.panel = PanelEx( self.frame, 51)
self.frame.CreateStatusBar()
self.panel.SetBackgroundColour("#AFAFAF")
self.txt = textCmd.TextCmd( self.panel, id=1000, pos=(500,10), size=(400,250) )
#self.pSrc= textSrc.TextSrc( self.panel, id=1001, pos=(10, 50), size=(400,500))
dbgClass = dbgC()
#self.pSrc.setFunc( dbgC.inst.cmdFunc )
self.txt.setFunc( dbgC.inst.cmdInput ) # from dbg-text window
self.panelG = wx.Panel( self.frame, 60, pos=(500,300),size=(400,250))
self.g = gridEx.GridEx( self.panelG, wx.ID_ANY)
"""
txt.Bind(wx.EVT_ENTER_WINDOW, onActive)
pSrc.Bind(wx.EVT_ENTER_WINDOW, onActive)
"""
self.frame.Bind(wx.EVT_TOOL, self.evtTool)
self.toolBarEnable(901,6,False) #最初は、デバックでないから、ツールボタンはみえない
args = sys.argv
del args[0]
if len( args ) ==1:
fileName = args[0]
else:
fileName = "1st.py"
args.append( fileName)
textSrc.TextSrc.inst.fileName = fileName
self.pSrc.LoadFile(fileName)
self.frame.Show()
return True
def fileNew(self):
fn =""
textSrc.TextSrc.inst.fileName =fn
self.frame.SetTitle( '(' + fn + ') wpdb')
textSrc.TextSrc.inst.ClearAll()
def fileOpen(self):
#ファイル選択ダイアログの表示
dirName = ''
dialog = wx.FileDialog( self.frame, "Choose a file", dirName, "", "*.*", wx.OPEN)
#OKボタンが押されるまで表示
if dialog.ShowModal() == wx.ID_OK:
fileName = dialog.GetFilename()
dirName = dialog.GetDirectory()
#file = open(os.path.join( dirName, fileName), 'r')
#ファイルデータ読み込み
#file.close()
fn = textSrc.TextSrc.inst.fileName = os.path.join( dirName, fileName)
textSrc.TextSrc.inst.LoadFile( fn )
print "fileOpen-new-ver", fn
self.frame.SetTitle( '(' + fn + ') wpdb')
#ダイアログの破棄
dialog.Destroy()
def fileSave( self ):
wildcard = "Python source (*.py)|*.py|" \
"All files (*.*)|*.*"
fn = textSrc.TextSrc.inst.fileName.strip()
if fn == "":
"""
Create and show the Save FileDialog
"""
dlg = wx.FileDialog(
self.frame, message="Save file as ...",
defaultDir= os.getcwd(),
defaultFile="", wildcard=wildcard, style=wx.SAVE
)
if dlg.ShowModal() == wx.ID_OK:
fn = dlg.GetPath()
print "You chose the following filename: %s" % fn
textSrc.TextSrc.inst.fileName = fn
self.frame.SetTitle( '(' + fn + ') wpdb')
dlg.Destroy()
self.pSrc.SaveFile( fn )
self.pSrc.SetFocus()
self.pSrc.GotoLine( 0 )
def toolBarEnable( self, st,n, flg):
for i in range( n ):
FrameEx.inst.toolbar.EnableTool( st+i, flg)
def evtTool( self, e ):
global th,frame,dbgMode
id = e.GetId()
print "onTool", id
if id == 800:
self.fileNew()
elif id == 801:
self.fileOpen()
elif id == 802:
self.fileSave()
elif id == 900:
dbgMode = FrameEx.inst.toolbar.GetToolState( id )
if dbgMode:
# file save and Debug start
self.fileSave()
dbgC.inst.dbgStart()
self.toolBarEnable(901,6,True)
else:
dbgC.inst.dbgEnd()
self.toolBarEnable(901,6,False)
else:
dbgC.inst.pdb.cmd( debugCmd[id] )
if __name__ == "__main__":
app =MyApp()
app.MainLoop()