การเริ่มต้นดีบักหลามโดยอัตโนมัติเมื่อเกิดข้อผิดพลาด


216

นี่เป็นคำถามที่ฉันสงสัยมาระยะหนึ่งแล้ว แต่ฉันไม่เคยพบวิธีแก้ปัญหาที่เหมาะสมมาก่อน ถ้าฉันเรียกใช้สคริปต์และเจอกันสมมติว่ามี IndexError หลามพิมพ์บรรทัดตำแหน่งและคำอธิบายอย่างรวดเร็วของข้อผิดพลาดและออก เป็นไปได้หรือไม่ที่จะเริ่ม pdb โดยอัตโนมัติเมื่อพบข้อผิดพลาด? ฉันไม่ได้มีคำสั่งนำเข้าเพิ่มเติมที่ด้านบนของไฟล์หรือไม่ต้องมีโค้ดพิเศษอีกสองสามบรรทัด


12
คุณคิดว่าจะเปลี่ยนคำตอบที่เป็นที่ยอมรับหรือไม่?
Joost

คำตอบ:


127

คุณสามารถใช้traceback.print_excเพื่อพิมพ์ข้อยกเว้น traceback จากนั้นใช้sys.exc_infoเพื่อแยก traceback และสุดท้ายเรียกpdb.post_mortemด้วย traceback นั้น

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)

หากคุณต้องการเริ่มบรรทัดคำสั่งแบบโต้ตอบด้วยโค้ดติดต่อโดยใช้ไอเดียของเฟรมที่มีข้อยกเว้นเกิดขึ้นคุณสามารถทำได้

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)

วิธีการแก้ปัญหาแรกจะกล่าวถึงต่อไปในตำราหลาม
dirkjot

3
ทำไมทุกคนจะชอบcodeมากกว่าpdbหลังจากหลังดูเหมือนจะขยายตัวในอดีต?
K3 --- rnc

ฉันมีคำถามเดียวกัน ทำไมคุณต้องการcode?
ARH

2
จากนั้นใช้sys.exc_infoเพื่อแยก traceback และสุดท้ายก็เรียกpdb.post_mortemด้วย tracebackนั้น คุณไม่จำเป็นต้องผ่านวัตถุ traceback pdb.post_mortemไป จากเอกสาร : หากไม่ได้รับการติดตามกลับจะใช้ข้อยกเว้นข้อใดข้อหนึ่งที่กำลังถูกจัดการอยู่ในขณะนี้ (ต้องมีการจัดการข้อยกเว้นหากใช้ค่าเริ่มต้น)
Piotr Dobrogost

2
@PiotrDobrogost จุดที่ดี ฉันคิดว่าการรู้ว่าคุณสามารถส่งผ่านวัตถุ tb ได้นั้นจะมีประโยชน์มากขึ้น เป็นการดีที่จะรู้ว่ามีตัวเลือกทั้งสองอยู่
davidA

455
python -m pdb -c continue myscript.py

หากคุณไม่ได้ระบุ-c continueธงคุณจะต้องป้อน 'c' (สำหรับดำเนินการต่อ) เมื่อเริ่มต้นการดำเนินการ จากนั้นมันจะวิ่งไปที่จุดผิดพลาดและให้คุณควบคุมได้ ตามที่กล่าวไว้โดย eqzxการตั้งค่าสถานะนี้เป็นการเพิ่มใหม่ใน python 3.2 ดังนั้นการป้อน 'c' จำเป็นสำหรับ Python เวอร์ชั่นก่อนหน้า (ดูhttps://docs.python.org/3/library/pdb.html )


5
ขอบคุณที่กล่าวถึง " ป้อน 'c' " - ฉันมักจะใช้เพื่อป้อน 'r' (สำหรับ "เรียกใช้") ถูกใช้จากgdb; และเมื่อคุณป้อน 'r' ในpdbโปรแกรมจะรัน แต่ไม่หยุด (หรือสร้าง backtrace) โดยมีข้อผิดพลาด ทำให้ฉันงุนงงจนกระทั่งฉันอ่านสิ่งนี้ ไชโย!
sdaau

3
Vineet มันจะเริ่มต้นคุณด้วยการดีบักบนดังนั้นป้อน "ต่อ" และมันจะทำงานจนกว่าจะพบข้อผิดพลาด จากตรงนั้นคุณสามารถตรวจสอบตัวแปร ฯลฯ เช่นในเซสชัน pdb อื่น ๆ
Catherine Devlin

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(หรืออะไรก็ได้ที่คุณชอบ) และวางมันไว้ที่ไหนสักแห่งในเส้นทางของหลาม

import debugตอนนี้ที่เริ่มต้นของสคริปต์ของคุณเพียงแค่เพิ่ม


2
นี่ควรเป็นคำตอบที่ยอมรับได้ - มันไม่จำเป็นต้องมีการแก้ไขโค้ดที่มีอยู่หรือห่อทุกอย่างในtry-catchIMO ที่น่าเกลียด
cyphar

ฉันรักคำตอบนี้ค่อนข้างบ่อย แต่ชอบมากกว่าpudb pdbกลับไปที่การคัดลอกและวางซึ่งแน่นอนว่าบางสิ่งเกี่ยวกับการขาดคำสั่งในชีวิตของฉัน
Stabledog

47

ipythonมีคำสั่งสำหรับการสลับพฤติกรรมนี้: % PDB มันทำสิ่งที่คุณอธิบายอาจจะมากกว่าเดิมเล็กน้อย (ให้ backtraces ที่ให้ข้อมูลกับคุณมากขึ้นด้วยการเน้นไวยากรณ์และการเติมโค้ดให้สมบูรณ์) มันคุ้มค่าที่จะลอง!


3
และนั่นเป็นคำตอบเดียวที่สมเหตุสมผลสำหรับเรื่องนี้
Michael


4
โปรดทราบว่า - ตามที่ระบุไว้ใน docs @matthiash ที่เชื่อมโยง - %debugอนุญาตให้หนึ่งเปิดตัวดีบักหลังจากพบข้อผิดพลาด %pdbฉันมักจะชอบมากกว่านี้ (การค้าออกเป็นเพียงการพิมพ์qครั้งที่คุณไม่ต้องการที่จะแก้ปัญหาข้อผิดพลาดกับการพิมพ์ทุก%debugครั้งที่คุณทุกคนทำต้องการแก้ปัญหาข้อผิดพลาด.)
Braham ไนเดอร์

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

8
ไม่เกือบมีประโยชน์เลยเปิดตัวในขอบเขตทั่วโลก ไม่สามารถกระตุ้นการทำงานที่ผิดพลาด
pixelpax

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 จากการอ่านข้อโต้แย้งของสคริปต์เป็นของตัวเอง

สิ่งนี้ยังมีข้อดีของการเรียกใช้ดีบักเกอร์ IPython ขั้นสูง (ipdb) แทนที่จะเป็น pdb


10

หากคุณใช้ipythonงานอยู่หลังจากเปิดใช้งานประเภท%pdb

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

ยกตัวอย่างเช่น
Jupyter

6

หากคุณใช้สภาพแวดล้อม IPython คุณสามารถใช้% debug และเชลล์จะนำคุณกลับไปยังบรรทัดที่ละเมิดด้วยสภาพแวดล้อม ipdb สำหรับการตรวจสอบและตัวเลือกอื่น ๆ ตามที่ได้กล่าวไว้ข้างต้นคือการใช้ iPython magic% pdb ซึ่งมีประสิทธิภาพ เหมือน.


โปรดทราบว่าหากข้อผิดพลาดเกิดขึ้นในฟังก์ชั่นโมดูลคุณสามารถนำทางผ่านเฟรมด้วยupและdownคำสั่งเพื่อกลับไปที่บรรทัดของรหัสที่สร้างข้อผิดพลาด
Jean Paul

4

คุณสามารถใส่บรรทัดนี้ในรหัสของคุณ:

import pdb ; pdb.set_trace()

ข้อมูลเพิ่มเติม: เริ่มดีบักหลามที่บรรทัดใดก็ได้


8
สิ่งนี้จะหยุดโค้ดและเริ่มดีบักเกอร์ในบรรทัดที่คุณใส่คำสั่งนี้ไม่ใช่บรรทัดที่มีข้อยกเว้นเกิดขึ้น
blueFast

3

หากต้องการให้มันรันโดยไม่ต้องพิมพ์ c ตอนเริ่มใช้

python -m pdb -c c <script name>

Pdb มีอาร์กิวเมนต์บรรทัดคำสั่งของตนเอง: -cc จะดำเนินการคำสั่ง c (ontinue) เมื่อเริ่มต้นการดำเนินการและโปรแกรมจะทำงานอย่างต่อเนื่องจนกว่าข้อผิดพลาด


3

python -m pdb script.py ใน python2.7 กดเพื่อเริ่มต้นต่อไปและจะทำงานไปที่ข้อผิดพลาดและหยุดการดีบัก


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.