Bắt đầu gỡ lỗi python tự động bị lỗi


216

Đây là một câu hỏi tôi đã tự hỏi trong một thời gian khá lâu, nhưng tôi chưa bao giờ tìm thấy một giải pháp phù hợp. Nếu tôi chạy một tập lệnh và tôi đi qua, giả sử IndexError, python in dòng, vị trí và mô tả nhanh về lỗi và thoát. Có thể tự động khởi động pdb khi gặp lỗi không? Tôi không chống lại việc có thêm một câu lệnh nhập ở đầu tệp, cũng không có thêm một vài dòng mã.


12
Bạn đã xem xét việc thay đổi câu trả lời được chấp nhận?
Joost

Câu trả lời:


127

Bạn có thể sử dụng tracBack.print_exc để in dấu vết ngoại lệ. Sau đó, sử dụng sys.exc_info để trích xuất truy nguyên và cuối cùng gọi pdb.post_mortem với truy nguyê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)

Nếu bạn muốn bắt đầu một dòng lệnh tương tác với code.interact bằng cách sử dụng các ngôn ngữ địa phương của khung nơi ngoại lệ bắt nguồn, bạn có thể làm

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)

giải pháp đầu tiên được thảo luận thêm tại sách dạy nấu ăn trăn
dirkjot

3
Tại sao mọi người thích codehơn pdbvì cái sau dường như mở rộng trên cái trước?
K3 --- rnc

Tôi có cùng một câu hỏi? Tại sao bạn thích code?
ARH

2
Sau đó sử dụng sys.exc_infođể trích xuất truy nguyên và cuối cùng gọi pdb.post_mortemvới truy nguyên đó . Bạn không cần phải vượt qua đối tượng truy nguyên pdb.post_mortem. Từ tài liệu : Nếu không có dấu vết nào được đưa ra, nó sử dụng một trong những ngoại lệ hiện đang được xử lý (một ngoại lệ phải được xử lý nếu sử dụng mặc định).
Piotr Dobrogost

2
@PiotrDobrogost Điểm tốt. Tuy nhiên, tôi nghĩ sẽ hữu ích hơn khi biết rằng bạn có thể truyền một đối tượng tb vào, vì nó thể hiện tốt hơn API. Tốt để biết cả hai lựa chọn tồn tại.
davidA

453
python -m pdb -c continue myscript.py

Nếu bạn không cung cấp -c continuecờ thì bạn sẽ cần nhập 'c' (cho Tiếp tục) khi bắt đầu thực thi. Sau đó, nó sẽ chạy đến điểm lỗi và cung cấp cho bạn quyền kiểm soát ở đó. Như eqzx đã đề cập , cờ này là một bổ sung mới trong python 3.2, vì vậy, việc nhập 'c' là bắt buộc đối với các phiên bản Python trước đó (xem https://docs.python.org/3/l Library / pdb.html ).


5
Cảm ơn bạn đã đề cập đến " enter 'c' " - tôi thường sử dụng để nhập 'r' (cho "chạy"), được sử dụng từ đó gdb; và khi bạn nhập 'r' in pdb, chương trình thực sự chạy, nhưng KHÔNG dừng lại (cũng không tạo ra backtrace) do lỗi; làm tôi hoang mang cho đến khi tôi đọc nó Chúc mừng!
sdaau

3
Vineet, nó sẽ khởi động bạn với trình gỡ lỗi trên, vì vậy hãy nhập "cont" và nó sẽ chạy cho đến khi gặp lỗi. Từ đó bạn có thể kiểm tra các biến, v.v. như trong bất kỳ phiên pdb nào khác.
Catherine Devlin

40
Hãy OP, chấp nhận điều này như một câu trả lời. Điều này là hữu ích nhất và tôi đã lãng phí 5 phút để đọc những cái khác cho đến khi tôi nhấn cái này ... đây là lần đầu tiên!
jhegedus

4
Điều này cũng hoạt động tương tự với ipdb; và tất nhiên các đối số có thể được thêm vào sau tập lệnh!
tutuDajuju

20
Điều này không hoạt động với Python 2.7. docs.python.org/3/library/pdb.html : "Mới trong phiên bản 3.2: pdb.py bây giờ chấp nhận một tùy chọn -c rằng lệnh thực thi"
eqzx

68

Sử dụng mô-đun sau:

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

Đặt tên cho nó debug(hoặc bất cứ điều gì bạn thích) và đặt nó ở đâu đó trong đường dẫn python của bạn.

Bây giờ, khi bắt đầu tập lệnh của bạn, chỉ cần thêm một import debug.


2
Đây phải là câu trả lời được chấp nhận - nó không yêu cầu bất kỳ sửa đổi nào về mã hiện có hoặc gói mọi thứ trong một try-catchIMO xấu xí.
cyphar

Tôi thích câu trả lời này khá thường xuyên, nhưng thích pudbhơn pdb. Tiếp tục quay trở lại sao chép và dán, điều chắc chắn nói lên điều gì đó về sự thiếu trật tự trong cuộc sống của tôi.
Stablesog

47

Ipython có một lệnh để chuyển đổi hành vi này: % pdb . Nó thực hiện chính xác những gì bạn mô tả, thậm chí có thể nhiều hơn một chút (cung cấp cho bạn nhiều backtrac thông tin hơn với tô sáng cú pháp và hoàn thành mã). Nó chắc chắn đáng để thử!


3
Và đó là câu trả lời hợp lý duy nhất cho vấn đề này.
Michael


4
Lưu ý rằng - như đã lưu ý trong tài liệu @matthiash được liên kết - %debugcho phép một người mở trình gỡ lỗi sau khi gặp lỗi. Tôi thường thích điều này hơn %pdb. (The trade-off là chỉ gõ qmỗi khi bạn không muốn gỡ lỗi một vs lỗi gõ %debugmỗi khi bạn làm muốn gỡ lỗi một lỗi.)
Braham Snyder

1
Cũng lưu ý rằng cài đặt c.InteractiveShell.pdb = Truetrong một người ipython_config.pysẽ %pdbtự động bật cho mỗi phiên.
Braham Snyder

33

Đây không phải là trình gỡ lỗi, nhưng có lẽ cũng hữu ích (?)

Tôi biết tôi đã nghe Guido đề cập đến điều này trong một bài phát biểu ở đâu đó.

Tôi vừa kiểm tra python -?, Và nếu bạn sử dụng lệnh -i, bạn có thể tương tác nơi tập lệnh của bạn dừng lại.

Vì vậy, đưa ra kịch bản này:

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

Bạn có thể nhận được đầu ra này!

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

Thành thật mà nói tôi đã không sử dụng nó, nhưng tôi nên, có vẻ rất hữu ích.


Nhẹ, nhưng thường chỉ là những gì cần thiết
Casebash

8
Không gần như hữu ích, khởi động vào phạm vi toàn cầu. Không thể chọc vào bất cứ chức năng nào bị rơi.
pixelpax

21

IPython làm điều này đơn giản trên dòng lệnh:

python myscript.py arg1 arg2

có thể được viết lại thành

ipython --pdb myscript.py -- arg1 arg2

Hoặc, tương tự, nếu gọi một mô-đun:

python -m mymodule arg1 arg2

có thể được viết lại thành

ipython --pdb -m mymodule -- arg1 arg2

Lưu ý --để ngăn IPython đọc các đối số của tập lệnh.

Điều này cũng có lợi thế là gọi trình gỡ lỗi IPython nâng cao (ipdb) thay vì pdb.


9

Nếu bạn đang sử dụng ipython, sau khi khởi chạy loại%pdb

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

Jupyter chẳng hạn
Blaztix

6

Nếu bạn đang sử dụng môi trường IPython, bạn chỉ cần sử dụng% debug và shell sẽ đưa bạn trở lại dòng vi phạm với môi trường ipdb để kiểm tra, v.v. Một tùy chọn khác như được chỉ ra ở trên là sử dụng ma thuật iPython% pdb giống nhau.


Lưu ý rằng nếu xảy ra lỗi trong chức năng mô-đun, bạn có thể điều hướng qua các khung updowncác lệnh để quay lại dòng mã đã tạo ra lỗi.
Jean Paul


3

Để nó chạy mà không phải gõ c khi bắt đầu sử dụng:

python -m pdb -c c <script name>

Pdb có các đối số dòng lệnh riêng: -cc sẽ thực thi lệnh c (liên tục) khi bắt đầu thực thi và chương trình sẽ chạy không bị gián đoạn cho đến khi xảy ra lỗi.


3

python -m pdb script.py trong python2.7 nhấn tiếp tục để bắt đầu và nó sẽ chạy đến lỗi và phá vỡ ở đó để gỡ lỗi.


1

Nếu bạn đang chạy một mô-đun:

python -m mymodule

Và bây giờ bạn muốn nhập pdbkhi có ngoại lệ xảy ra, hãy làm điều này:

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

(hoặc mở rộng của bạn PYTHONPATH). Điều PYTHONPATHnày là cần thiết để mô-đun được tìm thấy trong đường dẫn, vì bạn đang chạy pdbmô-đun bây giờ.


0

Đặt một điểm dừng bên trong hàm tạo của lớp ngoại lệ trên cùng trong cấu trúc phân cấp và hầu hết các lần bạn sẽ thấy lỗi được đưa ra ở đâu.

Đặt một điểm dừng có nghĩa là bất cứ điều gì bạn muốn nó có nghĩa là: bạn có thể sử dụng IDE, hoặc pdb.set_trace, hoặc bất cứ điều gì

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.