2008年8月2日土曜日

Pythonのtraceモジュールの補記

Python ドキュメント翻訳プロジェクトの libtrace に取りかかっているのだけど
説明が少ないのでいくつか試してみたメモ書き。間違っていたら指摘してください。

1. テスト用サンプルプログラム

python main.py {outfile} みたいに使う

import sys
from StringIO import StringIO

def isEven(i):
    if i%2 == 0:
        return True
    else:
        return False

def main():
    s = StringIO()
    s.write('Hello ')
    s.write('StringIO\n')
    
    for i in (range(10)):
        if isEven(i):
            s.write('%d: even\n'%i)
        else:
            s.write('%d: odd\n'%i)
            
    try:
        f = open(sys.argv[1], 'w')
        f.write(s.getvalue())
        f.close()
    except IOError:
        print('IOError')

if __name__ == '__main__':
    main()

2. 基本的な使い方

python -m trace {オプション} {トレース対象のプログラム}

3. 基本オプション

{オプション}にはどれか一つを必ず指定する必要がある。
オプション名説明
−−traceプログラム行を実行順に表示する。出力先は標準出力(stdout)。
−−countプログラム中で各行が実行された回数をカウントする。出力先は、対象がsomefile.pyの場合somefile.cover。
−−report必ず--fileオプションを一緒に指定しないといけない。--fileの引数は、python -m trace --count --file {ファイル名} {プログラム} で生成されたファイル。この場合は {トレース対象のプログラム} 引数は必要ない。このコマンドの実行で --file で指定されたファイルが更新されるんだけd、更新前と後の違いはいまのところ良く分からない)
−−listfuncs呼ばれた関数の一覧。出力は標準出力(stdout)。
−−trackcalls呼び出し元/呼び出し先の関係を表示。標準出力(std出力。

4. −−trace の例

たとえば、
python -m trace --trace main.py out.dat
の標準出力は

$ python -m trace --trace main.py out.dat 
 --- modulename: threading, funcname: settrace
threading.py(70):     _trace_hook = func
 --- modulename: main, funcname: 
main.py(1): import sys
main.py(2): from StringIO import StringIO
 --- modulename: StringIO, funcname: 
StringIO.py(30): """
StringIO.py(31): try:
StringIO.py(32):     from errno import EINVAL
StringIO.py(36): __all__ = ["StringIO"]
StringIO.py(38): def _complain_ifclosed(closed):
(略)
main.py(15):     for i in (range(10)):
main.py(21):     try:
main.py(22):         f = open(sys.argv[1], 'w')
main.py(23):         f.write(s.getvalue())
 --- modulename: StringIO, funcname: getvalue
StringIO.py(269):         if self.buflist:
StringIO.py(270):             self.buf += ''.join(self.buflist)
StringIO.py(271):             self.buflist = []
StringIO.py(272):         return self.buf
main.py(24):         f.close()

StringIO モジュールのトレースが邪魔な場合は、--trace --ignore-module {モジュール名} とできる。

$ python -m trace --trace --ignore-module StringIO main.py out.dat 
 --- modulename: threading, funcname: settrace
threading.py(70):     _trace_hook = func
 --- modulename: main, funcname: 
main.py(1): import sys
main.py(2): from StringIO import StringIO
(略)
main.py(21):     try:
main.py(22):         f = open(sys.argv[1], 'w')
main.py(23):         f.write(s.getvalue())
main.py(24):         f.close()

5. −−count の例

--count の出力は、--countを単独で指定した場合はソースコードの左に実行回数が記入された形になる。

$python -m trace --count main.py out.dat
$less main.cover
    1: import sys
    1: from StringIO import StringIO
       
    1: def isEven(i):
   10:     if i%2 == 0:
    5:         return True
           else:
    5:         return False
       
    1: def main():
    1:     s = StringIO()
    1:     s.write('Hello ')
    1:     s.write('StringIO\n')
           
   11:     for i in (range(10)):
   10:         if isEven(i):
    5:             s.write('%d: even\n'%i)
               else:
    5:             s.write('%d: odd\n'%i)
                   
    1:     try:
    1:         f = open(sys.argv[1], 'w')
    1:         f.write(s.getvalue())
    1:         f.close()
           except IOError:
               print('IOError')
       
    1: if __name__ == '__main__':
    1:     main()

−−count オプションに加えて−−missingを指定すると、実行されなかった行が">>>>>>"でマークされる。

$python -m trace --count --missing main.py out.dat
$less main.cover
    1: import sys
    1: from StringIO import StringIO
       
    1: def isEven(i):
   10:     if i%2 == 0:
    5:         return True
           else:
    5:         return False
       
    1: def main():
    1:     s = StringIO()
    1:     s.write('Hello ')
    1:     s.write('StringIO\n')
           
   11:     for i in (range(10)):
   10:         if isEven(i):
    5:             s.write('%d: even\n'%i)
               else:
    5:             s.write('%d: odd\n'%i)
                   
    1:     try:
    1:         f = open(sys.argv[1], 'w')
    1:         f.write(s.getvalue())
    1:         f.close()
>>>>>>     except IOError:
>>>>>>         print('IOError')
       
    1: if __name__ == '__main__':
    1:     main()

当然、 main.pyの引数に書き込めないファイルを指定すると実行されない行が変化する。

$ python -m trace --count --missing main.py noout.dat 
IOError
$ less main.cover
    1: import sys
    1: from StringIO import StringIO
       
    1: def isEven(i):
   10:     if i%2 == 0:
    5:         return True
           else:
    5:         return False
       
    1: def main():
    1:     s = StringIO()
    1:     s.write('Hello ')
    1:     s.write('StringIO\n')
           
   11:     for i in (range(10)):
   10:         if isEven(i):
    5:             s.write('%d: even\n'%i)
               else:
    5:             s.write('%d: odd\n'%i)
                   
    1:     try:
    1:         f = open(sys.argv[1], 'w')
>>>>>>         f.write(s.getvalue())
>>>>>>         f.close()
    1:     except IOError:
    1:         print('IOError')
       
    1: if __name__ == '__main__':
    1:     main()

(−−count に −−file オプションを付けるとpickle 形式のファイルが出力されて、
−−report −−file の入力に使うことができるのだけど、使い道はよくわからない)

6. −−listfuncs の例

listfuncs は使われた関数を一覧する:

$ python -m trace --listfuncs main.py out.dat 

functions called:
filename: /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/StringIO.py, modulename: StringIO, funcname: 
filename: /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/StringIO.py, modulename: StringIO, funcname: StringIO
filename: /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/StringIO.py, modulename: StringIO, funcname: StringIO.__init__
filename: /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/StringIO.py, modulename: StringIO, funcname: StringIO.getvalue
filename: /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/StringIO.py, modulename: StringIO, funcname: StringIO.write
filename: /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/StringIO.py, modulename: StringIO, funcname: _complain_ifclosed
filename: /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/threading.py, modulename: threading, funcname: settrace
filename: , modulename: , funcname: 
filename: main.py, modulename: main, funcname: 
filename: main.py, modulename: main, funcname: isEven
filename: main.py, modulename: main, funcname: main

ちなみに、listfuncs に ignore-module オプションは効かないみたい。


$ python -m trace --listfuncs --ignore-module StringIO main.py out.dat 

functions called:
filename: /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/StringIO.py, modulename: StringIO, funcname: 
filename: /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/StringIO.py, modulename: StringIO, funcname: StringIO
filename: /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/StringIO.py, modulename: StringIO, funcname: StringIO.__init__
filename: /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/StringIO.py, modulename: StringIO, funcname: StringIO.getvalue
filename: /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/StringIO.py, modulename: StringIO, funcname: StringIO.write
filename: /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/StringIO.py, modulename: StringIO, funcname: _complain_ifclosed
filename: /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/threading.py, modulename: threading, funcname: settrace
filename: , modulename: , funcname: 
filename: main.py, modulename: main, funcname: 
filename: main.py, modulename: main, funcname: isEven
filename: main.py, modulename: main, funcname: main

7. −−trackcalls の例


$ python -m trace --trackcalls main.py out.dat
−−trackcalls は関数の呼び出し関係を標準出力に表示。これもIgnore-moduleは無効。
calling relationships:

*** /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/StringIO.py ***
    StringIO. -> StringIO.StringIO
    StringIO.StringIO.write -> StringIO._complain_ifclosed

*** /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/trace.py ***
  --> /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/threading.py
    trace.Trace.run -> threading.settrace
  --> 
    trace.Trace.run -> .

***  ***
  --> main.py
    . -> main.

*** main.py ***
  --> /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/StringIO.py
    main. -> StringIO.
    main. -> main.main
    main.main -> StringIO.StringIO.__init__
    main.main -> StringIO.StringIO.getvalue
    main.main -> StringIO.StringIO.write
    main.main -> main.isEven

0 件のコメント:

コメントを投稿