Автоматично запускається налагоджувач 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)

Перше рішення далі обговорюється в кулінарній книзі пітона
dirkjot

3
чому хтось -то вважає за краще codeбільше , pdbоскільки останній , здається, розширити на колишній?
K3 --- rnc

У мене те саме питання? Чому ви віддаєте перевагу code?
ARH

2
Потім використовуйте sys.exc_infoдля вилучення відстеження і, нарешті, зателефонуйте за pdb.post_mortemдопомогою цього сліду . Вам не потрібно передавати об’єкт traceback pdb.post_mortem. З документів : Якщо не задано прослідкування, він використовує той виняток, який зараз обробляється (для використання за замовчуванням потрібно обробляти виняток).
Пьотр Доброгост

2
@PiotrDobrogost Добре. Я думаю, що корисніше знати, що ви можете передати об'єкт tb, хоча це краще демонструє API. Добре знати, що обидва варіанти існують.
davidA

454
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
Дякую за те, що ви згадали про " enter" c "- я зазвичай використовував для введення" r "(для" run "), використовуючи його до gdb; і коли ви вводите 'r' в pdb, програма дійсно працює, але НЕ зупиняється (і не генерує зворотній шлях) на помилку; мене спантеличено, поки я не прочитав це. Ура!
sdaau

3
Vineet, він запустить вас з налагоджувачем, тому введіть "продовження", і він працюватиме, поки не буде виявлена ​​помилка. Звідти ви можете перевірити змінні тощо, як і в будь-якому іншому сеансі pdb.
Катерина Девлін

40
Будь ласка, ОП, прийміть це як відповідь. Це найкорисніше, і я витратив 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що є просто потворним ІМО.
cyphar

Я люблю цю відповідь досить часто, але pudbбільше віддаю перевагу pdb. Продовжуйте повертатися до копіювання та вставки, що, безумовно, говорить про відсутність порядку в моєму житті.
Stabledog

47

Ipython має команду для перемикання такої поведінки: % pdb . Це робить саме те, що ви описали, можливо навіть трохи більше (надаючи більш інформативні зворотні дані з підсвічуванням синтаксису та заповненням коду). Це обов'язково варто спробувати!


3
І це єдина розумна відповідь на це.
Майкл

4
Задокументовано на ipython.readthedocs.io/en/stable/interactive/…
matthiash

4
Зауважте, що - як також зазначалося в "Документах @matthiash" - це %debugдозволяє відкрити налагоджувач після виявлення помилки. Я часто віддаю перевагу цьому %pdb. (Компроміс буде тільки набирати qкожен раз , коли ви не хочете , щоб налагодити vs. помилка %debugкожен раз , коли ви робите хочете налагодити помилку.)
Брем Снайдера

1
Зауважте також, що налаштування c.InteractiveShell.pdb = Trueв одному ipython_config.pyвключається %pdbавтоматично для кожного сеансу.
Брахам Снайдер

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
Не майже настільки корисний, запускає в глобальний масштаб. Неможливо проколотись у будь-яку функцію, яка завершилась.
піксельпакс

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.



6

Якщо ви використовуєте середовище IPython, ви можете просто скористатися налагодженням%, і оболонка поверне вас до лінії порушень із середовищем ipdb для перевірок тощо. Ще один варіант, як зазначено вище, - використовувати магію iPython% pdb, яка ефективно робить так само.


Зауважте, що якщо помилка трапилася в функції модуля, ви можете переміщатися по кадрах upі downкомандам, щоб повернутися до рядка вашого коду, який генерував помилку.
Жан Пол


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, або що завгодно

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.