Mulai python debugger secara otomatis saat terjadi kesalahan


216

Ini adalah pertanyaan yang telah saya tanyakan selama beberapa waktu, namun saya belum pernah menemukan solusi yang cocok. Jika saya menjalankan skrip dan menemukan, katakanlah IndexError, python mencetak garis, lokasi, dan deskripsi cepat tentang kesalahan dan keluar. Apakah mungkin untuk memulai pdb secara otomatis ketika kesalahan terjadi? Saya tidak menentang memiliki pernyataan impor tambahan di bagian atas file, atau beberapa baris kode tambahan.


12
Sudahkah Anda mempertimbangkan untuk mengubah jawaban yang diterima?
Joost

Jawaban:


127

Anda dapat menggunakan traceback.print_exc untuk mencetak pengecualian traceback. Kemudian gunakan sys.exc_info untuk mengekstrak traceback dan akhirnya memanggil pdb.post_mortem dengan traceback itu

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)

Jika Anda ingin memulai baris perintah interaktif dengan code.interact menggunakan penduduk lokal dari frame di mana pengecualian berasal Anda bisa melakukannya

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)

solusi pertama dibahas lebih lanjut di buku resep python
dirkjot

3
mengapa ada orang yang lebih memilih codelebih pdbkarena yang terakhir tampaknya memperluas mantan?
K3 --- rnc

Saya punya pertanyaan yang sama? Mengapa Anda lebih suka code?
ARH

2
Kemudian gunakan sys.exc_infountuk mengekstrak traceback dan akhirnya memanggil pdb.post_mortemdengan traceback itu . Anda tidak perlu meneruskan objek traceback ke pdb.post_mortem. Dari dokumen : Jika tidak ada traceback yang diberikan, ia menggunakan salah satu pengecualian yang sedang ditangani (pengecualian harus ditangani jika default akan digunakan).
Piotr Dobrogost

2
@PiotrDobrogost Poin bagus. Saya pikir lebih membantu untuk mengetahui bahwa Anda dapat melewatkan objek tb, karena lebih baik menunjukkan API. Baik untuk mengetahui kedua opsi yang ada.
davidA

453
python -m pdb -c continue myscript.py

Jika Anda tidak memberikan -c continuetanda maka Anda harus memasukkan 'c' (untuk Lanjutkan) saat eksekusi dimulai. Kemudian akan berjalan ke titik kesalahan dan memberi Anda kontrol di sana. Seperti yang disebutkan oleh eqzx , flag ini adalah tambahan baru di python 3.2 sehingga memasukkan 'c' diperlukan untuk versi Python sebelumnya (lihat https://docs.python.org/3/library/pdb.html ).


5
Terima kasih telah menyebutkan " enter 'c' " - Saya biasanya digunakan untuk memasukkan 'r' (untuk "run"), digunakan untuk itu dari gdb; dan ketika Anda memasukkan 'r' pdb, program memang berjalan, tetapi TIDAK berhenti (atau menghasilkan backtrace) pada kesalahan; membuat saya bingung sampai saya membaca ini. Bersulang!
sdaau

3
Vineet, itu akan memulai Anda dengan debugger aktif, jadi masukkan "cont" dan itu akan berjalan sampai kesalahan ditemukan. Dari sana Anda dapat memeriksa variabel, dll. Seperti pada sesi pdb lainnya.
Catherine Devlin

40
Tolong OP, terimalah ini sebagai jawaban. Ini adalah yang paling berguna dan saya sudah membuang waktu 5 menit membaca yang lain sampai saya menekan yang ini ... ini harus menjadi yang pertama!
jhegedus

4
Ini juga berfungsi sama dengan ipdb; dan tentu saja argumen dapat ditambahkan setelah skrip!
tutuDajuju

20
Ini tidak berfungsi dengan Python 2.7. docs.python.org/3/library/pdb.html : "Baru dalam versi 3.2: pdb.py sekarang menerima opsi -c yang mengeksekusi perintah"
eqzx

68

Gunakan modul berikut:

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

Beri nama debug(atau apa pun yang Anda suka) dan letakkan di suatu tempat di jalur python Anda.

Sekarang, di awal skrip Anda, tambahkan saja import debug.


2
Ini harus menjadi jawaban yang diterima - itu tidak memerlukan modifikasi kode yang ada atau membungkus segala sesuatu dalam try-catchyang hanya IMO jelek.
cyphar

Saya suka jawaban ini agak sering, tapi lebih suka pudblebih pdb. Terus kembali ke copy-and-paste, yang pasti mengatakan sesuatu tentang kurangnya ketertiban dalam hidup saya.
Stabledog

47

Ipython memiliki perintah untuk mengubah perilaku ini: % pdb . Itu tidak persis seperti yang Anda jelaskan, bahkan mungkin sedikit lebih (memberi Anda backtraces lebih informatif dengan penyorotan sintaksis dan penyelesaian kode). Pasti patut dicoba!


3
Dan itu satu-satunya jawaban yang masuk akal untuk ini.
Michael


4
Perhatikan bahwa - sebagaimana dicatat dalam docs @matthiash linked - %debugmemungkinkan seseorang untuk membuka debugger setelah menemukan kesalahan. Saya sering lebih suka ini %pdb. (Trade-off hanya mengetik qsetiap kali Anda tidak ingin debug kesalahan vs mengetik %debugsetiap kali Anda melakukan ingin debug kesalahan.)
Braham Snyder

1
Perhatikan juga bahwa pengaturan c.InteractiveShell.pdb = Truepada ipython_config.pygiliran seseorang dihidupkan %pdbsecara otomatis untuk setiap sesi.
Braham Snyder

33

Ini bukan debugger, tapi mungkin sama bermanfaatnya (?)

Saya tahu saya mendengar Guido menyebutkan ini dalam suatu pidato di suatu tempat.

Saya baru saja memeriksa python - ?, dan jika Anda menggunakan perintah -i Anda dapat berinteraksi di mana skrip Anda berhenti.

Jadi diberikan skrip ini:

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

Anda bisa mendapatkan hasil ini!

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
>>>

Sejujurnya saya belum pernah menggunakan ini, tetapi saya harus, tampaknya sangat berguna.


Ringan, tetapi seringkali hanya apa yang dibutuhkan
Casebash

8
Hampir tidak berguna, diluncurkan ke ruang lingkup global. Tidak bisa melihat-lihat fungsi apa pun yang macet.
pixelpax

21

IPython membuatnya mudah di baris perintah:

python myscript.py arg1 arg2

dapat ditulis ulang menjadi

ipython --pdb myscript.py -- arg1 arg2

Atau, sama halnya, jika memanggil modul:

python -m mymodule arg1 arg2

dapat ditulis ulang menjadi

ipython --pdb -m mymodule -- arg1 arg2

Perhatikan --untuk menghentikan IPython dari membaca argumen skrip sebagai miliknya.

Ini juga memiliki keuntungan menggunakan debugger IPython yang ditingkatkan (ipdb) daripada pdb.


9

Jika Anda menggunakan ipython, setelah meluncurkan jenis%pdb

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

Jupyter misalnya
Blaztix

6

Jika Anda menggunakan lingkungan IPython, Anda bisa menggunakan% debug dan shell akan membawa Anda kembali ke garis yang menyinggung dengan lingkungan ipdb untuk inspeksi dll. Opsi lain seperti yang ditunjukkan di atas adalah menggunakan sihir iPython% pdb yang secara efektif tidak sama.


Perhatikan bahwa jika kesalahan terjadi dalam fungsi modul, Anda dapat menavigasi melalui frame dengan updan downperintah untuk kembali ke baris kode Anda yang menghasilkan kesalahan.
Jean Paul

4

Anda dapat meletakkan baris ini dalam kode Anda:

import pdb ; pdb.set_trace()

Info lebih lanjut: Mulai python debugger di baris mana pun


8
Ini menghentikan kode dan memulai debugger di baris di mana Anda menempatkan perintah ini, bukan pada baris di mana pengecualian terjadi
blueFast

3

Untuk menjalankannya tanpa harus mengetikkan c di awal gunakan:

python -m pdb -c c <script name>

Pdb memiliki argumen baris perintahnya sendiri: -cc akan mengeksekusi perintah c (ontinue) pada awal eksekusi dan program akan berjalan tanpa gangguan sampai kesalahan.


3

python -m pdb script.py di python2.7 tekan terus untuk memulai dan itu akan berjalan ke kesalahan dan istirahat di sana untuk debug.


1

Jika Anda menjalankan modul:

python -m mymodule

Dan sekarang Anda ingin memasukkan pdbketika pengecualian terjadi, lakukan ini:

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

(atau perpanjang Anda PYTHONPATH). The PYTHONPATHdiperlukan agar modul ditemukan di jalan, karena Anda menjalankan pdbmodul sekarang.


0

Letakkan breakpoint di dalam konstruktor kelas pengecualian teratas dalam hierarki, dan sebagian besar waktu Anda akan melihat di mana kesalahan itu muncul.

Puting breakpoint berarti apa pun yang Anda inginkan: Anda dapat menggunakan IDE, atau pdb.set_trace, atau apa pun

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.