Pylons におけるデバッグ方法

社内向けに書いたドキュメントですが、汎用的で役に立ちそうなので、少し手を入れて公開することにしました。

ログ出力

ファイルの先頭でログ出力用オブジェクトをを初期化し、以下のようにログを書き出してください。

   import logging
   log = logging.getLogger(__name__)

   log.warn("Some Message")

デフォルトでは、サーバを実行しているコンソールにログが書き出されます。なお、 development.ini にログの設定を細かく書くことができます。詳しくは Logging を参照してください。

インタラクティブデバッガ

Pylons を debug=true で利用していると、エラー画面にデバッグ画面が表示されます。ここにはスタックトレースが表示され、各種変数を参照したり、Python コードを実行することができ、とても便利です。詳しくは Interactive Application Debugging を参照してください。

典型的なエラーを見て、間違いを発見する

例:

  • KeyError: 辞書型に対応するkeyが存在しない
デバッグ画面のコンソールを利用する

デバッグ画面のコンソールでは、任意のコードを実行することができます。

   >>> help(foo)
   >>> dir(foo)
   >>> foo()
   >>> foo.__dict__

インポートもできます。

   >>> from pylons import config  # 設定情報
   >>> from pylons import request
   >>> request.environ

整形出力したい場合は、pprint が便利です。

   >>> import pprint
   >>> pprint.pprint(environ)
Extra Data タブ

設定情報( pylons.config )や environ の中身を確認することができます。

わざと例外を起こす

Pylons 開発で慣れている人が良く用いる手法だと思いますが、raise をコード中に書いてわざと例外を起こし、デバッグ画面を起動します。

なお、 raise の代わりに raise RuntimeError を記述すると、try ブロックの中などでも例外が補足されづらく、便利です。

environ に値を格納する

例外を発生させられない特別な場所で利用される変数の値などは、environ に参照したい値や関数を格納しておくと、別の場所で例外を起こしてもデバッグ画面で値を参照できます。

値の格納(ソースコード上)

   from pylons import request
   request.environ["foo"] = some_value

値の参照(デバッグ画面)

   >>> from pylons import request
   >>> request.environ["foo"]
Jinja の中で例外を起こす

Jinja の中で raise を実行することはできませんが、以下のような不正なコードで例外を発生させることができます。

   {{ 0+"" }}
_ の振舞い

デバッグ画面のコンソール上では、 _ が特別な変数として認識され、1つ前に実行したコマンドの実行結果が格納されます。

この _ が国際化で利用される _ 関数と衝突するため、デバッグ画面を閉じた後に translate に関するエラーが表示されることがあります。このときはサーバを再起動してください。

Python シェルの _ については Python Quick Reference に説明があります。

注意事項

インタラクティブデバッガはセキュリティ上危険なので、リリース時には debug=False として、この画面を表示しないようにしましょう。

プロファイル

以下のコードを myproj.config.middleware でのアプリケーションの初期化に記述すると、デバッグモードで起動している際にページ下部にプロファイル情報を表示することができます。

   if config.get('debug'):
       from paste.debug.profile import ProfileMiddleware
       app = ProfileMiddleware(app, global_conf)

profile_decorator というデコレータを利用することもできます。詳しくは下記のページを参照してください。

Python シェル

Python シェル

WEB アプリの初期化に依存しないようなコードの確認であれば、 Python シェルが使えます。なお、きめ細やかな操作をサポートしている ipython を入れておくことをお勧めします。

   $ easy_install ipython
paster shell

Pylons で提供されているコマンドですが、 model に対してクエリを発行するのが面倒であるため、次項で説明する paster customshell を利用した方が良いでしょう。
(注: paster customshell は pyxis 用のコマンドです。)

  $ paster shell
paster customshell

paster shell でサポートしていることに加えて、 model にクエリを発行することもできます。
(注: paster customshell は pyxis 用のコマンドです。)

   $ paster customshell
   >>> query = model.Session.query(model.FooModel)
   >>> query.all()


なお、shell で実行した内容をコピーすれば、 doctest として利用することもできます。

pdb

pdb を使うには、ソースコード内で割り込みたい個所に以下のようなコードを記述してください。paster serve を起動しているシェルで、 pdb のシェルが自動的に立ち上がります。

   import pdb; pdb.set_trace()

pdb でよく使うコマンドには、以下のようなものがあります。

  • help: ヘルプを表示
  • n: 次へ
  • s: 関数の中へ
  • r: 1つ上へ
  • p: 値を表示
  • pp: 値を表示(pprint)
  • help: ヘルプを表示
  • q: pdbを抜ける

pdb シェル内で普通の python コマンドも実行できますが、先頭文字がコマンド文字列と同じ場合は、 ! を先頭につけてください。

   (Pdb) !p = 1
   (Pdb) p p
   1

参考

emacs ユーザのための Tips

emacs 上でのコード実行

emacspython-mode がインストールされている場合、C-c C-c (py-execute-buffer) でファイルの中身を直接実行できます。

if __name__ == "__main__" ブロック内のコードは、このファイルが直接実行されたときのみ実行されるため、ここにデバッグコードを書いて実行すると便利です。

   def foo():
       print "Hello World"

   if __name__ == "__main__":
       foo()
vc-annotate

M-x vc-annotate で Subversion の変更ログを見ることができます。
(vc-annotate で表示されている内容は、 :command:svn blame foo.txt を実行したときに見られる内容と同じです。)

  • A: vc-annotate-revision-previous-to-line
  • D: vc-annotate-show-diff-revision-at-line (diff 表示する)
  • J: vc-annotate-revision-at-line
  • L: vc-annotate-show-log-revision-at-line (ログ表示)
  • N: vc-annotate-next-version
  • P: vc-annotate-prev-version
  • W: vc-annotate-workfile-version

なお、vc-annotate を表示した画面で describe-mode を実行すると、利用可能なコマンドの一覧が表示されます。

参考

posted by id:junya_hayashi