28.10. "traceback" --- スタックトレースの表示または取得
*******************************************************

このモジュールは Python プログラムのスタックトレースを抽出し、書式を整
え、表示するための標準インターフェースを提供します。モジュールがスタッ
クトレースを表示するとき、Python インタープリタの動作を正確に模倣しま
す。インタープリタの"ラッパー"の場合のように、プログラムの制御の元でス
タックトレースを表示したいと思ったときに役に立ちます。

モジュールは traceback オブジェクトを使います --- これは変数
"sys.exc_traceback" (非推奨)と "sys.last_traceback" に保存され、
"sys.exc_info()" から三番目の項目として返されるオブジェクト型です。

このモジュールでは以下の関数を定義しています:

traceback.print_tb(tb[, limit[, file]])

   トレースバックオブジェクト *tb* から *limit* までのスタックトレース
   項目を出力します。 *limit* が省略されるか "None" の場合は、すべての
   項目が表示されます。 *file* が省略されるか "None" の場合は、
   "sys.stderr" へ出力されます。それ以外の場合は、出力を受けるためのオ
   ープンされたファイルまたはファイル風 (file-like) オブジェクトでなけ
   ればなりません。

traceback.print_exception(etype, value, tb[, limit[, file]])

   例外情報とトレースバック *tb* から *limit* までのスタックトレース項
   目を *file* へ出力します。これは以下のような点で "print_tb()" とは
   異なります: (1) *tb* が "None" でない場合は、ヘッダ "Traceback
   (most recent call last):" を出力します。 (2) スタックトレースの後に
   例外 *etype* と *value* を出力します。 (3) *etype* が "SyntaxError"
   であり、 *value* が適切な形式の場合は、エラーのおおよその位置を示す
   カレットを付けて構文エラーが起きた行を出力します。

traceback.print_exc([limit[, file]])

   これは "print_exception(sys.exc_type, sys.exc_value,
   sys.exc_traceback, limit, file)" の省略表現です。 (非推奨の変数を使
   う代わりにスレッドセーフな方法で同じ情報を引き出すために、実際には
   "sys.exc_info()" を使います。)

traceback.format_exc([limit])

   これは、"print_exc(limit)" に似ていますが、ファイルに出力する代わり
   に文字列を返します。

   バージョン 2.4 で追加.

traceback.print_last([limit[, file]])

   "print_exception(sys.last_type, sys.last_value, sys.last_traceback,
   limit, file)" の省略表現です。一般に、例外が対話的なプロンプトに達
   した後にだけ機能します ("sys.last_type" 参照)。

traceback.print_stack([f[, limit[, file]]])

   This function prints a stack trace from its invocation point. The
   optional *f* argument can be used to specify an alternate stack
   frame to start. The optional *limit* and *file* arguments have the
   same meaning as for "print_exception()".

traceback.extract_tb(tb[, limit])

   トレースバックオブジェクト *tb* から *limit* まで取り出された"前処
   理済み"スタックトレース項目のリストを返します。スタックトレースの代
   わりの書式設定を行うために役に立ちます。*limit* が省略されるか
   "None" の場合は、すべての項目が取り出されます。"前処理済み"スタック
   トレース項目とは4要素のタプル (*filename*, *line number*, *function
   name*, *text*) で、スタックトレースに対して通常出力される情報を表し
   ています。*text* は前後の空白を取り除いた文字列です。ソースが利用で
   きない場合は "None" です。

traceback.extract_stack([f[, limit]])

   現在のスタックフレームから生のトレースバックを取り出します。戻り値
   は "extract_tb()" と同じ形式です。オプションの *f* と *limit* 引数
   は "print_stack()" と同じ意味を持ちます。

traceback.format_list(extracted_list)

   "extract_tb()" または "extract_stack()" が返すタプルのリストが与え
   られると、出力の準備を整えた文字列のリストを返します。結果として生
   じるリストの中の各文字列は、引数リストの中の同じインデックスの要素
   に対応します。各文字列は末尾に改行が付いています。さらに、ソーステ
   キスト行が "None" でないそれらの要素に対しては、文字列は内部に改行
   を含んでいるかもしれません。

traceback.format_exception_only(etype, value)

   トレースバックの例外部分をフォーマットします。 引数は
   "sys.last_type" と "sys.last_value" で与えられるような、例外の型
   *etype* と値 *value* です。 戻り値はそれぞれが改行で終わっている文
   字列のリストです。 通常、リストは一つの文字列を含んでいます。 しか
   し、 "SyntaxError" 例外に対しては、 (出力されるときに) 構文エラーが
   起きた場所についての詳細な情報を示す行をいくつか含んでいます。 どの
   例外が起きたのかを示すメッセージは、常にリストの最後の文字列です。

traceback.format_exception(etype, value, tb[, limit])

   スタックトレースと例外情報を書式化します。引数は
   "print_exception()" の対応する引数と同じ意味を持ちます。戻り値は文
   字列のリストで、それぞれの文字列は改行で終わり、そのいくつかは内部
   に改行を含みます。これらの行が連結されて出力される場合は、厳密に
   "print_exception()" と同じテキストが出力されます。

traceback.format_tb(tb[, limit])

   "format_list(extract_tb(tb, limit))" の省略表現です。

traceback.format_stack([f[, limit]])

   "format_list(extract_stack(f, limit))" の省略表現です。

traceback.tb_lineno(tb)

   トレースバックオブジェクトに設定された現在の行番号を返します。
   Python 2.3より前のバージョンでは、 "-O" フラグが渡されたときに
   "tb.tb_lineno" が正しく更新されなかったため、この関数は必要でした。
   2.3以降のバージョンでは不要です。


28.10.1. トレースバックの例
===========================

この簡単な例では基本的な read-eval-print ループを実装しています。標準
的な Python の対話インタープリタループに似ていますが、 Python のものよ
り便利ではありません。インタープリタループのより完全な実装については、
"code" モジュールを参照してください。

   import sys, traceback

   def run_user_code(envdir):
       source = raw_input(">>> ")
       try:
           exec source in envdir
       except:
           print "Exception in user code:"
           print '-'*60
           traceback.print_exc(file=sys.stdout)
           print '-'*60

   envdir = {}
   while 1:
       run_user_code(envdir)

次の例は例外とトレースバックの出力並びに形式が異なることを示します:

   import sys, traceback

   def lumberjack():
       bright_side_of_death()

   def bright_side_of_death():
       return tuple()[0]

   try:
       lumberjack()
   except IndexError:
       exc_type, exc_value, exc_traceback = sys.exc_info()
       print "*** print_tb:"
       traceback.print_tb(exc_traceback, limit=1, file=sys.stdout)
       print "*** print_exception:"
       traceback.print_exception(exc_type, exc_value, exc_traceback,
                                 limit=2, file=sys.stdout)
       print "*** print_exc:"
       traceback.print_exc()
       print "*** format_exc, first and last line:"
       formatted_lines = traceback.format_exc().splitlines()
       print formatted_lines[0]
       print formatted_lines[-1]
       print "*** format_exception:"
       print repr(traceback.format_exception(exc_type, exc_value,
                                             exc_traceback))
       print "*** extract_tb:"
       print repr(traceback.extract_tb(exc_traceback))
       print "*** format_tb:"
       print repr(traceback.format_tb(exc_traceback))
       print "*** tb_lineno:", exc_traceback.tb_lineno

この例の出力は次のようになります:

   *** print_tb:
     File "<doctest...>", line 10, in <module>
       lumberjack()
   *** print_exception:
   Traceback (most recent call last):
     File "<doctest...>", line 10, in <module>
       lumberjack()
     File "<doctest...>", line 4, in lumberjack
       bright_side_of_death()
   IndexError: tuple index out of range
   *** print_exc:
   Traceback (most recent call last):
     File "<doctest...>", line 10, in <module>
       lumberjack()
     File "<doctest...>", line 4, in lumberjack
       bright_side_of_death()
   IndexError: tuple index out of range
   *** format_exc, first and last line:
   Traceback (most recent call last):
   IndexError: tuple index out of range
   *** format_exception:
   ['Traceback (most recent call last):\n',
    '  File "<doctest...>", line 10, in <module>\n    lumberjack()\n',
    '  File "<doctest...>", line 4, in lumberjack\n    bright_side_of_death()\n',
    '  File "<doctest...>", line 7, in bright_side_of_death\n    return tuple()[0]\n',
    'IndexError: tuple index out of range\n']
   *** extract_tb:
   [('<doctest...>', 10, '<module>', 'lumberjack()'),
    ('<doctest...>', 4, 'lumberjack', 'bright_side_of_death()'),
    ('<doctest...>', 7, 'bright_side_of_death', 'return tuple()[0]')]
   *** format_tb:
   ['  File "<doctest...>", line 10, in <module>\n    lumberjack()\n',
    '  File "<doctest...>", line 4, in lumberjack\n    bright_side_of_death()\n',
    '  File "<doctest...>", line 7, in bright_side_of_death\n    return tuple()[0]\n']
   *** tb_lineno: 10

次の例は、スタックの print と format の違いを示しています:

   >>> import traceback
   >>> def another_function():
   ...     lumberstack()
   ...
   >>> def lumberstack():
   ...     traceback.print_stack()
   ...     print repr(traceback.extract_stack())
   ...     print repr(traceback.format_stack())
   ...
   >>> another_function()
     File "<doctest>", line 10, in <module>
       another_function()
     File "<doctest>", line 3, in another_function
       lumberstack()
     File "<doctest>", line 6, in lumberstack
       traceback.print_stack()
   [('<doctest>', 10, '<module>', 'another_function()'),
    ('<doctest>', 3, 'another_function', 'lumberstack()'),
    ('<doctest>', 7, 'lumberstack', 'print repr(traceback.extract_stack())')]
   ['  File "<doctest>", line 10, in <module>\n    another_function()\n',
    '  File "<doctest>", line 3, in another_function\n    lumberstack()\n',
    '  File "<doctest>", line 8, in lumberstack\n    print repr(traceback.format_stack())\n']

最後の例は、残りの幾つかの関数のデモをします:

   >>> import traceback
   >>> traceback.format_list([('spam.py', 3, '<module>', 'spam.eggs()'),
   ...                        ('eggs.py', 42, 'eggs', 'return "bacon"')])
   ['  File "spam.py", line 3, in <module>\n    spam.eggs()\n',
    '  File "eggs.py", line 42, in eggs\n    return "bacon"\n']
   >>> an_error = IndexError('tuple index out of range')
   >>> traceback.format_exception_only(type(an_error), an_error)
   ['IndexError: tuple index out of range\n']
