エラー時にPythonデバッガを自動的に起動する


216

これはかなり長い間疑問に思っていた質問ですが、適切な解決策を見つけたことはありません。スクリプトを実行して、偶然にIndexErrorが発生した場合、pythonはエラーの行、場所、簡単な説明を出力して終了します。エラーが発生したときにpdbを自動的に起動することはできますか?ファイルの先頭に余分なインポートステートメントを追加したり、コードの数行を追加したりすることに反対しているわけではありません。


12
受け入れられる回答を変更することを検討しましたか?
Joost、

回答:


127

traceback.print_excを使用して、例外のトレースバックを出力できます。その後、使用sys.exc_infoをトレースバックを抽出し、最終的に呼び出すためにpdb.post_mortemをそのトレースバックで

import pdb, traceback, sys

def bombs():
    a = []
    print a[0]

if __name__ == '__main__':
    try:
        bombs()
    except:
        extype, value, tb = sys.exc_info()
        traceback.print_exc()
        pdb.post_mortem(tb)

例外が発生したフレームのローカルを使用して、code.interactでインタラクティブなコマンドラインを開始する場合は、次のことができます

import traceback, sys, code

def bombs():
    a = []
    print a[0]

if __name__ == '__main__':
    try:
        bombs()
    except:
        type, value, tb = sys.exc_info()
        traceback.print_exc()
        last_frame = lambda tb=tb: last_frame(tb.tb_next) if tb.tb_next else tb
        frame = last_frame().tb_frame
        ns = dict(frame.f_globals)
        ns.update(frame.f_locals)
        code.interact(local=ns)

最初の解決策は、pythonクックブック
dirkjot '27

3
なぜ誰もが好むcode超えるpdb後者が前者に拡大しているようですので、?
K3 --- rnc 2014

同じ質問がありますか?なぜあなたは好きcodeですか?
ARH

2
その後、使用sys.exc_infoトレースバックを抽出し、最終的に呼び出すためにpdb.post_mortemそのトレースバックで。トレースバックオブジェクトをに渡す必要はありませんpdb.post_mortemドキュメントから:トレースバックが指定されていない場合は、現在処理されている例外の1つを使用します(デフォルトを使用する場合は、例外を処理する必要があります)。
Piotr Dobrogost 2015

2
@PiotrDobrogost良い点。ただし、tbオブジェクトを渡すことができることを知っておくと、APIのデモンストレーションが改善されるため、より役立つと思います。両方のオプションが存在することを知っておくと便利です。
davidA 2016

453
python -m pdb -c continue myscript.py

-c continueフラグを指定しない場合は、実行の開始時に 'c'(続行)を入力する必要があります。その後、エラーポイントまで実行され、そこで制御できます。eqzx言及「C」を入力するので、このフラグは、Python 3.2で新たに追加され、以前のPythonのバージョン(参照のために必要とされるhttps://docs.python.org/3/library/pdb.htmlを)。


5
enter 'c'」について言及していただきありがとうございます。私は通常、「r」(「run」の意味)を入力するために使用されていましたgdb。で「r」を入力するとpdb、プログラムは実際に実行されますが、エラーで停止(またはバックトレースを生成)しません。これを読むまで私は戸惑いました。乾杯!
sdaau 2013

3
Vineet、デバッガをオンにして起動するので、「cont」と入力すると、エラーが発生するまで実行されます。そこから、他のpdbセッションと同様に、変数などを検査できます。
Catherine Devlin、2014

40
OPしてください、これを答えとして受け入れてください。これは最も便利で、これに当たるまで5分他の記事を読んで無駄にしています...これが最初のはずです!
jhegedus

4
これはでも同じように機能しipdbます。もちろん、引数はスクリプトの後に追加できます。
tutuDajuju

20
これはPython 2.7では機能しません。docs.python.org/3/library/pdb.html: "バージョン3.2の新機能:pdb.pyがコマンドを実行する-cオプションを受け入れるようになりました"
eqzx

68

次のモジュールを使用します。

import sys

def info(type, value, tb):
    if hasattr(sys, 'ps1') or not sys.stderr.isatty():
    # we are in interactive mode or we don't have a tty-like
    # device, so we call the default hook
        sys.__excepthook__(type, value, tb)
    else:
        import traceback, pdb
        # we are NOT in interactive mode, print the exception...
        traceback.print_exception(type, value, tb)
        print
        # ...then start the debugger in post-mortem mode.
        # pdb.pm() # deprecated
        pdb.post_mortem(tb) # more "modern"

sys.excepthook = info

名前を付けてdebug(または好きな名前を付けて)、Pythonパスのどこかに配置します。

次に、スクリプトの開始時に、を追加しimport debugます。


2
これは受け入れられる答えです。既存のコードを変更したり、すべてをtry-catch醜いIMOでラップしたりする必要はありません。
cyphar 2015

私はむしろ、頻繁にこの答えを愛し、しかし好むpudbオーバーpdb。私の人生の秩序の欠如について確かに何かを言っているコピー&ペーストに戻ってください。
Stabledog

47

Ipythonには、この動作を切り替えるためのコマンド%pdbがあります。それはあなたが説明したとおりに、おそらくもう少し(構文の強調表示とコード補完でより有益なバックトレースを提供します)します。ぜひお試しください!


3
そして、それがこれに対する唯一の合理的な答えです。
マイケル


4
リンクされたドキュメント@matthiashにも記載されているように、エラーが発生した後に%debugデバッガを開くことができることに注意してください。私はしばしばこれを好む。(トレードオフは、エラーをデバッグしたくないときは常にタイピングすることと、エラーをデバッグたいときはいつもタイピングすることです。)%pdbq%debug
Braham Snyder

1
また、セッションごとに設定c.InteractiveShell.pdb = Trueが自動的にipython_config.pyオンになることにも注意してください%pdb
Braham Snyder

33

これはデバッガではありませんが、おそらく同じくらい便利です(?)

グイドがどこかでスピーチの中でこれを言っているのを聞いたのを知っています。

私はpython-?を確認しました。-iコマンドを使用すると、スクリプトが停止した場所を操作できます。

したがって、次のスクリプトがあるとします。

testlist = [1,2,3,4,5, 0]

prev_i = None
for i in testlist:
    if not prev_i:
        prev_i = i
    else:
        result = prev_i/i

あなたはこの出力を得ることができます!

PS D:\> python -i debugtest.py
Traceback (most recent call last):
  File "debugtest.py", line 10, in <module>
    result = prev_i/i
ZeroDivisionError: integer division or modulo by zero
>>>
>>>
>>> prev_i
1
>>> i
0
>>>

正直なところ、これは使用していませんが、使用する必要がありますが、非常に便利です。


軽量ですが、多くの場合必要なものだけです
Casebash 2010

8
それほど有用ではありませんが、グローバルスコープで起動します。クラッシュした関数をあちこち見回すことはできません。
pixelpax 2016年

21

IPythonは、コマンドラインでこれを簡単にします。

python myscript.py arg1 arg2

に書き換えることができます

ipython --pdb myscript.py -- arg1 arg2

または、同様に、モジュールを呼び出す場合:

python -m mymodule arg1 arg2

に書き換えることができます

ipython --pdb -m mymodule -- arg1 arg2

--IPythonがスクリプトの引数を独自のものとして読み取るのを停止することに注意してください。

これには、pdbの代わりに拡張IPythonデバッガー(ipdb)を呼び出すという利点もあります。


9

を使用している場合はipython、タイプを起動した後%pdb

In [1]: %pdb
Automatic pdb calling has been turned ON

たとえば
Jupyter

6

IPython環境を使用している場合は、%debugを使用するだけで、シェルがipdb環境の問題のある行に戻って、検査などを行うことができます。上記の別のオプションは、効果的なiPythonマジック%pdbを使用することです。同じ。


モジュール関数でエラーが発生した場合、upおよびdownコマンドを使用してフレームをナビゲートし、エラーを生成したコードの行に戻ることができます。
Jean Paul


3

最初にcを入力せずに実行するには、次のコマンドを使用します。

python -m pdb -c c <script name>

Pdbには独自のコマンドライン引数があります。-ccは実行の開始時にc(ontinue)コマンドを実行し、プログラムはエラーが発生するまで中断されずに実行されます。


3

python2.7のpython -m pdb script.pyを押し続けて開始すると、エラーが発生してデバッグのために中断されます。


1

モジュールを実行している場合:

python -m mymodule

そしてpdb、例外が発生したときに入力したい場合は、次のようにします。

PYTHONPATH="." python -m pdb -c c mymodule/__main__.py

(またはあなたの拡張PYTHONPATH)。PYTHONPATHモジュールがパスに発見されたように、あなたが実行していることから、必要とされているpdb今、モジュールを。


0

階層の最上位の例外クラスのコンストラクター内にブレークポイントを配置すると、ほとんどの場合、エラーが発生した場所がわかります。

ブレークポイントを置くことは、それが意味することを何でも意味します:IDE、またはpdb.set_trace、または何でも使用できます

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.