Hata durumunda python hata ayıklayıcıyı otomatik olarak başlatma


216

Bu, uzun süredir merak ettiğim bir soru, ancak asla uygun bir çözüm bulamadım. Bir komut dosyası çalıştırırsam ve karşılaşırsam, bir IndexError diyelim, python hatanın satırını, konumunu ve hızlı açıklamasını yazdırır ve çıkar. Bir hatayla karşılaşıldığında pdb'yi otomatik olarak başlatmak mümkün müdür? Ben dosyanın üst kısmında fazladan bir ithalat ifadesi, ya da birkaç ekstra kod satırı karşı değilim.


12
Kabul edilen cevabı değiştirmeyi düşündünüz mü?
Joost

Yanıtlar:


127

Sen kullanabilirsiniz traceback.print_exc istisnalar traceback yazdırmak için. Sonra geri izleme ayıklamak için sys.exc_info kullanın ve son olarak bu geri izleme ile pdb.post_mortem arayın

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)

İstisna kaynaklı çerçevenin yerel ayarlarını kullanarak code.interact ile etkileşimli bir komut satırı başlatmak istiyorsanız, bunu yapabilirsiniz.

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)

ilk çözüm python yemek
kitabında

3
neden kimse tercih edeceğini codeüzerinde pdbikinci eski genişletmek görünüyor beri?
K3 - rnc

Bende aynı soru var mı? Neden tercih edersin code?
ARH

2
Sonra sys.exc_infogeri izleme çıkarmak için kullanın ve son pdb.post_mortemolarak bu geri izleme ile arayın . Geri izleme nesnesini iletmeniz gerekmez pdb.post_mortem. Gönderen docs : Hiçbir traceback verilirse, o anda (varsayılan kullanılacak ise bir istisna işlenen olmalıdır) işlenen istisna birini kullanır.
Piotr Dobrogost

2
@PiotrDobrogost İyi bir nokta. Ben daha iyi API gösterir gibi olsa da, bir tb nesnesi geçirebilirsiniz bilmek daha yararlı olduğunu düşünüyorum. Her iki seçeneğin de var olduğunu bilmek güzel.
davidA

455
python -m pdb -c continue myscript.py

-c continueBayrağı sağlamazsanız, yürütme başladığında 'c' (Devam için) girmeniz gerekir. Sonra hata noktasına gider ve orada kontrol sağlar. Eqzx tarafından belirtildiği gibi , bu bayrak python 3.2'de yeni bir ektir , bu nedenle önceki Python sürümleri için 'c' girilmesi gerekir (bkz. Https://docs.python.org/3/library/pdb.html ).


5
" Enter" c "den bahsettiğiniz için teşekkür ederiz - Genellikle" r "(" run "için) giriyordum, buna gdbalışkınım ve 'r' girdiğinizde pdb, program gerçekten çalışır, ancak hata durumunda durmaz (ya da geri izleme oluşturmaz); bunu okuyana kadar beni şaşırttı. Şerefe!
sdaau

3
Vine, hata ayıklayıcı açık olarak başlayacaktır, bu yüzden "devam" girin ve hata karşılaşılana kadar çalışır. Oradan diğer pdb oturumlarında olduğu gibi değişkenleri vb. İnceleyebilirsiniz.
Catherine Devlin

40
Lütfen OP, bunu bir cevap olarak kabul et. Bu en kullanışlı olanı ve diğerlerini okuduğumda 5 dakika harcadım.
jhegedus

4
Bu aynı zamanda ipdb; ve tabii ki senaryodan sonra argümanlar eklenebilir!
tutuDajuju

20
Bu Python 2.7 ile çalışmaz. docs.python.org/3/library/pdb.html : "Sürüm 3.2'deki yenilikler: pdb.py artık komutları yürüten bir -c seçeneğini kabul ediyor"
eqzx

68

Aşağıdaki modülü kullanın:

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

Adı debug(veya istediğinizi) adlandırın ve python yolunuzda bir yere koyun.

Şimdi, komut dosyanızın başına bir ekleyin import debug.


2
Bu kabul edilen cevap olmalıdır - mevcut kodda herhangi bir değişiklik yapılmasını veya try-catchsadece çirkin bir IMO olan her şeyi sarmayı gerektirmez .
cyphar

Doğrusu sık bu cevabı seviyorum ama tercih pudbüzerinde pdb. Kopyala ve yapıştır'a geri dönmeye devam et, bu da hayatımda düzen eksikliği hakkında bir şeyler söylüyor.
Stabledog

47

Ipython'un şu davranışı değiştirmek için bir komutu vardır: % pdb . Tam olarak açıkladığınız şeyi yapar, belki biraz daha fazla (sözdizimi vurgulama ve kod tamamlama ile daha bilgilendirici geri çekimler sağlar). Kesinlikle denemeye değer!


3
Ve bunun tek makul cevabı bu.
Michael


4
Bağlantılı docs @matthiash'te de belirtildiği gibi, bir hatayla karşılaştıktan sonra%debug hata ayıklayıcıyı açmaya izin verdiğini unutmayın . Bunu sık sık tercih ederim . (Trade-off sadece yazıyor yazarak bir hata VS. hata ayıklama istemiyorsanız her zaman her zaman yapmak bir hata ayıklamak istediğiniz.)%pdbq%debug
Braham Snyder'ı

1
Ayarını da unutmayın c.InteractiveShell.pdb = Truekişinin de ipython_config.pyüzerindeki dönüşler %pdbher oturum için otomatik olarak.
Braham Snyder

33

Bu hata ayıklayıcı değil, muhtemelen aynı derecede yararlı (?)

Guido'nun bir yerlerde yaptığı konuşmada bundan bahsettiğini duyduğumu biliyorum.

Python -? 'U kontrol ettim ve -i komutunu kullanırsanız betiğinizin durduğu yerde etkileşimde bulunabilirsiniz.

Bu komut dosyası verildiğinde:

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

Bu çıktıyı alabilirsiniz!

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

Dürüst olmak gerekirse, bunu kullanmadım, ama olmalıyım, çok yararlı görünüyor.


Hafif, ancak çoğu zaman sadece ihtiyaç duyulan şey
Casebash

8
Neredeyse faydalı değil, küresel kapsamda başlatılıyor. Herhangi bir işlev çöktüğünde poke edilemez.
pixelpax

21

IPython bunu komut satırında kolaylaştırır:

python myscript.py arg1 arg2

yeniden yazılabilir

ipython --pdb myscript.py -- arg1 arg2

Veya benzer şekilde, bir modül çağırıyorsanız:

python -m mymodule arg1 arg2

yeniden yazılabilir

ipython --pdb -m mymodule -- arg1 arg2

Not --kendi olarak komut dosyasının argümanları okumasını IPython durdurmak için.

Bu aynı zamanda pdb yerine gelişmiş IPython hata ayıklayıcısını (ipdb) çalıştırma avantajına sahiptir.


10

Kullanıyorsanız ipython, türü başlattıktan sonra%pdb

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

Örneğin
Jupyter

6

IPython ortamını kullanıyorsanız, yalnızca% hata ayıklamasını kullanabilirsiniz ve kabuk sizi denetimler vb. İçin ipdb ortamı ile rahatsız edici satıra geri götürecektir. aynısı.


Hata bir modül işlevinde meydana gelirse, hatayı oluşturan kodunuzun satırına geri dönmek için upve downkomutları ile kareler arasında gezinebileceğinizi unutmayın.
Jean Paul


3

Başlangıçta c yazmak zorunda kalmadan çalışmasını sağlamak için:

python -m pdb -c c <script name>

Pdb'nin kendi komut satırı bağımsız değişkenleri vardır: -cc yürütme başlangıcında c (devam) komutunu yürütür ve program hataya kadar kesintisiz çalışır.


3

python2.7'de python -m pdb script.py başlamaya devam eder ve hataya çalışır ve hata ayıklama için orada kırılır.


1

Bir modül çalıştırıyorsanız:

python -m mymodule

Ve şimdi pdbbir istisna meydana geldiğinde girmek istiyorsunuz , bunu yapın:

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

(veya genişletmek Şu Verilerinizi PYTHONPATH). PYTHONPATHModül yolunda bulunan böylece çalışan beri, tabi pdbşimdi modülü.


0

Hiyerarşide en üst düzey istisna sınıfının yapıcısına bir kesme noktası koyun ve çoğu zaman hatanın nerede oluştuğunu göreceksiniz.

Bir kesme noktası koymak, ne demek istediğinizi ifade eder: bir IDE kullanabilirsiniz, ya pdb.set_traceda

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.